first iteration of new game mode code. most things seem okay, maybe high scores/rankings should be double-checked, also the end-of-race screen seems a bit messed up
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2287 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
164a7b87cf
commit
67c514f1ed
@ -144,6 +144,8 @@ supertuxkart_SOURCES = main.cpp \
|
||||
gui/feature_unlocked.cpp gui/feature_unlocked.hpp \
|
||||
gui/font.hpp gui/font.cpp \
|
||||
robots/default_robot.cpp robots/default_robot.hpp \
|
||||
modes/follow_the_leader.cpp modes/follow_the_leader.hpp \
|
||||
modes/standard_race.cpp modes/standard_race.hpp \
|
||||
replay_buffer_tpl.hpp \
|
||||
replay_buffers.hpp replay_buffers.cpp \
|
||||
replay_base.hpp replay_base.cpp \
|
||||
@ -162,9 +164,5 @@ supertuxkart_LDADD = -L. -lstatic_ssg \
|
||||
-lplibjs -lplibsl -lplibssg -lplibpu -lplibfnt -lplibsg \
|
||||
-lplibul -lplibssgaux $(bullet_LIBS) $(enet_LIBS) $(opengl_LIBS) $(sdl_LIBS) $(openal_LIBS)
|
||||
|
||||
.PHONY: pot
|
||||
pot:
|
||||
xgettext -o supertuxkart.pot -k_ --c++ *.?pp */*.?pp
|
||||
|
||||
SUBDIRS = robots
|
||||
|
||||
|
@ -161,7 +161,7 @@ void Camera::update (float dt)
|
||||
kart_hpr.setRoll(0.0f);
|
||||
// Only adjust the pitch if it's not the race start, otherwise
|
||||
// the camera will change pitch during ready-set-go.
|
||||
if(world->isRacePhase())
|
||||
if(world->getClock().isRacePhase())
|
||||
{
|
||||
// If the terrain pitch is 'significantly' different from the camera angle,
|
||||
// start adjusting the camera. This helps with steep declines, where
|
||||
|
@ -311,14 +311,6 @@ std::string FileManager::getHighscoreFile(const std::string& fname) const
|
||||
{
|
||||
return getHomeDir()+"/"+fname;
|
||||
} // getHighscoreFile
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
std::string FileManager::getReplayFile(const std::string& fname) const
|
||||
{
|
||||
return m_root_dir+"/replay/"+fname;
|
||||
} // getReplayFile
|
||||
#endif
|
||||
//-----------------------------------------------------------------------------
|
||||
void FileManager::initConfigDir()
|
||||
{
|
||||
|
@ -59,9 +59,6 @@ public:
|
||||
std::string getSFXFile (const std::string& fname) const;
|
||||
std::string getFontFile (const std::string& fname) const;
|
||||
std::string getModelFile (const std::string& fname) const;
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
std::string getReplayFile (const std::string& fname) const;
|
||||
#endif
|
||||
|
||||
void listFiles(std::set<std::string>& result, const std::string& dir,
|
||||
bool is_full_path=false, bool make_full_path=false)
|
||||
|
@ -260,8 +260,9 @@ void RaceGUI::drawFPS ()
|
||||
//-----------------------------------------------------------------------------
|
||||
void RaceGUI::drawTimer ()
|
||||
{
|
||||
if(world->getPhase()!=World::RACE_PHASE &&
|
||||
world->getPhase()!=World::DELAY_FINISH_PHASE ) return;
|
||||
// if(world->getPhase() != RACE_PHASE &&
|
||||
// world->getPhase() != DELAY_FINISH_PHASE ) return;
|
||||
if(!world->shouldDrawTimer()) return;
|
||||
char str[256];
|
||||
|
||||
assert(world != NULL);
|
||||
@ -922,7 +923,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
glOrtho ( 0, user_config->m_width, 0, user_config->m_height, 0, 100 ) ;
|
||||
switch (world->getPhase())
|
||||
{
|
||||
case World::READY_PHASE:
|
||||
case READY_PHASE:
|
||||
{
|
||||
GLfloat const COLORS[] = { 0.9f, 0.66f, 0.62f, 1.0f };
|
||||
//I18N: as in "ready, set, go", shown at the beginning of the race
|
||||
@ -932,7 +933,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
COLORS );
|
||||
}
|
||||
break;
|
||||
case World::SET_PHASE:
|
||||
case SET_PHASE:
|
||||
{
|
||||
GLfloat const COLORS[] = { 0.9f, 0.9f, 0.62f, 1.0f };
|
||||
//I18N: as in "ready, set, go", shown at the beginning of the race
|
||||
@ -942,7 +943,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
COLORS );
|
||||
}
|
||||
break;
|
||||
case World::GO_PHASE:
|
||||
case GO_PHASE:
|
||||
{
|
||||
GLfloat const COLORS[] = { 0.39f, 0.82f, 0.39f, 1.0f };
|
||||
//I18N: as in "ready, set, go", shown at the beginning of the race
|
||||
@ -968,7 +969,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
// The penalty message needs to be displayed for up to one second
|
||||
// after the start of the race, otherwise it disappears if
|
||||
// "Go" is displayed and the race starts
|
||||
if(world->isStartPhase() || world->getTime()<1.0f)
|
||||
if(world->getClock().isStartPhase() || world->getTime()<1.0f)
|
||||
{
|
||||
for(unsigned int i=0; i<race_manager->getNumLocalPlayers(); i++)
|
||||
{
|
||||
@ -989,7 +990,7 @@ void RaceGUI::drawStatusText(const float dt)
|
||||
if(race_manager->getNumLocalPlayers() >= 3)
|
||||
split_screen_ratio_x = 0.5;
|
||||
|
||||
if ( world->isRacePhase() )
|
||||
if ( world->getClock().isRacePhase() )
|
||||
{
|
||||
const int numPlayers = race_manager->getNumLocalPlayers();
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -120,11 +120,11 @@ void MainLoop::run()
|
||||
if(user_config->m_profile) dt=1.0f/60.0f;
|
||||
// In the first call dt might be large (includes loading time),
|
||||
// which can cause the camera to significantly tilt
|
||||
scene->draw(world->getPhase()==World::SETUP_PHASE ? 0.0f : dt);
|
||||
scene->draw(world->getPhase()==SETUP_PHASE ? 0.0f : dt);
|
||||
|
||||
network_manager->receiveUpdates();
|
||||
|
||||
if ( world->getPhase() != World::LIMBO_PHASE)
|
||||
if ( world->getPhase() != LIMBO_PHASE)
|
||||
{
|
||||
world->update(dt);
|
||||
|
||||
|
114
src/modes/follow_the_leader.cpp
Normal file
114
src/modes/follow_the_leader.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004 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 3
|
||||
// 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 "modes/follow_the_leader.hpp"
|
||||
#include "unlock_manager.hpp"
|
||||
#include "gui/menu_manager.hpp"
|
||||
#include "user_config.hpp"
|
||||
|
||||
// -----------------------------
|
||||
FollowTheLeaderRace::FollowTheLeaderRace() : World(), ClockListener()
|
||||
{
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
|
||||
m_clock.registerEventListener(this);
|
||||
m_clock.setMode(COUNTDOWN, m_leader_intervals[0]);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
FollowTheLeaderRace::~FollowTheLeaderRace()
|
||||
{
|
||||
}
|
||||
|
||||
void FollowTheLeaderRace::restartRace()
|
||||
{
|
||||
World::restartRace();
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
}
|
||||
|
||||
// clock events
|
||||
void FollowTheLeaderRace::countdownReachedZero()
|
||||
{
|
||||
}
|
||||
|
||||
void FollowTheLeaderRace::onGo()
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
void FollowTheLeaderRace::update(float delta)
|
||||
{
|
||||
m_clock.updateClock(delta);
|
||||
|
||||
World::update(delta);
|
||||
if(!m_clock.isRacePhase()) return;
|
||||
|
||||
if(m_clock.getTime() < 0.0f)
|
||||
{
|
||||
if(m_leader_intervals.size()>1)
|
||||
m_leader_intervals.erase(m_leader_intervals.begin());
|
||||
m_clock.setTime(m_leader_intervals[0]);
|
||||
int kart_number;
|
||||
// If the leader kart is not the first kart, remove the first
|
||||
// kart, otherwise remove the last kart.
|
||||
int position_to_remove = m_kart[0]->getPosition()==1
|
||||
? getCurrentNumKarts() : 1;
|
||||
for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
|
||||
{
|
||||
if(m_kart[kart_number]->isEliminated()) continue;
|
||||
if(m_kart[kart_number]->getPosition()==position_to_remove)
|
||||
break;
|
||||
}
|
||||
if(kart_number==(int)m_kart.size())
|
||||
{
|
||||
fprintf(stderr,"Problem with removing leader: position %d not found\n",
|
||||
position_to_remove);
|
||||
for(int i=0; i<(int)m_kart.size(); i++)
|
||||
{
|
||||
fprintf(stderr,"kart %d: eliminated %d position %d\n",
|
||||
i,m_kart[i]->isEliminated(), m_kart[i]->getPosition());
|
||||
} // for i
|
||||
} // kart_number==m_kart.size()
|
||||
else
|
||||
{
|
||||
removeKart(kart_number);
|
||||
}
|
||||
// The follow the leader race is over if there is only one kart left,
|
||||
// or if all players have gone
|
||||
if(getCurrentNumKarts()==2 || getCurrentNumPlayers()==0)
|
||||
{
|
||||
// Add the results for the remaining kart
|
||||
for(int i=1; i<(int)race_manager->getNumKarts(); i++)
|
||||
if(!m_kart[i]->isEliminated())
|
||||
race_manager->RaceFinished(m_kart[i], m_clock.getTime());
|
||||
|
||||
m_clock.raceOver();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FollowTheLeaderRace::onTerminate()
|
||||
{
|
||||
World::terminateRace();
|
||||
}
|
41
src/modes/follow_the_leader.hpp
Normal file
41
src/modes/follow_the_leader.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004 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 3
|
||||
// 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.
|
||||
|
||||
#ifndef _follow_the_leader_hpp_
|
||||
#define _follow_the_leader_hpp_
|
||||
|
||||
#include "world.hpp"
|
||||
|
||||
class FollowTheLeaderRace : public World, public ClockListener
|
||||
{
|
||||
std::vector<float> m_leader_intervals; // time till elimination in follow leader
|
||||
public:
|
||||
FollowTheLeaderRace();
|
||||
~FollowTheLeaderRace();
|
||||
|
||||
// clock events
|
||||
virtual void countdownReachedZero();
|
||||
virtual void onGo();
|
||||
virtual void onTerminate();
|
||||
|
||||
// overriding World methods
|
||||
virtual void update(float delta);
|
||||
virtual void restartRace();
|
||||
};
|
||||
|
||||
|
||||
#endif
|
82
src/modes/standard_race.cpp
Normal file
82
src/modes/standard_race.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// 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 3
|
||||
// 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 "modes/standard_race.hpp"
|
||||
#include "user_config.hpp"
|
||||
#include "unlock_manager.hpp"
|
||||
#include "gui/menu_manager.hpp"
|
||||
|
||||
// -----------------------------
|
||||
StandardRace::StandardRace() : World(), ClockListener()
|
||||
{
|
||||
m_clock.registerEventListener(this);
|
||||
m_clock.setMode(CHRONO);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
StandardRace::~StandardRace()
|
||||
{
|
||||
}
|
||||
|
||||
// clock events
|
||||
void StandardRace::countdownReachedZero() { }
|
||||
|
||||
void StandardRace::onGo()
|
||||
{
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
void StandardRace::restartRace()
|
||||
{
|
||||
World::restartRace();
|
||||
}
|
||||
|
||||
void StandardRace::update(float delta)
|
||||
{
|
||||
m_clock.updateClock(delta);
|
||||
|
||||
World::update(delta);
|
||||
if(!m_clock.isRacePhase()) return;
|
||||
|
||||
// =========================================================
|
||||
if(race_manager->getFinishedKarts() >= race_manager->getNumKarts() )
|
||||
{
|
||||
m_clock.raceOver();
|
||||
if(user_config->m_profile<0) printProfileResultAndExit();
|
||||
unlock_manager->raceFinished();
|
||||
} // if all karts are finished
|
||||
|
||||
// All player karts are finished, but computer still racing
|
||||
// ===========================================================
|
||||
else if(race_manager->allPlayerFinished())
|
||||
{
|
||||
// Set delay mode to have time for camera animation, and
|
||||
// to give the AI some time to get non-estimated timings
|
||||
m_clock.raceOver(true /* delay */);
|
||||
}
|
||||
}
|
||||
|
||||
void StandardRace::onTerminate()
|
||||
{
|
||||
World::terminateRace();
|
||||
}
|
39
src/modes/standard_race.hpp
Normal file
39
src/modes/standard_race.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2004 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 3
|
||||
// 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.
|
||||
|
||||
#ifndef _standard_race_
|
||||
#define _standard_race_
|
||||
|
||||
#include "world.hpp"
|
||||
|
||||
class StandardRace : public World, public ClockListener
|
||||
{
|
||||
public:
|
||||
StandardRace();
|
||||
~StandardRace();
|
||||
|
||||
// clock events
|
||||
virtual void countdownReachedZero();
|
||||
virtual void onGo();
|
||||
virtual void onTerminate();
|
||||
|
||||
// overriding World methods
|
||||
virtual void update(float delta);
|
||||
virtual void restartRace();
|
||||
};
|
||||
|
||||
#endif
|
@ -171,7 +171,7 @@ void PlayerKart::update(float dt)
|
||||
{
|
||||
steer(dt, m_steer_val);
|
||||
|
||||
if(world->isStartPhase())
|
||||
if(world->getClock().isStartPhase())
|
||||
{
|
||||
if(m_controls.accel!=0.0 || m_controls.brake!=false ||
|
||||
m_controls.fire|m_controls.wheelie|m_controls.jump)
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "user_config.hpp"
|
||||
#include "stk_config.hpp"
|
||||
#include "network/network_manager.hpp"
|
||||
#include "modes/standard_race.hpp"
|
||||
#include "modes/follow_the_leader.hpp"
|
||||
|
||||
RaceManager* race_manager= NULL;
|
||||
|
||||
@ -231,7 +233,15 @@ void RaceManager::startNextRace()
|
||||
// variable world. Admittedly a bit ugly, but simplifies
|
||||
// handling of objects which get created in the constructor
|
||||
// and need world to be defined.
|
||||
new World();
|
||||
|
||||
/*
|
||||
RM_GRAND_PRIX, RM_SINGLE,
|
||||
RM_QUICK_RACE, RM_TIME_TRIAL, RM_FOLLOW_LEADER
|
||||
FIXME
|
||||
*/
|
||||
|
||||
if(m_minor_mode==RM_FOLLOW_LEADER) new FollowTheLeaderRace();
|
||||
else new StandardRace();
|
||||
|
||||
m_active_race = true;
|
||||
} // startNextRace
|
||||
|
@ -97,7 +97,7 @@ void DefaultRobot::update( float delta )
|
||||
return;
|
||||
}
|
||||
|
||||
if( world->isStartPhase())
|
||||
if( world->getClock().isStartPhase() )
|
||||
{
|
||||
handle_race_start();
|
||||
AutoKart::update( delta );
|
||||
@ -513,7 +513,7 @@ void DefaultRobot::handle_rescue(const float DELTA)
|
||||
|
||||
|
||||
// check if kart is stuck
|
||||
if(getSpeed()<2.0f && !isRescue() && !world->isStartPhase())
|
||||
if(getSpeed()<2.0f && !isRescue() && !world->getClock().isStartPhase())
|
||||
{
|
||||
m_time_since_stuck += DELTA;
|
||||
if(m_time_since_stuck > 2.0f)
|
||||
|
@ -167,7 +167,7 @@ public:
|
||||
bool m_no_start_screen;
|
||||
bool m_smoke;
|
||||
bool m_display_fps;
|
||||
int m_profile; // Positive number: time in seconds, neg: # laps
|
||||
int m_profile; // Positive number: time in seconds, neg: # laps. (used to profile AI)
|
||||
bool m_print_kart_sizes; // print all kart sizes
|
||||
// 0 if no profiling. Never saved in config file!
|
||||
bool m_skidding;
|
||||
|
485
src/world.cpp
485
src/world.cpp
@ -50,35 +50,174 @@
|
||||
#include "network/network_manager.hpp"
|
||||
#include "network/race_state.hpp"
|
||||
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
# include "replay_player.hpp"
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
World* world = 0;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
Clock::Clock()
|
||||
{
|
||||
m_mode = CHRONO;
|
||||
m_time = 0.0f;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_listener = NULL;
|
||||
m_phase = SETUP_PHASE;
|
||||
m_previous_phase = SETUP_PHASE; // initialise it just in case
|
||||
|
||||
// for profiling AI
|
||||
m_phase = user_config->m_profile ? RACE_PHASE : SETUP_PHASE;
|
||||
|
||||
// FIXME - is it a really good idea to reload and delete the sound every race??
|
||||
m_prestart_sound = sfx_manager->newSFX(SFXManager::SOUND_PRESTART);
|
||||
m_start_sound = sfx_manager->newSFX(SFXManager::SOUND_START);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::reset()
|
||||
{
|
||||
m_time = 0.0f;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_phase = READY_PHASE; // FIXME - unsure
|
||||
m_previous_phase = SETUP_PHASE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
Clock::~Clock()
|
||||
{
|
||||
sfx_manager->deleteSFX(m_prestart_sound);
|
||||
sfx_manager->deleteSFX(m_start_sound);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::setMode(const ClockType mode, const float initial_time)
|
||||
{
|
||||
m_mode = mode;
|
||||
m_time = initial_time;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::raceOver(const bool delay)
|
||||
{
|
||||
if(m_phase == DELAY_FINISH_PHASE or m_phase == FINISH_PHASE) return; // we already know
|
||||
|
||||
if(delay)
|
||||
{
|
||||
m_phase = DELAY_FINISH_PHASE;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
}
|
||||
else
|
||||
m_phase = FINISH_PHASE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::updateClock(const float dt)
|
||||
{
|
||||
switch(m_phase)
|
||||
{
|
||||
// Note: setup phase must be a separate phase, since the race_manager
|
||||
// checks the phase when updating the camera: in the very first time
|
||||
// step dt is large (it includes loading time), so the camera might
|
||||
// tilt way too much. A separate setup phase for the first frame
|
||||
// simplifies this handling
|
||||
case SETUP_PHASE:
|
||||
m_auxiliary_timer = 0.0f;
|
||||
m_phase = READY_PHASE;
|
||||
m_prestart_sound->play();
|
||||
return; // loading time, don't play sound yet
|
||||
case READY_PHASE:
|
||||
if(m_auxiliary_timer>1.0)
|
||||
{
|
||||
m_phase=SET_PHASE;
|
||||
m_prestart_sound->play();
|
||||
}
|
||||
m_auxiliary_timer += dt;
|
||||
return;
|
||||
case SET_PHASE :
|
||||
if(m_auxiliary_timer>2.0)
|
||||
{
|
||||
// set phase is over, go to the next one
|
||||
m_phase=GO_PHASE;
|
||||
|
||||
m_start_sound->play();
|
||||
|
||||
assert(m_listener != NULL);
|
||||
m_listener -> onGo();
|
||||
}
|
||||
m_auxiliary_timer += dt;
|
||||
return;
|
||||
case GO_PHASE :
|
||||
if(m_auxiliary_timer>3.0) // how long to display the 'go' message
|
||||
m_phase=RACE_PHASE;
|
||||
m_auxiliary_timer += dt;
|
||||
break;
|
||||
case DELAY_FINISH_PHASE :
|
||||
{
|
||||
m_auxiliary_timer += dt;
|
||||
|
||||
// Nothing more to do if delay time is not over yet
|
||||
if(m_auxiliary_timer < TIME_DELAY_TILL_FINISH) break;
|
||||
|
||||
m_phase = FINISH_PHASE;
|
||||
break;
|
||||
}
|
||||
case FINISH_PHASE:
|
||||
m_listener->onTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
switch(m_mode)
|
||||
{
|
||||
case CHRONO:
|
||||
m_time += dt;
|
||||
break;
|
||||
case COUNTDOWN:
|
||||
m_time -= dt;
|
||||
|
||||
if(m_time <= 0.0)
|
||||
{
|
||||
assert(m_listener != NULL);
|
||||
m_listener -> countdownReachedZero();
|
||||
}
|
||||
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::setTime(const float time)
|
||||
{
|
||||
m_time = time;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::registerEventListener(ClockListener* listener)
|
||||
{
|
||||
m_listener = listener;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::pause()
|
||||
{
|
||||
m_previous_phase = m_phase;
|
||||
m_phase = LIMBO_PHASE;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void Clock::unpause()
|
||||
{
|
||||
m_phase = m_previous_phase;
|
||||
}
|
||||
|
||||
World* world = 0; // FIXME, use singleton or something instead of this global variable
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
World::World()
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
, m_p_replay_player(NULL)
|
||||
#endif
|
||||
{
|
||||
delete world;
|
||||
world = this;
|
||||
race_state = new RaceState();
|
||||
m_phase = SETUP_PHASE;
|
||||
m_previous_phase = SETUP_PHASE; // initialise it just in case
|
||||
m_track = NULL;
|
||||
m_clock = 0.0f;
|
||||
m_faster_music_active = false;
|
||||
m_fastest_lap = 9999999.9f;
|
||||
m_fastest_kart = 0;
|
||||
m_eliminated_karts = 0;
|
||||
m_eliminated_players = 0;
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
|
||||
m_clock.setMode( CHRONO );
|
||||
|
||||
// Grab the track file
|
||||
try
|
||||
{
|
||||
@ -176,33 +315,14 @@ World::World()
|
||||
callback_manager->initAll();
|
||||
menu_manager->switchToRace();
|
||||
|
||||
m_prestart_sound = sfx_manager->newSFX(SFXManager::SOUND_PRESTART);
|
||||
m_start_sound = sfx_manager->newSFX(SFXManager::SOUND_START);
|
||||
|
||||
m_track->startMusic();
|
||||
|
||||
m_phase = user_config->m_profile ? RACE_PHASE : SETUP_PHASE;
|
||||
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
m_replay_recorder.initRecorder( race_manager->getNumKarts() );
|
||||
|
||||
m_p_replay_player = new ReplayPlayer;
|
||||
if( !loadReplayHumanReadable( "test1" ) )
|
||||
{
|
||||
delete m_p_replay_player;
|
||||
m_p_replay_player = NULL;
|
||||
}
|
||||
if( m_p_replay_player ) m_p_replay_player->showReplayAt( 0.0 );
|
||||
#endif
|
||||
network_manager->worldLoaded();
|
||||
} // World
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
World::~World()
|
||||
{
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
saveReplayHumanReadable( "test" );
|
||||
#endif
|
||||
delete race_state;
|
||||
m_track->cleanup();
|
||||
// Clear all callbacks
|
||||
@ -216,8 +336,6 @@ World::~World()
|
||||
delete m_physics;
|
||||
|
||||
sound_manager -> stopMusic();
|
||||
sfx_manager->deleteSFX(m_prestart_sound);
|
||||
sfx_manager->deleteSFX(m_start_sound);
|
||||
|
||||
sgVec3 sun_pos;
|
||||
sgVec4 ambient_col, specular_col, diffuse_col;
|
||||
@ -230,18 +348,15 @@ World::~World()
|
||||
ssgGetLight ( 0 ) -> setColour ( GL_AMBIENT , ambient_col ) ;
|
||||
ssgGetLight ( 0 ) -> setColour ( GL_DIFFUSE , diffuse_col ) ;
|
||||
ssgGetLight ( 0 ) -> setColour ( GL_SPECULAR, specular_col ) ;
|
||||
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
m_replay_recorder.destroy();
|
||||
if( m_p_replay_player )
|
||||
{
|
||||
m_p_replay_player->destroy();
|
||||
delete m_p_replay_player;
|
||||
m_p_replay_player = NULL;
|
||||
}
|
||||
#endif
|
||||
} // ~World
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::terminateRace()
|
||||
{
|
||||
m_clock.pause();
|
||||
menu_manager->pushMenu(MENUID_RACERESULT);
|
||||
estimateFinishTimes();
|
||||
unlock_manager->raceFinished();
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Waits till each kart is resting on the ground
|
||||
*
|
||||
@ -300,21 +415,7 @@ void World::update(float dt)
|
||||
// Clear race state so that new information can be stored
|
||||
race_state->clear();
|
||||
if(user_config->m_replay_history) dt=history->GetNextDelta();
|
||||
updateRaceStatus(dt);
|
||||
|
||||
if( getPhase() == FINISH_PHASE )
|
||||
{
|
||||
if(race_manager->getMinorMode()==RaceManager::RM_FOLLOW_LEADER)
|
||||
{
|
||||
pause();
|
||||
menu_manager->pushMenu(MENUID_RACERESULT);
|
||||
unlock_manager->raceFinished();
|
||||
return;
|
||||
}
|
||||
updateHighscores();
|
||||
pause();
|
||||
menu_manager->pushMenu(MENUID_RACERESULT);
|
||||
}
|
||||
if(!user_config->m_replay_history) history->StoreDelta(dt);
|
||||
if(network_manager->getMode()!=NetworkManager::NW_CLIENT) m_physics->update(dt);
|
||||
for (int i = 0 ; i <(int) m_kart.size(); ++i)
|
||||
@ -335,16 +436,6 @@ void World::update(float dt)
|
||||
|
||||
/* Routine stuff we do even when paused */
|
||||
callback_manager->update(dt);
|
||||
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
// 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
|
||||
if( m_phase == GO_PHASE )
|
||||
{
|
||||
m_replay_recorder.pushFrame();
|
||||
if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
void World::updateHighscores()
|
||||
@ -373,7 +464,6 @@ void World::updateHighscores()
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// FIXME: end
|
||||
|
||||
// Only record times for player karts
|
||||
if(!m_kart[index[pos]]->isPlayerKart()) continue;
|
||||
@ -394,180 +484,6 @@ void World::updateHighscores()
|
||||
delete []index;
|
||||
} // updateHighscores
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
bool World::saveReplayHumanReadable( std::string const &filename ) const
|
||||
{
|
||||
std::string path;
|
||||
path = file_manager->getReplayFile(filename+"."+ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
|
||||
|
||||
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", race_manager->getNumPlayers());
|
||||
fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
|
||||
fprintf(fd, "track: %s\n", m_track->getIdent().c_str());
|
||||
|
||||
for(int i=0; i<race_manager->getNumKarts(); i++)
|
||||
{
|
||||
fprintf(fd, "model %d: %s\n", i, race_manager->getKartName(i).c_str());
|
||||
}
|
||||
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 )
|
||||
{
|
||||
assert( m_p_replay_player );
|
||||
m_p_replay_player->destroy();
|
||||
|
||||
std::string path = file_manager->getReplayFile(filename+"."+
|
||||
ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
|
||||
|
||||
try
|
||||
{
|
||||
path = file_manager->getPath(path.c_str());
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
bool blnRet = m_p_replay_player->loadReplayHumanReadable( fd );
|
||||
|
||||
fclose( fd ); fd = NULL;
|
||||
|
||||
return blnRet;
|
||||
} // loadReplayHumanReadable
|
||||
#endif // HAVE_GHOST_REPLAY
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void World::updateRaceStatus(float dt)
|
||||
{
|
||||
switch (m_phase) {
|
||||
// Note: setup phase must be a separate phase, since the race_manager
|
||||
// checks the phase when updating the camera: in the very first time
|
||||
// step dt is large (it includes loading time), so the camera might
|
||||
// tilt way too much. A separate setup phase for the first frame
|
||||
// simplifies this handling
|
||||
case SETUP_PHASE: m_clock = 0.0f;
|
||||
m_phase = READY_PHASE;
|
||||
m_prestart_sound->play();
|
||||
dt = 0.0f; // solves the problem of adding track loading time
|
||||
return; // loading time, don't play sound yet
|
||||
case READY_PHASE: if(m_clock>1.0)
|
||||
{
|
||||
m_phase=SET_PHASE;
|
||||
m_prestart_sound->play();
|
||||
}
|
||||
m_clock += dt;
|
||||
return;
|
||||
case SET_PHASE : if(m_clock>2.0)
|
||||
{
|
||||
m_phase=GO_PHASE;
|
||||
if(race_manager->getMinorMode()==RaceManager::RM_FOLLOW_LEADER)
|
||||
m_clock=m_leader_intervals[0];
|
||||
else
|
||||
m_clock=0.0f;
|
||||
m_start_sound->play();
|
||||
// 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();
|
||||
}
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
// push positions at time 0.0 to replay-data
|
||||
m_replay_recorder.pushFrame();
|
||||
#endif
|
||||
}
|
||||
m_clock += dt;
|
||||
return;
|
||||
case GO_PHASE : if(race_manager->getMinorMode()==RaceManager::RM_FOLLOW_LEADER)
|
||||
{
|
||||
// Switch to race if more than 1 second has past
|
||||
if(m_clock<m_leader_intervals[0]-1.0f)
|
||||
m_phase=RACE_PHASE;
|
||||
m_clock -= dt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_clock>1.0) // how long to display the 'go' message
|
||||
m_phase=RACE_PHASE;
|
||||
m_clock += dt;
|
||||
}
|
||||
return;
|
||||
case DELAY_FINISH_PHASE :
|
||||
{
|
||||
m_clock += dt;
|
||||
// Nothing more to do if delay time is not over yet
|
||||
if(m_clock - m_finish_delay_start_time
|
||||
< TIME_DELAY_TILL_FINISH) return;
|
||||
|
||||
m_phase = FINISH_PHASE;
|
||||
estimateFinishTimes();
|
||||
unlock_manager->raceFinished();
|
||||
return;
|
||||
}
|
||||
default : break;
|
||||
} // switch
|
||||
|
||||
if(race_manager->getMinorMode()==RaceManager::RM_FOLLOW_LEADER)
|
||||
return updateLeaderMode(dt);
|
||||
|
||||
// The status must now be race mode!
|
||||
// =================================
|
||||
m_clock += dt;
|
||||
|
||||
// 2) A player comes in last, go immediately to finish phase
|
||||
// =========================================================
|
||||
if(race_manager->getFinishedKarts() >= race_manager->getNumKarts() )
|
||||
{
|
||||
m_phase = FINISH_PHASE;
|
||||
if(user_config->m_profile<0) printProfileResultAndExit();
|
||||
unlock_manager->raceFinished();
|
||||
} // if all karts are finished
|
||||
|
||||
// 3) All player karts are finished, but computer still racing
|
||||
// ===========================================================
|
||||
else if(race_manager->allPlayerFinished())
|
||||
{
|
||||
// Set delay mode to have time for camera animation, and
|
||||
// to give the AI some time to get non-estimated timings
|
||||
m_phase = DELAY_FINISH_PHASE;
|
||||
m_finish_delay_start_time = m_clock;
|
||||
}
|
||||
} // updateRaceStatus
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::estimateFinishTimes()
|
||||
@ -582,60 +498,6 @@ void World::estimateFinishTimes()
|
||||
} // for i
|
||||
} // estimateFinishTimes
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::updateLeaderMode(float dt)
|
||||
{
|
||||
// Count 'normal' till race phase has started, then count backwards
|
||||
if(m_phase==RACE_PHASE || m_phase==GO_PHASE)
|
||||
m_clock -=dt;
|
||||
else
|
||||
m_clock +=dt;
|
||||
if(m_clock<0.0f)
|
||||
{
|
||||
if(m_leader_intervals.size()>1)
|
||||
m_leader_intervals.erase(m_leader_intervals.begin());
|
||||
m_clock=m_leader_intervals[0];
|
||||
int kart_number;
|
||||
// If the leader kart is not the first kart, remove the first
|
||||
// kart, otherwise remove the last kart.
|
||||
int position_to_remove = m_kart[0]->getPosition()==1
|
||||
? getCurrentNumKarts() : 1;
|
||||
for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
|
||||
{
|
||||
if(m_kart[kart_number]->isEliminated()) continue;
|
||||
if(m_kart[kart_number]->getPosition()==position_to_remove)
|
||||
break;
|
||||
}
|
||||
if(kart_number==(int)m_kart.size())
|
||||
{
|
||||
fprintf(stderr,"Problem with removing leader: position %d not found\n",
|
||||
position_to_remove);
|
||||
for(int i=0; i<(int)m_kart.size(); i++)
|
||||
{
|
||||
fprintf(stderr,"kart %d: eliminated %d position %d\n",
|
||||
i,m_kart[i]->isEliminated(), m_kart[i]->getPosition());
|
||||
} // for i
|
||||
} // kart_number==m_kart.size()
|
||||
else
|
||||
{
|
||||
removeKart(kart_number);
|
||||
}
|
||||
// The follow the leader race is over if there is only one kart left,
|
||||
// or if all players have gone
|
||||
if(getCurrentNumKarts()==2 ||getCurrentNumPlayers()==0)
|
||||
{
|
||||
// Add the results for the remaining kart
|
||||
for(int i=1; i<(int)race_manager->getNumKarts(); i++)
|
||||
if(!m_kart[i]->isEliminated())
|
||||
race_manager->RaceFinished(m_kart[i], m_clock);
|
||||
m_phase=FINISH_PHASE;
|
||||
return;
|
||||
}
|
||||
} // m_clock<0
|
||||
return;
|
||||
|
||||
} // updateLeaderMode
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::printProfileResultAndExit()
|
||||
{
|
||||
@ -694,7 +556,7 @@ void World::removeKart(int kart_number)
|
||||
// ignored in all loops). Important:world->getCurrentNumKarts() returns
|
||||
// the number of karts still racing. This value can not be used for loops
|
||||
// over all karts, use race_manager->getNumKarts() instead!
|
||||
race_manager->RaceFinished(kart, m_clock);
|
||||
race_manager->RaceFinished(kart, m_clock.getTime());
|
||||
kart->eliminate();
|
||||
m_eliminated_karts++;
|
||||
|
||||
@ -782,23 +644,25 @@ void World::loadTrack()
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::restartRace()
|
||||
{
|
||||
m_clock = 0.0f;
|
||||
m_phase = SETUP_PHASE;
|
||||
m_previous_phase = SETUP_PHASE;
|
||||
m_clock.reset();
|
||||
m_faster_music_active = false;
|
||||
m_eliminated_karts = 0;
|
||||
m_eliminated_players = 0;
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
|
||||
for ( Karts::iterator i = m_kart.begin(); i != m_kart.end() ; ++i )
|
||||
{
|
||||
(*i)->reset();
|
||||
}
|
||||
|
||||
resetAllKarts();
|
||||
sound_manager->stopMusic(); // Start music from beginning
|
||||
|
||||
// Start music from beginning
|
||||
sound_manager->stopMusic();
|
||||
m_track->startMusic();
|
||||
|
||||
// Enable SFX again
|
||||
sfx_manager->resumeAll();
|
||||
|
||||
herring_manager->reset();
|
||||
projectile_manager->cleanup();
|
||||
race_manager->reset();
|
||||
@ -806,16 +670,6 @@ void World::restartRace()
|
||||
|
||||
// Resets the cameras in case that they are pointing too steep up or down
|
||||
scene->reset();
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
m_replay_recorder.destroy();
|
||||
m_replay_recorder.initRecorder( race_manager->getNumKarts() );
|
||||
|
||||
if( m_p_replay_player )
|
||||
{
|
||||
m_p_replay_player->reset();
|
||||
m_p_replay_player->showReplayAt( 0.0 );
|
||||
}
|
||||
#endif
|
||||
} // restartRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -845,8 +699,7 @@ void World::pause()
|
||||
{
|
||||
sound_manager->pauseMusic();
|
||||
sfx_manager->pauseAll();
|
||||
m_previous_phase = m_phase;
|
||||
m_phase = LIMBO_PHASE;
|
||||
m_clock.pause();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -854,7 +707,7 @@ void World::unpause()
|
||||
{
|
||||
sound_manager->resumeMusic() ;
|
||||
sfx_manager->resumeAll();
|
||||
m_phase = m_previous_phase;
|
||||
m_clock.unpause();
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
255
src/world.hpp
255
src/world.hpp
@ -32,11 +32,6 @@
|
||||
#include "network/network_kart.hpp"
|
||||
#include "utils/random_generator.hpp"
|
||||
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
# include "replay_recorder.hpp"
|
||||
class ReplayPlayer;
|
||||
#endif
|
||||
|
||||
class SFXBase;
|
||||
|
||||
/** This class is responsible for running the actual race. A world is created
|
||||
@ -78,117 +73,207 @@ class SFXBase;
|
||||
* would be done in the mode specific world (instead of in the
|
||||
* RaceManager).
|
||||
*/
|
||||
class World
|
||||
enum ClockType
|
||||
{
|
||||
CLOCK_NONE,
|
||||
CHRONO, // counts up
|
||||
COUNTDOWN
|
||||
};
|
||||
|
||||
/**
|
||||
* abstract base class, derive from it to receive events from the clock
|
||||
*/
|
||||
class ClockListener
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Kart*> Karts;
|
||||
|
||||
/** resources, this should be put in a separate class or replaced by a smart
|
||||
* resource manager
|
||||
virtual ~ClockListener(){};
|
||||
/*
|
||||
* Will be called to notify your derived class that the clock,
|
||||
* which is in COUNTDOWN mode, has reached zero.
|
||||
*/
|
||||
|
||||
enum Phase {
|
||||
// Game setup, e.g. track loading
|
||||
SETUP_PHASE,
|
||||
// 'Ready' is displayed
|
||||
READY_PHASE,
|
||||
// 'Set' is displayed
|
||||
SET_PHASE,
|
||||
// 'Go' is displayed, but this is already race phase
|
||||
GO_PHASE,
|
||||
// the actual race has started, no ready/set/go is displayed anymore
|
||||
RACE_PHASE,
|
||||
// All players have finished, now wait a certain amount of time for AI
|
||||
// karts to finish. If they do not finish in that time, finish the race
|
||||
DELAY_FINISH_PHASE,
|
||||
// The player crossed the finishing line and his and the time of
|
||||
// the other players is displayed, controll is automatic
|
||||
FINISH_PHASE,
|
||||
// The state after finish where no calculations are done.
|
||||
LIMBO_PHASE,
|
||||
};
|
||||
|
||||
Track* m_track;
|
||||
virtual void countdownReachedZero() = 0;
|
||||
|
||||
/** debug text that will be overlaid to the screen */
|
||||
std::string m_debug_text[10];
|
||||
/*
|
||||
* Called when the race actually starts.
|
||||
*/
|
||||
virtual void onGo() = 0;
|
||||
|
||||
/**
|
||||
* Called when race is over and should be terminated (mostly called by the clock).
|
||||
*/
|
||||
virtual void onTerminate() = 0;
|
||||
};
|
||||
|
||||
World();
|
||||
virtual ~World();
|
||||
void update(float delta);
|
||||
// Note: GO_PHASE is both: start phase and race phase
|
||||
bool isStartPhase() const {return m_phase<GO_PHASE;}
|
||||
bool isRacePhase() const {return m_phase>=GO_PHASE && m_phase<LIMBO_PHASE;}
|
||||
void restartRace();
|
||||
void disableRace(); // Put race into limbo phase
|
||||
|
||||
PlayerKart *getPlayerKart(int player) const { return m_player_karts[player]; }
|
||||
unsigned int getCurrentNumLocalPlayers() const {return m_local_player_karts.size();}
|
||||
PlayerKart *getLocalPlayerKart(int n) const { return m_local_player_karts[n]; }
|
||||
NetworkKart*getNetworkKart(int n) const {return m_network_karts[n]; }
|
||||
Kart *getKart(int kartId) const { assert(kartId >= 0 &&
|
||||
kartId < int(m_kart.size()));
|
||||
return m_kart[kartId]; }
|
||||
unsigned int getCurrentNumKarts() const { return (int)m_kart.size()-
|
||||
m_eliminated_karts; }
|
||||
unsigned int getCurrentNumPlayers() const { return (int)m_player_karts.size()-
|
||||
m_eliminated_players; }
|
||||
|
||||
/** Returns the phase of the game */
|
||||
Phase getPhase() const { return m_phase; }
|
||||
Physics *getPhysics() const { return m_physics; }
|
||||
Track *getTrack() const { return m_track; }
|
||||
Kart* getFastestKart() const { return m_fastest_kart; }
|
||||
float getFastestLapTime() const { return m_fastest_lap; }
|
||||
void setFastestLap(Kart *k, float time) {m_fastest_kart=k;m_fastest_lap=time;}
|
||||
const Highscores* getHighscores() const { return m_highscores; }
|
||||
float getTime() const { return m_clock; }
|
||||
|
||||
void pause();
|
||||
void unpause();
|
||||
enum Phase {
|
||||
// Game setup, e.g. track loading
|
||||
SETUP_PHASE,
|
||||
// 'Ready' is displayed
|
||||
READY_PHASE,
|
||||
// 'Set' is displayed
|
||||
SET_PHASE,
|
||||
// 'Go' is displayed, but this is already race phase
|
||||
GO_PHASE,
|
||||
// the actual race has started, no ready/set/go is displayed anymore
|
||||
RACE_PHASE,
|
||||
// All players have finished, now wait a certain amount of time for AI
|
||||
// karts to finish. If they do not finish in that time, finish the race
|
||||
DELAY_FINISH_PHASE,
|
||||
// The player crossed the finishing line and his and the time of
|
||||
// the other players is displayed, controll is automatic
|
||||
FINISH_PHASE,
|
||||
// The state after finish where no calculations are done.
|
||||
LIMBO_PHASE,
|
||||
};
|
||||
|
||||
/**
|
||||
* A class that manages the clock (countdown, chrono, etc.) Also manages stuff
|
||||
* like the 'ready/set/go' text at the beginning or the delay at the end of a race.
|
||||
*/
|
||||
class Clock
|
||||
{
|
||||
private:
|
||||
SFXBase *m_prestart_sound;
|
||||
SFXBase *m_start_sound;
|
||||
|
||||
/**
|
||||
* Elasped/remaining time in seconds
|
||||
*/
|
||||
float m_time;
|
||||
ClockType m_mode;
|
||||
/**
|
||||
* This object will be called to notify it of time events. Currently,
|
||||
* this is only relevant for countdown mode.
|
||||
*/
|
||||
ClockListener* m_listener;
|
||||
|
||||
|
||||
Phase m_phase;
|
||||
/**
|
||||
* Counts time during the initial 'ready/set/go' phase, or at the end of a race.
|
||||
* This timer basically kicks in when we need to calculate non-race time like labels.
|
||||
*/
|
||||
float m_auxiliary_timer;
|
||||
|
||||
/**
|
||||
* Remember previous phase e.g. on pause
|
||||
*/
|
||||
Phase m_previous_phase;
|
||||
public:
|
||||
Clock();
|
||||
~Clock();
|
||||
|
||||
void reset();
|
||||
|
||||
// Note: GO_PHASE is both: start phase and race phase
|
||||
bool isStartPhase() const { return m_phase<GO_PHASE; }
|
||||
bool isRacePhase() const { return m_phase>=GO_PHASE && m_phase<LIMBO_PHASE; }
|
||||
const Phase getPhase() const { return m_phase; }
|
||||
|
||||
/**
|
||||
* Call to specify what kind of clock you want. The second argument
|
||||
* can be used to specify the initial time value (especially useful
|
||||
* for countdowns)
|
||||
*/
|
||||
void setMode(const ClockType mode, const float initial_time=0.0f);
|
||||
int getMode() const { return m_mode; }
|
||||
/**
|
||||
* Call each frame, with the elapsed time as argument.
|
||||
*/
|
||||
void updateClock(const float dt);
|
||||
|
||||
float getTime() const { return m_time; }
|
||||
void setTime(const float time);
|
||||
|
||||
void pause();
|
||||
void unpause();
|
||||
|
||||
void raceOver(const bool delay=false);
|
||||
|
||||
void registerEventListener(ClockListener* listener);
|
||||
};
|
||||
|
||||
class World
|
||||
{
|
||||
protected:
|
||||
typedef std::vector<Kart*> Karts;
|
||||
|
||||
std::vector<PlayerKart*> m_player_karts;
|
||||
std::vector<PlayerKart*> m_local_player_karts;
|
||||
std::vector<NetworkKart*> m_network_karts;
|
||||
RandomGenerator m_random;
|
||||
|
||||
Clock m_clock;
|
||||
Karts m_kart;
|
||||
Physics* m_physics;
|
||||
float m_fastest_lap;
|
||||
Kart* m_fastest_kart;
|
||||
Highscores* m_highscores;
|
||||
Phase m_phase;
|
||||
Phase m_previous_phase; // used during the race popup menu
|
||||
float m_clock;
|
||||
float m_finish_delay_start_time;
|
||||
int m_eliminated_karts; // number of eliminated karts
|
||||
int m_eliminated_players; // number of eliminated players
|
||||
std::vector<float>
|
||||
m_leader_intervals; // time till elimination in follow leader
|
||||
|
||||
bool m_faster_music_active; // true if faster music was activated
|
||||
SFXBase *m_prestart_sound;
|
||||
SFXBase *m_start_sound;
|
||||
|
||||
void updateRacePosition(int k);
|
||||
void updateHighscores ();
|
||||
void loadTrack ();
|
||||
void updateRaceStatus (float dt);
|
||||
void resetAllKarts ();
|
||||
void removeKart (int kart_number);
|
||||
Kart* loadRobot (const std::string& kart_name, int position,
|
||||
const btTransform& init_pos);
|
||||
void updateLeaderMode (float dt);
|
||||
void printProfileResultAndExit();
|
||||
void estimateFinishTimes();
|
||||
#ifdef HAVE_GHOST_REPLAY
|
||||
private:
|
||||
bool saveReplayHumanReadable( std::string const &filename ) const;
|
||||
bool loadReplayHumanReadable( std::string const &filename );
|
||||
|
||||
ReplayRecorder m_replay_recorder;
|
||||
ReplayPlayer *m_p_replay_player;
|
||||
#endif
|
||||
|
||||
public:
|
||||
Track* m_track;
|
||||
|
||||
/** debug text that will be overlaid to the screen */
|
||||
std::string m_debug_text[10];
|
||||
|
||||
World();
|
||||
virtual ~World();
|
||||
virtual void update(float delta);
|
||||
virtual void restartRace();
|
||||
void disableRace(); // Put race into limbo phase
|
||||
|
||||
PlayerKart *getPlayerKart(int player) const { return m_player_karts[player]; }
|
||||
unsigned int getCurrentNumLocalPlayers() const { return m_local_player_karts.size(); }
|
||||
PlayerKart *getLocalPlayerKart(int n) const { return m_local_player_karts[n]; }
|
||||
NetworkKart *getNetworkKart(int n) const { return m_network_karts[n]; }
|
||||
Kart *getKart(int kartId) const { assert(kartId >= 0 &&
|
||||
kartId < int(m_kart.size()));
|
||||
return m_kart[kartId]; }
|
||||
unsigned int getCurrentNumKarts() const { return (int)m_kart.size() -
|
||||
m_eliminated_karts; }
|
||||
unsigned int getCurrentNumPlayers() const { return (int)m_player_karts.size()-
|
||||
m_eliminated_players; }
|
||||
|
||||
Physics *getPhysics() const { return m_physics; }
|
||||
Track *getTrack() const { return m_track; }
|
||||
Kart* getFastestKart() const { return m_fastest_kart; }
|
||||
float getFastestLapTime() const { return m_fastest_lap; }
|
||||
void setFastestLap(Kart *k, float time) {m_fastest_kart=k;m_fastest_lap=time; }
|
||||
const Highscores* getHighscores() const { return m_highscores; }
|
||||
float getTime() const { return m_clock.getTime(); }
|
||||
Phase getPhase() const { return m_clock.getPhase(); }
|
||||
const Clock& getClock() const { return m_clock; }
|
||||
|
||||
/**
|
||||
* Called when race is over and should be terminated (mostly called by the clock).
|
||||
*/
|
||||
void terminateRace();
|
||||
|
||||
void pause();
|
||||
void unpause();
|
||||
|
||||
/**
|
||||
* The code that draws the timer should call this first to know
|
||||
* whether the game mode wants a timer drawn
|
||||
*/
|
||||
bool shouldDrawTimer() const { return ((m_clock.getPhase() == RACE_PHASE or
|
||||
m_clock.getPhase() == DELAY_FINISH_PHASE) and
|
||||
m_clock.getMode() != CLOCK_NONE); }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user