Refactor end of race handling so that more functions are done in a base class only
(esp. code that was previously duplicated in the battle mode and standard race). There is now time for an end animation, even if the player should finish last (in which case the previous end camera would not be shown). This mostly in preparation for end animations. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@4750 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
b52a2a7e9b
commit
31e3806fd0
@ -48,7 +48,7 @@ final-camera-time is the time for the final camera to reach it's destination
|
||||
max-skidmarks="100"
|
||||
skid-fadeout-time="60"
|
||||
near-ground="2"
|
||||
delay-finish-time="10"
|
||||
delay-finish-time="4"
|
||||
music-credit-time="10"
|
||||
final-camera-time="1.5"
|
||||
/>
|
||||
|
@ -56,6 +56,7 @@ private:
|
||||
float m_time_since_faster;
|
||||
|
||||
public:
|
||||
#pragma warning(disable:4290)
|
||||
MusicInformation (const std::string& filename) throw (std::runtime_error);
|
||||
const std::string& getComposer () const {return m_composer; }
|
||||
const std::string& getTitle () const {return m_title; }
|
||||
|
@ -26,10 +26,11 @@
|
||||
/** Constructor, saves the kart pointer and a pointer to the KartControl
|
||||
* of the kart.
|
||||
*/
|
||||
Controller::Controller(Kart *kart)
|
||||
Controller::Controller(Kart *kart, ActivePlayer *player)
|
||||
{
|
||||
m_controls = &(kart->getControls());
|
||||
m_kart = kart;
|
||||
m_player = player;
|
||||
} // Controller
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -25,6 +25,7 @@ using namespace irr;
|
||||
|
||||
class Kart;
|
||||
class Item;
|
||||
class ActivePlayer;
|
||||
|
||||
/** This is the base class for kart controller - that can be a player
|
||||
* or a a robot.
|
||||
@ -39,14 +40,21 @@ protected:
|
||||
* it commands. */
|
||||
KartControl *m_controls;
|
||||
|
||||
/** If this belongs to a player, it stores the active player data
|
||||
* structure. Otherwise it is 0. */
|
||||
ActivePlayer *m_player;
|
||||
public:
|
||||
Controller (Kart *kart);
|
||||
Controller (Kart *kart, ActivePlayer *player=NULL);
|
||||
virtual ~Controller () {};
|
||||
/** Returns the active player for this controller (NULL
|
||||
* if this controller does not belong to a player. */
|
||||
ActivePlayer *getPlayer () {return m_player;}
|
||||
virtual void reset () {};
|
||||
virtual void update (float dt) {};
|
||||
virtual void handleZipper () {};
|
||||
virtual void collectedItem (const Item &item, int add_info=-1,
|
||||
float previous_energy=0) {};
|
||||
|
||||
virtual void crashed () {};
|
||||
virtual void setPosition (int p) {};
|
||||
virtual void finishedRace (float time) {};
|
||||
|
@ -44,7 +44,8 @@
|
||||
#include "tracks/track.hpp"
|
||||
#include "utils/constants.hpp"
|
||||
|
||||
EndController::EndController(Kart *kart) : Controller(kart)
|
||||
EndController::EndController(Kart *kart, ActivePlayer *player)
|
||||
: Controller(kart, player)
|
||||
{
|
||||
m_kart_length = m_kart->getKartProperties()->getKartModel()->getLength();
|
||||
m_kart_width = m_kart->getKartProperties()->getKartModel()->getWidth();
|
||||
@ -55,11 +56,13 @@ EndController::EndController(Kart *kart) : Controller(kart)
|
||||
m_next_node_index.reserve(m_quad_graph->getNumNodes());
|
||||
m_successor_index.reserve(m_quad_graph->getNumNodes());
|
||||
|
||||
// Initialise the fields with -1
|
||||
// Initialise the fields
|
||||
for(unsigned int i=0; i<m_quad_graph->getNumNodes(); i++)
|
||||
{
|
||||
m_next_node_index.push_back(-1);
|
||||
m_successor_index.push_back(-1);
|
||||
// 0 is always a valid successor - so even if the kart should end
|
||||
// up by accident on a non-selected path, it will keep on working.
|
||||
m_successor_index.push_back(0);
|
||||
}
|
||||
// For now pick one part on random, which is not adjusted during the run
|
||||
std::vector<unsigned int> next;
|
||||
|
@ -38,10 +38,15 @@ namespace irr
|
||||
class EndController : public Controller
|
||||
{
|
||||
private:
|
||||
int m_min_steps; //Minimum number of steps to check. If 0, the AI doesn't
|
||||
//even has check around the kart, if 1, it checks around
|
||||
//the kart always, and more than that will check the
|
||||
//remaining number of steps in front of the kart, always
|
||||
/** Stores the type of the previous controller. This is necessary so that
|
||||
* after the end of race ths kart (and its results) can still be
|
||||
* identified to be from a player kart. */
|
||||
bool m_was_player_controller;
|
||||
|
||||
int m_min_steps; //Minimum number of steps to check. If 0, the AI doesn't
|
||||
//even has check around the kart, if 1, it checks around
|
||||
//the kart always, and more than that will check the
|
||||
//remaining number of steps in front of the kart, always
|
||||
float m_max_handicap_accel; //The allowed maximum speed, in percentage,
|
||||
//from 0.0 to 1.0. Used only when
|
||||
//m_wait_for_players == true.
|
||||
@ -109,28 +114,30 @@ private:
|
||||
*variable, except handle_race_start() that isn't associated with any
|
||||
*specific action (more like, associated with inaction).
|
||||
*/
|
||||
void handleAcceleration(const float DELTA);
|
||||
void handleSteering(float dt);
|
||||
void handleRescue(const float DELTA);
|
||||
void handleBraking();
|
||||
|
||||
void handleAcceleration(const float DELTA);
|
||||
void handleSteering(float dt);
|
||||
void handleRescue(const float DELTA);
|
||||
void handleBraking();
|
||||
/*Lower level functions not called directly from update()*/
|
||||
float steerToAngle(const size_t SECTOR, const float ANGLE);
|
||||
float steerToPoint(const Vec3 &point, float dt);
|
||||
|
||||
void checkCrashes(const int STEPS, const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result);
|
||||
|
||||
float normalizeAngle(float angle);
|
||||
int calcSteps();
|
||||
void setSteering(float angle, float dt);
|
||||
void findCurve();
|
||||
float steerToAngle(const size_t SECTOR, const float ANGLE);
|
||||
float steerToPoint(const Vec3 &point, float dt);
|
||||
|
||||
void checkCrashes(const int STEPS, const Vec3& pos);
|
||||
void findNonCrashingPoint(Vec3 *result);
|
||||
float normalizeAngle(float angle);
|
||||
int calcSteps();
|
||||
void setSteering(float angle, float dt);
|
||||
void findCurve();
|
||||
public:
|
||||
EndController(Kart *kart);
|
||||
EndController(Kart *kart, ActivePlayer* player);
|
||||
~EndController();
|
||||
virtual void update (float delta) ;
|
||||
virtual void reset ();
|
||||
/** Returns if the original controller of the kart was a player
|
||||
* controller. This way e.g. highscores can still be assigned
|
||||
* to the right player. */
|
||||
virtual bool isPlayerController () const {return m_player!=NULL;}
|
||||
|
||||
}; // EndKart
|
||||
|
||||
#endif
|
||||
|
@ -33,26 +33,23 @@ class Player;
|
||||
class PlayerController : public Controller
|
||||
{
|
||||
private:
|
||||
int m_steer_val, m_steer_val_l, m_steer_val_r;
|
||||
int m_prev_accel;
|
||||
bool m_prev_brake;
|
||||
int m_steer_val, m_steer_val_l, m_steer_val_r;
|
||||
int m_prev_accel;
|
||||
bool m_prev_brake;
|
||||
|
||||
ActivePlayer *m_player;
|
||||
float m_penalty_time;
|
||||
float m_penalty_time;
|
||||
|
||||
SFXBase *m_bzzt_sound;
|
||||
SFXBase *m_wee_sound;
|
||||
SFXBase *m_ugh_sound;
|
||||
SFXBase *m_grab_sound;
|
||||
SFXBase *m_full_sound;
|
||||
SFXBase *m_bzzt_sound;
|
||||
SFXBase *m_wee_sound;
|
||||
SFXBase *m_ugh_sound;
|
||||
SFXBase *m_grab_sound;
|
||||
SFXBase *m_full_sound;
|
||||
|
||||
void steer(float, int);
|
||||
void steer(float, int);
|
||||
public:
|
||||
PlayerController (Kart *kart, ActivePlayer *_player,
|
||||
unsigned int player_index);
|
||||
~PlayerController ();
|
||||
ActivePlayer *getPlayer () { return m_player; }
|
||||
PlayerProfile *getPlayerProfile () { return m_player->getProfile(); }
|
||||
void update (float);
|
||||
void action (PlayerAction action, int value);
|
||||
void handleZipper ();
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "modes/world.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "karts/controller/end_controller.hpp"
|
||||
#include "karts/kart_model.hpp"
|
||||
#include "karts/kart_properties_manager.hpp"
|
||||
#include "network/race_state.hpp"
|
||||
@ -381,8 +382,6 @@ void Kart::reset()
|
||||
World::getWorld()->getPhysics()->addKart(this);
|
||||
}
|
||||
|
||||
if(m_node)
|
||||
m_node->setVisible(true); // In case that the kart was eliminated
|
||||
if(m_camera)
|
||||
m_camera->reset();
|
||||
// If the controller was replaced (e.g. replaced by end controller),
|
||||
@ -392,6 +391,10 @@ void Kart::reset()
|
||||
m_controller = m_saved_controller;
|
||||
m_saved_controller = NULL;
|
||||
}
|
||||
// Reset is also called when the kart is created, at which time
|
||||
// m_controller is not yet defined.
|
||||
if(m_controller)
|
||||
m_controller->reset();
|
||||
m_view_blocked_by_plunger = 0.0;
|
||||
m_attachment.clear();
|
||||
m_powerup.reset();
|
||||
@ -451,11 +454,17 @@ void Kart::reset()
|
||||
*/
|
||||
void Kart::finishedRace(float time)
|
||||
{
|
||||
// m_finished_race can be true if e.g. an AI kart was set to finish
|
||||
// because the race was over (i.e. estimating the finish time). If
|
||||
// this kart then crosses the finish line (with the end controller)
|
||||
// it would trigger a race end again.
|
||||
if(m_finished_race) return;
|
||||
m_finished_race = true;
|
||||
m_finish_time = time;
|
||||
m_kart_mode = KM_END_ANIM;
|
||||
m_controller->finishedRace(time);
|
||||
race_manager->RaceFinished(this, time);
|
||||
race_manager->kartFinishedRace(this, time);
|
||||
setController(new EndController(this, m_controller->getPlayer()));
|
||||
} // finishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -97,6 +97,11 @@ void Moveable::reset()
|
||||
m_body->setAngularVelocity(btVector3(0, 0, 0));
|
||||
m_body->setCenterOfMassTransform(m_transform);
|
||||
}
|
||||
if(m_node)
|
||||
m_node->setVisible(true); // In case that the objects was eliminated
|
||||
if(m_animated_node)
|
||||
m_animated_node->setVisible(true);
|
||||
|
||||
Coord c(m_transform);
|
||||
m_hpr = c.getHPR();
|
||||
} // reset
|
||||
|
@ -112,7 +112,7 @@ void MainLoop::updateRace(float dt)
|
||||
if ( World::getWorld()->getPhase() != WorldStatus::LIMBO_PHASE)
|
||||
{
|
||||
history->update(dt);
|
||||
World::getWorld()->update(dt);
|
||||
World::getWorld()->updateWorld(dt);
|
||||
} // phase != limbo phase
|
||||
} // updateRace
|
||||
|
||||
|
@ -83,21 +83,12 @@ void FollowTheLeaderRace::countdownReachedZero()
|
||||
// almost over, use fast music
|
||||
if(getCurrentNumKarts()==3)
|
||||
sound_manager->switchToFastMusic();
|
||||
|
||||
// The follow the leader race is over if there is only one kart left,
|
||||
// or if all players have gone
|
||||
if(isRaceOver())
|
||||
{
|
||||
// Note: LinearWorld::terminateRace adds the scores for all remaining
|
||||
// karts in the race.
|
||||
enterRaceOverState(false);
|
||||
return;
|
||||
}
|
||||
// End of race is detected from the World::update()
|
||||
} // countdownReachedZero
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The follow the leader race is over if there is only one kart left,
|
||||
* or if all players have gone.
|
||||
/** The follow the leader race is over if there is only one kart left (plus
|
||||
* the leader), or if all players have gone.
|
||||
*/
|
||||
bool FollowTheLeaderRace::isRaceOver()
|
||||
{
|
||||
@ -146,9 +137,13 @@ void FollowTheLeaderRace::raceResultOrder( int* order )
|
||||
race_time[kart_id] = race_manager->getOverallTime(kart_id);
|
||||
|
||||
// check this kart is not in front of leader. If it is, give a score of 0
|
||||
if(m_kart_info[kart_id].m_race_lap * world->getTrack()->getTrackLength() + getDistanceDownTrackForKart(kart_id) >
|
||||
m_kart_info[0].m_race_lap * world->getTrack()->getTrackLength() + getDistanceDownTrackForKart(0))
|
||||
if( getLapForKart(kart_id) * world->getTrack()->getTrackLength()
|
||||
+ getDistanceDownTrackForKart(kart_id)
|
||||
> getLapForKart(0) * world->getTrack()->getTrackLength()
|
||||
+ getDistanceDownTrackForKart(0))
|
||||
{
|
||||
scores[kart_id] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Bubblesort
|
||||
|
@ -23,7 +23,9 @@
|
||||
|
||||
class FollowTheLeaderRace : public LinearWorld
|
||||
{
|
||||
private:
|
||||
std::vector<float> m_leader_intervals; // time till elimination in follow leader
|
||||
|
||||
public:
|
||||
|
||||
FollowTheLeaderRace();
|
||||
|
@ -139,8 +139,8 @@ void LinearWorld::update(float delta)
|
||||
KartInfo& kart_info = m_kart_info[n];
|
||||
Kart* kart = m_karts[n];
|
||||
|
||||
// Nothing to do for karts that are currently being rescued.
|
||||
if(kart->isRescue()) continue;
|
||||
// Nothing to do for karts that are currently being rescued or eliminated
|
||||
if(kart->isRescue() || kart->isEliminated()) continue;
|
||||
|
||||
// ---------- deal with sector data ---------
|
||||
|
||||
@ -176,15 +176,14 @@ void LinearWorld::update(float delta)
|
||||
for(unsigned int i=0; i<kart_amount; i++)
|
||||
{
|
||||
// ---------- update rank ------
|
||||
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
||||
{
|
||||
updateRacePosition(m_karts[i], m_kart_info[i]);
|
||||
// During the last lap update the estimated finish time.
|
||||
// This is used to play the faster music, and by the AI
|
||||
if(m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1)
|
||||
m_kart_info[i].m_estimated_finish = estimateFinishTimeForKart(m_karts[i]);
|
||||
checkForWrongDirection(i);
|
||||
}
|
||||
if(m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
|
||||
continue;
|
||||
updateRacePosition(m_karts[i], m_kart_info[i]);
|
||||
// During the last lap update the estimated finish time.
|
||||
// This is used to play the faster music, and by the AI
|
||||
if(m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1)
|
||||
m_kart_info[i].m_estimated_finish = estimateFinishTimeForKart(m_karts[i]);
|
||||
checkForWrongDirection(i);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// FIXME: Debug output in case that the double position error
|
||||
@ -207,7 +206,6 @@ void LinearWorld::update(float delta)
|
||||
pos_used[m_karts[i]->getPosition()]=i;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -242,7 +240,6 @@ void LinearWorld::newLap(unsigned int kart_index)
|
||||
if(network_manager->getMode()!=NetworkManager::NW_CLIENT)
|
||||
{
|
||||
kart->finishedRace(getTime());
|
||||
createEndKart(kart_index);
|
||||
}
|
||||
}
|
||||
{
|
||||
@ -409,26 +406,6 @@ RaceGUI::KartIconDisplayInfo* LinearWorld::getKartsDisplayInfo()
|
||||
return m_kart_display_info;
|
||||
} // getKartsDisplayInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void LinearWorld::terminateRace()
|
||||
{
|
||||
World::terminateRace();
|
||||
|
||||
// if some karts have not yet finished the race yet, estimate
|
||||
// their times and use these values to proceed without waiting
|
||||
const unsigned int kart_amount = m_karts.size();
|
||||
for ( KartList::size_type i = 0; i < kart_amount; ++i)
|
||||
{
|
||||
// Eliminated karts have already called raceFinished.
|
||||
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
||||
{
|
||||
const float est_finish_time = m_kart_info[i].m_estimated_finish;
|
||||
m_karts[i]->finishedRace(est_finish_time);
|
||||
createEndKart(i);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
} // terminateRace
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Sets up the mapping from kart position to kart index.
|
||||
*/
|
||||
@ -465,7 +442,7 @@ float LinearWorld::estimateFinishTimeForKart(Kart* kart)
|
||||
// the average speed computed above.
|
||||
return getTime() + (full_distance - distance_covered) / average_speed;
|
||||
|
||||
} // estimateFinishTime
|
||||
} // estimateFinishTimeForKart
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Decide where to drop a rescued kart
|
||||
|
@ -54,58 +54,57 @@ private:
|
||||
|
||||
protected:
|
||||
RaceGUI::KartIconDisplayInfo* m_kart_display_info;
|
||||
|
||||
/** Linear races can trigger rescues for one additional reason : shortcuts.
|
||||
* It may need to do some specific world before calling the generic Kart::forceRescue
|
||||
*/
|
||||
void rescueKartAfterShortcut(Kart* kart, KartInfo& kart_info);
|
||||
|
||||
void checkForWrongDirection(unsigned int i);
|
||||
float estimateFinishTimeForKart(Kart* kart);
|
||||
void updateRacePosition ( Kart* kart, KartInfo& kart_info );
|
||||
public:
|
||||
LinearWorld();
|
||||
/** call just after instanciating. can't be moved to the contructor as child
|
||||
classes must be instanciated, otherwise polymorphism will fail and the
|
||||
results will be incorrect */
|
||||
void init();
|
||||
virtual ~LinearWorld();
|
||||
|
||||
|
||||
/** This vector contains an 'KartInfo' struct for every kart in the race.
|
||||
* This member is not strictly private but try not to use it directly outside
|
||||
* tightly related classes (e.g. AI)
|
||||
*/
|
||||
std::vector<KartInfo> m_kart_info;
|
||||
|
||||
virtual void update(float delta);
|
||||
|
||||
int getSectorForKart(const int kart_id) const;
|
||||
float getDistanceDownTrackForKart(const int kart_id) const;
|
||||
float getDistanceToCenterForKart(const int kart_id) const;
|
||||
float getEstimatedFinishTime(const int kart_id) const;
|
||||
int getLapForKart(const int kart_id) const;
|
||||
void setTimeAtLapForKart(float t, const int kart_id);
|
||||
float getTimeAtLapForKart(const int kart_id) const;
|
||||
/** Linear races can trigger rescues for one additional reason : shortcuts.
|
||||
* It may need to do some specific world before calling the generic Kart::forceRescue
|
||||
*/
|
||||
void rescueKartAfterShortcut(Kart* kart, KartInfo& kart_info);
|
||||
void checkForWrongDirection(unsigned int i);
|
||||
void updateRacePosition(Kart* kart, KartInfo& kart_info );
|
||||
virtual float estimateFinishTimeForKart(Kart* kart);
|
||||
|
||||
virtual RaceGUI::KartIconDisplayInfo* getKartsDisplayInfo();
|
||||
virtual void moveKartAfterRescue(Kart* kart, btRigidBody* body);
|
||||
|
||||
virtual void terminateRace();
|
||||
virtual void restartRace();
|
||||
|
||||
virtual bool raceHasLaps(){ return true; }
|
||||
virtual void newLap(unsigned int kart_index);
|
||||
public:
|
||||
LinearWorld();
|
||||
/** call just after instanciating. can't be moved to the contructor as child
|
||||
classes must be instanciated, otherwise polymorphism will fail and the
|
||||
results will be incorrect */
|
||||
void init();
|
||||
virtual ~LinearWorld();
|
||||
virtual void update(float delta);
|
||||
int getSectorForKart(const int kart_id) const;
|
||||
float getDistanceDownTrackForKart(const int kart_id) const;
|
||||
float getDistanceToCenterForKart(const int kart_id) const;
|
||||
float getEstimatedFinishTime(const int kart_id) const;
|
||||
int getLapForKart(const int kart_id) const;
|
||||
void setTimeAtLapForKart(float t, const int kart_id);
|
||||
float getTimeAtLapForKart(const int kart_id) const;
|
||||
|
||||
virtual bool haveBonusBoxes(){ return true; }
|
||||
virtual RaceGUI::KartIconDisplayInfo*
|
||||
getKartsDisplayInfo();
|
||||
virtual void moveKartAfterRescue(Kart* kart, btRigidBody* body);
|
||||
|
||||
virtual void restartRace();
|
||||
|
||||
virtual bool raceHasLaps(){ return true; }
|
||||
virtual void newLap(unsigned int kart_index);
|
||||
|
||||
virtual bool haveBonusBoxes(){ return true; }
|
||||
|
||||
/** Called by the race result GUI at the end of the race to know the final order
|
||||
(fill in the 'order' array) */
|
||||
virtual void raceResultOrder( int* order );
|
||||
virtual void raceResultOrder( int* order );
|
||||
/** Returns true if the kart is on a valid driveline quad.
|
||||
* \param kart_index Index of the kart.
|
||||
*/
|
||||
bool isOnRoad(unsigned int kart_index) const
|
||||
{ return m_kart_info[kart_index].m_on_road; }
|
||||
};
|
||||
bool isOnRoad(unsigned int kart_index) const
|
||||
{ return m_kart_info[kart_index].m_on_road; }
|
||||
}; // LinearWorld
|
||||
|
||||
#endif
|
||||
|
@ -115,7 +115,11 @@ void ProfileWorld::update(float dt)
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ProfileWorld::enterRaceOverState(const bool delay)
|
||||
/** This function is called when the race is finished, but end-of-race
|
||||
* animations have still to be played. In the case of profiling,
|
||||
* we can just abort here without waiting for the animations.
|
||||
*/
|
||||
void ProfileWorld::enterRaceOverState()
|
||||
{
|
||||
float runtime = (irr_driver->getRealTime()-m_start_time)*0.001f;
|
||||
printf("Number of frames: %d time %f, Average FPS: %f\n",
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
virtual std::string getInternalCode() const {return "PROFILE"; }
|
||||
virtual void update(float dt);
|
||||
virtual bool isRaceOver();
|
||||
virtual void enterRaceOverState(const bool delay=false);
|
||||
virtual void enterRaceOverState();
|
||||
|
||||
static void setProfileModeTime(float time);
|
||||
static void setProfileModeLaps(int laps);
|
||||
|
@ -26,54 +26,13 @@ StandardRace::StandardRace() : LinearWorld()
|
||||
WorldStatus::setClockMode(CLOCK_CHRONO);
|
||||
} // StandardRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
StandardRace::~StandardRace()
|
||||
{
|
||||
} // ~StandardRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called once per frame to update race specific data structures.
|
||||
* \param dt TIme step size.
|
||||
*/
|
||||
void StandardRace::update(float dt)
|
||||
{
|
||||
LinearWorld::update(dt);
|
||||
if(!WorldStatus::isRacePhase()) return;
|
||||
|
||||
// All karts are finished
|
||||
if(race_manager->getFinishedKarts() >= getNumKarts() )
|
||||
{
|
||||
enterRaceOverState();
|
||||
unlock_manager->raceFinished();
|
||||
} // if all karts are finished
|
||||
|
||||
// All player karts are finished, but computer still racing
|
||||
// ===========================================================
|
||||
else if(isRaceOver())
|
||||
{
|
||||
// Update the estimated finishing time for all karts that haven't
|
||||
// finished yet.
|
||||
const unsigned int kart_amount = getNumKarts();
|
||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||
{
|
||||
if(!m_karts[i]->hasFinishedRace())
|
||||
{
|
||||
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
|
||||
createEndKart(i);
|
||||
}
|
||||
} // i<kart_amount
|
||||
|
||||
// Set delay mode to have time for camera animation, and
|
||||
// to give the AI some time to get non-estimated timings
|
||||
enterRaceOverState();
|
||||
}
|
||||
} // update
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Returns true if the race is finished, i.e. all player karts are finished.
|
||||
*/
|
||||
bool StandardRace::isRaceOver()
|
||||
{
|
||||
// The race is over if all players have finished the race. Remaining
|
||||
// times for AI opponents will be estimated in enterRaceOverState
|
||||
return race_manager->allPlayerFinished();
|
||||
} // isRaceOver
|
||||
|
||||
@ -106,6 +65,6 @@ std::string StandardRace::getIdent() const
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
return IDENT_TTRIAL;
|
||||
else
|
||||
return IDENT_STD;
|
||||
|
||||
return IDENT_STD;
|
||||
} // getIdent
|
||||
|
||||
|
@ -26,18 +26,19 @@
|
||||
*/
|
||||
class StandardRace : public LinearWorld
|
||||
{
|
||||
public:
|
||||
StandardRace();
|
||||
virtual ~StandardRace();
|
||||
|
||||
protected:
|
||||
// clock events
|
||||
virtual bool isRaceOver();
|
||||
virtual bool isRaceOver();
|
||||
|
||||
public:
|
||||
StandardRace();
|
||||
virtual ~StandardRace() {};
|
||||
|
||||
// overriding World methods
|
||||
virtual void update(float delta);
|
||||
virtual void getDefaultCollectibles(int& collectible_type, int& amount);
|
||||
virtual bool haveBonusBoxes();
|
||||
virtual std::string getIdent() const;
|
||||
virtual void getDefaultCollectibles(int& collectible_type, int& amount);
|
||||
virtual bool haveBonusBoxes();
|
||||
virtual std::string
|
||||
getIdent() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -59,26 +59,6 @@ ThreeStrikesBattle::~ThreeStrikesBattle()
|
||||
delete[] m_kart_display_info;
|
||||
} // ~ThreeStrikesBattle
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ThreeStrikesBattle::terminateRace()
|
||||
{
|
||||
updateKartRanks();
|
||||
|
||||
// if some karts have not yet finished yet
|
||||
const unsigned int kart_amount = m_karts.size();
|
||||
for ( KartList::size_type i = 0; i < kart_amount; ++i)
|
||||
{
|
||||
if(!m_karts[i]->hasFinishedRace())
|
||||
{
|
||||
m_karts[i]->finishedRace(WorldStatus::getTime());
|
||||
createEndKart(i);
|
||||
} // if !hasFinishedRace
|
||||
} // for i
|
||||
|
||||
World::terminateRace();
|
||||
} // terminateRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ThreeStrikesBattle::kartHit(const int kart_id)
|
||||
{
|
||||
@ -171,16 +151,6 @@ void ThreeStrikesBattle::updateKartRanks()
|
||||
delete [] karts_list;
|
||||
} // updateKartRank
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ThreeStrikesBattle::enterRaceOverState(const bool delay)
|
||||
{
|
||||
World::enterRaceOverState(delay);
|
||||
// Add the results for the remaining kart
|
||||
for(unsigned int i=0; i<getNumKarts(); i++)
|
||||
if(!m_karts[i]->isEliminated())
|
||||
race_manager->RaceFinished(m_karts[i], WorldStatus::getTime());
|
||||
} // enterRaceOverState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** The battle is over if only one kart is left, or no player kart.
|
||||
*/
|
||||
@ -189,6 +159,17 @@ bool ThreeStrikesBattle::isRaceOver()
|
||||
return getCurrentNumKarts()==1 || getCurrentNumPlayers()==0;
|
||||
} // isRaceOver
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when the race finishes, i.e. after playing (if necessary) an
|
||||
* end of race animation. It updates the time for all karts still racing,
|
||||
* and then updates the ranks.
|
||||
*/
|
||||
void ThreeStrikesBattle::terminateRace()
|
||||
{
|
||||
updateKartRanks();
|
||||
World::terminateRace();
|
||||
} // terminateRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void ThreeStrikesBattle::restartRace()
|
||||
{
|
||||
|
@ -51,7 +51,6 @@ public:
|
||||
|
||||
// overriding World methods
|
||||
virtual void restartRace();
|
||||
virtual void enterRaceOverState(const bool delay=false);
|
||||
|
||||
//virtual void getDefaultCollectibles(int& collectible_type, int& amount);
|
||||
virtual bool useFastMusicNearEnd() const { return false; }
|
||||
|
@ -55,10 +55,23 @@
|
||||
|
||||
World* World::m_world = NULL;
|
||||
|
||||
/** The main world class is used to handle the track and the karts.
|
||||
* The end of the race is detected in two phases: first the (abstract)
|
||||
* function isRaceOver, which must be implemented by all game modes,
|
||||
* must return true. In which case enterRaceOverState is called. At
|
||||
* this time a winning (or losing) animation can be played. The WorldStatus
|
||||
* class will in its enterRaceOverState switch to DELAY_FINISH_PHASE,
|
||||
* but the remaining AI kart will keep on racing during that time.
|
||||
* After a time period specified in stk_config.xml WorldStatus will
|
||||
* switch to FINISH_PHASE and call terminateRace. Now the finishing status
|
||||
* of all karts is set (i.e. in a normal race the arrival time for karts
|
||||
* will be estimated), highscore is updated, and the race result gui
|
||||
* is being displayed.
|
||||
*/
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Constructor. Note that in the constructor it is not possible to call any
|
||||
* functions that use RaceManager::getWorld(), since this is only defined
|
||||
* after the constructor. Those functions can be called in the init()
|
||||
* functions that use World::getWorld(), since this is only defined
|
||||
* after the constructor. Those functions must be called in the init()
|
||||
* function, which is called immediately after the constructor.
|
||||
*/
|
||||
World::World() : WorldStatus()
|
||||
@ -70,7 +83,7 @@ World::World() : WorldStatus()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** This function is called after the World constructor. In init() functions
|
||||
* can be called that use RaceManager::getWorld(). The init function is
|
||||
* can be called that use World::getWorld(). The init function is
|
||||
* called immediately after the constructor.
|
||||
*/
|
||||
void World::init()
|
||||
@ -146,7 +159,7 @@ void World::init()
|
||||
* this player on the local machine.
|
||||
* \param global_player_id If the kart is a player kart this is the index of
|
||||
* this player globally (i.e. including network players).
|
||||
* \param init_pos The start XYZ coordinates.
|
||||
* \param init_pos The start transform (xyz and hpr).
|
||||
*/
|
||||
Kart *World::createKart(const std::string &kart_ident, int index,
|
||||
int local_player_id, int global_player_id,
|
||||
@ -158,7 +171,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
|
||||
switch(race_manager->getKartType(index))
|
||||
{
|
||||
case RaceManager::KT_PLAYER:
|
||||
std::cout << "===== World : creating player kart for kart #" << index << " which has local_player_id " << local_player_id << " ===========\n";
|
||||
std::cout << "===== World : creating player controller for kart #" << index << " which has local_player_id " << local_player_id << " ===========\n";
|
||||
controller = new PlayerController(new_kart,
|
||||
StateManager::get()->getActivePlayer(local_player_id),
|
||||
local_player_id);
|
||||
@ -170,7 +183,7 @@ Kart *World::createKart(const std::string &kart_ident, int index,
|
||||
//m_num_players++;
|
||||
//break;
|
||||
case RaceManager::KT_AI:
|
||||
std::cout << "===== World : creating AI kart for #" << index << "===========\n";
|
||||
std::cout << "===== World : creating AI controller for #" << index << "===========\n";
|
||||
|
||||
controller = loadAIController(new_kart);
|
||||
break;
|
||||
@ -254,13 +267,27 @@ void World::onGo()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called at the end of a race. Updates highscores, pauses the game, and
|
||||
* informs the unlock manager about the finished race.
|
||||
* informs the unlock manager about the finished race. This function must
|
||||
* be called after all other stats were updated from the different game
|
||||
* modes.
|
||||
*/
|
||||
void World::terminateRace()
|
||||
{
|
||||
// Update the estimated finishing time for all karts that haven't
|
||||
// finished yet.
|
||||
const unsigned int kart_amount = getNumKarts();
|
||||
for(unsigned int i = 0; i < kart_amount ; i++)
|
||||
{
|
||||
if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
|
||||
{
|
||||
m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
|
||||
|
||||
}
|
||||
} // i<kart_amount
|
||||
updateHighscores();
|
||||
WorldStatus::pause();
|
||||
unlock_manager->raceFinished();
|
||||
WorldStatus::terminateRace();
|
||||
} // terminateRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -340,6 +367,26 @@ void World::resetAllKarts()
|
||||
m_karts[i]->getCamera()->setInitialTransform();
|
||||
} // resetAllKarts
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** This is the main interface to update the world. This function calls
|
||||
* update(), and checks for the end of the race. Note that race over
|
||||
* handling can not necessarily be done in update(), since not all
|
||||
* data structures might have been updated (e.g.LinearWorld must
|
||||
* call World::update() first, to get updated kart positions. If race
|
||||
* over would be handled in World::update, LinearWorld had no opportunity
|
||||
* to update its data structures before the race is finished).
|
||||
* \param dt Time step size.
|
||||
*/
|
||||
void World::updateWorld(float dt)
|
||||
{
|
||||
update(dt);
|
||||
if( (!isFinishPhase()) && isRaceOver())
|
||||
{
|
||||
enterRaceOverState();
|
||||
}
|
||||
|
||||
} // updateWorld
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::update(float dt)
|
||||
{
|
||||
@ -530,13 +577,12 @@ void World::removeKart(int kart_number)
|
||||
camera->setMode(Camera::CM_LEADER_MODE);
|
||||
m_eliminated_players++;
|
||||
}
|
||||
//projectile_manager->newExplosion(kart->getXYZ());
|
||||
|
||||
// The kart can't be really removed from the m_kart array, since otherwise
|
||||
// a race can't be restarted. So it's only marked to be eliminated (and
|
||||
// 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, WorldStatus::getTime());
|
||||
kart->eliminate();
|
||||
m_eliminated_karts++;
|
||||
|
||||
@ -594,13 +640,4 @@ void World::unpause()
|
||||
((PlayerController*)(m_karts[i]->getController()))->resetInputState();
|
||||
} // pause
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Replaces the kart with index i with an EndKart, i.e. a kart that shows the
|
||||
* end animation, and does not use any items anymore.
|
||||
* \param i Index of the kart to be replaced.
|
||||
*/
|
||||
void World::createEndKart(unsigned int i)
|
||||
{
|
||||
m_karts[i]->setController(new EndController(m_karts[i]));
|
||||
} // createEndKart
|
||||
/* EOF */
|
||||
|
@ -110,7 +110,6 @@ protected:
|
||||
void removeKart (int kart_number);
|
||||
Controller*
|
||||
loadAIController (Kart *kart);
|
||||
void estimateFinishTimes();
|
||||
|
||||
virtual Kart *createKart(const std::string &kart_ident, int index,
|
||||
int local_player_id, int global_player_id,
|
||||
@ -122,8 +121,19 @@ protected:
|
||||
/** Pointer to the race GUI. The race GUI is handedl by world. */
|
||||
RaceGUI *m_race_gui;
|
||||
|
||||
virtual void onGo();
|
||||
|
||||
virtual void onGo();
|
||||
/** Returns true if the race is over. Must be defined by all modes. */
|
||||
virtual bool isRaceOver() = 0;
|
||||
virtual void update(float dt);
|
||||
/** Used for AI karts that are still racing when all player kart finished.
|
||||
* Generally it should estimate the arrival time for those karts, but as
|
||||
* a default (useful for battle mode and ftl races) we just use the
|
||||
* current time for this (since this is a good value for karts still
|
||||
* around at the end of a race, and other criteria (number of lives,
|
||||
* race position) will be used to determine the final order.
|
||||
*/
|
||||
virtual float estimateFinishTimeForKart(Kart* kart) {return getTime(); }
|
||||
|
||||
public:
|
||||
World();
|
||||
virtual ~World();
|
||||
@ -139,9 +149,7 @@ public:
|
||||
results will be incorrect */
|
||||
virtual void init();
|
||||
|
||||
virtual void update(float delta);
|
||||
/** Returns true if the race is over. Must be defined by all modes. */
|
||||
virtual bool isRaceOver() = 0;
|
||||
void updateWorld(float dt);
|
||||
virtual void restartRace();
|
||||
void disableRace(); // Put race into limbo phase
|
||||
/** Returns a pointer to the race gui. */
|
||||
@ -225,7 +233,6 @@ public:
|
||||
/** Called by the race result GUI at the end of the race to know the final order
|
||||
(fill in the 'order' array) */
|
||||
virtual void raceResultOrder( int* order ) = 0;
|
||||
void createEndKart(unsigned int i);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -70,24 +70,31 @@ void WorldStatus::setClockMode(const ClockType mode, const float initial_time)
|
||||
} // setClockMode
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Adjusts the phase to be finish or delay_finish.
|
||||
* \param delay True if there should be a delay before the game finishes.
|
||||
/** Called when the race is finished, but it still leaves some time
|
||||
* for an end of race animation, and potentially let some more AI karts
|
||||
* finish the race.
|
||||
*/
|
||||
void WorldStatus::enterRaceOverState(const bool delay)
|
||||
void WorldStatus::enterRaceOverState()
|
||||
{
|
||||
if(m_phase == DELAY_FINISH_PHASE || m_phase == FINISH_PHASE) return; // we already know
|
||||
// Don't
|
||||
if( m_phase == DELAY_FINISH_PHASE
|
||||
|| m_phase == FINISH_PHASE
|
||||
|| m_phase == LIMBO_PHASE ) return;
|
||||
|
||||
if(delay)
|
||||
{
|
||||
m_phase = DELAY_FINISH_PHASE;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
}
|
||||
else
|
||||
m_phase = FINISH_PHASE;
|
||||
m_phase = DELAY_FINISH_PHASE;
|
||||
m_auxiliary_timer = 0.0f;
|
||||
|
||||
} // enterRaceOverState
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Called when it's really over (delay over if any). This function must be
|
||||
* called after all stats were updated from the different modes!
|
||||
*/
|
||||
void WorldStatus::terminateRace()
|
||||
{
|
||||
if(network_manager->getMode()==NetworkManager::NW_SERVER)
|
||||
network_manager->sendRaceResults();
|
||||
} // enterRaceOverState
|
||||
} // terminateRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Updates all status information, called once per frame.
|
||||
@ -150,8 +157,8 @@ void WorldStatus::update(const float dt)
|
||||
// NOTE: no break, fall through to FINISH_PHASE handling!!
|
||||
}
|
||||
case FINISH_PHASE:
|
||||
new RaceOverDialog(0.6f, 0.9f);
|
||||
terminateRace();
|
||||
new RaceOverDialog(0.6f, 0.9f);
|
||||
return;
|
||||
default: break; // default for RACE_PHASE, LIMBO_PHASE
|
||||
}
|
||||
|
@ -115,12 +115,9 @@ public:
|
||||
|
||||
void pause();
|
||||
void unpause();
|
||||
|
||||
virtual void enterRaceOverState(const bool delay=false);
|
||||
virtual void enterRaceOverState();
|
||||
|
||||
/** Called when it's really over (delay over if any)
|
||||
*/
|
||||
virtual void terminateRace() = 0;
|
||||
virtual void terminateRace();
|
||||
|
||||
/*
|
||||
* Will be called to notify your derived class that the clock,
|
||||
|
@ -56,7 +56,6 @@ RaceResultMessage::RaceResultMessage(ENetPacket* pkt)
|
||||
char position = getChar();
|
||||
kart->setPosition(position);
|
||||
kart->finishedRace(time);
|
||||
world->createEndKart(i);
|
||||
}
|
||||
} // RaceResultMessage
|
||||
|
||||
|
@ -49,6 +49,7 @@ class GrandPrixData
|
||||
public:
|
||||
|
||||
/** Load the GrandPrixData from the given filename */
|
||||
#pragma warning(disable:4290)
|
||||
GrandPrixData (const std::string filename) throw(std::logic_error);
|
||||
GrandPrixData () {}; // empty for initialising
|
||||
|
||||
|
@ -373,12 +373,13 @@ void RaceManager::exitRace()
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** A kart has finished the race at the specified time (which can be
|
||||
* different from RaceManager::getWorld()->getClock() in case of setting extrapolated arrival
|
||||
* times).
|
||||
* different from World::getWorld()->getClock() in case of setting
|
||||
* extrapolated arrival times). This function is only called from
|
||||
* kart::finishedRace()
|
||||
* \param kart The kart that finished the race.
|
||||
* \param time Time at which the kart finished the race.
|
||||
*/
|
||||
void RaceManager::RaceFinished(const Kart *kart, float time)
|
||||
void RaceManager::kartFinishedRace(const Kart *kart, float time)
|
||||
{
|
||||
unsigned int id = kart->getWorldKartId();
|
||||
int pos = kart->getPosition();
|
||||
@ -392,7 +393,7 @@ void RaceManager::RaceFinished(const Kart *kart, float time)
|
||||
m_kart_status[id].m_last_time = time;
|
||||
m_num_finished_karts ++;
|
||||
if(kart->getController()->isPlayerController()) m_num_finished_players++;
|
||||
} // raceFinished
|
||||
} // kartFinishedRace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Reruns the last race. This is called after a race is finished, and it will
|
||||
|
@ -210,7 +210,7 @@ public:
|
||||
|
||||
void setNumPlayers(int num);
|
||||
void setPlayerKart(unsigned int player_id, const RemoteKartInfo& ki);
|
||||
void RaceFinished(const Kart* kart, float time);
|
||||
void kartFinishedRace(const Kart* kart, float time);
|
||||
void setTrack(const std::string& track);
|
||||
void setGrandPrix(const GrandPrixData &gp){ m_grand_prix = gp; }
|
||||
void setDifficulty(Difficulty diff);
|
||||
|
Loading…
x
Reference in New Issue
Block a user