1 //
2 //  SuperTuxKart - a fun racing game with go-kart
3 //  Copyright (C) 2006-2015 SuperTuxKart-Team
4 //
5 //  This program is free software; you can redistribute it and/or
6 //  modify it under the terms of the GNU General Public License
7 //  as published by the Free Software Foundation; either version 3
8 //  of the License, or (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 #include "modes/world.hpp"
20 
21 #include "audio/music_manager.hpp"
22 #include "audio/sfx_base.hpp"
23 #include "audio/sfx_manager.hpp"
24 #include "config/player_manager.hpp"
25 #include "challenges/unlock_manager.hpp"
26 #include "config/user_config.hpp"
27 #include "graphics/camera.hpp"
28 #include "graphics/central_settings.hpp"
29 #include "graphics/irr_driver.hpp"
30 #include "graphics/material.hpp"
31 #include "graphics/material_manager.hpp"
32 #include "graphics/render_info.hpp"
33 #include "guiengine/modaldialog.hpp"
34 #include "guiengine/screen_keyboard.hpp"
35 #include "io/file_manager.hpp"
36 #include "input/device_manager.hpp"
37 #include "input/keyboard_device.hpp"
38 #include "items/projectile_manager.hpp"
39 #include "karts/controller/battle_ai.hpp"
40 #include "karts/ghost_kart.hpp"
41 #include "karts/controller/end_controller.hpp"
42 #include "karts/controller/local_player_controller.hpp"
43 #include "karts/controller/skidding_ai.hpp"
44 #include "karts/controller/soccer_ai.hpp"
45 #include "karts/controller/spare_tire_ai.hpp"
46 #include "karts/controller/test_ai.hpp"
47 #include "karts/controller/network_ai_controller.hpp"
48 #include "karts/controller/network_player_controller.hpp"
49 #include "karts/kart.hpp"
50 #include "karts/kart_model.hpp"
51 #include "karts/kart_properties_manager.hpp"
52 #include "karts/kart_rewinder.hpp"
53 #include "main_loop.hpp"
54 #include "modes/overworld.hpp"
55 #include "network/child_loop.hpp"
56 #include "network/protocols/client_lobby.hpp"
57 #include "network/network_config.hpp"
58 #include "network/rewind_manager.hpp"
59 #include "network/stk_host.hpp"
60 #include "physics/btKart.hpp"
61 #include "physics/physics.hpp"
62 #include "physics/triangle_mesh.hpp"
63 #include "race/highscore_manager.hpp"
64 #include "race/history.hpp"
65 #include "race/race_manager.hpp"
66 #include "replay/replay_play.hpp"
67 #include "replay/replay_recorder.hpp"
68 #include "scriptengine/script_engine.hpp"
69 #include "states_screens/dialogs/race_paused_dialog.hpp"
70 #include "states_screens/race_gui_base.hpp"
71 #include "states_screens/main_menu_screen.hpp"
72 #include "states_screens/race_gui.hpp"
73 #include "states_screens/race_result_gui.hpp"
74 #include "states_screens/state_manager.hpp"
75 #include "tracks/check_manager.hpp"
76 #include "tracks/track.hpp"
77 #include "tracks/track_manager.hpp"
78 #include "tracks/track_object.hpp"
79 #include "tracks/track_object_manager.hpp"
80 #include "utils/constants.hpp"
81 #include "utils/profiler.hpp"
82 #include "utils/translation.hpp"
83 #include "utils/string_utils.hpp"
84 
85 #include <algorithm>
86 #include <assert.h>
87 #include <ctime>
88 #include <sstream>
89 #include <stdexcept>
90 
91 
92 World* World::m_world[PT_COUNT];
93 
94 /** The main world class is used to handle the track and the karts.
95  *  The end of the race is detected in two phases: first the (abstract)
96  *  function isRaceOver, which must be implemented by all game modes,
97  *  must return true. In which case enterRaceOverState is called. At
98  *  this time a winning (or losing) animation can be played. The WorldStatus
99  *  class will in its enterRaceOverState switch to DELAY_FINISH_PHASE,
100  *  but the remaining AI kart will keep on racing during that time.
101  *  After a time period specified in stk_config.xml WorldStatus will
102  *  switch to FINISH_PHASE and call terminateRace. Now the finishing status
103  *  of all karts is set (i.e. in a normal race the arrival time for karts
104  *  will be estimated), highscore is updated, and the race result gui
105  *  is being displayed.
106  *  Rescuing is handled via the three functions:
107  *  getNumberOfRescuePositions() - which returns the number of rescue
108  *           positions defined.
109  *  getRescuePositionIndex(AbstractKart *kart) - which determines the
110  *           index of the rescue position to be used for the given kart.
111  *  getRescueTransform(unsigned int index) - which returns the transform
112  *           (i.e. position and rotation) for the specified rescue
113  *           position.
114  *  This allows the world class to do some tests to make sure all rescue
115  *  positions are valid (when started with --track-debug). It tries to
116  *  place all karts on all rescue positions. If there are any problems
117  *  (e.g. a rescue position not over terrain (perhaps because it is too
118  *  low); or the rescue position is on a texture which will immediately
119  *  trigger another rescue), a warning message will be printed.
120  */
121 
122 //-----------------------------------------------------------------------------
123 /** Constructor. Note that in the constructor it is not possible to call any
124  *  functions that use World::getWorld(), since this is only defined
125  *  after the constructor. Those functions must be called in the init()
126  *  function, which is called immediately after the constructor.
127  */
World()128 World::World() : WorldStatus()
129 {
130     if (m_process_type == PT_MAIN)
131         GUIEngine::getDevice()->setResizable(true);
132     RewindManager::setEnable(NetworkConfig::get()->isNetworking());
133 #ifdef DEBUG
134     m_magic_number = 0xB01D6543;
135 #endif
136 
137     m_race_gui           = NULL;
138     m_saved_race_gui     = NULL;
139     m_use_highscores     = true;
140     m_schedule_pause     = false;
141     m_schedule_unpause   = false;
142     m_schedule_exit_race = false;
143     m_schedule_tutorial  = false;
144     m_is_network_world   = false;
145 
146     m_stop_music_when_dialog_open = true;
147 
148     WorldStatus::setClockMode(CLOCK_CHRONO);
149 
150 }   // World
151 
152 // ----------------------------------------------------------------------------
153 /** This function is called after instanciating. The code here can't be moved
154  *  to the contructor as child classes must be instanciated, otherwise
155  *  polymorphism will fail and the results will be incorrect . Also in init()
156  *  functions can be called that use World::getWorld().
157  */
init()158 void World::init()
159 {
160     m_ended_early         = false;
161     m_faster_music_active = false;
162     m_fastest_kart        = 0;
163     m_eliminated_karts    = 0;
164     m_eliminated_players  = 0;
165     m_num_players         = 0;
166     unsigned int gk       = 0;
167     m_red_ai = m_blue_ai = 0;
168     if (RaceManager::get()->hasGhostKarts())
169         gk = ReplayPlay::get()->getNumGhostKart();
170 
171     // Create the race gui before anything else is attached to the scene node
172     // (which happens when the track is loaded). This allows the race gui to
173     // do any rendering on texture. Note that this function can NOT be called
174     // in the World constuctor, since it might be overwritten by a the game
175     // mode class, which would not have been constructed at the time that this
176     // constructor is called, so the wrong race gui would be created.
177     createRaceGUI();
178     main_loop->renderGUI(1000);
179     RewindManager::create();
180     main_loop->renderGUI(1100);
181     // Grab the track file
182     Track *track = track_manager->getTrack(RaceManager::get()->getTrackName());
183     if (m_process_type == PT_MAIN)
184     {
185         Scripting::ScriptEngine::getInstance<Scripting::ScriptEngine>();
186         if(!track)
187         {
188             std::ostringstream msg;
189             msg << "Track '" << RaceManager::get()->getTrackName()
190                 << "' not found.\n";
191             throw std::runtime_error(msg.str());
192         }
193 
194         std::string script_path = track->getTrackFile("scripting.as");
195         Scripting::ScriptEngine::getInstance()->loadScript(script_path, true);
196     }
197     main_loop->renderGUI(1200);
198     // Create the physics
199     Physics::create();
200     main_loop->renderGUI(1300);
201     unsigned int num_karts = RaceManager::get()->getNumberOfKarts();
202     //assert(num_karts > 0);
203 
204     // Load the track models - this must be done before the karts so that the
205     // karts can be positioned properly on (and not in) the tracks.
206     // This also defines the static Track::getCurrentTrack function.
207     if (m_process_type == PT_MAIN)
208         track->loadTrackModel(RaceManager::get()->getReverseTrack());
209     else
210     {
211         Track* child_track = Track::getCurrentTrack();
212         ChildLoop* child_loop = STKHost::getByType(PT_MAIN)->getChildLoop();
213         while (!child_loop->isAborted() && child_track == NULL)
214         {
215             StkTime::sleep(1);
216             child_track = Track::getCurrentTrack();
217         }
218         if (!child_loop->isAborted())
219             child_track->initChildTrack();
220     }
221 
222     // Shuffles the start transforms with playing 3-strikes or free for all battles.
223     if ((RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES ||
224          RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL) &&
225          !NetworkConfig::get()->isNetworking())
226     {
227         track->shuffleStartTransforms();
228     }
229 
230     main_loop->renderGUI(6998);
231     if (gk > 0)
232     {
233         ReplayPlay::get()->load();
234         for (unsigned int k = 0; k < gk; k++)
235             m_karts.push_back(ReplayPlay::get()->getGhostKart(k));
236     }
237     main_loop->renderGUI(6999);
238 
239     // Assign team of AIs for team mode before createKart
240     if (hasTeam())
241         setAITeam();
242 
243     for(unsigned int i=0; i<num_karts; i++)
244     {
245         main_loop->renderGUI(7000, i, num_karts);
246         if (RaceManager::get()->getKartType(i) == RaceManager::KT_GHOST) continue;
247         std::string kart_ident = history->replayHistory()
248                                ? history->getKartIdent(i)
249                                : RaceManager::get()->getKartIdent(i);
250         int local_player_id  = RaceManager::get()->getKartLocalPlayerId(i);
251         int global_player_id = RaceManager::get()->getKartGlobalPlayerId(i);
252         std::shared_ptr<AbstractKart> new_kart;
253         if (hasTeam())
254         {
255             new_kart = createKartWithTeam(kart_ident, i, local_player_id,
256                 global_player_id, RaceManager::get()->getKartType(i),
257                 RaceManager::get()->getPlayerHandicap(i));
258         }
259         else
260         {
261             new_kart = createKart(kart_ident, i, local_player_id,
262                 global_player_id, RaceManager::get()->getKartType(i),
263                 RaceManager::get()->getPlayerHandicap(i));
264         }
265         new_kart->setBoostAI(RaceManager::get()->hasBoostedAI(i));
266         m_karts.push_back(new_kart);
267     }  // for i
268 
269     main_loop->renderGUI(7050);
270     // Load other custom models if needed
271     loadCustomModels();
272     main_loop->renderGUI(7100);
273     // Must be called after all karts are created
274     if (m_race_gui)
275         m_race_gui->init();
276 
277     if (m_process_type == PT_MAIN)
278         powerup_manager->computeWeightsForRace(RaceManager::get()->getNumberOfKarts());
279     main_loop->renderGUI(7200);
280     if (m_process_type == PT_MAIN && UserConfigParams::m_particles_effects > 1)
281     {
282         Weather::getInstance<Weather>();   // create Weather instance
283     }
284 
285     if (Camera::getNumCameras() == 0)
286     {
287         auto cl = LobbyProtocol::get<ClientLobby>();
288         if ( (NetworkConfig::get()->isServer() &&
289               !GUIEngine::isNoGraphics()       ) ||
290             RaceManager::get()->isWatchingReplay()        ||
291             (cl && cl->isSpectator()))
292         {
293             // In case that the server is running with gui, watching replay or
294             // spectating the game, create a camera and attach it to the first
295             // kart.
296             Camera::createCamera(World::getWorld()->getKart(0), 0);
297 
298         }   // if server with graphics of is watching replay
299     } // if getNumCameras()==0
300 
301     const unsigned int kart_amount = (unsigned int)m_karts.size();
302     for (unsigned int i = 0; i < kart_amount; i++)
303         initTeamArrows(m_karts[i].get());
304 
305     main_loop->renderGUI(7300);
306 }   // init
307 
308 //-----------------------------------------------------------------------------
initTeamArrows(AbstractKart * k)309 void World::initTeamArrows(AbstractKart* k)
310 {
311     if (!hasTeam() || GUIEngine::isNoGraphics())
312         return;
313 #ifndef SERVER_ONLY
314     //Loading the indicator textures
315     std::string red_path =
316             file_manager->getAsset(FileManager::GUI_ICON, "red_arrow.png");
317     std::string blue_path =
318             file_manager->getAsset(FileManager::GUI_ICON, "blue_arrow.png");
319 
320     // Assigning indicators
321     scene::ISceneNode *arrow_node = NULL;
322 
323     KartModel* km = k->getKartModel();
324     // Color of karts can be changed using shaders if the model supports
325     if (km->supportColorization() && CVS->isGLSL())
326         return;
327 
328     float arrow_pos_height = km->getHeight() + 0.5f;
329     KartTeam team = getKartTeam(k->getWorldKartId());
330 
331     arrow_node = irr_driver->addBillboard(
332         core::dimension2d<irr::f32>(0.3f,0.3f),
333         team == KART_TEAM_BLUE ? blue_path : red_path,
334         k->getNode());
335 
336     arrow_node->setPosition(core::vector3df(0, arrow_pos_height, 0));
337 #endif
338 }   // initTeamArrows
339 
340 //-----------------------------------------------------------------------------
341 /** This function is called before a race is started (i.e. either after
342  *  calling init() when starting a race for the first time, or after
343  *  restarting a race, in which case no init() is called.
344  */
reset(bool restart)345 void World::reset(bool restart)
346 {
347     RewindManager::get()->reset();
348 
349     // If m_saved_race_gui is set, it means that the restart was done
350     // when the race result gui was being shown. In this case restore the
351     // race gui (note that the race result gui is cached and so never really
352     // destroyed).
353     bool reset_streak = restart && !m_saved_race_gui;
354 
355     if(m_saved_race_gui)
356     {
357         m_race_gui       = m_saved_race_gui;
358         m_saved_race_gui = NULL;
359     }
360 
361     m_ended_early = false;
362     m_schedule_pause = false;
363     m_schedule_unpause = false;
364 
365     WorldStatus::reset(restart);
366     m_faster_music_active = false;
367     m_eliminated_karts    = 0;
368     m_eliminated_players  = 0;
369     m_is_network_world = false;
370 
371     for ( KartList::iterator i = m_karts.begin(); i != m_karts.end() ; ++i )
372     {
373         (*i)->reset();
374         if (m_process_type == PT_MAIN && (*i)->getController()->canGetAchievements())
375         {
376             updateAchievementModeCounters(true /*start*/);
377 
378             PlayerManager::resetKartHits(getNumKarts());
379             if (RaceManager::get()->isLinearRaceMode())
380             {
381                 PlayerManager::trackEvent(RaceManager::get()->getTrackName(), AchievementsStatus::TR_STARTED);
382                 AchievementsStatus::AchievementData diff;
383                 diff = (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_EASY)   ? AchievementsStatus::EASY_STARTED :
384                        (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM) ? AchievementsStatus::MEDIUM_STARTED :
385                        (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_HARD)   ? AchievementsStatus::HARD_STARTED :
386                                                                                            AchievementsStatus::BEST_STARTED;
387                 PlayerManager::increaseAchievement(diff,1);
388             }
389             else if (RaceManager::get()->isEggHuntMode())
390             {
391                 PlayerManager::trackEvent(RaceManager::get()->getTrackName(), AchievementsStatus::TR_EGG_HUNT_STARTED);
392             }
393             if (reset_streak)
394                 PlayerManager::onRaceEnd(true /* previous race aborted */);
395         }
396     }
397 
398     if (!GUIEngine::isNoGraphics())
399         Camera::resetAllCameras();
400 
401     if(RaceManager::get()->hasGhostKarts())
402         ReplayPlay::get()->reset();
403 
404     // Remove all (if any) previous game flyables before reset karts, so no
405     // explosion animation will be created
406     ProjectileManager::get()->cleanup();
407     resetAllKarts();
408     // Note: track reset must be called after all karts exist, since check
409     // objects need to allocate data structures depending on the number
410     // of karts.
411     Track::getCurrentTrack()->reset();
412 
413     // Reset the race gui.
414     if (m_race_gui)
415         m_race_gui->reset();
416 
417     // Start music from beginning
418     music_manager->stopMusic();
419 
420     // Enable SFX again
421     SFXManager::get()->resumeAll();
422 
423     RewindManager::get()->reset();
424     RaceManager::get()->reset();
425     // Make sure to overwrite the data from the previous race.
426     if(!history->replayHistory()) history->initRecording();
427     if(RaceManager::get()->isRecordingRace())
428     {
429         Log::info("World", "Start Recording race.");
430         ReplayRecorder::get()->init();
431     }
432 
433     // Reset all data structures that depend on number of karts.
434     if (m_process_type == PT_MAIN)
435         irr_driver->reset();
436     m_unfair_team = false;
437 }   // reset
438 
439 //-----------------------------------------------------------------------------
440 
createRaceGUI()441 void World::createRaceGUI()
442 {
443     if (!GUIEngine::isNoGraphics())
444         m_race_gui = new RaceGUI();
445 }
446 
447 //-----------------------------------------------------------------------------
448 /** Creates a kart, having a certain position, starting location, and local
449  *  and global player id (if applicable).
450  *  \param kart_ident Identifier of the kart to create.
451  *  \param index Index of the kart.
452  *  \param local_player_id If the kart is a player kart this is the index of
453  *         this player on the local machine.
454  *  \param global_player_id If the kart is a player kart this is the index of
455  *         this player globally (i.e. including network players).
456  */
createKart(const std::string & kart_ident,int index,int local_player_id,int global_player_id,RaceManager::KartType kart_type,HandicapLevel handicap)457 std::shared_ptr<AbstractKart> World::createKart
458     (const std::string &kart_ident, int index, int local_player_id,
459     int global_player_id, RaceManager::KartType kart_type,
460     HandicapLevel handicap)
461 {
462     unsigned int gk = 0;
463     if (RaceManager::get()->hasGhostKarts())
464         gk = ReplayPlay::get()->getNumGhostKart();
465 
466     std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
467     core::stringw online_name;
468     if (global_player_id > -1)
469     {
470         ri->setHue(RaceManager::get()->getKartInfo(global_player_id)
471             .getDefaultKartColor());
472         online_name = RaceManager::get()->getKartInfo(global_player_id)
473             .getPlayerName();
474     }
475 
476     int position           = index+1;
477     btTransform init_pos   = getStartTransform(index - gk);
478     std::shared_ptr<AbstractKart> new_kart;
479     if (RewindManager::get()->isEnabled())
480     {
481         auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
482             init_pos, handicap, ri);
483         kr->rewinderAdd();
484         new_kart = kr;
485     }
486     else
487     {
488         new_kart = std::make_shared<Kart>(kart_ident, index, position,
489             init_pos, handicap, ri);
490     }
491 
492     new_kart->init(RaceManager::get()->getKartType(index));
493     Controller *controller = NULL;
494     switch(kart_type)
495     {
496     case RaceManager::KT_PLAYER:
497     {
498         int local_player_count = 99999;
499         if (NetworkConfig::get()->isNetworking() &&
500             NetworkConfig::get()->isClient())
501         {
502             local_player_count =
503                 (int)NetworkConfig::get()->getNetworkPlayers().size();
504         }
505         // local_player_id >= local_player_count for fixed AI defined in create
506         // server screen
507         if (NetworkConfig::get()->isNetworkAIInstance() ||
508             local_player_id >= local_player_count)
509         {
510             AIBaseController* ai = NULL;
511             if (RaceManager::get()->isBattleMode())
512                 ai = new BattleAI(new_kart.get());
513             else
514                 ai = new SkiddingAI(new_kart.get());
515             controller = new NetworkAIController(new_kart.get(),
516                 local_player_id, ai);
517         }
518         else
519         {
520             controller = new LocalPlayerController(new_kart.get(),
521                 local_player_id, handicap);
522             const PlayerProfile* p = StateManager::get()
523                 ->getActivePlayer(local_player_id)->getConstProfile();
524             if (p && p->getDefaultKartColor() > 0.0f)
525             {
526                 ri->setHue(p->getDefaultKartColor());
527             }
528         }
529         m_num_players ++;
530         break;
531     }
532     case RaceManager::KT_NETWORK_PLAYER:
533     {
534         controller = new NetworkPlayerController(new_kart.get());
535         m_num_players++;
536         break;
537     }
538     case RaceManager::KT_AI:
539     {
540         controller = loadAIController(new_kart.get());
541         break;
542     }
543     case RaceManager::KT_GHOST:
544     case RaceManager::KT_LEADER:
545     case RaceManager::KT_SPARE_TIRE:
546         break;
547     }
548 
549     if (!controller->isLocalPlayerController() && !online_name.empty())
550         new_kart->setOnScreenText(online_name.c_str());
551     new_kart->setController(controller);
552     RaceManager::get()->setKartColor(index, ri->getHue());
553     return new_kart;
554 }   // createKart
555 
556 //-----------------------------------------------------------------------------
557 /** Returns the start coordinates for a kart with a given index.
558  *  \param index Index of kart ranging from 0 to kart_num-1. */
getStartTransform(int index)559 const btTransform &World::getStartTransform(int index)
560 {
561     return Track::getCurrentTrack()->getStartTransform(index);
562 }   // getStartTransform
563 
564 //-----------------------------------------------------------------------------
565 /** Creates an AI controller for the kart.
566  *  \param kart The kart to be controlled by an AI.
567  */
loadAIController(AbstractKart * kart)568 Controller* World::loadAIController(AbstractKart* kart)
569 {
570     Controller *controller;
571     int turn=0;
572 
573     if(RaceManager::get()->getMinorMode()==RaceManager::MINOR_MODE_3_STRIKES
574         || RaceManager::get()->getMinorMode()==RaceManager::MINOR_MODE_FREE_FOR_ALL)
575         turn=1;
576     else if(RaceManager::get()->getMinorMode()==RaceManager::MINOR_MODE_SOCCER)
577         turn=2;
578     // If different AIs should be used, adjust turn (or switch randomly
579     // or dependent on difficulty)
580     switch(turn)
581     {
582         case 0:
583             // If requested, start the test ai
584             if( (AIBaseController::getTestAI()!=0                       ) &&
585                 ( (kart->getWorldKartId()+1) % AIBaseController::getTestAI() )==0)
586                 controller = new TestAI(kart);
587             else
588                 controller = new SkiddingAI(kart);
589             break;
590         case 1:
591             controller = new BattleAI(kart);
592             break;
593         case 2:
594             controller = new SoccerAI(kart);
595             break;
596         default:
597             Log::warn("[World]", "Unknown AI, using default.");
598             controller = new SkiddingAI(kart);
599             break;
600     }
601 
602     return controller;
603 }   // loadAIController
604 
605 //-----------------------------------------------------------------------------
~World()606 World::~World()
607 {
608     if (m_process_type == PT_MAIN)
609     {
610         GUIEngine::getDevice()->setResizable(false);
611         material_manager->unloadAllTextures();
612     }
613 
614     RewindManager::destroy();
615 
616     if (m_process_type == PT_MAIN)
617         irr_driver->onUnloadWorld();
618 
619     ProjectileManager::get()->cleanup();
620 
621     // In case that a race is aborted (e.g. track not found) track is 0.
622     if (m_process_type == PT_MAIN)
623     {
624         if(Track::getCurrentTrack())
625             Track::getCurrentTrack()->cleanup();
626     }
627     else
628         Track::cleanChildTrack();
629 
630     // Delete the in-race-gui:
631     if(m_saved_race_gui)
632     {
633         // If there is a save race gui, this means that the result gui is
634         // currently being shown. The race result gui is a screen and so
635         // is deleted by the state manager. So we only have to delete
636         // the actual race gui:
637         delete m_saved_race_gui;
638     }
639     else
640     {
641         // No race result gui is shown, so m_race_gui is the in-race
642         // gui and this must be deleted.
643         delete m_race_gui;
644     }
645 
646     if (m_process_type == PT_MAIN)
647         Weather::kill();
648 
649     m_karts.clear();
650     if(RaceManager::get()->hasGhostKarts() || RaceManager::get()->isRecordingRace())
651     {
652         // Destroy the old replay object, which also stored the ghost
653         // karts, and create a new one (which means that in further
654         // races the usage of ghosts will still be enabled).
655         // It can allow auto recreation of ghost replay file lists
656         // when next time visit the ghost replay selection screen.
657         ReplayPlay::destroy();
658         ReplayPlay::create();
659     }
660     if(RaceManager::get()->isRecordingRace())
661         ReplayRecorder::get()->reset();
662     RaceManager::get()->setRaceGhostKarts(false);
663     RaceManager::get()->setRecordRace(false);
664     RaceManager::get()->setWatchingReplay(false);
665     RaceManager::get()->setTimeTarget(0.0f);
666     RaceManager::get()->setSpareTireKartNum(0);
667 
668     if (!GUIEngine::isNoGraphics())
669         Camera::removeAllCameras();
670 
671     // In case that the track is not found, Physics was not instantiated,
672     // but kill handles this correctly.
673     Physics::destroy();
674 
675     if (m_process_type == PT_MAIN)
676         Scripting::ScriptEngine::kill();
677 
678     m_world[m_process_type] = NULL;
679 
680     if (m_process_type == PT_MAIN)
681         irr_driver->getSceneManager()->clear();
682 
683 #ifdef DEBUG
684     m_magic_number = 0xDEADBEEF;
685 #endif
686 
687 }   // ~World
688 
689 //-----------------------------------------------------------------------------
690 /** Called when 'go' is being displayed for the first time. Here the brakes
691  *  of the karts are released.
692  */
onGo()693 void World::onGo()
694 {
695     // Reset the brakes now that the prestart
696     // phase is over (braking prevents the karts
697     // from sliding downhill)
698     for(unsigned int i=0; i<m_karts.size(); i++)
699     {
700         if (m_karts[i]->isGhostKart()) continue;
701         m_karts[i]->getVehicle()->setAllBrakes(0);
702     }
703     // Reset track objects 1 more time to make sure all instances of moveable
704     // fall at the same instant when race start in network
705     if (NetworkConfig::get()->isNetworking())
706     {
707         PtrVector<TrackObject>& objs = Track::getCurrentTrack()
708             ->getTrackObjectManager()->getObjects();
709         for (TrackObject* curr : objs)
710         {
711             if (curr->getPhysicalObject())
712             {
713                 curr->reset();
714                 curr->resetEnabled();
715             }
716         }
717     }
718 }   // onGo
719 
720 //-----------------------------------------------------------------------------
721 /** Called at the end of a race. Updates highscores, pauses the game, and
722  *  informs the unlock manager about the finished race. This function must
723  *  be called after all other stats were updated from the different game
724  *  modes.
725  */
terminateRace()726 void World::terminateRace()
727 {
728     // In case the user opened paused dialog in network
729     if (!GUIEngine::isNoGraphics())
730     {
731         GUIEngine::ScreenKeyboard::dismiss();
732         GUIEngine::ModalDialog::dismiss();
733     }
734 
735     m_schedule_pause = false;
736     m_schedule_unpause = false;
737 
738     // Update the estimated finishing time for all karts that haven't
739     // finished yet.
740     const unsigned int kart_amount = getNumKarts();
741     for(unsigned int i = 0; i < kart_amount ; i++)
742     {
743         if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
744         {
745             m_karts[i]->finishedRace(
746                 estimateFinishTimeForKart(m_karts[i].get()));
747 
748         }
749     }   // i<kart_amount
750 
751     // Update highscores, and retrieve the best highscore if relevant
752     // to show it in the GUI
753     int best_highscore_rank = -1;
754     std::string highscore_who = "";
755     if (!isNetworkWorld())
756     {
757         updateHighscores(&best_highscore_rank);
758     }
759 
760     if (m_process_type == PT_MAIN)
761     {
762         updateAchievementDataEndRace();
763         PlayerManager::getCurrentPlayer()->raceFinished();
764     }
765 
766     if (m_race_gui) m_race_gui->clearAllMessages();
767     // we can't delete the race gui here, since it is needed in case of
768     // a restart: the constructor of it creates some textures which assume
769     // that no scene nodes exist. In case of a restart there are scene nodes,
770     // so we can't create the race gui again, so we keep it around
771     // and save the pointer.
772     assert(m_saved_race_gui==NULL);
773     m_saved_race_gui = m_race_gui;
774 
775     if (!GUIEngine::isNoGraphics())
776     {
777         RaceResultGUI* results = RaceResultGUI::getInstance();
778         m_race_gui = results;
779         if (best_highscore_rank > 0)
780             results->setHighscore(best_highscore_rank);
781         else
782             results->clearHighscores();
783         results->push();
784     }
785 
786     WorldStatus::terminateRace();
787 }   // terminateRace
788 
789 //-----------------------------------------------------------------------------
790 /** Waits till each kart is resting on the ground
791  *
792  * Does simulation steps still all karts reach the ground, i.e. are not
793  * moving anymore
794  */
resetAllKarts()795 void World::resetAllKarts()
796 {
797     // Reset the physics 'remaining' time to 0 so that the number
798     // of timesteps is reproducible if doing a physics-based history run
799     Physics::get()->getPhysicsWorld()->resetLocalTime();
800 
801     // If track checking is requested, check all rescue positions if
802     // they are high enough.
803     if(UserConfigParams::m_track_debug)
804     {
805         // Loop over all karts, in case that some karts are dfferent
806         for(unsigned int kart_id=0; kart_id<(unsigned int)m_karts.size(); kart_id++)
807         {
808             if (m_karts[kart_id]->isGhostKart()) continue;
809             for(unsigned int rescue_pos=0;
810                 rescue_pos<getNumberOfRescuePositions();
811                 rescue_pos++)
812             {
813                 btTransform t = getRescueTransform(rescue_pos);
814                 // This will print out warnings if there is no terrain under
815                 // the kart, or the kart is being dropped on a reset texture
816                 moveKartTo(m_karts[kart_id].get(), t);
817 
818             }   // rescue_pos<getNumberOfRescuePositions
819 
820             // Reset the karts back to the original start position.
821             // This call is a bit of an overkill, but setting the correct
822             // transforms, positions, motion state is a bit of a hassle.
823             m_karts[kart_id]->reset();
824         }   // for kart_id<m_karts.size()
825 
826 
827     }   // if m_track_debug
828 
829     m_schedule_pause = false;
830     m_schedule_unpause = false;
831 
832     //Project karts onto track from above. This will lower each kart so
833     //that at least one of its wheel will be on the surface of the track
834     for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
835     {
836         if ((*i)->isGhostKart()) continue;
837         Vec3 xyz = (*i)->getXYZ();
838         //start projection from top of kart
839         Vec3 up_offset = (*i)->getNormal() * (0.5f * ((*i)->getKartHeight()));
840         (*i)->setXYZ(xyz+up_offset);
841 
842         bool kart_over_ground = Track::getCurrentTrack()->findGround(i->get());
843 
844         if (!kart_over_ground)
845         {
846             Log::error("World",
847                        "No valid starting position for kart %d on track %s.",
848                        (int)(i - m_karts.begin()),
849                        Track::getCurrentTrack()->getIdent().c_str());
850             if (UserConfigParams::m_artist_debug_mode)
851             {
852                 Log::warn("World", "Activating fly mode.");
853                 (*i)->flyUp();
854                 continue;
855             }
856             else
857             {
858                 exit(-1);
859             }
860         }
861     }
862 
863     // Do a longer initial simulation, which should be long enough for all
864     // karts to be firmly on ground.
865     float g = Track::getCurrentTrack()->getGravity();
866     for (KartList::iterator i = m_karts.begin(); i != m_karts.end(); i++)
867     {
868         if ((*i)->isGhostKart()) continue;
869         (*i)->getBody()->setGravity(
870             (*i)->getMaterial() && (*i)->getMaterial()->hasGravity() ?
871             (*i)->getNormal() * -g : Vec3(0, -g, 0));
872     }
873     for(int i=0; i<stk_config->getPhysicsFPS(); i++)
874         Physics::get()->update(1);
875 
876     for ( KartList::iterator i=m_karts.begin(); i!=m_karts.end(); i++)
877     {
878         (*i)->kartIsInRestNow();
879     }
880 
881     // Initialise the cameras, now that the correct kart positions are set
882     if (!GUIEngine::isNoGraphics())
883     {
884         for(unsigned int i=0; i<Camera::getNumCameras(); i++)
885         {
886             Camera::getCamera(i)->setInitialTransform();
887         }
888     }
889 }   // resetAllKarts
890 
891 // ----------------------------------------------------------------------------
892 /** Places a kart that is rescued. It calls getRescuePositionIndex to find
893  *  to which rescue position the kart should be moved, then getRescueTransform
894  *  to get the position and rotation of this rescue position, and then moves
895  *  the kart.
896  *  \param kart The kart that is rescued.
897  */
moveKartAfterRescue(AbstractKart * kart)898 void World::moveKartAfterRescue(AbstractKart* kart)
899 {
900     unsigned int index = getRescuePositionIndex(kart);
901     btTransform t      = getRescueTransform(index);
902     moveKartTo(kart, t);
903 }  // moveKartAfterRescue
904 
905 // ----------------------------------------------------------------------------
906 /** Places the kart at a given position and rotation.
907  *  \param kart The kart to be moved.
908  *  \param transform
909  */
moveKartTo(AbstractKart * kart,const btTransform & transform)910 void World::moveKartTo(AbstractKart* kart, const btTransform &transform)
911 {
912     btTransform pos(transform);
913 
914     // Move the kart
915     Vec3 xyz = pos.getOrigin() +
916         pos.getBasis() * Vec3(0, 0.5f*kart->getKartHeight(), 0);
917     pos.setOrigin(xyz);
918     kart->setXYZ(xyz);
919     kart->setRotation(pos.getRotation());
920 
921     kart->getBody()->setCenterOfMassTransform(pos);
922     // The raycast to determine the terrain underneath the kart is done from
923     // the centre point of the 4 wheel positions. After a rescue, the wheel
924     // positions need to be updated (otherwise the raycast will be done from
925     // the previous position, which might be the position that triggered
926     // the rescue in the first place).
927     kart->getVehicle()->updateAllWheelPositions();
928 
929     // Project kart to surface of track
930     // This will set the physics transform
931     Track::getCurrentTrack()->findGround(kart);
932     Track::getCurrentTrack()->getCheckManager()->resetAfterKartMove(kart);
933 
934 }   // moveKartTo
935 
936 // ----------------------------------------------------------------------------
schedulePause(Phase phase)937 void World::schedulePause(Phase phase)
938 {
939     if (m_schedule_unpause)
940     {
941         m_schedule_unpause = false;
942     }
943     else
944     {
945         m_schedule_pause = true;
946         m_scheduled_pause_phase = phase;
947     }
948 }   // schedulePause
949 
950 // ----------------------------------------------------------------------------
scheduleUnpause()951 void World::scheduleUnpause()
952 {
953     if (m_schedule_pause)
954     {
955         m_schedule_pause = false;
956     }
957     else
958     {
959         m_schedule_unpause = true;
960     }
961 }   // scheduleUnpause
962 
963 //-----------------------------------------------------------------------------
964 /** This is the main interface to update the world. This function calls
965  *  update(), and checks then for the end of the race. Note that race over
966  *  handling can not necessarily be done in update(), since not all
967  *  data structures might have been updated (e.g.LinearWorld must
968  *  call World::update() first, to get updated kart positions. If race
969  *  over would be handled in World::update, LinearWorld had no opportunity
970  *  to update its data structures before the race is finished).
971  *  \param ticks Number of physics time steps - should be 1.
972  */
updateWorld(int ticks)973 void World::updateWorld(int ticks)
974 {
975 #ifdef DEBUG
976     assert(m_magic_number == 0xB01D6543);
977 #endif
978 
979 
980     if (m_schedule_pause)
981     {
982         pause(m_scheduled_pause_phase);
983         m_schedule_pause = false;
984     }
985     else if (m_schedule_unpause)
986     {
987         unpause();
988         m_schedule_unpause = false;
989     }
990 
991     // Don't update world if a menu is shown or the race is over.
992     if (getPhase() == FINISH_PHASE ||
993         (!NetworkConfig::get()->isNetworking() &&
994         getPhase() == IN_GAME_MENU_PHASE))
995         return;
996 
997     try
998     {
999         update(ticks);
1000     }
1001     catch (AbortWorldUpdateException& e)
1002     {
1003         (void)e;   // avoid compiler warning
1004         return;
1005     }
1006 
1007 #ifdef DEBUG
1008     assert(m_magic_number == 0xB01D6543);
1009 #endif
1010 
1011     if( (!isFinishPhase()) && isRaceOver())
1012     {
1013         enterRaceOverState();
1014     }
1015     else
1016     {
1017         if (m_schedule_exit_race)
1018         {
1019             m_schedule_exit_race = false;
1020             RaceManager::get()->exitRace(false);
1021             RaceManager::get()->setAIKartOverride("");
1022 
1023             StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
1024 
1025             if (m_schedule_tutorial)
1026             {
1027                 m_schedule_tutorial = false;
1028                 RaceManager::get()->setNumPlayers(1);
1029                 RaceManager::get()->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
1030                 RaceManager::get()->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL);
1031                 RaceManager::get()->setNumKarts( 1 );
1032                 RaceManager::get()->setTrack( "tutorial" );
1033                 RaceManager::get()->setDifficulty(RaceManager::DIFFICULTY_EASY);
1034                 RaceManager::get()->setReverseTrack(false);
1035 
1036                 // Use keyboard 0 by default (FIXME: let player choose?)
1037                 InputDevice* device = input_manager->getDeviceManager()->getKeyboard(0);
1038 
1039                 // Create player and associate player with keyboard
1040                 StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(),
1041                                                         device);
1042 
1043                 if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart))
1044                 {
1045                     Log::warn("[World]",
1046                               "Cannot find kart '%s', will revert to default.",
1047                               UserConfigParams::m_default_kart.c_str());
1048                     UserConfigParams::m_default_kart.revertToDefaults();
1049                 }
1050                 RaceManager::get()->setPlayerKart(0, UserConfigParams::m_default_kart);
1051 
1052                 // ASSIGN should make sure that only input from assigned devices
1053                 // is read.
1054                 input_manager->getDeviceManager()->setAssignMode(ASSIGN);
1055                 input_manager->getDeviceManager()
1056                     ->setSinglePlayer( StateManager::get()->getActivePlayer(0) );
1057 
1058                 delete this;
1059 
1060                 StateManager::get()->enterGameState();
1061                 RaceManager::get()->setupPlayerKartInfo();
1062                 RaceManager::get()->startNew(true);
1063             }
1064             else
1065             {
1066                 delete this;
1067 
1068                 if (RaceManager::get()->raceWasStartedFromOverworld())
1069                 {
1070                     OverWorld::enterOverWorld();
1071                 }
1072 
1073             }
1074         }
1075     }
1076 }   // updateWorld
1077 
1078 #define MEASURE_FPS 0
1079 
1080 //-----------------------------------------------------------------------------
1081 
scheduleTutorial()1082 void World::scheduleTutorial()
1083 {
1084     m_schedule_exit_race = true;
1085     m_schedule_tutorial = true;
1086 }   // scheduleTutorial
1087 
1088 //-----------------------------------------------------------------------------
1089 /** This updates all only graphical elements. It is only called once per
1090  *  rendered frame, not once per time step.
1091  *  float dt Time since last frame.
1092  */
updateGraphics(float dt)1093 void World::updateGraphics(float dt)
1094 {
1095     if (auto cl = LobbyProtocol::get<ClientLobby>())
1096     {
1097         // Reset all smooth network body of rewinders so the rubber band effect
1098         // of moveable does not exist during firstly live join.
1099         if (cl->hasLiveJoiningRecently())
1100             RewindManager::get()->resetSmoothNetworkBody();
1101     }
1102 
1103     PROFILER_PUSH_CPU_MARKER("World::update (weather)", 0x80, 0x7F, 0x00);
1104     if (UserConfigParams::m_particles_effects > 1 && Weather::getInstance())
1105     {
1106         Weather::getInstance()->update(dt);
1107     }
1108     PROFILER_POP_CPU_MARKER();
1109 
1110     // Update graphics of karts, e.g. visual suspension, skid marks
1111     const int kart_amount = (int)m_karts.size();
1112     for (int i = 0; i < kart_amount; ++i)
1113     {
1114         // Update all karts that are visible
1115         if (m_karts[i]->isVisible())
1116         {
1117             m_karts[i]->updateGraphics(dt);
1118         }
1119     }
1120 
1121     PROFILER_PUSH_CPU_MARKER("World::updateGraphics (camera)", 0x60, 0x7F, 0);
1122     for (unsigned int i = 0; i < Camera::getNumCameras(); i++)
1123         Camera::getCamera(i)->update(dt);
1124     PROFILER_POP_CPU_MARKER();
1125 
1126     Scripting::ScriptEngine *script_engine =
1127         Scripting::ScriptEngine::getInstance();
1128     if (script_engine)
1129         script_engine->update(dt);
1130 
1131     ProjectileManager::get()->updateGraphics(dt);
1132     Track::getCurrentTrack()->updateGraphics(dt);
1133 }   // updateGraphics
1134 
1135 //-----------------------------------------------------------------------------
1136 /** Updates the physics, all karts, the track, and projectile manager.
1137  *  \param ticks Number of physics time steps - should be 1.
1138  */
update(int ticks)1139 void World::update(int ticks)
1140 {
1141 #ifdef DEBUG
1142     assert(m_magic_number == 0xB01D6543);
1143 #endif
1144 
1145     PROFILER_PUSH_CPU_MARKER("World::update()", 0x00, 0x7F, 0x00);
1146 
1147 #if MEASURE_FPS
1148     static int time = 0.0f;
1149     time += ticks;
1150     if (time > stk_config->time2Ticks(5.0f))
1151     {
1152         time -= stk_config->time2Ticks(5.0f);
1153         printf("%i\n",irr_driver->getVideoDriver()->getFPS());
1154     }
1155 #endif
1156 
1157     PROFILER_PUSH_CPU_MARKER("World::update (sub-updates)", 0x20, 0x7F, 0x00);
1158     WorldStatus::update(ticks);
1159     PROFILER_POP_CPU_MARKER();
1160     PROFILER_PUSH_CPU_MARKER("World::update (RewindManager)", 0x20, 0x7F, 0x40);
1161     RewindManager::get()->update(ticks);
1162     PROFILER_POP_CPU_MARKER();
1163 
1164     PROFILER_PUSH_CPU_MARKER("World::update (Track object manager)", 0x20, 0x7F, 0x40);
1165     Track::getCurrentTrack()->getTrackObjectManager()->update(stk_config->ticks2Time(ticks));
1166     PROFILER_POP_CPU_MARKER();
1167 
1168     PROFILER_PUSH_CPU_MARKER("World::update (Kart::upate)", 0x40, 0x7F, 0x00);
1169 
1170     // Update all the karts. This in turn will also update the controller,
1171     // which causes all AI steering commands set. So in the following
1172     // physics update the new steering is taken into account.
1173     const int kart_amount = (int)m_karts.size();
1174     for (int i = 0 ; i < kart_amount; ++i)
1175     {
1176         SpareTireAI* sta =
1177             dynamic_cast<SpareTireAI*>(m_karts[i]->getController());
1178         // Update all karts that are not eliminated
1179         if(!m_karts[i]->isEliminated() || (sta && sta->isMoving()))
1180             m_karts[i]->update(ticks);
1181         if (isStartPhase())
1182             m_karts[i]->makeKartRest();
1183     }
1184     PROFILER_POP_CPU_MARKER();
1185     if(RaceManager::get()->isRecordingRace()) ReplayRecorder::get()->update(ticks);
1186 
1187     PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00);
1188     ProjectileManager::get()->update(ticks);
1189     PROFILER_POP_CPU_MARKER();
1190 
1191     PROFILER_PUSH_CPU_MARKER("World::update (physics)", 0xa0, 0x7F, 0x00);
1192     Physics::get()->update(ticks);
1193     PROFILER_POP_CPU_MARKER();
1194 
1195     PROFILER_POP_CPU_MARKER();
1196 
1197 #ifdef DEBUG
1198     assert(m_magic_number == 0xB01D6543);
1199 #endif
1200 }   // update
1201 
1202 // ----------------------------------------------------------------------------
1203 /** Only updates the track. The order in which the various parts of STK are
1204  *  updated is quite important (i.e. the track can't be updated as part of
1205  *  the standard update call):
1206  *  the track must be updated after updating the karts (otherwise the
1207  *  checklines would be using the previous kart positions to determine
1208  *  new laps, but linear world which determines distance along track would
1209  *  be using the new kart positions --> the lap counting line will be
1210  *  triggered one frame too late, potentially causing strange behaviour of
1211  *  the icons.
1212  *  Similarly linear world must update the position of all karts after all
1213  *  karts have been updated (i.e. World::update() must be called before
1214  *  updating the position of the karts). The check manager (which is called
1215  *  from Track::update()) needs the updated distance along track, so track
1216  *  update has to be called after updating the race position in linear world.
1217  *  That's why there is a separate call for trackUpdate here.
1218  */
updateTrack(int ticks)1219 void World::updateTrack(int ticks)
1220 {
1221     Track::getCurrentTrack()->update(ticks);
1222 }   // update Track
1223 
1224 // ----------------------------------------------------------------------------
getHighscores() const1225 Highscores* World::getHighscores() const
1226 {
1227     if (isNetworkWorld() || !m_use_highscores) return NULL;
1228 
1229     const Highscores::HighscoreType type = "HST_" + getIdent();
1230 
1231     Highscores * highscores =
1232         highscore_manager->getHighscores(type,
1233                                          RaceManager::get()->getNumNonGhostKarts(),
1234                                          RaceManager::get()->getDifficulty(),
1235                                          RaceManager::get()->getTrackName(),
1236                                          RaceManager::get()->getNumLaps(),
1237                                          RaceManager::get()->getReverseTrack());
1238 
1239     return highscores;
1240 }   // getHighscores
1241 
1242 // ----------------------------------------------------------------------------
1243 /** Called at the end of a race. Checks if the current times are worth a new
1244  *  score, if so it notifies the HighscoreManager so the new score is added
1245  *  and saved.
1246  */
updateHighscores(int * best_highscore_rank)1247 void World::updateHighscores(int* best_highscore_rank)
1248 {
1249     *best_highscore_rank = -1;
1250 
1251     if(!m_use_highscores) return;
1252 
1253     // Add times to highscore list. First compute the order of karts,
1254     // so that the timing of the fastest kart is added first (otherwise
1255     // someone might get into the highscore list, only to be kicked out
1256     // again by a faster kart in the same race), which might be confusing
1257     // if we ever decide to display a message (e.g. during a race)
1258     unsigned int *index = new unsigned int[m_karts.size()];
1259 
1260     const unsigned int kart_amount = (unsigned int) m_karts.size();
1261     for (unsigned int i=0; i<kart_amount; i++ )
1262     {
1263         index[i] = 999; // first reset the contents of the array
1264     }
1265     for (unsigned int i=0; i<kart_amount; i++ )
1266     {
1267         const int pos = m_karts[i]->getPosition()-1;
1268         if(pos < 0 || pos >= (int)kart_amount) continue; // wrong position
1269         index[pos] = i;
1270     }
1271 
1272     for (unsigned int pos=0; pos<kart_amount; pos++)
1273     {
1274         if(index[pos] == 999)
1275         {
1276             // no kart claimed to be in this position, most likely means
1277             // the kart location data is wrong
1278 
1279 #ifdef DEBUG
1280             Log::error("[World]", "Incorrect kart positions:");
1281             for (unsigned int i=0; i<m_karts.size(); i++ )
1282             {
1283                 Log::error("[World]", "i=%d position %d.",i,
1284                            m_karts[i]->getPosition());
1285             }
1286 #endif
1287             continue;
1288         }
1289 
1290         // Only record times for local player karts and only if
1291         // they finished the race
1292         if(!m_karts[index[pos]]->getController()->isLocalPlayerController())
1293             continue;
1294         if (!m_karts[index[pos]]->hasFinishedRace()) continue;
1295         if (m_karts[index[pos]]->isEliminated()) continue;
1296 
1297         assert(index[pos] < m_karts.size());
1298         Kart *k = (Kart*)m_karts[index[pos]].get();
1299 
1300         Highscores* highscores = getHighscores();
1301 
1302         int highscore_rank = 0;
1303         // The player is a local player, so there is a name:
1304         highscore_rank = highscores->addData(k->getIdent(),
1305                                              k->getController()->getName(),
1306                                              k->getFinishTime()    );
1307 
1308         if (highscore_rank > 0)
1309         {
1310             if (*best_highscore_rank == -1 ||
1311                 highscore_rank < *best_highscore_rank)
1312             {
1313                 *best_highscore_rank = highscore_rank;
1314             }
1315 
1316             highscore_manager->saveHighscores();
1317         }
1318     } // next position
1319     delete []index;
1320 
1321 }   // updateHighscores
1322 
1323 //-----------------------------------------------------------------------------
1324 /** Returns the n-th player kart. Note that this function is O(N), not O(1),
1325  *  so it shouldn't be called inside of loops.
1326  *  \param n Index of player kart to return.
1327  */
getPlayerKart(unsigned int n) const1328 AbstractKart *World::getPlayerKart(unsigned int n) const
1329 {
1330     unsigned int count = -1;
1331 
1332     for(unsigned int i = 0; i < m_karts.size(); i++)
1333     {
1334         if (m_karts[i]->getController()->isPlayerController())
1335         {
1336             count++;
1337             if (count == n)
1338                 return m_karts[i].get();
1339         }
1340     }
1341     return NULL;
1342 }   // getPlayerKart
1343 
1344 //-----------------------------------------------------------------------------
1345 /** Returns the nth local player kart, i.e. a kart that has a camera.
1346  *  Note that in profile mode this means a non player kart could be returned
1347  *  (since an AI kart will have the camera).
1348  *  \param n Index of player kart to return.
1349  */
getLocalPlayerKart(unsigned int n) const1350 AbstractKart *World::getLocalPlayerKart(unsigned int n) const
1351 {
1352     if(n>=Camera::getNumCameras()) return NULL;
1353     return Camera::getCamera(n)->getKart();
1354 }   // getLocalPlayerKart
1355 
1356 //-----------------------------------------------------------------------------
1357 /** Remove (eliminate) a kart from the race */
eliminateKart(int kart_id,bool notify_of_elimination)1358 void World::eliminateKart(int kart_id, bool notify_of_elimination)
1359 {
1360     assert(kart_id < (int)m_karts.size());
1361     AbstractKart *kart = m_karts[kart_id].get();
1362     if (kart->isGhostKart()) return;
1363 
1364     // Display a message about the eliminated kart in the race gui
1365     if (m_race_gui && notify_of_elimination)
1366     {
1367         for(unsigned int i=0; i<Camera::getNumCameras(); i++)
1368         {
1369             Camera *camera = Camera::getCamera(i);
1370             if(camera->getKart()==kart)
1371                 m_race_gui->addMessage(_("You have been eliminated!"), kart,
1372                                        2.0f);
1373             else
1374             {
1375                 // Store the temporary string because clang would mess this up
1376                 // (remove the stringw before the wchar_t* is used).
1377                 const core::stringw &kart_name = kart->getController()->getName();
1378                 m_race_gui->addMessage(_("'%s' has been eliminated.",
1379                                        kart_name),
1380                                        camera->getKart(),
1381                                        2.0f);
1382             }
1383         }  // for i < number of cameras
1384     }   // if notify_of_elimination
1385 
1386     if(kart->getController()->isLocalPlayerController())
1387     {
1388         for(unsigned int i=0; i<Camera::getNumCameras(); i++)
1389         {
1390             // Change the camera so that it will be attached to the leader
1391             // and facing backwards.
1392             Camera *camera = Camera::getCamera(i);
1393             if(camera->getKart()==kart)
1394                 camera->setMode(Camera::CM_LEADER_MODE);
1395         }
1396         m_eliminated_players++;
1397     }
1398 
1399     // The kart can't be really removed from the m_kart array, since otherwise
1400     // a race can't be restarted. So it's only marked to be eliminated (and
1401     // ignored in all loops). Important:world->getCurrentNumKarts() returns
1402     // the number of karts still racing. This value can not be used for loops
1403     // over all karts, use RaceManager::get()->getNumKarts() instead!
1404     kart->eliminate();
1405     m_eliminated_karts++;
1406 
1407 }   // eliminateKart
1408 
1409 //-----------------------------------------------------------------------------
1410 /** Called to determine the default collectibles to give each player at the
1411  *  start for this kind of race. Both parameters are of 'out' type.
1412  *  \param collectible_type The type of collectible each kart.
1413  *  \param amount The number of collectibles.
1414  */
getDefaultCollectibles(int * collectible_type,int * amount)1415 void World::getDefaultCollectibles(int *collectible_type, int *amount )
1416 {
1417     *collectible_type = PowerupManager::POWERUP_NOTHING;
1418     *amount = 0;
1419 }   // getDefaultCollectibles
1420 
1421 //-----------------------------------------------------------------------------
1422 /** Pauses the music (and then pauses WorldStatus).
1423  */
pause(Phase phase)1424 void World::pause(Phase phase)
1425 {
1426     if (m_stop_music_when_dialog_open)
1427         music_manager->pauseMusic();
1428     SFXManager::get()->pauseAll();
1429 
1430     WorldStatus::pause(phase);
1431 }   // pause
1432 
1433 //-----------------------------------------------------------------------------
unpause()1434 void World::unpause()
1435 {
1436     if (m_stop_music_when_dialog_open)
1437         music_manager->resumeMusic();
1438     SFXManager::get()->resumeAll();
1439 
1440     WorldStatus::unpause();
1441 
1442     for(unsigned int i=0; i<m_karts.size(); i++)
1443     {
1444         // Note that we can not test for isPlayerController here, since
1445         // an EndController will also return 'isPlayerController' if the
1446         // kart belonged to a player.
1447         LocalPlayerController *pc =
1448             dynamic_cast<LocalPlayerController*>(m_karts[i]->getController());
1449         if(pc)
1450             pc->resetInputState();
1451     }
1452 }   // pause
1453 
1454 //-----------------------------------------------------------------------------
escapePressed()1455 void World::escapePressed()
1456 {
1457     for (unsigned i = 0; i < m_karts.size(); i++)
1458     {
1459         for (unsigned j = 0; j < PA_PAUSE_RACE; j++)
1460         {
1461             if (m_karts[i]->isEliminated() || !m_karts[i]->getController()
1462                 ->isLocalPlayerController())
1463                 continue;
1464             m_karts[i]->getController()->action((PlayerAction)j, 0);
1465         }
1466     }
1467 
1468     new RacePausedDialog(0.8f, 0.6f);
1469 }   // escapePressed
1470 
1471 // ----------------------------------------------------------------------------
1472 /** Returns the start transform with the give index.
1473  *  \param rescue_pos Index of the start position to be returned.
1474  *  \returns The transform of the corresponding start position.
1475  */
getRescueTransform(unsigned int rescue_pos) const1476 btTransform World::getRescueTransform(unsigned int rescue_pos) const
1477 {
1478     return Track::getCurrentTrack()->getStartTransform(rescue_pos);
1479 }   // getRescueTransform
1480 
1481 //-----------------------------------------------------------------------------
1482 /** Uses the start position as rescue positions, override if necessary
1483  */
getNumberOfRescuePositions() const1484 unsigned int World::getNumberOfRescuePositions() const
1485 {
1486     return Track::getCurrentTrack()->getNumberOfStartPositions();
1487 }   // getNumberOfRescuePositions
1488 
1489 //-----------------------------------------------------------------------------
createKartWithTeam(const std::string & kart_ident,int index,int local_player_id,int global_player_id,RaceManager::KartType kart_type,HandicapLevel handicap)1490 std::shared_ptr<AbstractKart> World::createKartWithTeam
1491     (const std::string &kart_ident, int index, int local_player_id,
1492     int global_player_id, RaceManager::KartType kart_type,
1493     HandicapLevel handicap)
1494 {
1495     int cur_red = getTeamNum(KART_TEAM_RED);
1496     int cur_blue = getTeamNum(KART_TEAM_BLUE);
1497     int pos_index = 0;
1498     int position  = index + 1;
1499     KartTeam team = KART_TEAM_BLUE;
1500 
1501     if (kart_type == RaceManager::KT_AI)
1502     {
1503         if (index < m_red_ai)
1504             team = KART_TEAM_RED;
1505         else
1506             team = KART_TEAM_BLUE;
1507         m_kart_team_map[index] = team;
1508     }
1509     else if (NetworkConfig::get()->isNetworking())
1510     {
1511         m_kart_team_map[index] = RaceManager::get()->getKartInfo(index).getKartTeam();
1512         team = RaceManager::get()->getKartInfo(index).getKartTeam();
1513     }
1514     else
1515     {
1516         int rm_id = index -
1517             (RaceManager::get()->getNumberOfKarts() - RaceManager::get()->getNumPlayers());
1518 
1519         assert(rm_id >= 0);
1520         team = RaceManager::get()->getKartInfo(rm_id).getKartTeam();
1521         m_kart_team_map[index] = team;
1522     }
1523 
1524     core::stringw online_name;
1525     if (global_player_id > -1)
1526     {
1527         online_name = RaceManager::get()->getKartInfo(global_player_id)
1528             .getPlayerName();
1529     }
1530 
1531     // Notice: In blender, please set 1,3,5,7... for blue starting position;
1532     // 2,4,6,8... for red.
1533     if (team == KART_TEAM_BLUE)
1534     {
1535         pos_index = 1 + 2 * cur_blue;
1536     }
1537     else
1538     {
1539         pos_index = 2 + 2 * cur_red;
1540     }
1541 
1542     btTransform init_pos = getStartTransform(pos_index - 1);
1543     m_kart_position_map[index] = (unsigned)(pos_index - 1);
1544 
1545     std::shared_ptr<RenderInfo> ri = std::make_shared<RenderInfo>();
1546     ri = (team == KART_TEAM_BLUE ? std::make_shared<RenderInfo>(0.66f) :
1547         std::make_shared<RenderInfo>(1.0f));
1548 
1549     std::shared_ptr<AbstractKart> new_kart;
1550     if (RewindManager::get()->isEnabled())
1551     {
1552         auto kr = std::make_shared<KartRewinder>(kart_ident, index, position,
1553             init_pos, handicap, ri);
1554         kr->rewinderAdd();
1555         new_kart = kr;
1556     }
1557     else
1558     {
1559         new_kart = std::make_shared<Kart>(kart_ident, index, position,
1560             init_pos, handicap, ri);
1561     }
1562 
1563     new_kart->init(RaceManager::get()->getKartType(index));
1564     Controller *controller = NULL;
1565 
1566     switch(kart_type)
1567     {
1568     case RaceManager::KT_PLAYER:
1569         controller = new LocalPlayerController(new_kart.get(), local_player_id, handicap);
1570         m_num_players ++;
1571         break;
1572     case RaceManager::KT_NETWORK_PLAYER:
1573         controller = new NetworkPlayerController(new_kart.get());
1574         if (!online_name.empty())
1575             new_kart->setOnScreenText(online_name.c_str());
1576         m_num_players++;
1577         break;
1578     case RaceManager::KT_AI:
1579         controller = loadAIController(new_kart.get());
1580         break;
1581     case RaceManager::KT_GHOST:
1582     case RaceManager::KT_LEADER:
1583     case RaceManager::KT_SPARE_TIRE:
1584         break;
1585     }
1586 
1587     new_kart->setController(controller);
1588 
1589     return new_kart;
1590 }   // createKartWithTeam
1591 
1592 //-----------------------------------------------------------------------------
getTeamNum(KartTeam team) const1593 int World::getTeamNum(KartTeam team) const
1594 {
1595     int total = 0;
1596     if (m_kart_team_map.empty()) return total;
1597 
1598     for (unsigned int i = 0; i < (unsigned)m_karts.size(); ++i)
1599     {
1600         if (team == getKartTeam(m_karts[i]->getWorldKartId())) total++;
1601     }
1602 
1603     return total;
1604 }   // getTeamNum
1605 
1606 //-----------------------------------------------------------------------------
getKartTeam(unsigned int kart_id) const1607 KartTeam World::getKartTeam(unsigned int kart_id) const
1608 {
1609     std::map<int, KartTeam>::const_iterator n =
1610         m_kart_team_map.find(kart_id);
1611 
1612     assert(n != m_kart_team_map.end());
1613     return n->second;
1614 }   // getKartTeam
1615 
1616 //-----------------------------------------------------------------------------
setAITeam()1617 void World::setAITeam()
1618 {
1619     m_red_ai  = RaceManager::get()->getNumberOfRedAIKarts();
1620     m_blue_ai = RaceManager::get()->getNumberOfBlueAIKarts();
1621 
1622     for (int i = 0; i < (int)RaceManager::get()->getNumLocalPlayers(); i++)
1623     {
1624         KartTeam team = RaceManager::get()->getKartInfo(i).getKartTeam();
1625 
1626         // Happen in profiling mode
1627         if (team == KART_TEAM_NONE)
1628         {
1629             RaceManager::get()->setKartTeam(i, KART_TEAM_BLUE);
1630             team = KART_TEAM_BLUE;
1631             continue; //FIXME, this is illogical
1632         }
1633     }
1634 
1635     Log::debug("World", "Blue AI: %d red AI: %d", m_blue_ai, m_red_ai);
1636 
1637 }   // setAITeam
1638 
1639 // As a class name can't be skipped with "using", we use a preprocessor macro
1640 // to clean up the two following functions
1641 #define ACS AchievementsStatus
1642 
1643 //-----------------------------------------------------------------------------
1644 /* This function takes care to update all relevant achievements
1645  * and statistics counters related to a finished race. */
updateAchievementDataEndRace()1646 void World::updateAchievementDataEndRace()
1647 {
1648     const unsigned int kart_amount = getNumKarts();
1649 
1650     for(unsigned int i = 0; i < kart_amount; i++)
1651     {
1652         // TODO : does this work in multiplayer ?
1653         // TODO : check what happens when abandonning a race in a GP
1654         // Retrieve the current player
1655         if (m_karts[i]->getController()->canGetAchievements())
1656         {
1657             // Increment won races counts and track finished counts
1658             if (RaceManager::get()->isLinearRaceMode())
1659             {
1660                 ACS::AchievementData diff;
1661                 diff = (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_EASY)   ? ACS::EASY_FINISHED :
1662                        (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_MEDIUM) ? ACS::MEDIUM_FINISHED :
1663                        (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_HARD)   ? ACS::HARD_FINISHED :
1664                                                                                            ACS::BEST_FINISHED;
1665                 PlayerManager::increaseAchievement(diff,1);
1666 
1667                 PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_FINISHED);
1668                 if (RaceManager::get()->getReverseTrack())
1669                     PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_FINISHED_REVERSE);
1670 
1671                 if (RaceManager::get()->modeHasLaps())
1672                 {
1673                     Track* track = track_manager->getTrack(RaceManager::get()->getTrackName());
1674                     int default_lap_num = track->getDefaultNumberOfLaps();
1675                     if (RaceManager::get()->getNumLaps() < default_lap_num)
1676                     {
1677                         PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_LESS_LAPS);
1678                     }
1679                     else if (RaceManager::get()->getNumLaps() > default_lap_num)
1680                     {
1681                         PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_MORE_LAPS);
1682                         if (RaceManager::get()->getNumLaps() >= 2*default_lap_num)
1683                             PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_MIN_TWICE_LAPS);
1684                     }
1685                 }
1686 
1687                 int winner_position = 1;
1688                 //TODO : check this always work : what happens if the leader is overtaken between the last elimination
1689                 //       and the results screen ?
1690                 if (RaceManager::get()->isFollowMode()) winner_position = 2;
1691                 // Check if the player has won
1692                 if (m_karts[i]->getPosition() == winner_position)
1693                 {
1694                     if (RaceManager::get()->getNumNonGhostKarts() >= 2)
1695                         PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_WON);
1696                     else
1697                         PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_FINISHED_ALONE);
1698                     if (RaceManager::get()->getNumberOfAIKarts() >= 3)
1699                     {
1700                         PlayerManager::increaseAchievement(ACS::WON_RACES,1);
1701                         PlayerManager::increaseAchievement(ACS::CONS_WON_RACES,1);
1702                         if (RaceManager::get()->isTimeTrialMode())
1703                             PlayerManager::increaseAchievement(ACS::WON_TT_RACES,1);
1704                         else if (RaceManager::get()->isFollowMode())
1705                             PlayerManager::increaseAchievement(ACS::WON_FTL_RACES,1);
1706                         else // normal race
1707                             PlayerManager::increaseAchievement(ACS::WON_NORMAL_RACES,1);
1708                     }
1709                     if (RaceManager::get()->getNumberOfAIKarts() >= 5 &&
1710                         (RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_HARD ||
1711                          RaceManager::get()->getDifficulty() == RaceManager::DIFFICULTY_BEST))
1712                         PlayerManager::increaseAchievement(ACS::CONS_WON_RACES_HARD,1);
1713                 }
1714                 // Race lost, reset the consecutive wins counters
1715                 else if (m_karts[i]->getPosition() > winner_position)
1716                 {
1717                     PlayerManager::resetAchievementData(ACS::CONS_WON_RACES);
1718                     PlayerManager::resetAchievementData(ACS::CONS_WON_RACES_HARD);
1719                 }
1720             } // if isLinearMode
1721 
1722             // Increment egg hunt finished count
1723             else if (RaceManager::get()->isEggHuntMode())
1724             {
1725                 PlayerManager::trackEvent(RaceManager::get()->getTrackName(), ACS::TR_EGG_HUNT_FINISHED);
1726             }
1727 
1728             updateAchievementModeCounters(false /*start*/);
1729          } // if m_karts[i]->getController()->canGetAchievements()
1730     } // for i<kart_amount
1731 } // updateAchievementDataEndRace
1732 
1733 //-----------------------------------------------------------------------------
1734 /* This function updates the race mode start and finish counters.
1735  * \param start - true if start, false if finish */
updateAchievementModeCounters(bool start)1736 void World::updateAchievementModeCounters(bool start)
1737 {
1738     if (RaceManager::get()->isTimeTrialMode())
1739         PlayerManager::increaseAchievement(start ? ACS::TT_STARTED : ACS::TT_FINISHED,1);
1740     else if (RaceManager::get()->isFollowMode())
1741         PlayerManager::increaseAchievement(start ? ACS::FTL_STARTED : ACS::FTL_FINISHED,1);
1742     else if (RaceManager::get()->isEggHuntMode())
1743         PlayerManager::increaseAchievement(start ? ACS::EGG_HUNT_STARTED : ACS::EGG_HUNT_FINISHED,1);
1744     else if (RaceManager::get()->isSoccerMode())
1745         PlayerManager::increaseAchievement(start ? ACS::SOCCER_STARTED : ACS::SOCCER_FINISHED,1);
1746     else if (RaceManager::get()->isBattleMode())
1747     {
1748         if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES)
1749             PlayerManager::increaseAchievement(start ? ACS::THREE_STRIKES_STARTED : ACS::THREE_STRIKES_FINISHED,1);
1750         else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_CAPTURE_THE_FLAG)
1751             PlayerManager::increaseAchievement(start ? ACS::CTF_STARTED : ACS::CTF_FINISHED,1);
1752         else if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL)
1753             PlayerManager::increaseAchievement(start ? ACS::FFA_STARTED : ACS::FFA_FINISHED,1);
1754     }
1755     else // normal races
1756         PlayerManager::increaseAchievement(start ? ACS::NORMAL_STARTED : ACS::NORMAL_FINISHED,1);
1757 
1758     if (RaceManager::get()->hasGhostKarts())
1759         PlayerManager::increaseAchievement(start ? ACS::WITH_GHOST_STARTED : ACS::WITH_GHOST_FINISHED,1);
1760 } // updateAchievementModeCounters
1761 #undef ACS
1762