1) Cleaned up implementation of history function.

2) Improved history file format to collect control information (like 
   steering etc) to allow replaying based on the physics (and not only
   replaying recorded kart positions).
3) Added some constants (time till finish, time for music credits) to
   the stk_config.dat file.
4) Made name of the menu background picture configureable in 
   stk_config.dat file.


git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2328 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
hikerstk 2008-10-06 13:40:11 +00:00
parent 6a9a943292
commit 167107fcbc
20 changed files with 361 additions and 257 deletions

View File

@ -10,6 +10,10 @@
;; points 1st, 0 is least points ;; points 1st, 0 is least points
;; 1st ;; 1st
(title-music "main_theme.music") (title-music "main_theme.music")
(menu-background "st_title_screen.rgb")
(max-history 10000) ;; maximum number of history frames.
(delay-finish-time 10) ;; delay till race results are displayed.
(music-credit-time 10) ;; time for which the music credits are displayed.
;; Attachment related parameters ;; Attachment related parameters
;; ----------------------------- ;; -----------------------------

View File

@ -17,13 +17,9 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_CONSTANTS_H #ifndef HEADER_CONSTANTS_HPP
#define HEADER_CONSTANTS_H #define HEADER_CONSTANTS_HPP
#define MAX_HISTORY 50000 /* number of history events */
#define TIME_DELAY_TILL_FINISH 10.0f /* time after all player karts finish */
#define TIME_MUSIC_DESCRIPTION 10.0f /* duration music description is displayed */
/* /*
All final units are in meters (or meters/sec or meters/sec^2) All final units are in meters (or meters/sec or meters/sec^2)
and degrees (or degrees/sec). and degrees (or degrees/sec).

View File

@ -39,7 +39,7 @@ float Flyable::m_st_force_updown[COLLECT_MAX];
btVector3 Flyable::m_st_extend[COLLECT_MAX]; btVector3 Flyable::m_st_extend[COLLECT_MAX];
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
Flyable::Flyable(Kart *kart, CollectableType type, float mass) : Moveable(false) Flyable::Flyable(Kart *kart, CollectableType type, float mass) : Moveable()
{ {
// get the appropriate data from the static fields // get the appropriate data from the static fields
m_speed = m_st_speed[type]; m_speed = m_st_speed[type];

View File

@ -18,45 +18,136 @@
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "history.hpp" #include "history.hpp"
#include <stdio.h>
#include "kart.hpp" #include "kart.hpp"
#include "track.hpp" #include "track.hpp"
#include "race_manager.hpp" #include "race_manager.hpp"
#include "modes/world.hpp"
#include "network/network_manager.hpp"
History* history = 0; History* history = 0;
void History::SetSize(int n) //-----------------------------------------------------------------------------
/** Initialises the history object and sets the mode to none.
*/
History::History()
{ {
m_size = n; m_replay_mode = HISTORY_NONE;
m_all_deltas = new float[m_size];
m_current = -1;
m_wrapped = false;
} // History } // History
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void History::StoreDelta(float delta) /** Starts replay from the history file in the current directory.
*/
void History::startReplay()
{ {
this->m_current++; Load();
if(m_current>=m_size) } // initReplay
//-----------------------------------------------------------------------------
/** Initialise the history for a new recording. It especially allocates memory
* to store the history.
*/
void History::initRecording()
{
allocateMemory(stk_config->m_max_history);
m_current = -1;
m_wrapped = false;
m_size = 0;
} // initRecording
//-----------------------------------------------------------------------------
/** Allocates memory for the history. This is used when recording as well
* as when replaying (since in replay the data is read into memory first).
* \param number_of_frames Maximum number of frames to store.
*/
void History::allocateMemory(int number_of_frames)
{
m_all_deltas.resize (number_of_frames);
m_all_controls.resize (number_of_frames*race_manager->getNumKarts());
m_all_xyz.resize (number_of_frames*race_manager->getNumKarts());
m_all_rotations.resize(number_of_frames*race_manager->getNumKarts());
} // allocateMemory
//-----------------------------------------------------------------------------
/** Depending on mode either saves the data for the current time step, or
* replays the data.
* /param dt Time step.
*/
void History::update(float dt)
{
if(m_replay_mode==HISTORY_NONE)
updateSaving(dt);
else
updateReplay(dt);
} // update
//-----------------------------------------------------------------------------
/** Saves the current history.
* \param dt Time step size.
*/
void History::updateSaving(float dt)
{
m_current++;
if(m_current>=(int)m_all_deltas.size())
{ {
m_wrapped = true; m_wrapped = true;
m_current = 0; m_current = 0;
} }
m_all_deltas[m_current] = delta; else
} // StoreDT {
m_size ++;
}
m_all_deltas[m_current] = dt;
unsigned int max_num_karts = race_manager->getNumKarts();
// n<=max_num_karts, e.g. if karts are eliminated
unsigned int n = race_manager->getNumKarts();
for(unsigned int i=0; i<n; i++)
{
unsigned int index=m_current*max_num_karts+i;
const Kart *kart = RaceManager::getKart(i);
m_all_controls[index] = kart->getControls();
m_all_xyz[index] = kart->getXYZ();
m_all_rotations[index] = kart->getRotation();
} // for i
} // updateSaving
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
float History::GetNextDelta() /** Sets the kart position and controls to the recorded history value.
* \param dt Time step size.
*/
void History::updateReplay(float dt)
{ {
m_current++; m_current++;
if(m_current>=m_size) if(m_current>=(int)m_all_deltas.size())
{ {
fprintf(stderr,"History: finished.\n"); printf("Replay finished.\n");
exit(-3); exit(2);
} }
return m_all_deltas[m_current]; unsigned int num_karts = race_manager->getNumKarts();
} // GetNextDT for(unsigned k=0; k<num_karts; k++)
{
Kart *kart = RaceManager::getKart(k);
unsigned int index=m_current*num_karts+k;
if(m_replay_mode==HISTORY_POSITION)
{
kart->setXYZ(m_all_xyz[index]);
kart->setRotation(m_all_rotations[index]);
}
else
{
kart->setControls(m_all_controls[index]);
}
}
} // updateReplay
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Saves the history stored in the internal data structures into a file called
* history.dat.
*/
void History::Save() void History::Save()
{ {
FILE *fd = fopen("history.dat","w"); FILE *fd = fopen("history.dat","w");
@ -72,12 +163,12 @@ void History::Save()
int k; int k;
for(k=0; k<nKarts; k++) for(k=0; k<nKarts; k++)
{ {
fprintf(fd, "model %d: %s\n",k, RaceManager::getKart(k)->getName().c_str()); fprintf(fd, "model %d: %s\n",k, RaceManager::getKart(k)->getIdent().c_str());
} }
fprintf(fd, "size: %d\n", GetCount()); fprintf(fd, "size: %d\n", m_size);
int j = m_wrapped ? m_current : 0; int j = m_wrapped ? m_current : 0;
for(int i=0; i<GetCount(); i++) for(int i=0; i<m_size; i++)
{ {
fprintf(fd, "delta: %f\n",m_all_deltas[i]); fprintf(fd, "delta: %f\n",m_all_deltas[i]);
j=(j+1)%m_size; j=(j+1)%m_size;
@ -86,12 +177,19 @@ void History::Save()
for(int k=0; k<nKarts; k++) for(int k=0; k<nKarts; k++)
{ {
Kart* kart= RaceManager::getKart(k); Kart* kart= RaceManager::getKart(k);
char s[1024];
j = m_wrapped ? m_current : 0; j = m_wrapped ? m_current : 0;
for(int i=0; i<GetCount(); i++) for(int i=0; i<m_size; i++)
{ {
kart->WriteHistory(s, k, j); // FIXME: kart number is not really necessary
fprintf(fd, "%s\n",s); fprintf(fd, "%d %f %f %d %f %f %f %f %f %f %f\n",
k,
m_all_controls[j].lr,
m_all_controls[j].accel,
m_all_controls[j].getButtonsCompressed(),
m_all_xyz[j].getX(), m_all_xyz[j].getY(),
m_all_xyz[j].getZ(),
m_all_rotations[j].getX(), m_all_rotations[j].getY(),
m_all_rotations[j].getZ(), m_all_rotations[j].getW() );
j=(j+1)%m_size; j=(j+1)%m_size;
} // for i } // for i
} // for k } // for k
@ -100,13 +198,15 @@ void History::Save()
} // Save } // Save
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Loads a history from history.dat in the current directory.
*/
void History::Load() void History::Load()
{ {
char s[1024], s1[1024]; char s[1024], s1[1024];
int n, numKarts; int n;
m_fd = fopen("history.dat","r"); FILE *fd = fopen("history.dat","r");
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s,"Version: %s",s1)!=1) if(sscanf(s,"Version: %s",s1)!=1)
{ {
fprintf(stderr, "WARNING: no Version information found in history file.\n"); fprintf(stderr, "WARNING: no Version information found in history file.\n");
@ -119,15 +219,16 @@ void History::Load()
fprintf(stderr, " tuxracer version is '%s'\n",VERSION); fprintf(stderr, " tuxracer version is '%s'\n",VERSION);
} }
#endif #endif
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s, "numkarts: %d",&numKarts)!=1) unsigned int num_karts;
if(sscanf(s, "numkarts: %d",&num_karts)!=1)
{ {
fprintf(stderr,"WARNING: No number of karts found in history file.\n"); fprintf(stderr,"WARNING: No number of karts found in history file.\n");
exit(-2); exit(-2);
} }
race_manager->setNumKarts(numKarts); race_manager->setNumKarts(num_karts);
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s, "numplayers: %d",&n)!=1) if(sscanf(s, "numplayers: %d",&n)!=1)
{ {
fprintf(stderr,"WARNING: No number of players found in history file.\n"); fprintf(stderr,"WARNING: No number of players found in history file.\n");
@ -135,7 +236,7 @@ void History::Load()
} }
race_manager->setNumPlayers(n); race_manager->setNumPlayers(n);
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s, "difficulty: %d",&n)!=1) if(sscanf(s, "difficulty: %d",&n)!=1)
{ {
fprintf(stderr,"WARNING: No difficulty found in history file.\n"); fprintf(stderr,"WARNING: No difficulty found in history file.\n");
@ -143,7 +244,7 @@ void History::Load()
} }
race_manager->setDifficulty((RaceManager::Difficulty)n); race_manager->setDifficulty((RaceManager::Difficulty)n);
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s, "track: %s",s1)!=1) if(sscanf(s, "track: %s",s1)!=1)
{ {
fprintf(stderr,"WARNING: Track not found in history file.\n"); fprintf(stderr,"WARNING: Track not found in history file.\n");
@ -153,40 +254,58 @@ void History::Load()
// the racing phase can switch to 'ending' // the racing phase can switch to 'ending'
race_manager->setNumLaps(10); race_manager->setNumLaps(10);
for(int i=0; i<numKarts; i++) for(unsigned int i=0; i<num_karts; i++)
{ {
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s, "model %d: %s",&n, s1)!=2) if(sscanf(s, "model %d: %s",&n, s1)!=2)
{ {
fprintf(stderr,"WARNING: No model information for kart %d found.\n", fprintf(stderr,"WARNING: No model information for kart %d found.\n",
i); i);
exit(-2); exit(-2);
} }
if(i<race_manager->getNumPlayers())
{
race_manager->setLocalKartInfo(i, s1);
}
} // for i<nKarts } // for i<nKarts
// JH: The model information is currently ignored // FIXME: The model information is currently ignored
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
if(sscanf(s,"size: %d",&n)!=1) if(sscanf(s,"size: %d",&m_size)!=1)
{ {
fprintf(stderr,"WARNING: Number of records not found in history file.\n"); fprintf(stderr,"WARNING: Number of records not found in history file.\n");
exit(-2); exit(-2);
} }
SetSize(n); allocateMemory(m_size);
m_current = -1;
for(int i=0; i<m_size; i++) for(int i=0; i<m_size; i++)
{ {
fgets(s, 1023, m_fd); fgets(s, 1023, fd);
sscanf(s, "delta: %f\n",m_all_deltas+i); sscanf(s, "delta: %f\n",&m_all_deltas[i]);
} }
m_current = -1;
for(unsigned int k=0; k<num_karts; k++)
{
int j=0;
for(int i=0; i<m_size; i++)
{
fgets(s, 1023, fd);
int buttonsCompressed;
float x,y,z,rx,ry,rz,rw;
sscanf(s, "%d %f %f %d %f %f %f %f %f %f %f\n",
&j,
&m_all_controls[i].lr,
&m_all_controls[i].accel,
&buttonsCompressed,
&x, &y, &z, &rx, &ry, &rz, &rw);
m_all_xyz[i] = Vec3(x,y,z);
m_all_rotations[i] = btQuaternion(rx,ry,rz,rw);
m_all_controls[i].setButtonsCompressed(char(buttonsCompressed));
} // for i
} // for k
fprintf(fd, "History file end.\n");
fclose(fd);
network_manager->setupPlayerKartInfo();
} // Load } // Load
//-----------------------------------------------------------------------------
void History::LoadKartData(Kart* k, int kartNumber)
{
char s[1024];
for(int i=0; i<m_size; i++)
{
fgets(s, 1023, m_fd);
k->ReadHistory(s, kartNumber, i);
} // for i<m_current
} // LoadKartData

View File

@ -17,35 +17,62 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_HISTORY_H #ifndef HEADER_HISTORY_HPP
#define HEADER_HISTORY_H #define HEADER_HISTORY_HPP
#include <cstdio> #include <vector>
#include "constants.hpp"
#include "LinearMath/btQuaternion.h"
#include "kart_control.hpp"
#include "vec3.hpp"
class Kart; class Kart;
class History class History
{ {
protected:
// maximum number of history events to store
int m_size;
int m_current;
bool m_wrapped;
FILE* m_fd;
float * m_all_deltas;
public: public:
History () { SetSize(MAX_HISTORY);} /** Determines which replay mode is selected:
int GetCount () { return m_wrapped ? m_size : m_current+1; } * HISTORY_NONE: no history replay.
int GetCurrentIndex() { return m_current;} * HISTORY_POSITION: replay the positions and orientations of the karts,
int GetSize () { return m_size; } * but don't simulate the physics.
void SetSize (int n); * HISTORY_PHYSICS: Simulate the phyics based on the recorded actions.
void StoreDelta (float delta); * These values can be used together, e.g. HISTORY_POSITION|HISTORY_CONTROL
*/
enum HistoryReplayMode { HISTORY_NONE = 0,
HISTORY_POSITION = 1,
HISTORY_PHYSICS = 2 };
private:
// maximum number of history events to store
HistoryReplayMode m_replay_mode;
int m_current;
bool m_wrapped;
int m_size;
std::vector<float> m_all_deltas;
std::vector<KartControl> m_all_controls;
std::vector<Vec3> m_all_xyz;
std::vector<btQuaternion> m_all_rotations;
void allocateMemory(int number_of_frames);
void updateSaving(float dt);
void updateReplay(float dt);
public:
History ();
void startReplay ();
void initRecording ();
void update (float dt);
void Save (); void Save ();
void Load (); void Load ();
void LoadKartData (Kart* k, int kartNumber); float getNextDelta () const { return m_all_deltas[m_current]; }
float GetNextDelta ();
// ------------------------------------------------------------------------
/** Returns if a history is replayed, i.e. the history mode is not none. */
bool replayHistory () const { return m_replay_mode != HISTORY_NONE; }
// ------------------------------------------------------------------------
/** Enable replaying a history, enabled from the command line. */
void doReplayHistory(HistoryReplayMode m) {m_replay_mode = m; }
// ------------------------------------------------------------------------
/** Returns true if the physics should not be simulated in replay mode.
* I.e. either no replay mode, or physics replay mode. */
bool dontDoPhysics () const { return m_replay_mode == HISTORY_POSITION;}
}; };
extern History* history; extern History* history;

View File

@ -53,14 +53,16 @@
#include "utils/ssg_help.hpp" #include "utils/ssg_help.hpp"
Kart::Kart (const std::string& kart_name, int position,
const btTransform& init_transform)
: TerrainInfo(1),
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(WIN32) && !defined(__CYGWIN__)
// Disable warning for using 'this' in base member initializer list // Disable warning for using 'this' in base member initializer list
# pragma warning(disable:4355) # pragma warning(disable:4355)
#endif #endif
Moveable(true), m_attachment(this), m_collectable(this)
Kart::Kart (const std::string& kart_name, int position,
const btTransform& init_transform)
: TerrainInfo(1),
Moveable(), m_attachment(this), m_collectable(this)
#if defined(WIN32) && !defined(__CYGWIN__) #if defined(WIN32) && !defined(__CYGWIN__)
# pragma warning(1:4355) # pragma warning(1:4355)
#endif #endif

View File

@ -178,6 +178,8 @@ public:
float getSteerPercent () const {return m_controls.lr; } float getSteerPercent () const {return m_controls.lr; }
const KartControl& const KartControl&
getControls () const {return m_controls; } getControls () const {return m_controls; }
/** Sets the kart controls. Used e.g. by replaying history. */
void setControls(const KartControl &c) { m_controls = c; }
float getMaxSpeed () const {return m_max_speed; } float getMaxSpeed () const {return m_max_speed; }
void createPhysics (ssgEntity *obj); void createPhysics (ssgEntity *obj);
float getKartLength () const {return m_kart_properties->getKartLength();} float getKartLength () const {return m_kart_properties->getKartLength();}

View File

@ -60,23 +60,37 @@ public:
{ {
m->addFloat(lr); m->addFloat(lr);
m->addFloat(accel); m->addFloat(accel);
m->addChar( brake ? 1 : 0 m->addChar(getButtonsCompressed());
+ wheelie ? 2 : 0
+ jump ? 4 : 0
+ rescue ? 8 : 0
+ fire ? 16 : 0);
} // compress } // compress
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void uncompress(char *c) void uncompress(char *c)
{ {
lr = ((float*)c)[0]; lr = ((float*)c)[0];
accel = ((float*)c)[1]; accel = ((float*)c)[1];
brake = (c[8] & 1) != 0; setButtonsCompressed(c[8]);
wheelie = (c[8] & 2) != 0;
jump = (c[8] & 4) != 0;
rescue = (c[8] & 8) != 0;
fire = (c[8] & 16) != 0;
} // uncompress } // uncompress
// ------------------------------------------------------------------------
/** Compresses all buttons into a single integer value. */
char getButtonsCompressed() const
{
return brake ? 1 : 0
+ wheelie ? 2 : 0
+ jump ? 4 : 0
+ rescue ? 8 : 0
+ fire ? 16 : 0;
} // getButtonsCompressed
// ------------------------------------------------------------------------
/** Sets the buttons from a compressed representation.
* /param c Character containing the compressed representation.
*/
void setButtonsCompressed(char c)
{
brake = (c & 1) != 0;
wheelie = (c & 2) != 0;
jump = (c & 4) != 0;
rescue = (c & 8) != 0;
fire = (c & 16) != 0;
} // setButtonsCompressed
}; };
#endif #endif

View File

@ -109,6 +109,9 @@ void cmdLineHelp (char* invocation)
// " --profile=n Enable automatic driven profile mode for n seconds\n" // " --profile=n Enable automatic driven profile mode for n seconds\n"
// " if n<0 --> (-n) = number of laps to drive // " if n<0 --> (-n) = number of laps to drive
// " --history Replay history file 'history.dat'\n" // " --history Replay history file 'history.dat'\n"
// " --history=n Replay history file 'history.dat' using mode:\n"
// " n=1: use recorded positions\n"
// " n=2: use recorded key strokes\n"
" --server[=port] This is the server (running on the specified port)\n" " --server[=port] This is the server (running on the specified port)\n"
" --client=ip This is a client, connect to the specified ip address\n" " --client=ip This is a client, connect to the specified ip address\n"
" --port=n Port number to use\n" " --port=n Port number to use\n"
@ -374,7 +377,7 @@ int handleCmdLine(int argc, char **argv)
else if( !strcmp(argv[i], "--log=file")) else if( !strcmp(argv[i], "--log=file"))
{ {
user_config->m_log_errors=true; user_config->m_log_errors=true;
}else if( sscanf(argv[i], "--profile=%d", &n)==1) } else if( sscanf(argv[i], "--profile=%d", &n)==1)
{ {
user_config->m_profile=n; user_config->m_profile=n;
if(n<0) if(n<0)
@ -392,9 +395,13 @@ int handleCmdLine(int argc, char **argv)
{ {
user_config->m_profile=20; user_config->m_profile=20;
} }
else if( sscanf(argv[i], "--history=%d", &n)==1)
{
history->doReplayHistory( (History::HistoryReplayMode)n);
}
else if( !strcmp(argv[i], "--history") ) else if( !strcmp(argv[i], "--history") )
{ {
user_config->m_replay_history=true; history->doReplayHistory(History::HISTORY_POSITION);
} }
else if( !strcmp(argv[i], "--herring") && i+1<argc ) else if( !strcmp(argv[i], "--herring") && i+1<argc )
{ {
@ -519,7 +526,7 @@ int main(int argc, char *argv[] )
// Replay a race // Replay a race
// ============= // =============
if(user_config->m_replay_history) if(history->replayHistory())
{ {
// This will setup the race manager etc. // This will setup the race manager etc.
history->Load(); history->Load();

View File

@ -62,7 +62,7 @@ MainLoop::~MainLoop()
void MainLoop::run() void MainLoop::run()
{ {
const GLuint TITLE_SCREEN_TEXTURE = const GLuint TITLE_SCREEN_TEXTURE =
material_manager->getMaterial("st_title_screen.rgb")->getState()->getTextureHandle(); material_manager->getMaterial(stk_config->m_menu_background)->getState()->getTextureHandle();
bool music_on = false; bool music_on = false;
m_curr_time = SDL_GetTicks(); m_curr_time = SDL_GetTicks();
@ -134,6 +134,7 @@ void MainLoop::run()
if ( RaceManager::getWorld()->getPhase() != LIMBO_PHASE) if ( RaceManager::getWorld()->getPhase() != LIMBO_PHASE)
{ {
history->update(dt);
RaceManager::getWorld()->update(dt); RaceManager::getWorld()->update(dt);
if(user_config->m_profile>0) if(user_config->m_profile>0)
@ -146,7 +147,7 @@ void MainLoop::run()
printf("Number of frames: %d time %f, Average FPS: %f\n", printf("Number of frames: %d time %f, Average FPS: %f\n",
m_frame_count, SDL_GetTicks() * 0.001, m_frame_count, SDL_GetTicks() * 0.001,
(float)m_frame_count/(SDL_GetTicks() * 0.001)); (float)m_frame_count/(SDL_GetTicks() * 0.001));
if(!user_config->m_replay_history) history->Save(); if(!history->replayHistory()) history->Save();
std::exit(-2); std::exit(-2);
} // if profile finished } // if profile finished
} // if m_profile } // if m_profile

View File

@ -117,7 +117,8 @@ void TimedRace::update(const float dt)
m_auxiliary_timer += dt; m_auxiliary_timer += dt;
break; break;
case MUSIC_PHASE: case MUSIC_PHASE:
if(m_auxiliary_timer>TIME_MUSIC_DESCRIPTION) // how long to display the 'music' message // how long to display the 'music' message
if(m_auxiliary_timer>stk_config->m_music_credit_time)
m_phase=RACE_PHASE; m_phase=RACE_PHASE;
m_auxiliary_timer += dt; m_auxiliary_timer += dt;
break; break;
@ -126,7 +127,7 @@ void TimedRace::update(const float dt)
m_auxiliary_timer += dt; m_auxiliary_timer += dt;
// Nothing more to do if delay time is not over yet // Nothing more to do if delay time is not over yet
if(m_auxiliary_timer < TIME_DELAY_TILL_FINISH) break; if(m_auxiliary_timer < stk_config->m_delay_finish_time) break;
m_phase = FINISH_PHASE; m_phase = FINISH_PHASE;
break; break;

View File

@ -140,10 +140,7 @@ World::World() : TimedRace()
break; break;
} }
} // if !user_config->m_profile } // if !user_config->m_profile
if(user_config->m_replay_history)
{
history->LoadKartData(newkart, i);
}
newkart -> getModelTransform() -> clrTraversalMaskBits(SSGTRAV_ISECT|SSGTRAV_HOT); newkart -> getModelTransform() -> clrTraversalMaskBits(SSGTRAV_ISECT|SSGTRAV_HOT);
scene->add ( newkart -> getModelTransform() ) ; scene->add ( newkart -> getModelTransform() ) ;
@ -162,6 +159,7 @@ World::World() : TimedRace()
m_track->startMusic(); m_track->startMusic();
if(!history->replayHistory()) history->initRecording();
network_manager->worldLoaded(); network_manager->worldLoaded();
} // World } // World
@ -257,13 +255,17 @@ void World::resetAllKarts()
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void World::update(float dt) void World::update(float dt)
{ {
if(history->replayHistory()) dt=history->getNextDelta();
TimedRace::update(dt); TimedRace::update(dt);
// Clear race state so that new information can be stored // Clear race state so that new information can be stored
race_state->clear(); race_state->clear();
if(user_config->m_replay_history) dt=history->GetNextDelta();
if(!user_config->m_replay_history) history->StoreDelta(dt); if(network_manager->getMode()!=NetworkManager::NW_CLIENT &&
if(network_manager->getMode()!=NetworkManager::NW_CLIENT) m_physics->update(dt); !history->dontDoPhysics())
{
m_physics->update(dt);
}
const int kart_amount = m_kart.size(); const int kart_amount = m_kart.size();
for (int i = 0 ; i < kart_amount; ++i) for (int i = 0 ; i < kart_amount; ++i)
{ {

View File

@ -22,9 +22,8 @@
#include "material_manager.hpp" #include "material_manager.hpp"
#include "material.hpp" #include "material.hpp"
#include "user_config.hpp" #include "user_config.hpp"
#include "history.hpp"
Moveable::Moveable (bool bHasHistory) Moveable::Moveable()
{ {
m_body = 0; m_body = 0;
m_motion_state = 0; m_motion_state = 0;
@ -33,17 +32,6 @@ Moveable::Moveable (bool bHasHistory)
m_model_transform = new ssgTransform(); m_model_transform = new ssgTransform();
m_model_transform->ref(); m_model_transform->ref();
if(bHasHistory)
{
m_history_velocity = new sgCoord[history->GetSize()];
m_history_position = new sgCoord[history->GetSize()];
}
else
{
m_history_velocity = NULL;
m_history_position = NULL;
}
} // Moveable } // Moveable
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -52,11 +40,6 @@ Moveable::~Moveable()
// The body is being removed from the world in kart/projectile // The body is being removed from the world in kart/projectile
if(m_body) delete m_body; if(m_body) delete m_body;
if(m_motion_state) delete m_motion_state; if(m_motion_state) delete m_motion_state;
if(m_history_velocity)
{
delete [] m_history_velocity;
delete [] m_history_position;
}
// FIXME what about model? // FIXME what about model?
} // ~Moveable } // ~Moveable
@ -106,52 +89,6 @@ void Moveable::update (float dt)
m_velocityLC = getVelocity()*getTrans().getBasis(); m_velocityLC = getVelocity()*getTrans().getBasis();
m_hpr.setHPR(m_transform.getBasis()); m_hpr.setHPR(m_transform.getBasis());
if(m_history_velocity)
{
if(user_config->m_replay_history)
{
sgCoord tmp;
sgCopyCoord(&tmp, &(m_history_velocity[history->GetCurrentIndex()]));
#undef IGNORE_Z_IN_HISTORY
#ifdef IGNORE_Z_IN_HISTORY
const float DUMMY=m_velocity.xyz[2];
sgCopyCoord(&m_velocity, &tmp);
m_velocity.xyz[2]=DUMMY;
#else
m_velocityLC.setValue(tmp.xyz[0],tmp.xyz[1],tmp.xyz[2]);
#endif
}
else
{
m_history_velocity[history->GetCurrentIndex()].xyz[0]=m_velocityLC.getX();
m_history_velocity[history->GetCurrentIndex()].xyz[1]=m_velocityLC.getY();
m_history_velocity[history->GetCurrentIndex()].xyz[2]=m_velocityLC.getZ();
}
} // if m_history_velocity
if(m_history_position)
{
if(user_config->m_replay_history)
{
sgCoord tmp;
sgCopyCoord(&tmp, &(m_history_position[history->GetCurrentIndex()]));
Vec3 hpr(tmp.hpr);
hpr.degreeToRad();
btMatrix3x3 rotation;
rotation.setEulerZYX(hpr.getPitch(), hpr.getRoll(), hpr.getHeading());
m_transform.setBasis(rotation);
m_transform.setOrigin(Vec3(tmp.xyz));
}
else
{
Coord c(m_transform);
sgCopyCoord(&(m_history_position[history->GetCurrentIndex()]), &c.toSgCoord());
}
} // if m_history_position
updateGraphics(Vec3(0,0,0), Vec3(0,0,0)); updateGraphics(Vec3(0,0,0), Vec3(0,0,0));
m_first_time = false ; m_first_time = false ;
} // update } // update
@ -166,46 +103,3 @@ void Moveable::updateGraphics(const Vec3& off_xyz, const Vec3& off_hpr)
m_model_transform->setTransform(&c); m_model_transform->setTransform(&c);
} // updateGraphics } // updateGraphics
//-----------------------------------------------------------------------------
void Moveable::WriteHistory(char* s, int kartNumber, int indx)
{
sprintf(s, "Kart %d: v=%f,%f,%f,%f,%f,%f, p=%f,%f,%f,%f,%f,%f", kartNumber,
m_history_velocity[indx].xyz[0],
m_history_velocity[indx].xyz[1],
m_history_velocity[indx].xyz[2],
m_history_velocity[indx].hpr[0],
m_history_velocity[indx].hpr[1],
m_history_velocity[indx].hpr[2],
m_history_position[indx].xyz[0],
m_history_position[indx].xyz[1],
m_history_position[indx].xyz[2],
m_history_position[indx].hpr[0],
m_history_position[indx].hpr[1],
m_history_position[indx].hpr[2]);
} // WriteHistory
//-----------------------------------------------------------------------------
void Moveable::ReadHistory(char* s, int kartNumber, int indx)
{
int k;
sscanf(s, "Kart %d: v=%f,%f,%f,%f,%f,%f, p=%f,%f,%f,%f,%f,%f", &k,
m_history_velocity[indx].xyz+0,
m_history_velocity[indx].xyz+1,
m_history_velocity[indx].xyz+2,
m_history_velocity[indx].hpr+0,
m_history_velocity[indx].hpr+1,
m_history_velocity[indx].hpr+2,
m_history_position[indx].xyz+0,
m_history_position[indx].xyz+1,
m_history_position[indx].xyz+2,
m_history_position[indx].hpr+0,
m_history_position[indx].hpr+1,
m_history_position[indx].hpr+2);
if(k!=kartNumber)
{
fprintf(stderr,"WARNING: tried reading data for kart %d, found:\n",
kartNumber);
fprintf(stderr,"%s\n",s);
exit(-2);
}
} // ReadHistory

View File

@ -43,18 +43,16 @@ private:
Vec3 m_hpr; Vec3 m_hpr;
protected: protected:
UserPointer m_user_pointer; UserPointer m_user_pointer;
sgVec4* m_normal_hot; /* plane on which HOT was computed */ sgVec4 *m_normal_hot; /* plane on which HOT was computed */
Material* m_material_hot; /* Material at HOT */ Material *m_material_hot; /* Material at HOT */
ssgTransform* m_model_transform; // The transform where the model is under ssgTransform *m_model_transform; // The transform where the model is under
ssgTransform* m_shadow; ssgTransform *m_shadow;
int m_first_time ; int m_first_time ;
sgCoord* m_history_velocity; btRigidBody *m_body;
sgCoord* m_history_position; btDefaultMotionState *m_motion_state;
btRigidBody* m_body;
btDefaultMotionState* m_motion_state;
public: public:
Moveable (bool bHasHistory=false); Moveable ();
virtual ~Moveable(); virtual ~Moveable();
ssgTransform* getModelTransform() {return m_model_transform; } ssgTransform* getModelTransform() {return m_model_transform; }
@ -77,8 +75,6 @@ public:
virtual void handleZipper () {}; virtual void handleZipper () {};
virtual void reset (); virtual void reset ();
virtual void update (float dt) ; virtual void update (float dt) ;
void WriteHistory (char* s, int kartNumber, int indx);
void ReadHistory (char* s, int kartNumber, int indx);
btRigidBody* getBody () const {return m_body; } btRigidBody* getBody () const {return m_body; }
void createBody(float mass, btTransform& trans, void createBody(float mass, btTransform& trans,
btCollisionShape *shape); btCollisionShape *shape);

View File

@ -21,6 +21,7 @@
#include "constants.hpp" #include "constants.hpp"
#include "audio/sfx_manager.hpp" #include "audio/sfx_manager.hpp"
#include "audio/sfx_base.hpp" #include "audio/sfx_base.hpp"
#include "history.hpp"
#include "player_kart.hpp" #include "player_kart.hpp"
#include "player.hpp" #include "player.hpp"
#include "sdldrv.hpp" #include "sdldrv.hpp"
@ -169,7 +170,11 @@ void PlayerKart::steer(float dt, int steer_val)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void PlayerKart::update(float dt) void PlayerKart::update(float dt)
{ {
steer(dt, m_steer_val); // Don't do steering if it's replay. In position only replay it doesn't
// matter, but if it's physics replay the gradual steering causes
// incorrect results, since the stored values are already adjusted.
if(!history->replayHistory())
steer(dt, m_steer_val);
if(RaceManager::getWorld()->isStartPhase()) if(RaceManager::getWorld()->isStartPhase())
{ {

View File

@ -37,7 +37,7 @@ void STKConfig::load(const std::string filename)
// Check that all necessary values are indeed set // Check that all necessary values are indeed set
// ----------------------------------------------- // -----------------------------------------------
#define CHECK_NEG( a,strA) if(a==UNDEFINED) { \ #define CHECK_NEG( a,strA) if(a<=UNDEFINED) { \
fprintf(stderr,"Missing default value for '%s' in '%s'.\n", \ fprintf(stderr,"Missing default value for '%s' in '%s'.\n", \
strA,filename.c_str());exit(-1); \ strA,filename.c_str());exit(-1); \
} }
@ -69,6 +69,11 @@ void STKConfig::load(const std::string filename)
fprintf(stderr,"No follow leader interval(s) defined in stk_config"); fprintf(stderr,"No follow leader interval(s) defined in stk_config");
exit(-1); exit(-1);
} }
if(m_menu_background.size()==0)
{
fprintf(stderr,"No menu background defined in stk_config");
exit(-1);
}
CHECK_NEG(m_max_karts, "max-karts" ); CHECK_NEG(m_max_karts, "max-karts" );
CHECK_NEG(m_grid_order, "grid-order" ); CHECK_NEG(m_grid_order, "grid-order" );
@ -127,6 +132,9 @@ void STKConfig::load(const std::string filename)
CHECK_NEG(m_camera_max_accel, "camera-max-accel" ); CHECK_NEG(m_camera_max_accel, "camera-max-accel" );
CHECK_NEG(m_camera_max_brake, "camera-max-brake" ); CHECK_NEG(m_camera_max_brake, "camera-max-brake" );
CHECK_NEG(m_camera_distance, "camera-distance" ); CHECK_NEG(m_camera_distance, "camera-distance" );
CHECK_NEG(m_max_history, "max-history" );
CHECK_NEG(m_delay_finish_time, "delay-finish-time" );
CHECK_NEG(m_music_credit_time, "music-credit-time" );
} // load } // load
@ -147,7 +155,7 @@ void STKConfig::init_defaults()
m_wheelie_restore_rate = m_wheelie_speed_boost = m_wheelie_restore_rate = m_wheelie_speed_boost =
m_bomb_time = m_bomb_time_increase= m_anvil_time = m_bomb_time = m_bomb_time_increase= m_anvil_time =
m_zipper_time = m_zipper_force = m_zipper_speed_gain = m_zipper_time = m_zipper_force = m_zipper_speed_gain =
m_shortcut_length = m_shortcut_length = m_music_credit_time = m_delay_finish_time =
//bullet physics data //bullet physics data
m_suspension_stiffness = m_wheel_damping_relaxation = m_suspension_stiffness = m_wheel_damping_relaxation =
m_wheel_damping_compression = m_friction_slip = m_roll_influence = m_wheel_damping_compression = m_friction_slip = m_roll_influence =
@ -164,6 +172,7 @@ void STKConfig::init_defaults()
m_rear_wheel_connection = Vec3(UNDEFINED); m_rear_wheel_connection = Vec3(UNDEFINED);
m_max_karts = -100; m_max_karts = -100;
m_grid_order = -100; m_grid_order = -100;
m_max_history = -100;
m_title_music = NULL; m_title_music = NULL;
m_scores.clear(); m_scores.clear();
m_leader_intervals.clear(); m_leader_intervals.clear();
@ -193,7 +202,11 @@ void STKConfig::getAllData(const lisp::Lisp* lisp)
lisp->get("explosion-impulse-objects", m_explosion_impulse_objects); lisp->get("explosion-impulse-objects", m_explosion_impulse_objects);
lisp->get("max-karts", m_max_karts ); lisp->get("max-karts", m_max_karts );
lisp->get("grid-order", m_grid_order ); lisp->get("grid-order", m_grid_order );
lisp->getVector("scores", m_scores); lisp->getVector("scores", m_scores );
lisp->get("max-history", m_max_history );
lisp->get("delay-finish-time", m_delay_finish_time );
lisp->get("music-credit-time", m_music_credit_time );
lisp->get("menu-background", m_menu_background );
std::string title_music; std::string title_music;
lisp->get("title-music", title_music ); lisp->get("title-music", title_music );
m_title_music = new MusicInformation(file_manager->getMusicFile(title_music)); m_title_music = new MusicInformation(file_manager->getMusicFile(title_music));

View File

@ -21,39 +21,61 @@
#define HEADER_STKCONFIG_H #define HEADER_STKCONFIG_H
#include "kart_properties.hpp" #include "kart_properties.hpp"
#include "lisp/lisp.hpp"
class Lisp;
class MusicInformation; class MusicInformation;
/** Global STK configuration information. Parameters here can be tuned without
* recompilation, but the user shouldn't actually modify them. It also
* includes the list of default kart physics parameters which are used for
* each kart (but which can be overwritten for each kart, too).
*/
class STKConfig : public KartProperties class STKConfig : public KartProperties
{ {
public: public:
static float UNDEFINED; static float UNDEFINED;
float m_anvil_weight; // Additional kart weight if anvil is attached float m_anvil_weight; /**<Additional kart weight if anvil is
float m_anvil_speed_factor; // To decrease speed once when attached attached. */
float m_parachute_friction; // Increased air friction when parachute float m_anvil_speed_factor; /**<Speed decrease when attached first. */
float m_parachute_done_fraction; // fraction of speed when lost will detach parachute float m_parachute_friction; /**<Increased parachute air friction. */
float m_parachute_time; // time a parachute is active float m_parachute_done_fraction; /**<Fraction of speed when lost will
float m_parachute_time_other; // time a parachute attached to other karts is active detach parachute. */
float m_bomb_time; // time before a bomb explodes float m_parachute_time; /**<Time a parachute is active. */
float m_bomb_time_increase; // time added to bomb timer when it's passed on float m_parachute_time_other; /**<Time a parachute attached to other
float m_anvil_time; // time an anvil is active karts is active. */
float m_zipper_time; // duration a zipper is active float m_bomb_time; /**<Time before a bomb explodes. */
float m_zipper_force; // additional force added to the acceleration float m_bomb_time_increase; /**<Time added to bomb timer when it's
float m_zipper_speed_gain; // initial one time speed gain passed on. */
float m_shortcut_length; // skipping more than this number of segments is float m_anvil_time; /**<Time an anvil is active. */
// considered to be a shortcut float m_zipper_time; /**<Duration a zipper is active. */
float m_explosion_impulse; // impulse affecting each non-hit kart float m_zipper_force; /**<Additional force added to the
float m_explosion_impulse_objects;// impulse of explosion on moving objects, e.g. road cones, ... acceleration. */
int m_max_karts; // maximum number of karts float m_zipper_speed_gain; /**<Initial one time speed gain. */
int m_grid_order; // whether grand prix grid is in point or reverse point order float m_shortcut_length; /**<Skipping more than this distance
in segments triggers a shortcut. */
float m_explosion_impulse; /**<Impulse affecting each non-hit kart.*/
float m_explosion_impulse_objects;/**<Impulse of explosion on moving
objects, e.g. road cones, ... */
float m_delay_finish_time; /**<Delay after a race finished before
the results are displayed. */
float m_music_credit_time; /**<Time the music credits are
displayed. */
int m_max_karts; /**<Maximum number of karts. */
int m_grid_order; /**<Whether grand prix grid is in point
or reverse point order. */
int m_max_history; /**<Maximum number of frames to save in
a history files. */
std::vector<float> std::vector<float>
m_leader_intervals; // interval in follow the leader till last kart is reomved m_leader_intervals; /**<Interval in follow the leader till
std::vector<int> m_scores; // scores depending on position last kart is reomved. */
std::vector<int> m_scores; /**<Scores depending on position. */
MusicInformation* m_title_music; // filename of the title music to play MusicInformation* m_title_music; /**<Filename of the title music to play.*/
std::string m_menu_background; /**<Picture used as menu background. */
STKConfig() : KartProperties() {}; /** Empty constructor. The actual work is done in load. */
STKConfig() : KartProperties() {};
void init_defaults (); void init_defaults ();
void getAllData (const lisp::Lisp* lisp); void getAllData (const lisp::Lisp* lisp);
void load (const std::string filename); void load (const std::string filename);

View File

@ -444,16 +444,17 @@ btTransform Track::getStartTransform(unsigned int pos) const {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/** Determines if a kart moving from sector OLDSEC to sector NEWSEC /** Determines if a kart moving from sector OLDSEC to sector NEWSEC
* would be taking a shortcut, i.e. if the distance is larger * would be taking a shortcut, i.e. if the distance is larger
* than a certain detla * than a certain delta
*/ */
bool Track::isShortcut(const int OLDSEC, const int NEWSEC) const bool Track::isShortcut(const int OLDSEC, const int NEWSEC) const
{ {
// If the kart was off the road, don't do any shortcuts // If the kart was off the road, don't do any shortcuts
if(OLDSEC==UNKNOWN_SECTOR || NEWSEC==UNKNOWN_SECTOR) return false; if(OLDSEC==UNKNOWN_SECTOR || NEWSEC==UNKNOWN_SECTOR) return false;
int distance_sectors = m_distance_from_start[std::max(NEWSEC, OLDSEC)] - m_distance_from_start[std::min(NEWSEC, OLDSEC)]; int distance_sectors = (int)(m_distance_from_start[std::max(NEWSEC, OLDSEC)] -
m_distance_from_start[std::min(NEWSEC, OLDSEC)] );
// Handle 'warp around' // Handle 'warp around'
const int track_length = m_distance_from_start[m_driveline.size()-1]; const int track_length = (int)m_distance_from_start[m_driveline.size()-1];
if( distance_sectors < 0 ) distance_sectors += track_length; if( distance_sectors < 0 ) distance_sectors += track_length;
else if( distance_sectors > track_length/2) distance_sectors -= track_length; else if( distance_sectors > track_length/2) distance_sectors -= track_length;

View File

@ -109,7 +109,6 @@ void UserConfig::setDefaults()
m_max_fps = 120; m_max_fps = 120;
m_sfx_volume = 1.0f; m_sfx_volume = 1.0f;
m_use_kph = false; m_use_kph = false;
m_replay_history = false;
m_width = 800; m_width = 800;
m_height = 600; m_height = 600;
m_prev_width = m_width; m_prev_width = m_width;

View File

@ -180,7 +180,6 @@ public:
std::string m_track_group; // Track group used last std::string m_track_group; // Track group used last
std::string m_server_address; std::string m_server_address;
int m_server_port; int m_server_port;
bool m_replay_history;
bool m_use_kph; bool m_use_kph;
int m_width; int m_width;
int m_height; int m_height;