2007-05-27 12:01:53 -04:00
|
|
|
// $Id$
|
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
|
|
|
// Copyright (C) 2006 SuperTuxKart-Team
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <ctime>
|
|
|
|
|
|
|
|
#include "world.hpp"
|
|
|
|
#include "herring_manager.hpp"
|
|
|
|
#include "projectile_manager.hpp"
|
|
|
|
#include "gui/menu_manager.hpp"
|
2008-02-29 22:18:53 -05:00
|
|
|
#include "file_manager.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
#include "player_kart.hpp"
|
|
|
|
#include "auto_kart.hpp"
|
|
|
|
#include "track.hpp"
|
|
|
|
#include "kart_properties_manager.hpp"
|
|
|
|
#include "track_manager.hpp"
|
|
|
|
#include "race_manager.hpp"
|
|
|
|
#include "user_config.hpp"
|
|
|
|
#include "callback_manager.hpp"
|
|
|
|
#include "history.hpp"
|
|
|
|
#include "constants.hpp"
|
|
|
|
#include "sound_manager.hpp"
|
|
|
|
#include "translation.hpp"
|
|
|
|
#include "highscore_manager.hpp"
|
|
|
|
#include "scene.hpp"
|
2007-09-19 06:54:27 -04:00
|
|
|
#include "camera.hpp"
|
2007-05-27 12:01:53 -04:00
|
|
|
#include "robots/default_robot.hpp"
|
2008-03-26 22:38:10 -04:00
|
|
|
#include "unlock_manager.hpp"
|
2007-09-19 05:23:02 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
# include "replay_player.hpp"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
#if defined(WIN32) && !defined(__CYGWIN__)
|
|
|
|
# define snprintf _snprintf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
World* world = 0;
|
|
|
|
|
|
|
|
World::World(const RaceSetup& raceSetup_) : m_race_setup(raceSetup_)
|
2007-09-19 05:23:02 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
, m_p_replay_player(NULL)
|
|
|
|
#endif
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
delete world;
|
|
|
|
world = this;
|
2008-02-12 20:02:02 -05:00
|
|
|
m_phase = SETUP_PHASE;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
m_track = NULL;
|
|
|
|
|
|
|
|
m_clock = 0.0f;
|
|
|
|
m_fastest_lap = 9999999.9f;
|
|
|
|
m_fastest_kart = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Grab the track file
|
|
|
|
try
|
|
|
|
{
|
|
|
|
m_track = track_manager->getTrack(m_race_setup.m_track) ;
|
|
|
|
}
|
|
|
|
catch(std::runtime_error)
|
|
|
|
{
|
|
|
|
char msg[MAX_ERROR_MESSAGE_LENGTH];
|
|
|
|
snprintf(msg, sizeof(msg),
|
|
|
|
"Track '%s' not found.\n",m_race_setup.m_track.c_str());
|
|
|
|
throw std::runtime_error(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the physics
|
|
|
|
m_physics = new Physics(getGravity());
|
|
|
|
|
|
|
|
assert(m_race_setup.m_karts.size() > 0);
|
|
|
|
|
|
|
|
// Load the track models - this must be done before the karts so that the
|
|
|
|
// karts can be positioned properly on (and not in) the tracks.
|
2007-12-12 09:07:26 -05:00
|
|
|
loadTrack() ;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
int pos = 0;
|
|
|
|
int playerIndex = 0;
|
|
|
|
for (RaceSetup::Karts::iterator i = m_race_setup.m_karts.begin() ;
|
|
|
|
i != m_race_setup.m_karts.end() ; ++i )
|
|
|
|
{
|
2007-09-25 23:43:02 -04:00
|
|
|
sgCoord init_pos;
|
|
|
|
m_track->getStartCoords(pos, &init_pos);
|
2007-05-27 12:01:53 -04:00
|
|
|
Kart* newkart;
|
|
|
|
if(user_config->m_profile)
|
|
|
|
{
|
|
|
|
// In profile mode, load only the old kart
|
|
|
|
newkart = new DefaultRobot (kart_properties_manager->getKart("tuxkart"), pos,
|
2007-11-03 09:13:26 -04:00
|
|
|
init_pos);
|
2008-02-17 07:58:12 -05:00
|
|
|
// Create a camera for the last kart (since this way more of the
|
|
|
|
// karts can be seen.
|
|
|
|
if((i+1)==m_race_setup.m_karts.end())
|
|
|
|
{
|
|
|
|
scene->createCamera(m_race_setup.getNumPlayers(), playerIndex);
|
|
|
|
}
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (std::find(m_race_setup.m_players.begin(),
|
|
|
|
m_race_setup.m_players.end(), pos) != m_race_setup.m_players.end())
|
|
|
|
{
|
2007-09-19 06:54:27 -04:00
|
|
|
|
|
|
|
Camera *cam = scene->createCamera(m_race_setup.getNumPlayers(), playerIndex);
|
2007-05-27 12:01:53 -04:00
|
|
|
// the given position belongs to a player
|
|
|
|
newkart = new PlayerKart (kart_properties_manager->getKart(*i), pos,
|
2007-09-19 06:54:27 -04:00
|
|
|
&(user_config->m_player[playerIndex]),
|
|
|
|
init_pos, cam);
|
|
|
|
playerIndex++;
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
newkart = loadRobot(kart_properties_manager->getKart(*i), pos,
|
2007-11-03 09:13:26 -04:00
|
|
|
init_pos);
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
} // if !user_config->m_profile
|
|
|
|
if(user_config->m_replay_history)
|
|
|
|
{
|
|
|
|
history->LoadKartData(newkart, pos);
|
|
|
|
}
|
2007-12-08 08:04:56 -05:00
|
|
|
newkart -> getModelTransform() -> clrTraversalMaskBits(SSGTRAV_ISECT|SSGTRAV_HOT);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2007-12-08 08:04:56 -05:00
|
|
|
scene->add ( newkart -> getModelTransform() ) ;
|
2007-05-27 12:01:53 -04:00
|
|
|
m_kart.push_back(newkart);
|
|
|
|
pos++;
|
|
|
|
} // for i
|
|
|
|
|
|
|
|
resetAllKarts();
|
|
|
|
|
|
|
|
#ifdef SSG_BACKFACE_COLLISIONS_SUPPORTED
|
|
|
|
//ssgSetBackFaceCollisions ( m_race_setup.mirror ) ;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Highscores::HighscoreType hst = (m_race_setup.m_mode==RaceSetup::RM_TIME_TRIAL)
|
|
|
|
? Highscores::HST_TIMETRIAL_OVERALL_TIME
|
|
|
|
: Highscores::HST_RACE_OVERALL_TIME;
|
|
|
|
|
2007-12-12 09:07:26 -05:00
|
|
|
m_highscores = highscore_manager->getHighscores(hst, (int)m_kart.size(),
|
2007-05-27 12:01:53 -04:00
|
|
|
m_race_setup.m_difficulty,
|
|
|
|
m_track->getName(),
|
|
|
|
m_race_setup.m_num_laps);
|
|
|
|
|
|
|
|
callback_manager->initAll();
|
|
|
|
menu_manager->switchToRace();
|
|
|
|
|
2008-03-14 05:49:17 -04:00
|
|
|
m_track->playMusic();
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2008-02-12 20:02:02 -05:00
|
|
|
m_phase = user_config->m_profile ? RACE_PHASE : SETUP_PHASE;
|
2007-09-19 05:23:02 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
m_replay_recorder.initRecorder( m_race_setup.getNumKarts() );
|
2007-09-21 14:02:53 -04:00
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
m_p_replay_player = new ReplayPlayer;
|
2007-09-19 14:28:48 -04:00
|
|
|
if( !loadReplayHumanReadable( "test1" ) )
|
2007-11-03 09:13:26 -04:00
|
|
|
{
|
|
|
|
delete m_p_replay_player;
|
|
|
|
m_p_replay_player = NULL;
|
|
|
|
}
|
|
|
|
if( m_p_replay_player ) m_p_replay_player->showReplayAt( 0.0 );
|
2007-09-19 05:23:02 -04:00
|
|
|
#endif
|
2007-12-08 08:04:56 -05:00
|
|
|
} // World
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
World::~World()
|
|
|
|
{
|
2007-09-19 05:23:02 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
saveReplayHumanReadable( "test" );
|
|
|
|
#endif
|
2007-12-12 09:07:26 -05:00
|
|
|
m_track->cleanup();
|
2007-12-08 08:04:56 -05:00
|
|
|
// Clear all callbacks
|
|
|
|
callback_manager->clear(CB_TRACK);
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
for ( unsigned int i = 0 ; i < m_kart.size() ; i++ )
|
|
|
|
delete m_kart[i];
|
|
|
|
|
|
|
|
m_kart.clear();
|
|
|
|
projectile_manager->cleanup();
|
|
|
|
delete m_physics;
|
|
|
|
|
|
|
|
sound_manager -> stopMusic();
|
|
|
|
|
|
|
|
sgVec3 sun_pos;
|
|
|
|
sgVec4 ambient_col, specular_col, diffuse_col;
|
|
|
|
sgSetVec3 ( sun_pos, 0.0f, 0.0f, 1.0f );
|
|
|
|
sgSetVec4 ( ambient_col , 0.2f, 0.2f, 0.2f, 1.0f );
|
|
|
|
sgSetVec4 ( specular_col, 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
sgSetVec4 ( diffuse_col , 1.0f, 1.0f, 1.0f, 1.0f );
|
|
|
|
|
|
|
|
ssgGetLight ( 0 ) -> setPosition ( sun_pos ) ;
|
|
|
|
ssgGetLight ( 0 ) -> setColour ( GL_AMBIENT , ambient_col ) ;
|
|
|
|
ssgGetLight ( 0 ) -> setColour ( GL_DIFFUSE , diffuse_col ) ;
|
|
|
|
ssgGetLight ( 0 ) -> setColour ( GL_SPECULAR, specular_col ) ;
|
2007-09-19 05:23:02 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
m_replay_recorder.destroy();
|
2007-11-03 09:13:26 -04:00
|
|
|
if( m_p_replay_player )
|
|
|
|
{
|
|
|
|
m_p_replay_player->destroy();
|
|
|
|
delete m_p_replay_player;
|
|
|
|
m_p_replay_player = NULL;
|
|
|
|
}
|
2007-09-19 05:23:02 -04:00
|
|
|
#endif
|
2007-11-03 09:13:26 -04:00
|
|
|
} // ~World
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Waits till each kart is resting on the ground
|
|
|
|
*
|
|
|
|
* Does simulation steps still all karts reach the ground, i.e. are not
|
|
|
|
* moving anymore
|
|
|
|
*/
|
|
|
|
void World::resetAllKarts()
|
|
|
|
{
|
|
|
|
bool all_finished=false;
|
2008-02-12 22:42:18 -05:00
|
|
|
// kart->isInRest() is not fully correct, since it only takes the
|
|
|
|
// velocity in count, which might be close to zero when the kart
|
|
|
|
// is just hitting the floor, before being pushed up again by
|
|
|
|
// the suspension. So we just do a longer initial simulation,
|
|
|
|
// which should be long enough for all karts to be firmly on ground.
|
|
|
|
for(int i=0; i<100; i++) m_physics->update(1.f/60.f);
|
2007-05-27 12:01:53 -04:00
|
|
|
while(!all_finished)
|
|
|
|
{
|
2007-11-21 20:20:57 -05:00
|
|
|
m_physics->update(1.f/60.f);
|
2007-05-27 12:01:53 -04:00
|
|
|
all_finished=true;
|
|
|
|
for ( Karts::iterator i=m_kart.begin(); i!=m_kart.end(); i++)
|
|
|
|
{
|
|
|
|
if(!(*i)->isInRest())
|
|
|
|
{
|
|
|
|
all_finished=false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // while
|
2008-01-29 23:36:00 -05:00
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
} // resetAllKarts
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2007-12-12 09:07:26 -05:00
|
|
|
void World::update(float dt)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2007-12-12 09:07:26 -05:00
|
|
|
if(user_config->m_replay_history) dt=history->GetNextDelta();
|
2008-02-12 20:02:02 -05:00
|
|
|
updateRaceStatus(dt);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
if( getPhase() == FINISH_PHASE )
|
|
|
|
{
|
|
|
|
// Add times to highscore list. First compute the order of karts,
|
|
|
|
// so that the timing of the fastest kart is added first (otherwise
|
|
|
|
// someone might get into the highscore list, only to be kicked out
|
|
|
|
// again by a faster kart in the same race), which might be confusing
|
|
|
|
// if we ever decide to display a message (e.g. during a race)
|
|
|
|
unsigned int *index = new unsigned int[m_kart.size()];
|
|
|
|
for (unsigned int i=0; i<m_kart.size(); i++ )
|
|
|
|
{
|
|
|
|
index[m_kart[i]->getPosition()-1] = i;
|
|
|
|
}
|
|
|
|
|
2007-06-04 23:45:43 -04:00
|
|
|
// Don't record the time for the last kart, since it didn't finish
|
|
|
|
// the race - unless it's timetrial (then there is only one kart)
|
2007-12-12 09:07:26 -05:00
|
|
|
unsigned int karts_to_enter = (m_race_setup.m_mode==RaceSetup::RM_TIME_TRIAL)
|
|
|
|
? (unsigned int)m_kart.size() : (unsigned int)m_kart.size()-1;
|
2007-06-04 23:45:43 -04:00
|
|
|
for(unsigned int pos=0; pos<karts_to_enter; pos++)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
// Only record times for player karts
|
|
|
|
if(!m_kart[index[pos]]->isPlayerKart()) continue;
|
|
|
|
|
|
|
|
PlayerKart *k = (PlayerKart*)m_kart[index[pos]];
|
|
|
|
|
|
|
|
Highscores::HighscoreType hst = (m_race_setup.m_mode==RaceSetup::RM_TIME_TRIAL)
|
|
|
|
? Highscores::HST_TIMETRIAL_OVERALL_TIME
|
|
|
|
: Highscores::HST_RACE_OVERALL_TIME;
|
2007-12-12 09:07:26 -05:00
|
|
|
if(m_highscores->addData(hst, (int)m_kart.size(),
|
2007-11-03 09:13:26 -04:00
|
|
|
m_race_setup.m_difficulty,
|
|
|
|
m_track->getName(),
|
|
|
|
k->getName(),
|
|
|
|
k->getPlayer()->getName(),
|
|
|
|
k->getFinishTime(),
|
|
|
|
m_race_setup.m_num_laps)>0)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
highscore_manager->Save();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete []index;
|
2007-06-09 21:13:39 -04:00
|
|
|
pause();
|
2007-05-27 12:01:53 -04:00
|
|
|
menu_manager->pushMenu(MENUID_RACERESULT);
|
|
|
|
}
|
2007-12-12 09:07:26 -05:00
|
|
|
if(!user_config->m_replay_history) history->StoreDelta(dt);
|
|
|
|
m_physics->update(dt);
|
|
|
|
for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2007-12-12 09:07:26 -05:00
|
|
|
m_kart[i]->update(dt) ;
|
|
|
|
}
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2007-12-12 09:07:26 -05:00
|
|
|
projectile_manager->update(dt);
|
|
|
|
herring_manager->update(dt);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
|
|
|
|
{
|
|
|
|
if(!m_kart[i]->raceIsFinished()) updateRacePosition((int)i);
|
|
|
|
m_kart[i]->addMessages();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Routine stuff we do even when paused */
|
2007-12-12 09:07:26 -05:00
|
|
|
callback_manager->update(dt);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
2007-09-19 05:23:02 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
2007-11-03 09:13:26 -04:00
|
|
|
// we start recording after START_PHASE, since during start-phase m_clock is incremented
|
|
|
|
// normally, but after switching to RACE_PHASE m_clock is set back to 0.0
|
2008-02-12 20:02:02 -05:00
|
|
|
if( m_phase == GO_PHASE )
|
2007-11-03 09:13:26 -04:00
|
|
|
{
|
|
|
|
m_replay_recorder.pushFrame();
|
|
|
|
if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock );
|
|
|
|
}
|
2007-09-19 05:23:02 -04:00
|
|
|
#endif
|
2007-05-27 12:01:53 -04:00
|
|
|
}
|
|
|
|
|
2007-09-19 05:23:02 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool World::saveReplayHumanReadable( std::string const &filename ) const
|
|
|
|
{
|
|
|
|
std::string path;
|
2008-02-29 22:18:53 -05:00
|
|
|
path = file_manager->getReplayFile(filename+"."+ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
|
2007-09-19 05:23:02 -04:00
|
|
|
|
|
|
|
FILE *fd = fopen( path.c_str(), "w" );
|
|
|
|
if( !fd )
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("Error while opening replay file for writing '%s'\n"), path.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int nKarts = world->getNumKarts();
|
|
|
|
const char *version = "unknown";
|
|
|
|
#ifdef VERSION
|
|
|
|
version = VERSION;
|
|
|
|
#endif
|
|
|
|
fprintf(fd, "Version: %s\n", version);
|
|
|
|
fprintf(fd, "numkarts: %d\n", m_kart.size());
|
|
|
|
fprintf(fd, "numplayers: %d\n", m_race_setup.getNumPlayers());
|
|
|
|
fprintf(fd, "difficulty: %d\n", m_race_setup.m_difficulty);
|
2008-02-26 20:11:02 -05:00
|
|
|
fprintf(fd, "track: %s\n", m_track->getIdent().c_str());
|
2007-09-21 14:02:53 -04:00
|
|
|
|
|
|
|
for (RaceSetup::Karts::const_iterator i = m_race_setup.m_karts.begin() ;
|
|
|
|
i != m_race_setup.m_karts.end() ; ++i )
|
2007-09-19 05:23:02 -04:00
|
|
|
{
|
2007-09-21 14:02:53 -04:00
|
|
|
fprintf(fd, "model %d: %s\n", i-m_race_setup.m_karts.begin(), (*i).c_str());
|
2007-09-19 05:23:02 -04:00
|
|
|
}
|
|
|
|
if( !m_replay_recorder.saveReplayHumanReadable( fd ) )
|
|
|
|
{
|
|
|
|
fclose( fd ); fd = NULL;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose( fd ); fd = NULL;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} // saveReplayHumanReadable
|
|
|
|
#endif // HAVE_GHOST_REPLAY
|
|
|
|
|
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool World::loadReplayHumanReadable( std::string const &filename )
|
|
|
|
{
|
2007-09-19 14:28:48 -04:00
|
|
|
assert( m_p_replay_player );
|
|
|
|
m_p_replay_player->destroy();
|
2007-09-19 05:23:02 -04:00
|
|
|
|
2008-02-29 22:18:53 -05:00
|
|
|
std::string path = file_manager->getReplayFile(filename+"."+
|
2008-02-25 21:30:28 -05:00
|
|
|
ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
|
2007-09-19 05:23:02 -04:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
2008-02-29 22:18:53 -05:00
|
|
|
path = file_manager->getPath(path.c_str());
|
2007-09-19 05:23:02 -04:00
|
|
|
}
|
|
|
|
catch(std::runtime_error& e)
|
|
|
|
{
|
|
|
|
fprintf( stderr, _("Couldn't find replay-file: '%s'\n"), path.c_str() );
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
FILE *fd = fopen( path.c_str(), "r" );
|
|
|
|
if( !fd )
|
|
|
|
{
|
|
|
|
fprintf(stderr, _("Error while opening replay file for loading '%s'\n"), path.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-09-21 14:02:53 -04:00
|
|
|
bool blnRet = m_p_replay_player->loadReplayHumanReadable( fd );
|
2007-09-19 05:23:02 -04:00
|
|
|
|
|
|
|
fclose( fd ); fd = NULL;
|
|
|
|
|
|
|
|
return blnRet;
|
|
|
|
} // loadReplayHumanReadable
|
|
|
|
#endif // HAVE_GHOST_REPLAY
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2008-02-12 20:02:02 -05:00
|
|
|
void World::updateRaceStatus(float dt)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
2008-02-12 20:02:02 -05:00
|
|
|
switch (m_phase) {
|
|
|
|
case SETUP_PHASE: m_clock=0.0f; m_phase=READY_PHASE;
|
|
|
|
dt = 0.0f; // solves the problem of adding track loading time
|
|
|
|
break; // loading time, don't play sound yet
|
|
|
|
case READY_PHASE: if(m_clock==0.0) // play sound at beginning of next frame
|
|
|
|
sound_manager->playSfx(SOUND_PRESTART);
|
|
|
|
if(m_clock>1.0)
|
|
|
|
{
|
|
|
|
m_phase=SET_PHASE;
|
|
|
|
sound_manager->playSfx(SOUND_PRESTART);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SET_PHASE : if(m_clock>2.0)
|
|
|
|
{
|
|
|
|
m_phase=GO_PHASE;
|
|
|
|
m_clock=0.0f;
|
|
|
|
sound_manager->playSfx(SOUND_START);
|
|
|
|
// Reset the brakes now that the prestart
|
|
|
|
// phase is over (braking prevents the karts
|
|
|
|
// from sliding downhill)
|
|
|
|
for(unsigned int i=0; i<m_kart.size(); i++)
|
|
|
|
{
|
|
|
|
m_kart[i]->resetBrakes();
|
|
|
|
}
|
2007-09-21 14:02:53 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
2008-02-12 20:02:02 -05:00
|
|
|
// push positions at time 0.0 to replay-data
|
|
|
|
m_replay_recorder.pushFrame();
|
2007-09-21 14:02:53 -04:00
|
|
|
#endif
|
2008-02-12 20:02:02 -05:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case GO_PHASE : if(m_clock>1.0) m_phase=RACE_PHASE; break;
|
|
|
|
default : break;
|
|
|
|
} // switch
|
|
|
|
m_clock += dt;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
/*if all players have finished, or if only one kart is not finished when
|
|
|
|
not in time trial mode, the race is over. Players are the last in the
|
|
|
|
vector, so substracting the number of players finds the first player's
|
|
|
|
position.*/
|
|
|
|
int new_finished_karts = 0;
|
|
|
|
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
|
|
|
|
{
|
2008-02-07 23:43:35 -05:00
|
|
|
// FIXME: this part should be done as part of Kart::update
|
2007-05-27 12:01:53 -04:00
|
|
|
if ((m_kart[i]->getLap () >= m_race_setup.m_num_laps) && !m_kart[i]->raceIsFinished())
|
|
|
|
{
|
|
|
|
m_kart[i]->setFinishingState(m_clock);
|
|
|
|
|
|
|
|
race_manager->addKartScore((int)i, m_kart[i]->getPosition());
|
2008-02-09 15:23:14 -05:00
|
|
|
race_manager->addKartOverallTime((int) i, m_clock);
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
++new_finished_karts;
|
|
|
|
if(m_kart[i]->isPlayerKart())
|
|
|
|
{
|
|
|
|
race_manager->PlayerFinishes();
|
|
|
|
RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
|
|
|
|
if(m)
|
|
|
|
{
|
|
|
|
m->addMessage(m_kart[i]->getPosition()==1
|
|
|
|
? _("You won")
|
|
|
|
: _("You finished") ,
|
|
|
|
m_kart[i], 2.0f, 60);
|
|
|
|
m->addMessage( _("the race!"), m_kart[i], 2.0f, 60);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
race_manager->addFinishedKarts(new_finished_karts);
|
2008-02-07 23:43:35 -05:00
|
|
|
|
|
|
|
// 1) All karts are finished --> end the race
|
|
|
|
// ==========================================
|
|
|
|
if(race_manager->getFinishedKarts() >= m_race_setup.getNumKarts() )
|
|
|
|
{
|
|
|
|
m_phase = FINISH_PHASE;
|
2008-02-17 23:16:57 -05:00
|
|
|
if(user_config->m_profile<0) // profiling number of laps -> print stats
|
2008-02-17 07:58:12 -05:00
|
|
|
{
|
2008-02-17 23:16:57 -05:00
|
|
|
float min_t=999999.9f, max_t=0.0, av_t=0.0;
|
2008-02-17 07:58:12 -05:00
|
|
|
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
|
|
|
|
{
|
|
|
|
max_t = std::max(max_t, m_kart[i]->getFinishTime());
|
|
|
|
min_t = std::min(min_t, m_kart[i]->getFinishTime());
|
2008-02-17 23:16:57 -05:00
|
|
|
av_t += m_kart[i]->getFinishTime();
|
|
|
|
printf("%s start %d end %d time %f\n",
|
2008-02-17 07:58:12 -05:00
|
|
|
m_kart[i]->getName().c_str(),(int)i,
|
|
|
|
m_kart[i]->getPosition(),
|
|
|
|
m_kart[i]->getFinishTime());
|
2008-02-17 23:16:57 -05:00
|
|
|
}
|
|
|
|
printf("min %f max %f av %f\n",min_t, max_t, av_t/m_kart.size());
|
2008-02-17 07:58:12 -05:00
|
|
|
std::exit(-2);
|
2008-02-17 23:16:57 -05:00
|
|
|
}
|
|
|
|
} // if all karts are finished
|
2008-02-07 23:43:35 -05:00
|
|
|
|
|
|
|
// 2) All player karts are finished --> wait some
|
|
|
|
// time for AI karts to arrive before finishing
|
|
|
|
// ===============================================
|
2008-02-17 07:58:12 -05:00
|
|
|
else if(race_manager->allPlayerFinished() && m_phase == RACE_PHASE &&
|
|
|
|
!user_config->m_profile)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
m_phase = DELAY_FINISH_PHASE;
|
|
|
|
m_finish_delay_start_time = m_clock;
|
|
|
|
}
|
2008-02-07 23:43:35 -05:00
|
|
|
|
|
|
|
// 3) If the 'wait for AI' time is over, estimate arrival times & finish
|
|
|
|
// =====================================================================
|
2007-05-27 12:01:53 -04:00
|
|
|
else if(m_phase==DELAY_FINISH_PHASE &&
|
2008-02-17 07:58:12 -05:00
|
|
|
m_clock-m_finish_delay_start_time>TIME_DELAY_TILL_FINISH &&
|
|
|
|
!user_config->m_profile)
|
2007-05-27 12:01:53 -04:00
|
|
|
{
|
|
|
|
m_phase = FINISH_PHASE;
|
|
|
|
for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
|
|
|
|
{
|
|
|
|
if(!m_kart[i]->raceIsFinished())
|
|
|
|
{
|
2008-02-09 15:23:14 -05:00
|
|
|
const float est_finish_time = m_kart[i]->estimateFinishTime();
|
|
|
|
m_kart[i]->setFinishingState(est_finish_time);
|
2007-05-27 12:01:53 -04:00
|
|
|
race_manager->addKartScore((int)i, m_kart[i]->getPosition());
|
2008-02-09 15:23:14 -05:00
|
|
|
race_manager->addKartOverallTime((int) i, est_finish_time);
|
2007-05-27 12:01:53 -04:00
|
|
|
} // if !raceIsFinished
|
|
|
|
} // for i
|
|
|
|
}
|
2008-03-26 22:38:10 -04:00
|
|
|
if(m_phase==FINISH_PHASE) unlock_manager->raceFinished();
|
2008-02-12 20:02:02 -05:00
|
|
|
} // updateRaceStatus
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void World::updateRacePosition ( int k )
|
|
|
|
{
|
|
|
|
int p = 1 ;
|
|
|
|
|
|
|
|
/* Find position of kart 'k' */
|
|
|
|
|
|
|
|
for ( Karts::size_type j = 0 ; j < m_kart.size() ; ++j )
|
|
|
|
{
|
|
|
|
if ( int(j) == k ) continue ;
|
|
|
|
|
|
|
|
// Count karts ahead of the current kart, i.e. kart that are already
|
|
|
|
// finished (the current kart k has not yet finished!!), have done more
|
|
|
|
// laps, or the same number of laps, but a greater distance.
|
|
|
|
if (m_kart[j]->raceIsFinished() ||
|
|
|
|
m_kart[j]->getLap() > m_kart[k]->getLap() ||
|
|
|
|
(m_kart[j]->getLap() == m_kart[k]->getLap() &&
|
|
|
|
m_kart[j]->getDistanceDownTrack() > m_kart[k]->getDistanceDownTrack()) )
|
|
|
|
p++ ;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_kart [ k ] -> setPosition ( p ) ;
|
|
|
|
} // updateRacePosition
|
|
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void World::loadTrack()
|
|
|
|
{
|
|
|
|
// remove old herrings (from previous race), and remove old
|
|
|
|
// track specific herring models
|
|
|
|
herring_manager->cleanup();
|
|
|
|
if(m_race_setup.m_mode == RaceSetup::RM_GRAND_PRIX)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
herring_manager->loadHerringStyle(m_race_setup.getHerringStyle());
|
|
|
|
}
|
|
|
|
catch(std::runtime_error)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "The cup '%s' contains an invalid herring style '%s'.\n",
|
|
|
|
race_manager->getGrandPrix()->getName().c_str(),
|
|
|
|
race_manager->getGrandPrix()->getHerringStyle().c_str());
|
|
|
|
fprintf(stderr, "Please fix the file '%s'.\n",
|
|
|
|
race_manager->getGrandPrix()->getFilename().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
herring_manager->loadHerringStyle(m_track->getHerringStyle());
|
|
|
|
}
|
|
|
|
catch(std::runtime_error)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "The track '%s' contains an invalid herring style '%s'.\n",
|
|
|
|
m_track->getName(), m_track->getHerringStyle().c_str());
|
|
|
|
fprintf(stderr, "Please fix the file '%s'.\n",
|
|
|
|
m_track->getFilename().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-12 09:07:26 -05:00
|
|
|
m_track->loadTrackModel();
|
2007-05-27 12:01:53 -04:00
|
|
|
} // loadTrack
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void World::restartRace()
|
|
|
|
{
|
|
|
|
m_clock = 0.0f;
|
2008-02-12 20:02:02 -05:00
|
|
|
m_phase = SETUP_PHASE;
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
for ( Karts::iterator i = m_kart.begin(); i != m_kart.end() ; ++i )
|
|
|
|
{
|
|
|
|
(*i)->reset();
|
|
|
|
}
|
|
|
|
resetAllKarts();
|
|
|
|
herring_manager->reset();
|
|
|
|
projectile_manager->cleanup();
|
|
|
|
race_manager->reset();
|
2008-02-05 06:56:21 -05:00
|
|
|
callback_manager->reset();
|
2007-09-21 15:17:48 -04:00
|
|
|
|
2008-02-11 19:01:27 -05:00
|
|
|
// Resets the cameras in case that they are pointing too steep up or down
|
|
|
|
scene->reset();
|
2007-09-21 15:17:48 -04:00
|
|
|
#ifdef HAVE_GHOST_REPLAY
|
|
|
|
m_replay_recorder.destroy();
|
|
|
|
m_replay_recorder.initRecorder( m_race_setup.getNumKarts() );
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
if( m_p_replay_player )
|
2007-09-21 15:17:48 -04:00
|
|
|
{
|
|
|
|
m_p_replay_player->reset();
|
|
|
|
m_p_replay_player->showReplayAt( 0.0 );
|
|
|
|
}
|
|
|
|
#endif
|
2008-02-11 19:01:27 -05:00
|
|
|
} // restartRace
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Kart* World::loadRobot(const KartProperties *kart_properties, int position,
|
|
|
|
sgCoord init_pos)
|
|
|
|
{
|
|
|
|
Kart* currentRobot;
|
|
|
|
|
|
|
|
const int NUM_ROBOTS = 1;
|
|
|
|
|
2007-11-03 09:13:26 -04:00
|
|
|
srand((unsigned)std::time(0));
|
2007-05-27 12:01:53 -04:00
|
|
|
|
|
|
|
switch(rand() % NUM_ROBOTS)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
currentRobot = new DefaultRobot(kart_properties, position,
|
|
|
|
init_pos);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
std::cerr << "Warning: Unknown robot, using default." << std::endl;
|
|
|
|
currentRobot = new DefaultRobot(kart_properties, position,
|
|
|
|
init_pos);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return currentRobot;
|
|
|
|
}
|
|
|
|
|
2007-06-09 21:13:39 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void World::pause()
|
|
|
|
{
|
|
|
|
sound_manager -> pauseMusic() ;
|
|
|
|
m_phase = LIMBO_PHASE;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void World::unpause()
|
|
|
|
{
|
|
|
|
sound_manager -> resumeMusic() ;
|
|
|
|
m_phase = RACE_PHASE;
|
|
|
|
}
|
|
|
|
|
2007-05-27 12:01:53 -04:00
|
|
|
/* EOF */
|