Back to index

supertuxkart  0.5+dfsg1
world.cpp
Go to the documentation of this file.
00001 //  $Id: world.cpp 2111 2008-05-31 07:04:30Z cosmosninja $
00002 //
00003 //  SuperTuxKart - a fun racing game with go-kart
00004 //  Copyright (C) 2006 SuperTuxKart-Team
00005 //
00006 //  This program is free software; you can redistribute it and/or
00007 //  modify it under the terms of the GNU General Public License
00008 //  as published by the Free Software Foundation; either version 2
00009 //  of the License, or (at your option) any later version.
00010 //
00011 //  This program is distributed in the hope that it will be useful,
00012 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 //  GNU General Public License for more details.
00015 //
00016 //  You should have received a copy of the GNU General Public License
00017 //  along with this program; if not, write to the Free Software
00018 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019 
00020 #include <assert.h>
00021 #include <sstream>
00022 #include <stdexcept>
00023 #include <algorithm>
00024 #include <ctime>
00025 
00026 #include "world.hpp"
00027 #include "herring_manager.hpp"
00028 #include "projectile_manager.hpp"
00029 #include "gui/menu_manager.hpp"
00030 #include "file_manager.hpp"
00031 #include "player_kart.hpp"
00032 #include "auto_kart.hpp"
00033 #include "track.hpp"
00034 #include "kart_properties_manager.hpp"
00035 #include "track_manager.hpp"
00036 #include "race_manager.hpp"
00037 #include "user_config.hpp"
00038 #include "callback_manager.hpp"
00039 #include "history.hpp"
00040 #include "constants.hpp"
00041 #include "sound_manager.hpp"
00042 #include "translation.hpp"
00043 #include "highscore_manager.hpp"
00044 #include "scene.hpp"
00045 #include "camera.hpp"
00046 #include "robots/default_robot.hpp"
00047 #include "unlock_manager.hpp"
00048 #ifdef HAVE_GHOST_REPLAY
00049 #  include "replay_player.hpp"
00050 #endif
00051 
00052 #if defined(WIN32) && !defined(__CYGWIN__)
00053 #  define snprintf  _snprintf
00054 #endif
00055 
00056 World* world = 0;
00057 
00058 World::World()
00059 #ifdef HAVE_GHOST_REPLAY
00060 , m_p_replay_player(NULL)
00061 #endif
00062 {
00063     delete world;
00064     world                 = this;
00065     m_phase               = SETUP_PHASE;
00066     m_previous_phase      = SETUP_PHASE;  // initialise it just in case
00067     m_track               = NULL;
00068     m_clock               = 0.0f;
00069     m_faster_music_active = false;
00070     m_fastest_lap         = 9999999.9f;
00071     m_fastest_kart        = 0;
00072     m_eliminated_karts    = 0;
00073     m_eliminated_players  = 0;
00074     m_leader_intervals    = stk_config->m_leader_intervals;
00075 
00076     // Grab the track file
00077     try
00078     {
00079         m_track = track_manager->getTrack(race_manager->getTrackName());
00080     }
00081     catch(std::runtime_error)
00082     {
00083         char msg[MAX_ERROR_MESSAGE_LENGTH];
00084         snprintf(msg, sizeof(msg), 
00085                  "Track '%s' not found.\n",race_manager->getTrackName().c_str());
00086         throw std::runtime_error(msg);
00087     }
00088 
00089     // Create the physics
00090     m_physics = new Physics(m_track->getGravity());
00091 
00092     assert(race_manager->getNumKarts() > 0);
00093 
00094     // Load the track models - this must be done before the karts so that the
00095     // karts can be positioned properly on (and not in) the tracks.
00096     loadTrack() ;
00097 
00098     int playerIndex = 0;
00099     for(unsigned int i=0; i<race_manager->getNumKarts(); i++)
00100     {
00101         int position = i+1;   // position start with 1
00102         sgCoord init_pos;
00103         m_track->getStartCoords(i, &init_pos);
00104         Kart* newkart;
00105         const std::string& kart_name=race_manager->getKartName(i);
00106         if(user_config->m_profile)
00107         {
00108             // In profile mode, load only the old kart
00109             newkart = new DefaultRobot(kart_name, position, init_pos);
00110            // Create a camera for the last kart (since this way more of the 
00111                // karts can be seen.
00112             if(i==race_manager->getNumKarts()-1) 
00113             {
00114                 btVector3 startpos(init_pos.xyz[0], init_pos.xyz[1], init_pos.xyz[2]);
00115                 scene->createCamera(playerIndex, newkart);
00116             }
00117         }
00118         else
00119         {
00120             if (race_manager->isPlayer(i))
00121             {
00122                 newkart = new PlayerKart(kart_name, position,
00123                                          &(user_config->m_player[playerIndex]),
00124                                          init_pos, playerIndex);
00125                 m_player_karts.push_back((PlayerKart*)newkart);
00126                 playerIndex++;
00127             }
00128             else
00129             {
00130                 newkart = loadRobot(kart_name, position, init_pos);
00131             }
00132         }   // if !user_config->m_profile
00133         if(user_config->m_replay_history)
00134         {
00135             history->LoadKartData(newkart, i);
00136         }
00137         newkart -> getModelTransform() -> clrTraversalMaskBits(SSGTRAV_ISECT|SSGTRAV_HOT);
00138 
00139         scene->add ( newkart -> getModelTransform() ) ;
00140         m_kart.push_back(newkart);
00141     }  // for i
00142 
00143     resetAllKarts();
00144 
00145 #ifdef SSG_BACKFACE_COLLISIONS_SUPPORTED
00146     //ssgSetBackFaceCollisions ( !not defined! race_manager->mirror ) ;
00147 #endif
00148 
00149     Highscores::HighscoreType hst = (race_manager->getRaceMode()==RaceManager::RM_TIME_TRIAL) 
00150                                   ? Highscores::HST_TIMETRIAL_OVERALL_TIME
00151                                   : Highscores::HST_RACE_OVERALL_TIME;
00152 
00153     m_highscores   = highscore_manager->getHighscores(hst);
00154 
00155     callback_manager->initAll();
00156     menu_manager->switchToRace();
00157 
00158     m_track->startMusic();
00159 
00160     m_phase = user_config->m_profile ? RACE_PHASE : SETUP_PHASE;
00161 
00162 #ifdef HAVE_GHOST_REPLAY
00163     m_replay_recorder.initRecorder( race_manager->getNumKarts() );
00164 
00165     m_p_replay_player = new ReplayPlayer;
00166     if( !loadReplayHumanReadable( "test1" ) ) 
00167     {
00168         delete m_p_replay_player;
00169         m_p_replay_player = NULL;
00170     }
00171     if( m_p_replay_player ) m_p_replay_player->showReplayAt( 0.0 );
00172 #endif
00173 }   // World
00174 
00175 //-----------------------------------------------------------------------------
00176 World::~World()
00177 {
00178 #ifdef HAVE_GHOST_REPLAY
00179     saveReplayHumanReadable( "test" );
00180 #endif
00181     m_track->cleanup();
00182     // Clear all callbacks
00183     callback_manager->clear(CB_TRACK);
00184 
00185     for ( unsigned int i = 0 ; i < m_kart.size() ; i++ )
00186         delete m_kart[i];
00187 
00188     m_kart.clear();
00189     projectile_manager->cleanup();
00190     delete m_physics;
00191 
00192     sound_manager -> stopMusic();
00193 
00194     sgVec3 sun_pos;
00195     sgVec4 ambient_col, specular_col, diffuse_col;
00196     sgSetVec3 ( sun_pos, 0.0f, 0.0f, 1.0f );
00197     sgSetVec4 ( ambient_col , 0.2f, 0.2f, 0.2f, 1.0f );
00198     sgSetVec4 ( specular_col, 1.0f, 1.0f, 1.0f, 1.0f );
00199     sgSetVec4 ( diffuse_col , 1.0f, 1.0f, 1.0f, 1.0f );
00200 
00201     ssgGetLight ( 0 ) -> setPosition ( sun_pos ) ;
00202     ssgGetLight ( 0 ) -> setColour ( GL_AMBIENT , ambient_col  ) ;
00203     ssgGetLight ( 0 ) -> setColour ( GL_DIFFUSE , diffuse_col ) ;
00204     ssgGetLight ( 0 ) -> setColour ( GL_SPECULAR, specular_col ) ;
00205 
00206 #ifdef HAVE_GHOST_REPLAY
00207     m_replay_recorder.destroy();
00208     if( m_p_replay_player )
00209     {
00210         m_p_replay_player->destroy();
00211         delete m_p_replay_player;
00212         m_p_replay_player = NULL;
00213     }
00214 #endif
00215 }   // ~World
00216 
00217 //-----------------------------------------------------------------------------
00223 void World::resetAllKarts()
00224 {
00225     bool all_finished=false;
00226     // kart->isInRest() is not fully correct, since it only takes the
00227     // velocity in count, which might be close to zero when the kart
00228     // is just hitting the floor, before being pushed up again by
00229     // the suspension. So we just do a longer initial simulation,
00230     // which should be long enough for all karts to be firmly on ground.
00231     for(int i=0; i<100; i++) m_physics->update(1.f/60.f);
00232     while(!all_finished)
00233     {
00234         m_physics->update(1.f/60.f);
00235         all_finished=true;
00236         for ( Karts::iterator i=m_kart.begin(); i!=m_kart.end(); i++)
00237         {
00238             if(!(*i)->isInRest()) 
00239             {
00240                 all_finished=false;
00241                 break;
00242             }
00243         }
00244     }   // while
00245 
00246 }   // resetAllKarts
00247 
00248 //-----------------------------------------------------------------------------
00249 void World::update(float dt)
00250 {
00251     if(user_config->m_replay_history) dt=history->GetNextDelta();
00252     updateRaceStatus(dt);
00253 
00254     if( getPhase() == FINISH_PHASE )
00255     {
00256         if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
00257         {
00258             menu_manager->pushMenu(MENUID_LEADERRESULT);
00259             unlock_manager->raceFinished();
00260             return;
00261         }
00262         // Add times to highscore list. First compute the order of karts,
00263         // so that the timing of the fastest kart is added first (otherwise
00264         // someone might get into the highscore list, only to be kicked out
00265         // again by a faster kart in the same race), which might be confusing
00266         // if we ever decide to display a message (e.g. during a race)
00267         unsigned int *index = new unsigned int[m_kart.size()];
00268         for (unsigned int i=0; i<m_kart.size(); i++ )
00269         {
00270             index[m_kart[i]->getPosition()-1] = i;
00271         }
00272 
00273         for(unsigned int pos=0; pos<m_kart.size(); pos++)
00274         {
00275             // Only record times for player karts
00276             if(!m_kart[index[pos]]->isPlayerKart()) continue;
00277 
00278             PlayerKart *k = (PlayerKart*)m_kart[index[pos]];
00279             
00280             Highscores::HighscoreType hst = (race_manager->getRaceMode()==
00281                                                     RaceManager::RM_TIME_TRIAL) 
00282                                             ? Highscores::HST_TIMETRIAL_OVERALL_TIME
00283                                             : Highscores::HST_RACE_OVERALL_TIME;
00284             if(m_highscores->addData(hst, k->getName(),
00285                                      k->getPlayer()->getName(),
00286                                      k->getFinishTime())>0      )
00287             {
00288                 highscore_manager->Save();
00289             }
00290         }
00291         delete []index;
00292         pause();
00293         menu_manager->pushMenu(MENUID_RACERESULT);
00294     }
00295     if(!user_config->m_replay_history) history->StoreDelta(dt);
00296     m_physics->update(dt);
00297     for (int i = 0 ; i <(int) m_kart.size(); ++i)
00298     {
00299         // Update all karts that are not eliminated
00300         if(!race_manager->isEliminated(i)) m_kart[i]->update(dt) ;
00301     }
00302 
00303     projectile_manager->update(dt);
00304     herring_manager->update(dt);
00305 
00306     for ( Karts::size_type i = 0 ; i < m_kart.size(); ++i)
00307     {
00308         if(m_kart[i]->isEliminated()) continue;   // ignore eliminated kart
00309         if(!m_kart[i]->raceIsFinished()) updateRacePosition((int)i);
00310         if(m_kart[i]->isPlayerKart()) m_kart[i]->addMessages();   // add 'wrong direction'
00311     }
00312 
00313     /* Routine stuff we do even when paused */
00314     callback_manager->update(dt);
00315 
00316 #ifdef HAVE_GHOST_REPLAY
00317     // we start recording after START_PHASE, since during start-phase m_clock is incremented
00318     // normally, but after switching to RACE_PHASE m_clock is set back to 0.0
00319     if( m_phase == GO_PHASE ) 
00320     {
00321         m_replay_recorder.pushFrame();
00322         if( m_p_replay_player ) m_p_replay_player->showReplayAt( m_clock );
00323     }
00324 #endif
00325 }
00326 
00327 #ifdef HAVE_GHOST_REPLAY
00328 //-----------------------------------------------------------------------------
00329 bool World::saveReplayHumanReadable( std::string const &filename ) const
00330 {
00331     std::string path;
00332     path = file_manager->getReplayFile(filename+"."+ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
00333 
00334     FILE *fd = fopen( path.c_str(), "w" );
00335     if( !fd ) 
00336     {
00337         fprintf(stderr, "Error while opening replay file for writing '%s'\n", path.c_str());
00338         return false;
00339     }
00340     int  nKarts = world->getNumKarts();
00341     const char *version = "unknown";
00342 #ifdef VERSION
00343     version = VERSION;
00344 #endif
00345     fprintf(fd, "Version:  %s\n",   version);
00346     fprintf(fd, "numkarts: %d\n",   m_kart.size());
00347     fprintf(fd, "numplayers: %d\n", race_manager->getNumPlayers());
00348     fprintf(fd, "difficulty: %d\n", race_manager->getDifficulty());
00349     fprintf(fd, "track: %s\n",      m_track->getIdent().c_str());
00350 
00351     for(int i=0; i<race_manager->getNumKarts(); i++)
00352     {
00353         fprintf(fd, "model %d: %s\n", i, race_manager->getKartName(i).c_str());
00354     }
00355     if( !m_replay_recorder.saveReplayHumanReadable( fd ) )
00356     {
00357         fclose( fd ); fd = NULL;
00358         return false;
00359     }
00360 
00361     fclose( fd ); fd = NULL;
00362 
00363     return true;
00364 }  // saveReplayHumanReadable
00365 #endif  // HAVE_GHOST_REPLAY
00366 
00367 #ifdef HAVE_GHOST_REPLAY
00368 //-----------------------------------------------------------------------------
00369 bool World::loadReplayHumanReadable( std::string const &filename )
00370 {
00371     assert( m_p_replay_player );
00372     m_p_replay_player->destroy();
00373 
00374     std::string path = file_manager->getReplayFile(filename+"."+ 
00375             ReplayBase::REPLAY_FILE_EXTENSION_HUMAN_READABLE);
00376 
00377     try
00378     {
00379         path = file_manager->getPath(path.c_str());
00380     }
00381     catch(std::runtime_error& e)
00382     {
00383         fprintf( stderr, "Couldn't find replay-file: '%s'\n", path.c_str() );
00384         return false;
00385     }
00386 
00387     FILE *fd = fopen( path.c_str(), "r" );
00388     if( !fd ) 
00389     {
00390         fprintf(stderr, "Error while opening replay file for loading '%s'\n", path.c_str());
00391         return false;
00392     }
00393 
00394     bool blnRet = m_p_replay_player->loadReplayHumanReadable( fd );
00395 
00396     fclose( fd ); fd = NULL;
00397 
00398     return blnRet;
00399 }  // loadReplayHumanReadable
00400 #endif  // HAVE_GHOST_REPLAY
00401 
00402 //-----------------------------------------------------------------------------
00403 
00404 void World::updateRaceStatus(float dt)
00405 {
00406     switch (m_phase) {
00407         case SETUP_PHASE:   m_clock=0.0f;  m_phase=READY_PHASE;
00408                             dt = 0.0f;  // solves the problem of adding track loading time
00409                             break;                // loading time, don't play sound yet
00410         case READY_PHASE:   if(m_clock==0.0)      // play sound at beginning of next frame
00411                                 sound_manager->playSfx(SOUND_PRESTART);
00412                             if(m_clock>1.0)
00413                             {
00414                                 m_phase=SET_PHASE;   
00415                                 sound_manager->playSfx(SOUND_PRESTART);
00416                             }
00417                             break;
00418         case SET_PHASE  :   if(m_clock>2.0) 
00419                             {
00420                                 m_phase=GO_PHASE;
00421                                 if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
00422                                     m_clock=m_leader_intervals[0];
00423                                 else
00424                                     m_clock=0.0f;
00425                                 sound_manager->playSfx(SOUND_START);
00426                                 // Reset the brakes now that the prestart 
00427                                 // phase is over (braking prevents the karts 
00428                                 // from sliding downhill)
00429                                 for(unsigned int i=0; i<m_kart.size(); i++) 
00430                                 {
00431                                     m_kart[i]->resetBrakes();
00432                                 }
00433 #ifdef HAVE_GHOST_REPLAY
00434                                 // push positions at time 0.0 to replay-data
00435                                 m_replay_recorder.pushFrame();
00436 #endif
00437                             }
00438                             break;
00439         case GO_PHASE  :    if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
00440                             {
00441                                 // Switch to race if more than 1 second has past
00442                                 if(m_clock<m_leader_intervals[0]-1.0f)
00443                                     m_phase=RACE_PHASE;
00444                             }
00445                             else
00446                             {
00447                                 if(m_clock>1.0)    // how long to display the 'go' message  
00448                                     m_phase=RACE_PHASE;    
00449                             }
00450 
00451                             break;
00452         default        :    break;
00453     }   // switch
00454     if(race_manager->getRaceMode()==RaceManager::RM_FOLLOW_LEADER)
00455     {
00456         // Count 'normal' till race phase has started, then count backwards
00457         if(m_phase==RACE_PHASE || m_phase==GO_PHASE)
00458             m_clock -=dt;
00459         else
00460             m_clock +=dt;
00461         if(m_clock<0.0f)
00462         {
00463             if(m_leader_intervals.size()>1)
00464                 m_leader_intervals.erase(m_leader_intervals.begin());
00465             m_clock=m_leader_intervals[0];
00466             int kart_number;
00467             // If the leader kart is not the first kart, remove the first
00468             // kart, otherwise remove the last kart.
00469             int position_to_remove = m_kart[0]->getPosition()==1 
00470                                    ? getCurrentNumKarts() : 1;
00471             for (kart_number=0; kart_number<(int)m_kart.size(); kart_number++)
00472             {
00473                 if(m_kart[kart_number]->isEliminated()) continue;
00474                 if(m_kart[kart_number]->getPosition()==position_to_remove)
00475                     break;
00476             }
00477             if(kart_number==m_kart.size())
00478             {
00479                 fprintf(stderr,"Problem with removing leader: position %d not found\n",
00480                         position_to_remove);
00481                 for(int i=0; i<(int)m_kart.size(); i++)
00482                 {
00483                     fprintf(stderr,"kart %d: eliminated %d position %d\n",
00484                         i,m_kart[i]->isEliminated(), m_kart[i]->getPosition());
00485                 }   // for i
00486             }  // kart_number==m_kart.size()
00487             else
00488             {
00489                 removeKart(kart_number);
00490             }
00491             // The follow the leader race is over if there isonly one kart left,
00492             // or if all players have gone
00493             if(getCurrentNumKarts()==2 ||getCurrentNumPlayers()==0)
00494             {
00495                 // Add the results for the remaining kart
00496                 for(int i=1; i<(int)race_manager->getNumKarts(); i++)
00497                     if(!m_kart[i]->isEliminated()) 
00498                         race_manager->addKartResult(i, m_kart[i]->getPosition(), 
00499                                                     m_clock);
00500                 m_phase=FINISH_PHASE;
00501                 return;
00502             }
00503         }   // m_clock<0
00504         return;
00505     }   // if is follow leader mode
00506     
00507     // Now handling of normal race
00508     // ===========================
00509     m_clock += dt;
00510 
00511     /*if all players have finished, or if only one kart is not finished when
00512       not in time trial mode, the race is over. Players are the last in the
00513       vector, so substracting the number of players finds the first player's
00514       position.*/
00515     int new_finished_karts   = 0;
00516     for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
00517     {
00518         if(m_kart[i]->isEliminated()) continue;
00519         // FIXME: this part should be done as part of Kart::update
00520         if ((m_kart[i]->getLap () >= race_manager->getNumLaps()) && !m_kart[i]->raceIsFinished())
00521         {
00522             m_kart[i]->setFinishingState(m_clock);
00523 
00524             race_manager->addKartResult((int)i, m_kart[i]->getPosition(), m_clock);
00525 
00526             ++new_finished_karts;
00527             if(m_kart[i]->isPlayerKart())
00528             {
00529                 race_manager->PlayerFinishes();
00530                 RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
00531                 if(m)
00532                 {
00533                     m->addMessage(m_kart[i]->getPosition()==1
00534                                   ? _("You won") 
00535                                   : _("You finished") ,
00536                                   m_kart[i], 2.0f, 60);
00537                     m->addMessage( _("the race!"), m_kart[i], 2.0f, 60);
00538                 }
00539             }
00540         }
00541     }
00542     race_manager->addFinishedKarts(new_finished_karts);
00543 
00544     // 1) All karts are finished --> end the race
00545     // ==========================================
00546     if(race_manager->getFinishedKarts() >= race_manager->getNumKarts() )
00547     {
00548         m_phase = FINISH_PHASE;
00549            if(user_config->m_profile<0)  // profiling number of laps -> print stats
00550         {
00551                float min_t=999999.9f, max_t=0.0, av_t=0.0;
00552             for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
00553             {
00554                 max_t = std::max(max_t, m_kart[i]->getFinishTime());
00555                 min_t = std::min(min_t, m_kart[i]->getFinishTime());
00556                       av_t += m_kart[i]->getFinishTime();
00557                    printf("%s  start %d  end %d time %f\n",
00558                        m_kart[i]->getName().c_str(),(int)i,
00559                        m_kart[i]->getPosition(),
00560                        m_kart[i]->getFinishTime());
00561                } 
00562                printf("min %f  max %f  av %f\n",min_t, max_t, av_t/m_kart.size());
00563             std::exit(-2);
00564            }
00565     }   // if all karts are finished
00566 
00567     // 2) All player karts are finished --> wait some
00568     //    time for AI karts to arrive before finishing
00569     // ===============================================
00570     else if(race_manager->allPlayerFinished() && m_phase == RACE_PHASE &&
00571             !user_config->m_profile)
00572     {
00573         m_phase = DELAY_FINISH_PHASE;
00574         m_finish_delay_start_time = m_clock;
00575     }
00576 
00577     // 3) If the 'wait for AI' time is over, estimate arrival times & finish
00578     // =====================================================================
00579     else if(m_phase==DELAY_FINISH_PHASE &&
00580             m_clock-m_finish_delay_start_time>TIME_DELAY_TILL_FINISH &&
00581             !user_config->m_profile)
00582     {
00583         m_phase = FINISH_PHASE;
00584         for ( Karts::size_type i = 0; i < m_kart.size(); ++i)
00585         {
00586             if(!m_kart[i]->raceIsFinished())
00587             {
00588                 const float est_finish_time = m_kart[i]->estimateFinishTime();
00589                 m_kart[i]->setFinishingState(est_finish_time);
00590                 race_manager->addKartResult((int)i, m_kart[i]->getPosition(),
00591                                             est_finish_time);
00592             }   // if !raceIsFinished
00593         }   // for i
00594     }
00595     
00596     if(m_phase==FINISH_PHASE) unlock_manager->raceFinished();
00597 }  // updateRaceStatus
00598 
00599 //-----------------------------------------------------------------------------
00602 void World::removeKart(int kart_number)
00603 {
00604     Kart *kart = m_kart[kart_number];
00605     // Display a message about the eliminated kart in the race gui 
00606     RaceGUI* m=(RaceGUI*)menu_manager->getRaceMenu();
00607     if(m)
00608     {
00609         for (std::vector<PlayerKart*>::iterator i  = m_player_karts.begin();
00610                                                 i != m_player_karts.end();  i++ )
00611         {   
00612             if(*i==kart) 
00613             {
00614                 m->addMessage(_("You have been\neliminated!"), *i, 2.0f, 60);
00615             }
00616             else
00617             {
00618                 char s[MAX_MESSAGE_LENGTH];
00619                 snprintf(s, MAX_MESSAGE_LENGTH,_("'%s' has\nbeen eliminated."),
00620                          kart->getName().c_str());
00621                 m->addMessage( s, *i, 2.0f, 60);
00622             }
00623         }   // for i in kart
00624     }   // if raceMenu exist
00625     if(kart->isPlayerKart())
00626     {
00627         // Change the camera so that it will be attached to the leader 
00628         // and facing backwards.
00629         Camera* camera=((PlayerKart*)kart)->getCamera();
00630         camera->setMode(Camera::CM_LEADER_MODE);
00631         m_eliminated_players++;
00632     }
00633     projectile_manager->newExplosion(kart->getCoord());
00634     // The kart can't be really removed from the m_kart array, since otherwise 
00635     // a race can't be restarted. So it's only marked to be eliminated (and 
00636     // ignored in all loops). Important:world->getCurrentNumKarts() returns 
00637     // the number of karts still racing. This value can not be used for loops 
00638     // over all karts, use race_manager->getNumKarts() instead!
00639     race_manager->addKartResult(kart_number, kart->getPosition(), m_clock);
00640     race_manager->eliminate(kart_number);
00641     kart->eliminate();
00642     m_eliminated_karts++;
00643 
00644 }   // removeKart
00645 
00646 //-----------------------------------------------------------------------------
00647 void World::updateRacePosition ( int k )
00648 {
00649     int p = 1 ;
00650 
00651     /* Find position of kart 'k' */
00652 
00653     for ( Karts::size_type j = 0 ; j < m_kart.size() ; ++j )
00654     {
00655         if(int(j) == k) continue;
00656         if(m_kart[j]->isEliminated()) continue;   // eliminated karts   
00657 
00658         // Count karts ahead of the current kart, i.e. kart that are already
00659         // finished (the current kart k has not yet finished!!), have done more
00660         // laps, or the same number of laps, but a greater distance.
00661         if (m_kart[j]->raceIsFinished()                                          ||
00662             m_kart[j]->getLap() >  m_kart[k]->getLap()                             ||
00663             (m_kart[j]->getLap() == m_kart[k]->getLap() &&
00664              m_kart[j]->getDistanceDownTrack() > m_kart[k]->getDistanceDownTrack()) )
00665             p++ ;
00666     }
00667 
00668     m_kart[k]->setPosition(p);
00669     // Switch on faster music (except in follow leader mode) if not already 
00670     // done so, and the first kart is doing its last lap, and the estimated
00671     // remaining time is less than 30 seconds.
00672     if(!m_faster_music_active                                      && 
00673         m_kart[k]->getLap()==race_manager->getNumLaps()-1          && 
00674         p==1                                                       &&
00675         race_manager->getRaceMode()!=RaceManager::RM_FOLLOW_LEADER &&
00676         m_kart[k]->estimateFinishTime()-getTime()<30.0f               ) 
00677     {
00678         sound_manager->switchToFastMusic();
00679         m_faster_music_active=true;
00680     }
00681 }   // updateRacePosition
00682 
00683 //-----------------------------------------------------------------------------
00684 void World::loadTrack()
00685 {
00686     // remove old herrings (from previous race), and remove old
00687     // track specific herring models
00688     herring_manager->cleanup();
00689     if(race_manager->getRaceMode()== RaceManager::RM_GRAND_PRIX)
00690     {
00691         try
00692         {
00693             herring_manager->loadHerringStyle(race_manager->getHerringStyle());
00694         }
00695         catch(std::runtime_error)
00696         {
00697             fprintf(stderr, "The cup '%s' contains an invalid herring style '%s'.\n",
00698                     race_manager->getGrandPrix()->getName().c_str(),
00699                     race_manager->getHerringStyle().c_str());
00700             fprintf(stderr, "Please fix the file '%s'.\n",
00701                     race_manager->getGrandPrix()->getFilename().c_str());
00702         }
00703     }
00704     else
00705     {
00706         try
00707         {
00708             herring_manager->loadHerringStyle(m_track->getHerringStyle());
00709         }
00710         catch(std::runtime_error)
00711         {
00712             fprintf(stderr, "The track '%s' contains an invalid herring style '%s'.\n",
00713                     m_track->getName(), m_track->getHerringStyle().c_str());
00714             fprintf(stderr, "Please fix the file '%s'.\n",
00715                     m_track->getFilename().c_str());
00716         }
00717     }
00718 
00719     m_track->loadTrackModel();
00720 }   // loadTrack
00721 
00722 //-----------------------------------------------------------------------------
00723 void World::restartRace()
00724 {
00725     m_clock               = 0.0f;
00726     m_phase               = SETUP_PHASE;
00727     m_previous_phase      = SETUP_PHASE;
00728     m_faster_music_active = false;
00729     m_eliminated_karts    = 0;
00730     m_eliminated_players  = 0;
00731     m_leader_intervals    = stk_config->m_leader_intervals;
00732 
00733     for ( Karts::iterator i = m_kart.begin(); i != m_kart.end() ; ++i )
00734     {
00735         (*i)->reset();
00736     }
00737     resetAllKarts();
00738     sound_manager->stopMusic();     // Start music from beginning
00739     m_track->startMusic();
00740     herring_manager->reset();
00741     projectile_manager->cleanup();
00742     race_manager->reset();
00743     callback_manager->reset();
00744 
00745     // Resets the cameras in case that they are pointing too steep up or down
00746     scene->reset();
00747 #ifdef HAVE_GHOST_REPLAY
00748     m_replay_recorder.destroy();
00749     m_replay_recorder.initRecorder( race_manager->getNumKarts() );
00750 
00751     if( m_p_replay_player ) 
00752     {
00753         m_p_replay_player->reset();
00754         m_p_replay_player->showReplayAt( 0.0 );
00755     }
00756 #endif
00757 }   // restartRace
00758 
00759 //-----------------------------------------------------------------------------
00760 Kart* World::loadRobot(const std::string& kart_name, int position,
00761                        sgCoord init_pos)
00762 {
00763     Kart* currentRobot;
00764     
00765     const int NUM_ROBOTS = 1;
00766 
00767     srand((unsigned)std::time(0));
00768 
00769     switch(rand() % NUM_ROBOTS)
00770     {
00771         case 0:
00772             currentRobot = new DefaultRobot(kart_name, position, init_pos);
00773             break;
00774         default:
00775             std::cerr << "Warning: Unknown robot, using default." << std::endl;
00776             currentRobot = new DefaultRobot(kart_name, position, init_pos);
00777             break;
00778     }
00779     
00780     return currentRobot;
00781 }
00782 
00783 //-----------------------------------------------------------------------------
00784 void  World::pause()
00785 {
00786     sound_manager -> pauseMusic() ;
00787     m_previous_phase = m_phase;
00788     m_phase = LIMBO_PHASE;
00789 }
00790 
00791 //-----------------------------------------------------------------------------
00792 void  World::unpause()
00793 {
00794     sound_manager -> resumeMusic() ;
00795     m_phase = m_previous_phase;
00796 }
00797 
00798 /* EOF */