Merge branch 'master' of https://github.com/supertuxkart/stk-code
This commit is contained in:
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 );
|
||||
|
||||
|
||||
@@ -370,6 +370,9 @@ void RibbonWidget::add()
|
||||
m_element->setTabOrder(id);
|
||||
m_element->setTabGroup(false);
|
||||
updateSelection();
|
||||
|
||||
if (!m_is_visible)
|
||||
setVisible(false);
|
||||
} // add
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(); }
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
Reference in New Issue
Block a user