2010-07-15 18:41:41 -04:00
|
|
|
//
|
|
|
|
// SuperTuxKart - a fun racing game with go-kart
|
2015-03-29 20:31:42 -04:00
|
|
|
// Copyright (C) 2010-2015 Joerg Henrichs
|
2010-07-15 18:41:41 -04:00
|
|
|
//
|
|
|
|
// 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 "states_screens/race_result_gui.hpp"
|
|
|
|
|
2011-05-20 21:07:06 -04:00
|
|
|
#include "audio/music_manager.hpp"
|
2014-09-17 07:38:21 -04:00
|
|
|
#include "audio/sfx_manager.hpp"
|
2011-05-20 21:07:06 -04:00
|
|
|
#include "audio/sfx_base.hpp"
|
2010-08-24 19:19:14 -04:00
|
|
|
#include "challenges/unlock_manager.hpp"
|
2014-02-09 07:22:45 -05:00
|
|
|
#include "config/player_manager.hpp"
|
2014-02-25 20:52:16 -05:00
|
|
|
#include "config/user_config.hpp"
|
2014-10-18 12:16:50 -04:00
|
|
|
#include "graphics/2dutils.hpp"
|
2011-05-22 15:29:52 -04:00
|
|
|
#include "graphics/material.hpp"
|
2010-07-15 18:41:41 -04:00
|
|
|
#include "guiengine/engine.hpp"
|
2018-04-21 04:00:14 -04:00
|
|
|
#include "guiengine/message_queue.hpp"
|
2013-02-16 19:20:40 -05:00
|
|
|
#include "guiengine/modaldialog.hpp"
|
2010-07-20 20:01:22 -04:00
|
|
|
#include "guiengine/scalable_font.hpp"
|
2010-08-24 19:19:14 -04:00
|
|
|
#include "guiengine/widget.hpp"
|
2011-10-07 19:25:02 -04:00
|
|
|
#include "guiengine/widgets/icon_button_widget.hpp"
|
2014-03-26 20:14:29 -04:00
|
|
|
#include "guiengine/widgets/label_widget.hpp"
|
2010-09-13 21:28:19 -04:00
|
|
|
#include "io/file_manager.hpp"
|
2012-03-19 16:21:11 -04:00
|
|
|
#include "karts/abstract_kart.hpp"
|
2012-03-08 17:56:33 -05:00
|
|
|
#include "karts/controller/controller.hpp"
|
2016-05-06 02:47:36 -04:00
|
|
|
#include "karts/controller/end_controller.hpp"
|
|
|
|
#include "karts/controller/local_player_controller.hpp"
|
2012-03-19 16:21:11 -04:00
|
|
|
#include "karts/kart_properties.hpp"
|
2012-10-20 15:01:45 -04:00
|
|
|
#include "karts/kart_properties_manager.hpp"
|
2012-09-13 20:03:38 -04:00
|
|
|
#include "modes/cutscene_world.hpp"
|
2012-05-06 20:10:33 -04:00
|
|
|
#include "modes/demo_world.hpp"
|
2018-08-12 12:59:20 -04:00
|
|
|
#include "modes/free_for_all.hpp"
|
2012-04-01 11:42:44 -04:00
|
|
|
#include "modes/overworld.hpp"
|
2013-09-14 15:20:08 -04:00
|
|
|
#include "modes/soccer_world.hpp"
|
2018-03-09 08:17:31 -05:00
|
|
|
#include "network/network_config.hpp"
|
2018-03-08 00:19:24 -05:00
|
|
|
#include "network/stk_host.hpp"
|
2016-11-22 17:39:33 -05:00
|
|
|
#include "network/protocols/client_lobby.hpp"
|
2012-10-20 15:01:45 -04:00
|
|
|
#include "race/highscores.hpp"
|
2018-05-13 20:51:52 -04:00
|
|
|
#include "replay/replay_play.hpp"
|
|
|
|
#include "replay/replay_recorder.hpp"
|
2015-12-05 19:42:06 -05:00
|
|
|
#include "scriptengine/property_animator.hpp"
|
2011-01-03 13:23:52 -05:00
|
|
|
#include "states_screens/feature_unlocked.hpp"
|
2010-08-24 19:19:14 -04:00
|
|
|
#include "states_screens/main_menu_screen.hpp"
|
2018-04-22 02:32:41 -04:00
|
|
|
#include "states_screens/networking_lobby.hpp"
|
2010-08-24 19:33:30 -04:00
|
|
|
#include "states_screens/race_setup_screen.hpp"
|
2011-10-07 19:25:02 -04:00
|
|
|
#include "tracks/track.hpp"
|
|
|
|
#include "tracks/track_manager.hpp"
|
2010-07-15 18:41:41 -04:00
|
|
|
#include "utils/string_utils.hpp"
|
2013-10-14 09:27:42 -04:00
|
|
|
#include <algorithm>
|
2010-07-15 18:41:41 -04:00
|
|
|
|
|
|
|
/** Constructor, initialises internal data structures.
|
|
|
|
*/
|
2013-05-29 18:04:35 -04:00
|
|
|
RaceResultGUI::RaceResultGUI() : Screen("race_result.stkgui",
|
2016-03-17 02:19:21 -04:00
|
|
|
/*pause race*/ false)
|
2010-07-15 18:41:41 -04:00
|
|
|
{
|
|
|
|
} // RaceResultGUI
|
|
|
|
|
2010-08-24 19:19:14 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
/** Besides calling init in the base class this makes all buttons of this
|
|
|
|
* screen invisible. The buttons will only displayed once the animation is
|
2010-08-24 20:58:45 -04:00
|
|
|
* over.
|
2010-08-24 19:19:14 -04:00
|
|
|
*/
|
|
|
|
void RaceResultGUI::init()
|
|
|
|
{
|
|
|
|
Screen::init();
|
|
|
|
determineTableLayout();
|
|
|
|
m_animation_state = RR_INIT;
|
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_timer = 0;
|
2010-08-24 19:19:14 -04:00
|
|
|
|
|
|
|
getWidget("top")->setVisible(false);
|
|
|
|
getWidget("middle")->setVisible(false);
|
|
|
|
getWidget("bottom")->setVisible(false);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-05-20 21:07:06 -04:00
|
|
|
music_manager->stopMusic();
|
2016-01-01 00:31:15 -05:00
|
|
|
|
|
|
|
bool human_win = true;
|
|
|
|
unsigned int num_karts = race_manager->getNumberOfKarts();
|
|
|
|
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
|
|
|
|
{
|
|
|
|
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
|
2018-04-21 04:00:14 -04:00
|
|
|
if (kart->getController()->isLocalPlayerController())
|
2016-01-01 00:31:15 -05:00
|
|
|
human_win = human_win && kart->getRaceResult();
|
|
|
|
}
|
|
|
|
|
2016-01-02 21:19:51 -05:00
|
|
|
m_finish_sound = SFXManager::get()->quickSound(
|
2016-06-24 20:22:48 -04:00
|
|
|
human_win ? "race_finish_victory" : "race_finish");
|
2016-01-02 21:19:51 -05:00
|
|
|
|
|
|
|
//std::string path = (human_win ? Different result music too later
|
|
|
|
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music") :
|
|
|
|
// file_manager->getAsset(FileManager::MUSIC, "race_summary.music"));
|
|
|
|
std::string path = file_manager->getAsset(FileManager::MUSIC, "race_summary.music");
|
2016-01-01 00:31:15 -05:00
|
|
|
m_race_over_music = music_manager->getMusicInformation(path);
|
|
|
|
|
2015-02-11 15:57:51 -05:00
|
|
|
if (!m_finish_sound)
|
|
|
|
{
|
|
|
|
// If there is no finish sound (because sfx are disabled), start
|
|
|
|
// the race over music here (since the race over music is only started
|
|
|
|
// when the finish sound has been played).
|
|
|
|
music_manager->startMusic(m_race_over_music);
|
|
|
|
}
|
2014-03-26 20:14:29 -04:00
|
|
|
|
|
|
|
// Calculate how many track screenshots can fit into the "result-table" widget
|
|
|
|
GUIEngine::Widget* result_table = getWidget("result-table");
|
|
|
|
assert(result_table != NULL);
|
|
|
|
m_sshot_height = (int)(UserConfigParams::m_height*0.1275);
|
2016-03-17 02:19:21 -04:00
|
|
|
m_max_tracks = std::max(1, ((result_table->m_h - getFontHeight() * 5) /
|
2014-03-26 20:14:29 -04:00
|
|
|
(m_sshot_height + SSHOT_SEPARATION))); //Show at least one
|
|
|
|
|
|
|
|
// Calculate screenshot scrolling parameters
|
2014-04-13 15:34:28 -04:00
|
|
|
const std::vector<std::string> tracks =
|
2014-07-07 23:20:53 -04:00
|
|
|
race_manager->getGrandPrix().getTrackNames();
|
2014-09-23 02:23:22 -04:00
|
|
|
int n_tracks = (int)tracks.size();
|
2014-03-26 20:14:29 -04:00
|
|
|
int currentTrack = race_manager->getTrackNumber();
|
|
|
|
m_start_track = currentTrack;
|
2014-03-28 19:16:56 -04:00
|
|
|
if (n_tracks > m_max_tracks)
|
2014-03-26 20:14:29 -04:00
|
|
|
{
|
2014-03-28 19:16:56 -04:00
|
|
|
m_start_track = std::min(currentTrack, n_tracks - m_max_tracks);
|
|
|
|
m_end_track = std::min(currentTrack + m_max_tracks, n_tracks);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-04-13 15:34:28 -04:00
|
|
|
m_start_track = 0;
|
2017-04-08 09:25:33 -04:00
|
|
|
m_end_track = (int)tracks.size();
|
2014-03-26 20:14:29 -04:00
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
} // init
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::tearDown()
|
|
|
|
{
|
|
|
|
Screen::tearDown();
|
2016-07-18 11:00:40 -04:00
|
|
|
//m_font->setMonospaceDigits(m_was_monospace);
|
2013-10-22 15:05:03 -04:00
|
|
|
|
|
|
|
if (m_finish_sound != NULL &&
|
2014-10-13 17:05:04 -04:00
|
|
|
m_finish_sound->getStatus() == SFXBase::SFX_PLAYING)
|
2013-10-22 15:05:03 -04:00
|
|
|
{
|
|
|
|
m_finish_sound->stop();
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
} // tearDown
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2010-08-24 19:19:14 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Makes the correct buttons visible again, and gives them the right label.
|
|
|
|
* 1) If something was unlocked, only a 'next' button is displayed.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::enableAllButtons()
|
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
GUIEngine::Widget *top = getWidget("top");
|
2010-08-29 19:17:56 -04:00
|
|
|
GUIEngine::Widget *middle = getWidget("middle");
|
|
|
|
GUIEngine::Widget *bottom = getWidget("bottom");
|
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
2011-11-07 20:50:31 -05:00
|
|
|
{
|
|
|
|
enableGPProgress();
|
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2013-08-26 10:14:52 -04:00
|
|
|
// If we're in a network world, change the buttons text
|
2013-08-29 13:57:56 -04:00
|
|
|
if (World::getWorld()->isNetworkWorld())
|
2013-08-26 10:14:52 -04:00
|
|
|
{
|
|
|
|
top->setVisible(false);
|
2018-03-08 00:19:24 -05:00
|
|
|
middle->setText(_("Continue"));
|
2013-08-26 10:14:52 -04:00
|
|
|
middle->setVisible(true);
|
|
|
|
middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
2018-03-08 00:19:24 -05:00
|
|
|
bottom->setText(_("Quit the server"));
|
2013-08-26 10:14:52 -04:00
|
|
|
bottom->setVisible(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-08-24 19:19:14 -04:00
|
|
|
// If something was unlocked
|
|
|
|
// -------------------------
|
2014-09-23 00:41:32 -04:00
|
|
|
int n = (int)PlayerManager::getCurrentPlayer()->getRecentlyCompletedChallenges().size();
|
2016-03-17 02:19:21 -04:00
|
|
|
if (n > 0)
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
top->setText(n == 1 ? _("You completed a challenge!")
|
|
|
|
: _("You completed challenges!"));
|
2010-08-24 19:19:14 -04:00
|
|
|
top->setVisible(true);
|
2011-08-21 12:54:50 -04:00
|
|
|
top->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
else if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
2010-08-26 06:16:58 -04:00
|
|
|
{
|
2010-08-29 19:17:56 -04:00
|
|
|
// In case of a GP:
|
|
|
|
// ----------------
|
2010-12-20 12:52:39 -05:00
|
|
|
top->setVisible(false);
|
2017-11-08 19:11:29 -05:00
|
|
|
top->setFocusable(false);
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
middle->setText(_("Continue"));
|
2010-08-24 19:19:14 -04:00
|
|
|
middle->setVisible(true);
|
|
|
|
|
2017-10-31 19:15:57 -04:00
|
|
|
if (race_manager->getTrackNumber() + 1 < race_manager->getNumOfTracks())
|
|
|
|
{
|
|
|
|
bottom->setText(_("Abort Grand Prix"));
|
|
|
|
bottom->setVisible(true);
|
2017-11-08 19:11:29 -05:00
|
|
|
bottom->setFocusable(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bottom->setFocusable(false);
|
2017-10-31 19:15:57 -04:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2011-08-21 12:54:50 -04:00
|
|
|
middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
2010-08-26 06:16:58 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Normal race
|
|
|
|
// -----------
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
middle->setText(_("Restart"));
|
2010-08-26 06:16:58 -04:00
|
|
|
middle->setVisible(true);
|
2017-10-29 13:34:40 -04:00
|
|
|
middle->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
2012-04-01 11:42:44 -04:00
|
|
|
if (race_manager->raceWasStartedFromOverworld())
|
|
|
|
{
|
2013-05-16 02:53:01 -04:00
|
|
|
top->setVisible(false);
|
2016-03-17 02:19:21 -04:00
|
|
|
bottom->setText(_("Back to challenge selection"));
|
2012-04-01 11:42:44 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-13 20:51:52 -04:00
|
|
|
if (race_manager->isRecordingRace())
|
|
|
|
top->setText(_("Race against the new ghost replay"));
|
|
|
|
else
|
|
|
|
top->setText(_("Setup New Race"));
|
2013-05-16 02:53:01 -04:00
|
|
|
top->setVisible(true);
|
2016-03-17 02:19:21 -04:00
|
|
|
bottom->setText(_("Back to the menu"));
|
2012-04-01 11:42:44 -04:00
|
|
|
}
|
2010-08-26 06:16:58 -04:00
|
|
|
bottom->setVisible(true);
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
} // enableAllButtons
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2013-05-29 18:04:35 -04:00
|
|
|
void RaceResultGUI::eventCallback(GUIEngine::Widget* widget,
|
2016-03-17 02:19:21 -04:00
|
|
|
const std::string& name, const int playerID)
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2014-07-07 23:20:53 -04:00
|
|
|
int n_tracks = race_manager->getGrandPrix().getNumberOfTracks();
|
2014-03-26 20:14:29 -04:00
|
|
|
if (name == "up_button" && n_tracks > m_max_tracks && m_start_track > 0)
|
|
|
|
{
|
|
|
|
m_start_track--;
|
|
|
|
m_end_track--;
|
|
|
|
displayScreenShots();
|
|
|
|
}
|
|
|
|
else if (name == "down_button" && n_tracks > m_max_tracks &&
|
|
|
|
m_start_track < (n_tracks - m_max_tracks))
|
|
|
|
{
|
|
|
|
m_start_track++;
|
|
|
|
m_end_track++;
|
|
|
|
displayScreenShots();
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2018-04-21 04:00:14 -04:00
|
|
|
// If we're playing online :
|
|
|
|
if (World::getWorld()->isNetworkWorld())
|
|
|
|
{
|
|
|
|
if (name == "middle") // Continue button (return to server lobby)
|
|
|
|
{
|
|
|
|
// Signal to the server that this client is back in the lobby now.
|
|
|
|
auto cl = LobbyProtocol::get<ClientLobby>();
|
|
|
|
if (cl)
|
|
|
|
cl->doneWithResults();
|
|
|
|
getWidget("middle")->setText(_("Waiting for others"));
|
|
|
|
}
|
|
|
|
if (name == "bottom") // Quit server (return to online lan / wan menu)
|
|
|
|
{
|
|
|
|
race_manager->clearNetworkGrandPrixResult();
|
|
|
|
if (STKHost::existHost())
|
|
|
|
{
|
|
|
|
STKHost::get()->shutdown();
|
|
|
|
}
|
|
|
|
race_manager->exitRace();
|
|
|
|
race_manager->setAIKartOverride("");
|
|
|
|
StateManager::get()->resetAndSetStack(
|
|
|
|
NetworkConfig::get()->getResetScreens().data());
|
|
|
|
NetworkConfig::get()->unsetNetworking();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
// If something was unlocked, the 'continue' button was
|
2010-08-24 19:19:14 -04:00
|
|
|
// actually used to display "Show unlocked feature(s)" text.
|
|
|
|
// ---------------------------------------------------------
|
2014-09-23 00:41:32 -04:00
|
|
|
int n = (int)PlayerManager::getCurrentPlayer()
|
2016-03-17 02:19:21 -04:00
|
|
|
->getRecentlyCompletedChallenges().size();
|
|
|
|
if (n>0)
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
if (name == "top")
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2011-11-07 20:50:31 -05:00
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
{
|
|
|
|
cleanupGPProgress();
|
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
|
|
|
std::vector<const ChallengeData*> unlocked =
|
2014-04-07 18:06:52 -04:00
|
|
|
PlayerManager::getCurrentPlayer()->getRecentlyCompletedChallenges();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-09-13 20:03:38 -04:00
|
|
|
bool gameCompleted = false;
|
|
|
|
for (unsigned int n = 0; n < unlocked.size(); n++)
|
|
|
|
{
|
SuperTux in Story Mode (and other improvements) (#3207)
* Add SuperTux difficulty & update number of karts
Also make the expert challenge slightly easier to match more the difficulty of other challenges.
* Add SuperTux difficulty & update number of karts & points required
Also give some more time margin in easier difficulties, as it is a hard challenge compared to most.
* Add SuperTux difficulty & update number of karts & points required
Also change the lap count to 4 as it is a very short track (sub 30s)
* Add SuperTux difficulty
Also tweak the expert challenge to have a more appropriate difficulty
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also correct the requirement position, since this is not a FTL race anymore.
* Add SuperTux difficulty & update number of karts & points required
Also slight balancing improvements for the usual difficulties.
* Add SuperTux difficulty & update number of karts & points required
Also adds a position requirement in expert
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 5, as this is a very short track. The time requirements for easier difficulties have been kept proportionally similar to before.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4.
* Add SuperTux difficulty & update number of karts & points required
Also add a position requirement to expert and intermediate.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4, as a lap often is 30s or less in expert/supertux
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Rename islandtrack.challenge to gran_paradiso.challenge
* Rename challenge file
* Add SuperTux difficulty & update number of karts & points required
Also makes the time limit in expert less easy and tweak position requirement.
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Doesn't unlock the SuperTux difficulty anymore - it's managed elsewhere.
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add new unlock challenges, for difficulty and karts
* Add a lap to oliver's math class
* Replace Northern Resort by Volcano Island
* Replace Volcano Island by Candela City
Candela City was in no (official) GP before this.
Also sets Green Valley to 3 laps.
* Add Northern Resort and remove Fort Magma
In 0.9.3, this GP has only 4 races in Story Mode (5 for the other GPs) because Fort Magma is locked.
Of all the tracks outside this GP before, Northern Resort is one of the hardest, the AI being rather good there.
* Temporary cup for SuperTux challenges
Recolored version of the gold cup
* Update challenge selection UI for the SuperTux challenges
* GUI used before SuperTux difficulty unlocking
This is the old select_challenge.stkgui
* Swap the two sara
* Replace Kiki by another kart to unlock on Benau's demand
* Update for improved Story Mode
* Update for improved Story Mode
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Update for SuperTux ; also adds the ability to unlock a challenge by points
* Update for unlocking by points
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Minor changes to function calls
* Update for SuperTux challenges
* Add support for SuperTux challenges
* Update for Story Mode GP changes
* Allows to display the correct number of points for GP challenges
* Set the unlock of the 1st bonus kart to correct non-test value
* Add support for SuperTux challenges
Including a bigger challenge selection diaolg
* Add default value
* Icon to indicate that there is an unlockable
The number of points needed to unlock it are displayed next to it.
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Function for unlock by points UI
* Add default for unlock list node and use requirements node for all
* Make unlockByPoints simpler and more flexible
Now the code will iterate in StoryModeStatus and send the unlock_list challenges for treatment here. The question of getting the right challenge statuses beings solved, it allows for a great simplification and much more flexibility
* Update unlockByPoints declaration
* Adds support for next unlockable UI
* Improve call of unlockByPoints
Also calculations for displaying in the UI how many point the next unlockable by points requires.
* Add icon for next unlockable
* Displays icon/number to make the player aware of the next unlockable
Also displays the number below the icon rather than on the side, for more clarity.
* Changes to display karts in the unlock scene
* Update unlock functions declarations
* New function to clarify code and more logical recently unlocked list management
In the previous version, everything was added to the recently unlocked list at some point, necessitating a clearing at the end of computeActive, which also removed from the list the non-race challenges. Checking if the feature is newly unlocked to add it to the list remove the need of that clearing.
* Declaration for unlockFeatureByList
* Display newly unlocked karts
* Display newly unlocked karts
* Clear the list of recently unlocked features at the end
* Update testing code
* Update unlocks finding function call
* Improve UI scaling
* Fixes indentation
* Update the number of points before checking for unlock by points
* Add const to declarations
* Remove const_cast
* Remove a const_cast
There are other const_cast in the menu debug items (but they are unrelated to this PR)
* Fix menu being bolder
2018-04-29 18:27:03 -04:00
|
|
|
if (unlocked[n]->getChallengeId() == "fortmagma")
|
2012-09-13 20:03:38 -04:00
|
|
|
{
|
|
|
|
gameCompleted = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-09-13 20:03:38 -04:00
|
|
|
if (gameCompleted)
|
|
|
|
{
|
|
|
|
// clear the race
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-11-10 19:15:03 -05:00
|
|
|
// kart will no longer be available during cutscene, drop reference
|
|
|
|
StateManager::get()->getActivePlayer(playerID)->setKart(NULL);
|
2015-12-05 19:42:06 -05:00
|
|
|
PropertyAnimator::get()->clear();
|
2012-09-13 20:03:38 -04:00
|
|
|
World::deleteWorld();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2014-11-05 18:13:47 -05:00
|
|
|
CutsceneWorld::setUseDuration(true);
|
2012-09-13 20:03:38 -04:00
|
|
|
StateManager::get()->enterGameState();
|
|
|
|
race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE);
|
2016-03-17 02:19:21 -04:00
|
|
|
race_manager->setNumKarts(0);
|
2012-09-13 20:03:38 -04:00
|
|
|
race_manager->setNumPlayers(0);
|
|
|
|
race_manager->startSingleRace("endcutscene", 999, false);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-09-13 20:03:38 -04:00
|
|
|
std::vector<std::string> parts;
|
|
|
|
parts.push_back("endcutscene");
|
|
|
|
((CutsceneWorld*)World::getWorld())->setParts(parts);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-06-07 19:51:34 -04:00
|
|
|
StateManager::get()->popMenu();
|
2015-12-05 19:42:06 -05:00
|
|
|
PropertyAnimator::get()->clear();
|
2014-06-07 19:51:34 -04:00
|
|
|
World::deleteWorld();
|
|
|
|
|
2015-01-05 19:36:04 -05:00
|
|
|
CutsceneWorld::setUseDuration(false);
|
2014-06-07 19:51:34 -04:00
|
|
|
StateManager::get()->enterGameState();
|
|
|
|
race_manager->setMinorMode(RaceManager::MINOR_MODE_CUTSCENE);
|
|
|
|
race_manager->setNumKarts(0);
|
|
|
|
race_manager->setNumPlayers(0);
|
2014-11-17 19:07:37 -05:00
|
|
|
race_manager->startSingleRace("featunlocked", 999, race_manager->raceWasStartedFromOverworld());
|
2014-06-07 19:51:34 -04:00
|
|
|
|
2013-05-29 18:04:35 -04:00
|
|
|
FeatureUnlockedCutScene* scene =
|
2012-09-13 20:03:38 -04:00
|
|
|
FeatureUnlockedCutScene::getInstance();
|
2014-06-05 20:06:27 -04:00
|
|
|
|
SuperTux in Story Mode (and other improvements) (#3207)
* Add SuperTux difficulty & update number of karts
Also make the expert challenge slightly easier to match more the difficulty of other challenges.
* Add SuperTux difficulty & update number of karts & points required
Also give some more time margin in easier difficulties, as it is a hard challenge compared to most.
* Add SuperTux difficulty & update number of karts & points required
Also change the lap count to 4 as it is a very short track (sub 30s)
* Add SuperTux difficulty
Also tweak the expert challenge to have a more appropriate difficulty
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also correct the requirement position, since this is not a FTL race anymore.
* Add SuperTux difficulty & update number of karts & points required
Also slight balancing improvements for the usual difficulties.
* Add SuperTux difficulty & update number of karts & points required
Also adds a position requirement in expert
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 5, as this is a very short track. The time requirements for easier difficulties have been kept proportionally similar to before.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4.
* Add SuperTux difficulty & update number of karts & points required
Also add a position requirement to expert and intermediate.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4, as a lap often is 30s or less in expert/supertux
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Rename islandtrack.challenge to gran_paradiso.challenge
* Rename challenge file
* Add SuperTux difficulty & update number of karts & points required
Also makes the time limit in expert less easy and tweak position requirement.
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Doesn't unlock the SuperTux difficulty anymore - it's managed elsewhere.
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add new unlock challenges, for difficulty and karts
* Add a lap to oliver's math class
* Replace Northern Resort by Volcano Island
* Replace Volcano Island by Candela City
Candela City was in no (official) GP before this.
Also sets Green Valley to 3 laps.
* Add Northern Resort and remove Fort Magma
In 0.9.3, this GP has only 4 races in Story Mode (5 for the other GPs) because Fort Magma is locked.
Of all the tracks outside this GP before, Northern Resort is one of the hardest, the AI being rather good there.
* Temporary cup for SuperTux challenges
Recolored version of the gold cup
* Update challenge selection UI for the SuperTux challenges
* GUI used before SuperTux difficulty unlocking
This is the old select_challenge.stkgui
* Swap the two sara
* Replace Kiki by another kart to unlock on Benau's demand
* Update for improved Story Mode
* Update for improved Story Mode
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Update for SuperTux ; also adds the ability to unlock a challenge by points
* Update for unlocking by points
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Minor changes to function calls
* Update for SuperTux challenges
* Add support for SuperTux challenges
* Update for Story Mode GP changes
* Allows to display the correct number of points for GP challenges
* Set the unlock of the 1st bonus kart to correct non-test value
* Add support for SuperTux challenges
Including a bigger challenge selection diaolg
* Add default value
* Icon to indicate that there is an unlockable
The number of points needed to unlock it are displayed next to it.
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Function for unlock by points UI
* Add default for unlock list node and use requirements node for all
* Make unlockByPoints simpler and more flexible
Now the code will iterate in StoryModeStatus and send the unlock_list challenges for treatment here. The question of getting the right challenge statuses beings solved, it allows for a great simplification and much more flexibility
* Update unlockByPoints declaration
* Adds support for next unlockable UI
* Improve call of unlockByPoints
Also calculations for displaying in the UI how many point the next unlockable by points requires.
* Add icon for next unlockable
* Displays icon/number to make the player aware of the next unlockable
Also displays the number below the icon rather than on the side, for more clarity.
* Changes to display karts in the unlock scene
* Update unlock functions declarations
* New function to clarify code and more logical recently unlocked list management
In the previous version, everything was added to the recently unlocked list at some point, necessitating a clearing at the end of computeActive, which also removed from the list the non-race challenges. Checking if the feature is newly unlocked to add it to the list remove the need of that clearing.
* Declaration for unlockFeatureByList
* Display newly unlocked karts
* Display newly unlocked karts
* Clear the list of recently unlocked features at the end
* Update testing code
* Update unlocks finding function call
* Improve UI scaling
* Fixes indentation
* Update the number of points before checking for unlock by points
* Add const to declarations
* Remove const_cast
* Remove a const_cast
There are other const_cast in the menu debug items (but they are unrelated to this PR)
* Fix menu being bolder
2018-04-29 18:27:03 -04:00
|
|
|
scene->addTrophy(race_manager->getDifficulty(),false);
|
|
|
|
scene->findWhatWasUnlocked(race_manager->getDifficulty(),unlocked);
|
2014-09-23 02:43:50 -04:00
|
|
|
scene->push();
|
2012-12-06 19:24:20 -05:00
|
|
|
race_manager->setAIKartOverride("");
|
2014-06-07 19:51:34 -04:00
|
|
|
|
|
|
|
std::vector<std::string> parts;
|
|
|
|
parts.push_back("featunlocked");
|
|
|
|
((CutsceneWorld*)World::getWorld())->setParts(parts);
|
2012-09-13 20:03:38 -04:00
|
|
|
}
|
SuperTux in Story Mode (and other improvements) (#3207)
* Add SuperTux difficulty & update number of karts
Also make the expert challenge slightly easier to match more the difficulty of other challenges.
* Add SuperTux difficulty & update number of karts & points required
Also give some more time margin in easier difficulties, as it is a hard challenge compared to most.
* Add SuperTux difficulty & update number of karts & points required
Also change the lap count to 4 as it is a very short track (sub 30s)
* Add SuperTux difficulty
Also tweak the expert challenge to have a more appropriate difficulty
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also correct the requirement position, since this is not a FTL race anymore.
* Add SuperTux difficulty & update number of karts & points required
Also slight balancing improvements for the usual difficulties.
* Add SuperTux difficulty & update number of karts & points required
Also adds a position requirement in expert
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 5, as this is a very short track. The time requirements for easier difficulties have been kept proportionally similar to before.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4.
* Add SuperTux difficulty & update number of karts & points required
Also add a position requirement to expert and intermediate.
* Add SuperTux difficulty & update number of karts & points required
Also change the number of laps to 4, as a lap often is 30s or less in expert/supertux
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Rename islandtrack.challenge to gran_paradiso.challenge
* Rename challenge file
* Add SuperTux difficulty & update number of karts & points required
Also makes the time limit in expert less easy and tweak position requirement.
* Add SuperTux difficulty & update number of karts
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
Doesn't unlock the SuperTux difficulty anymore - it's managed elsewhere.
* Add SuperTux difficulty & update number of karts & points required
* Add SuperTux difficulty & update number of karts & points required
* Add new unlock challenges, for difficulty and karts
* Add a lap to oliver's math class
* Replace Northern Resort by Volcano Island
* Replace Volcano Island by Candela City
Candela City was in no (official) GP before this.
Also sets Green Valley to 3 laps.
* Add Northern Resort and remove Fort Magma
In 0.9.3, this GP has only 4 races in Story Mode (5 for the other GPs) because Fort Magma is locked.
Of all the tracks outside this GP before, Northern Resort is one of the hardest, the AI being rather good there.
* Temporary cup for SuperTux challenges
Recolored version of the gold cup
* Update challenge selection UI for the SuperTux challenges
* GUI used before SuperTux difficulty unlocking
This is the old select_challenge.stkgui
* Swap the two sara
* Replace Kiki by another kart to unlock on Benau's demand
* Update for improved Story Mode
* Update for improved Story Mode
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Update for SuperTux ; also adds the ability to unlock a challenge by points
* Update for unlocking by points
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Add support for SuperTux challenges
* Minor changes to function calls
* Update for SuperTux challenges
* Add support for SuperTux challenges
* Update for Story Mode GP changes
* Allows to display the correct number of points for GP challenges
* Set the unlock of the 1st bonus kart to correct non-test value
* Add support for SuperTux challenges
Including a bigger challenge selection diaolg
* Add default value
* Icon to indicate that there is an unlockable
The number of points needed to unlock it are displayed next to it.
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Changed format : the point requirements is now specified in the file
* Function for unlock by points UI
* Add default for unlock list node and use requirements node for all
* Make unlockByPoints simpler and more flexible
Now the code will iterate in StoryModeStatus and send the unlock_list challenges for treatment here. The question of getting the right challenge statuses beings solved, it allows for a great simplification and much more flexibility
* Update unlockByPoints declaration
* Adds support for next unlockable UI
* Improve call of unlockByPoints
Also calculations for displaying in the UI how many point the next unlockable by points requires.
* Add icon for next unlockable
* Displays icon/number to make the player aware of the next unlockable
Also displays the number below the icon rather than on the side, for more clarity.
* Changes to display karts in the unlock scene
* Update unlock functions declarations
* New function to clarify code and more logical recently unlocked list management
In the previous version, everything was added to the recently unlocked list at some point, necessitating a clearing at the end of computeActive, which also removed from the list the non-race challenges. Checking if the feature is newly unlocked to add it to the list remove the need of that clearing.
* Declaration for unlockFeatureByList
* Display newly unlocked karts
* Display newly unlocked karts
* Clear the list of recently unlocked features at the end
* Update testing code
* Update unlocks finding function call
* Improve UI scaling
* Fixes indentation
* Update the number of points before checking for unlock by points
* Add const to declarations
* Remove const_cast
* Remove a const_cast
There are other const_cast in the menu debug items (but they are unrelated to this PR)
* Fix menu being bolder
2018-04-29 18:27:03 -04:00
|
|
|
|
|
|
|
PlayerManager::getCurrentPlayer()->clearUnlocked();
|
|
|
|
|
2010-08-24 19:19:14 -04:00
|
|
|
return;
|
|
|
|
}
|
2017-10-25 20:16:36 -04:00
|
|
|
Log::warn("RaceResultGUI", "Incorrect event '%s' when things are unlocked.",
|
2016-03-17 02:19:21 -04:00
|
|
|
name.c_str());
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Next check for GP
|
|
|
|
// -----------------
|
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
{
|
2010-12-20 12:52:39 -05:00
|
|
|
if (name == "middle") // Next GP
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2011-10-07 19:25:02 -04:00
|
|
|
cleanupGPProgress();
|
2010-12-20 12:52:39 -05:00
|
|
|
StateManager::get()->popMenu();
|
2010-08-24 19:19:14 -04:00
|
|
|
race_manager->next();
|
|
|
|
}
|
2010-12-20 12:52:39 -05:00
|
|
|
else if (name == "bottom") // Abort
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2013-02-16 19:20:40 -05:00
|
|
|
new MessageDialog(_("Do you really want to abort the Grand Prix?"),
|
2016-03-17 02:19:21 -04:00
|
|
|
MessageDialog::MESSAGE_DIALOG_CONFIRM, this, false);
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
2011-10-07 19:25:02 -04:00
|
|
|
else if (!getWidget(name.c_str())->isVisible())
|
2017-01-15 19:32:15 -05:00
|
|
|
{
|
|
|
|
Log::warn("RaceResultGUI", "Incorrect event '%s' when things are unlocked.",
|
2016-03-17 02:19:21 -04:00
|
|
|
name.c_str());
|
2017-01-15 19:32:15 -05:00
|
|
|
}
|
2010-08-29 19:17:56 -04:00
|
|
|
return;
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
|
|
|
|
2010-08-29 19:17:56 -04:00
|
|
|
StateManager::get()->popMenu();
|
2016-03-17 02:19:21 -04:00
|
|
|
if (name == "top") // Setup new race
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
2018-05-13 20:51:52 -04:00
|
|
|
// Save current race data for race against new ghost
|
|
|
|
std::string track_name = race_manager->getTrackName();
|
|
|
|
int laps = race_manager->getNumLaps();
|
|
|
|
bool reverse = race_manager->getReverseTrack();
|
|
|
|
bool new_ghost_race = race_manager->isRecordingRace();
|
|
|
|
|
2010-08-24 19:19:14 -04:00
|
|
|
race_manager->exitRace();
|
2012-12-06 19:24:20 -05:00
|
|
|
race_manager->setAIKartOverride("");
|
2018-04-14 20:38:23 -04:00
|
|
|
|
|
|
|
//If pressing continue quickly in a losing challenge
|
|
|
|
if (race_manager->raceWasStartedFromOverworld())
|
|
|
|
{
|
|
|
|
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
|
|
|
OverWorld::enterOverWorld();
|
|
|
|
}
|
2018-05-13 20:51:52 -04:00
|
|
|
// Special case : race against a newly saved ghost
|
|
|
|
else if (new_ghost_race)
|
|
|
|
{
|
|
|
|
ReplayPlay::get()->loadAllReplayFile();
|
|
|
|
unsigned long long int last_uid = ReplayRecorder::get()->getLastUID();
|
|
|
|
ReplayPlay::get()->setReplayFileByUID(last_uid);
|
|
|
|
|
|
|
|
race_manager->setRecordRace(true);
|
|
|
|
race_manager->setRaceGhostKarts(true);
|
|
|
|
|
|
|
|
race_manager->setNumKarts(race_manager->getNumLocalPlayers());
|
|
|
|
|
|
|
|
// Disable accidentally unlocking of a challenge
|
|
|
|
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
|
|
|
|
|
|
|
|
race_manager->setReverseTrack(reverse);
|
|
|
|
race_manager->startSingleRace(track_name, laps, false);
|
|
|
|
}
|
2018-04-14 20:38:23 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Screen* newStack[] = { MainMenuScreen::getInstance(),
|
|
|
|
RaceSetupScreen::getInstance(),
|
|
|
|
NULL };
|
|
|
|
StateManager::get()->resetAndSetStack(newStack);
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
else if (name == "middle") // Restart
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
|
|
|
race_manager->rerunRace();
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
else if (name == "bottom") // Back to main
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
|
|
|
race_manager->exitRace();
|
2012-12-06 19:24:20 -05:00
|
|
|
race_manager->setAIKartOverride("");
|
2010-08-24 19:19:14 -04:00
|
|
|
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2012-04-01 11:42:44 -04:00
|
|
|
if (race_manager->raceWasStartedFromOverworld())
|
|
|
|
{
|
|
|
|
OverWorld::enterOverWorld();
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
}
|
|
|
|
else
|
2017-10-25 20:19:46 -04:00
|
|
|
Log::warn("RaceResultGUI", "Incorrect event '%s' for normal race.",
|
2016-03-17 02:19:21 -04:00
|
|
|
name.c_str());
|
2010-08-29 19:17:56 -04:00
|
|
|
return;
|
2010-08-24 19:19:14 -04:00
|
|
|
} // eventCallback
|
|
|
|
|
2013-02-16 19:20:40 -05:00
|
|
|
//-----------------------------------------------------------------------------
|
2018-03-31 03:23:20 -04:00
|
|
|
/** Sets up the gui to go back to the lobby. Can only be called in case of a
|
2016-03-17 02:19:21 -04:00
|
|
|
* networked game.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::backToLobby()
|
2013-02-16 19:20:40 -05:00
|
|
|
{
|
2018-04-21 04:00:14 -04:00
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX &&
|
|
|
|
race_manager->getTrackNumber() == race_manager->getNumOfTracks() - 1)
|
|
|
|
{
|
|
|
|
core::stringw msg = _("Network grand prix has been finished.");
|
|
|
|
MessageQueue::add(MessageQueue::MT_ACHIEVEMENT, msg);
|
|
|
|
}
|
|
|
|
race_manager->clearNetworkGrandPrixResult();
|
2013-02-16 19:20:40 -05:00
|
|
|
race_manager->exitRace();
|
|
|
|
race_manager->setAIKartOverride("");
|
2018-04-20 02:18:05 -04:00
|
|
|
GUIEngine::ModalDialog::dismiss();
|
2018-04-21 04:00:14 -04:00
|
|
|
cleanupGPProgress();
|
2018-03-31 03:23:20 -04:00
|
|
|
StateManager::get()->resetAndSetStack(
|
|
|
|
NetworkConfig::get()->getResetScreens(true/*lobby*/).data());
|
2018-04-22 02:32:41 -04:00
|
|
|
NetworkingLobby::getInstance()->addMoreServerInfo(L"--------------------");
|
2016-03-17 02:19:21 -04:00
|
|
|
} // backToLobby
|
2013-02-16 19:20:40 -05:00
|
|
|
|
2010-07-15 18:41:41 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2016-03-17 02:19:21 -04:00
|
|
|
void RaceResultGUI::onConfirm()
|
|
|
|
{
|
|
|
|
//race_manager->saveGP(); // Save the aborted GP
|
|
|
|
GUIEngine::ModalDialog::dismiss();
|
|
|
|
cleanupGPProgress();
|
|
|
|
StateManager::get()->popMenu();
|
|
|
|
race_manager->exitRace();
|
|
|
|
race_manager->setAIKartOverride("");
|
|
|
|
StateManager::get()->resetAndGoToScreen(
|
|
|
|
MainMenuScreen::getInstance());
|
2010-09-04 21:07:44 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (race_manager->raceWasStartedFromOverworld())
|
|
|
|
{
|
|
|
|
OverWorld::enterOverWorld();
|
|
|
|
}
|
|
|
|
}
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** This determines the layout, i.e. the size of all columns, font size etc.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::determineTableLayout()
|
|
|
|
{
|
|
|
|
GUIEngine::Widget *table_area = getWidget("result-table");
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_font = GUIEngine::getFont();
|
|
|
|
assert(m_font);
|
2016-07-18 11:00:40 -04:00
|
|
|
//m_was_monospace = m_font->getMonospaceDigits();
|
|
|
|
//m_font->setMonospaceDigits(true);
|
2016-03-17 02:19:21 -04:00
|
|
|
WorldWithRank *rank_world = (WorldWithRank*)World::getWorld();
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
unsigned int first_position = 1;
|
2016-10-08 21:50:26 -04:00
|
|
|
unsigned int sta = race_manager->getNumSpareTireKarts();
|
2016-03-17 02:19:21 -04:00
|
|
|
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
|
|
|
first_position = 2;
|
2010-09-04 21:07:44 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Use only the karts that are supposed to be displayed (and
|
|
|
|
// ignore e.g. the leader in a FTL race).
|
2016-10-07 02:39:39 -04:00
|
|
|
unsigned int num_karts = race_manager->getNumberOfKarts() - first_position + 1 - sta;
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// In FTL races the leader kart is not displayed
|
|
|
|
m_all_row_infos.resize(num_karts);
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Determine the kart to display in the right order,
|
|
|
|
// and the maximum width for the kart name column
|
|
|
|
// -------------------------------------------------
|
|
|
|
m_width_kart_name = 0;
|
|
|
|
float max_finish_time = 0;
|
2010-07-20 19:01:47 -04:00
|
|
|
|
2018-08-12 12:59:20 -04:00
|
|
|
FreeForAll* ffa = dynamic_cast<FreeForAll*>(World::getWorld());
|
2016-03-17 02:19:21 -04:00
|
|
|
for (unsigned int position = first_position;
|
2016-10-07 02:39:39 -04:00
|
|
|
position <= race_manager->getNumberOfKarts() - sta; position++)
|
2012-10-25 19:17:10 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
const AbstractKart *kart = rank_world->getKartAtPosition(position);
|
2010-07-20 19:01:47 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Save a pointer to the current row_info entry
|
|
|
|
RowInfo *ri = &(m_all_row_infos[position - first_position]);
|
|
|
|
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
2017-08-03 19:51:42 -04:00
|
|
|
ri->m_kart_name = kart->getController()->getName();
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
video::ITexture *icon =
|
|
|
|
kart->getKartProperties()->getIconMaterial()->getTexture();
|
|
|
|
ri->m_kart_icon = icon;
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// FTL karts will get a time assigned, they are not shown as eliminated
|
|
|
|
if (kart->isEliminated() &&
|
|
|
|
race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
|
|
|
{
|
|
|
|
ri->m_finish_time_string = core::stringw(_("Eliminated"));
|
|
|
|
}
|
2018-08-12 12:59:20 -04:00
|
|
|
else if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_FREE_FOR_ALL ||
|
|
|
|
race_manager->getMajorMode() == RaceManager::MAJOR_MODE_CAPTURE_THE_FLAG)
|
|
|
|
{
|
|
|
|
assert(ffa);
|
|
|
|
ri->m_finish_time_string =
|
|
|
|
StringUtils::toWString(ffa->getKartScore(kart->getWorldKartId()));
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const float time = kart->getFinishTime();
|
|
|
|
if (time > max_finish_time) max_finish_time = time;
|
|
|
|
std::string time_string = StringUtils::timeToString(time);
|
|
|
|
ri->m_finish_time_string = time_string.c_str();
|
|
|
|
}
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
core::dimension2du rect =
|
|
|
|
m_font->getDimension(ri->m_kart_name.c_str());
|
|
|
|
if (rect.Width > m_width_kart_name)
|
|
|
|
m_width_kart_name = rect.Width;
|
|
|
|
} // for position
|
2010-07-20 19:01:47 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
std::string max_time = StringUtils::timeToString(max_finish_time);
|
|
|
|
core::stringw string_max_time(max_time.c_str());
|
|
|
|
core::dimension2du r = m_font->getDimension(string_max_time.c_str());
|
|
|
|
m_width_finish_time = r.Width;
|
2010-07-25 18:37:11 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Top pixel where to display text
|
|
|
|
m_top = table_area->m_y;
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Height of the result display
|
|
|
|
unsigned int height = table_area->m_h;
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Setup different timing information for the different phases
|
|
|
|
// -----------------------------------------------------------
|
|
|
|
// How much time between consecutive rows
|
|
|
|
m_time_between_rows = 0.1f;
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// How long it takes for one line to scroll from right to left
|
|
|
|
m_time_single_scroll = 0.2f;
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Time to rotate the entries to the proper GP position.
|
|
|
|
m_time_rotation = 1.0f;
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// The time the first phase is being displayed: add the start time
|
|
|
|
// of the last kart to the duration of the scroll plus some time
|
|
|
|
// of rest before the next phase starts
|
|
|
|
m_time_overall_scroll = (num_karts - 1)*m_time_between_rows
|
|
|
|
+ m_time_single_scroll + 2.0f;
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// The time to increase the number of points.
|
|
|
|
m_time_for_points = 1.0f;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Determine text height
|
|
|
|
r = m_font->getDimension(L"Y");
|
|
|
|
m_distance_between_rows = (int)(1.5f*r.Height);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// If there are too many karts, reduce size between rows
|
|
|
|
if (m_distance_between_rows * num_karts > height)
|
|
|
|
m_distance_between_rows = height / num_karts;
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_width_icon = table_area->m_h / 18;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_width_column_space = 10;
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Determine width of new points column
|
2010-09-07 19:05:31 -04:00
|
|
|
|
2016-07-18 11:00:40 -04:00
|
|
|
//m_font->setMonospaceDigits(true);
|
2016-03-17 02:19:21 -04:00
|
|
|
core::dimension2du r_new_p = m_font->getDimension(L"+99");
|
2010-07-22 18:51:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_width_new_points = r_new_p.Width;
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Determine width of overall points column
|
|
|
|
core::dimension2du r_all_p = m_font->getDimension(L"999");
|
2016-07-18 11:00:40 -04:00
|
|
|
//m_font->setMonospaceDigits(false);
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_width_all_points = r_all_p.Width;
|
2010-08-25 09:54:28 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_table_width = m_width_icon + m_width_column_space
|
|
|
|
+ m_width_kart_name;
|
2010-08-25 09:54:28 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
|
|
|
m_table_width += m_width_finish_time + m_width_column_space;
|
2010-08-26 06:16:58 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Only in GP mode are the points displayed.
|
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
m_table_width += m_width_new_points + m_width_all_points
|
|
|
|
+ 2 * m_width_column_space;
|
|
|
|
|
|
|
|
m_leftmost_column = table_area->m_x;
|
|
|
|
} // determineTableLayout
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** This function is called when one of the player presses 'fire'. The next
|
|
|
|
* phase of the animation will be displayed. E.g.
|
|
|
|
* in a GP: pressing fire while/after showing the latest race result will
|
|
|
|
* start the animation for the current GP result
|
|
|
|
* in a normal race: when pressing fire while an animation is played,
|
|
|
|
* start the menu showing 'rerun, new race, back to main' etc.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::nextPhase()
|
|
|
|
{
|
|
|
|
// This will trigger the next phase in the next render call.
|
|
|
|
m_timer = 9999;
|
|
|
|
} // nextPhase
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** If escape is pressed, don't do the default option (close the screen), but
|
|
|
|
* advance to the next animation phase.
|
|
|
|
*/
|
|
|
|
bool RaceResultGUI::onEscapePressed()
|
|
|
|
{
|
|
|
|
nextPhase();
|
|
|
|
return false; // indicates 'do not close'
|
|
|
|
} // onEscapePressed
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** This is called before an event is sent to a widget. Since in this case
|
|
|
|
* no widget is active, the event would be lost, so we act on fire events
|
|
|
|
* here and trigger the next phase.
|
|
|
|
*/
|
|
|
|
GUIEngine::EventPropagation RaceResultGUI::filterActions(PlayerAction action,
|
|
|
|
int deviceID,
|
|
|
|
const unsigned int value,
|
|
|
|
Input::InputType type,
|
|
|
|
int playerId)
|
|
|
|
{
|
|
|
|
if (action != PA_FIRE) return GUIEngine::EVENT_LET;
|
2010-08-26 06:16:58 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// If the buttons are already visible, let the event go through since
|
|
|
|
// it will be triggering eventCallback where this is handles.
|
2010-08-26 06:16:58 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (m_animation_state == RR_WAIT_TILL_END) return GUIEngine::EVENT_LET;
|
2010-08-26 06:16:58 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
nextPhase();
|
|
|
|
return GUIEngine::EVENT_BLOCK;
|
|
|
|
} // filterActions
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Called once a frame, this now triggers the rendering of the actual
|
|
|
|
* race result gui.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::onUpdate(float dt)
|
2011-05-20 21:07:06 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
renderGlobal(dt);
|
|
|
|
|
|
|
|
// When the finish sound has been played, start the race over music.
|
|
|
|
if (m_finish_sound && m_finish_sound->getStatus() != SFXBase::SFX_PLAYING)
|
2011-06-03 20:17:22 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
try
|
|
|
|
{
|
|
|
|
// This call is done once each frame, but startMusic() is cheap
|
|
|
|
// if the music is already playing.
|
|
|
|
music_manager->startMusic(m_race_over_music);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
Log::error("RaceResultGUI", "Exception caught when "
|
|
|
|
"trying to load music: %s", e.what());
|
|
|
|
}
|
2011-06-03 20:17:22 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
} // onUpdate
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Render all global parts of the race gui, i.e. things that are only
|
|
|
|
* displayed once even in splitscreen.
|
|
|
|
* \param dt Timestep sized.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::renderGlobal(float dt)
|
|
|
|
{
|
2016-04-17 10:29:59 -04:00
|
|
|
#ifndef SERVER_ONLY
|
2016-03-17 02:19:21 -04:00
|
|
|
bool isSoccerWorld = race_manager->getMinorMode() == RaceManager::MINOR_MODE_SOCCER;
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_timer += dt;
|
|
|
|
assert(World::getWorld()->getPhase() == WorldStatus::RESULT_DISPLAY_PHASE);
|
|
|
|
unsigned int num_karts = (unsigned int)m_all_row_infos.size();
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// First: Update the finite state machine
|
|
|
|
// ======================================
|
|
|
|
switch (m_animation_state)
|
2010-07-29 19:03:20 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
case RR_INIT:
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
|
|
|
ri->m_start_at = m_time_between_rows * i;
|
|
|
|
ri->m_x_pos = (float)UserConfigParams::m_width;
|
|
|
|
ri->m_y_pos = (float)(m_top + i*m_distance_between_rows);
|
|
|
|
}
|
|
|
|
m_animation_state = RR_RACE_RESULT;
|
|
|
|
break;
|
|
|
|
case RR_RACE_RESULT:
|
|
|
|
if (m_timer > m_time_overall_scroll)
|
2010-09-06 07:11:38 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
// Make sure that all lines are aligned to the left
|
|
|
|
// (in case that the animation was skipped).
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
|
|
|
ri->m_x_pos = (float)m_leftmost_column;
|
|
|
|
}
|
|
|
|
if (race_manager->getMajorMode() !=
|
|
|
|
RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
{
|
|
|
|
m_animation_state = RR_WAIT_TILL_END;
|
|
|
|
enableAllButtons();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
determineGPLayout();
|
|
|
|
m_animation_state = RR_OLD_GP_RESULTS;
|
|
|
|
m_timer = 0;
|
2010-09-06 07:11:38 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
break;
|
|
|
|
case RR_OLD_GP_RESULTS:
|
|
|
|
if (m_timer > m_time_overall_scroll)
|
2010-07-29 19:03:20 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
m_animation_state = RR_INCREASE_POINTS;
|
|
|
|
m_timer = 0;
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
|
|
|
ri->m_x_pos = (float)m_leftmost_column;
|
|
|
|
}
|
2010-07-29 19:03:20 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
break;
|
|
|
|
case RR_INCREASE_POINTS:
|
|
|
|
// Have one second delay before the resorting starts.
|
|
|
|
if (m_timer > 1 + m_time_for_points)
|
|
|
|
{
|
|
|
|
m_animation_state = RR_RESORT_TABLE;
|
|
|
|
if (m_gp_position_was_changed)
|
|
|
|
m_timer = 0;
|
|
|
|
else
|
|
|
|
// This causes the phase to go to RESORT_TABLE once, and then
|
|
|
|
// immediately wait till end. This has the advantage that any
|
|
|
|
// phase change settings will be processed properly.
|
|
|
|
m_timer = m_time_rotation + 1;
|
|
|
|
// Make the new row permanent; necessary in case
|
|
|
|
// that the animation is skipped.
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
|
|
|
ri->m_new_points = 0;
|
|
|
|
ri->m_current_displayed_points =
|
|
|
|
(float)ri->m_new_overall_points;
|
|
|
|
}
|
2010-07-29 19:03:20 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RR_RESORT_TABLE:
|
|
|
|
if (m_timer > m_time_rotation)
|
2010-08-26 06:16:58 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
m_animation_state = RR_WAIT_TILL_END;
|
|
|
|
// Make the new row permanent.
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
|
|
|
ri->m_y_pos = ri->m_centre_point - ri->m_radius;
|
|
|
|
}
|
|
|
|
enableAllButtons();
|
2010-08-26 06:16:58 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
break;
|
|
|
|
case RR_WAIT_TILL_END:
|
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
displayGPProgress();
|
|
|
|
if (m_timer - m_time_rotation > 1.0f &&
|
|
|
|
dynamic_cast<DemoWorld*>(World::getWorld()))
|
2010-08-25 18:55:58 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
race_manager->exitRace();
|
|
|
|
StateManager::get()->resetAndGoToScreen(MainMenuScreen::getInstance());
|
2010-08-25 18:55:58 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
break;
|
|
|
|
} // switch
|
2010-08-25 18:55:58 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Second phase: update X and Y positions for the various animations
|
|
|
|
// =================================================================
|
|
|
|
float v = 0.9f*UserConfigParams::m_width / m_time_single_scroll;
|
|
|
|
if (!isSoccerWorld)
|
2010-07-29 19:03:20 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
for (unsigned int i = 0; i < m_all_row_infos.size(); i++)
|
2010-08-24 19:19:14 -04:00
|
|
|
{
|
|
|
|
RowInfo *ri = &(m_all_row_infos[i]);
|
2016-03-17 02:19:21 -04:00
|
|
|
float x = ri->m_x_pos;
|
|
|
|
float y = ri->m_y_pos;
|
|
|
|
switch (m_animation_state)
|
|
|
|
{
|
|
|
|
// Both states use the same scrolling:
|
|
|
|
case RR_INIT: break; // Remove compiler warning
|
|
|
|
case RR_RACE_RESULT:
|
|
|
|
case RR_OLD_GP_RESULTS:
|
|
|
|
if (m_timer > ri->m_start_at)
|
|
|
|
{ // if active
|
|
|
|
ri->m_x_pos -= dt*v;
|
|
|
|
if (ri->m_x_pos < m_leftmost_column)
|
|
|
|
ri->m_x_pos = (float)m_leftmost_column;
|
|
|
|
x = ri->m_x_pos;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case RR_INCREASE_POINTS:
|
|
|
|
{
|
|
|
|
WorldWithRank *wwr = dynamic_cast<WorldWithRank*>(World::getWorld());
|
|
|
|
assert(wwr);
|
|
|
|
int most_points;
|
|
|
|
if (race_manager->getMinorMode() == RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
|
|
|
most_points = wwr->getScoreForPosition(2);
|
|
|
|
else
|
|
|
|
most_points = wwr->getScoreForPosition(1);
|
|
|
|
ri->m_current_displayed_points +=
|
|
|
|
dt*most_points / m_time_for_points;
|
|
|
|
if (ri->m_current_displayed_points > ri->m_new_overall_points)
|
|
|
|
{
|
|
|
|
ri->m_current_displayed_points =
|
|
|
|
(float)ri->m_new_overall_points;
|
|
|
|
}
|
|
|
|
ri->m_new_points -=
|
|
|
|
dt*most_points / m_time_for_points;
|
|
|
|
if (ri->m_new_points < 0)
|
|
|
|
ri->m_new_points = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case RR_RESORT_TABLE:
|
|
|
|
x = ri->m_x_pos
|
|
|
|
- ri->m_radius*sin(m_timer / m_time_rotation*M_PI);
|
|
|
|
y = ri->m_centre_point
|
|
|
|
+ ri->m_radius*cos(m_timer / m_time_rotation*M_PI);
|
|
|
|
break;
|
|
|
|
case RR_WAIT_TILL_END:
|
|
|
|
break;
|
|
|
|
} // switch
|
|
|
|
displayOneEntry((unsigned int)x, (unsigned int)y, i, true);
|
|
|
|
} // for i
|
2010-07-29 19:03:20 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
else
|
|
|
|
displaySoccerResults();
|
|
|
|
|
|
|
|
// Display highscores
|
|
|
|
if (race_manager->getMajorMode() != RaceManager::MAJOR_MODE_GRAND_PRIX ||
|
|
|
|
m_animation_state == RR_RACE_RESULT)
|
2012-05-06 20:10:33 -04:00
|
|
|
{
|
2016-06-15 19:36:37 -04:00
|
|
|
displayPostRaceInfo();
|
2012-05-06 20:10:33 -04:00
|
|
|
}
|
2016-04-17 10:29:59 -04:00
|
|
|
#endif
|
2016-03-17 02:19:21 -04:00
|
|
|
} // renderGlobal
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Determine the layout and fields for the GP table based on the previous
|
|
|
|
* GP results.
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::determineGPLayout()
|
2010-07-15 18:41:41 -04:00
|
|
|
{
|
2016-04-17 10:29:59 -04:00
|
|
|
#ifndef SERVER_ONLY
|
2016-03-17 02:19:21 -04:00
|
|
|
unsigned int num_karts = race_manager->getNumberOfKarts();
|
|
|
|
std::vector<int> old_rank(num_karts, 0);
|
|
|
|
for (unsigned int kart_id = 0; kart_id < num_karts; kart_id++)
|
2010-07-25 18:37:11 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
int rank = race_manager->getKartGPRank(kart_id);
|
|
|
|
// In case of FTL mode: ignore the leader
|
|
|
|
if (rank < 0) continue;
|
|
|
|
old_rank[kart_id] = rank;
|
|
|
|
const AbstractKart *kart = World::getWorld()->getKart(kart_id);
|
|
|
|
RowInfo *ri = &(m_all_row_infos[rank]);
|
|
|
|
ri->m_kart_icon =
|
|
|
|
kart->getKartProperties()->getIconMaterial()->getTexture();
|
|
|
|
ri->m_is_player_kart = kart->getController()->isLocalPlayerController();
|
2017-08-03 19:51:42 -04:00
|
|
|
ri->m_kart_name = kart->getController()->getName();
|
2016-03-17 02:19:21 -04:00
|
|
|
|
|
|
|
// In FTL karts do have a time, which is shown even when the kart
|
|
|
|
// is eliminated
|
|
|
|
if (kart->isEliminated() &&
|
|
|
|
race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
2011-10-26 01:01:51 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
ri->m_finish_time_string = core::stringw(_("Eliminated"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float time = race_manager->getOverallTime(kart_id);
|
|
|
|
ri->m_finish_time_string
|
|
|
|
= StringUtils::timeToString(time).c_str();
|
|
|
|
}
|
|
|
|
ri->m_start_at = m_time_between_rows * rank;
|
|
|
|
ri->m_x_pos = (float)UserConfigParams::m_width;
|
|
|
|
ri->m_y_pos = (float)(m_top + rank*m_distance_between_rows);
|
|
|
|
int p = race_manager->getKartPrevScore(kart_id);
|
|
|
|
ri->m_current_displayed_points = (float)p;
|
|
|
|
if (kart->isEliminated() &&
|
|
|
|
race_manager->getMinorMode() != RaceManager::MINOR_MODE_FOLLOW_LEADER)
|
|
|
|
{
|
|
|
|
ri->m_new_points = 0;
|
|
|
|
}
|
|
|
|
else
|
2015-07-27 19:39:00 -04:00
|
|
|
{
|
|
|
|
WorldWithRank *wwr = dynamic_cast<WorldWithRank*>(World::getWorld());
|
|
|
|
assert(wwr);
|
2016-03-17 02:19:21 -04:00
|
|
|
ri->m_new_points =
|
|
|
|
(float)wwr->getScoreForPosition(kart->getPosition());
|
2015-07-27 19:39:00 -04:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
}
|
2010-07-15 18:41:41 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Now update the GP ranks, and determine the new position
|
|
|
|
// -------------------------------------------------------
|
|
|
|
race_manager->computeGPRanks();
|
|
|
|
m_gp_position_was_changed = false;
|
|
|
|
for (unsigned int i = 0; i < num_karts; i++)
|
|
|
|
{
|
|
|
|
int j = old_rank[i];
|
|
|
|
int gp_position = race_manager->getKartGPRank(i);
|
|
|
|
m_gp_position_was_changed |= j != gp_position;
|
|
|
|
RowInfo *ri = &(m_all_row_infos[j]);
|
|
|
|
ri->m_radius = (j - gp_position)*(int)m_distance_between_rows*0.5f;
|
|
|
|
ri->m_centre_point = m_top + (gp_position + j)*m_distance_between_rows*0.5f;
|
|
|
|
int p = race_manager->getKartScore(i);
|
|
|
|
ri->m_new_overall_points = p;
|
|
|
|
} // i < num_karts
|
2016-04-17 10:29:59 -04:00
|
|
|
#endif
|
2016-03-17 02:19:21 -04:00
|
|
|
} // determineGPLayout
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/** Displays the race results for a single kart.
|
|
|
|
* \param n Index of the kart to be displayed.
|
|
|
|
* \param display_points True if GP points should be displayed, too
|
|
|
|
*/
|
|
|
|
void RaceResultGUI::displayOneEntry(unsigned int x, unsigned int y,
|
|
|
|
unsigned int n, bool display_points)
|
2010-07-29 19:03:20 -04:00
|
|
|
{
|
2016-04-17 10:29:59 -04:00
|
|
|
#ifndef SERVER_ONLY
|
2016-03-17 02:19:21 -04:00
|
|
|
RowInfo *ri = &(m_all_row_infos[n]);
|
|
|
|
video::SColor color = ri->m_is_player_kart
|
|
|
|
? video::SColor(255, 255, 0, 0)
|
|
|
|
: video::SColor(255, 255, 255, 255);
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
unsigned int current_x = x;
|
2010-08-24 19:19:14 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// First draw the icon
|
|
|
|
// -------------------
|
|
|
|
if (ri->m_kart_icon)
|
2015-07-23 20:01:54 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
core::recti source_rect(core::vector2di(0, 0),
|
|
|
|
ri->m_kart_icon->getSize());
|
|
|
|
core::recti dest_rect(current_x, y,
|
|
|
|
current_x + m_width_icon, y + m_width_icon);
|
|
|
|
draw2DImage(ri->m_kart_icon, dest_rect,
|
|
|
|
source_rect, NULL, NULL,
|
|
|
|
true);
|
2015-07-23 20:01:54 -04:00
|
|
|
}
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
current_x += m_width_icon + m_width_column_space;
|
2010-09-07 19:05:31 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Draw the name
|
|
|
|
// -------------
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
core::recti pos_name(current_x, y,
|
|
|
|
UserConfigParams::m_width, y + m_distance_between_rows);
|
|
|
|
m_font->draw(ri->m_kart_name, pos_name, color, false, false, NULL,
|
|
|
|
true /* ignoreRTL */);
|
|
|
|
current_x += m_width_kart_name + m_width_column_space;
|
2011-01-03 05:45:31 -05:00
|
|
|
|
2013-10-13 20:23:20 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10);
|
|
|
|
m_font->draw(ri->m_finish_time_string, dest_rect, color, false, false,
|
|
|
|
NULL, true /* ignoreRTL */);
|
|
|
|
current_x += m_width_finish_time + m_width_column_space;
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Only display points in GP mode and when the GP results are displayed.
|
|
|
|
// =====================================================================
|
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX &&
|
|
|
|
m_animation_state != RR_RACE_RESULT)
|
2011-05-29 17:00:31 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
// Draw the new points
|
|
|
|
// -------------------
|
|
|
|
if (ri->m_new_points > 0)
|
|
|
|
{
|
|
|
|
core::recti dest_rect = core::recti(current_x, y,
|
|
|
|
current_x + 100, y + 10);
|
|
|
|
core::stringw point_string = core::stringw("+")
|
|
|
|
+ core::stringw((int)ri->m_new_points);
|
|
|
|
// With mono-space digits space has the same width as each digit,
|
|
|
|
// so we can simply fill up the string with spaces to get the
|
|
|
|
// right aligned.
|
|
|
|
while (point_string.size() < 3)
|
|
|
|
point_string = core::stringw(" ") + point_string;
|
|
|
|
m_font->draw(point_string, dest_rect, color, false, false, NULL,
|
|
|
|
true /* ignoreRTL */);
|
|
|
|
}
|
|
|
|
current_x += m_width_new_points + m_width_column_space;
|
|
|
|
|
|
|
|
// Draw the old_points plus increase value
|
|
|
|
// ---------------------------------------
|
|
|
|
core::recti dest_rect = core::recti(current_x, y, current_x + 100, y + 10);
|
|
|
|
core::stringw point_inc_string =
|
|
|
|
core::stringw((int)(ri->m_current_displayed_points));
|
|
|
|
while (point_inc_string.size() < 3)
|
|
|
|
point_inc_string = core::stringw(" ") + point_inc_string;
|
|
|
|
m_font->draw(point_inc_string, dest_rect, color, false, false, NULL,
|
|
|
|
true /* ignoreRTL */);
|
2011-05-29 17:00:31 -04:00
|
|
|
}
|
2016-04-17 10:29:59 -04:00
|
|
|
#endif
|
2016-03-17 02:19:21 -04:00
|
|
|
} // displayOneEntry
|
2010-07-20 19:01:47 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::displaySoccerResults()
|
2013-10-13 20:23:20 -04:00
|
|
|
{
|
2016-04-17 10:29:59 -04:00
|
|
|
#ifndef SERVER_ONLY
|
2016-03-17 02:19:21 -04:00
|
|
|
//Draw win text
|
|
|
|
core::stringw result_text;
|
|
|
|
static video::SColor color = video::SColor(255, 255, 255, 255);
|
|
|
|
gui::IGUIFont* font = GUIEngine::getTitleFont();
|
|
|
|
int current_x = UserConfigParams::m_width / 2;
|
|
|
|
RowInfo *ri = &(m_all_row_infos[0]);
|
|
|
|
int current_y = (int)ri->m_y_pos;
|
|
|
|
SoccerWorld* sw = (SoccerWorld*)World::getWorld();
|
|
|
|
const int red_score = sw->getScore(SOCCER_TEAM_RED);
|
|
|
|
const int blue_score = sw->getScore(SOCCER_TEAM_BLUE);
|
|
|
|
|
|
|
|
GUIEngine::Widget *table_area = getWidget("result-table");
|
|
|
|
int height = table_area->m_h + table_area->m_y;
|
|
|
|
|
|
|
|
if (red_score > blue_score)
|
|
|
|
{
|
|
|
|
result_text = _("Red Team Wins");
|
|
|
|
}
|
|
|
|
else if (blue_score > red_score)
|
|
|
|
{
|
|
|
|
result_text = _("Blue Team Wins");
|
|
|
|
}
|
2013-10-18 03:33:18 -04:00
|
|
|
else
|
2016-01-19 03:21:58 -05:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
//Cannot really happen now. Only in time limited matches.
|
|
|
|
result_text = _("It's a draw");
|
2016-01-19 03:21:58 -05:00
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
core::rect<s32> pos(current_x, current_y, current_x, current_y);
|
|
|
|
font->draw(result_text.c_str(), pos, color, true, true);
|
|
|
|
|
2016-03-28 02:46:04 -04:00
|
|
|
core::dimension2du rect = font->getDimension(result_text.c_str());
|
2016-03-17 02:19:21 -04:00
|
|
|
|
|
|
|
//Draw team scores:
|
|
|
|
current_y += rect.Height;
|
|
|
|
current_x /= 2;
|
|
|
|
irr::video::ITexture* red_icon = irr_driver->getTexture(FileManager::GUI,
|
|
|
|
"soccer_ball_red.png");
|
|
|
|
irr::video::ITexture* blue_icon = irr_driver->getTexture(FileManager::GUI,
|
|
|
|
"soccer_ball_blue.png");
|
|
|
|
|
|
|
|
core::recti source_rect(core::vector2di(0, 0), red_icon->getSize());
|
|
|
|
core::recti dest_rect(current_x, current_y, current_x + red_icon->getSize().Width / 2,
|
|
|
|
current_y + red_icon->getSize().Height / 2);
|
|
|
|
draw2DImage(red_icon, dest_rect, source_rect,
|
|
|
|
NULL, NULL, true);
|
|
|
|
current_x += UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2;
|
|
|
|
dest_rect = core::recti(current_x, current_y, current_x + red_icon->getSize().Width / 2,
|
|
|
|
current_y + red_icon->getSize().Height / 2);
|
|
|
|
draw2DImage(blue_icon, dest_rect, source_rect,
|
|
|
|
NULL, NULL, true);
|
2013-10-18 03:33:18 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
result_text = StringUtils::toWString(blue_score);
|
2016-03-28 02:46:04 -04:00
|
|
|
rect = font->getDimension(result_text.c_str());
|
2016-03-17 02:19:21 -04:00
|
|
|
current_x += red_icon->getSize().Width / 4;
|
|
|
|
current_y += red_icon->getSize().Height / 2 + rect.Height / 4;
|
|
|
|
pos = core::rect<s32>(current_x, current_y, current_x, current_y);
|
|
|
|
font->draw(result_text.c_str(), pos, color, true, false);
|
|
|
|
|
|
|
|
current_x -= UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2;
|
|
|
|
result_text = StringUtils::toWString(red_score);
|
|
|
|
pos = core::rect<s32>(current_x, current_y, current_x, current_y);
|
|
|
|
font->draw(result_text.c_str(), pos, color, true, false);
|
|
|
|
|
|
|
|
int center_x = UserConfigParams::m_width / 2;
|
|
|
|
pos = core::rect<s32>(center_x, current_y, center_x, current_y);
|
|
|
|
font->draw("-", pos, color, true, false);
|
|
|
|
|
|
|
|
//Draw goal scorers:
|
|
|
|
//The red scorers:
|
|
|
|
current_y += rect.Height / 2 + rect.Height / 4;
|
|
|
|
font = GUIEngine::getSmallFont();
|
|
|
|
std::vector<SoccerWorld::ScorerData> scorers = sw->getScorers(SOCCER_TEAM_RED);
|
2016-12-30 19:59:24 -05:00
|
|
|
while (scorers.size() > 10)
|
|
|
|
{
|
|
|
|
scorers.erase(scorers.begin());
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
std::vector<float> score_times = sw->getScoreTimes(SOCCER_TEAM_RED);
|
2016-12-30 20:03:42 -05:00
|
|
|
while (score_times.size() > 10)
|
|
|
|
{
|
|
|
|
score_times.erase(score_times.begin());
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
irr::video::ITexture* scorer_icon;
|
|
|
|
|
|
|
|
int prev_y = current_y;
|
|
|
|
for (unsigned int i = 0; i < scorers.size(); i++)
|
|
|
|
{
|
|
|
|
const bool own_goal = !(scorers.at(i).m_correct_goal);
|
2013-10-17 16:15:12 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
const int kart_id = scorers.at(i).m_id;
|
|
|
|
const int rm_id = kart_id -
|
|
|
|
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
|
2013-10-14 16:25:30 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (rm_id >= 0)
|
|
|
|
result_text = race_manager->getKartInfo(rm_id).getPlayerName();
|
|
|
|
else
|
|
|
|
result_text = sw->getKart(kart_id)->
|
|
|
|
getKartProperties()->getName();
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (own_goal)
|
|
|
|
{
|
|
|
|
result_text.append(" ");
|
2016-05-05 20:37:05 -04:00
|
|
|
//I18N: indicates a player that scored in their own goal in result screen
|
2016-03-17 02:19:21 -04:00
|
|
|
result_text.append(_("(Own Goal)"));
|
|
|
|
}
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
result_text.append(" ");
|
|
|
|
result_text.append(StringUtils::timeToString(score_times.at(i)).c_str());
|
2016-03-28 02:46:04 -04:00
|
|
|
rect = font->getDimension(result_text.c_str());
|
2016-01-19 03:21:58 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height)
|
|
|
|
current_y += (height - prev_y) / ((short)scorers.size() + 1);
|
|
|
|
else
|
|
|
|
current_y += rect.Height;
|
|
|
|
|
|
|
|
if (current_y > height) break;
|
|
|
|
|
|
|
|
pos = core::rect<s32>(current_x, current_y, current_x, current_y);
|
|
|
|
font->draw(result_text, pos, (own_goal ?
|
|
|
|
video::SColor(255, 255, 0, 0) : color), true, false);
|
|
|
|
scorer_icon = sw->getKart(scorers.at(i).m_id)
|
|
|
|
->getKartProperties()->getIconMaterial()->getTexture();
|
|
|
|
source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize());
|
2016-03-28 02:46:04 -04:00
|
|
|
irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f);
|
2016-03-17 02:19:21 -04:00
|
|
|
dest_rect = core::recti(current_x - offset_x - 30, current_y, current_x - offset_x, current_y + 30);
|
|
|
|
draw2DImage(scorer_icon, dest_rect, source_rect,
|
|
|
|
NULL, NULL, true);
|
2016-01-19 03:21:58 -05:00
|
|
|
}
|
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//The blue scorers:
|
|
|
|
current_y = prev_y;
|
|
|
|
current_x += UserConfigParams::m_width / 2 - red_icon->getSize().Width / 2;
|
|
|
|
scorers = sw->getScorers(SOCCER_TEAM_BLUE);
|
2016-12-30 19:59:24 -05:00
|
|
|
while (scorers.size() > 10)
|
|
|
|
{
|
|
|
|
scorers.erase(scorers.begin());
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
score_times = sw->getScoreTimes(SOCCER_TEAM_BLUE);
|
2016-12-30 20:03:42 -05:00
|
|
|
while (score_times.size() > 10)
|
|
|
|
{
|
|
|
|
score_times.erase(score_times.begin());
|
|
|
|
}
|
2016-03-17 02:19:21 -04:00
|
|
|
for (unsigned int i = 0; i < scorers.size(); i++)
|
|
|
|
{
|
|
|
|
const bool own_goal = !(scorers.at(i).m_correct_goal);
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
const int kart_id = scorers.at(i).m_id;
|
|
|
|
const int rm_id = kart_id -
|
|
|
|
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
|
2013-10-18 03:33:18 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (rm_id >= 0)
|
|
|
|
result_text = race_manager->getKartInfo(rm_id).getPlayerName();
|
|
|
|
else
|
|
|
|
result_text = sw->getKart(kart_id)->
|
|
|
|
getKartProperties()->getName();
|
2013-10-17 16:15:12 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (own_goal)
|
|
|
|
{
|
|
|
|
result_text.append(" ");
|
|
|
|
result_text.append(_("(Own Goal)"));
|
|
|
|
}
|
2013-10-14 09:27:42 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
result_text.append(" ");
|
|
|
|
result_text.append(StringUtils::timeToString(score_times.at(i)).c_str());
|
2016-03-28 02:46:04 -04:00
|
|
|
rect = font->getDimension(result_text.c_str());
|
2013-10-13 20:23:20 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (height - prev_y < ((short)scorers.size() + 1)*(short)rect.Height)
|
|
|
|
current_y += (height - prev_y) / ((short)scorers.size() + 1);
|
|
|
|
else
|
|
|
|
current_y += rect.Height;
|
2011-05-23 21:34:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (current_y > height) break;
|
2011-05-23 21:34:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
pos = core::rect<s32>(current_x, current_y, current_x, current_y);
|
|
|
|
font->draw(result_text, pos, (own_goal ?
|
|
|
|
video::SColor(255, 255, 0, 0) : color), true, false);
|
|
|
|
scorer_icon = sw->getKart(scorers.at(i).m_id)->
|
|
|
|
getKartProperties()->getIconMaterial()->getTexture();
|
|
|
|
source_rect = core::recti(core::vector2di(0, 0), scorer_icon->getSize());
|
2016-03-28 02:46:04 -04:00
|
|
|
irr::u32 offset_x = (irr::u32)(font->getDimension(result_text.c_str()).Width / 1.5f);
|
2011-05-23 21:34:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
dest_rect = core::recti(current_x - offset_x - 30, current_y, current_x - offset_x, current_y + 30);
|
|
|
|
draw2DImage(scorer_icon, dest_rect, source_rect,
|
|
|
|
NULL, NULL, true);
|
|
|
|
}
|
2016-04-17 10:29:59 -04:00
|
|
|
#endif
|
2016-03-17 02:19:21 -04:00
|
|
|
}
|
2011-10-07 19:25:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void RaceResultGUI::clearHighscores()
|
2011-10-08 16:50:07 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
m_highscore_rank = 0;
|
|
|
|
} // clearHighscores
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
//-----------------------------------------------------------------------------
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
void RaceResultGUI::setHighscore(int rank)
|
|
|
|
{
|
|
|
|
m_highscore_rank = rank;
|
|
|
|
} // setHighscore
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::enableGPProgress()
|
|
|
|
{
|
|
|
|
if (race_manager->getMajorMode() == RaceManager::MAJOR_MODE_GRAND_PRIX)
|
|
|
|
{
|
|
|
|
GUIEngine::Widget* result_table = getWidget("result-table");
|
|
|
|
assert(result_table != NULL);
|
|
|
|
|
|
|
|
int currentTrack = race_manager->getTrackNumber();
|
|
|
|
int font_height = getFontHeight();
|
|
|
|
int w = (int)(UserConfigParams::m_width*0.17);
|
|
|
|
int x = (int)(result_table->m_x + result_table->m_w - w - 15);
|
|
|
|
int y = (m_top + font_height + 5);
|
|
|
|
|
|
|
|
//Current progress
|
|
|
|
GUIEngine::LabelWidget* status_label = new GUIEngine::LabelWidget();
|
|
|
|
status_label->m_properties[GUIEngine::PROP_ID] = "status_label";
|
|
|
|
status_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "center";
|
|
|
|
status_label->m_x = x;
|
|
|
|
status_label->m_y = y;
|
|
|
|
status_label->m_w = w;
|
|
|
|
status_label->m_h = font_height;
|
|
|
|
status_label->add();
|
|
|
|
status_label->setText(_("Track %i/%i", currentTrack + 1,
|
|
|
|
race_manager->getGrandPrix().getNumberOfTracks()), true);
|
|
|
|
addGPProgressWidget(status_label);
|
|
|
|
y = (status_label->m_y + status_label->m_h + 5);
|
|
|
|
|
|
|
|
//Scroll up button
|
|
|
|
GUIEngine::IconButtonWidget* up_button = new GUIEngine::IconButtonWidget(
|
|
|
|
GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
|
|
|
|
false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
|
|
|
up_button->m_properties[GUIEngine::PROP_ID] = "up_button";
|
|
|
|
up_button->m_x = x;
|
|
|
|
up_button->m_y = y;
|
|
|
|
up_button->m_w = w;
|
|
|
|
up_button->m_h = font_height;
|
|
|
|
up_button->add();
|
|
|
|
up_button->setImage(file_manager->getAsset(FileManager::GUI, "scroll_up.png"));
|
|
|
|
addGPProgressWidget(up_button);
|
|
|
|
y = (up_button->m_y + up_button->m_h + SSHOT_SEPARATION);
|
|
|
|
|
|
|
|
//Track screenshots and labels
|
|
|
|
int n_sshot = 1;
|
|
|
|
for (int i = m_start_track; i < m_end_track; i++)
|
|
|
|
{
|
|
|
|
//Screenshot
|
|
|
|
GUIEngine::IconButtonWidget* screenshot_widget =
|
|
|
|
new GUIEngine::IconButtonWidget(
|
|
|
|
GUIEngine::IconButtonWidget::
|
|
|
|
SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
|
|
|
|
false, false,
|
|
|
|
GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
|
|
|
screenshot_widget->setCustomAspectRatio(4.0f / 3.0f);
|
|
|
|
screenshot_widget->m_x = x;
|
|
|
|
screenshot_widget->m_y = y;
|
|
|
|
screenshot_widget->m_w = w;
|
|
|
|
screenshot_widget->m_h = m_sshot_height;
|
|
|
|
screenshot_widget->m_properties[GUIEngine::PROP_ID] =
|
|
|
|
("sshot_" + StringUtils::toString(n_sshot));
|
|
|
|
screenshot_widget->add();
|
|
|
|
addGPProgressWidget(screenshot_widget);
|
|
|
|
|
|
|
|
//Label
|
|
|
|
GUIEngine::LabelWidget* sshot_label = new GUIEngine::LabelWidget();
|
|
|
|
sshot_label->m_properties[GUIEngine::PROP_ID] =
|
|
|
|
("sshot_label_" + StringUtils::toString(n_sshot));
|
|
|
|
sshot_label->m_properties[GUIEngine::PROP_TEXT_ALIGN] = "left";
|
|
|
|
sshot_label->m_x = (x + w + 5);
|
|
|
|
sshot_label->m_y = (y + (m_sshot_height / 2) - (font_height / 2));
|
|
|
|
sshot_label->m_w = (w / 2);
|
|
|
|
sshot_label->m_h = font_height;
|
|
|
|
sshot_label->add();
|
|
|
|
addGPProgressWidget(sshot_label);
|
|
|
|
|
|
|
|
y += (m_sshot_height + SSHOT_SEPARATION);
|
|
|
|
n_sshot++;
|
|
|
|
} // for
|
|
|
|
displayScreenShots();
|
|
|
|
|
|
|
|
//Scroll down button
|
|
|
|
GUIEngine::IconButtonWidget* down_button = new GUIEngine::IconButtonWidget(
|
|
|
|
GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
|
|
|
|
false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
|
|
|
|
down_button->m_properties[GUIEngine::PROP_ID] = "down_button";
|
|
|
|
down_button->m_x = x;
|
|
|
|
down_button->m_y = y;
|
|
|
|
down_button->m_w = w;
|
|
|
|
down_button->m_h = font_height;
|
|
|
|
down_button->add();
|
|
|
|
down_button->setImage(file_manager->getAsset(FileManager::GUI, "scroll_down.png"));
|
|
|
|
addGPProgressWidget(down_button);
|
|
|
|
|
|
|
|
} // if MAJOR_MODE_GRAND_PRIX)
|
|
|
|
|
|
|
|
} // enableGPProgress
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::addGPProgressWidget(GUIEngine::Widget* widget)
|
|
|
|
{
|
|
|
|
m_widgets.push_back(widget);
|
|
|
|
m_gp_progress_widgets.push_back(widget);
|
|
|
|
}
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::displayGPProgress()
|
|
|
|
{
|
|
|
|
core::stringw msg = _("Grand Prix progress:");
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
GUIEngine::Widget* result_table = getWidget("result-table");
|
|
|
|
assert(result_table != NULL);
|
2011-10-07 19:25:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
video::SColor color = video::SColor(255, 255, 0, 0);
|
|
|
|
core::recti dest_rect(
|
|
|
|
result_table->m_x + result_table->m_w - m_font->getDimension(msg.c_str()).Width - 5,
|
|
|
|
m_top, 0, 0);
|
2011-10-07 19:25:02 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
m_font->draw(msg, dest_rect, color, false, false, NULL, true);
|
|
|
|
} // displayGPProgress
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::cleanupGPProgress()
|
|
|
|
{
|
2017-04-08 09:25:33 -04:00
|
|
|
for (unsigned int i = 0; i < m_gp_progress_widgets.size(); i++)
|
2016-03-17 02:19:21 -04:00
|
|
|
m_widgets.remove(m_gp_progress_widgets.get(i));
|
|
|
|
m_gp_progress_widgets.clearAndDeleteAll();
|
|
|
|
} // cleanupGPProgress
|
2012-11-16 07:51:26 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
2016-06-15 19:36:37 -04:00
|
|
|
void RaceResultGUI::displayPostRaceInfo()
|
2012-10-20 15:01:45 -04:00
|
|
|
{
|
2016-04-17 10:29:59 -04:00
|
|
|
#ifndef SERVER_ONLY
|
2016-03-17 02:19:21 -04:00
|
|
|
// This happens in demo world
|
|
|
|
if (!World::getWorld())
|
|
|
|
return;
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
Highscores* scores = World::getWorld()->getHighscores();
|
2016-06-15 19:36:37 -04:00
|
|
|
|
|
|
|
video::SColor white_color = video::SColor(255, 255, 255, 255);
|
|
|
|
|
|
|
|
int x = (int)(UserConfigParams::m_width*0.65f);
|
|
|
|
int y = m_top;
|
|
|
|
|
|
|
|
int current_y = y;
|
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// In some case for exemple FTL they will be no highscores
|
|
|
|
if (scores != NULL)
|
|
|
|
{
|
|
|
|
// First draw title
|
|
|
|
GUIEngine::getFont()->draw(_("Highscores"),
|
|
|
|
core::recti(x, y, 0, 0),
|
|
|
|
white_color,
|
|
|
|
false, false, NULL, true /* ignoreRTL */);
|
2013-05-29 18:04:35 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
std::string kart_name;
|
|
|
|
irr::core::stringw player_name;
|
2015-02-04 08:42:10 -05:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// prevent excessive long name
|
|
|
|
unsigned int max_characters = 15;
|
|
|
|
unsigned int max_width = (UserConfigParams::m_width / 2 - 200) / 10;
|
|
|
|
if (max_width < 15)
|
|
|
|
max_characters = max_width;
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
float time;
|
|
|
|
for (int i = 0; i < scores->getNumberEntries(); i++)
|
2012-10-20 15:01:45 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
scores->getEntry(i, kart_name, player_name, &time);
|
|
|
|
if (player_name.size() > max_characters)
|
|
|
|
{
|
|
|
|
int begin = (int(m_timer / 0.4f)) % (player_name.size() - max_characters);
|
|
|
|
player_name = player_name.subString(begin, max_characters, false);
|
|
|
|
}
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
video::SColor text_color = white_color;
|
|
|
|
if (m_highscore_rank - 1 == i)
|
|
|
|
{
|
|
|
|
text_color = video::SColor(255, 255, 0, 0);
|
|
|
|
}
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
int current_x = x;
|
2016-06-15 19:36:37 -04:00
|
|
|
current_y = y + (int)((i + 1) * m_distance_between_rows * 1.5f);
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
const KartProperties* prop = kart_properties_manager->getKart(kart_name);
|
|
|
|
if (prop != NULL)
|
2013-01-20 15:28:47 -05:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
const std::string &icon_path = prop->getAbsoluteIconFile();
|
|
|
|
video::ITexture* kart_icon_texture = irr_driver->getTexture(icon_path);
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
if (kart_icon_texture != NULL)
|
|
|
|
{
|
|
|
|
core::recti source_rect(core::vector2di(0, 0),
|
|
|
|
kart_icon_texture->getSize());
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
core::recti dest_rect(current_x, current_y,
|
|
|
|
current_x + m_width_icon, current_y + m_width_icon);
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
draw2DImage(
|
|
|
|
kart_icon_texture, dest_rect,
|
|
|
|
source_rect, NULL, NULL,
|
|
|
|
true);
|
|
|
|
|
|
|
|
current_x += m_width_icon + m_width_column_space;
|
|
|
|
}
|
2013-01-20 15:28:47 -05:00
|
|
|
}
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// draw the player name
|
|
|
|
GUIEngine::getSmallFont()->draw(player_name.c_str(),
|
|
|
|
core::recti(current_x, current_y, current_x + 150, current_y + 10),
|
|
|
|
text_color,
|
|
|
|
false, false, NULL, true /* ignoreRTL */);
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
current_x = (int)(UserConfigParams::m_width * 0.85f);
|
2012-10-20 15:01:45 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// Finally draw the time
|
|
|
|
std::string time_string = StringUtils::timeToString(time);
|
|
|
|
GUIEngine::getSmallFont()->draw(time_string.c_str(),
|
|
|
|
core::recti(current_x, current_y, current_x + 100, current_y + 10),
|
|
|
|
text_color,
|
|
|
|
false, false, NULL, true /* ignoreRTL */);
|
|
|
|
}
|
2012-10-20 15:01:45 -04:00
|
|
|
}
|
2016-06-15 19:36:37 -04:00
|
|
|
|
|
|
|
if (race_manager->getMinorMode() != RaceManager::MINOR_MODE_SOCCER)
|
|
|
|
{
|
|
|
|
// display lap count
|
|
|
|
if (race_manager->modeHasLaps())
|
|
|
|
{
|
|
|
|
core::stringw laps = _("Laps: %i", race_manager->getNumLaps());
|
2016-07-26 17:54:54 -04:00
|
|
|
current_y += int(m_distance_between_rows * 0.8f * 2);
|
2016-06-15 19:36:37 -04:00
|
|
|
GUIEngine::getFont()->draw(laps, core::recti(x, current_y, 0, 0),
|
|
|
|
white_color, false, false, nullptr, true);
|
|
|
|
}
|
|
|
|
// display difficulty
|
|
|
|
const core::stringw& difficulty_name =
|
|
|
|
race_manager->getDifficultyName(race_manager->getDifficulty());
|
|
|
|
core::stringw difficulty_string = _("Difficulty: %s", difficulty_name);
|
2016-07-26 17:54:54 -04:00
|
|
|
current_y += int(m_distance_between_rows * 0.8f);
|
2016-06-15 19:36:37 -04:00
|
|
|
GUIEngine::getFont()->draw(difficulty_string, core::recti(x, current_y, 0, 0),
|
|
|
|
white_color, false, false, nullptr, true);
|
|
|
|
// show fastest lap
|
|
|
|
if (race_manager->modeHasLaps())
|
|
|
|
{
|
|
|
|
float best_lap_time = static_cast<LinearWorld*>(World::getWorld())->getFastestLap();
|
|
|
|
core::stringw best_lap_string = _("Best lap time: %s",
|
|
|
|
StringUtils::timeToString(best_lap_time).c_str());
|
2016-07-26 17:54:54 -04:00
|
|
|
current_y += int(m_distance_between_rows * 0.8f);
|
2016-06-15 19:36:37 -04:00
|
|
|
GUIEngine::getFont()->draw(best_lap_string,
|
|
|
|
core::recti(x, current_y, 0, 0), white_color, false, false,
|
|
|
|
nullptr, true);
|
2016-04-17 10:29:59 -04:00
|
|
|
} // if mode has laps
|
|
|
|
} // if not soccer mode
|
|
|
|
#endif
|
2012-10-20 15:01:45 -04:00
|
|
|
}
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
void RaceResultGUI::displayScreenShots()
|
2014-03-26 20:14:29 -04:00
|
|
|
{
|
2016-03-17 02:19:21 -04:00
|
|
|
const std::vector<std::string> tracks =
|
|
|
|
race_manager->getGrandPrix().getTrackNames();
|
|
|
|
int currentTrack = race_manager->getTrackNumber();
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
int n_sshot = 1;
|
|
|
|
for (int i = m_start_track; i < m_end_track; i++)
|
|
|
|
{
|
|
|
|
Track* track = track_manager->getTrack(tracks[i]);
|
|
|
|
GUIEngine::IconButtonWidget* sshot = getWidget<GUIEngine::IconButtonWidget>(
|
|
|
|
("sshot_" + StringUtils::toString(n_sshot)).c_str());
|
|
|
|
GUIEngine::LabelWidget* label = getWidget<GUIEngine::LabelWidget>(
|
|
|
|
("sshot_label_" + StringUtils::toString(n_sshot)).c_str());
|
2018-04-21 04:00:14 -04:00
|
|
|
assert(sshot != NULL && label != NULL);
|
2016-03-17 02:19:21 -04:00
|
|
|
|
2018-04-21 04:32:43 -04:00
|
|
|
// Network grand prix chooses each track 1 by 1
|
2018-04-21 04:00:14 -04:00
|
|
|
if (track == NULL)
|
|
|
|
{
|
|
|
|
sshot->setImage(file_manager->getAsset(FileManager::GUI,
|
|
|
|
"main_help.png"));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sshot->setImage(track->getScreenshotFile());
|
2016-03-17 02:19:21 -04:00
|
|
|
if (i <= currentTrack)
|
|
|
|
sshot->setBadge(GUIEngine::OK_BADGE);
|
|
|
|
else
|
|
|
|
sshot->resetAllBadges();
|
2014-03-26 20:14:29 -04:00
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
label->setText(StringUtils::toWString(i + 1), true);
|
|
|
|
|
|
|
|
n_sshot++;
|
|
|
|
}
|
2014-03-26 20:14:29 -04:00
|
|
|
}
|
|
|
|
|
2016-03-17 02:19:21 -04:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
int RaceResultGUI::getFontHeight() const
|
|
|
|
{
|
|
|
|
assert(m_font != NULL);
|
|
|
|
return m_font->getDimension(L"A").Height; //Could be any capital letter
|
|
|
|
}
|