Add Ghost replay GUI
This commit is contained in:
parent
5cd27f8f99
commit
8a121ed32b
30
data/gui/ghost_replay_info_dialog.stkgui
Normal file
30
data/gui/ghost_replay_info_dialog.stkgui
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<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" />
|
||||
</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="80%" proportion="5" align="center">
|
||||
<buttonbar id="actions" x="0" y="0" height="100%" width="100%" align="center">
|
||||
<icon-button id="start" width="128" height="128"
|
||||
icon="gui/green_check.png"
|
||||
I18N="Ghost replay info screen action" text="Start Race" />
|
||||
<icon-button id="remove" width="128" height="128"
|
||||
icon="gui/remove.png"
|
||||
I18N="Ghost replay info action" text="Remove" />
|
||||
<icon-button id="back" width="128" height="128"
|
||||
icon="gui/back.png"
|
||||
I18N="Ghost replay info action" text="Back" />
|
||||
</buttonbar>
|
||||
</div>
|
||||
</div>
|
||||
</stkgui>
|
15
data/gui/ghost_replay_selection.stkgui
Normal file
15
data/gui/ghost_replay_selection.stkgui
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<stkgui>
|
||||
<div x="0%" y="1%" width="100%" height="98%" layout="vertical-row" >
|
||||
|
||||
<div x="0" y="0" width="100%" layout="horizontal-row" height="8%">
|
||||
<icon-button id="back" height="100%" icon="gui/back.png"/>
|
||||
<header text_align="center" proportion="1" text="Ghost Replay Selection" align="center"/>
|
||||
<icon-button id="reload" height="90%" icon="gui/restart.png"/>
|
||||
</div>
|
||||
|
||||
<box proportion="1" width="98%" align="center" layout="vertical-row" padding="6">
|
||||
<list id="replay_list" x="0" y="0" width="100%" height="100%"/>
|
||||
</box>
|
||||
</div>
|
||||
</stkgui>
|
@ -25,6 +25,8 @@
|
||||
<!-- Populated dynamically at runtime -->
|
||||
<tabs width="100%" height="25" id="trackgroups"> </tabs>
|
||||
|
||||
<spacer width="100%" height="2%" />
|
||||
<spacer width="100%" height="3%" />
|
||||
|
||||
<button id="ghost" I18N="In the track selection screen" text="Load Ghost Replay" />
|
||||
</div>
|
||||
</stkgui>
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Modify this file to change the last-modified date when you add/remove a file.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
# This will then trigger a new cmake run automatically.
|
||||
file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||
|
@ -526,7 +526,6 @@ void cmdLineHelp()
|
||||
" spaces are allowed in the track names.\n"
|
||||
" --demo-laps=n Number of laps in a demo.\n"
|
||||
" --demo-karts=n Number of karts to use in a demo.\n"
|
||||
" --ghost Replay ghost data together with one player kart.\n"
|
||||
// " --history Replay history file 'history.dat'.\n"
|
||||
// " --history=n Replay history file 'history.dat' using:\n"
|
||||
// " n=1: recorded positions\n"
|
||||
@ -998,9 +997,6 @@ int handleCmdLine()
|
||||
}
|
||||
} // --with-profile
|
||||
|
||||
if(CommandLine::has("--ghost"))
|
||||
ReplayPlay::create();
|
||||
|
||||
if(CommandLine::has("--history", &n))
|
||||
{
|
||||
history->doReplayHistory( (History::HistoryReplayMode)n);
|
||||
@ -1151,6 +1147,7 @@ void initRest()
|
||||
// The order here can be important, e.g. KartPropertiesManager needs
|
||||
// defaultKartProperties, which are defined in stk_config.
|
||||
history = new History ();
|
||||
ReplayPlay::create();
|
||||
ReplayRecorder::create();
|
||||
material_manager = new MaterialManager ();
|
||||
track_manager = new TrackManager ();
|
||||
@ -1575,7 +1572,6 @@ static void cleanSuperTuxKart()
|
||||
irr_driver->updateConfigIfRelevant();
|
||||
AchievementsManager::destroy();
|
||||
Referee::cleanup();
|
||||
if(ReplayPlay::get()) ReplayPlay::destroy();
|
||||
if(race_manager) delete race_manager;
|
||||
if(grand_prix_manager) delete grand_prix_manager;
|
||||
if(highscore_manager) delete highscore_manager;
|
||||
@ -1587,6 +1583,7 @@ static void cleanSuperTuxKart()
|
||||
if(track_manager) delete track_manager;
|
||||
if(material_manager) delete material_manager;
|
||||
if(history) delete history;
|
||||
ReplayPlay::destroy();
|
||||
ReplayRecorder::destroy();
|
||||
delete ParticleKindManager::get();
|
||||
PlayerManager::destroy();
|
||||
|
@ -147,7 +147,7 @@ void World::init()
|
||||
m_eliminated_players = 0;
|
||||
m_num_players = 0;
|
||||
unsigned int gk = 0;
|
||||
if (ReplayPlay::get())
|
||||
if (race_manager->hasGhostKarts())
|
||||
gk = ReplayPlay::get()->getNumGhostKart();
|
||||
|
||||
// Create the race gui before anything else is attached to the scene node
|
||||
@ -257,7 +257,7 @@ void World::reset()
|
||||
Camera::getCamera(i)->reset();
|
||||
}
|
||||
|
||||
if(ReplayPlay::get())
|
||||
if(race_manager->hasGhostKarts())
|
||||
ReplayPlay::get()->reset();
|
||||
|
||||
resetAllKarts();
|
||||
@ -420,7 +420,7 @@ World::~World()
|
||||
delete m_karts[i];
|
||||
}
|
||||
|
||||
if(ReplayPlay::get())
|
||||
if(race_manager->hasGhostKarts())
|
||||
{
|
||||
// Destroy the old replay object, which also stored the ghost
|
||||
// karts, and create a new one (which means that in further
|
||||
@ -429,6 +429,7 @@ World::~World()
|
||||
ReplayPlay::create();
|
||||
}
|
||||
m_karts.clear();
|
||||
race_manager->setRaceGhostKarts(false);
|
||||
|
||||
Camera::removeAllCameras();
|
||||
|
||||
|
@ -77,6 +77,7 @@ RaceManager::RaceManager()
|
||||
m_have_kart_last_position_on_overworld = false;
|
||||
setReverseTrack(false);
|
||||
setRecordRace(false);
|
||||
setRaceGhostKarts(false);
|
||||
setTrack("jungle");
|
||||
m_default_ai_list.clear();
|
||||
setNumPlayers(0);
|
||||
@ -311,11 +312,8 @@ void RaceManager::computeRandomKartList()
|
||||
void RaceManager::startNew(bool from_overworld)
|
||||
{
|
||||
unsigned int gk = 0;
|
||||
if (ReplayPlay::get())
|
||||
{
|
||||
ReplayPlay::get()->loadBasicInfo();
|
||||
if (m_has_ghost_karts)
|
||||
gk = ReplayPlay::get()->getNumGhostKart();
|
||||
}
|
||||
|
||||
m_started_from_overworld = from_overworld;
|
||||
m_saved_gp = NULL; // There will be checks for this being NULL done later
|
||||
|
@ -351,6 +351,8 @@ private:
|
||||
bool m_continue_saved_gp;
|
||||
|
||||
bool m_will_record_race;
|
||||
|
||||
bool m_has_ghost_karts;
|
||||
public:
|
||||
RaceManager();
|
||||
~RaceManager();
|
||||
@ -704,10 +706,20 @@ public:
|
||||
m_will_record_race = record;
|
||||
} // setRecordRace
|
||||
// ------------------------------------------------------------------------
|
||||
void setRaceGhostKarts(bool ghost)
|
||||
{
|
||||
m_has_ghost_karts = ghost;
|
||||
} // setRaceGhostKarts
|
||||
// ------------------------------------------------------------------------
|
||||
bool willRecordRace() const
|
||||
{
|
||||
return m_will_record_race;
|
||||
} // willRecordRace
|
||||
// ------------------------------------------------------------------------
|
||||
bool hasGhostKarts() const
|
||||
{
|
||||
return m_has_ghost_karts;
|
||||
} // hasGhostKarts
|
||||
|
||||
}; // RaceManager
|
||||
|
||||
|
@ -23,19 +23,16 @@
|
||||
// -----------------------------------------------------------------------------
|
||||
ReplayBase::ReplayBase()
|
||||
{
|
||||
m_filename = "";
|
||||
} // ReplayBaese
|
||||
// -----------------------------------------------------------------------------
|
||||
/** Opens a replay file (depending on the track name, which is taken from
|
||||
* the race manager).
|
||||
/** Opens a replay file which is determined by sub classes.
|
||||
* \param writeable True if the file should be opened for writing.
|
||||
* \return A FILE *, or NULL if the file could not be opened.
|
||||
*/
|
||||
FILE* ReplayBase::openReplayFile(bool writeable)
|
||||
{
|
||||
m_filename = file_manager->getReplayDir() +
|
||||
race_manager->getTrackName() + ".replay";
|
||||
FILE *fd = fopen(m_filename.c_str(), writeable ? "w" : "r");
|
||||
FILE *fd = fopen((file_manager->getReplayDir() +
|
||||
getReplayFilename()).c_str(), writeable ? "w" : "r");
|
||||
if (!fd)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* \ingroup race
|
||||
@ -32,10 +33,20 @@ class ReplayBase : public NoCopy
|
||||
{
|
||||
// Needs access to KartReplayEvent
|
||||
friend class GhostKart;
|
||||
private:
|
||||
/** The filename of the replay file. Only defined after calling
|
||||
* openReplayFile. */
|
||||
std::string m_filename;
|
||||
|
||||
public:
|
||||
class ReplayData
|
||||
{
|
||||
public:
|
||||
std::string m_filename;
|
||||
bool m_reverse;
|
||||
std::vector<std::string> m_kart_list;
|
||||
unsigned int m_difficulty;
|
||||
std::string m_track_name;
|
||||
unsigned int m_laps;
|
||||
float m_min_time;
|
||||
}; // ReplayData
|
||||
|
||||
protected:
|
||||
/** Stores a transform event, i.e. a position and rotation of a kart
|
||||
* at a certain time. */
|
||||
@ -69,16 +80,19 @@ protected:
|
||||
}; // KartReplayEvent
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
ReplayBase();
|
||||
FILE *openReplayFile(bool writeable);
|
||||
// ----------------------------------------------------------------------
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the filename that was opened. */
|
||||
const std::string &getReplayFilename() const { return m_filename;}
|
||||
// ----------------------------------------------------------------------
|
||||
virtual const std::string& getReplayFilename() const = 0;
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the version number of the replay file. This is used to check
|
||||
* that a loaded replay file can still be understood by this
|
||||
* executable. */
|
||||
unsigned int getReplayVersion() const { return 1; }
|
||||
|
||||
public:
|
||||
ReplayBase();
|
||||
virtual ~ReplayBase() {};
|
||||
}; // ReplayBase
|
||||
|
||||
#endif
|
||||
|
@ -37,8 +37,7 @@ ReplayPlay *ReplayPlay::m_replay_play = NULL;
|
||||
*/
|
||||
ReplayPlay::ReplayPlay()
|
||||
{
|
||||
m_next = 0;
|
||||
m_ghost_karts_list.clear();
|
||||
m_current_replay_file = 0;
|
||||
} // ReplayPlay
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -52,8 +51,6 @@ ReplayPlay::~ReplayPlay()
|
||||
*/
|
||||
void ReplayPlay::reset()
|
||||
{
|
||||
m_next = 0;
|
||||
m_ghost_karts_list.clear();
|
||||
for(unsigned int i=0; i<(unsigned int)m_ghost_karts.size(); i++)
|
||||
{
|
||||
m_ghost_karts[i].reset();
|
||||
@ -61,11 +58,78 @@ void ReplayPlay::reset()
|
||||
} // reset
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads the basic (ghost karts, reverse track) info in the replay file,
|
||||
* required by race manager.
|
||||
*/
|
||||
void ReplayPlay::loadBasicInfo()
|
||||
void ReplayPlay::loadAllReplayFile()
|
||||
{
|
||||
m_replay_file_list.clear();
|
||||
std::set<std::string> files;
|
||||
file_manager->listFiles(files, file_manager->getReplayDir(),
|
||||
/*is_full_path*/ false);
|
||||
|
||||
char s[1024], s1[1024];
|
||||
for (std::set<std::string>::iterator i = files.begin();
|
||||
i != files.end(); ++i)
|
||||
{
|
||||
if (StringUtils::getExtension(*i) != "replay") continue;
|
||||
FILE *fd = fopen((file_manager->getReplayDir() + (*i)).c_str(), "r");
|
||||
if (fd == NULL) continue;
|
||||
ReplayData rd;
|
||||
|
||||
rd.m_filename = *i;
|
||||
|
||||
int reverse = 0;
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "reverse: %d", &reverse) != 1)
|
||||
Log::fatal("Replay", "Reverse info found in replay file.");
|
||||
rd.m_reverse = (bool)reverse;
|
||||
|
||||
while(true)
|
||||
{
|
||||
fgets(s, 1023, fd);
|
||||
core::stringc is_end(s);
|
||||
is_end.trim();
|
||||
if (is_end == "kart_list_end") break;
|
||||
char s1[1024];
|
||||
|
||||
if (sscanf(s,"kart: %s", s1) != 1)
|
||||
Log::fatal("Replay", "Could not read ghost karts info!");
|
||||
|
||||
rd.m_kart_list.push_back(std::string(s1));
|
||||
}
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
unsigned int version;
|
||||
if (sscanf(s,"version: %u", &version) != 1)
|
||||
Log::fatal("Replay", "No Version information found in replay file (bogus replay file).");
|
||||
|
||||
if (version != getReplayVersion())
|
||||
{
|
||||
Log::warn("Replay", "Replay is version '%d'",version);
|
||||
Log::warn("Replay", "STK version is '%d'",getReplayVersion());
|
||||
Log::warn("Replay", "We try to proceed, but it may fail.");
|
||||
}
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
if (sscanf(s, "difficulty: %u", &rd.m_difficulty) != 1)
|
||||
Log::fatal("Replay", " No difficulty found in replay file.");
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
if (sscanf(s, "track: %s", s1) != 1)
|
||||
Log::fatal("Replay", "Track not found in replay file.");
|
||||
rd.m_track_name = std::string(s1);
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "laps: %u", &rd.m_laps) != 1)
|
||||
Log::fatal("Replay", "No number of laps found in replay file.");
|
||||
|
||||
rd.m_min_time = 0.0f;
|
||||
fclose(fd);
|
||||
m_replay_file_list.push_back(rd);
|
||||
}
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
void ReplayPlay::load()
|
||||
{
|
||||
m_ghost_karts.clearAndDeleteAll();
|
||||
char s[1024];
|
||||
|
||||
FILE *fd = openReplayFile(/*writeable*/false);
|
||||
@ -77,100 +141,11 @@ void ReplayPlay::loadBasicInfo()
|
||||
return;
|
||||
}
|
||||
|
||||
int reverse;
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "reverse: %d", &reverse) != 1)
|
||||
Log::fatal("Replay", "Reverse info found in replay file.");
|
||||
race_manager->setReverseTrack((bool)reverse);
|
||||
|
||||
Log::info("Replay", "Reading ghost karts info");
|
||||
while(true)
|
||||
{
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
core::stringc is_end(s);
|
||||
is_end.trim();
|
||||
if (is_end == "kart_list_end") break;
|
||||
char s1[1024];
|
||||
|
||||
if (sscanf(s,"kart: %s", s1) != 1)
|
||||
Log::fatal("Replay", "Could not read ghost karts info!");
|
||||
|
||||
m_ghost_karts_list.push_back(std::string(s1));
|
||||
}
|
||||
fclose(fd);
|
||||
} // loadBasicInfo
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
/** Loads a replay data from file called 'trackname'.replay.
|
||||
*/
|
||||
void ReplayPlay::load()
|
||||
{
|
||||
m_ghost_karts.clearAndDeleteAll();
|
||||
char s[1024], s1[1024];
|
||||
|
||||
FILE *fd = openReplayFile(/*writeable*/false);
|
||||
if(!fd)
|
||||
{
|
||||
Log::error("Replay", "Can't read '%s', ghost replay disabled.",
|
||||
getReplayFilename().c_str());
|
||||
destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
Log::info("Replay", "Reading replay file '%s'.", getReplayFilename().c_str());
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
// Skip reverse info which is already read.
|
||||
|
||||
for (unsigned int i = 0; i < m_ghost_karts_list.size(); i++)
|
||||
{
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
// Skip kart info which is already read.
|
||||
}
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
// Skip kart_list_end
|
||||
|
||||
unsigned int version;
|
||||
if (sscanf(s,"version: %u", &version) != 1)
|
||||
Log::fatal("Replay", "No Version information found in replay file (bogus replay file).");
|
||||
|
||||
if (version != getReplayVersion())
|
||||
{
|
||||
Log::warn("Replay", "Replay is version '%d'",version);
|
||||
Log::warn("Replay", "STK version is '%d'",getReplayVersion());
|
||||
Log::warn("Replay", "We try to proceed, but it may fail.");
|
||||
}
|
||||
|
||||
if (fgets(s, 1023, fd) == NULL)
|
||||
Log::fatal("Replay", "Could not read '%s'.", getReplayFilename().c_str());
|
||||
|
||||
int n;
|
||||
if(sscanf(s, "difficulty: %d", &n) != 1)
|
||||
Log::fatal("Replay", " No difficulty found in replay file.");
|
||||
|
||||
if(race_manager->getDifficulty()!=(RaceManager::Difficulty)n)
|
||||
Log::warn("Replay", "Difficulty of replay is '%d', "
|
||||
"while '%d' is selected.",
|
||||
race_manager->getDifficulty(), n);
|
||||
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "track: %s", s1) != 1)
|
||||
Log::warn("Replay", "Track not found in replay file.");
|
||||
assert(std::string(s1)==race_manager->getTrackName());
|
||||
race_manager->setTrack(s1);
|
||||
|
||||
unsigned int num_laps;
|
||||
fgets(s, 1023, fd);
|
||||
if(sscanf(s, "laps: %u", &num_laps) != 1)
|
||||
Log::fatal("Replay", "No number of laps found in replay file.");
|
||||
|
||||
race_manager->setNumLaps(num_laps);
|
||||
const unsigned int line_skipped = getNumGhostKart() + 6;
|
||||
for (unsigned int i = 0; i < line_skipped; i++)
|
||||
fgets(s, 1023, fd);
|
||||
|
||||
// eof actually doesn't trigger here, since it requires first to try
|
||||
// reading behind eof, but still it's clearer this way.
|
||||
@ -193,7 +168,8 @@ void ReplayPlay::readKartData(FILE *fd, char *next_line)
|
||||
{
|
||||
char s[1024];
|
||||
const unsigned int kart_num = m_ghost_karts.size();
|
||||
m_ghost_karts.push_back(new GhostKart(m_ghost_karts_list.at(kart_num),
|
||||
m_ghost_karts.push_back(new GhostKart(m_replay_file_list
|
||||
[m_current_replay_file].m_kart_list.at(kart_num),
|
||||
kart_num, kart_num + 1));
|
||||
m_ghost_karts[kart_num].init(RaceManager::KT_GHOST);
|
||||
Controller* controller = new GhostController(getGhostKart(kart_num));
|
||||
|
@ -34,15 +34,14 @@ class GhostKart;
|
||||
class ReplayPlay : public ReplayBase
|
||||
{
|
||||
private:
|
||||
static ReplayPlay *m_replay_play;
|
||||
static ReplayPlay *m_replay_play;
|
||||
|
||||
/** Points to the next free entry. */
|
||||
unsigned int m_next;
|
||||
unsigned int m_current_replay_file;
|
||||
|
||||
std::vector<std::string> m_ghost_karts_list;
|
||||
std::vector<ReplayData> m_replay_file_list;
|
||||
|
||||
/** All ghost karts. */
|
||||
PtrVector<GhostKart> m_ghost_karts;
|
||||
PtrVector<GhostKart> m_ghost_karts;
|
||||
|
||||
ReplayPlay();
|
||||
~ReplayPlay();
|
||||
@ -50,16 +49,30 @@ private:
|
||||
public:
|
||||
void reset();
|
||||
void load();
|
||||
void loadBasicInfo();
|
||||
|
||||
void loadAllReplayFile();
|
||||
// ------------------------------------------------------------------------
|
||||
void setReplayFile(unsigned int n)
|
||||
{ m_current_replay_file = n; }
|
||||
// ------------------------------------------------------------------------
|
||||
const ReplayData& getReplayData(unsigned int n) const
|
||||
{ return m_replay_file_list.at(n); }
|
||||
// ------------------------------------------------------------------------
|
||||
const unsigned int getNumReplayFile() const
|
||||
{ return m_replay_file_list.size(); }
|
||||
// ------------------------------------------------------------------------
|
||||
GhostKart* getGhostKart(int n) { return m_ghost_karts.get(n); }
|
||||
// ------------------------------------------------------------------------
|
||||
const unsigned int getNumGhostKart() const
|
||||
{ return m_ghost_karts_list.size(); }
|
||||
{
|
||||
assert(m_replay_file_list.size() > 0);
|
||||
return m_replay_file_list.at(m_current_replay_file).m_kart_list.size();
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
const std::string& getGhostKartName(int n) const
|
||||
{ return m_ghost_karts_list.at(n); }
|
||||
{
|
||||
assert(m_replay_file_list.size() > 0);
|
||||
return m_replay_file_list.at(m_current_replay_file).m_kart_list.at(n);
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
/** Creates a new instance of the replay object. */
|
||||
static void create() { m_replay_play = new ReplayPlay(); }
|
||||
@ -71,6 +84,13 @@ public:
|
||||
static void destroy()
|
||||
{ delete m_replay_play; m_replay_play = NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the filename that was opened. */
|
||||
virtual const std::string& getReplayFilename() const
|
||||
{
|
||||
assert(m_replay_file_list.size() > 0);
|
||||
return m_replay_file_list.at(m_current_replay_file).m_filename;
|
||||
}
|
||||
// ------------------------------------------------------------------------
|
||||
}; // Replay
|
||||
|
||||
#endif
|
||||
|
@ -39,6 +39,7 @@ ReplayRecorder *ReplayRecorder::m_replay_recorder = NULL;
|
||||
*/
|
||||
ReplayRecorder::ReplayRecorder()
|
||||
{
|
||||
m_filename = "TODO.replay";
|
||||
} // ReplayRecorder
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -97,9 +98,6 @@ void ReplayRecorder::update(float dt)
|
||||
unsigned int num_karts = world->getNumKarts();
|
||||
|
||||
float time = world->getTime();
|
||||
// Once we use interpolate results, we don't have to increase
|
||||
// m_next by num_karts, so count how often to increase
|
||||
|
||||
for(unsigned int i=0; i<num_karts; i++)
|
||||
{
|
||||
const AbstractKart *kart = world->getKart(i);
|
||||
|
@ -30,6 +30,7 @@
|
||||
class ReplayRecorder : public ReplayBase
|
||||
{
|
||||
private:
|
||||
std::string m_filename;
|
||||
|
||||
/** A separate vector of Replay Events for all transforms. */
|
||||
std::vector< std::vector<TransformEvent> > m_transform_events;
|
||||
@ -85,6 +86,10 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
/** Delete the instance of the replay object. */
|
||||
static void destroy() { delete m_replay_recorder; m_replay_recorder=NULL; }
|
||||
// ------------------------------------------------------------------------
|
||||
/** Returns the filename that was opened. */
|
||||
virtual const std::string& getReplayFilename() const { return m_filename; }
|
||||
// ------------------------------------------------------------------------
|
||||
}; // ReplayRecorder
|
||||
|
||||
#endif
|
||||
|
109
src/states_screens/dialogs/ghost_replay_info_dialog.cpp
Normal file
109
src/states_screens/dialogs/ghost_replay_info_dialog.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/dialogs/ghost_replay_info_dialog.hpp"
|
||||
|
||||
#include "config/player_manager.hpp"
|
||||
#include "replay/replay_play.hpp"
|
||||
#include "states_screens/ghost_replay_selection.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
|
||||
using namespace GUIEngine;
|
||||
using namespace irr::core;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GhostReplayInfoDialog::GhostReplayInfoDialog(unsigned int replay_id)
|
||||
: ModalDialog(0.5f,0.5f), m_replay_id(replay_id)
|
||||
{
|
||||
m_self_destroy = false;
|
||||
m_rd = ReplayPlay::get()->getReplayData(m_replay_id);
|
||||
loadFromFile("ghost_replay_info_dialog.stkgui");
|
||||
|
||||
LabelWidget *name = getWidget<LabelWidget>("name");
|
||||
assert(name);
|
||||
name->setText(stringw((m_rd.m_filename).c_str()), false);
|
||||
|
||||
m_back_widget = getWidget<IconButtonWidget>("back");
|
||||
m_back_widget->setFocusForPlayer(PLAYER_ID_GAME_MASTER);
|
||||
m_action_widget = getWidget<RibbonWidget>("actions");
|
||||
} // GhostReplayInfoDialog
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GhostReplayInfoDialog::~GhostReplayInfoDialog()
|
||||
{
|
||||
} // ~GhostReplayInfoDialog
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
GUIEngine::EventPropagation
|
||||
GhostReplayInfoDialog::processEvent(const std::string& event_source)
|
||||
{
|
||||
|
||||
if (event_source == "actions")
|
||||
{
|
||||
const std::string& selection =
|
||||
m_action_widget->getSelectionIDString(PLAYER_ID_GAME_MASTER);
|
||||
|
||||
if(selection == "start")
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
ReplayPlay::get()->setReplayFile(m_replay_id);
|
||||
race_manager->setRaceGhostKarts(true);
|
||||
race_manager->setNumKarts(race_manager->getNumLocalPlayers());
|
||||
|
||||
// Disable accidentally unlocking of a challenge
|
||||
PlayerManager::getCurrentPlayer()->setCurrentChallenge("");
|
||||
|
||||
race_manager->setReverseTrack(m_rd.m_reverse);
|
||||
race_manager->startSingleRace(m_rd.m_track_name, m_rd.m_laps, false);
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if(selection == "remove")
|
||||
{
|
||||
m_self_destroy = true;
|
||||
if (!file_manager
|
||||
->removeFile(file_manager->getReplayDir() + m_rd.m_filename))
|
||||
Log::warn("GhostReplayInfoDialog", "Failed to delete file.");
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
else if (selection == "back")
|
||||
{
|
||||
m_self_destroy = true;
|
||||
return GUIEngine::EVENT_BLOCK;
|
||||
}
|
||||
}
|
||||
return GUIEngine::EVENT_LET;
|
||||
} // processEvent
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
bool GhostReplayInfoDialog::onEscapePressed()
|
||||
{
|
||||
if (m_back_widget->isActivated())
|
||||
m_self_destroy = true;
|
||||
return false;
|
||||
} // onEscapePressed
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void GhostReplayInfoDialog::onUpdate(float dt)
|
||||
{
|
||||
if (m_self_destroy)
|
||||
{
|
||||
ModalDialog::dismiss();
|
||||
GhostReplaySelection::getInstance()->refresh();
|
||||
return;
|
||||
}
|
||||
} // onUpdate
|
55
src/states_screens/dialogs/ghost_replay_info_dialog.hpp
Normal file
55
src/states_screens/dialogs/ghost_replay_info_dialog.hpp
Normal file
@ -0,0 +1,55 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_GHOST_REPLAY_INFO_DIALOG_HPP
|
||||
#define HEADER_GHOST_REPLAY_INFO_DIALOG_HPP
|
||||
|
||||
#include "guiengine/modaldialog.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "guiengine/widgets/ribbon_widget.hpp"
|
||||
#include "replay/replay_base.hpp"
|
||||
|
||||
#include <irrString.h>
|
||||
|
||||
/** \brief Dialog that allows a user to do action with ghost replay file
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class GhostReplayInfoDialog : public GUIEngine::ModalDialog
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
bool m_self_destroy;
|
||||
|
||||
const unsigned int m_replay_id;
|
||||
ReplayBase::ReplayData m_rd;
|
||||
|
||||
GUIEngine::RibbonWidget* m_action_widget;
|
||||
GUIEngine::IconButtonWidget* m_back_widget;
|
||||
|
||||
public:
|
||||
GhostReplayInfoDialog(unsigned int replay_id);
|
||||
~GhostReplayInfoDialog();
|
||||
|
||||
GUIEngine::EventPropagation processEvent(const std::string& eventSource);
|
||||
|
||||
virtual bool onEscapePressed();
|
||||
virtual void onUpdate(float dt);
|
||||
}; // class ServerInfoDialog
|
||||
|
||||
#endif
|
130
src/states_screens/ghost_replay_selection.cpp
Normal file
130
src/states_screens/ghost_replay_selection.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "states_screens/ghost_replay_selection.hpp"
|
||||
|
||||
#include "replay/replay_play.hpp"
|
||||
#include "states_screens/dialogs/ghost_replay_info_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
DEFINE_SCREEN_SINGLETON( GhostReplaySelection );
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Constructor, which loads the stkgui file.
|
||||
*/
|
||||
GhostReplaySelection::GhostReplaySelection() : Screen("ghost_replay_selection.stkgui")
|
||||
{
|
||||
} // GhostReplaySelection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Destructor.
|
||||
*/
|
||||
GhostReplaySelection::~GhostReplaySelection()
|
||||
{
|
||||
} // GhostReplaySelection
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Triggers a refresh of the replay file list.
|
||||
*/
|
||||
void GhostReplaySelection::refresh()
|
||||
{
|
||||
ReplayPlay::get()->loadAllReplayFile();
|
||||
loadList();
|
||||
} // refresh
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Set pointers to the various widgets.
|
||||
*/
|
||||
void GhostReplaySelection::loadedFromFile()
|
||||
{
|
||||
m_replay_list_widget = getWidget<GUIEngine::ListWidget>("replay_list");
|
||||
assert(m_replay_list_widget != NULL);
|
||||
m_replay_list_widget->setColumnListener(this);
|
||||
} // loadedFromFile
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Clear the replay file list, which will be reloaded.
|
||||
*/
|
||||
void GhostReplaySelection::beforeAddingWidget()
|
||||
{
|
||||
m_replay_list_widget->clearColumns();
|
||||
m_replay_list_widget->addColumn( _("Track"), 3 );
|
||||
m_replay_list_widget->addColumn( _("Laps"), 1);
|
||||
} // beforeAddingWidget
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GhostReplaySelection::init()
|
||||
{
|
||||
Screen::init();
|
||||
refresh();
|
||||
} // init
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
/** Loads the list of all replay files. The gui element will be
|
||||
* updated.
|
||||
*/
|
||||
void GhostReplaySelection::loadList()
|
||||
{
|
||||
m_replay_list_widget->clear();
|
||||
for (unsigned int i = 0; i < ReplayPlay::get()->getNumReplayFile() ; i++)
|
||||
{
|
||||
const ReplayBase::ReplayData rd = ReplayPlay::get()->getReplayData(i);
|
||||
|
||||
std::vector<GUIEngine::ListWidget::ListCell> row;
|
||||
Track* t = track_manager->getTrack(rd.m_track_name);
|
||||
row.push_back(GUIEngine::ListWidget::ListCell
|
||||
(translations->fribidize(t->getName()) , -1, 3));
|
||||
row.push_back(GUIEngine::ListWidget::ListCell
|
||||
(StringUtils::toWString(rd.m_laps), -1, 1, true));
|
||||
m_replay_list_widget->addItem("replay", row);
|
||||
}
|
||||
} // loadList
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void GhostReplaySelection::eventCallback( GUIEngine::Widget* widget,
|
||||
const std::string& name,
|
||||
const int playerID)
|
||||
{
|
||||
if (name == "back")
|
||||
{
|
||||
race_manager->setRaceGhostKarts(false);
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
|
||||
else if (name == "reload")
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
else if (name == m_replay_list_widget->m_properties[GUIEngine::PROP_ID])
|
||||
{
|
||||
unsigned int selected_index = m_replay_list_widget->getSelectionID();
|
||||
// This can happen e.g. when the list is empty and the user
|
||||
// clicks somewhere.
|
||||
if(selected_index >= ReplayPlay::get()->getNumReplayFile() ||
|
||||
selected_index < 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
new GhostReplayInfoDialog(selected_index);
|
||||
} // click on replay file
|
||||
|
||||
} // eventCallback
|
72
src/states_screens/ghost_replay_selection.hpp
Normal file
72
src/states_screens/ghost_replay_selection.hpp
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2016 SuperTuxKart-Team
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef HEADER_GHOST_REPLAY_SELECTION_HPP
|
||||
#define HEADER_GHOST_REPLAY_SELECTION_HPP
|
||||
|
||||
#include "guiengine/screen.hpp"
|
||||
#include "guiengine/widgets.hpp"
|
||||
|
||||
namespace GUIEngine { class Widget; }
|
||||
|
||||
/**
|
||||
* \brief GhostReplaySelection
|
||||
* \ingroup states_screens
|
||||
*/
|
||||
class GhostReplaySelection : public GUIEngine::Screen,
|
||||
public GUIEngine::ScreenSingleton<GhostReplaySelection>,
|
||||
public GUIEngine::IListWidgetHeaderListener
|
||||
|
||||
{
|
||||
friend class GUIEngine::ScreenSingleton<GhostReplaySelection>;
|
||||
|
||||
private:
|
||||
GhostReplaySelection();
|
||||
~GhostReplaySelection();
|
||||
|
||||
GUIEngine::ListWidget * m_replay_list_widget;
|
||||
|
||||
public:
|
||||
|
||||
void refresh();
|
||||
|
||||
/** Load the addons into the main list.*/
|
||||
void loadList();
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void loadedFromFile() OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void eventCallback(GUIEngine::Widget* widget, const std::string& name,
|
||||
const int playerID) OVERRIDE;
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void beforeAddingWidget() OVERRIDE;
|
||||
|
||||
virtual void onColumnClicked(int columnId) {};
|
||||
|
||||
virtual void init() OVERRIDE;
|
||||
|
||||
virtual void tearDown() OVERRIDE {};
|
||||
|
||||
/** \brief implement callback from parent class GUIEngine::Screen */
|
||||
virtual void onUpdate(float dt) OVERRIDE {};
|
||||
|
||||
}; // ServerSelection
|
||||
|
||||
#endif
|
@ -22,6 +22,7 @@
|
||||
#include "config/user_config.hpp"
|
||||
#include "graphics/irr_driver.hpp"
|
||||
#include "guiengine/widget.hpp"
|
||||
#include "guiengine/widgets/button_widget.hpp"
|
||||
#include "guiengine/widgets/dynamic_ribbon_widget.hpp"
|
||||
#include "guiengine/widgets/icon_button_widget.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
@ -30,9 +31,10 @@
|
||||
#include "network/stk_host.hpp"
|
||||
#include "race/grand_prix_data.hpp"
|
||||
#include "race/grand_prix_manager.hpp"
|
||||
#include "states_screens/ghost_replay_selection.hpp"
|
||||
#include "states_screens/gp_info_screen.hpp"
|
||||
#include "states_screens/state_manager.hpp"
|
||||
#include "states_screens/track_info_screen.hpp"
|
||||
#include "states_screens/gp_info_screen.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
#include "tracks/track_manager.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
@ -137,10 +139,15 @@ void TracksScreen::eventCallback(Widget* widget, const std::string& name,
|
||||
UserConfigParams::m_last_used_track_group = tabs->getSelectionIDString(0);
|
||||
buildTrackList();
|
||||
}
|
||||
else if (name == "ghost")
|
||||
{
|
||||
GhostReplaySelection::getInstance()->push();
|
||||
}
|
||||
else if (name == "back")
|
||||
{
|
||||
StateManager::get()->escapePressed();
|
||||
}
|
||||
|
||||
} // eventCallback
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@ -254,6 +261,9 @@ void TracksScreen::init()
|
||||
tracks_widget->setSelection(0, PLAYER_ID_GAME_MASTER, true);
|
||||
}
|
||||
irr_driver->unsetTextureErrorMessage();
|
||||
|
||||
const bool ghost_available = race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL;
|
||||
getWidget<ButtonWidget>("ghost")->setVisible(ghost_available);
|
||||
} // init
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user