Add Lap Trial mode (#4663)

This commit is contained in:
Kuba 2021-11-01 20:02:16 +01:00 committed by GitHub
parent 8b5b68585c
commit 3623fa8f5f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 398 additions and 38 deletions

View File

@ -31,6 +31,14 @@
<label id="reverse-text" width="52%" height="fit" I18N="In the grand prix info screen" text="Reverse" text_align="left"/>
</div>
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row">
<div width="45%" height="fit" layout="horizontal-row">
<spinner id="time-target-spinner" width="100%" min_value="1" max_value="20" align="center" wrap_around="true" />
</div>
<spacer width="3%"/>
<label id="time-target-text" width="52%" height="fit" I18N="In the grand prix info screen" text="Maximum time (min.)" text_align="left"/>
</div>
<spacer width="1" height="1%"/>
<div width="100%" height="fit" layout="horizontal-row">
<div width="45%" height="fit" layout="horizontal-row">
<spinner id="track-spinner" width="100%" min_value="1" max_value="20" align="center" wrap_around="true" />

View File

@ -22,6 +22,8 @@
I18N="In the high score selection screen" text="Time Trial"/>
<icon-button id="tab_egg_hunt" width="128" height="128" icon="gui/icons/mode_easter.png"
I18N="In the high score selection screen" text="Egg Hunt"/>
<icon-button id="tab_lap_trial" width="128" height="128" icon="gui/icons/mode_normal.png"
I18N="In the high score selection screen" text="Lap Trial"/>
<icon-button id="tab_grand_prix" width="128" height="128" icon="gui/icons/gp_new.png"
I18N="In the high score selection screen" text="Grand Prix"/>
</tabs>

View File

@ -71,6 +71,8 @@ SavedGrandPrix::SavedGrandPrix(unsigned int player_id,
int last_track,
int reverse_type,
int skipped_tracks,
float time_target,
int player_total_laps,
const std::vector<RaceManager::KartStatus> &kart_list)
: m_savedgp_group("SavedGP",
"Represents the saved state of a GP"),
@ -81,7 +83,9 @@ SavedGrandPrix::SavedGrandPrix(unsigned int player_id,
m_player_karts(player_karts,"player_karts", &m_savedgp_group),
m_next_track(last_track,"last_track", &m_savedgp_group),
m_reverse_type(reverse_type,"reverse_type", &m_savedgp_group),
m_skipped_tracks(skipped_tracks, "skipped_tracks", &m_savedgp_group)
m_skipped_tracks(skipped_tracks, "skipped_tracks", &m_savedgp_group),
m_time_target(time_target, "time_target", &m_savedgp_group),
m_player_total_laps(player_total_laps, "player_total_laps", &m_savedgp_group)
{
for(unsigned int i =0; i < kart_list.size(); i++)
{
@ -107,7 +111,9 @@ SavedGrandPrix::SavedGrandPrix(const XMLNode* node)
m_player_karts(0,"player_karts", &m_savedgp_group),
m_next_track (0,"last_track", &m_savedgp_group),
m_reverse_type(0,"reverse_type", &m_savedgp_group),
m_skipped_tracks(0, "skipped_tracks", &m_savedgp_group)
m_skipped_tracks(0, "skipped_tracks", &m_savedgp_group),
m_time_target(0.0f, "time_target", &m_savedgp_group),
m_player_total_laps(0, "player_total_laps", &m_savedgp_group)
{
//m_player_group.findYourDataInAChildOf(node);
m_player_id. findYourDataInAnAttributeOf(node);
@ -118,6 +124,8 @@ SavedGrandPrix::SavedGrandPrix(const XMLNode* node)
m_next_track. findYourDataInAnAttributeOf(node);
m_reverse_type.findYourDataInAnAttributeOf(node);
m_skipped_tracks.findYourDataInAnAttributeOf(node);
m_time_target.findYourDataInAnAttributeOf(node);
m_player_total_laps.findYourDataInAnAttributeOf(node);
std::vector<XMLNode*> karts;
node->getNodes("Kart", karts);

View File

@ -85,6 +85,12 @@ protected:
/** Count of tracks that player skipped */
IntUserConfigParam m_skipped_tracks;
/** Time target used in Lap Trial mode */
FloatUserConfigParam m_time_target;
/** Total laps count, used in Lap Trial mode */
IntUserConfigParam m_player_total_laps;
PtrVector<SavedGPKart> m_karts;
public:
@ -100,6 +106,8 @@ public:
int last_track,
int reverse_type,
int skipped_tracks,
float time_target,
int player_total_laps,
const std::vector<RaceManager::KartStatus> &kart_list);
/**
@ -146,6 +154,14 @@ public:
/** Returns skipped tracks count */
int getSkippedTracks() const { return m_skipped_tracks; }
// ------------------------------------------------------------------------
/** Returns time target used in Lap Trial mode */
float getTimeTarget() const { return m_time_target; }
// ------------------------------------------------------------------------
/** Returns total laps in GP */
int getPlayerTotalLaps() const { return m_player_total_laps; }
// ------------------------------------------------------------------------
/** Sets the index of the last track finished. */
void setNextTrack(int next_track) { m_next_track = next_track; }

View File

@ -446,6 +446,9 @@ namespace UserConfigParams
PARAM_PREFIX BoolUserConfigParam m_use_ffa_mode
PARAM_DEFAULT(BoolUserConfigParam(false, "use-ffa-mode",
&m_race_setup_group, "Use ffa mode instead of 3 strikes battle."));
PARAM_PREFIX IntUserConfigParam m_lap_trial_time_limit
PARAM_DEFAULT(IntUserConfigParam(3, "lap-trial-time-limit",
&m_race_setup_group, "Time limit in lap trial mode."));
PARAM_PREFIX IntUserConfigParam m_num_goals
PARAM_DEFAULT( IntUserConfigParam(3, "numgoals",
&m_race_setup_group, "Default number of goals in soccer mode.") );

View File

@ -524,6 +524,7 @@ void PowerupManager::computeWeightsForRace(int num_karts)
switch (RaceManager::get()->getMinorMode())
{
case RaceManager::MINOR_MODE_TIME_TRIAL: /* fall through */
case RaceManager::MINOR_MODE_LAP_TRIAL: /* fall through */
case RaceManager::MINOR_MODE_NORMAL_RACE: class_name="race"; break;
case RaceManager::MINOR_MODE_FOLLOW_LEADER: class_name="ftl"; break;
case RaceManager::MINOR_MODE_3_STRIKES: class_name="battle"; break;

View File

@ -1027,7 +1027,8 @@ void Kart::finishedRace(float time, bool from_server)
}
if (RaceManager::get()->isLinearRaceMode() || RaceManager::get()->isBattleMode() ||
RaceManager::get()->isSoccerMode() || RaceManager::get()->isEggHuntMode())
RaceManager::get()->isSoccerMode() || RaceManager::get()->isEggHuntMode() ||
RaceManager::get()->isLapTrialMode())
{
// Save for music handling in race result gui
setRaceResult();
@ -1052,7 +1053,8 @@ void Kart::finishedRace(float time, bool from_server)
void Kart::setRaceResult()
{
if (RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE ||
RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
RaceManager::get()->isLapTrialMode())
{
if (m_controller->isLocalPlayerController()) // if player is on this computer
{

95
src/modes/lap_trial.cpp Normal file
View File

@ -0,0 +1,95 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "modes/lap_trial.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "utils/string_utils.hpp"
#include "tracks/track.hpp"
LapTrial::LapTrial() : LinearWorld()
{
WorldStatus::setClockMode(WorldStatus::CLOCK_COUNTDOWN, RaceManager::get()->getTimeTarget());
RaceManager::get()->setNumLaps(99999);
}
bool LapTrial::isRaceOver()
{
return m_count_down_reached_zero;
}
void LapTrial::countdownReachedZero()
{
// When countdown reaches zero stop race
LinearWorld::countdownReachedZero();
m_count_down_reached_zero = true;
}
void LapTrial::getKartsDisplayInfo(std::vector<RaceGUIBase::KartIconDisplayInfo>* icons)
{
const unsigned int numKarts = getNumKarts();
for(unsigned int i = 0; i < numKarts; i++)
{
AbstractKart* kart = m_karts[i].get();
RaceGUIBase::KartIconDisplayInfo& icon = (*icons)[i];
int laps = getFinishedLapsOfKart(kart->getWorldKartId());
icon.lap = -1;
icon.m_outlined_font = true;
icon.m_color = irr::video::SColor(255,255,255,255);
if (kart->hasFinishedRace())
{
icon.m_text = kart->getController()->getName();
if (RaceManager::get()->getKartGlobalPlayerId(i) > -1)
{
const core::stringw& flag = StringUtils::getCountryFlag(
RaceManager::get()->getKartInfo(i).getCountryCode());
if (!flag.empty())
{
icon.m_text += L" ";
icon.m_text += flag;
}
}
}
else
{
icon.m_text = irr::core::stringw((!kart->isEliminated() && laps < 0) ? 0 : laps);
}
}
}
void LapTrial::reset(bool restart)
{
LinearWorld::reset(restart);
WorldStatus::setClockMode(WorldStatus::CLOCK_COUNTDOWN, RaceManager::get()->getTimeTarget());
m_count_down_reached_zero = false;
}
void LapTrial::update(int ticks)
{
LinearWorld::update(ticks);
}
void LapTrial::terminateRace()
{
for (unsigned int i = 0; i < getNumKarts(); i++)
{
getKart(i)->finishedRace(RaceManager::get()->getTimeTarget());
}
World::terminateRace();
}

40
src/modes/lap_trial.hpp Normal file
View File

@ -0,0 +1,40 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2004-2015 SuperTuxKart-Team
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_LAP_TRIAL_HPP
#define HEADER_LAP_TRIAL_HPP
#include "modes/linear_world.hpp"
class LapTrial : public LinearWorld
{
protected:
virtual bool isRaceOver() OVERRIDE;
public:
LapTrial();
virtual void countdownReachedZero() OVERRIDE;
virtual void reset(bool restart = false) OVERRIDE;
virtual void update(int ticks) OVERRIDE;
virtual void terminateRace() OVERRIDE;
virtual const std::string& getIdent() const OVERRIDE { return IDENT_LAP_TRIAL; }
virtual bool showLapsTarget() OVERRIDE { return false; }
virtual void getKartsDisplayInfo(std::vector<RaceGUIBase::KartIconDisplayInfo>* icons) OVERRIDE;
private:
bool m_count_down_reached_zero;
};
#endif

View File

@ -516,10 +516,18 @@ void LinearWorld::newLap(unsigned int kart_index)
int ticks_per_lap;
if (kart_info.m_finished_laps == 1) // just completed first lap
{
// To avoid negative times in countdown mode
if (getClockMode() == CLOCK_COUNTDOWN)
ticks_per_lap = stk_config->time2Ticks(RaceManager::get()->getTimeTarget()) - getTimeTicks();
else
ticks_per_lap = getTimeTicks();
}
else //completing subsequent laps
{
// To avoid negative times in countdown mode
if (getClockMode() == CLOCK_COUNTDOWN)
ticks_per_lap = kart_info.m_lap_start_ticks - getTimeTicks();
else
ticks_per_lap = getTimeTicks() - kart_info.m_lap_start_ticks;
}

View File

@ -236,6 +236,8 @@ public:
void updateCheckLinesClient(const BareNetworkString& b);
// ------------------------------------------------------------------------
void handleServerCheckStructureCount(unsigned count);
// ------------------------------------------------------------------------
virtual bool showLapsTarget() OVERRIDE { return true; }
}; // LinearWorld
#endif

View File

@ -1262,7 +1262,7 @@ Highscores* World::getHighscores() const
RaceManager::get()->getNumNonGhostKarts(),
RaceManager::get()->getDifficulty(),
RaceManager::get()->getTrackName(),
RaceManager::get()->getNumLaps(),
RaceManager::get()->isLapTrialMode() ? RaceManager::get()->getTimeTarget() : RaceManager::get()->getNumLaps(),
RaceManager::get()->getReverseTrack());
return highscores;
@ -1341,9 +1341,19 @@ void World::updateHighscores(int* best_highscore_rank)
int highscore_rank = 0;
// The player is a local player, so there is a name:
if (RaceManager::get()->isLapTrialMode())
{
highscore_rank = highscores->addData(k->getIdent(),
k->getController()->getName(),
static_cast<float>(getFinishedLapsOfKart(index[pos])));
}
else
{
highscore_rank = highscores->addData(k->getIdent(),
k->getController()->getName(),
k->getFinishTime() );
}
if (highscore_rank > 0)
{

View File

@ -260,6 +260,9 @@ public:
* counting laps. */
virtual bool raceHasLaps() = 0;
// ------------------------------------------------------------------------
/** If true lap counter shows lap count in format: 4/20 or if false then in format: 4 */
virtual bool showLapsTarget() { return false; }
// ------------------------------------------------------------------------
/** Returns the number of laps for a given kart. Only valid when
* raceHasLaps() - otherwise STK will abort. */
virtual int getFinishedLapsOfKart(unsigned int kart_index) const

View File

@ -226,7 +226,7 @@ int Highscores::findHighscorePosition(const std::string& kart_name,
}
// Check if new entry is faster than than in slot 'i', if so
// move times etc and insert new entry
if(time < m_time[i])
if(RaceManager::get()->isLapTrialMode() ? (time > m_time[i]) : (time < m_time[i]))
{
for(int j=HIGHSCORE_LEN-2;j>=i;j--)
{
@ -256,6 +256,9 @@ int Highscores::addData(const std::string& kart_name,
m_track = RaceManager::get()->getTrackName();
m_number_of_karts = RaceManager::get()->getNumNonGhostKarts();
m_difficulty = RaceManager::get()->getDifficulty();
if (RaceManager::get()->isLapTrialMode())
m_number_of_laps = static_cast<int>(RaceManager::get()->getTimeTarget());
else
m_number_of_laps = RaceManager::get()->getNumLaps();
m_reverse = RaceManager::get()->getReverseTrack();
m_name[position] = name;
@ -275,7 +278,10 @@ int Highscores::addGPData(const std::string& kart_name,
m_track = track_name;
m_number_of_karts = RaceManager::get()->getNumNonGhostKarts();
m_difficulty = RaceManager::get()->getDifficulty();
m_number_of_laps = 0;
if (RaceManager::get()->isLapTrialMode())
m_number_of_laps = static_cast<int>(RaceManager::get()->getTimeTarget());
else
m_number_of_laps = RaceManager::get()->getNumLaps();
m_gp_reverse_type = RaceManager::get()->getGrandPrix().getReverseType();
m_gp_minor_mode = RaceManager::get()->getMinorMode();
m_name[position] = name;

View File

@ -47,6 +47,7 @@
#include "modes/world.hpp"
#include "modes/three_strikes_battle.hpp"
#include "modes/soccer_world.hpp"
#include "modes/lap_trial.hpp"
#include "network/protocol_manager.hpp"
#include "network/network_config.hpp"
#include "network/network_string.hpp"
@ -133,6 +134,8 @@ RaceManager::RaceManager()
m_flag_return_ticks = stk_config->time2Ticks(20.0f);
m_flag_deactivated_ticks = stk_config->time2Ticks(3.0f);
m_skipped_tracks_in_gp = 0;
m_gp_time_target = 0.0f;
m_gp_total_laps = 0;
setMaxGoal(0);
setTimeTarget(0.0f);
setReverseTrack(false);
@ -422,6 +425,12 @@ void RaceManager::startNew(bool from_overworld)
m_saved_gp->getReverseType());
m_reverse_track = m_grand_prix.getReverse();
m_skipped_tracks_in_gp = m_saved_gp->getSkippedTracks();
Log::info("RaceManager","%d",isLapTrialMode());
if (isLapTrialMode())
{
m_gp_time_target = m_saved_gp->getTimeTarget();
m_gp_total_laps = m_saved_gp->getPlayerTotalLaps();
}
} // if m_saved_gp==NULL
} // if m_continue_saved_gp
} // if !network_world
@ -637,6 +646,12 @@ void RaceManager::startNextRace()
else if(m_minor_mode==MINOR_MODE_NORMAL_RACE ||
m_minor_mode==MINOR_MODE_TIME_TRIAL)
World::setWorld(new StandardRace());
else if(m_minor_mode==MINOR_MODE_LAP_TRIAL)
{
World::setWorld(new LapTrial());
if (m_major_mode == MAJOR_MODE_GRAND_PRIX)
RaceManager::get()->setTimeTarget(m_gp_time_target);
}
else if(m_minor_mode==MINOR_MODE_TUTORIAL)
World::setWorld(new TutorialWorld());
else if (isBattleMode())
@ -766,6 +781,8 @@ void RaceManager::saveGP()
m_track_number,
m_grand_prix.getReverseType(),
m_skipped_tracks_in_gp,
isLapTrialMode() ? m_gp_time_target : 0.0f,
isLapTrialMode() ? m_gp_total_laps : 0,
m_kart_status);
// If a new GP is saved, delete any other saved data for this

View File

@ -50,6 +50,7 @@ static const std::string IDENT_SOCCER ("SOCCER" );
static const std::string IDENT_GHOST ("GHOST" );
static const std::string IDENT_OVERWORLD("OVERWORLD" );
static const std::string IDENT_CUTSCENE ("CUTSCENE" );
static const std::string IDENT_LAP_TRIAL("LAP_TRIAL" );
/**
* The race manager has two functions:
@ -121,7 +122,8 @@ public:
MINOR_MODE_OVERWORLD = MISC(0),
MINOR_MODE_TUTORIAL = MISC(1),
MINOR_MODE_CUTSCENE = MISC(2)
MINOR_MODE_CUTSCENE = MISC(2),
MINOR_MODE_LAP_TRIAL = MISC(3)
};
// ----------------------------------------------------------------------------------------
@ -144,6 +146,7 @@ public:
case MINOR_MODE_NORMAL_RACE: return IDENT_STD;
case MINOR_MODE_TIME_TRIAL: return IDENT_TTRIAL;
case MINOR_MODE_FOLLOW_LEADER: return IDENT_FTL;
case MINOR_MODE_LAP_TRIAL: return IDENT_LAP_TRIAL;
case MINOR_MODE_3_STRIKES: return IDENT_STRIKES;
case MINOR_MODE_FREE_FOR_ALL: return IDENT_FFA;
case MINOR_MODE_CAPTURE_THE_FLAG: return IDENT_CTF;
@ -165,6 +168,7 @@ public:
case MINOR_MODE_NORMAL_RACE: return "/gui/icons/mode_normal.png";
case MINOR_MODE_TIME_TRIAL: return "/gui/icons/mode_tt.png";
case MINOR_MODE_FOLLOW_LEADER: return "/gui/icons/mode_ftl.png";
case MINOR_MODE_LAP_TRIAL: return "/gui/icons/mode_normal.png"; // TODO: Add lap trial icon
case MINOR_MODE_3_STRIKES: return "/gui/icons/mode_3strikes.png";
case MINOR_MODE_FREE_FOR_ALL: return "/gui/icons/mode_weapons.png";
case MINOR_MODE_CAPTURE_THE_FLAG: return "/gui/icons/mode_weapons.png";
@ -185,6 +189,7 @@ public:
case MINOR_MODE_NORMAL_RACE: return true;
case MINOR_MODE_TIME_TRIAL: return true;
case MINOR_MODE_FOLLOW_LEADER: return true;
case MINOR_MODE_LAP_TRIAL: return true;
case MINOR_MODE_3_STRIKES: return true;
case MINOR_MODE_FREE_FOR_ALL: return false;
case MINOR_MODE_CAPTURE_THE_FLAG: return false;
@ -340,6 +345,10 @@ private:
int m_goal_target;
int m_hit_capture_limit;
int m_skipped_tracks_in_gp;
/** Time target for GP, used in Lap Trial mode */
float m_gp_time_target;
/** Total laps from every track, used in Lap Trial mode */
int m_gp_total_laps;
void startNextRace(); // start a next race
friend bool operator< (const KartStatus& left, const KartStatus& right)
@ -752,6 +761,8 @@ public:
// ----------------------------------------------------------------------------------------
bool isTimeTrialMode() const { return m_minor_mode == MINOR_MODE_TIME_TRIAL; }
// ----------------------------------------------------------------------------------------
bool isLapTrialMode() const { return m_minor_mode == MINOR_MODE_LAP_TRIAL; }
// ----------------------------------------------------------------------------------------
/** \brief Returns the number of second's decimals to display */
int currentModeTimePrecision() const
@ -905,6 +916,12 @@ public:
// ----------------------------------------------------------------------------------------
void addSkippedTrackInGP() { m_skipped_tracks_in_gp++; }
// ----------------------------------------------------------------------------------------
void setGPTimeTarget(float time_target) { m_gp_time_target = time_target; }
// ----------------------------------------------------------------------------------------
int getGPTotalLaps() const { return m_gp_total_laps; }
// ----------------------------------------------------------------------------------------
void addGPTotalLaps(int laps) { m_gp_total_laps += laps; }
// ----------------------------------------------------------------------------------------
/** Whether the current game mode allow live joining even the current game
*. started in network*/
bool supportsLiveJoining() const

View File

@ -133,6 +133,9 @@ HighScoreInfoDialog::HighScoreInfoDialog(Highscores* highscore, bool is_linear,
else
{
is_reverse = m_hs->m_reverse ? _("Yes") : _("No");
if (m_minor_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
m_num_karts_label->setText(_("Time target: %s",StringUtils::toWString(StringUtils::timeToString(m_hs->m_number_of_laps))),true);
else
m_num_laps_label->setText(_("Laps: %d", m_hs->m_number_of_laps), true);
}
@ -187,15 +190,22 @@ void HighScoreInfoDialog::updateHighscoreEntries()
{
m_hs->getEntry(n, kart_name, name, &time);
std::string time_string;
std::string highscore_string;
if (m_minor_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
{
highscore_string = std::to_string(static_cast<int>(time));
}
else
{
if (time > 60.0f * 60.0f)
{
time_string = StringUtils::timeToString(time, time_precision,
highscore_string = StringUtils::timeToString(time, time_precision,
/*display_minutes_if_zero*/true, /*display_hours*/true);
}
else
{
time_string = StringUtils::timeToString(time, time_precision);
highscore_string = StringUtils::timeToString(time, time_precision);
}
}
for(unsigned int i=0; i<kart_properties_manager->getNumberOfKarts(); i++)
@ -208,7 +218,7 @@ void HighScoreInfoDialog::updateHighscoreEntries()
}
}
line = name + " " + core::stringw(time_string.c_str());
line = name + " " + core::stringw(highscore_string.c_str());
}
else
{
@ -272,6 +282,11 @@ GUIEngine::EventPropagation
int laps = m_hs->m_number_of_laps;
RaceManager::MajorRaceModeType major_mode = m_major_mode;
if (RaceManager::get()->isLapTrialMode())
{
RaceManager::get()->setTimeTarget(static_cast<float>(m_hs->m_number_of_laps));
}
ModalDialog::dismiss();
if (major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX)
@ -283,7 +298,7 @@ GUIEngine::EventPropagation
else
{
RaceManager::get()->setReverseTrack(reverse);
RaceManager::get()->startSingleRace(track_name, laps, false);
RaceManager::get()->startSingleRace(track_name, RaceManager::get()->isLapTrialMode() ? -1 : laps, false);
}
return GUIEngine::EVENT_BLOCK;
}

View File

@ -85,6 +85,8 @@ void GPInfoScreen::loadedFromFile()
m_ai_kart_spinner = getWidget<SpinnerWidget>("ai-spinner");
m_time_target_spinner = getWidget<SpinnerWidget>("time-target-spinner");
GUIEngine::IconButtonWidget* screenshot = getWidget<IconButtonWidget>("screenshot");
screenshot->setFocusable(false);
screenshot->m_tab_stop = false;
@ -100,6 +102,7 @@ void GPInfoScreen::loadedFromFile()
video::ITexture* kart_not_found = irr_driver->getTexture(file_manager->getAsset(FileManager::GUI_ICON, "random_kart.png"));
m_unknown_kart_icon = m_icon_bank->addTextureAsSprite(kart_not_found);
} // loadedFromFile
// ----------------------------------------------------------------------------
@ -188,6 +191,11 @@ void GPInfoScreen::init()
getWidget<LabelWidget >("group-text" )->setVisible(random);
m_group_spinner->setVisible(random);
m_time_target_spinner->setVisible(RaceManager::get()->isLapTrialMode());
getWidget<LabelWidget>("time-target-text")->setVisible(RaceManager::get()->isLapTrialMode());
if (RaceManager::get()->isLapTrialMode())
m_time_target_spinner->setValue(UserConfigParams::m_lap_trial_time_limit);
// Number of AIs
// -------------
const bool has_AI = RaceManager::get()->hasAI();
@ -350,6 +358,11 @@ void GPInfoScreen::eventCallback(Widget *, const std::string &name,
RaceManager::get()->setNumKarts(local_players + num_ai);
UserConfigParams::m_num_karts_per_gamemode[RaceManager::MAJOR_MODE_GRAND_PRIX] = local_players + num_ai;
if (RaceManager::get()->isLapTrialMode())
{
RaceManager::get()->setGPTimeTarget(static_cast<int>(m_time_target_spinner->getValue()) * 60);
}
m_gp.changeReverse(getReverse());
RaceManager::get()->startGP(m_gp, false, false);
}
@ -400,6 +413,11 @@ void GPInfoScreen::eventCallback(Widget *, const std::string &name,
UserConfigParams::m_gp_reverse = reverse;
updateHighscores();
}
else if(name == "time-target-spinner")
{
UserConfigParams::m_lap_trial_time_limit = m_time_target_spinner->getValue();
updateHighscores();
}
} // eventCallback
@ -491,7 +509,13 @@ void GPInfoScreen::updateHighscores()
if(i < count)
{
highscores->getEntry(i, kart, name, &time);
std::string time_string = StringUtils::timeToString(time);
std::string highscore_string;
if (RaceManager::get()->isLapTrialMode())
highscore_string = std::to_string(static_cast<int>(time));
else
highscore_string = StringUtils::timeToString(time);
for(unsigned int n=0; n<kart_properties_manager->getNumberOfKarts(); n++)
{
const KartProperties* prop = kart_properties_manager->getKartById(n);
@ -501,7 +525,7 @@ void GPInfoScreen::updateHighscores()
break;
}
}
line = name + " " + irr::core::stringw(time_string.c_str());
line = name + " " + irr::core::stringw(highscore_string.c_str());
}
else
{

View File

@ -55,6 +55,9 @@ private:
/** Spinner for number of AI karts. */
GUIEngine::SpinnerWidget* m_ai_kart_spinner;
/** Spinner for time target in Lap Trial */
GUIEngine::SpinnerWidget* m_time_target_spinner;
/** List with last 5 highscores */
GUIEngine::ListWidget* m_highscore_list;

View File

@ -147,13 +147,16 @@ void HighScoreSelection::beforeAddingWidget()
{
m_high_scores_list_widget->addColumn(_("Game mode"),3);
}
else
else if (m_active_mode != RaceManager::MINOR_MODE_LAP_TRIAL)
{
m_high_scores_list_widget->addColumn(_C("column_name", "Laps"), 3);
}
m_high_scores_list_widget->addColumn(_C("column_name", "Reverse"), 3);
}
if (m_active_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
m_high_scores_list_widget->addColumn(_("Time limit"),4);
m_high_scores_list_widget->createHeader();
} // beforeAddingWidget
@ -199,6 +202,9 @@ void HighScoreSelection::loadList()
else if (m_active_mode == RaceManager::MINOR_MODE_EASTER_EGG &&
hs->m_highscore_type != "HST_EASTER_EGG_HUNT")
continue;
else if (m_active_mode == RaceManager::MINOR_MODE_LAP_TRIAL &&
hs->m_highscore_type != "HST_LAP_TRIAL")
continue;
}
else if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX &&
hs->m_highscore_type != "HST_GRANDPRIX")
@ -236,12 +242,12 @@ void HighScoreSelection::loadList()
getDifficultyName((RaceManager::Difficulty) hs->m_difficulty),
display_lock ? m_icon_lock : -1, 4, true));
if (m_active_mode_is_linear)
if (m_active_mode_is_linear || m_active_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
{
row.push_back(GUIEngine::ListWidget::ListCell
(StringUtils::toWString(hs->m_number_of_karts), -1, 4, true));
if (m_major_mode != RaceManager::MAJOR_MODE_GRAND_PRIX)
if (m_major_mode != RaceManager::MAJOR_MODE_GRAND_PRIX && m_active_mode != RaceManager::MINOR_MODE_LAP_TRIAL)
{
row.push_back(GUIEngine::ListWidget::ListCell
(StringUtils::toWString(hs->m_number_of_laps), -1, 3, true));
@ -259,6 +265,11 @@ void HighScoreSelection::loadList()
(hs->m_reverse ? _("Yes") : _("No"), -1, 3, true));
}
}
if (m_active_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
{
row.push_back(GUIEngine::ListWidget::ListCell(
StringUtils::toWString(StringUtils::timeToString(hs->m_number_of_laps)), -1, 4, true));
}
m_high_scores_list_widget->addItem(StringUtils::toString(i), row);
}
} // loadList
@ -316,12 +327,18 @@ void HighScoreSelection::eventCallback(GUIEngine::Widget* widget,
m_active_mode = RaceManager::MINOR_MODE_EASTER_EGG;
m_major_mode = RaceManager::MAJOR_MODE_SINGLE;
}
else if (selection == "tab_lap_trial")
{
m_active_mode = RaceManager::MINOR_MODE_LAP_TRIAL;
m_major_mode = RaceManager::MAJOR_MODE_SINGLE;
}
else if (selection == "tab_grand_prix")
{
m_active_mode = RaceManager::MINOR_MODE_NORMAL_RACE;
m_major_mode = RaceManager::MAJOR_MODE_GRAND_PRIX;
}
if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX)
if (m_major_mode == RaceManager::MAJOR_MODE_GRAND_PRIX || m_active_mode == RaceManager::MINOR_MODE_LAP_TRIAL)
m_active_mode_is_linear = true;
else
m_active_mode_is_linear = RaceManager::get()->isLinearRaceMode(m_active_mode);

View File

@ -1369,7 +1369,10 @@ void RaceGUI::drawLap(const AbstractKart* kart,
pos.LowerRightCorner.X -= icon_width;
std::ostringstream out;
if (world->showLapsTarget())
out << lap + 1 << "/" << RaceManager::get()->getNumLaps();
else
out << lap;
gui::ScalableFont* font = GUIEngine::getHighresDigitFont();
font->setBlackBorder(true);

View File

@ -207,14 +207,20 @@ void RaceResultGUI::init()
if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX &&
!NetworkConfig::get()->isNetworking() &&
(RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL))
(RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_NORMAL_RACE || RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL ||
RaceManager::get()->isLapTrialMode()))
{
const AbstractKart* k = RaceManager::get()->getKartWithGPRank(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER));
RaceManager::get()->addGPTotalLaps(World::getWorld()->getFinishedLapsOfKart(k->getWorldKartId()));
if (RaceManager::get()->getNumOfTracks() == RaceManager::get()->getTrackNumber() + 1
&& !RaceManager::get()->getGrandPrix().isRandomGP() && RaceManager::get()->getSkippedTracksInGP() == 0)
{
Highscores* highscores = World::getWorld()->getGPHighscores();
const AbstractKart* k = RaceManager::get()->getKartWithGPRank(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER));
float full_time = RaceManager::get()->getOverallTime(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER));
float full_time;
if (RaceManager::get()->isLapTrialMode())
full_time = static_cast<float>(RaceManager::get()->getGPTotalLaps());
else
full_time = RaceManager::get()->getOverallTime(RaceManager::get()->getLocalPlayerGPRank(PLAYER_ID_GAME_MASTER));
std::string gp_name = RaceManager::get()->getGrandPrix().getId();
highscores->addGPData(k->getIdent(), k->getController()->getName(), gp_name, full_time);
}
@ -1439,6 +1445,16 @@ void RaceResultGUI::unload()
NULL, true /* ignoreRTL */);
current_x += m_width_finish_time + m_width_column_space;
if (RaceManager::get()->isLapTrialMode())
{
core::recti pos_laps = core::recti(current_x, y, current_x + 100, y + 10);
int laps = World::getWorld()->getFinishedLapsOfKart(n);
m_font->draw(irr::core::stringw(laps), pos_laps, color, false, false,
NULL, true /* ignoreRTL */);
}
current_x += 100 + m_width_column_space;
// Only display points in GP mode and when the GP results are displayed.
// =====================================================================
if (RaceManager::get()->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX &&
@ -1913,8 +1929,12 @@ void RaceResultGUI::unload()
current_x = (int)(UserConfigParams::m_width * 0.85f);
// Finally draw the time
std::string time_string = StringUtils::timeToString(time, time_precision);
GUIEngine::getSmallFont()->draw(time_string.c_str(),
std::string highscore_string;
if (RaceManager::get()->isLapTrialMode())
highscore_string = std::to_string(static_cast<int>(time));
else
highscore_string = StringUtils::timeToString(time, time_precision);
GUIEngine::getSmallFont()->draw(highscore_string.c_str(),
core::recti(current_x, current_y, current_x + 100, current_y + 10),
text_color,
false, false, NULL, true /* ignoreRTL */);

View File

@ -42,6 +42,7 @@ const int CONFIG_CODE_3STRIKES = 3;
const int CONFIG_CODE_EASTER = 4;
const int CONFIG_CODE_SOCCER = 5;
const int CONFIG_CODE_GHOST = 6;
const int CONFIG_CODE_LAP_TRIAL = 7;
using namespace GUIEngine;
@ -137,6 +138,10 @@ void RaceSetupScreen::init()
name6 += _("Race against ghost karts and try to beat them!");
w2->addItem( name6, IDENT_GHOST, "/gui/icons/mode_ghost.png");
irr::core::stringw name7 = irr::core::stringw(_("Lap Trial")) + L"\n";
name7 += _("Get highest lap count in certain amount of time.");
w2->addItem(name7, IDENT_LAP_TRIAL, RaceManager::getIconOf(RaceManager::MINOR_MODE_LAP_TRIAL));
w2->updateItemDisplay();
// restore saved game mode
@ -163,6 +168,9 @@ void RaceSetupScreen::init()
case CONFIG_CODE_GHOST :
w2->setSelection(IDENT_GHOST, PLAYER_ID_GAME_MASTER, true);
break;
case CONFIG_CODE_LAP_TRIAL:
w2->setSelection(IDENT_LAP_TRIAL, PLAYER_ID_GAME_MASTER, true);
break;
}
{
@ -247,6 +255,12 @@ void RaceSetupScreen::eventCallback(Widget* widget, const std::string& name,
UserConfigParams::m_game_mode = CONFIG_CODE_GHOST;
GhostReplaySelection::getInstance()->push();
}
else if (selectedMode == IDENT_LAP_TRIAL)
{
RaceManager::get()->setMinorMode(RaceManager::MINOR_MODE_LAP_TRIAL);
UserConfigParams::m_game_mode = CONFIG_CODE_LAP_TRIAL;
TracksAndGPScreen::getInstance()->push();
}
else if (selectedMode == "locked")
{
unlock_manager->playLockSound();

View File

@ -113,6 +113,7 @@ void TrackInfoScreen::loadedFromFile()
void TrackInfoScreen::beforeAddingWidget()
{
m_is_soccer = RaceManager::get()->isSoccerMode();
m_is_lap_trial = RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_LAP_TRIAL;
m_show_ffa_spinner = RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_3_STRIKES
|| RaceManager::get()->getMinorMode() == RaceManager::MINOR_MODE_FREE_FOR_ALL;
@ -275,6 +276,14 @@ void TrackInfoScreen::init()
m_target_value_label->setText(_("Number of laps"), false);
}
if (m_is_lap_trial)
{
m_target_value_spinner->setVisible(true);
m_target_value_label->setVisible(true);
m_target_value_label->setText(_("Maximum time (min.)"), false);
m_target_value_spinner->setValue(UserConfigParams::m_lap_trial_time_limit);
}
// Reverse track or random item in arena
// -------------
const bool reverse_available = m_track->reverseAvailable()
@ -483,7 +492,7 @@ void TrackInfoScreen::updateHighScores()
RaceManager::get()->getNumberOfKarts(),
RaceManager::get()->getDifficulty(),
m_track->getIdent(),
RaceManager::get()->getNumLaps(),
RaceManager::get()->isLapTrialMode() ? m_target_value_spinner->getValue() * 60 : RaceManager::get()->getNumLaps(),
RaceManager::get()->getReverseTrack() );
const int amount = highscores->getNumberEntries();
@ -506,7 +515,11 @@ void TrackInfoScreen::updateHighScores()
{
highscores->getEntry(n, kart_name, name, &time);
std::string time_string = StringUtils::timeToString(time, time_precision);
std::string highscore_string;
if (RaceManager::get()->isLapTrialMode())
highscore_string = std::to_string(static_cast<int>(time));
else
highscore_string = StringUtils::timeToString(time, time_precision);
for(unsigned int i=0; i<kart_properties_manager->getNumberOfKarts(); i++)
{
@ -518,7 +531,7 @@ void TrackInfoScreen::updateHighScores()
}
}
line = name + " " + core::stringw(time_string.c_str());
line = name + " " + core::stringw(highscore_string.c_str());
}
else
{
@ -596,6 +609,12 @@ void TrackInfoScreen::onEnterPressedInternal()
RaceManager::get()->setMaxGoal(selected_target_value);
}
if (m_is_lap_trial)
{
RaceManager::get()->setMinorMode(RaceManager::MINOR_MODE_LAP_TRIAL);
RaceManager::get()->setTimeTarget(static_cast<float>(selected_target_value) * 60);
}
if (UserConfigParams::m_num_karts_per_gamemode
[RaceManager::get()->getMinorMode()] != unsigned(local_players + num_ai))
{
@ -667,6 +686,11 @@ void TrackInfoScreen::eventCallback(Widget* widget, const std::string& name,
if (enable_ffa)
UserConfigParams::m_ffa_time_limit = m_target_value_spinner->getValue();
}
else if (m_is_lap_trial)
{
UserConfigParams::m_lap_trial_time_limit = m_target_value_spinner->getValue();
updateHighScores();
}
else
{
assert(RaceManager::get()->modeHasLaps());

View File

@ -49,6 +49,8 @@ class TrackInfoScreen : public GUIEngine::Screen,
bool m_is_soccer;
bool m_is_lap_trial;
bool m_show_ffa_spinner;
// When there is no need to tab through / click on images/labels, we can add directly