示例#1
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
示例#2
0
/** Updates all status information, called once per frame.
 *  \param dt Duration of time step.
 */
void WorldStatus::update(const float dt)
{
    switch(m_phase)
    {
        // Note: setup phase must be a separate phase, since the race_manager
        // checks the phase when updating the camera: in the very first time
        // step dt is large (it includes loading time), so the camera might
        // tilt way too much. A separate setup phase for the first frame
        // simplifies this handling
        case SETUP_PHASE:
            m_auxiliary_timer = 0.0f;  
            m_phase = TRACK_INTRO_PHASE;
            if (UserConfigParams::m_music && m_play_racestart_sounds)
            {
                m_track_intro_sound->play();
            }
            return;
        case TRACK_INTRO_PHASE:
            m_auxiliary_timer += dt;
            // Work around a bug that occurred on linux once:
            // the sfx_manager kept on reporting that it is playing,
            // while it was not - so STK would never reach the ready
            // ... phase. Since the sound effect is about 3 seconds
            // long, we use the aux timer to force the next phase
            // after 3.5 seconds.
            if(m_track_intro_sound->getStatus()==SFXManager::SFX_PLAYING
	            && m_auxiliary_timer<3.5f)
                return;
            m_auxiliary_timer = 0.0f;
            if (m_play_racestart_sounds) m_prestart_sound->play();
            m_phase = READY_PHASE;
            for(unsigned int i=0; i<World::getWorld()->getNumKarts(); i++)
                World::getWorld()->getKart(i)->startEngineSFX();

            break;
        case READY_PHASE:
            if(m_auxiliary_timer>1.0)
            {
                if (m_play_racestart_sounds) m_prestart_sound->play();
                m_phase=SET_PHASE;   
            }
            m_auxiliary_timer += dt;
            
            // In artist debug mode, when without opponents, skip the ready/set/go counter faster
            if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1)
                m_auxiliary_timer += dt*6;
            return;
        case SET_PHASE  :
            if(m_auxiliary_timer>2.0) 
            {
                // set phase is over, go to the next one
                m_phase=GO_PHASE;  
                if (m_play_racestart_sounds) m_start_sound->play();
                
                World::getWorld()->getTrack()->startMusic();
                
                // event
                onGo();
            }
            m_auxiliary_timer += dt;
            
            // In artist debug mode, when without opponents, skip the ready/set/go counter faster
            if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1)
                m_auxiliary_timer += dt*6;
            return;
        case GO_PHASE  :
            
            if (m_auxiliary_timer>2.5f && music_manager->getCurrentMusic())
                music_manager->startMusic(music_manager->getCurrentMusic());
            
            if(m_auxiliary_timer>3.0f)    // how long to display the 'go' message  
            {
                m_phase=MUSIC_PHASE;
            }
            
            m_auxiliary_timer += dt;
            
            // In artist debug mode, when without opponents, skip the ready/set/go counter faster
            if (UserConfigParams::m_artist_debug_mode && race_manager->getNumberOfKarts() == 1)
                m_auxiliary_timer += dt*6;
            break;
        case MUSIC_PHASE:
            // how long to display the 'music' message
            if(m_auxiliary_timer>stk_config->m_music_credit_time)
                m_phase=RACE_PHASE;  
            m_auxiliary_timer += dt;
            break;
        case RACE_PHASE:
            // Nothing to do for race phase, switch to delay finish phase
            // happens when 
            break;
        case DELAY_FINISH_PHASE :
        {
            m_auxiliary_timer += dt;
            
            // Change to next phase if delay is over
            if(m_auxiliary_timer > stk_config->m_delay_finish_time)
            {
                m_phase = RESULT_DISPLAY_PHASE;
                terminateRace();
            }
            break;
        }
        case RESULT_DISPLAY_PHASE : 
            {
                // Wait for the race over GUI/modal dialog to appear
                // Previously the in race race over results are shown,
                // and getCurrent() returns NULL.
                RaceOverDialog *m = 
                    dynamic_cast<RaceOverDialog*>(GUIEngine::ModalDialog
                                                          ::getCurrent());
                if( m && m->menuIsFinished() )
                {
                    m_phase = FINISH_PHASE;
                }
            break;
            }
        case FINISH_PHASE:
            // Nothing to do here.
            break;
        default: break;
    }
    
    switch(m_clock_mode)
    {
        case CLOCK_CHRONO:
            m_time += dt;
            break;
        case CLOCK_COUNTDOWN:
            // stop countdown when race is over
            if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE)
            {
                m_time = 0.0f;
                break;
            }
            
            m_time -= dt;
            
            if(m_time <= 0.0)
            {
                // event
                countdownReachedZero();
            }
                
            break;
        default: break;
    }
}   // update
示例#3
0
/** Updates the world time and clock (which might be running backwards), and
 *  all status information, called once per frame at the end of the main
 *  loop.
 *  \param ticks Number of ticks (physics time steps) - should be 1.
 */
void WorldStatus::updateTime(int ticks)
{
    switch (m_phase.load())
    {
        // Note: setup phase must be a separate phase, since the race_manager
        // checks the phase when updating the camera: in the very first time
        // step dt is large (it includes loading time), so the camera might
        // tilt way too much. A separate setup phase for the first frame
        // simplifies this handling
        case SETUP_PHASE:
            m_auxiliary_ticks= 0;
            m_phase = TRACK_INTRO_PHASE;
            
            if (m_play_track_intro_sound)
            {
                m_track_intro_sound->play();
            }

            if (Weather::getInstance())
            {
                Weather::getInstance()->playSound();
            }

            return;   // Do not increase time
        case TRACK_INTRO_PHASE:
            m_auxiliary_ticks++;

            if (UserConfigParams::m_artist_debug_mode &&
                !NetworkConfig::get()->isNetworking() &&
                race_manager->getNumberOfKarts() -
                race_manager->getNumSpareTireKarts() == 1 &&
                race_manager->getTrackName() != "tutorial")
            {
                m_auxiliary_ticks += 6;
            }

            if (!m_play_track_intro_sound)
            {
                startEngines();
            }

            // Wait before ready phase
            if (m_auxiliary_ticks < stk_config->time2Ticks(3.0f))
                return;

            m_auxiliary_ticks = 0;

            // In a networked game the client needs to wait for a notification
            // from the server that all clients and the server are ready to 
            // start the game. The server will actually wait for all clients
            // to confirm that they have started the race before starting
            // itself. In a normal race, this phase is skipped and the race
            // starts immediately.
            if (NetworkConfig::get()->isNetworking())
            {
                m_phase = WAIT_FOR_SERVER_PHASE;
                // In networked races, inform the start game protocol that
                // the world has been setup
                if (!m_live_join_world)
                {
                    auto lobby = LobbyProtocol::get<LobbyProtocol>();
                    assert(lobby);
                    lobby->finishedLoadingWorld();
                }
            }
            else
            {
                if (m_play_ready_set_go_sounds)
                    m_prestart_sound->play();
                m_phase = READY_PHASE;
            }
            return;   // Don't increase time
        case WAIT_FOR_SERVER_PHASE:
        {
            if (m_live_join_world)
            {
                m_auxiliary_ticks++;
                // Add 3 seconds delay before telling server finish loading
                // world, so previous (if any) disconnected player has left
                // fully
                if (m_auxiliary_ticks == stk_config->time2Ticks(3.0f))
                {
                    auto cl = LobbyProtocol::get<ClientLobby>();
                    assert(cl);
                    cl->finishedLoadingWorld();
#ifndef ANDROID
                    static bool helper_msg_shown = false;
                    if (!helper_msg_shown && cl->isSpectator())
                    {
                        helper_msg_shown = true;
                        cl->addSpectateHelperMessage();
                    }
#endif
                }
                return;
            }
            return;   // Don't increase time
        }
        case SERVER_READY_PHASE:
        {
            auto lobby = LobbyProtocol::get<LobbyProtocol>();
            if (lobby && lobby->isRacing())
            {
                if (m_play_ready_set_go_sounds)
                    m_prestart_sound->play();
                m_phase = READY_PHASE;
            }
            return;   // Don't increase time
        }
        case READY_PHASE:
            startEngines();
            // One second
            if (m_auxiliary_ticks > stk_config->getPhysicsFPS())
            {
                if (m_play_ready_set_go_sounds)
                {
                    m_prestart_sound->play();
                }

                m_phase = SET_PHASE;
            }

            m_auxiliary_ticks++;

            // In artist debug mode, when without opponents, skip the
            // ready/set/go counter faster
            if (UserConfigParams::m_artist_debug_mode     &&
                !NetworkConfig::get()->isNetworking()     &&
                race_manager->getNumberOfKarts() -
                race_manager->getNumSpareTireKarts() == 1 &&
                race_manager->getTrackName() != "tutorial")
            {
                m_auxiliary_ticks += 6;
            }

            return;   // Do not increase time
        case SET_PHASE:
            if (m_auxiliary_ticks > 2*stk_config->getPhysicsFPS())
            {
                // set phase is over, go to the next one
                m_phase = GO_PHASE;
                if (m_play_ready_set_go_sounds)
                {
                    m_start_sound->play();
                }

                // event
                onGo();
                // In artist debug mode, when without opponents,
                // skip the ready/set/go counter faster
                m_start_music_ticks =
                    UserConfigParams::m_artist_debug_mode &&
                    !NetworkConfig::get()->isNetworking()     &&
                    race_manager->getNumberOfKarts() -
                    race_manager->getNumSpareTireKarts() == 1 &&
                    race_manager->getTrackName() != "tutorial" ?
                    stk_config->time2Ticks(0.2f) :
                    stk_config->time2Ticks(1.0f);
                // how long to display the 'music' message
                // no graphics mode goes race phase at 3 seconds;
                m_race_ticks = ProfileWorld::isNoGraphics() ?
                    stk_config->time2Ticks(3.0f) :
                    stk_config->time2Ticks(stk_config->m_music_credit_time);
            }

            m_auxiliary_ticks++;

            // In artist debug mode, when without opponents, 
            // skip the ready/set/go counter faster
            if (UserConfigParams::m_artist_debug_mode &&
                !NetworkConfig::get()->isNetworking() &&
                race_manager->getNumberOfKarts() -
                race_manager->getNumSpareTireKarts() == 1 &&
                race_manager->getTrackName() != "tutorial")
            {
                m_auxiliary_ticks += 6;
            }

            return;   // Do not increase time
        case GO_PHASE:
        {
            if (m_start_music_ticks != -1 &&
                m_count_up_ticks >= m_start_music_ticks)
            {
                m_start_music_ticks = -1;
                if (music_manager->getCurrentMusic() &&
                    !music_manager->getCurrentMusic()->isPlaying())
                {
                    music_manager->startMusic();
                }
                m_phase = MUSIC_PHASE;
            }
            break;   // Now the world time starts
        }
        case MUSIC_PHASE:
        {
            // Start the music here when starting fast
            if (UserConfigParams::m_race_now)
            {
                music_manager->startMusic();
                UserConfigParams::m_race_now = false;
            }
            if (m_race_ticks != -1 && m_count_up_ticks >= m_race_ticks)
            {
                m_race_ticks = -1;
                m_phase = RACE_PHASE;
            }
            break;
        }
        case RACE_PHASE:
            // Nothing to do for race phase, switch to delay finish phase
            // happens when
            break;
        case DELAY_FINISH_PHASE:
        {
            m_auxiliary_ticks++;

            // Change to next phase if delay is over
            if (m_auxiliary_ticks >
                stk_config->time2Ticks(stk_config->m_delay_finish_time))
            {
                m_phase = RESULT_DISPLAY_PHASE;
                terminateRace();
            }

            break;
        }
        case RESULT_DISPLAY_PHASE:
        {
            break;
        }
        case FINISH_PHASE:
        case IN_GAME_MENU_PHASE:
            // Nothing to do here.
            break;
        case GOAL_PHASE:
            // Nothing to do here as well.
            break;

        default: break;
    }

    IrrlichtDevice *device = irr_driver->getDevice();
    
    switch (m_clock_mode)
    {
        case CLOCK_CHRONO:
            if (!device->getTimer()->isStopped())
            {
                m_time_ticks++;
                m_time  = stk_config->ticks2Time(m_time_ticks);
                m_count_up_ticks++;
            }
            break;
        case CLOCK_COUNTDOWN:
            // stop countdown when race is over
            if (m_phase == RESULT_DISPLAY_PHASE || m_phase == FINISH_PHASE)
            {
                m_time_ticks = 0;
                m_time = 0.0f;
                m_count_up_ticks = 0;
                break;
            }

            if (!device->getTimer()->isStopped())
            {
                m_time_ticks--;
                m_time = stk_config->ticks2Time(m_time_ticks);
                m_count_up_ticks++;
            }

            if (m_time_ticks <= 0)
            {
                // event
                countdownReachedZero();
            }

            break;
        default: break;
    }   // switch m_phase

}   // update