This commit is contained in:
hiker
2016-03-21 11:03:48 +11:00
25 changed files with 359 additions and 449 deletions

View File

@@ -3,13 +3,23 @@
<div x="5%" y="5%" width="90%" height="90%" layout="vertical-row">
<div x="5%" y="0%" width="90%" proportion="6" layout="horizontal-row">
<div width="40%" height="100%" layout="vertical-row">
<icon id="icon" align="center" proportion="8" width="100%" icon="gui/loading.png" />
<spacer proportion="1" />
<icon id="icon" align="center" width="100%" icon="gui/loading.png" />
</div>
<spacer proportion="1" />
<div width="60%" height="50%" layout="vertical-row">
<label id="name" width="100%" text_align="left"/>
<spacer height="10"/>
</div>
</div>
<div width="90%" align="center" layout="vertical-row" height="fit">
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="record-race" I18N="Ghost replay info action" text_align="left"/>
<spacer width="10"/>
<label proportion="1" id="record-race-text" height="100%" text_align="left" I18N="Ghost replay info action" text="Record the race for ghost replay"/>
</div>
<div width="100%" height="fit" layout="horizontal-row" >
<checkbox width="fit" id="watch-only" I18N="Ghost replay info action" text_align="left"/>
<spacer width="10"/>
<label proportion="1" id="watch-only-text" height="100%" text_align="left" I18N="Ghost replay info action" text="Watch replay only"/>
</div>
</div>

View File

@@ -70,11 +70,11 @@
</div>
<spacer height="10"/>
<div width="100%" height="fit" layout="horizontal-row" >
<label id="reverse-text" proportion="1" I18N="In the track info screen" text="Drive in reverse" text_align="right"/>
<label id="option-text" proportion="1" I18N="In the track info screen" text_align="right"/>
<spacer width="40"/>
<div proportion="1" height="fit" layout="horizontal-row">
<div width="50%" height="fit" text-align="center" layout="vertical-row" >
<checkbox id="reverse" align="center"/>
<checkbox id="option" align="center"/>
</div>
</div>
</div>

View File

@@ -515,6 +515,9 @@ namespace UserConfigParams
/** If track debugging is enabled. */
PARAM_PREFIX int m_track_debug PARAM_DEFAULT( false );
/** If random number of items is used in an arena. */
PARAM_PREFIX bool m_random_arena_item PARAM_DEFAULT( false );
/** True if check structures should be debugged. */
PARAM_PREFIX bool m_check_debug PARAM_DEFAULT( false );

View File

@@ -370,6 +370,9 @@ void RibbonWidget::add()
m_element->setTabOrder(id);
m_element->setTabGroup(false);
updateSelection();
if (!m_is_visible)
setVisible(false);
} // add
// ----------------------------------------------------------------------------

View File

@@ -710,7 +710,8 @@ void InputManager::dispatchInput(Input::InputType type, int deviceID,
// ... when in-game
if (StateManager::get()->getGameState() == GUIEngine::GAME &&
!GUIEngine::ModalDialog::isADialogActive() )
!GUIEngine::ModalDialog::isADialogActive() &&
!race_manager->isWatchingReplay() )
{
if (player == NULL)
{

View File

@@ -23,6 +23,7 @@
#include <sstream>
#include "config/stk_config.hpp"
#include "config/user_config.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/material.hpp"
#include "graphics/material_manager.hpp"
@@ -32,6 +33,7 @@
#include "network/network_config.hpp"
#include "network/race_event_manager.hpp"
#include "tracks/quad_graph.hpp"
#include "tracks/battle_graph.hpp"
#include "tracks/track.hpp"
#include "utils/string_utils.hpp"
@@ -473,3 +475,103 @@ void ItemManager::switchItems()
m_switch_time = m_switch_time < 0 ? stk_config->m_item_switch_time : -1;
} // switchItems
//-----------------------------------------------------------------------------
bool ItemManager::randomItemsForArena(const AlignedArray<btTransform>& pos)
{
if (!UserConfigParams::m_random_arena_item) return false;
if (!BattleGraph::get()) return false;
std::vector<int> used_location;
std::vector<int> invalid_location;
for (unsigned int i = 0; i < pos.size(); i++)
{
// Load all starting positions of arena, so no items will be near them
int node = BattleGraph::get()->pointToNode(/*cur_node*/-1,
Vec3(pos[i].getOrigin()), /*ignore_vertical*/true);
assert(node != -1);
used_location.push_back(node);
invalid_location.push_back(node);
}
RandomGenerator random;
const unsigned int MIN_DIST = sqrt(BattleGraph::get()->getNumNodes());
const unsigned int TOTAL_ITEM = MIN_DIST / 2;
Log::info("[ItemManager]","Creating %d random items for arena", TOTAL_ITEM);
for (unsigned int i = 0; i < TOTAL_ITEM; i++)
{
int chosen_node = -1;
const unsigned int total_node = BattleGraph::get()->getNumNodes();
while(true)
{
if (used_location.size() - pos.size() +
invalid_location.size() == total_node)
{
Log::warn("[ItemManager]","Can't place more random items! "
"Use default item location.");
return false;
}
const int node = random.get(total_node);
// Check if tried
std::vector<int>::iterator it = std::find(invalid_location.begin(),
invalid_location.end(), node);
if (it != invalid_location.end())
continue;
// Check if near edge
if (BattleGraph::get()->isNearEdge(node))
{
invalid_location.push_back(node);
continue;
}
// Check if too close
bool found = true;
for (unsigned int j = 0; j < used_location.size(); j++)
{
if (!found) continue;
Vec3 d = BattleGraph::get()
->getPolyOfNode(used_location[j]).getCenter() -
BattleGraph::get()->getPolyOfNode(node).getCenter();
found = d.length_2d() > MIN_DIST;
}
if (found)
{
chosen_node = node;
invalid_location.push_back(node);
break;
}
else
invalid_location.push_back(node);
}
assert(chosen_node != -1);
used_location.push_back(chosen_node);
}
for (unsigned int i = 0; i < pos.size(); i++)
used_location.erase(used_location.begin());
assert (used_location.size() == TOTAL_ITEM);
// Hard-coded ratio for now
const int BONUS_BOX = 4;
const int NITRO_BIG = 2;
const int NITRO_SMALL = 1;
for (unsigned int i = 0; i < TOTAL_ITEM; i++)
{
const int j = random.get(10);
Item::ItemType type = (j > BONUS_BOX ? Item::ITEM_BONUS_BOX :
j > NITRO_BIG ? Item::ITEM_NITRO_BIG :
j > NITRO_SMALL ? Item::ITEM_NITRO_SMALL : Item::ITEM_BANANA);
Vec3 loc = BattleGraph::get()
->getPolyOfNode(used_location[i]).getCenter();
Item* item = newItem(type, loc, Vec3(0, 1, 0));
BattleGraph::get()->insertItems(item, used_location[i]);
}
return true;
} // randomItemsForArena

View File

@@ -19,7 +19,10 @@
#ifndef HEADER_ITEMMANAGER_HPP
#define HEADER_ITEMMANAGER_HPP
#include "LinearMath/btTransform.h"
#include "items/item.hpp"
#include "utils/aligned_array.hpp"
#include "utils/no_copy.hpp"
#include <SColor.h>
@@ -110,6 +113,8 @@ public:
int add_info=-1);
void switchItems ();
// ------------------------------------------------------------------------
bool randomItemsForArena(const AlignedArray<btTransform>& pos);
// ------------------------------------------------------------------------
/** Returns the number of items. */
unsigned int getNumberOfItems() const { return (unsigned int) m_all_items.size(); }
// ------------------------------------------------------------------------

View File

@@ -83,6 +83,19 @@ void GhostKart::update(float dt)
}
const unsigned int idx = gc->getCurrentReplayIndex();
if (!race_manager->isWatchingReplay())
{
if (idx == 0)
{
m_node->setVisible(false);
}
if (idx == 1)
{
// Start showing the ghost when it start racing
m_node->setVisible(true);
}
}
const float rd = gc->getReplayDelta();
assert(idx < m_all_transform.size());

View File

@@ -21,6 +21,7 @@
#include "items/powerup_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "karts/controller/controller.hpp"
#include "karts/controller/ghost_controller.hpp"
#include "network/network_config.hpp"
//-----------------------------------------------------------------------------
@@ -34,6 +35,11 @@ StandardRace::StandardRace() : LinearWorld()
*/
bool StandardRace::isRaceOver()
{
if (race_manager->isWatchingReplay())
{
return dynamic_cast<GhostController*>
(m_karts[0]->getController())->isReplayEnd();
}
// The race is over if all players have finished the race. Remaining
// times for AI opponents will be estimated in enterRaceOverState
return race_manager->allPlayerFinished();

View File

@@ -285,10 +285,11 @@ void World::reset()
Log::info("World", "Start Recording race.");
ReplayRecorder::get()->init();
}
if(NetworkConfig::get()->isServer() && !ProfileWorld::isNoGraphics())
if((NetworkConfig::get()->isServer() && !ProfileWorld::isNoGraphics()) ||
race_manager->isWatchingReplay())
{
// In case that the server is running with gui, create a camera and
// attach it to the first kart.
// In case that the server is running with gui or watching replay,
// create a camera and attach it to the first kart.
Camera::createCamera(World::getWorld()->getKart(0));
}
@@ -322,8 +323,12 @@ AbstractKart *World::createKart(const std::string &kart_ident, int index,
RaceManager::KartType kart_type,
PerPlayerDifficulty difficulty)
{
unsigned int gk = 0;
if (race_manager->hasGhostKarts())
gk = ReplayPlay::get()->getNumGhostKart();
int position = index+1;
btTransform init_pos = getStartTransform(index);
btTransform init_pos = getStartTransform(index - gk);
AbstractKart *new_kart = new Kart(kart_ident, index, position, init_pos,
difficulty);
new_kart->init(race_manager->getKartType(index));
@@ -440,8 +445,11 @@ World::~World()
ReplayPlay::create();
}
m_karts.clear();
if(race_manager->willRecordRace())
ReplayRecorder::get()->reset();
race_manager->setRaceGhostKarts(false);
race_manager->setRecordRace(false);
race_manager->setWatchingReplay(false);
Camera::removeAllCameras();

View File

@@ -78,6 +78,7 @@ RaceManager::RaceManager()
setReverseTrack(false);
setRecordRace(false);
setRaceGhostKarts(false);
setWatchingReplay(false);
setTrack("jungle");
m_default_ai_list.clear();
setNumPlayers(0);
@@ -913,6 +914,7 @@ void RaceManager::startSingleRace(const std::string &track_ident,
const int num_laps,
bool from_overworld)
{
assert(!m_watching_replay);
StateManager::get()->enterGameState();
setTrack(track_ident);
@@ -931,10 +933,46 @@ void RaceManager::startSingleRace(const std::string &track_ident,
//-----------------------------------------------------------------------------
/** Fills up the remaining kart slots with AI karts.
v*/
*/
void RaceManager::setupPlayerKartInfo()
{
computeRandomKartList();
} // setupPlayerKartInfo
//-----------------------------------------------------------------------------
/** \brief Function to start the race with only ghost kart(s) and watch.
* \param trackIdent Internal name of the track to race on
* \param num_laps Number of laps to race, or -1 if number of laps is
* not relevant in current mode
*/
void RaceManager::startWatchingReplay(const std::string &track_ident,
const int num_laps)
{
assert(m_watching_replay && m_has_ghost_karts && !m_will_record_race);
StateManager::get()->enterGameState();
setTrack(track_ident);
setNumLaps(num_laps);
setMajorMode(RaceManager::MAJOR_MODE_SINGLE);
setCoinTarget(0);
m_num_karts = ReplayPlay::get()->getNumGhostKart();
m_kart_status.clear();
Log::verbose("RaceManager", "%u ghost kart(s) for watching replay only\n",
(unsigned int)m_num_karts);
int init_gp_rank = 0;
for(int i = 0; i < m_num_karts; i++)
{
m_kart_status.push_back(KartStatus(ReplayPlay::get()->getGhostKartName(i),
i, -1, -1, init_gp_rank, KT_GHOST, PLAYER_DIFFICULTY_NORMAL));
init_gp_rank ++;
}
m_track_number = 0;
startNextRace();
} // startSingleRace
//-----------------------------------------------------------------------------
/* EOF */

View File

@@ -354,6 +354,8 @@ private:
bool m_will_record_race;
bool m_has_ghost_karts;
bool m_watching_replay;
public:
RaceManager();
~RaceManager();
@@ -407,6 +409,7 @@ public:
void saveGP();
void startSingleRace(const std::string &track_ident, const int num_laps,
bool from_overworld);
void startWatchingReplay(const std::string &track_ident, const int num_laps);
void setupPlayerKartInfo();
void kartFinishedRace(const AbstractKart* kart, float time);
void setNumPlayers(int players, int local_players=-1);
@@ -727,6 +730,11 @@ public:
m_has_ghost_karts = ghost;
} // setRaceGhostKarts
// ------------------------------------------------------------------------
void setWatchingReplay(bool watch)
{
m_watching_replay = watch;
} // setWatchingReplay
// ------------------------------------------------------------------------
bool willRecordRace() const
{
return m_will_record_race;
@@ -736,6 +744,11 @@ public:
{
return m_has_ghost_karts;
} // hasGhostKarts
// ------------------------------------------------------------------------
bool isWatchingReplay() const
{
return m_watching_replay;
} // isWatchingReplay
}; // RaceManager

View File

@@ -50,16 +50,31 @@ ReplayRecorder::~ReplayRecorder()
} // ~Replay
//-----------------------------------------------------------------------------
/** Initialise the replay recorder. It especially allocates memory
* to store the replay data.
*/
void ReplayRecorder::init()
/** Reset the replay recorder. */
void ReplayRecorder::reset()
{
m_complete_replay = false;
m_incorrect_replay = false;
m_transform_events.clear();
m_physic_info.clear();
m_kart_replay_event.clear();
m_count_transforms.clear();
m_last_saved_time.clear();
#ifdef DEBUG
m_count = 0;
m_count_skipped_time = 0;
m_count_skipped_interpolation = 0;
#endif
} // clear
//-----------------------------------------------------------------------------
/** Initialise the replay recorder. It especially allocates memory
* to store the replay data.
*/
void ReplayRecorder::init()
{
reset();
m_transform_events.resize(race_manager->getNumberOfKarts());
m_physic_info.resize(race_manager->getNumberOfKarts());
m_kart_replay_event.resize(race_manager->getNumberOfKarts());
@@ -71,16 +86,10 @@ void ReplayRecorder::init()
m_physic_info[i].resize(max_frames);
m_kart_replay_event[i].resize(max_frames);
}
m_count_transforms.clear();
m_count_transforms.resize(race_manager->getNumberOfKarts(), 0);
m_last_saved_time.clear();
m_last_saved_time.resize(race_manager->getNumberOfKarts(), -1.0f);
#ifdef DEBUG
m_count = 0;
m_count_skipped_time = 0;
m_count_skipped_interpolation = 0;
#endif
} // init
//-----------------------------------------------------------------------------

View File

@@ -70,8 +70,9 @@ private:
~ReplayRecorder();
public:
void init();
void update(float dt);
void reset();
void save();
void update(float dt);
// ------------------------------------------------------------------------
/** Creates a new instance of the replay object. */

View File

@@ -31,6 +31,9 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id)
: ModalDialog(0.8f,0.5f), m_replay_id(replay_id)
{
m_self_destroy = false;
m_record_race = false;
m_watch_only = false;
m_rd = ReplayPlay::get()->getReplayData(m_replay_id);
loadFromFile("ghost_replay_info_dialog.stkgui");
@@ -41,6 +44,19 @@ GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id)
m_back_widget = getWidget<IconButtonWidget>("back");
m_back_widget->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
m_action_widget = getWidget<RibbonWidget>("actions");
m_record_widget = getWidget<CheckBoxWidget>("record-race");
m_watch_widget = getWidget<CheckBoxWidget>("watch-only");
if (race_manager->getNumLocalPlayers() > 1)
{
// No watching replay when split-screen
m_watch_widget->setVisible(false);
getWidget<LabelWidget>("watch-only-text")->setVisible(false);
}
m_record_widget->setState(false);
m_watch_widget->setState(false);
} // GhostReplayInfoDialog
// -----------------------------------------------------------------------------
@@ -65,16 +81,25 @@ GUIEngine::EventPropagation
int laps = m_rd.m_laps;
int replay_id = m_replay_id;
race_manager->setRecordRace(m_record_race);
race_manager->setWatchingReplay(m_watch_only);
ModalDialog::dismiss();
ReplayPlay::get()->setReplayFile(replay_id);
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);
if (race_manager->isWatchingReplay())
race_manager->startWatchingReplay(track_name, laps);
else
race_manager->startSingleRace(track_name, laps, false);
return GUIEngine::EVENT_BLOCK;
}
else if(selection == "remove")
@@ -92,6 +117,20 @@ GUIEngine::EventPropagation
return GUIEngine::EVENT_BLOCK;
}
}
if (event_source == "record-race")
{
m_record_race = m_record_widget->getState();
}
else if (event_source == "watch-only")
{
m_watch_only = m_watch_widget->getState();
m_record_race = false;
m_record_widget->setState(false);
m_record_widget->setVisible(!m_watch_only);
getWidget<LabelWidget>("record-race-text")->setVisible(!m_watch_only);
}
return GUIEngine::EVENT_LET;
} // processEvent

View File

@@ -20,6 +20,7 @@
#define HEADER_GHOST_REPLAY_INFO_DIALOG_HPP
#include "guiengine/modaldialog.hpp"
#include "guiengine/widgets/check_box_widget.hpp"
#include "guiengine/widgets/icon_button_widget.hpp"
#include "guiengine/widgets/ribbon_widget.hpp"
#include "replay/replay_play.hpp"
@@ -34,11 +35,16 @@ private:
bool m_self_destroy;
bool m_record_race;
bool m_watch_only;
const unsigned int m_replay_id;
ReplayPlay::ReplayData m_rd;
GUIEngine::RibbonWidget* m_action_widget;
GUIEngine::IconButtonWidget* m_back_widget;
GUIEngine::CheckBoxWidget* m_record_widget;
GUIEngine::CheckBoxWidget* m_watch_widget;
public:
GhostReplayInfoDialog(unsigned int replay_id);

View File

@@ -1,303 +0,0 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Marianne Gagnon
//
// 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/dialogs/gp_info_dialog.hpp"
#include "challenges/unlock_manager.hpp"
#include "config/player_manager.hpp"
#include "config/saved_grand_prix.hpp"
#include "guiengine/engine.hpp"
#include "guiengine/screen.hpp"
#include "guiengine/widgets/button_widget.hpp"
#include "guiengine/widgets/icon_button_widget.hpp"
#include "guiengine/widgets/label_widget.hpp"
#include "io/file_manager.hpp"
#include "race/grand_prix_manager.hpp"
#include "race/grand_prix_data.hpp"
#include "race/race_manager.hpp"
#include "states_screens/state_manager.hpp"
#include "states_screens/tracks_screen.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "utils/translation.hpp"
#include <IGUIEnvironment.h>
#include <IGUIStaticText.h>
using irr::gui::IGUIStaticText;
using GUIEngine::PROP_ID;
typedef GUIEngine::LabelWidget Label;
const float GPInfoDialog::PERCENT_WIDTH = 0.8f;
const float GPInfoDialog::PERCENT_HEIGHT = 0.7f;
GPInfoDialog::GPInfoDialog(const std::string& gp_ident)
: ModalDialog(PERCENT_WIDTH, PERCENT_HEIGHT)
{
doInit();
m_curr_time = 0.0f;
m_gp = *grand_prix_manager->getGrandPrix(gp_ident);
m_gp.checkConsistency();
m_under_title = m_area.getHeight()/7;
m_over_body = m_area.getHeight()/7;
m_lower_bound = m_area.getHeight()*6/7;
addTitle();
addTracks();
addScreenshot();
addButtons();
}
// ----------------------------------------------------------------------------
GPInfoDialog::~GPInfoDialog()
{
GUIEngine::Screen* curr_screen = GUIEngine::getCurrentScreen();
if (curr_screen->getName() == "tracks.stkgui")
static_cast<TracksScreen*>(curr_screen)->setFocusOnGP(m_gp.getId());
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addTitle()
{
core::rect< s32 > area_top(0, 0, m_area.getWidth(), m_under_title);
const wchar_t *text = translations->fribidize(m_gp.getName());
IGUIStaticText* title = GUIEngine::getGUIEnv()->addStaticText(
text,
area_top, false, true, // border, word wrap
m_irrlicht_window);
title->setTabStop(false);
title->setTextAlignment(irr::gui::EGUIA_CENTER, irr::gui::EGUIA_CENTER);
title->setRightToLeft(translations->isRTLText(text));
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addTracks()
{
const std::vector<std::string> tracks = m_gp.getTrackNames();
const unsigned int track_amount = tracks.size();
int height_of_one_line = std::min((m_lower_bound - m_over_body)/(track_amount+1),
(unsigned int)(GUIEngine::getFontHeight()*1.5f));
// Count the number of label already existing labels representing a track
unsigned int existing = 0;
for (unsigned int i = 0; i < m_widgets.size(); i++)
{
if (m_widgets.get(i)->m_properties[PROP_ID] == "Track label")
existing++;
}
unsigned int reuse = std::min(existing, track_amount);
// m_widgets has the type PtrVector<Widget, HOLD>
unsigned int widgets_iter = 0;
for (unsigned int i = 0; i < reuse; i++)
{
Track* track = track_manager->getTrack(tracks[i]);
// Find the next widget that is a track label
while (m_widgets.get(widgets_iter)->m_properties[PROP_ID] != "Track label")
widgets_iter++;
Label* widget = dynamic_cast<Label*>(m_widgets.get(widgets_iter));
widget->setText(translations->fribidize(track->getName()), false);
widget->move(20, m_over_body + height_of_one_line*i,
m_area.getWidth()/2 - 20, height_of_one_line);
widgets_iter++;
}
if (existing < track_amount)
{
// There are not enough labels for all the track names, so we have to
// add some more
for (unsigned int i = reuse; i < track_amount; i++)
{
Track* track = track_manager->getTrack(tracks[i]);
assert(track != NULL);
Label* widget = new Label();
widget->m_properties[PROP_ID] = "Track label";
widget->setText(translations->fribidize(track->getName()), false);
widget->setParent(m_irrlicht_window);
m_widgets.push_back(widget);
widget->add();
widget->move(20, m_over_body + height_of_one_line*i,
m_area.getWidth()/2 - 20, height_of_one_line);
}
}
else if (existing > track_amount)
{
// There are label which are not necessary anymore so they're deleted
for (unsigned int i = widgets_iter; i < m_widgets.size(); i++)
{
if (m_widgets.get(i)->m_properties[PROP_ID] == "Track label")
{
m_irrlicht_window->removeChild(m_widgets.get(i)->getIrrlichtElement());
m_widgets.remove(i);
i--;
}
}
}
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addScreenshot()
{
m_screenshot_widget = new GUIEngine::IconButtonWidget(
GUIEngine::IconButtonWidget::SCALE_MODE_KEEP_CUSTOM_ASPECT_RATIO,
false, false, GUIEngine::IconButtonWidget::ICON_PATH_TYPE_ABSOLUTE);
// images are saved squared, but must be stretched to 4:3
m_screenshot_widget->setCustomAspectRatio(4.0f / 3.0f);
m_screenshot_widget->m_x = m_area.getWidth()/2-20;
m_screenshot_widget->m_y = m_over_body + 10;
// Scale the picture to the biggest possible size without an overflow
if (m_lower_bound - m_over_body - 20 < m_area.getWidth()/2*3/4)
{
m_screenshot_widget->m_w = (m_lower_bound - m_over_body - 30)*4/3;
m_screenshot_widget->m_h = m_lower_bound - m_over_body - 30;
}
else
{
m_screenshot_widget->m_w = m_area.getWidth()/2;
m_screenshot_widget->m_h = m_area.getWidth()*3/8; // *(3/4)*(1/2)
}
Track* track = track_manager->getTrack(m_gp.getTrackNames()[0]);
m_screenshot_widget->m_properties[GUIEngine::PROP_ICON] = (track->getScreenshotFile().c_str());
m_screenshot_widget->setParent(m_irrlicht_window);
m_screenshot_widget->add();
m_widgets.push_back(m_screenshot_widget);
}
// ----------------------------------------------------------------------------
void GPInfoDialog::addButtons()
{
// ---- Start button
GUIEngine::ButtonWidget* okBtn = new GUIEngine::ButtonWidget();
GUIEngine::ButtonWidget* continueBtn = new GUIEngine::ButtonWidget();
SavedGrandPrix* saved_gp = SavedGrandPrix::getSavedGP( StateManager::get()
->getActivePlayerProfile(0)
->getUniqueID(),
m_gp.getId(),
race_manager->getMinorMode(),
race_manager->getNumLocalPlayers());
okBtn->m_properties[PROP_ID] = "start";
okBtn->setText(_("Start Grand Prix"));
continueBtn->m_properties[PROP_ID] = "continue";
continueBtn->setText(_("Continue"));
if (saved_gp)
{
continueBtn->m_x = m_area.getWidth()/2 + 110;
continueBtn->m_y = m_lower_bound;
continueBtn->m_w = 200;
continueBtn->m_h = m_area.getHeight() - m_lower_bound - 15;
continueBtn->setParent(m_irrlicht_window);
m_widgets.push_back(continueBtn);
continueBtn->add();
continueBtn->getIrrlichtElement()->setTabStop(true);
continueBtn->getIrrlichtElement()->setTabGroup(false);
okBtn->m_x = m_area.getWidth()/2 - 310;
}
else
{
okBtn->m_x = m_area.getWidth()/2 - 200;
}
okBtn->m_y = m_lower_bound;
okBtn->m_w = 400;
okBtn->m_h = m_area.getHeight() - m_lower_bound - 15;
okBtn->setParent(m_irrlicht_window);
m_widgets.push_back(okBtn);
okBtn->add();
okBtn->getIrrlichtElement()->setTabStop(true);
okBtn->getIrrlichtElement()->setTabGroup(false);
okBtn->setFocusForPlayer( PLAYER_ID_GAME_MASTER );
}
// ----------------------------------------------------------------------------
void GPInfoDialog::onEnterPressedInternal()
{
// Save the GP id because dismiss() will destroy this instance
std::string gp_id = m_gp.getId();
ModalDialog::dismiss();
// Disable accidentally unlocking of a challenge
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
race_manager->startGP(*grand_prix_manager->getGrandPrix(gp_id), false, false);
}
// ----------------------------------------------------------------------------
GUIEngine::EventPropagation GPInfoDialog::processEvent(const std::string& event_source)
{
if (event_source == "start" || event_source == "continue")
{
// Save GP identifier, since dismiss will delete this object.
std::string gp_id = m_gp.getId();
// Also create a copy of the string: it is a reference to data
// in a widget in the dialog - so if we call dismiss, this reference
// becomes invalid!
std::string save_source = event_source;
ModalDialog::dismiss();
//race_manager->startGP(grand_prix_manager->getGrandPrix(gp_id), false,
// (save_source == "continue"));
return GUIEngine::EVENT_BLOCK;
}
return GUIEngine::EVENT_LET;
}
// ----------------------------------------------------------------------------
void GPInfoDialog::onUpdate(float dt)
{
if (dt == 0)
return; // if nothing changed, return right now
m_curr_time += dt;
int frameAfter = (int)(m_curr_time / 1.5f);
const std::vector<std::string> tracks = m_gp.getTrackNames();
if (frameAfter >= (int)tracks.size())
{
frameAfter = 0;
m_curr_time = 0;
}
Track* track = track_manager->getTrack(tracks[frameAfter]);
std::string file = track->getScreenshotFile();
typedef GUIEngine::IconButtonWidget Icon;
m_screenshot_widget->setImage(file.c_str(), Icon::ICON_PATH_TYPE_ABSOLUTE);
}

View File

@@ -1,83 +0,0 @@
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2009-2015 Marianne Gagnon
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#ifndef HEADER_GP_INFO_DIALOG_HPP
#define HEADER_GP_INFO_DIALOG_HPP
#include "guiengine/modaldialog.hpp"
#include "race/grand_prix_data.hpp"
class GrandPrixData;
namespace GUIEngine
{
class IconButtonWidget;
}
/**
* \brief Dialog that shows information about a specific grand prix
* \ingroup states_screens
*/
class GPInfoDialog : public GUIEngine::ModalDialog
{
protected: // Necessary for RandomGPInfoDialog
GUIEngine::IconButtonWidget* m_screenshot_widget;
float m_curr_time;
/** The grand prix data. */
GrandPrixData m_gp;
/** height of the separator over the body */
int m_over_body;
/** height of the separator under the titlebar, which is equal to
* m_over_body in a normal GPInfoDialo and lower in RandomGPInfoDialog. */
int m_under_title;
/** height of the seperator over the buttons */
int m_lower_bound;
void addTitle();
/** \brief display all the tracks according to the current gp
* For a normal gp info dialog, it just creates a label for every track.
* But with a random gp info dialog, it tries to reuse as many
* labels as possible by just changing their text. */
void addTracks();
void addScreenshot();
/** display a ok-button and eventually a continue-button */
void addButtons();
/** only used for track_screen.cpp */
GPInfoDialog() : ModalDialog(PERCENT_WIDTH, PERCENT_HEIGHT) {}
private:
static const float PERCENT_WIDTH;
static const float PERCENT_HEIGHT;
public:
GPInfoDialog(const std::string& gpIdent);
/** Places the focus back on the selected GP, in the case that the dialog
* was cancelled and we're returning to the track selection screen */
virtual ~GPInfoDialog();
void onEnterPressedInternal();
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
virtual void onUpdate(float dt);
};
#endif

View File

@@ -27,7 +27,6 @@
#include "states_screens/state_manager.hpp"
#include "states_screens/edit_gp_screen.hpp"
#include "states_screens/dialogs/enter_gp_name_dialog.hpp"
#include "states_screens/dialogs/gp_info_dialog.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "utils/translation.hpp"

View File

@@ -497,7 +497,7 @@ void RaceResultGUI::backToLobby()
const int rm_id = kart->getWorldKartId() -
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
if (rm_id >= 0)
if (rm_id >= 0 && !race_manager->isWatchingReplay())
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
else
ri->m_kart_name = translations->fribidize(kart->getName());
@@ -869,7 +869,7 @@ void RaceResultGUI::backToLobby()
const int rm_id = kart_id -
(race_manager->getNumberOfKarts() - race_manager->getNumPlayers());
if (rm_id >= 0)
if (rm_id >= 0 && !race_manager->isWatchingReplay())
ri->m_kart_name = race_manager->getKartInfo(rm_id).getPlayerName();
else
ri->m_kart_name = translations->fribidize(kart->getName());

View File

@@ -67,9 +67,9 @@ void TrackInfoScreen::loadedFromFile()
{
m_lap_spinner = getWidget<SpinnerWidget>("lap-spinner");
m_ai_kart_spinner = getWidget<SpinnerWidget>("ai-spinner");
m_reverse = getWidget<CheckBoxWidget>("reverse");
m_option = getWidget<CheckBoxWidget>("option");
m_record_race = getWidget<CheckBoxWidget>("record");
m_reverse->setState(false);
m_option->setState(false);
m_record_race->setState(false);
m_highscore_label = getWidget<LabelWidget>("highscores");
@@ -198,18 +198,31 @@ void TrackInfoScreen::init()
else
race_manager->setNumKarts(local_players);
// Reverse track
// Reverse track or random item in arena
// -------------
const bool reverse_available = m_track->reverseAvailable() &&
race_manager->getMinorMode() != RaceManager::MINOR_MODE_EASTER_EGG;
m_reverse->setVisible(reverse_available);
getWidget<LabelWidget>("reverse-text")->setVisible(reverse_available);
const bool random_item = m_track->hasNavMesh();
m_option->setVisible(reverse_available || random_item);
getWidget<LabelWidget>("option-text")->setVisible(reverse_available || random_item);
if (reverse_available)
{
m_reverse->setState(race_manager->getReverseTrack());
//I18N: In the track info screen
getWidget<LabelWidget>("option-text")->setText(_("Drive in reverse"), false);
}
else if (random_item)
{
//I18N: In the track info screen
getWidget<LabelWidget>("option-text")->setText(_("Random item location"), false);
}
if (reverse_available)
{
m_option->setState(race_manager->getReverseTrack());
}
else
m_reverse->setState(false);
m_option->setState(false);
// Record race or not
// -------------
@@ -312,12 +325,16 @@ void TrackInfoScreen::onEnterPressedInternal()
// not be accessible after dismiss:
const int num_laps = race_manager->modeHasLaps() ? m_lap_spinner->getValue()
: -1;
const bool reverse_track = m_reverse == NULL ? false
: m_reverse->getState();
const bool option_state = m_option == NULL ? false
: m_option->getState();
// Avoid negative lap numbers (after e.g. easter egg mode).
if(num_laps>=0)
m_track->setActualNumberOfLaps(num_laps);
race_manager->setReverseTrack(reverse_track);
if(m_track->hasNavMesh())
UserConfigParams::m_random_arena_item = option_state;
else
race_manager->setReverseTrack(option_state);
// Avoid invaild Ai karts number during switching game modes
const int max_arena_players = m_track->getMaxArenaPlayers();
@@ -361,12 +378,19 @@ void TrackInfoScreen::eventCallback(Widget* widget, const std::string& name,
{
StateManager::get()->escapePressed();
}
else if (name == "reverse")
else if (name == "option")
{
race_manager->setReverseTrack(m_reverse->getState());
// Makes sure the highscores get swapped when clicking the 'reverse'
// checkbox.
updateHighScores();
if (m_track->hasNavMesh())
{
UserConfigParams::m_random_arena_item = m_option->getState();
}
else
{
race_manager->setReverseTrack(m_option->getState());
// Makes sure the highscores get swapped when clicking the 'reverse'
// checkbox.
updateHighScores();
}
}
else if (name == "record")
{

View File

@@ -52,8 +52,8 @@ class TrackInfoScreen : public GUIEngine::Screen,
/** Spinner for number of AI karts. */
GUIEngine::SpinnerWidget* m_ai_kart_spinner;
/** Check box for reverse mode. */
GUIEngine::CheckBoxWidget* m_reverse;
/** Check box for reverse mode or random item in arena. */
GUIEngine::CheckBoxWidget* m_option;
/** Check box for record race. */
GUIEngine::CheckBoxWidget* m_record_race;

View File

@@ -116,7 +116,11 @@ public:
const NavPoly& getPolyOfNode(int i) const
{ return NavMesh::get()->getNavPoly(i); }
// ----------------------------------------------------------------------
// ------------------------------------------------------------------------
/** Returns true if the NavPoly lies near the edge. */
bool isNearEdge(int i) const
{ return NavMesh::get()->getNavPoly(i).isPolyNearEdge(); }
// ------------------------------------------------------------------------
/** Returns the next polygon on the shortest path from i to j.
* Note: m_parent_poly[j][i] contains the parent of i on path from j to i,
* which is the next node on the path from i to j (undirected graph) */
@@ -124,9 +128,12 @@ public:
const std::vector < std::pair<const Item*, int> >& getItemList()
{ return m_items_on_graph; }
// ------------------------------------------------------------------------
void insertItems(Item* item, int polygon)
{ m_items_on_graph.push_back(std::make_pair(item, polygon)); }
// ------------------------------------------------------------------------
void findItemsOnGraphNodes();
// ----------------------------------------------------------------------
// ------------------------------------------------------------------------
int pointToNode(const int cur_node,
const Vec3& cur_point,
bool ignore_vertical) const;

View File

@@ -45,11 +45,11 @@ public:
// ------------------------------------------------------------------------
/** Returns the center point of a polygon. */
const Vec3& getCenter() const {return m_center;}
const Vec3& getCenter() const { return m_center; }
// ------------------------------------------------------------------------
/** Returns the adjacent polygons of a polygon. */
const std::vector<int>& getAdjacents() const {return m_adjacents;}
const std::vector<int>& getAdjacents() const { return m_adjacents; }
// ------------------------------------------------------------------------
/** Returns the vertices(Vec3) of this polygon. */
@@ -57,13 +57,17 @@ public:
// ------------------------------------------------------------------------
/** Returns the indices of the vertices of this polygon */
const std::vector<int> getVerticesIndex() const {return m_vertices;}
const std::vector<int> getVerticesIndex() const
{ return m_vertices; }
// ------------------------------------------------------------------------
/** Returns true if a given point lies in this polygon. */
bool pointInPoly(const Vec3& p,
bool ignore_vertical) const;
// ------------------------------------------------------------------------
/** Returns true if this polygon lies near the edge. */
bool isPolyNearEdge() const
{ return m_adjacents.size() < 4; }
// ------------------------------------------------------------------------
const Vec3& operator[](int i) const ;
}; // class NavPoly

View File

@@ -1862,22 +1862,27 @@ void Track::loadTrackModel(bool reverse_track, unsigned int mode_id)
createPhysicsModel(main_track_count);
const bool arena_random_item_created =
ItemManager::get()->randomItemsForArena(m_start_transforms);
for (unsigned int i=0; i<root->getNumNodes(); i++)
if (!arena_random_item_created)
{
const XMLNode *node = root->getNode(i);
const std::string &name = node->getName();
if (name=="banana" || name=="item" ||
name=="small-nitro" || name=="big-nitro" ||
name=="easter-egg" )
for (unsigned int i=0; i<root->getNumNodes(); i++)
{
itemCommand(node);
}
} // for i<root->getNumNodes()
const XMLNode *node = root->getNode(i);
const std::string &name = node->getName();
if (name=="banana" || name=="item" ||
name=="small-nitro" || name=="big-nitro" ||
name=="easter-egg" )
{
itemCommand(node);
}
} // for i<root->getNumNodes()
}
delete root;
if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh)
if ((m_is_arena || m_is_soccer) && !m_is_cutscene && m_has_navmesh && !arena_random_item_created)
BattleGraph::get()->findItemsOnGraphNodes();
if (UserConfigParams::m_track_debug &&