Beispiel #1
0
/** A kart has finished the race at the specified time (which can be
 *  different from World::getWorld()->getClock() in case of setting
 *  extrapolated arrival times). This function is only called from
 *  kart::finishedRace()
 *  \param kart The kart that finished the race.
 *  \param time Time at which the kart finished the race.
 */
void RaceManager::kartFinishedRace(const AbstractKart *kart, float time)
{
    unsigned int id = kart->getWorldKartId();
    int pos = kart->getPosition();

    assert(pos-1 >= 0);
    assert(pos-1 < (int)m_kart_status.size());

    m_kart_status[id].m_last_score    = m_kart_status[id].m_score;

    // In follow the leader mode, the winner is actually the kart with
    // position 2, so adjust the points (#points for leader do not matter)
    WorldWithRank *wwr = dynamic_cast<WorldWithRank*>(World::getWorld());
    if (wwr)
        m_kart_status[id].m_score += wwr->getScoreForPosition(pos);
    else
    {
        Log::error("RaceManager",
                   "World with scores that is not a WorldWithRank??");
    }

    m_kart_status[id].m_overall_time += time;
    m_kart_status[id].m_last_time     = time;
    m_num_finished_karts ++;
    if(kart->getController()->isPlayerController())
        m_num_finished_players++;
}   // kartFinishedRace
/** Displays the rank and the lap of the kart.
 *  \param info Info object c
*/
void RaceGUI::drawRankLap(const KartIconDisplayInfo* info,
                          const AbstractKart* kart,
                          const core::recti &viewport)
{
    // Don't display laps or ranks if the kart has already finished the race.
    if (kart->hasFinishedRace()) return;

    core::recti pos;
    pos.UpperLeftCorner.Y   = viewport.UpperLeftCorner.Y;
    // If the time display in the top right is in this viewport,
    // move the lap/rank display down a little bit so that it is
    // displayed under the time.
    if(viewport.UpperLeftCorner.Y==0 && 
        viewport.LowerRightCorner.X==UserConfigParams::m_width &&
        race_manager->getNumPlayers()!=3)
        pos.UpperLeftCorner.Y   += 40;
    pos.LowerRightCorner.Y  = viewport.LowerRightCorner.Y;
    pos.UpperLeftCorner.X   = viewport.LowerRightCorner.X 
                            - m_rank_lap_width - 10;
    pos.LowerRightCorner.X  = viewport.LowerRightCorner.X;

    gui::ScalableFont* font = (race_manager->getNumLocalPlayers() > 2 ? GUIEngine::getSmallFont() : GUIEngine::getFont());
    int font_height         = (int)(font->getDimension(L"X").Height);
    static video::SColor color = video::SColor(255, 255, 255, 255);
    WorldWithRank *world    = (WorldWithRank*)(World::getWorld());

    if (world->displayRank())
    {
        const int rank = kart->getPosition();
            
        font->draw(m_string_rank.c_str(), pos, color);
        pos.UpperLeftCorner.Y  += font_height;
        pos.LowerRightCorner.Y += font_height;

        char str[256];
        const unsigned int kart_amount = world->getCurrentNumKarts();
        sprintf(str, "%d/%d", rank, kart_amount);
        font->draw(core::stringw(str).c_str(), pos, color);
        pos.UpperLeftCorner.Y  += font_height;
        pos.LowerRightCorner.Y += font_height;
    }
    
    // Don't display laps in follow the leader mode
    if(world->raceHasLaps())
    {
        const int lap = info[kart->getWorldKartId()].lap;
    
        // don't display 'lap 0/...'
        if(lap>=0)
        {
            font->draw(m_string_lap.c_str(), pos, color);
            char str[256];
            sprintf(str, "%d/%d", lap+1, race_manager->getNumLaps());
            pos.UpperLeftCorner.Y  += font_height;
            pos.LowerRightCorner.Y += font_height;
            font->draw(core::stringw(str).c_str(), pos, color);
            pos.UpperLeftCorner.Y  += font_height;
            pos.LowerRightCorner.Y += font_height;
        }
    }

} // drawRankLap
Beispiel #3
0
/** Draws the rank of a player.
 *  \param kart The kart of the player.
 *  \param offset Offset of top left corner for this display (for splitscreen).
 *  \param min_ratio Scaling of the screen (for splitscreen).
 *  \param meter_width Width of the meter (inside which the rank is shown).
 *  \param meter_height Height of the meter (inside which the rank is shown).
 *  \param dt Time step size.
 */
void RaceGUI::drawRank(const AbstractKart *kart,
                      const core::vector2df &offset,
                      float min_ratio, int meter_width,
                      int meter_height, float dt)
{
    // Draw rank
    WorldWithRank *world = dynamic_cast<WorldWithRank*>(World::getWorld());
    if (!world || !world->displayRank())
        return;

    int id = kart->getWorldKartId();

    if (m_animation_states[id] == AS_NONE)
    {
        if (m_last_ranks[id] != kart->getPosition())
        {
            m_rank_animation_duration[id] = 0.0f;
            m_animation_states[id] = AS_SMALLER;
        }
    }
    else
    {
        m_rank_animation_duration[id] += dt;
    }

    float scale = 1.0f;
    int rank = kart->getPosition();
    const float DURATION = 0.4f;
    const float MIN_SHRINK = 0.3f;
    if (m_animation_states[id] == AS_SMALLER)
    {
        scale = 1.0f - m_rank_animation_duration[id]/ DURATION;
        rank = m_last_ranks[id];
        if (scale < MIN_SHRINK)
        {
            m_animation_states[id] = AS_BIGGER;
            m_rank_animation_duration[id] = 0.0f;
            // Store the new rank
            m_last_ranks[id] = kart->getPosition();
            scale = MIN_SHRINK;
        }
    }
    else if (m_animation_states[id] == AS_BIGGER)
    {
        scale = m_rank_animation_duration[id] / DURATION + MIN_SHRINK;
        rank = m_last_ranks[id];
        if (scale > 1.0f)
        {
            m_animation_states[id] = AS_NONE;
            scale = 1.0f;
        }

    }
    else
    {
        m_last_ranks[id] = kart->getPosition();
    }

    gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
    font->setScale(min_ratio * scale);
    font->setShadow(video::SColor(255, 128, 0, 0));
    std::ostringstream oss;
    oss << rank; // the current font has no . :(   << ".";

    core::recti pos;
    pos.LowerRightCorner = core::vector2di(int(offset.X + 0.65f*meter_width),
                                           int(offset.Y - 0.55f*meter_height));
    pos.UpperLeftCorner = core::vector2di(int(offset.X + 0.65f*meter_width),
                                          int(offset.Y - 0.55f*meter_height));

    static video::SColor color = video::SColor(255, 255, 255, 255);
    font->draw(oss.str().c_str(), pos, color, true, true);
    font->setScale(1.0f);
}   // drawRank
/** Displays the rank and the lap of the kart.
 *  \param info Info object c
*/
void MinimalRaceGUI::drawRankLap(const KartIconDisplayInfo* info, 
                                 const AbstractKart* kart,
                                 const core::recti &viewport)
{
    // Don't display laps or ranks if the kart has already finished the race.
    if (kart->hasFinishedRace()) return;

    core::recti pos;

    gui::ScalableFont* font = (race_manager->getNumLocalPlayers() > 2 
                            ? GUIEngine::getSmallFont() 
                            : GUIEngine::getFont());
    float scale = font->getScale();
    font->setScale(m_font_scale);
    // Add a black shadow to make the text better readable on
    // 'white' tracks (e.g. with snow and ice).
    font->setShadow(video::SColor(255, 0, 0, 0));
    static video::SColor color = video::SColor(255, 255, 255, 255);
    WorldWithRank *world    = (WorldWithRank*)(World::getWorld());

    if (world->displayRank())
    {
        pos.UpperLeftCorner.Y   = viewport.UpperLeftCorner.Y;
        pos.LowerRightCorner.Y  = viewport.UpperLeftCorner.Y+50;
        // Split screen 3 or 4 players, left side:
        if(viewport.LowerRightCorner.X < UserConfigParams::m_width)
        {
            pos.UpperLeftCorner.X   = 10;
            pos.LowerRightCorner.X  = viewport.LowerRightCorner.X;
        }
        else
        {
            pos.UpperLeftCorner.X   = viewport.LowerRightCorner.X
                                    - m_rank_width-10;
            pos.LowerRightCorner.X  = viewport.LowerRightCorner.X;
        }

        char str[256];
        sprintf(str, "%d/%d", kart->getPosition(), 
                world->getCurrentNumKarts());
        font->draw(str, pos, color);
    }
    
    // Don't display laps in follow the leader mode
    if(world->raceHasLaps())
    {
        const int lap = info[kart->getWorldKartId()].lap;
    
        // don't display 'lap 0/...'
        if(lap>=0)
        {
            pos.LowerRightCorner.Y  = viewport.LowerRightCorner.Y;
            pos.UpperLeftCorner.Y   = viewport.LowerRightCorner.Y-60;
            pos.LowerRightCorner.X  = viewport.LowerRightCorner.X;
            // Split screen 3 or 4 players, left side:
            if(viewport.LowerRightCorner.X < UserConfigParams::m_width)
            {
                pos.UpperLeftCorner.X = 10;
            }
            else
            {
                pos.UpperLeftCorner.X = (int)(viewport.LowerRightCorner.X
                                              - m_lap_width -10          );
            }

            char str[256];
            sprintf(str, "%d/%d", lap+1, race_manager->getNumLaps());
            core::stringw s = m_string_lap+" "+str;
            font->draw(s.c_str(), pos, color);
        }
    }
    font->setScale(scale);
    font->disableShadow();
} // drawRankLap
/** Draw players icons and their times (if defined in the current mode).
 *  Also takes care of icon looking different due to plumber, squashing, ...
 */
void RaceGUIBase::drawGlobalPlayerIcons(int bottom_margin)
{
    // For now, don't draw player icons when in soccer mode
    const RaceManager::MinorRaceModeType  minor_mode = race_manager->getMinorMode();
    if(minor_mode == RaceManager::MINOR_MODE_SOCCER)
        return;

    int x_base = 10;
    int y_base = 20;
    unsigned int y_space = UserConfigParams::m_height - bottom_margin - y_base;
    // Special case : when 3 players play, use 4th window to display such stuff
    if (race_manager->getNumLocalPlayers() == 3)
    {
        x_base = UserConfigParams::m_width/2 + x_base;
        y_base = UserConfigParams::m_height/2 + y_base;
        y_space = UserConfigParams::m_height - y_base;
    }

    // -2 because that's the spacing further on
    int ICON_PLAYER_WIDTH = y_space / race_manager->getNumberOfKarts() - 2;

    int icon_width_max = (int)(50*(UserConfigParams::m_width/800.0f));
    int icon_width_min = (int)(35*(UserConfigParams::m_height/600.0f));
    if (icon_width_min > icon_width_max)
    {
        int icon_width_tmp = icon_width_max;
        icon_width_max = icon_width_min;
        icon_width_min = icon_width_tmp;
    }

    // Make sure it fits within our boundaries
    if (ICON_PLAYER_WIDTH > icon_width_max) ICON_PLAYER_WIDTH = icon_width_max;
    if (ICON_PLAYER_WIDTH < icon_width_min) ICON_PLAYER_WIDTH = icon_width_min;

    // TODO: Is this absolute treshold necessary?
    if(UserConfigParams::m_height<600)
    {
        ICON_PLAYER_WIDTH = 35;
    }

    // Icon width for the AI karts
    int ICON_WIDTH = ICON_PLAYER_WIDTH * 4 / 5;

    WorldWithRank *world    = (WorldWithRank*)(World::getWorld());
    //initialize m_previous_icons_position
    if(m_previous_icons_position.size()==0)
    {
        for(unsigned int i=0; i<race_manager->getNumberOfKarts(); i++)
        {
            const AbstractKart *kart = world->getKart(i);
            int position = kart->getPosition();
            core::vector2d<s32> pos(x_base,y_base+(position-1)*(ICON_PLAYER_WIDTH+2));
            m_previous_icons_position.push_back(pos);
        }
    }

    int x;
    int y;
    float previous_distance=0.0;//no need to be far ahead, first kart won't try to overlap



    int previous_x=x_base;
    int previous_y=y_base-ICON_PLAYER_WIDTH-2;

    gui::ScalableFont* font = GUIEngine::getFont();
    const unsigned int kart_amount = world->getNumKarts();

    //where is the limit to hide last icons
    int y_icons_limit=UserConfigParams::m_height-bottom_margin-ICON_PLAYER_WIDTH;
    if (race_manager->getNumLocalPlayers() == 3)
        y_icons_limit=UserConfigParams::m_height-ICON_WIDTH;

    world->getKartsDisplayInfo(&m_kart_display_infos);

    for(int position = 1; position <= (int)kart_amount ; position++)
    {
        AbstractKart *kart = world->getKartAtPosition(position);

        if (kart->getPosition() == -1)//if position is not set
        {
            //we use karts ordered by id only
            //(needed for beginning of MINOR_MODE_3_STRIKES)
            kart= world->getKart(position-1);
        }

        if(kart->isEliminated()) continue;
        unsigned int kart_id = kart->getWorldKartId();

        KartIconDisplayInfo &info = m_kart_display_infos[kart_id];
        //x,y is the target position
        int lap = info.lap;

        // In battle mode mode there is no distance along track etc.
        if( minor_mode==RaceManager::MINOR_MODE_3_STRIKES ||
            minor_mode==RaceManager::MINOR_MODE_EASTER_EGG)
        {
            x = x_base;
            y = previous_y+ICON_PLAYER_WIDTH+2;
        }
        else
        {
            LinearWorld *linear_world = (LinearWorld*)(World::getWorld());

            float distance = linear_world->getDistanceDownTrackForKart(kart_id)
                           + linear_world->getTrack()->getTrackLength()*lap;
            if ((position>1) &&
                (previous_distance-distance<m_dist_show_overlap) &&
                (!kart->hasFinishedRace())                          )
            {
                //linear translation : form (0,ICON_PLAYER_WIDTH+2) to
                // (previous_x-x_base+(ICON_PLAYER_WIDTH+2)/2,0)
                x=(int)(x_base+(1-(previous_distance-distance)
                                /m_dist_show_overlap)
                        *(previous_x-x_base+(ICON_PLAYER_WIDTH+2)/2));
                y=(int)(previous_y+(previous_distance-distance)
                        /m_dist_show_overlap*(ICON_PLAYER_WIDTH+2));
            }
            else
            {
                x=x_base;
                y=previous_y+ICON_PLAYER_WIDTH+2;
            }
            previous_distance=distance;
        }   // not three-strike-battle


        previous_x=x;//save coord of the previous kart in list
        previous_y=y;

        //soft movement using previous position:
        x=(int)((x+m_previous_icons_position[kart_id].X*m_icons_inertia)
                /(m_icons_inertia+1));
        y=(int)((y+m_previous_icons_position[kart_id].Y*m_icons_inertia)
                /(m_icons_inertia+1));

        //save position for next time
        m_previous_icons_position[kart_id].X=x;
        m_previous_icons_position[kart_id].Y=y;

        if (y>y_icons_limit)
        {
            //there are too many icons, write "Top 9", to express that
            //there is not everybody shown
            core::recti pos_top;
            pos_top.UpperLeftCorner.Y  = y_base-22;
            pos_top.UpperLeftCorner.X  = x_base;

            static video::SColor color = video::SColor(255, 255, 255, 255);
            pos_top.LowerRightCorner   = pos_top.UpperLeftCorner;

            font->draw(StringUtils::insertValues( m_string_top, position-1 ), pos_top, color);

            break;
        }

        if (m_kart_display_infos[kart_id].m_text.size() > 0)
        {
            core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5,
                                x+ICON_PLAYER_WIDTH, y+5);
            core::stringw s=info.m_text.c_str();

            font->draw(s.c_str(), pos, info.m_color, false, false, NULL,
                       true /* ignore RTL */);
        }

        if (info.special_title.size() > 0)
        {
            core::rect<s32> pos(x+ICON_PLAYER_WIDTH, y+5,
                                x+ICON_PLAYER_WIDTH, y+5);
            core::stringw s(info.special_title.c_str());
            font->draw(s.c_str(), pos, info.m_color, false, false, NULL,
                       true /* ignore RTL */);
        }

        // draw icon
        video::ITexture *icon =
        kart->getKartProperties()->getIconMaterial()->getTexture();
        int w =
        kart->getController()->isPlayerController() ? ICON_PLAYER_WIDTH
        : ICON_WIDTH;
        const core::rect<s32> pos(x, y, x+w, y+w);

        //to bring to light the player's icon: add a background
        if (kart->getController()->isPlayerController())
        {
            video::SColor colors[4];
            for (unsigned int i=0;i<4;i++)
            {
                colors[i]=kart->getKartProperties()->getColor();
                colors[i].setAlpha(
                                   100+(int)(100*cos(M_PI/2*i+World::getWorld()->getTime()*2)));
            }
            const core::rect<s32> rect(core::position2d<s32>(0,0),
                                       m_icons_frame->getTexture()->getOriginalSize());
            draw2DImage(
                                                      m_icons_frame->getTexture(), pos, rect,NULL, colors, true);
        }

        // Fixes crash bug, why are certain icons not showing up?
        if (icon  && !kart->getKartAnimation() && !kart->isSquashed())
        {
            const core::rect<s32> rect(core::position2d<s32>(0,0),
                                       icon->getOriginalSize());
            draw2DImage(icon, pos, rect,
                                                      NULL, NULL, true);
        }

        //draw status info - icon fade out in case of rescue/explode

        if (icon  && dynamic_cast<RescueAnimation*>(kart->getKartAnimation()))
        {
            //icon fades to the left
            float t = kart->getKartAnimation()->getAnimationTimer();
            float t_anim=100*sin(0.5f*M_PI*t);
            const core::rect<s32> rect1(core::position2d<s32>(0,0),
                                        icon->getOriginalSize());
            const core::rect<s32> pos1((int)(x-t_anim), y,
                                       (int)(x+w-t_anim), y+w);
            draw2DImage(icon, pos1, rect1,
                                                      NULL, NULL, true);
        }

        if (icon  && !kart->getKartAnimation() && kart->isSquashed() )
        {
            //syncs icon squash with kart squash
            const core::rect<s32> destRect(core::position2d<s32>(x,y+w/4),
                                           core::position2d<s32>(x+w,y+w*3/4));
            const core::rect<s32> sourceRect(core::position2d<s32>(0,0),
                                             icon->getOriginalSize());
            draw2DImage(icon, destRect,
                                                      sourceRect, NULL, NULL,
                                                      true);
        }

        if (icon  &&
            dynamic_cast<ExplosionAnimation*>(kart->getKartAnimation()) )
        {
            //exploses into 4 parts
            float t = kart->getKartAnimation()->getAnimationTimer();
            float t_anim=50.0f*sin(0.5f*M_PI*t);
            u16 icon_size_x=icon->getOriginalSize().Width;
            u16 icon_size_y=icon->getOriginalSize().Height;

            const core::rect<s32> rect1(0, 0, icon_size_x/2,icon_size_y/2);
            const core::rect<s32> pos1((int)(x-t_anim), (int)(y-t_anim),
                                       (int)(x+w/2-t_anim),
                                       (int)(y+w/2-t_anim));
            draw2DImage(icon, pos1, rect1,
                                                      NULL, NULL, true);

            const core::rect<s32> rect2(icon_size_x/2,0,
                                        icon_size_x,icon_size_y/2);
            const core::rect<s32> pos2((int)(x+w/2+t_anim),
                                       (int)(y-t_anim),
                                       (int)(x+w+t_anim),
                                       (int)(y+w/2-t_anim));
            draw2DImage(icon, pos2, rect2,
                                                      NULL, NULL, true);

            const core::rect<s32> rect3(0, icon_size_y/2, icon_size_x/2,icon_size_y);
            const core::rect<s32> pos3((int)(x-t_anim), (int)(y+w/2+t_anim),
                                       (int)(x+w/2-t_anim), (int)(y+w+t_anim));
            draw2DImage(icon, pos3, rect3, NULL, NULL, true);

            const core::rect<s32> rect4(icon_size_x/2,icon_size_y/2,icon_size_x,icon_size_y);
            const core::rect<s32> pos4((int)(x+w/2+t_anim), (int)(y+w/2+t_anim),
                                       (int)(x+w+t_anim), (int)(y+w+t_anim));
            draw2DImage(icon, pos4, rect4, NULL, NULL, true);
        }

        //Plunger
        if (kart->getBlockedByPlungerTime()>0)
        {
            video::ITexture *icon_plunger =
            powerup_manager->getIcon(PowerupManager::POWERUP_PLUNGER)->getTexture();
            if (icon_plunger != NULL)
            {
                const core::rect<s32> rect(core::position2d<s32>(0,0),
                                           icon_plunger->getOriginalSize());
                const core::rect<s32> pos1(x+10, y-10, x+w+10, y+w-10);
                draw2DImage(icon_plunger, pos1,
                                                          rect, NULL, NULL,
                                                          true);
            }
        }
        //attachment
        if (kart->getAttachment()->getType() != Attachment::ATTACH_NOTHING)
        {
            video::ITexture *icon_attachment =
            attachment_manager->getIcon(kart->getAttachment()->getType())
            ->getTexture();
            if (icon_attachment != NULL)
            {
                const core::rect<s32> rect(core::position2d<s32>(0,0),
                                           icon_attachment->getOriginalSize());
                const core::rect<s32> pos1(x-20, y-10, x+w-20, y+w-10);
                draw2DImage(icon_attachment,
                                                          pos1, rect, NULL,
                                                          NULL, true);
            }
        }

    } //next position
}   // drawGlobalPlayerIcons