diff --git a/data/stk_config.xml b/data/stk_config.xml index f4b0b6280..fd9a72589 100644 --- a/data/stk_config.xml +++ b/data/stk_config.xml @@ -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" /> diff --git a/src/audio/music_information.hpp b/src/audio/music_information.hpp index 648d943ff..d3f2cad2d 100644 --- a/src/audio/music_information.hpp +++ b/src/audio/music_information.hpp @@ -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; } diff --git a/src/karts/controller/controller.cpp b/src/karts/controller/controller.cpp index 871a81513..468b83787 100644 --- a/src/karts/controller/controller.cpp +++ b/src/karts/controller/controller.cpp @@ -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 // ---------------------------------------------------------------------------- diff --git a/src/karts/controller/controller.hpp b/src/karts/controller/controller.hpp index 572434e18..c92dabf1e 100644 --- a/src/karts/controller/controller.hpp +++ b/src/karts/controller/controller.hpp @@ -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) {}; diff --git a/src/karts/controller/end_controller.cpp b/src/karts/controller/end_controller.cpp index 06a836724..051d3aac5 100644 --- a/src/karts/controller/end_controller.cpp +++ b/src/karts/controller/end_controller.cpp @@ -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; igetNumNodes(); 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 next; diff --git a/src/karts/controller/end_controller.hpp b/src/karts/controller/end_controller.hpp index 1ac27c5b3..6713f6537 100644 --- a/src/karts/controller/end_controller.hpp +++ b/src/karts/controller/end_controller.hpp @@ -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 diff --git a/src/karts/controller/player_controller.hpp b/src/karts/controller/player_controller.hpp index 3e7dae7a9..c5c9aee70 100644 --- a/src/karts/controller/player_controller.hpp +++ b/src/karts/controller/player_controller.hpp @@ -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 (); diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index cab27dc13..93829ec49 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -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 //----------------------------------------------------------------------------- diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index cae408407..fd9df3e61 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -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 diff --git a/src/main_loop.cpp b/src/main_loop.cpp index 218bed3dd..aafc9c5ac 100644 --- a/src/main_loop.cpp +++ b/src/main_loop.cpp @@ -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 diff --git a/src/modes/follow_the_leader.cpp b/src/modes/follow_the_leader.cpp index badafa41a..3035dca2f 100644 --- a/src/modes/follow_the_leader.cpp +++ b/src/modes/follow_the_leader.cpp @@ -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 diff --git a/src/modes/follow_the_leader.hpp b/src/modes/follow_the_leader.hpp index b9119ac6f..f32b7a654 100644 --- a/src/modes/follow_the_leader.hpp +++ b/src/modes/follow_the_leader.hpp @@ -23,7 +23,9 @@ class FollowTheLeaderRace : public LinearWorld { +private: std::vector m_leader_intervals; // time till elimination in follow leader + public: FollowTheLeaderRace(); diff --git a/src/modes/linear_world.cpp b/src/modes/linear_world.cpp index db56b8e3c..3f0025d37 100644 --- a/src/modes/linear_world.cpp +++ b/src/modes/linear_world.cpp @@ -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; ihasFinishedRace() && !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 diff --git a/src/modes/linear_world.hpp b/src/modes/linear_world.hpp index ede017ede..3e38d8a21 100644 --- a/src/modes/linear_world.hpp +++ b/src/modes/linear_world.hpp @@ -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 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 diff --git a/src/modes/profile_world.cpp b/src/modes/profile_world.cpp index 25b8d0188..6c729be77 100644 --- a/src/modes/profile_world.cpp +++ b/src/modes/profile_world.cpp @@ -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", diff --git a/src/modes/profile_world.hpp b/src/modes/profile_world.hpp index b7c574d48..8ff342762 100644 --- a/src/modes/profile_world.hpp +++ b/src/modes/profile_world.hpp @@ -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); diff --git a/src/modes/standard_race.cpp b/src/modes/standard_race.cpp index 82091a98a..b954b7891 100644 --- a/src/modes/standard_race.cpp +++ b/src/modes/standard_race.cpp @@ -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); - } - } // iallPlayerFinished(); } // 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 + diff --git a/src/modes/standard_race.hpp b/src/modes/standard_race.hpp index 42ef28c35..2971b70e3 100644 --- a/src/modes/standard_race.hpp +++ b/src/modes/standard_race.hpp @@ -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 diff --git a/src/modes/three_strikes_battle.cpp b/src/modes/three_strikes_battle.cpp index 1c87cdad7..9aaadacba 100644 --- a/src/modes/three_strikes_battle.cpp +++ b/src/modes/three_strikes_battle.cpp @@ -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; iisEliminated()) - 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() { diff --git a/src/modes/three_strikes_battle.hpp b/src/modes/three_strikes_battle.hpp index 13be07e0d..ded5c9a7d 100644 --- a/src/modes/three_strikes_battle.hpp +++ b/src/modes/three_strikes_battle.hpp @@ -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; } diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 4c67287d3..4bb508914 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -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])); + + } + } // iraceFinished(); + 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 */ diff --git a/src/modes/world.hpp b/src/modes/world.hpp index 59e562ddf..93d99123c 100644 --- a/src/modes/world.hpp +++ b/src/modes/world.hpp @@ -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 diff --git a/src/modes/world_status.cpp b/src/modes/world_status.cpp index 2178f805d..cc063bdb4 100644 --- a/src/modes/world_status.cpp +++ b/src/modes/world_status.cpp @@ -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 } diff --git a/src/modes/world_status.hpp b/src/modes/world_status.hpp index 332bbd142..8629ce5fe 100644 --- a/src/modes/world_status.hpp +++ b/src/modes/world_status.hpp @@ -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, diff --git a/src/network/race_result_message.cpp b/src/network/race_result_message.cpp index deed59586..2b4db9767 100644 --- a/src/network/race_result_message.cpp +++ b/src/network/race_result_message.cpp @@ -56,7 +56,6 @@ RaceResultMessage::RaceResultMessage(ENetPacket* pkt) char position = getChar(); kart->setPosition(position); kart->finishedRace(time); - world->createEndKart(i); } } // RaceResultMessage diff --git a/src/race/grand_prix_data.hpp b/src/race/grand_prix_data.hpp index 974faedbf..9ef723728 100644 --- a/src/race/grand_prix_data.hpp +++ b/src/race/grand_prix_data.hpp @@ -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 diff --git a/src/race/race_manager.cpp b/src/race/race_manager.cpp index 2e84d4dce..529391545 100644 --- a/src/race/race_manager.cpp +++ b/src/race/race_manager.cpp @@ -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 diff --git a/src/race/race_manager.hpp b/src/race/race_manager.hpp index 32b921fda..737ac0272 100644 --- a/src/race/race_manager.hpp +++ b/src/race/race_manager.hpp @@ -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);