started highscores refactor, also fixing them (they had been broken during the world refactor)
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/trunk/supertuxkart@2296 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -168,7 +168,7 @@ Widget *RaceResultsGUI::displayRaceResults()
|
||||
widget_manager->hideWgtRect(WTOK_HIGHSCORES);
|
||||
w_prev->setPosition(WGT_DIR_FROM_RIGHT, 0.1f, NULL, WGT_DIR_FROM_TOP, 0.1f, NULL);
|
||||
|
||||
const Highscores *hs = RaceManager::getWorld()->getHighscores();
|
||||
const HighscoreEntry *hs = RaceManager::getWorld()->getHighscores();
|
||||
unsigned int num_scores = hs->getNumberEntries();
|
||||
char *highscores = new char[num_scores * MAX_STR_LEN];
|
||||
|
||||
|
||||
@@ -91,6 +91,7 @@ void HighscoreManager::Load()
|
||||
}
|
||||
try
|
||||
{
|
||||
// check for opening 'highscores' nodes
|
||||
const lisp::Lisp* const node = root->getLisp("highscores");
|
||||
if(!node)
|
||||
{
|
||||
@@ -98,6 +99,22 @@ void HighscoreManager::Load()
|
||||
snprintf(msg, sizeof(msg), "No 'highscore' node found.");
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// check file version
|
||||
int v;
|
||||
if (!node->get("file-version",v) || v<CURRENT_HSCORE_FILE_VERSION)
|
||||
{
|
||||
fprintf(stderr, "Highscore file format too old, a new one will be created.\n");
|
||||
std::string warning = _("The highscore file was too old,\nall highscores have been erased.");
|
||||
user_config->setWarning( warning );
|
||||
|
||||
// since we haven't had the chance to load the current scores yet,
|
||||
// calling Save() now will generate an empty file.
|
||||
Save();
|
||||
return;
|
||||
}
|
||||
|
||||
// get number of entries
|
||||
int n;
|
||||
if (!node->get("number-entries",n))
|
||||
{
|
||||
@@ -106,6 +123,7 @@ void HighscoreManager::Load()
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
|
||||
// read all entries one by one and store them in 'm_allScores'
|
||||
for(int i=0; i<n; i++)
|
||||
{
|
||||
char record_name[255];
|
||||
@@ -118,11 +136,12 @@ void HighscoreManager::Load()
|
||||
i,m_filename.c_str());
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
Highscores *highscores = new Highscores();
|
||||
HighscoreEntry *highscores = new HighscoreEntry(node_record);
|
||||
m_allScores.push_back(highscores);
|
||||
highscores->Read(node_record);
|
||||
}
|
||||
fprintf(stderr, "Highscores will be saved in '%s'.\n",m_filename.c_str());
|
||||
//highscores->Read(node_record);
|
||||
}// next entry
|
||||
|
||||
fprintf(stderr, "Highscores will be saved in '%s'.\n",m_filename.c_str());
|
||||
}
|
||||
catch(std::exception& err)
|
||||
{
|
||||
@@ -144,19 +163,21 @@ void HighscoreManager::Save()
|
||||
{
|
||||
lisp::Writer writer(m_filename);
|
||||
writer.beginList("highscores");
|
||||
writer.writeComment("Number of highscores in this file");
|
||||
writer.write("number-entries\t",(unsigned int)m_allScores.size());
|
||||
int record_number=0;
|
||||
for(type_all_scores::iterator i = m_allScores.begin();
|
||||
i != m_allScores.end(); i++)
|
||||
{
|
||||
char record_name[255];
|
||||
snprintf(record_name, sizeof(record_name),"record-%d\t",record_number);
|
||||
record_number++;
|
||||
writer.beginList(record_name);
|
||||
(*i)->Write(&writer);
|
||||
writer.endList(record_name);
|
||||
} // for i
|
||||
writer.writeComment("File format version");
|
||||
writer.write("file-version\t", CURRENT_HSCORE_FILE_VERSION);
|
||||
writer.writeComment("Number of highscores in this file");
|
||||
writer.write("number-entries\t",(unsigned int)m_allScores.size());
|
||||
int record_number=0;
|
||||
for(type_all_scores::iterator i = m_allScores.begin();
|
||||
i != m_allScores.end(); i++)
|
||||
{
|
||||
char record_name[255];
|
||||
snprintf(record_name, sizeof(record_name),"record-%d\t",record_number);
|
||||
record_number++;
|
||||
writer.beginList(record_name);
|
||||
(*i)->Write(&writer);
|
||||
writer.endList(record_name);
|
||||
} // next score
|
||||
writer.endList("highscores");
|
||||
m_can_write=true;
|
||||
} // try
|
||||
@@ -171,43 +192,28 @@ void HighscoreManager::Save()
|
||||
} // Save
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
Highscores* HighscoreManager::getHighscores(const Highscores::HighscoreType highscore_type)
|
||||
/*
|
||||
* Returns the high scores entry for a specific type of race. Creates one if none exists yet.
|
||||
*/
|
||||
HighscoreEntry* HighscoreManager::getHighscoreEntry(const HighscoreEntry::HighscoreType highscore_type,
|
||||
int num_karts, const RaceManager::Difficulty difficulty,
|
||||
const std::string trackName, const int number_of_laps)
|
||||
{
|
||||
Highscores *highscores = 0;
|
||||
HighscoreEntry *highscores = 0;
|
||||
|
||||
// See if we already have a record for this type
|
||||
|
||||
for(type_all_scores::iterator i = m_allScores.begin();
|
||||
i != m_allScores.end(); i++)
|
||||
{
|
||||
if((*i)->matches(highscore_type, race_manager->getNumKarts(),
|
||||
race_manager->getDifficulty(), race_manager->getTrackName(),
|
||||
race_manager->getNumLaps()))
|
||||
if((*i)->matches(highscore_type, num_karts, difficulty, trackName, number_of_laps) )
|
||||
{
|
||||
// we found one entry for this kind of race, return it
|
||||
return (*i);
|
||||
}
|
||||
} // for i in m_allScores
|
||||
|
||||
highscores = new Highscores();
|
||||
// we don't have an entry for such a race currently. Create one.
|
||||
highscores = new HighscoreEntry(highscore_type, num_karts, difficulty, trackName, number_of_laps);
|
||||
m_allScores.push_back(highscores);
|
||||
return highscores;
|
||||
} // getHighscores
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Checks if the specified times needs to be put into the highscore list.
|
||||
// If it's one of the fastest HIGHSCORE_LEN results, it is put into the
|
||||
// list and the new position (1 ... HIGHSCORE_LEN) is returned, otherwise 0.
|
||||
Highscores * HighscoreManager::addResult(const Highscores::HighscoreType highscore_type,
|
||||
const std::string kart_name,
|
||||
const std::string name,
|
||||
const float time)
|
||||
{
|
||||
Highscores *highscores = getHighscores(highscore_type);
|
||||
|
||||
if(highscores->addData(highscore_type, kart_name, name, time) >0)
|
||||
{
|
||||
Save();
|
||||
}
|
||||
return highscores;
|
||||
} // addResult
|
||||
// -----------------------------------------------------------------------------
|
||||
} // getHighscoreEntry
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
|
||||
#include "highscores.hpp"
|
||||
#include "lisp/lisp.hpp"
|
||||
|
||||
const unsigned int CURRENT_HSCORE_FILE_VERSION = 1;
|
||||
|
||||
/**
|
||||
* This class reads and writes the 'highscores.data' file, and also takes
|
||||
* care of dealing with new records. One 'HighscoreEntry' object is created
|
||||
* for each highscore entry.
|
||||
*/
|
||||
class HighscoreManager
|
||||
{
|
||||
public:
|
||||
private:
|
||||
typedef std::vector<Highscores*> type_all_scores;
|
||||
typedef std::vector<HighscoreEntry*> type_all_scores;
|
||||
type_all_scores m_allScores;
|
||||
|
||||
std::string m_filename;
|
||||
@@ -43,10 +51,9 @@ public:
|
||||
HighscoreManager();
|
||||
~HighscoreManager();
|
||||
void Save();
|
||||
Highscores *getHighscores(const Highscores::HighscoreType highscore_type);
|
||||
Highscores *addResult (const Highscores::HighscoreType highscore_type,
|
||||
const std::string kart_name,
|
||||
const std::string name, const float time);
|
||||
HighscoreEntry *getHighscoreEntry(const HighscoreEntry::HighscoreType highscore_type,
|
||||
int num_karts, const RaceManager::Difficulty difficulty,
|
||||
const std::string trackName, const int number_of_laps);
|
||||
}; // HighscoreManager
|
||||
|
||||
extern HighscoreManager* highscore_manager;
|
||||
|
||||
@@ -24,28 +24,50 @@
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
# define snprintf _snprintf
|
||||
#endif
|
||||
Highscores::Highscores()
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
HighscoreEntry::HighscoreEntry(const HighscoreEntry::HighscoreType highscore_type,
|
||||
int num_karts, const RaceManager::Difficulty difficulty,
|
||||
const std::string trackName, const int number_of_laps)
|
||||
{
|
||||
m_track = "";
|
||||
m_highscore_type = HST_UNDEFINED;
|
||||
m_number_of_karts =-1;
|
||||
m_difficulty = -1;
|
||||
m_number_of_laps = -1;
|
||||
m_track = trackName;
|
||||
m_highscore_type = highscore_type;
|
||||
m_number_of_karts = num_karts;
|
||||
m_difficulty = difficulty;
|
||||
m_number_of_laps = number_of_laps;
|
||||
|
||||
for(int i=0; i<HIGHSCORE_LEN; i++)
|
||||
{
|
||||
m_name[i] = "";
|
||||
m_kart_name[i] = "";
|
||||
m_time[i] = -9.9f;
|
||||
}
|
||||
} // Highscores
|
||||
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void Highscores::Read(const lisp::Lisp* const node)
|
||||
HighscoreEntry::HighscoreEntry(const lisp::Lisp* const node)
|
||||
{
|
||||
m_track = "";
|
||||
m_highscore_type = "HST_UNDEFINED";
|
||||
m_number_of_karts = -1;
|
||||
m_difficulty = -1;
|
||||
m_number_of_laps = -1;
|
||||
|
||||
for(int i=0; i<HIGHSCORE_LEN; i++)
|
||||
{
|
||||
m_name[i] = "";
|
||||
m_kart_name[i] = "";
|
||||
m_time[i] = -9.9f;
|
||||
}
|
||||
|
||||
Read(node);
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
void HighscoreEntry::Read(const lisp::Lisp* const node)
|
||||
{
|
||||
node->get("track-name", m_track );
|
||||
node->get("number-karts", m_number_of_karts );
|
||||
int hst=0;
|
||||
node->get("race-mode", hst );
|
||||
std::string hst="HST_UNDEFINED";
|
||||
node->get("hscore-type", hst );
|
||||
m_highscore_type = (HighscoreType)hst;
|
||||
node->get("difficulty", m_difficulty );
|
||||
node->get("number-of-laps", m_number_of_laps );
|
||||
@@ -63,12 +85,12 @@ void Highscores::Read(const lisp::Lisp* const node)
|
||||
} // Read
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void Highscores::Write(lisp::Writer *writer)
|
||||
void HighscoreEntry::Write(lisp::Writer *writer)
|
||||
{
|
||||
writer->write("track-name\t", m_track );
|
||||
writer->write("number-karts\t", m_number_of_karts );
|
||||
writer->write("difficulty\t\t", m_difficulty );
|
||||
writer->write("race-mode\t\t", m_highscore_type );
|
||||
writer->write("hscore-type\t\t", m_highscore_type );
|
||||
writer->write("number-of-laps\t", m_number_of_laps );
|
||||
for(int j=0; j<HIGHSCORE_LEN; j++)
|
||||
{
|
||||
@@ -84,9 +106,9 @@ void Highscores::Write(lisp::Writer *writer)
|
||||
} // Write
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
int Highscores::matches(HighscoreType highscore_type,
|
||||
int num_karts, RaceManager::Difficulty difficulty,
|
||||
const std::string &track, const int number_of_laps)
|
||||
int HighscoreEntry::matches(HighscoreType highscore_type,
|
||||
int num_karts, RaceManager::Difficulty difficulty,
|
||||
const std::string track, const int number_of_laps)
|
||||
{
|
||||
return (m_highscore_type == highscore_type &&
|
||||
m_track == track &&
|
||||
@@ -100,8 +122,8 @@ int Highscores::matches(HighscoreType highscore_type,
|
||||
* be in the highscore list, the new position (1-HIGHSCORE_LEN) is returned,
|
||||
* otherwise a 0.
|
||||
*/
|
||||
int Highscores::addData(const HighscoreType highscore_type, const std::string kart_name,
|
||||
const std::string name, const float time)
|
||||
int HighscoreEntry::addData(const std::string& kart_name,
|
||||
const std::string& name, const float time)
|
||||
{
|
||||
int position=-1;
|
||||
for(int i=0; i<HIGHSCORE_LEN; i++)
|
||||
@@ -112,7 +134,7 @@ int Highscores::addData(const HighscoreType highscore_type, const std::string ka
|
||||
position=i;
|
||||
break;
|
||||
}
|
||||
// Check if new entry is faster than previous entry, if so
|
||||
// Check if new entry is faster than than in slot 'i', if so
|
||||
// move times etc and insert new entry
|
||||
if(time < m_time[i])
|
||||
{
|
||||
@@ -125,12 +147,11 @@ int Highscores::addData(const HighscoreType highscore_type, const std::string ka
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}//next score slot
|
||||
|
||||
if(position>=0)
|
||||
{
|
||||
m_track = race_manager->getTrackName();
|
||||
m_highscore_type = highscore_type;
|
||||
m_number_of_karts = race_manager->getNumKarts();
|
||||
m_difficulty = race_manager->getDifficulty();
|
||||
m_number_of_laps = race_manager->getNumLaps();
|
||||
@@ -143,7 +164,7 @@ int Highscores::addData(const HighscoreType highscore_type, const std::string ka
|
||||
|
||||
} // addData
|
||||
// -----------------------------------------------------------------------------
|
||||
int Highscores::getNumberEntries() const
|
||||
int HighscoreEntry::getNumberEntries() const
|
||||
{
|
||||
for(int i=HIGHSCORE_LEN-1; i>=0; i--)
|
||||
{
|
||||
@@ -153,7 +174,7 @@ int Highscores::getNumberEntries() const
|
||||
} // getNumberEntries
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
void Highscores::getEntry(int number, std::string &kart_name,
|
||||
void HighscoreEntry::getEntry(int number, std::string &kart_name,
|
||||
std::string &name, float *const time) const
|
||||
{
|
||||
if(number<0 || number>getNumberEntries())
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
#include "lisp/writer.hpp"
|
||||
#include "race_manager.hpp"
|
||||
|
||||
class Highscores
|
||||
/**
|
||||
* Represents one highscore entry.
|
||||
*/
|
||||
class HighscoreEntry
|
||||
{
|
||||
public:
|
||||
enum HighscoreType {HST_UNDEFINED,
|
||||
HST_TIMETRIAL_FASTEST_LAP,
|
||||
HST_TIMETRIAL_OVERALL_TIME,
|
||||
HST_RACE_FASTEST_LAP,
|
||||
HST_RACE_OVERALL_TIME};
|
||||
typedef std::string HighscoreType;
|
||||
|
||||
private:
|
||||
enum {HIGHSCORE_LEN = 3}; // It's a top 3 list
|
||||
std::string m_track;
|
||||
@@ -46,17 +46,25 @@ private:
|
||||
std::string m_name[HIGHSCORE_LEN];
|
||||
float m_time[HIGHSCORE_LEN];
|
||||
public:
|
||||
Highscores();
|
||||
/** Creates a new entry
|
||||
*/
|
||||
HighscoreEntry (const HighscoreEntry::HighscoreType highscore_type,
|
||||
int num_karts, const RaceManager::Difficulty difficulty,
|
||||
const std::string trackName, const int number_of_laps);
|
||||
/** Creates an entry from a file
|
||||
*/
|
||||
HighscoreEntry (const lisp::Lisp* const node);
|
||||
|
||||
void Read (const lisp::Lisp* const node);
|
||||
void Write (lisp::Writer* writer);
|
||||
int matches (HighscoreType highscore_type, int num_karts,
|
||||
const RaceManager::Difficulty difficulty,
|
||||
const std::string &track, const int number_of_laps);
|
||||
int addData (const HighscoreType highscore_type, const std::string kart_name,
|
||||
const std::string name, const float time);
|
||||
const std::string track, const int number_of_laps);
|
||||
int addData (const std::string& kart_name,
|
||||
const std::string& name, const float time);
|
||||
int getNumberEntries() const;
|
||||
void getEntry (int number, std::string &kart_name,
|
||||
std::string &name, float *const time) const;
|
||||
}; // Highscores
|
||||
}; // HighscoreEntry
|
||||
|
||||
#endif
|
||||
|
||||
@@ -119,4 +119,9 @@ void FollowTheLeaderRace::restartRace()
|
||||
{
|
||||
World::restartRace();
|
||||
m_leader_intervals = stk_config->m_leader_intervals;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string FollowTheLeaderRace::getInternalCode() const
|
||||
{
|
||||
return "FOLLOW_LEADER";
|
||||
}
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
// overriding World methods
|
||||
virtual void update(float delta);
|
||||
virtual void restartRace();
|
||||
virtual std::string getInternalCode() const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -105,3 +105,11 @@ bool StandardRace::useRedHerring()
|
||||
// in time trial mode, don't use "red herrings"
|
||||
return race_manager->getMinorMode() != RaceManager::MINOR_MODE_TIME_TRIAL;
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
std::string StandardRace::getInternalCode() const
|
||||
{
|
||||
if(race_manager->getMinorMode() == RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
return "STD_TIMETRIAL";
|
||||
else
|
||||
return "STANDARD";
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
virtual void restartRace();
|
||||
virtual void getDefaultCollectibles(int& collectible_type, int& amount);
|
||||
virtual bool useRedHerring();
|
||||
virtual std::string getInternalCode() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -159,14 +159,6 @@ World::World()
|
||||
//ssgSetBackFaceCollisions ( !not defined! race_manager->mirror ) ;
|
||||
#endif
|
||||
|
||||
// FIXME - will need better way to deal with high scores if we have lots of modes
|
||||
// and we wish to keep them modular
|
||||
Highscores::HighscoreType hst = (race_manager->getMinorMode()==RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
? Highscores::HST_TIMETRIAL_OVERALL_TIME
|
||||
: Highscores::HST_RACE_OVERALL_TIME;
|
||||
|
||||
m_highscores = highscore_manager->getHighscores(hst);
|
||||
|
||||
callback_manager->initAll();
|
||||
menu_manager->switchToRace();
|
||||
|
||||
@@ -207,6 +199,7 @@ World::~World()
|
||||
//-----------------------------------------------------------------------------
|
||||
void World::terminateRace()
|
||||
{
|
||||
updateHighscores();
|
||||
m_clock.pause();
|
||||
menu_manager->pushMenu(MENUID_RACERESULT);
|
||||
estimateFinishTimes();
|
||||
@@ -293,6 +286,24 @@ void World::update(float dt)
|
||||
callback_manager->update(dt);
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
HighscoreEntry* World::getHighscores() const
|
||||
{
|
||||
const HighscoreEntry::HighscoreType type = "HST_" + getInternalCode();
|
||||
|
||||
HighscoreEntry* highscores =
|
||||
highscore_manager->getHighscoreEntry(type,
|
||||
race_manager->getNumKarts(),
|
||||
race_manager->getDifficulty(),
|
||||
race_manager->getTrackName(),
|
||||
race_manager->getNumLaps());
|
||||
|
||||
return highscores;
|
||||
}
|
||||
// ----------------------------------------------------------------------------
|
||||
/*
|
||||
* usually called at the end of a race. Checks if the current times are worth a new
|
||||
* score, if so it notifies the HighscoreManager so the new score is added and saved.
|
||||
*/
|
||||
void World::updateHighscores()
|
||||
{
|
||||
// Add times to highscore list. First compute the order of karts,
|
||||
@@ -325,14 +336,11 @@ void World::updateHighscores()
|
||||
|
||||
PlayerKart *k = (PlayerKart*)m_kart[index[pos]];
|
||||
|
||||
Highscores::HighscoreType hst = (race_manager->getMinorMode()==
|
||||
RaceManager::MINOR_MODE_TIME_TRIAL)
|
||||
? Highscores::HST_TIMETRIAL_OVERALL_TIME
|
||||
: Highscores::HST_RACE_OVERALL_TIME;
|
||||
|
||||
if(m_highscores->addData(hst, k->getName(),
|
||||
k->getPlayer()->getName(),
|
||||
k->getFinishTime())>0 )
|
||||
HighscoreEntry* highscores = getHighscores();
|
||||
|
||||
if(highscores->addData(k->getName(),
|
||||
k->getPlayer()->getName(),
|
||||
k->getFinishTime())>0 )
|
||||
{
|
||||
highscore_manager->Save();
|
||||
}
|
||||
|
||||
@@ -92,7 +92,6 @@ protected:
|
||||
Physics* m_physics;
|
||||
float m_fastest_lap;
|
||||
Kart* m_fastest_kart;
|
||||
Highscores* m_highscores;
|
||||
Phase m_previous_phase; // used during the race popup menu
|
||||
int m_eliminated_karts; // number of eliminated karts
|
||||
int m_eliminated_players; // number of eliminated players
|
||||
@@ -146,7 +145,7 @@ public:
|
||||
Kart* getFastestKart() const { return m_fastest_kart; }
|
||||
float getFastestLapTime() const { return m_fastest_lap; }
|
||||
void setFastestLap(Kart *k, float time) {m_fastest_kart=k;m_fastest_lap=time; }
|
||||
const Highscores* getHighscores() const { return m_highscores; }
|
||||
HighscoreEntry* getHighscores() const;
|
||||
float getTime() const { return m_clock.getTime(); }
|
||||
Phase getPhase() const { return m_clock.getPhase(); }
|
||||
const Clock& getClock() const { return m_clock; }
|
||||
@@ -164,6 +163,11 @@ public:
|
||||
*/
|
||||
virtual bool useRedHerring(){ return true; }
|
||||
|
||||
/** Each game mode should have a unique internal code. Override
|
||||
* this method in child classes to provide it.
|
||||
*/
|
||||
virtual std::string getInternalCode() const = 0;
|
||||
|
||||
void pause();
|
||||
void unpause();
|
||||
|
||||
|
||||
@@ -231,7 +231,8 @@ public:
|
||||
bool isFixedInput(InputType, int, int, int);
|
||||
const std::string& getWarning() {return m_warning;}
|
||||
void resetWarning() {m_warning="";}
|
||||
|
||||
void setWarning(std::string& warning) {m_warning=warning;}
|
||||
|
||||
/** Creates ActionMap for use in menu mode. */
|
||||
ActionMap *newMenuActionMap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user