Beispiel #1
0
/** Sets the kart position and controls to the recorded history value.
 *  \param dt Time step size.
 */
void History::updateReplay(float dt)
{
    m_current++;
    if(m_current>=(int)m_all_deltas.size())
    {
        printf("Replay finished.\n");
        exit(2);
    }
    World *world = World::getWorld();
    unsigned int num_karts = world->getNumKarts();
    for(unsigned k=0; k<num_karts; k++)
    {
        Kart *kart = world->getKart(k);
        unsigned int index=m_current*num_karts+k;
        if(m_replay_mode==HISTORY_POSITION)
        {
            kart->setXYZ(m_all_xyz[index]);
            kart->setRotation(m_all_rotations[index]);
        }
        else
        {
            kart->setControls(m_all_controls[index]);
        }
    }
}   // updateReplay
Beispiel #2
0
/** Determine the nearest kart or item and update the current target 
 *  accordingly.
 */
void Swatter::chooseTarget()
{
    // TODO: for the moment, only handle karts...
    const World *world         = World::getWorld();
    Kart        *closest_kart  = NULL;
    float       min_dist2      = FLT_MAX;

    for(unsigned int i=0; i<world->getNumKarts(); i++)
    {
        Kart *kart = world->getKart(i);
        // TODO: isSwatterReady(), isSquashable()?
        if(kart->isEliminated() || kart==m_kart)
            continue;
        // don't squash an already hurt kart
        if (kart->isInvulnerable() || kart->isSquashed())
            continue;
        
        float dist2 = (kart->getXYZ()-m_kart->getXYZ()).length2();
        if(dist2<min_dist2)
        {
            min_dist2 = dist2;
            closest_kart = kart;
        }
    }
    m_target = closest_kart;    // may be NULL
}
Beispiel #3
0
/** Actually sets the camera based on the given parameter.
 *  \param above_kart How far above the camera should aim at.
 *  \param cam_angle  Angle above the kart plane for the camera.
 *  \param sideway Sideway movement of the camera.
 *  \param distance Distance from kart.
*/
void Camera::positionCamera(float dt, float above_kart, float cam_angle,
                           float side_way, float distance, float smoothing)
{
    Vec3 wanted_position;
    Vec3 wanted_target = m_kart->getXYZ();
    if(UserConfigParams::m_camera_debug==2)
        wanted_target.setY(m_kart->getVehicle()->getWheelInfo(2).m_raycastInfo.m_contactPointWS.getY());
    else
        wanted_target.setY(wanted_target.getY()+above_kart);
    float tan_up = tan(cam_angle);
    Vec3 relative_position(side_way,
                           fabsf(distance)*tan_up+above_kart,
                           distance);
    btTransform t=m_kart->getTrans();
    if(stk_config->m_camera_follow_skid &&
        m_kart->getSkidding()->getVisualSkidRotation()!=0)
    {
        // If the camera should follow the graphical skid, add the
        // visual rotation to the relative vector:
        btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0);
        t.setBasis(t.getBasis() * btMatrix3x3(q));
    }
    wanted_position = t(relative_position);

    if (smoothing)
    {
        smoothMoveCamera(dt, wanted_position, wanted_target);
    }
    else
    {
        if (m_mode!=CM_FALLING)
            m_camera->setPosition(wanted_position.toIrrVector());
        m_camera->setTarget(wanted_target.toIrrVector());

        if (race_manager->getNumLocalPlayers() < 2)
        {
            sfx_manager->positionListener(m_camera->getPosition(),
                                      wanted_target - m_camera->getPosition());
        }
    }

    Kart *kart = dynamic_cast<Kart*>(m_kart);
    if (kart && !kart->isFlying())
    {
        // Rotate the up vector (0,1,0) by the rotation ... which is just column 1
        Vec3 up = m_kart->getTrans().getBasis().getColumn(1);
        float f = 0.04f;  // weight for new up vector to reduce shaking
        f = 0;
        m_camera->setUpVector(f      * up.toIrrVector() +
            (1.0f - f) * m_camera->getUpVector());
    }   // kart && !flying
    else
        m_camera->setUpVector(core::vector3df(0, 1, 0));
}   // positionCamera
/** Activates the next debug mode, or switches the mode off again.
 */
void IrrDebugDrawer::nextDebugMode()
{
    // Go to next debug mode. Note that debug mode 3 (
    m_debug_mode = (DebugModeType) ((m_debug_mode+1) % 3);
    World *world = World::getWorld();
    unsigned int num_karts = world->getNumKarts();
    for(unsigned int i=0; i<num_karts; i++)
    {
        Kart *kart = world->getKart(i);
        if(kart->isEliminated()) continue;
        kart->getNode()->setVisible(!(m_debug_mode & DM_NO_KARTS_GRAPHICS));
    }
}   // nextDebugMode
Beispiel #5
0
/** Actually sets the camera based on the given parameter.
 *  \param above_kart How far above the camera should aim at.
 *  \param cam_angle  Angle above the kart plane for the camera.
 *  \param sideway Sideway movement of the camera.
 *  \param distance Distance from kart.
*/
void CameraDebug::positionCamera(float dt, float above_kart, float cam_angle,
                                 float side_way, float distance              )
{
    Vec3 wanted_position;
    Vec3 wanted_target = m_kart->getXYZ();
    if(m_default_debug_Type==CM_DEBUG_GROUND)
    {
        const btWheelInfo &w = m_kart->getVehicle()->getWheelInfo(2);
        wanted_target.setY(w.m_raycastInfo.m_contactPointWS.getY());
    }
    else
        wanted_target.setY(wanted_target.getY()+above_kart);
    float tan_up = tan(cam_angle);
    Vec3 relative_position(side_way,
                           fabsf(distance)*tan_up+above_kart,
                           distance);
    btTransform t=m_kart->getTrans();
    if(stk_config->m_camera_follow_skid &&
        m_kart->getSkidding()->getVisualSkidRotation()!=0)
    {
        // If the camera should follow the graphical skid, add the
        // visual rotation to the relative vector:
        btQuaternion q(m_kart->getSkidding()->getVisualSkidRotation(), 0, 0);
        t.setBasis(t.getBasis() * btMatrix3x3(q));
    }
    if (m_default_debug_Type == CM_DEBUG_GROUND)
    {
        wanted_position = t(relative_position);
        // Make sure that the Y position is a the same height as the wheel.
        wanted_position.setY(wanted_target.getY());
    }
    else
        wanted_position = t(relative_position);

    if (getMode() != CM_FALLING)
        m_camera->setPosition(wanted_position.toIrrVector());
    m_camera->setTarget(wanted_target.toIrrVector());

    Kart *kart = dynamic_cast<Kart*>(m_kart);
    if (kart && !kart->isFlying())
    {
        // Rotate the up vector (0,1,0) by the rotation ... which is just column 1
        Vec3 up = m_kart->getTrans().getBasis().getColumn(1);
        float f = 0.04f;  // weight for new up vector to reduce shaking
        m_camera->setUpVector(        f  * up.toIrrVector() +
                              (1.0f - f) * m_camera->getUpVector());
    }   // kart && !flying
    else
        m_camera->setUpVector(core::vector3df(0, 1, 0));
}   // positionCamera
// ----------------------------------------------------------------------------
KartUpdateMessage::KartUpdateMessage(ENetPacket* pkt)
                  : Message(pkt, MT_KART_INFO)
{
    World *world = World::getWorld();
    unsigned int num_karts = getInt();
    for(unsigned int i=0; i<num_karts; i++)
    {
        // Currently not used
        KartControl kc(this);
        Vec3 xyz = getVec3();
        btQuaternion q = getQuaternion();
        Kart *kart = world->getKart(i);
        kart->setXYZ(xyz);
        kart->setRotation(q);
    }   // for i
};   // KartUpdateMessage
/** Checks if the kart was overtaken, and if so plays a sound
*/
void PlayerController::setPosition(int p)
{
    if(m_kart->getPosition()<p)
    {
        World *world = World::getWorld();
        //have the kart that did the passing beep.
        //I'm not sure if this method of finding the passing kart is fail-safe.
        for(unsigned int i = 0 ; i < world->getNumKarts(); i++ )
        {
            Kart *kart = world->getKart(i);
            if(kart->getPosition() == p + 1)
            {
                kart->beep();
                break;
            }
        }
    }
}   // setPosition
Beispiel #8
0
/** Squash karts or items that are around the end position (determined using 
 *  a joint) of the swatter.
 */
void Swatter::squashThingsAround()
{
    const KartProperties*  kp           = m_kart->getKartProperties();
    // Square of the minimum distance
    float                  min_dist2    = kp->getSwatterDistance2();
    const World*           world        = World::getWorld();

    // Get the node corresponding to the joint at the center of the swatter
    // (by swatter, I mean the thing hold in the hand, not the whole thing)
    scene::ISceneNode* swatter_node = m_scene_node->getJointNode("Swatter");
    assert(swatter_node);
    Vec3 swatter_pos = swatter_node->getAbsolutePosition();

    m_swat_sound->position(swatter_pos);
    m_swat_sound->play();
    
    // Squash karts around
    for(unsigned int i=0; i<world->getNumKarts(); i++)
    {
        Kart *kart = world->getKart(i);
        // TODO: isSwatterReady()
        if(kart->isEliminated() || kart==m_kart)
            continue;
        // don't swat an already hurt kart
        if (kart->isInvulnerable() || kart->isSquashed())
            continue;
        
        float dist2 = (kart->getXYZ()-swatter_pos).length2();

        if(dist2 >= min_dist2) continue;   // too far away, ignore this kart

        kart->setSquash(kp->getSquashDuration(), kp->getSquashSlowdown());
        if (kart->getAttachment()->getType()==Attachment::ATTACH_BOMB)
        {   // make bomb explode
            kart->getAttachment()->update(10000);
            HitEffect *he = new Explosion(m_kart->getXYZ(),  "explosion");
            if(m_kart->getController()->isPlayerController())
                he->setPlayerKartHit();
            projectile_manager->addHitEffect(he);
            m_kart->handleExplosion(m_kart->getXYZ(),  /*direct_hit*/ true);
        }   // if kart has bomb attached
        World::getWorld()->kartHit(kart->getWorldKartId());
    }   // for i < num_kartrs

    // TODO: squash items
}
Beispiel #9
0
/** Called at the end of a race. Checks if the current times are worth a new
 *  score, if so it notifies the HighscoreManager so the new score is added
 *  and saved.
 */
void World::updateHighscores(int* best_highscore_rank, int* best_finish_time,
                             std::string* highscore_who,
                             StateManager::ActivePlayer** best_player)
{
    *best_highscore_rank = -1;
    *best_player = NULL;

    if(!m_use_highscores) return;

    // Add times to highscore list. First compute the order of karts,
    // so that the timing of the fastest kart is added first (otherwise
    // someone might get into the highscore list, only to be kicked out
    // again by a faster kart in the same race), which might be confusing
    // if we ever decide to display a message (e.g. during a race)
    unsigned int *index = new unsigned int[m_karts.size()];

    const unsigned int kart_amount = (unsigned int) m_karts.size();
    for (unsigned int i=0; i<kart_amount; i++ )
    {
        index[i] = 999; // first reset the contents of the array
    }
    for (unsigned int i=0; i<kart_amount; i++ )
    {
        const int pos = m_karts[i]->getPosition()-1;
        if(pos < 0 || pos >= (int)kart_amount) continue; // wrong position
        index[pos] = i;
    }

    for (unsigned int pos=0; pos<kart_amount; pos++)
    {
        if(index[pos] == 999)
        {
            // no kart claimed to be in this position, most likely means
            // the kart location data is wrong

#ifdef DEBUG
            Log::error("[World]", "Incorrect kart positions:");
            for (unsigned int i=0; i<m_karts.size(); i++ )
            {
                Log::error("[World]", "i=%d position %d.",i,
                           m_karts[i]->getPosition());
            }
#endif
            continue;
        }

        // Only record times for player karts and only if
        // they finished the race
        if(!m_karts[index[pos]]->getController()->isPlayerController())
            continue;
        if (!m_karts[index[pos]]->hasFinishedRace()) continue;

        assert(index[pos] < m_karts.size());
        Kart *k = (Kart*)m_karts[index[pos]];

        Highscores* highscores = getHighscores();

        PlayerController *controller = (PlayerController*)(k->getController());

        int highscore_rank = 0;
        if (controller->getPlayer()->getProfile() != NULL) // if we have the player profile here
            highscore_rank = highscores->addData(k->getIdent(),
                              controller->getPlayer()->getProfile()->getName(),
                                                 k->getFinishTime());

        if (highscore_rank > 0)
        {
            if (*best_highscore_rank == -1 ||
                highscore_rank < *best_highscore_rank)
            {
                *best_highscore_rank = highscore_rank;
                *best_finish_time = (int)(k->getFinishTime());
                *best_player = controller->getPlayer();
                *highscore_who = k->getIdent();
            }

            highscore_manager->saveHighscores();
        }
    } // next position
    delete []index;

}   // updateHighscores
Beispiel #10
0
/** Moves the camera smoothly from the current camera position (and target)
 *  to the new position and target.
 *  \param wanted_position The position the camera wanted to reach.
 *  \param wanted_target The point the camera wants to point to.
 */
void Camera::smoothMoveCamera(float dt)
{
    Kart *kart = dynamic_cast<Kart*>(m_kart);
    if (kart->isFlying())
    {
        Vec3 vec3 = m_kart->getXYZ() + Vec3(sin(m_kart->getHeading()) * -4.0f, 0.5f, cos(m_kart->getHeading()) * -4.0f);
        m_camera->setTarget(m_kart->getXYZ().toIrrVector());
        m_camera->setPosition(vec3.toIrrVector());
        return;
    }


    core::vector3df current_position  =  m_camera->getPosition();
    // Smoothly interpolate towards the position and target
    const KartProperties *kp = m_kart->getKartProperties();
    float max_increase_with_zipper = kp->getZipperMaxSpeedIncrease();
    float max_speed_without_zipper = kp->getMaxSpeed();
    float current_speed = m_kart->getSpeed();

    const Skidding *ks = m_kart->getSkidding();
    float skid_factor = ks->getVisualSkidRotation();

    float skid_angle = asin(skid_factor);
    float ratio = (current_speed - max_speed_without_zipper) / max_increase_with_zipper;
    ratio = ratio > -0.12f ? ratio : -0.12f;
    float camera_distance = -3 * (0.5f + ratio);// distance of camera from kart in x and z plane
    if (camera_distance > -2.0f) camera_distance = -2.0f;
    Vec3 camera_offset(camera_distance * sin(skid_angle / 2),
                       1.1f * (1 + ratio / 2),
                       camera_distance * cos(skid_angle / 2));// defines how far camera should be from player kart.
    Vec3 m_kart_camera_position_with_offset = m_kart->getTrans()(camera_offset);
    
    

    core::vector3df current_target = m_kart->getXYZ().toIrrVector();// next target
    current_target.Y += 0.5f;
    core::vector3df wanted_position = m_kart_camera_position_with_offset.toIrrVector();// new required position of camera
    
    if ((m_kart->getSpeed() > 5 ) || (m_kart->getSpeed() < 0 ))
    {
        current_position += ((wanted_position - current_position) * dt 
                          * (m_kart->getSpeed()>0 ? m_kart->getSpeed()/3 + 1.0f
                                                 : -1.5f * m_kart->getSpeed() + 2.0f));
    }
    else
    {
        current_position += (wanted_position - current_position) * dt * 5;
    }

    if(m_mode!=CM_FALLING)
        m_camera->setPosition(current_position);
    m_camera->setTarget(current_target);//set new target

    assert(!isnan(m_camera->getPosition().X));
    assert(!isnan(m_camera->getPosition().Y));
    assert(!isnan(m_camera->getPosition().Z));

    if (race_manager->getNumLocalPlayers() < 2)
    {
        sfx_manager->positionListener(current_position,  current_target - current_position);
    }
}   // smoothMoveCamera
Beispiel #11
0
/** Find the position (rank) of every kart
  */
void LinearWorld::updateRacePosition()
{
    // Mostly for debugging:
    beginSetKartPositions();
    const unsigned int kart_amount = m_karts.size();

#ifdef DEBUG
    bool rank_changed = false;
#endif
    
    // NOTE: if you do any changes to this loop, the next loop (see
    // DEBUG_KART_RANK below) needs to have the same changes applied
    // so that debug output is still correct!!!!!!!!!!!
    for (unsigned int i=0; i<kart_amount; i++)
    {
        Kart* kart          = m_karts[i];
        // Karts that are either eliminated or have finished the
        // race already have their (final) position assigned. If
        // these karts would get their rank updated, it could happen
        // that a kart that finished first will be overtaken after
        // crossing the finishing line and become second!
        if(kart->isEliminated() || kart->hasFinishedRace())
        {
            // This is only necessary to support debugging inconsistencies
            // in kart position parameters.
            setKartPosition(i, kart->getPosition());
            continue;
        }
        KartInfo& kart_info = m_kart_info[i];
        
        int p = 1 ;

        const int my_id                = kart->getWorldKartId();
        const int my_laps              = getLapForKart(my_id);
        const float my_progression     = getDistanceDownTrackForKart(my_id);        
        // Count karts ahead of the current kart, i.e. kart that are already finished,
        // have done more laps, or the same number of laps, but a greater distance.
        for (unsigned int j = 0 ; j < kart_amount ; j++)
        {
            if(j == kart->getWorldKartId())  continue; // don't compare a kart with itself
            
            if(m_karts[j]->isEliminated())   continue; // dismiss eliminated karts

            if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace())
            {
                p++;
                continue;
            }

            /* has done more or less lapses */
            assert(j==m_karts[j]->getWorldKartId());
            int other_laps = getLapForKart(j);
            if (other_laps !=  my_laps)
            {
                if(other_laps > my_laps)
                {
                    p++; // Other kart has more lapses
                }
                continue;
            }
            // Now both karts have the same number of lapses. Test progression.
            // A kart is ahead if it's driven further, or driven the same
            // distance, but started further to the back.
            float other_progression = getDistanceDownTrackForKart(j);
            if(other_progression > my_progression ||
                (other_progression == my_progression &&
                m_karts[j]->getInitialPosition() > kart->getInitialPosition()) )
            {
                p++;
#if _DEBUG_PRINTS_LIKE_MAD_
                std::cout << "    " << p << " : " << m_karts[j]->getIdent() <<
                        " because he has is further within the track (my progression is " <<
                        my_progression << ", his progression is " << other_progression << ")\n";
#endif
            }
        } //next kart

#ifndef DEBUG
        setKartPosition(i, p);
#else
        rank_changed |= kart->getPosition()!=p;
        if (!setKartPosition(i,p))
        {
            std::cerr << "ERROR, same rank used twice!!\n";

            std::cerr <<  "Info used to decide ranking :\n";
            for (unsigned int d=0; d<kart_amount; d++)
            {
                std::cerr << "   kart " << m_karts[d]->getIdent() << " has finished(" << m_karts[d]->hasFinishedRace()
                          << "), is at lap (" << getLapForKart(d) << "), is at distance("
                          << getDistanceDownTrackForKart(d) << "), is eliminated(" << m_karts[d]->isEliminated() << ")" << std::endl;
            }
                        
            std::cerr <<  "Who has each ranking so far :\n";
            for (unsigned int d=0; d<i; d++)
            {
                std::cerr << "    " << m_karts[d]->getIdent() << " has rank " << m_karts[d]->getPosition() << std::endl;
            }
            
            std::cerr << "    --> And " << kart->getIdent() << " is being set at rank " << p << std::endl;
            history->Save();
            assert(false);
        }
#endif

        // Switch on faster music if not already done so, if the
        // first kart is doing its last lap, and if the estimated
        // remaining time is less than 30 seconds.
        if(!m_faster_music_active                                  &&
           kart_info.m_race_lap == race_manager->getNumLaps()-1    &&
           p==1                                                    &&
           useFastMusicNearEnd()                                   &&
           kart_info.m_estimated_finish > 0                        &&
           kart_info.m_estimated_finish - getTime() < 30.0f              )
        {
            music_manager->switchToFastMusic();
            m_faster_music_active=true;
        }
    }   // for i<kart_amount

    // Define this to get a detailled analyses each time a race position 
    // changes.
#ifdef DEBUG
#undef DEBUG_KART_RANK
#ifdef DEBUG_KART_RANK
    if(rank_changed)
    {
        std::cout << "Counting laps at "<<getTime()<<" seconds.\n";
        for (unsigned int i=0; i<kart_amount; i++)
        {
            Kart* kart          = m_karts[i];
            if(kart->isEliminated() || kart->hasFinishedRace()) continue;
            KartInfo& kart_info = m_kart_info[i];
            int p = 1 ;
            const int my_id                = kart->getWorldKartId();
            const int my_laps              = getLapForKart(my_id);
            const float my_progression     = getDistanceDownTrackForKart(my_id);
            std::cout << "counting karts ahead of " << kart->getIdent() 
                << " (laps "<<m_kart_info[i].m_race_lap<<", progress "
                << my_progression<<").\n";
            for (unsigned int j = 0 ; j < kart_amount ; j++)
            {
                if(j == kart->getWorldKartId())  continue; // don't compare a kart with itself
                if(!kart->hasFinishedRace() && m_karts[j]->hasFinishedRace())
                {
                    p++;
                    std::cout << "    " << p << " : " << m_karts[j]->getIdent() << " because he has finished.\n";
                    continue;
                }
                int other_laps = getLapForKart(j);
                if (other_laps !=  my_laps)
                {
                    if(other_laps > my_laps)
                    {
                        p++; // Other kart has more lapses
                        std::cout << "    " << p << " : " << m_karts[j]->getIdent() << " because he has more laps than me.\n";
                    }
                    continue;
                }
                float other_progression = getDistanceDownTrackForKart(j);
                if(other_progression > my_progression ||
                    (other_progression == my_progression &&
                    m_karts[j]->getInitialPosition() > kart->getInitialPosition()) )
                {
                    p++;
                    std::cout << "    " << p << " : " << m_karts[j]->getIdent() <<
                        " because he is further within the track (my progression is " <<
                        my_progression << ", his progression is " << other_progression << ")\n";
                }
            } //next kart
        }   // for i<kart_amount
        std::cout << "-------------------------------------------\n";
    }   // if rank_changed
#endif
#endif

    endSetKartPositions();
}   // updateRacePosition
Beispiel #12
0
//-----------------------------------------------------------------------------
RaceGUIBase::KartIconDisplayInfo* LinearWorld::getKartsDisplayInfo()
{
    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 = m_kart_display_info[i];
        Kart* kart = m_karts[i];

        // reset color
        rank_info.r = 1.0;
        rank_info.g = 1.0;
        rank_info.b = 1.0;
        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 = m_kart_display_info[i];
        KartInfo& kart_info = m_kart_info[i];
        Kart* kart = m_karts[i];

        const int position = kart->getPosition();

        if(laps_of_leader>0 &&    // Don't compare times when crossing the start line first
           (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.g = rank_info.b = 0;
        }
        else if(kart_info.m_race_lap>=0 && numLaps>1)
        {
            rank_info.g = rank_info.b = 1.0f-(float)kart_info.m_race_lap/((float)numLaps-1.0f);
        }
    }   // next kart


    return m_kart_display_info;
}   // getKartsDisplayInfo
Beispiel #13
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
Beispiel #14
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