/** 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;
    updateHighscores(&best_highscore_rank, &best_finish_time, &highscore_who, 
                     &best_player);
    
    unlock_manager->getCurrentSlot()->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();
    }
    
    StateManager::get()->pushScreen(results);
    WorldStatus::terminateRace();
}   // terminateRace
Esempio n. 2
0
/** Ends the race early and places still active player karts at the back.
 *  The race immediately goes to the result stage, estimating the time for the
 *  karts still in the race. Still active player karts get a penalty in time
 *  as well as being placed at the back. Players that already finished keep
 *  their position.
 *
 *  End time for the punished players is calculated as follows
 *  end_time = current_time + (estimated_time - current_time)
 *                          + (estimated_time_for_last - current_time)
 *           = estimated_time + estimated_time_for_last - current_time
 *  This will put them at the end at all times. The further you (and the last in
 *  the race) are from the finish line, the harsher the punishment will be.
 */
void StandardRace::endRaceEarly()
{
    const unsigned int kart_amount = (unsigned int)m_karts.size();
    std::vector<int> active_players;
    // Required for debugging purposes
    beginSetKartPositions();
    for (unsigned int i = 1; i <= kart_amount; i++)
    {
        int kartid = m_position_index[i-1];
        AbstractKart* kart = m_karts[kartid];
        if (kart->hasFinishedRace())
        {
            // Have to do this to keep endSetKartPosition happy
            setKartPosition(kartid, kart->getPosition());
            continue;
        }

        if (kart->getController()->isPlayerController())
        {
            // Keep active players apart for now
            active_players.push_back(kartid);
        }
        else
        {
            // AI karts finish
            setKartPosition(kartid, i - (unsigned int) active_players.size());
            kart->finishedRace(estimateFinishTimeForKart(kart));
        }
    } // i <= kart_amount
    // Now make the active players finish
    for (unsigned int i = 0; i < active_players.size(); i++)
    {
        int kartid = active_players[i];
        int position = getNumKarts() - (int) active_players.size() + 1 + i;
        setKartPosition(kartid, position);
        m_karts[kartid]->eliminate();
    } // Finish the active players
    endSetKartPositions();
    setPhase(RESULT_DISPLAY_PHASE);
    if (!isNetworkWorld() || NetworkConfig::get()->isServer())
        terminateRace();
} // endRaceEarly
Esempio n. 3
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
Esempio n. 4
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
Esempio n. 5
0
/** This function is called when the race is finished, but end-of-race
 *  animations have still to be played. In the case of profiling,
 *  we can just abort here without waiting for the animations.
 */
void ProfileWorld::enterRaceOverState()
{
    // If in timing mode, the number of laps is way too high (which avoids
    // aborting too early). So in this case determine the maximum number
    // of laps and set this +1 as the number of laps to get more meaningful
    // time estimations.
    if(m_profile_mode==PROFILE_TIME)
    {
        int max_laps = -2;
        for(unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
        {
            if(m_kart_info[i].m_race_lap>max_laps)
                max_laps = m_kart_info[i].m_race_lap;
        }   // for i<getNumberOfKarts
        race_manager->setNumLaps(max_laps+1);
    }

    StandardRace::enterRaceOverState();
    // Estimate finish time and set all karts to be finished.
    for (unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
    {
        // ---------- update rank ------
        if (m_karts[i]->hasFinishedRace() || m_karts[i]->isEliminated())
            continue;
        m_karts[i]->finishedRace(estimateFinishTimeForKart(m_karts[i]));
    }

    // Print framerate statistics
    float runtime = (irr_driver->getRealTime()-m_start_time)*0.001f;
    Log::verbose("profile", "Number of frames: %d time %f, Average FPS: %f",
                 m_frame_count, runtime, (float)m_frame_count/runtime);

    // Print geometry statistics if we're not in no-graphics mode
    if(!m_no_graphics)
    {
        Log::verbose("profile", "Average # drawn nodes           %f k",
                     (float)m_num_triangles/m_frame_count);
        Log::verbose("profile", "Average # culled nodes:         %f k",
                     (float)m_num_culls/m_frame_count);
        Log::verbose("profile", "Average # solid nodes:          %f k",
                     (float)m_num_solid/m_frame_count);
        Log::verbose("profile", "Average # transparent nodes:    %f",
                     (float)m_num_transparent/m_frame_count);
        Log::verbose("profile", "Average # transp. effect nodes: %f",
                     (float)m_num_trans_effect/m_frame_count);
    }

    // Print race statistics for each individual kart
    float min_t=999999.9f, max_t=0.0, av_t=0.0;
    Log::verbose("profile", "name start_position end_position time average_speed top_speed "
           "skid_time rescue_time rescue_count brake_count "
           "explosion_time explosion_count bonus_count banana_count "
           "small_nitro_count large_nitro_count bubblegum_count");

    std::set<std::string> all_groups;

    for ( KartList::size_type i = 0; i < m_karts.size(); ++i)
    {
        KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);

        max_t = std::max(max_t, kart->getFinishTime());
        min_t = std::min(min_t, kart->getFinishTime());
        av_t += kart->getFinishTime();
        std::ostringstream ss;
        ss << kart->getIdent() << " "
           << kart->getController()->getControllerName() << " ";
        ss << 1+(int)i << " " << kart->getPosition() << " "
           << kart->getFinishTime() << " ";

        all_groups.insert(kart->getController()->getControllerName());
        float distance = (float)(m_profile_mode==PROFILE_LAPS
                                 ? race_manager->getNumLaps() : 1);
        distance *= m_track->getTrackLength();
        ss << distance/kart->getFinishTime() << " " << kart->getTopSpeed() << " ";
        ss << kart->getSkiddingTime() << " " << kart->getRescueTime() << " ";
        ss << kart->getRescueCount() << " " << kart->getBrakeCount() << " ";
        ss << kart->getExplosionTime() << " " << kart->getExplosionCount() << " ";
        ss << kart->getBonusCount() << " " << kart->getBananaCount() << " ";
        ss << kart->getSmallNitroCount() << " " << kart->getLargeNitroCount() << " ";
        ss << kart->getBubblegumCount() << " " << kart->getOffTrackCount() << " ";
        Log::verbose("profile", ss.str().c_str());
    }

    // Print group statistics of all karts
    Log::verbose("profile", "min %f  max %f  av %f\n",
                  min_t, max_t, av_t/m_karts.size());

    // Determine maximum length of group name
    unsigned int max_len=4;   // for 'name' heading
    for(std::set<std::string>::iterator it = all_groups.begin();
        it !=all_groups.end(); it++)
    {
        if(it->size()>max_len) max_len = (unsigned int) it->size();
    }
    max_len++;  // increase by 1 for one additional space after the name

    std::ostringstream ss;
    Log::verbose("profile", "");
    ss << "name" << std::setw(max_len-4) << " "
       << "Strt End  Time    AvSp  Top   Skid  Resc Rsc Brake Expl Exp Itm Ban SNitLNit Bub  Off";
    Log::verbose("profile", ss.str().c_str());
    for(std::set<std::string>::iterator it = all_groups.begin();
        it !=all_groups.end(); it++)
    {
        int   count         = 0,    position_gain   = 0,    rescue_count = 0;
        int   brake_count   = 0,    bonus_count     = 0,    banana_count = 0;
        int   l_nitro_count = 0,    s_nitro_count   = 0,    bubble_count = 0;
        int   expl_count    = 0,    off_track_count = 0;
        float skidding_time = 0.0f, rescue_time     = 0.0f, expl_time    = 0.0f;
        float av_time       = 0.0f;
        for ( unsigned int i = 0; i < (unsigned int)m_karts.size(); ++i)
        {
            KartWithStats* kart = dynamic_cast<KartWithStats*>(m_karts[i]);
            const std::string &name=kart->getController()->getControllerName();
            if(name!=*it)
                continue;
            count ++;
            std::ostringstream ss;
            ss.setf(std::ios::fixed, std::ios::floatfield);
            ss.precision(2);
            ss << name << std::setw(max_len-name.size()) << " ";
            ss << std::setw(4) <<  1 + i
               << std::setw(4) << kart->getPosition()
               << std::setw(7) << kart->getFinishTime();
            position_gain += 1+i - kart->getPosition();

            float distance = (float)(m_profile_mode==PROFILE_LAPS
                                     ? race_manager->getNumLaps() : 1);
            distance *= m_track->getTrackLength();

            Log::verbose("profile",
                   "%s %4.2f %3.2f %6.2f %4.2f %3d %5d %4.2f %3d %3d %3d %3d %3d %3d %5d",
                   ss.str().c_str(), distance/kart->getFinishTime(),
                   kart->getTopSpeed(),
                   kart->getSkiddingTime(),        kart->getRescueTime(),
                   kart->getRescueCount(),         kart->getBrakeCount(),
                   kart->getExplosionTime(),       kart->getExplosionCount(),
                   kart->getBonusCount(),          kart->getBananaCount(),
                   kart->getSmallNitroCount(),     kart->getLargeNitroCount(),
                   kart->getBubblegumCount(),      kart->getOffTrackCount()
                   );
            Log::verbose("profile", "nitro %f\n", kart->getEnergy());
            av_time += kart->getFinishTime();
            skidding_time   += kart->getSkiddingTime();
            rescue_time     += kart->getRescueTime();
            rescue_count    += kart->getRescueCount();
            brake_count     += kart->getBrakeCount();
            bonus_count     += kart->getBonusCount();
            banana_count    += kart->getBananaCount();
            l_nitro_count   += kart->getLargeNitroCount();
            s_nitro_count   += kart->getSmallNitroCount();
            bubble_count    += kart->getBubblegumCount();
            expl_time       += kart->getExplosionTime();
            expl_count      += kart->getExplosionCount();
            off_track_count += kart->getOffTrackCount();
        }    // for i < m_karts.size

        Log::verbose("profile", std::string(max_len+85, '-').c_str());
        ss.clear();
        ss.str("");
        ss << *it << std::string(max_len-it->size(),' ');
        ss << std::showpos << std::setw(4) << position_gain
           << std::noshowpos << std::setw(13) << av_time/count
           << std::string(11,' ');

        Log::verbose("profile", "%s%6.2f %4.2f %3d %5d %4.2f %3d %3d %3d %3d %3d %3d %5d",
               ss.str().c_str(), skidding_time/count, rescue_time/count,
               rescue_count,brake_count, expl_time, expl_count, bonus_count,
               banana_count, s_nitro_count, l_nitro_count, bubble_count,
               off_track_count);
        Log::verbose("profile", "");
    }   // for it !=all_groups.end
    delete this;
    main_loop->abort();
}   // enterRaceOverState
Esempio n. 6
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