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:
auria
2008-09-23 01:16:50 +00:00
parent 497454b2e0
commit 0e5106bfb9
12 changed files with 173 additions and 103 deletions

View File

@@ -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];

View File

@@ -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

View File

@@ -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;

View File

@@ -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())

View File

@@ -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

View File

@@ -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";
}

View File

@@ -35,6 +35,7 @@ public:
// overriding World methods
virtual void update(float delta);
virtual void restartRace();
virtual std::string getInternalCode() const;
};

View File

@@ -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";
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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();