Exemple #1
0
/** Called at the end of a race. Updates highscores, pauses the game, and
 *  informs the unlock manager about the finished race. This function must
 *  be called after all other stats were updated from the different game
 *  modes.
 */
void World::terminateRace()
{
    m_schedule_pause = false;
    m_schedule_unpause = false;

    // Update the estimated finishing time for all karts that haven't
    // finished yet.
    const unsigned int kart_amount = getNumKarts();
    for(unsigned int i = 0; i < kart_amount ; i++)
    {
        if(!m_karts[i]->hasFinishedRace() && !m_karts[i]->isEliminated())
        {
            m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));

        }
    }   // i<kart_amount

    // Update highscores, and retrieve the best highscore if relevant
    // to show it in the GUI
    int best_highscore_rank = -1;
    int best_finish_time = -1;
    std::string highscore_who = "";
    StateManager::ActivePlayer* best_player = NULL;
    if (!this->isNetworkWorld())
    {
        updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who,
                     &best_player);
    }

    // Check achievements
    PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_COLUMBUS,
                                       getTrack()->getIdent(), 1);
    if (raceHasLaps())
    {
        PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_MARATHONER,
                                           "laps", race_manager->getNumLaps());
    }

    Achievement *achiev = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER);
    if (achiev)
    {
        std::string mode_name = getIdent(); // Get the race mode name
        int winner_position = 1;
        unsigned int opponents = achiev->getInfo()->getGoalValue("opponents"); // Get the required opponents number
        if (mode_name == IDENT_FTL)
        {
            winner_position = 2;
            opponents++;
        }
        for(unsigned int i = 0; i < kart_amount; i++)
        {
            // Retrieve the current player
            StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
            if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
            {
                // Check if the player has won
                if (m_karts[i]->getPosition() == winner_position && kart_amount > opponents )
                {
                    // Update the achievement
                    mode_name = StringUtils::toLowerCase(mode_name);
                    if (achiev->getValue("opponents") <= 0)
                        PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
                                                            "opponents", opponents);
                    PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_GOLD_DRIVER,
                                                        mode_name, 1);
                }
            }
        } // for i < kart_amount
    } // if (achiev)

    Achievement *win = PlayerManager::getCurrentAchievementsStatus()->getAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE);
    //if achivement has been unlocked
    if (win->getValue("wins") < 5 )
    {
        for(unsigned int i = 0; i < kart_amount; i++)
        {
            // Retrieve the current player
            StateManager::ActivePlayer* p = m_karts[i]->getController()->getPlayer();
            if (p && p->getConstProfile() == PlayerManager::getCurrentPlayer())
            {
                // Check if the player has won
                if (m_karts[i]->getPosition() == 1 )
                {
                    // Increase number of consecutive wins
                       PlayerManager::increaseAchievement(AchievementInfo::ACHIEVE_UNSTOPPABLE,
                                                            "wins", 1);
                }
                else
                {
                      //Set number of consecutive wins to 0
                      win->reset();
                }
            }
         }
    }
    PlayerManager::getCurrentPlayer()->raceFinished();

    if (m_race_gui) m_race_gui->clearAllMessages();
    // we can't delete the race gui here, since it is needed in case of
    // a restart: the constructor of it creates some textures which assume
    // that no scene nodes exist. In case of a restart there are scene nodes,
    // so we can't create the race gui again, so we keep it around
    // and save the pointer.
    assert(m_saved_race_gui==NULL);
    m_saved_race_gui = m_race_gui;

    RaceResultGUI* results = RaceResultGUI::getInstance();
    m_race_gui       = results;

    if (best_highscore_rank > 0)
    {
        results->setHighscore(highscore_who, best_player, best_highscore_rank,
                              best_finish_time);
    }
    else
    {
        results->clearHighscores();
    }

    results->push();
    WorldStatus::terminateRace();
}   // terminateRace
Exemple #2
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
Exemple #3
0
//-----------------------------------------------------------------------------
void LinearWorld::getKartsDisplayInfo(
                           std::vector<RaceGUIBase::KartIconDisplayInfo> *info)
{
    int   laps_of_leader       = -1;
    float time_of_leader       = -1;
    // Find the best time for the lap. We can't simply use
    // the time of the kart at position 1, since the kart
    // might have been overtaken by now
    const unsigned int kart_amount = getNumKarts();
    for(unsigned int i = 0; i < kart_amount ; i++)
    {
        RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
        AbstractKart* kart = m_karts[i];

        // reset color
        rank_info.m_color = video::SColor(255, 255, 255, 255);
        rank_info.lap = -1;

        if(kart->isEliminated()) continue;
        const float lap_time = getTimeAtLapForKart(kart->getWorldKartId());
        const int current_lap  = getLapForKart( kart->getWorldKartId() );
        rank_info.lap = current_lap;

        if(current_lap > laps_of_leader)
        {
            // more laps than current leader --> new leader and
            // new time computation
            laps_of_leader = current_lap;
            time_of_leader = lap_time;
        } else if(current_lap == laps_of_leader)
        {
            // Same number of laps as leader: use fastest time
            time_of_leader=std::min(time_of_leader,lap_time);
        }
    }

    // we now know the best time of the lap. fill the remaining bits of info
    for(unsigned int i = 0; i < kart_amount ; i++)
    {
        RaceGUIBase::KartIconDisplayInfo& rank_info = (*info)[i];
        KartInfo& kart_info = m_kart_info[i];
        AbstractKart* kart = m_karts[i];

        const int position = kart->getPosition();

        // Don't compare times when crossing the start line first
        if(laps_of_leader>0                                                &&
           (getTime() - getTimeAtLapForKart(kart->getWorldKartId())<5.0f ||
            rank_info.lap != laps_of_leader)                               &&
            raceHasLaps())
        {  // Display for 5 seconds
            std::string str;
            if(position == 1)
            {
                str = " " + StringUtils::timeToString(
                                 getTimeAtLapForKart(kart->getWorldKartId()) );
            }
            else
            {
                float timeBehind;
                timeBehind = (kart_info.m_race_lap==laps_of_leader
                                ? getTimeAtLapForKart(kart->getWorldKartId())
                                : getTime())
                           - time_of_leader;
                str = "+" + StringUtils::timeToString(timeBehind);
            }
            rank_info.m_text = irr::core::stringw(str.c_str());
        }
        else
        {
            rank_info.m_text = "";
        }

        int numLaps = race_manager->getNumLaps();

        if(kart_info.m_race_lap>=numLaps)
        {  // kart is finished, display in green
            rank_info.m_color.setGreen(0);
            rank_info.m_color.setBlue(0);
        }
        else if(kart_info.m_race_lap>=0 && numLaps>1)
        {
            int col = (int)(255*(1.0f-(float)kart_info.m_race_lap
                                    /((float)numLaps-1.0f)        ));
            rank_info.m_color.setBlue(col);
            rank_info.m_color.setGreen(col);
        }
    }   // next kart


}   // getKartsDisplayInfo
/** 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