Esempio n. 1
0
//-----------------------------------------------------------------------------
void SoccerWorld::updateAIData()
{
    if (isRaceOver()) return;

    // Fill the kart distance map
    m_red_kdm.clear();
    m_blue_kdm.clear();

    for (unsigned int i = 0; i < m_karts.size(); ++i)
    {
        if (UserConfigParams::m_arena_ai_stats &&
            m_karts[i]->getController()->isPlayerController())
            continue;

        if (getKartTeam(m_karts[i]->getWorldKartId()) == SOCCER_TEAM_RED)
        {
            Vec3 rd = m_karts[i]->getXYZ() - getBallPosition();
            m_red_kdm.push_back(KartDistanceMap(i, rd.length_2d()));
        }
        else
        {
            Vec3 bd = m_karts[i]->getXYZ() - getBallPosition();
            m_blue_kdm.push_back(KartDistanceMap(i, bd.length_2d()));
        }
    }
    // Sort the vectors, so first vector will have the min distance
    std::sort(m_red_kdm.begin(), m_red_kdm.end());
    std::sort(m_blue_kdm.begin(), m_blue_kdm.end());

    // Fill Ball and goals data
    m_bgd.updateBallAndGoal(getBallPosition(), getBallHeading());

}   // updateAIData
Esempio n. 2
0
/** Localize the ball on the navigation mesh.
 */
void SoccerWorld::updateBallPosition(float dt)
{
    if (isRaceOver()) return;

    m_ball_position = m_ball->getPresentation<TrackObjectPresentationMesh>()
        ->getNode()->getPosition();

    if (m_track->hasNavMesh())
    {
        m_ball_on_node  = BattleGraph::get()->pointToNode(m_ball_on_node,
                          m_ball_position, true/*ignore_vertical*/);

        if (m_ball_on_node == BattleGraph::UNKNOWN_POLY &&
            World::getWorld()->getPhase() == RACE_PHASE)
        {
            m_ball_invalid_timer += dt;
            // Reset the ball and karts if out of navmesh after 2 seconds
            if (m_ball_invalid_timer >= 2.0f)
            {
                m_ball_invalid_timer = 0.0f;
                resetBall();
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
            }
        }
        else
            m_ball_invalid_timer = 0.0f;
    }

}   // updateBallPosition
/** Localize the ball on the navigation mesh.
 */
void SoccerWorld::updateBallPosition(int ticks)
{
    if (isRaceOver()) return;

    if (!ballNotMoving())
    {
        // Only update heading if the ball is moving
        m_ball_heading = atan2f(m_ball_body->getLinearVelocity().getX(),
            m_ball_body->getLinearVelocity().getZ());
    }

    if (Track::getCurrentTrack()->hasNavMesh())
    {
        m_ball_track_sector
            ->update(getBallPosition(), true/*ignore_vertical*/);
        if (!m_ball_track_sector->isOnRoad() && getPhase() == RACE_PHASE)
        {
            m_ball_invalid_timer += ticks;
            // Reset the ball and karts if out of navmesh after 2 seconds
            if (m_ball_invalid_timer >= stk_config->time2Ticks(2.0f))
            {
                m_ball_invalid_timer = 0;
                m_ball->reset();
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
                if (UserConfigParams::m_arena_ai_stats)
                    getKart(8)->flyUp();
            }
        }
        else
            m_ball_invalid_timer = 0;
    }

}   // updateBallPosition
//-----------------------------------------------------------------------------
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
    if (isRaceOver() || isStartPhase())
        return;

    setPhase(WorldStatus::GOAL_PHASE);
    m_goal_sound->play();
    if (m_ball_hitter != -1)
    {
        if (UserConfigParams::m_arena_ai_stats)
        {
            const int elapsed_frame = m_goal_frame.empty() ? 0 :
                std::accumulate(m_goal_frame.begin(), m_goal_frame.end(), 0);
            m_goal_frame.push_back(m_frame_count - elapsed_frame);
        }

        ScorerData sd;
        sd.m_id = m_ball_hitter;
        sd.m_correct_goal = isCorrectGoal(m_ball_hitter, first_goal);

        if (sd.m_correct_goal)
        {
            m_karts[m_ball_hitter]->getKartModel()
                ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/);
        }

        else if (!sd.m_correct_goal)
        {
            m_karts[m_ball_hitter]->getKartModel()
                ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/);
        }

        if (first_goal)
        {
            // Notice: true first_goal means it's blue goal being shoot,
            // so red team can score
            m_red_scorers.push_back(sd);
            if (race_manager->hasTimeTarget())
            {
                m_red_score_times.push_back(race_manager->getTimeTarget()
                    - getTime());
            }
            else
                m_red_score_times.push_back(getTime());
        }
        else
        {
            m_blue_scorers.push_back(sd);
            if (race_manager->hasTimeTarget())
            {
                m_blue_score_times.push_back(race_manager->getTimeTarget()
                    - getTime());
            }
            else
                m_blue_score_times.push_back(getTime());
        }
    }
    m_ball->reset();

}   // onCheckGoalTriggered
/** This is the main interface to update the world. This function calls
 *  update(), and checks then for the end of the race. Note that race over 
 *  handling can not necessarily be done in update(), since not all
 *  data structures might have been updated (e.g.LinearWorld must
 *  call World::update() first, to get updated kart positions. If race
 *  over would be handled in World::update, LinearWorld had no opportunity
 *  to update its data structures before the race is finished).
 *  \param dt Time step size.
 */
void World::updateWorld(float dt)
{
    if (m_schedule_pause)
    {
        pause(m_scheduled_pause_phase);
        m_schedule_pause = false;
    }
    else if (m_schedule_unpause)
    {
        unpause();
        m_schedule_unpause = false;
    }
    
    if (m_self_destruct)
    {
        delete this;
        return;
    }
    
    // Don't update world if a menu is shown or the race is over.
    if( getPhase() == FINISH_PHASE         ||
        getPhase() == IN_GAME_MENU_PHASE      )  
        return;

    update(dt);
    if( (!isFinishPhase()) && isRaceOver())
    {
        enterRaceOverState();
    }
}   // updateWorld
Esempio n. 6
0
//Método principal para atualização do game em tempo real
void Game::gameUpdate(){
	//Limite de Frame Rate
	gameWindow.setFramerateLimit(60);

	//Checa se algum dos players completou as 3 voltas
	isRaceOver();

	//Verifica se a tecla ESC é pressionada, abrindo o menuPause
	renderPause();
	if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
		menuPause.abrirMenu();

	//Toca a música que será reproduzida durante a corrida
	raceBGM.playMusic();
	raceBGM.setVolume(100);

	//Ativa os métodos de entrada de keyboard para os controles de ambos os players
	player[0].ativarMovimentos(0);
	player[1].ativarMovimentos(1);

	//Checa todas as colisões possíveis dentro da partida para cada Player
	checkCollision(0);
	checkCollision(1);

	//Checa se os players estão no sentido correto da pista (caso eles percorram ao contrário), seus
	//carros explodirão
	player[0].checarSentido();
	player[1].checarSentido();

	//Checa durante a partida quando a linha de chegada é ultrapassada
	checkLap();
	
	//Centralizando cada câmera em seu respectivo player
	player[0].centralizarCamera();
	player[1].centralizarCamera();

	//Renderizações na tela do Player1
	gameWindow.setView(player[0].getCamera());
	renderMap();
	gameWindow.draw(player[0].getSprite());
	gameWindow.draw(player[1].getSprite());
	renderProjeteis();
	renderGUI(0);
	
	//Renderizações na tela do Player 2
	gameWindow.setView(player[1].getCamera());
	renderMap();
	gameWindow.draw(player[1].getSprite());
	gameWindow.draw(player[0].getSprite());
	renderProjeteis();
	renderGUI(1);

	gameWindow.display();
	gameWindow.clear();
}
Esempio n. 7
0
//-----------------------------------------------------------------------------
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
    if (isRaceOver() || isStartPhase())
        return;

    setPhase(WorldStatus::GOAL_PHASE);
    m_goal_sound->play();
    if (m_ball_hitter != -1)
    {
        ScorerData sd;
        sd.m_id = m_ball_hitter;
        sd.m_correct_goal = isCorrectGoal(m_ball_hitter, first_goal);

        if (sd.m_correct_goal)
        {
            m_karts[m_ball_hitter]->getKartModel()
                ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/);
        }

        else if (!sd.m_correct_goal)
        {
            m_karts[m_ball_hitter]->getKartModel()
                ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/);
        }

        if (first_goal)
        {
            // Notice: true first_goal means it's blue goal being shoot,
            // so red team can score
            m_red_scorers.push_back(sd);
            if (race_manager->hasTimeTarget())
            {
                m_red_score_times.push_back(race_manager->getTimeTarget()
                    - getTime());
            }
            else
                m_red_score_times.push_back(getTime());
        }
        else
        {
            m_blue_scorers.push_back(sd);
            if (race_manager->hasTimeTarget())
            {
                m_blue_score_times.push_back(race_manager->getTimeTarget()
                    - getTime());
            }
            else
                m_blue_score_times.push_back(getTime());
        }
    }
    m_ball->reset();

}   // onCheckGoalTriggered
Esempio n. 8
0
/** Updates the m_kart_on_node value of each kart to localize it
 *  on the navigation mesh.
 */
void SoccerWorld::updateKartNodes()
{
    if (isRaceOver()) return;

    const unsigned int n = getNumKarts();
    for (unsigned int i = 0; i < n; i++)
    {
        if (m_karts[i]->isEliminated()) continue;

        m_kart_on_node[i] = BattleGraph::get()->pointToNode(m_kart_on_node[i],
                            m_karts[i]->getXYZ(), false/*ignore_vertical*/);
    }
}   // updateKartNodes
Esempio n. 9
0
/** Localize each kart on the graph using its center xyz.
 */
void WorldWithRank::updateSectorForKarts()
{
    if (isRaceOver()) return;

    const unsigned int n = getNumKarts();
    assert(n == m_kart_track_sector.size());
    for (unsigned int i = 0; i < n; i++)
    {
        SpareTireAI* sta =
            dynamic_cast<SpareTireAI*>(m_karts[i]->getController());
        if (!m_karts[i]->isEliminated() || (sta && sta->isMoving()))
            getTrackSector(i)->update(m_karts[i]->getXYZ());
    }
}   // updateSectorForKarts
Esempio n. 10
0
//-----------------------------------------------------------------------------
void SoccerWorld::updateDefenders()
{
    if (isRaceOver()) return;

    float distance = 99999.9f;
    int defender = -1;

    // Check for red team
    for (unsigned int i = 0; i < (unsigned)m_karts.size(); ++i)
    {
        if (m_karts[i]->getController()->isPlayerController() ||
            getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_RED)
            continue;

        Vec3 d = this->getGoalLocation(SOCCER_TEAM_RED,
            CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();

        if (d.length_2d() <= distance)
        {
            defender = i;
            distance = d.length_2d();
        }
    }
    if (defender != -1) m_red_defender = defender;

    distance = 99999.9f;
    defender = -1;

    // Check for blue team
    for (unsigned int i = 0; i < (unsigned)m_karts.size(); ++i)
    {
        if (m_karts[i]->getController()->isPlayerController() ||
            getKartTeam(m_karts[i]->getWorldKartId()) != SOCCER_TEAM_BLUE)
            continue;

        Vec3 d = this->getGoalLocation(SOCCER_TEAM_BLUE,
            CheckGoal::POINT_CENTER) - m_karts[i]->getXYZ();

        if (d.length_2d() <= distance)
        {
            defender = i;
            distance = d.length_2d();
        }
    }
    if (defender != -1) m_blue_defender = defender;

}   // updateDefenders
Esempio n. 11
0
/** Update the world and the track.
 *  \param dt Time step size.
 */
void SoccerWorld::update(float dt)
{
    updateBallPosition(dt);
    if (m_track->hasNavMesh())
    {
        updateKartNodes();
        updateAIData();
    }

    WorldWithRank::update(dt);
    WorldWithRank::updateTrack(dt);

    if (getPhase() == World::GOAL_PHASE)
    {
        if (m_goal_timer == 0.0f)
        {
            // Stop all karts
            for (unsigned int i = 0; i < m_karts.size(); i++)
                m_karts[i]->setVelocity(btVector3(0, 0, 0));
        }
        m_goal_timer += dt;

        if (m_goal_timer > 3.0f)
        {
            setPhase(WorldStatus::RACE_PHASE);
            m_goal_timer = 0.0f;
            if (!isRaceOver())
            {
                // Reset all karts
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
                if (UserConfigParams::m_arena_ai_stats)
                    getKart(8)->flyUp();
            }
        }
    }
    if (UserConfigParams::m_arena_ai_stats)
        m_frame_count++;

}   // update
/** Update the world and the track.
 *  \param ticks Physics time steps - should be 1.
 */
void SoccerWorld::update(int ticks)
{
    updateBallPosition(ticks);
    if (Track::getCurrentTrack()->hasNavMesh())
    {
        updateSectorForKarts();
        updateAIData();
    }

    WorldWithRank::update(ticks);
    WorldWithRank::updateTrack(ticks);

    if (getPhase() == World::GOAL_PHASE)
    {
        if (m_goal_timer == 0)
        {
            // Stop all karts
            for (unsigned int i = 0; i < m_karts.size(); i++)
                m_karts[i]->setVelocity(btVector3(0, 0, 0));
        }
        m_goal_timer += ticks;

        if (m_goal_timer > stk_config->time2Ticks(3.0f))
        {
            setPhase(WorldStatus::RACE_PHASE);
            m_goal_timer = 0;
            if (!isRaceOver())
            {
                // Reset all karts
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
                if (UserConfigParams::m_arena_ai_stats)
                    getKart(8)->flyUp();
            }
        }
    }
    if (UserConfigParams::m_arena_ai_stats)
        m_frame_count++;

}   // update
Esempio n. 13
0
/** Update the world and the track.
 *  \param dt Time step size.
 */
void SoccerWorld::update(float dt)
{
    World *world = World::getWorld();

    WorldWithRank::update(dt);
    WorldWithRank::updateTrack(dt);

    updateBallPosition(dt);
    if (m_track->hasNavMesh())
    {
        updateKartNodes();
        updateDefenders();
    }

    if (world->getPhase() == World::GOAL_PHASE)
    {
        if (m_goal_timer == 0.0f)
        {
            // Stop all karts
            for (unsigned int i = 0; i < m_karts.size(); i++)
                m_karts[i]->setVelocity(btVector3(0, 0, 0));
        }
        m_goal_timer += dt;

        if (m_goal_timer > 3.0f)
        {
            world->setPhase(WorldStatus::RACE_PHASE);
            m_goal_timer = 0.0f;
            if (!isRaceOver())
            {
                // Reset all karts
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
            }
        }
    }

}   // update
Esempio n. 14
0
/** Localize the ball on the navigation mesh.
 */
void SoccerWorld::updateBallPosition(float dt)
{
    if (isRaceOver()) return;

    if (!ballNotMoving())
    {
        // Only update heading if the ball is moving
        m_ball_heading = atan2f(m_ball_body->getLinearVelocity().getX(),
            m_ball_body->getLinearVelocity().getZ());
    }

    if (m_track->hasNavMesh())
    {
        m_ball_on_node  = BattleGraph::get()->pointToNode(m_ball_on_node,
                          getBallPosition(), true/*ignore_vertical*/);

        if (m_ball_on_node == BattleGraph::UNKNOWN_POLY &&
            getPhase() == RACE_PHASE)
        {
            m_ball_invalid_timer += dt;
            // Reset the ball and karts if out of navmesh after 2 seconds
            if (m_ball_invalid_timer >= 2.0f)
            {
                m_ball_invalid_timer = 0.0f;
                m_ball->reset();
                for (unsigned int i = 0; i < m_karts.size(); i++)
                    moveKartAfterRescue(m_karts[i]);
                if (UserConfigParams::m_arena_ai_stats)
                    getKart(8)->flyUp();
            }
        }
        else
            m_ball_invalid_timer = 0.0f;
    }

}   // updateBallPosition
Esempio n. 15
0
/** This is the main interface to update the world. This function calls
 *  update(), and checks then for the end of the race. Note that race over
 *  handling can not necessarily be done in update(), since not all
 *  data structures might have been updated (e.g.LinearWorld must
 *  call World::update() first, to get updated kart positions. If race
 *  over would be handled in World::update, LinearWorld had no opportunity
 *  to update its data structures before the race is finished).
 *  \param dt Time step size.
 */
void World::updateWorld(float dt)
{
#ifdef DEBUG
    assert(m_magic_number == 0xB01D6543);
#endif


    if (m_schedule_pause)
    {
        pause(m_scheduled_pause_phase);
        m_schedule_pause = false;
    }
    else if (m_schedule_unpause)
    {
        unpause();
        m_schedule_unpause = false;
    }

    if (m_self_destruct)
    {
        delete this;
        return;
    }

    // Don't update world if a menu is shown or the race is over.
    if( getPhase() == FINISH_PHASE         ||
        getPhase() == IN_GAME_MENU_PHASE      )
        return;

    try
    {
        update(dt);
    }
    catch (AbortWorldUpdateException& e)
    {
        (void)e;   // avoid compiler warning
        return;
    }

#ifdef DEBUG
    assert(m_magic_number == 0xB01D6543);
#endif

    if( (!isFinishPhase()) && isRaceOver())
    {
        enterRaceOverState();
    }
    else
    {
        if (m_schedule_exit_race)
        {
            m_schedule_exit_race = false;
            race_manager->exitRace(false);
            race_manager->setAIKartOverride("");

            StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());

            if (m_schedule_tutorial)
            {
                m_schedule_tutorial = false;
                race_manager->setNumLocalPlayers(1);
                race_manager->setMajorMode (RaceManager::MAJOR_MODE_SINGLE);
                race_manager->setMinorMode (RaceManager::MINOR_MODE_TUTORIAL);
                race_manager->setNumKarts( 1 );
                race_manager->setTrack( "tutorial" );
                race_manager->setDifficulty(RaceManager::DIFFICULTY_EASY);
                race_manager->setReverseTrack(false);

                // Use keyboard 0 by default (FIXME: let player choose?)
                InputDevice* device = input_manager->getDeviceManager()->getKeyboard(0);

                // Create player and associate player with keyboard
                StateManager::get()->createActivePlayer(PlayerManager::getCurrentPlayer(),
                                                        device);

                if (!kart_properties_manager->getKart(UserConfigParams::m_default_kart))
                {
                    Log::warn("[World]",
                              "Cannot find kart '%s', will revert to default.",
                              UserConfigParams::m_default_kart.c_str());
                    UserConfigParams::m_default_kart.revertToDefaults();
                }
                race_manager->setLocalKartInfo(0, UserConfigParams::m_default_kart);

                // ASSIGN should make sure that only input from assigned devices
                // is read.
                input_manager->getDeviceManager()->setAssignMode(ASSIGN);
                input_manager->getDeviceManager()
                    ->setSinglePlayer( StateManager::get()->getActivePlayer(0) );

                delete this;

                StateManager::get()->enterGameState();
                race_manager->setupPlayerKartInfo();
                race_manager->startNew(true);
            }
            else
            {
                delete this;

                if (race_manager->raceWasStartedFromOverworld())
                {
                    OverWorld::enterOverWorld();
                }

            }
        }
    }
}   // updateWorld
Esempio n. 16
0
//-----------------------------------------------------------------------------
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
    if (isRaceOver())
        return;

    if (m_can_score_points)
    {
        m_team_goals[first_goal ? 0 : 1]++;

        World *world = World::getWorld();
        world->setPhase(WorldStatus::GOAL_PHASE);
        m_goal_sound->play();
        if(m_lastKartToHitBall != -1)
        {
            if(first_goal)
            {
                m_redScorers.push_back(m_lastKartToHitBall);
                if(race_manager->hasTimeTarget())
                    m_redScoreTimes.push_back(race_manager->getTimeTarget() - world->getTime());
                else
                    m_redScoreTimes.push_back(world->getTime());
            }
            else
            {
                m_blueScorers.push_back(m_lastKartToHitBall);
                if(race_manager->hasTimeTarget())
                    m_blueScoreTimes.push_back(race_manager->getTimeTarget() - world->getTime());
                else
                    m_blueScoreTimes.push_back(world->getTime());
            }
        }
    }

    // Reset original positions for the soccer balls
    TrackObjectManager* tom = getTrack()->getTrackObjectManager();
    assert(tom);

    PtrVector<TrackObject>& objects = tom->getObjects();
    for(unsigned int i=0; i<objects.size(); i++)
    {
        TrackObject* obj = objects.get(i);
        if(!obj->isSoccerBall())
            continue;

        obj->reset();
        obj->getPhysicalObject()->reset();
    }

    //Resetting the ball triggers the goal check line one more time.
    //This ensures that only one goal is counted, and the second is ignored.
    m_can_score_points = !m_can_score_points;

    //for(int i=0 ; i < getNumKarts() ; i++

    /*if(World::getWorld()->getTrack()->isAutoRescueEnabled() &&
        !getKartAnimation() && fabs(getRoll())>60*DEGREE_TO_RAD &&
                              fabs(getSpeed())<3.0f                )
    {
        new RescueAnimation(this, true);
    }*/

    // TODO: rescue the karts
}   // onCheckGoalTriggered
Esempio n. 17
0
//-----------------------------------------------------------------------------
void SoccerWorld::onCheckGoalTriggered(bool first_goal)
{
    if (isRaceOver() || isStartPhase())
        return;

    if (m_can_score_points)
    {
        (first_goal ? m_red_goal++ : m_blue_goal++);

        World *world = World::getWorld();
        world->setPhase(WorldStatus::GOAL_PHASE);
        m_goal_sound->play();
        if (m_ball_hitter != -1)
        {
            ScorerData sd;
            sd.m_id = m_ball_hitter;
            sd.m_correct_goal = isCorrectGoal(m_ball_hitter, first_goal);

            if (sd.m_correct_goal)
            {
                m_karts[m_ball_hitter]->getKartModel()
                    ->setAnimation(KartModel::AF_WIN_START, true/* play_non_loop*/);
            }

            else if (!sd.m_correct_goal)
            {
                m_karts[m_ball_hitter]->getKartModel()
                    ->setAnimation(KartModel::AF_LOSE_START, true/* play_non_loop*/);
            }

            if (first_goal)
            {
                // Notice: true first_goal means it's blue goal being shoot,
                // so red team can score
                m_red_scorers.push_back(sd);
                if(race_manager->hasTimeTarget())
                {
                    m_red_score_times.push_back(race_manager
                        ->getTimeTarget() - world->getTime());
                }
                else
                    m_red_score_times.push_back(world->getTime());
            }
            else
            {
                m_blue_scorers.push_back(sd);
                if (race_manager->hasTimeTarget())
                {
                    m_blue_score_times.push_back(race_manager
                        ->getTimeTarget() - world->getTime());
                }
                else
                    m_blue_score_times.push_back(world->getTime());
            }
        }
    }

    resetBall();
    //Resetting the ball triggers the goal check line one more time.
    //This ensures that only one goal is counted, and the second is ignored.
    m_can_score_points = !m_can_score_points;

}   // onCheckGoalTriggered
Esempio n. 18
0
/** 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