Example #1
0
//-----------------------------------------------------------------------------
void LinearWorld::restartRace()
{
    WorldWithRank::restartRace();
    //if(m_last_lap_sfx->getStatus()== SFXManager::SFX_PLAYING)
    //    m_last_lap_sfx->stop();
    m_last_lap_sfx_played = false;
    m_last_lap_sfx_playing = false;

    const unsigned int kart_amount = m_karts.size();
    for(unsigned int i=0; i<kart_amount; i++)
    {
        KartInfo& info              = m_kart_info[i];
        info.m_track_sector         = QuadGraph::UNKNOWN_SECTOR;
        info.m_last_valid_sector    = 0;
        info.m_lap_start_time       = 0;
        m_track->getQuadGraph().findRoadSector(m_karts[i]->getXYZ(),
                                               &info.m_track_sector);

        //If m_track_sector == UNKNOWN_SECTOR, then the kart is not on top of
        //the road, so we have to use another function to find the sector.
        info.m_on_road = info.m_track_sector != QuadGraph::UNKNOWN_SECTOR;
        if (!info.m_on_road)
        {
            info.m_track_sector =
                m_track->getQuadGraph().findOutOfRoadSector(m_karts[i]->getXYZ(),
                                                            QuadGraph::UNKNOWN_SECTOR );
        }

        m_track->getQuadGraph().spatialToTrack(&info.m_curr_track_coords,
                                               m_karts[i]->getXYZ(),
                                               info.m_track_sector );
        info.m_race_lap             = -1;
        info.m_lap_start_time       = -0;
        info.m_time_at_last_lap     = 99999.9f;
    }   // next kart

    // First all kart infos must be updated before  the kart position can be 
    // recomputed, since otherwise 'new' (initialised) valued will be compared
    // with old values.
    updateRacePosition();
    
#ifdef DEBUG
    //FIXME: this could be defined somewhere in a central header so it can be used everywhere
#define assertExpr( ARG1, OP, ARG2 ) if (!(ARG1 OP ARG2)) \
        { \
            std::cerr << "Failed assert " << #ARG1 << #OP << #ARG2 << " @ " << __FILE__ << ":" << __LINE__ \
                      << "; values are (" << ARG1 << #OP << ARG2 << ")\n"; \
            assert(false); \
        }
    
    for (unsigned int i=0; i<kart_amount; i++)
    {
        for (unsigned int j=i+1; j<kart_amount; j++)
        {
            assertExpr( m_karts[i]->getPosition(), !=, m_karts[j]->getPosition() );
        }
    }
#endif
    
}   // restartRace
Example #2
0
/** Called before a race is started (or restarted). It resets the data
 *  structures that keep track of position and distance long track of
 *  all karts.
 */
void LinearWorld::reset()
{
    WorldWithRank::reset();
    m_last_lap_sfx_played = false;
    m_last_lap_sfx_playing = false;

    const unsigned int kart_amount = (unsigned int) m_karts.size();
    for(unsigned int i=0; i<kart_amount; i++)
    {
        m_kart_info[i].reset();
        m_karts[i]->setWrongwayCounter(0);
    }   // next kart

    // At the moment the last kart would be the one that is furthest away
    // from the start line, i.e. it would determine the amount by which
    // the track length must be extended (to avoid negative numbers in
    // estimateFinishTimeForKart()). On the other hand future game modes
    // might not follow this rule, so check the distance for all karts here:
    m_distance_increase = m_track->getTrackLength();
    for(unsigned int i=0; i<kart_amount; i++)
    {
        m_distance_increase = std::min(m_distance_increase,
                                       getDistanceDownTrackForKart(i));
    }
    // Track length - minimum distance is how much the track length must
    // be increased to avoid negative values in estimateFinishTimeForKart
    // Increase this value somewhat in case that a kart drivess/slides
    // backwards a little bit at start.
    m_distance_increase = m_track->getTrackLength() - m_distance_increase
                        + 5.0f;

    if(m_distance_increase<0) m_distance_increase = 1.0f;  // shouldn't happen

    // First all kart infos must be updated before the kart position can be
    // recomputed, since otherwise 'new' (initialised) valued will be compared
    // with old values.
    updateRacePosition();

#ifdef DEBUG
    //FIXME: this could be defined somewhere in a central header so it can
    //       be used everywhere
#define assertExpr( ARG1, OP, ARG2 ) if (!(ARG1 OP ARG2)) \
        { \
            std::cerr << "Failed assert " << #ARG1 << #OP << #ARG2 << " @ " \
                      << __FILE__ << ":" << __LINE__ \
                      << "; values are (" << ARG1 << #OP << ARG2 << ")\n"; \
            assert(false); \
        }

    for (unsigned int i=0; i<kart_amount; i++)
    {
        for (unsigned int j=i+1; j<kart_amount; j++)
        {
            assertExpr( m_karts[i]->getPosition(), !=,
                        m_karts[j]->getPosition() );
        }
    }
#endif

}   // reset
//-----------------------------------------------------------------------------
void LinearWorld::restartRace()
{
    WorldWithRank::restartRace();
    //if(m_last_lap_sfx->getStatus()== SFXManager::SFX_PLAYING)
    //    m_last_lap_sfx->stop();
    m_last_lap_sfx_played = false;
    m_last_lap_sfx_playing = false;

    const unsigned int kart_amount = m_karts.size();
    for(unsigned int i=0; i<kart_amount; i++)
    {
        m_kart_info[i].reset();
        m_kart_info[i].getSector()->update(m_karts[i]->getXYZ());
    }   // next kart

    // First all kart infos must be updated before  the kart position can be 
    // recomputed, since otherwise 'new' (initialised) valued will be compared
    // with old values.
    updateRacePosition();
    
#ifdef DEBUG
    //FIXME: this could be defined somewhere in a central header so it can 
    //       be used everywhere
#define assertExpr( ARG1, OP, ARG2 ) if (!(ARG1 OP ARG2)) \
        { \
            std::cerr << "Failed assert " << #ARG1 << #OP << #ARG2 << " @ " << __FILE__ << ":" << __LINE__ \
                      << "; values are (" << ARG1 << #OP << ARG2 << ")\n"; \
            assert(false); \
        }
    
    for (unsigned int i=0; i<kart_amount; i++)
    {
        for (unsigned int j=i+1; j<kart_amount; j++)
        {
            assertExpr( m_karts[i]->getPosition(), !=,
                        m_karts[j]->getPosition() );
        }
    }
#endif
    
}   // restartRace
Example #4
0
/** Is called by check structures if a kart starts a new lap.
 *  \param kart_index Index of the kart.
 */
void LinearWorld::newLap(unsigned int kart_index)
{
    KartInfo &kart_info = m_kart_info[kart_index];
    AbstractKart *kart  = m_karts[kart_index];

    // Reset reset-after-lap achievements
    StateManager::ActivePlayer *c = kart->getController()->getPlayer();
    PlayerProfile *p = PlayerManager::getCurrentPlayer();
    if (c && c->getConstProfile() == p)
    {
        p->getAchievementsStatus()->onLapEnd();
    }

    // Only update the kart controller if a kart that has already finished
    // the race crosses the start line again. This avoids 'fastest lap'
    // messages if the end controller does a fastest lap, but especially
    // allows the end controller to switch end cameras
    if(kart->hasFinishedRace())
    {
        kart->getController()->newLap(kart_info.m_race_lap);
        return;
    }

    const int lap_count = race_manager->getNumLaps();

    // Only increase the lap counter and set the new time if the
    // kart hasn't already finished the race (otherwise the race_gui
    // will begin another countdown).
    if(kart_info.m_race_lap+1 <= lap_count)
    {
        assert(kart->getWorldKartId()==kart_index);
        kart_info.m_time_at_last_lap=getTime();
        kart_info.m_race_lap++;
        m_kart_info[kart_index].m_overall_distance =
              m_kart_info[kart_index].m_race_lap * m_track->getTrackLength()
            + getDistanceDownTrackForKart(kart->getWorldKartId());
    }
    // Last lap message (kart_index's assert in previous block already)
    if (raceHasLaps() && kart_info.m_race_lap+1 == lap_count)
    {
        m_race_gui->addMessage(_("Final lap!"), kart,
                               3.0f, video::SColor(255, 210, 100, 50), true);
        if(!m_last_lap_sfx_played && lap_count > 1)
        {
            if (UserConfigParams::m_music)
            {
                m_last_lap_sfx->play();
                m_last_lap_sfx_played = true;
                m_last_lap_sfx_playing = true;

                // In case that no music is defined
                if(music_manager->getCurrentMusic() &&
                    music_manager->getMasterMusicVolume() > 0.2f)
                {
                    music_manager->setTemporaryVolume(0.2f);
                }
            }
            else
            {
                m_last_lap_sfx_played = true;
                m_last_lap_sfx_playing = false;
            }
        }
    }
    else if (raceHasLaps() && kart_info.m_race_lap > 0 &&
             kart_info.m_race_lap+1 < lap_count)
    {
        m_race_gui->addMessage(_("Lap %i", kart_info.m_race_lap+1),
                               kart, 3.0f, video::SColor(255, 210, 100, 50),
                               true);
    }

    // The race positions must be updated here: consider the situation where
    // the first kart does not cross the finish line in its last lap, instead
    // it passes it, the kart reverses and crosses the finishing line
    // backwards. Just before crossing the finishing line the kart will be on
    // the last lap, but with a distance along the track close to zero.
    // Therefore its position will be wrong. If the race position gets updated
    // after increasing the number of laps (but before tagging the kart to have
    // finished the race) the position will be correct (since the kart now
    // has one additional lap it will be ahead of the other karts).
    // Without this call the incorrect position for this kart would remain
    // (since a kart that has finished the race does not get its position
    // changed anymore), potentially resulting in a duplicated race position
    // (since the first kart does not have position 1, no other kart can get
    // position 1, so one rank will be duplicated).
    // Similarly the situation can happen if the distance along track should
    // go back to zero before actually crossing the finishing line. While this
    // should not happen, it could potentially be caused by floating point
    // errors. In this case the call to updateRacePosition will avoid
    // duplicated race positions as well.
    updateRacePosition();

    // Race finished
    if(kart_info.m_race_lap >= race_manager->getNumLaps() && raceHasLaps())
    {
        kart->finishedRace(getTime());
    }
    float time_per_lap;
    if (kart_info.m_race_lap == 1) // just completed first lap
    {
        time_per_lap=getTime();
    }
    else //completing subsequent laps
    {
        time_per_lap=getTime() - kart_info.m_lap_start_time;
    }

    // if new fastest lap
    if(time_per_lap < m_fastest_lap && raceHasLaps() &&
        kart_info.m_race_lap>0)
    {
        m_fastest_lap = time_per_lap;

        std::string s = StringUtils::timeToString(time_per_lap);

        // Store the temporary string because clang would mess this up
        // (remove the stringw before the wchar_t* is used).
        const core::stringw &kart_name = kart->getName();

        //I18N: as in "fastest lap: 60 seconds by Wilber"
        irr::core::stringw m_fastest_lap_message =
            _C("fastest_lap", "%s by %s", s.c_str(), kart_name);

        m_race_gui->addMessage(m_fastest_lap_message, NULL,
                               3.0f, video::SColor(255, 255, 255, 255), false);

        m_race_gui->addMessage(_("New fastest lap"), NULL,
                               3.0f, video::SColor(255, 255, 255, 255), false);

    } // end if new fastest lap

    kart_info.m_lap_start_time = getTime();
    kart->getController()->newLap(kart_info.m_race_lap);
}   // newLap
Example #5
0
/** General update function called once per frame. This updates the kart
 *  sectors, which are then used to determine the kart positions.
 *  \param dt Time step size.
 */
void LinearWorld::update(float dt)
{
    // run generic parent stuff that applies to all modes. It
    // especially updates the kart positions.
    WorldWithRank::update(dt);

    if (m_last_lap_sfx_playing &&
        m_last_lap_sfx->getStatus() != SFXBase::SFX_PLAYING)
    {
        music_manager->resetTemporaryVolume();
        m_last_lap_sfx_playing = false;
    }

    const unsigned int kart_amount = getNumKarts();

    // Do stuff specific to this subtype of race.
    // ------------------------------------------
    for(unsigned int n=0; n<kart_amount; n++)
    {
        KartInfo& kart_info = m_kart_info[n];
        AbstractKart* kart = m_karts[n];

        // Nothing to do for karts that are currently being
        // rescued or eliminated
        if(kart->getKartAnimation()) continue;

        kart_info.getTrackSector()->update(kart->getFrontXYZ());
        kart_info.m_overall_distance = kart_info.m_race_lap
                                     * m_track->getTrackLength()
                        + getDistanceDownTrackForKart(kart->getWorldKartId());
    }   // for n

    // Update all positions. This must be done after _all_ karts have
    // updated their position and laps etc, otherwise inconsistencies
    // (like two karts at same position) can occur.
    // ---------------------------------------------------------------
    WorldWithRank::updateTrack(dt);
    updateRacePosition();

    for (unsigned int i=0; i<kart_amount; i++)
    {
        // ---------- update rank ------
        if (m_karts[i]->hasFinishedRace() ||
            m_karts[i]->isEliminated()       ) continue;

        // During the last lap update the estimated finish time.
        // This is used to play the faster music, and by the AI
        if (m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1)
        {
            m_kart_info[i].m_estimated_finish =
                estimateFinishTimeForKart(m_karts[i]);
        }
        checkForWrongDirection(i, dt);
    }

#ifdef DEBUG
    // Debug output in case that the double position error occurs again.
    std::vector<int> pos_used;
    pos_used.resize(kart_amount+1, -99);
    for(unsigned int i=0; i<kart_amount; i++)
    {
        if(pos_used[m_karts[i]->getPosition()]!=-99)
        {
            for(unsigned int j=0; j<kart_amount; j++)
            {
                Log::verbose("[LinearWorld]", "kart id=%u, position=%d, finished=%d, laps=%d, "
                       "distanceDownTrack=%f overallDistance=%f %s",
                    j, m_karts[j]->getPosition(),
                    m_karts[j]->hasFinishedRace(),
                    m_kart_info[j].m_race_lap,
                    getDistanceDownTrackForKart(m_karts[j]->getWorldKartId()),
                    m_kart_info[j].m_overall_distance,
                    (m_karts[j]->getPosition() == m_karts[i]->getPosition()
                     ? "<--- !!!" : "")                                      );
            }
        }
        pos_used[m_karts[i]->getPosition()]=i;
    }
#endif
}   // update
/** Called when a kart must be eliminated.
 */
void FollowTheLeaderRace::countdownReachedZero()
{
    if(m_leader_intervals.size()>1)
        m_leader_intervals.erase(m_leader_intervals.begin());
    WorldStatus::setTime(m_leader_intervals[0]);

    // If the leader kart is not the first kart, remove the first
    // kart, otherwise remove the last kart.
    int position_to_remove = m_karts[0]->getPosition()==1
                           ? getCurrentNumKarts() : 1;
    AbstractKart *kart = getKartAtPosition(position_to_remove);
    if(!kart || kart->isEliminated())
    {
        fprintf(stderr,"Problem with removing leader: position %d not found\n",
                position_to_remove);
        for(unsigned int i=0; i<m_karts.size(); i++)
        {
            fprintf(stderr,"kart %d: eliminated %d position %d\n",
                    i,m_karts[i]->isEliminated(), m_karts[i]->getPosition());
        }   // for i
    }  //
    else
    {
        if(UserConfigParams::m_ftl_debug)
        {
            printf("[ftl] Eliminiating kart '%s' at position %d.\n",
                kart->getIdent().c_str(), position_to_remove);
        }
        eliminateKart(kart->getWorldKartId());

        // In case that the kart on position 1 was removed, we have
        // to set the correct position (which equals the remaining
        // number of karts) for the removed kart, as well as recompute
        // the position for all other karts
        if(position_to_remove==1)
        {
            // We have to add 1 to the number of karts to get the correct
            // position, since the eliminated kart was already removed
            // from the value returned by getCurrentNumKarts (and we have
            // to remove the kart before we can call updateRacePosition).
            // Note that we can not call WorldWithRank::setKartPosition
            // here, since it would not properly support debugging kart
            // ranks (since this kart would get its position set again
            // in updateRacePosition). We only set the rank of the eliminated
            // kart, and updateRacePosition will then call setKartPosition
            // for the now eliminated kart.
            kart->setPosition(getCurrentNumKarts()+1);
            updateRacePosition();
        }
        // Time doesn't make any sense in FTL (and it is not displayed)
        kart->finishedRace(-1.0f);

        // Move any camera for this kart to the leader, facing backwards,
        // so that the eliminated player has something to watch.
        if (race_manager->getNumPlayers() > 1)
        {
            for(unsigned int i=0; i<Camera::getNumCameras(); i++)
            {
                Camera *camera = Camera::getCamera(i);
                if(camera->getKart()==kart)
                {
                    camera->setMode(Camera::CM_LEADER_MODE);
                    camera->setKart(getKart(0));
                }
            }   // for i<number of cameras
        }
    }   // if kart to eliminate exists

    // almost over, use fast music
    if(getCurrentNumKarts()==3)
    {
        music_manager->switchToFastMusic();
    }

    if (isRaceOver())
    {
        // Handle special FTL situation: the leader is kart number 3 when
        // the last kart gets eliminated. In this case kart on position 1
        // is eliminated, and the kart formerly on position 2 is on
        // position 1, the leader now position 2. In this case the kart
        // on position 1 would get more points for this victory. So if
        // this is the case, change the position
        if(m_karts[0]->getPosition()!=1)
        {
            // Adjust the position of all still driving karts that
            // are ahead of the leader by +1, and move the leader
            // to position 1.
            for (unsigned int i=1; i<m_karts.size(); i++)
            {
                if(!m_karts[i]->hasFinishedRace() &&
                    !m_karts[i]->isEliminated()   &&
                    m_karts[i]->getPosition()<m_karts[0]->getPosition())
                {
                        m_karts[i]->setPosition(m_karts[i]->getPosition()+1);
                }
            }
            m_karts[0]->setPosition(1);
        }

        // Mark all still racing karts to be finished.
        for (unsigned int n=0; n<m_karts.size(); n++)
        {
            if (!m_karts[n]->isEliminated() &&
                !m_karts[n]->hasFinishedRace())
            {
                m_karts[n]->finishedRace(getTime());
            }
        }
    }
    // End of race is detected from World::updateWorld()

}   // countdownReachedZero
Example #7
0
/** Is called by check structures if a kart starts a new lap.
 *  \param kart_index Index of the kart.
 */
void LinearWorld::newLap(unsigned int kart_index)
{
    KartInfo &kart_info = m_kart_info[kart_index];
    Kart    *kart       = m_karts[kart_index];

    // Don't do anything if a kart that has already finished the race
    // crosses the start line again. This avoids 'fastest lap' messages
    // if the end controller does a fastest lap.
    if(kart->hasFinishedRace()) return;

    const int lap_count = race_manager->getNumLaps();
    
    // Only increase the lap counter and set the new time if the
    // kart hasn't already finished the race (otherwise the race_gui
    // will begin another countdown).
    if(kart_info.m_race_lap+1 <= lap_count)
    {
        assert(kart->getWorldKartId()==kart_index);
        setTimeAtLapForKart(getTime(), kart_index );
        kart_info.m_race_lap++ ;
    }
    // Last lap message (kart_index's assert in previous block already)
    if(kart_info.m_race_lap+1 == lap_count)
    {
        m_race_gui->addMessage(_("Final lap!"), m_karts[kart_index],
                               3.0f, 40, video::SColor(255, 210, 100, 50), true);
        if(!m_last_lap_sfx_played && lap_count > 1)
        {
            m_last_lap_sfx->play();
            m_last_lap_sfx_played = true;
            m_last_lap_sfx_playing = true;
            
            // In case that no music is defined
            if(music_manager->getCurrentMusic() && music_manager->getMasterMusicVolume() > 0.2f)
            {
                music_manager->getCurrentMusic()->setTemporaryVolume(0.2f);
            }
        }
    }

    // The race positions must be updated here: consider the situation where 
    // the first kart does not cross the finish line in its last lap, instead 
    // it passes it, the kart reverses and crosses the finishing line 
    // backwards. Just before crossing the finishing line the kart will be on
    // the last lap, but with a distance along the track close to zero. 
    // Therefore its position will be wrong. If the race position gets updated
    // after increasing the number of laps (but before tagging the kart to have
    // finished the race) the position will be correct (since the kart now
    // has one additional lap it will be ahead of the other karts).
    // Without this call the incorrect position for this kart would remain
    // (since a kart that has finished the race does not get its position
    // changed anymore), potentially resulting in a duplicated race position
    // (since the first kart does not have position 1, no other kart can get
    // position 1, so one rank will be duplicated).
    // Similarly the situation can happen if the distance along track should
    // go back to zero before actually crossing the finishing line. While this
    // should not happen, it could potentially be caused by floating point
    // errors. In this case the call to updateRacePosition will avoid 
    // duplicated race positions as well.
    updateRacePosition();

    // Race finished
    if(kart_info.m_race_lap >= race_manager->getNumLaps() && raceHasLaps())
    {
        // A client wait does not detect race finished by itself, it will
        // receive a message from the server. So a client does not do
        // anything here.
        if(network_manager->getMode()!=NetworkManager::NW_CLIENT)
        {
            kart->finishedRace(getTime());
        }
    }
    {
        float time_per_lap;
        if (kart_info.m_race_lap == 1) // just completed first lap
        {
            time_per_lap=getTime();
        }
        else //completing subsequent laps
        {
            time_per_lap=getTime() - kart_info.m_lap_start_time;
        }

        // if new fastest lap
        if(time_per_lap < getFastestLapTime() && raceHasLaps() &&
            kart_info.m_race_lap>0)
        {
            setFastestLap(kart, time_per_lap);
            m_race_gui->addMessage(_("New fastest lap"), NULL,
                                   2.0f, 40, video::SColor(255, 100, 210, 100), true);
            std::string s = StringUtils::timeToString(time_per_lap);

            irr::core::stringw m_fastest_lap_message;
            //I18N: as in "fastest lap: 60 seconds by Wilber"
            m_fastest_lap_message += StringUtils::insertValues(_("%s by %s"), s.c_str(), kart->getName().c_str()).c_str();

            m_race_gui->addMessage(m_fastest_lap_message, NULL,
                                   2.0f, 40, video::SColor(255, 100, 210, 100));
        } // end if new fastest lap
    }
    kart_info.m_lap_start_time = getTime();
}   // newLap
Example #8
0
/** General update function called once per frame. This updates the kart
 *  sectors, which are then used to determine the kart positions.
 *  \param dt Time step size.
 */
void LinearWorld::update(float delta)
{
    // run generic parent stuff that applies to all modes. It
    // especially updates the kart positions.
    WorldWithRank::update(delta);
    
    if (m_last_lap_sfx_playing && m_last_lap_sfx->getStatus() != SFXManager::SFX_PLAYING)
    {
        music_manager->getCurrentMusic()->resetTemporaryVolume();
        m_last_lap_sfx_playing = false;
    }
    
    const unsigned int kart_amount = getNumKarts();

    // Do stuff specific to this subtype of race.
    // ------------------------------------------
    for(unsigned int n=0; n<kart_amount; n++)
    {
        KartInfo& kart_info = m_kart_info[n];
        Kart* kart = m_karts[n];

        // Nothing to do for karts that are currently being rescued or eliminated
        if(kart->playingEmergencyAnimation()) continue;

        // ---------- deal with sector data ---------

        // update sector variables
        int prev_sector = kart_info.m_track_sector;
        m_track->getQuadGraph().findRoadSector(kart->getXYZ(),
                                               &kart_info.m_track_sector);

        kart_info.m_on_road = kart_info.m_track_sector != QuadGraph::UNKNOWN_SECTOR;
        if(kart_info.m_on_road)
        {
            kart_info.m_last_valid_sector   = kart_info.m_track_sector;
            kart_info.m_last_valid_race_lap = kart_info.m_race_lap;
        }
        else
        {
            // Kart off road. Find the closest sector instead.
            kart_info.m_track_sector =
                m_track->getQuadGraph().findOutOfRoadSector(kart->getXYZ(), prev_sector );
        }

        // Update track coords (=progression)
        m_track->getQuadGraph().spatialToTrack(&kart_info.m_curr_track_coords,
                                               kart->getXYZ(),
                                               kart_info.m_track_sector    );

    }   // for n

    // Update all positions. This must be done after _all_ karts have
    // updated their position and laps etc, otherwise inconsistencies
    // (like two karts at same position) can occur.
    // ---------------------------------------------------------------
    
    updateRacePosition();
    
    for (unsigned int i=0; i<kart_amount; i++)
    {
        // ---------- update rank ------
        if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated()) continue;

        // During the last lap update the estimated finish time.
        // This is used to play the faster music, and by the AI
        if (m_kart_info[i].m_race_lap == race_manager->getNumLaps()-1)
        {
            m_kart_info[i].m_estimated_finish = estimateFinishTimeForKart(m_karts[i]);
        }
        checkForWrongDirection(i);
    }
    
#ifdef DEBUG
    // FIXME: Debug output in case that the double position error occurs again.
    std::vector<int> pos_used;
    pos_used.resize(kart_amount+1, -99);
    for(unsigned int i=0; i<kart_amount; i++)
    {
        if(pos_used[m_karts[i]->getPosition()]!=-99)
        {
            for(unsigned int j =0; j<kart_amount; j++)
            {
                printf("kart id=%d, position=%d, finished=%d, laps=%d, distanceDownTrack=%f %s\n",
                    j, m_karts[j]->getPosition(),
                    m_karts[j]->hasFinishedRace(),
                    m_kart_info[j].m_race_lap,
                    getDistanceDownTrackForKart(m_karts[j]->getWorldKartId()),
                    (m_karts[j]->getPosition() == m_karts[i]->getPosition() ? "<--- !!!" : ""));
            }
        }
        pos_used[m_karts[i]->getPosition()]=i;
    }
#endif
}   // update