overhauling stats: move all stats from SongManager to ProfileManager
This commit is contained in:
@@ -31,8 +31,6 @@
|
|||||||
#include "ProfileManager.h"
|
#include "ProfileManager.h"
|
||||||
#include "arch/arch.h"
|
#include "arch/arch.h"
|
||||||
#include "ThemeManager.h"
|
#include "ThemeManager.h"
|
||||||
//#include "fstream"
|
|
||||||
#include "Bookkeeper.h"
|
|
||||||
#include "LightsManager.h"
|
#include "LightsManager.h"
|
||||||
#include "RageFile.h"
|
#include "RageFile.h"
|
||||||
|
|
||||||
@@ -144,10 +142,6 @@ void GameState::Reset()
|
|||||||
PROFILEMAN->UnloadProfile( (PlayerNumber)p );
|
PROFILEMAN->UnloadProfile( (PlayerNumber)p );
|
||||||
}
|
}
|
||||||
|
|
||||||
// save stats info intermitently in case of crash
|
|
||||||
BOOKKEEPER->WriteToDisk();
|
|
||||||
SONGMAN->SaveMachineScoresToDisk();
|
|
||||||
|
|
||||||
LIGHTSMAN->SetLightMode( LIGHTMODE_ATTRACT );
|
LIGHTSMAN->SetLightMode( LIGHTMODE_ATTRACT );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -959,7 +953,7 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector<RankingFeats> &asFeatsO
|
|||||||
|
|
||||||
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
|
for( i=0; i<NUM_RANKING_CATEGORIES; i++ )
|
||||||
{
|
{
|
||||||
vector<SongManager::CategoryData::HighScore> &vHighScores = SONGMAN->m_CategoryDatas[nt][i].vHighScores;
|
vector<ProfileManager::CategoryData::HighScore> &vHighScores = PROFILEMAN->m_CategoryDatas[nt][i].vHighScores;
|
||||||
for( unsigned j=0; j<vHighScores.size(); j++ )
|
for( unsigned j=0; j<vHighScores.size(); j++ )
|
||||||
{
|
{
|
||||||
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
if( vHighScores[j].sName != RANKING_TO_FILL_IN_MARKER[pn] )
|
||||||
|
|||||||
@@ -21,10 +21,11 @@
|
|||||||
#include "GameConstantsAndTypes.h"
|
#include "GameConstantsAndTypes.h"
|
||||||
#include "SongManager.h"
|
#include "SongManager.h"
|
||||||
#include "GameState.h"
|
#include "GameState.h"
|
||||||
|
#include "song.h"
|
||||||
|
#include "Course.h"
|
||||||
|
#include "GameManager.h"
|
||||||
|
#include "ProductInfo.h"
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
#include "windows.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our program
|
ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our program
|
||||||
|
|
||||||
@@ -36,6 +37,17 @@ ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our
|
|||||||
#define NEW_MEM_CARD_NAME "NewCard"
|
#define NEW_MEM_CARD_NAME "NewCard"
|
||||||
#define NEW_PROFILE_NAME "NewProfile"
|
#define NEW_PROFILE_NAME "NewProfile"
|
||||||
|
|
||||||
|
|
||||||
|
#define SM_300_STATISTICS_FILE BASE_PATH "statistics.ini"
|
||||||
|
#define STATS_PATH BASE_PATH "stats.html"
|
||||||
|
const CString CATEGORY_RANKING_FILE = BASE_PATH "Data" SLASH "CategoryRanking.dat";
|
||||||
|
const CString MACHINE_STEPS_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineStepsMemCardData.dat";
|
||||||
|
const CString MACHINE_COURSE_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineCourseMemCardData.dat";
|
||||||
|
const int CATEGORY_RANKING_VERSION = 3;
|
||||||
|
const int STEPS_MEM_CARD_DATA_VERSION = 7;
|
||||||
|
const int COURSE_MEM_CARD_DATA_VERSION = 5;
|
||||||
|
|
||||||
|
|
||||||
static const char *MemCardDirs[NUM_PLAYERS] =
|
static const char *MemCardDirs[NUM_PLAYERS] =
|
||||||
{
|
{
|
||||||
/* @ is important; see RageFileManager LoadedDriver::GetPath */
|
/* @ is important; see RageFileManager LoadedDriver::GetPath */
|
||||||
@@ -52,11 +64,15 @@ ProfileManager::ProfileManager()
|
|||||||
if( PREFSMAN->m_sMemoryCardDir[p] != "" )
|
if( PREFSMAN->m_sMemoryCardDir[p] != "" )
|
||||||
FILEMAN->Mount( "dir", PREFSMAN->m_sMemoryCardDir[p], MemCardDirs[p] );
|
FILEMAN->Mount( "dir", PREFSMAN->m_sMemoryCardDir[p], MemCardDirs[p] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitMachineScoresFromDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileManager::~ProfileManager()
|
ProfileManager::~ProfileManager()
|
||||||
{
|
{
|
||||||
|
WriteStatsWebPage();
|
||||||
|
|
||||||
|
SaveMachineScoresToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfileManager::GetMachineProfileIDs( vector<CString> &asProfileIDsOut )
|
void ProfileManager::GetMachineProfileIDs( vector<CString> &asProfileIDsOut )
|
||||||
@@ -96,8 +112,8 @@ bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIs
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load scores into SONGMAN
|
// Load scores into SONGMAN
|
||||||
SONGMAN->ReadStepsMemCardDataFromFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
PROFILEMAN->ReadStepsMemCardDataFromFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
||||||
SONGMAN->ReadCourseMemCardDataFromFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
PROFILEMAN->ReadCourseMemCardDataFromFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
||||||
|
|
||||||
// apply saved default modifiers if any
|
// apply saved default modifiers if any
|
||||||
if( m_Profile[pn].m_bUsingProfileDefaultModifiers )
|
if( m_Profile[pn].m_bUsingProfileDefaultModifiers )
|
||||||
@@ -190,8 +206,8 @@ bool ProfileManager::SaveProfile( PlayerNumber pn )
|
|||||||
// Save scores into SONGMAN
|
// Save scores into SONGMAN
|
||||||
//
|
//
|
||||||
// TODO: move record data to this class
|
// TODO: move record data to this class
|
||||||
SONGMAN->SaveStepsMemCardDataToFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
SaveStepsMemCardDataToFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
||||||
SONGMAN->SaveCourseMemCardDataToFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
SaveCourseMemCardDataToFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn );
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -320,3 +336,666 @@ bool ProfileManager::DeleteMachineProfile( CString sProfileID )
|
|||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProfileManager::SaveMachineScoresToDisk()
|
||||||
|
{
|
||||||
|
SaveCategoryRankingsToFile( CATEGORY_RANKING_FILE );
|
||||||
|
SaveStepsMemCardDataToFile( MACHINE_STEPS_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
||||||
|
SaveCourseMemCardDataToFile( MACHINE_COURSE_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::CategoryData::AddHighScore( HighScore hs, int &iIndexOut )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for( i=0; i<(int)vHighScores.size(); i++ )
|
||||||
|
{
|
||||||
|
if( hs >= vHighScores[i] )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( i < NUM_RANKING_LINES )
|
||||||
|
{
|
||||||
|
vHighScores.insert( vHighScores.begin()+i, hs );
|
||||||
|
iIndexOut = i;
|
||||||
|
if( int(vHighScores.size()) > NUM_RANKING_LINES )
|
||||||
|
vHighScores.erase( vHighScores.begin()+NUM_RANKING_LINES, vHighScores.end() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helper function for reading/writing scores
|
||||||
|
//
|
||||||
|
bool FileRead(RageFile& f, CString& sOut)
|
||||||
|
{
|
||||||
|
if (f.AtEOF())
|
||||||
|
return false;
|
||||||
|
sOut = f.GetLine();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRead(RageFile& f, int& iOut)
|
||||||
|
{
|
||||||
|
CString s;
|
||||||
|
if (!FileRead(f, s))
|
||||||
|
return false;
|
||||||
|
iOut = atoi(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRead(RageFile& f, unsigned& uOut)
|
||||||
|
{
|
||||||
|
CString s;
|
||||||
|
if (!FileRead(f, s))
|
||||||
|
return false;
|
||||||
|
uOut = atoi(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileRead(RageFile& f, float& fOut)
|
||||||
|
{
|
||||||
|
CString s;
|
||||||
|
if (!FileRead(f, s))
|
||||||
|
return false;
|
||||||
|
fOut = (float)atof(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileWrite(RageFile& f, const CString& sWrite)
|
||||||
|
{
|
||||||
|
f.PutLine( sWrite );
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileWrite(RageFile& f, int iWrite)
|
||||||
|
{
|
||||||
|
f.PutLine( ssprintf("%d", iWrite) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileWrite(RageFile& f, size_t uWrite)
|
||||||
|
{
|
||||||
|
f.PutLine( ssprintf("%lu", uWrite) );
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileWrite(RageFile& f, float fWrite)
|
||||||
|
{
|
||||||
|
f.PutLine( ssprintf("%f", fWrite) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WARN_AND_RETURN { LOG->Warn("Error parsing file '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); return; }
|
||||||
|
|
||||||
|
|
||||||
|
void ProfileManager::ReadStepsMemCardDataFromFile( CString fn, int mc )
|
||||||
|
{
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return; /* don't warn if it just doesn't exist */
|
||||||
|
|
||||||
|
int version;
|
||||||
|
if( !FileRead(f, version) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
if( version != STEPS_MEM_CARD_DATA_VERSION )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
int iNumSongs;
|
||||||
|
if( !FileRead(f, iNumSongs) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
for( int s=0; s<iNumSongs; s++ )
|
||||||
|
{
|
||||||
|
CString sSongDir;
|
||||||
|
if( !FileRead(f, sSongDir) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
Song* pSong = SONGMAN->GetSongFromDir( sSongDir );
|
||||||
|
|
||||||
|
int iNumNotes;
|
||||||
|
if( !FileRead(f, iNumNotes) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
for( int n=0; n<iNumNotes; n++ )
|
||||||
|
{
|
||||||
|
StepsType nt;
|
||||||
|
if( !FileRead(f, (int&)nt) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
Difficulty dc;
|
||||||
|
if( !FileRead(f, (int&)dc) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
CString sDescription;
|
||||||
|
if( !FileRead(f, sDescription) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
// Even if pSong or pNotes is null, we still have to skip over that data.
|
||||||
|
|
||||||
|
Steps* pNotes = NULL;
|
||||||
|
if( pSong )
|
||||||
|
{
|
||||||
|
if( dc==DIFFICULTY_INVALID )
|
||||||
|
pNotes = pSong->GetStepsByDescription( nt, sDescription );
|
||||||
|
else
|
||||||
|
pNotes = pSong->GetStepsByDifficulty( nt, dc );
|
||||||
|
}
|
||||||
|
|
||||||
|
int iNumTimesPlayed;
|
||||||
|
if( !FileRead(f, iNumTimesPlayed) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
if( pNotes )
|
||||||
|
pNotes->m_MemCardDatas[mc].iNumTimesPlayed = iNumTimesPlayed;
|
||||||
|
|
||||||
|
if( pNotes )
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
CString sName;
|
||||||
|
if( !FileRead(f, sName) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
Grade grade;
|
||||||
|
if( !FileRead(f, (int&)grade) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
CLAMP( grade, (Grade)0, (Grade)(NUM_GRADES-1) );
|
||||||
|
|
||||||
|
int iScore;
|
||||||
|
if( !FileRead(f, iScore) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
float fPercentDP;
|
||||||
|
if( !FileRead(f, fPercentDP) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
if( pNotes )
|
||||||
|
{
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores[l].sName = sName;
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores[l].grade = grade;
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores[l].iScore = iScore;
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores[l].fPercentDP = fPercentDP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProfileManager::ReadCategoryRankingsFromFile( CString fn )
|
||||||
|
{
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return; /* don't warn if it just doesn't exist */
|
||||||
|
|
||||||
|
int version;
|
||||||
|
if( !FileRead(f, version) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
if( version != CATEGORY_RANKING_VERSION )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
for( int st=0; st<NUM_STEPS_TYPES; st++ )
|
||||||
|
{
|
||||||
|
for( int rc=0; rc<NUM_RANKING_CATEGORIES; rc++ )
|
||||||
|
{
|
||||||
|
m_CategoryDatas[st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
CString sName;
|
||||||
|
if( !FileRead(f, sName) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
int iScore;
|
||||||
|
if( !FileRead(f, iScore) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
m_CategoryDatas[st][rc].vHighScores[l].sName = sName;
|
||||||
|
m_CategoryDatas[st][rc].vHighScores[l].iScore = iScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::ReadCourseMemCardDataFromFile( CString fn, int mc )
|
||||||
|
{
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return; /* don't warn if it just doesn't exist */
|
||||||
|
|
||||||
|
int version;
|
||||||
|
if( !FileRead(f, version) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
if( version != COURSE_MEM_CARD_DATA_VERSION )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
int iNumCourses;
|
||||||
|
if( !FileRead(f, iNumCourses) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
for( int c=0; c<iNumCourses; c++ )
|
||||||
|
{
|
||||||
|
CString sPath;
|
||||||
|
if( !FileRead(f, sPath) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
Course* pCourse = SONGMAN->GetCourseFromPath( sPath );
|
||||||
|
if( pCourse == NULL )
|
||||||
|
pCourse = SONGMAN->GetCourseFromName( sPath );
|
||||||
|
|
||||||
|
// even if we don't find the Course*, we still have to read past the input
|
||||||
|
|
||||||
|
int NumStepsPlayed = 0;
|
||||||
|
if( !FileRead(f, NumStepsPlayed) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
while( NumStepsPlayed-- )
|
||||||
|
{
|
||||||
|
int st;
|
||||||
|
if( !FileRead(f, st) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
int iNumTimesPlayed;
|
||||||
|
if( !FileRead(f, iNumTimesPlayed) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
if( pCourse )
|
||||||
|
pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed = iNumTimesPlayed;
|
||||||
|
if( pCourse )
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
CString sName;
|
||||||
|
if( !FileRead(f, sName) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
int iScore;
|
||||||
|
if( !FileRead(f, iScore) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
float fSurviveTime;
|
||||||
|
if( !FileRead(f, fSurviveTime) )
|
||||||
|
WARN_AND_RETURN;
|
||||||
|
|
||||||
|
if( pCourse && st < NUM_STEPS_TYPES )
|
||||||
|
{
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName = sName;
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores[l].iScore = iScore;
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores[l].fSurviveTime = fSurviveTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::InitMachineScoresFromDisk()
|
||||||
|
{
|
||||||
|
// read old style notes scores
|
||||||
|
ReadSM300NoteScores();
|
||||||
|
|
||||||
|
// category ranking
|
||||||
|
ReadCategoryRankingsFromFile( CATEGORY_RANKING_FILE );
|
||||||
|
ReadCourseMemCardDataFromFile( MACHINE_COURSE_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
||||||
|
ReadStepsMemCardDataFromFile( MACHINE_STEPS_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::ReadSM300NoteScores()
|
||||||
|
{
|
||||||
|
IniFile ini;
|
||||||
|
ini.SetPath( SM_300_STATISTICS_FILE );
|
||||||
|
if( !ini.ReadFile() ) {
|
||||||
|
LOG->Trace( "WARNING: Could not read SM 3.0 final statistics '%s'.", SM_300_STATISTICS_FILE );
|
||||||
|
return; // load nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
// load song statistics
|
||||||
|
const IniFile::key* pKey = ini.GetKey( "Statistics" );
|
||||||
|
if( pKey )
|
||||||
|
{
|
||||||
|
for( IniFile::key::const_iterator iter = pKey->begin();
|
||||||
|
iter != pKey->end();
|
||||||
|
iter++ )
|
||||||
|
{
|
||||||
|
CString name = iter->first;
|
||||||
|
CString value = iter->second;
|
||||||
|
|
||||||
|
// Each value has the format "SongName::StepsType::StepsDescription=TimesPlayed::TopGrade::TopScore::MaxCombo".
|
||||||
|
char szSongDir[256];
|
||||||
|
char szStepsType[256];
|
||||||
|
char szStepsDescription[256];
|
||||||
|
int iRetVal;
|
||||||
|
|
||||||
|
// Parse for Song name and Notes name
|
||||||
|
iRetVal = sscanf( name, "%[^:]::%[^:]::%[^:]", szSongDir, szStepsType, szStepsDescription );
|
||||||
|
if( iRetVal != 3 )
|
||||||
|
continue; // this line doesn't match what is expected
|
||||||
|
|
||||||
|
CString sSongDir = FixSlashes( szSongDir );
|
||||||
|
|
||||||
|
// Search for the corresponding Song pointer.
|
||||||
|
Song* pSong = SONGMAN->GetSongFromDir( sSongDir );
|
||||||
|
if( pSong == NULL ) // didn't find a match
|
||||||
|
continue; // skip this entry
|
||||||
|
|
||||||
|
StepsType st = GAMEMAN->StringToNotesType( szStepsType );
|
||||||
|
Difficulty dc = StringToDifficulty( szStepsDescription );
|
||||||
|
|
||||||
|
// Search for the corresponding Notes pointer.
|
||||||
|
Steps* pNotes = pSong->GetStepsByDifficulty( st, dc );
|
||||||
|
if( pNotes == NULL ) // didn't find a match
|
||||||
|
continue; // skip this entry
|
||||||
|
|
||||||
|
|
||||||
|
// Parse the Notes statistics.
|
||||||
|
char szGradeLetters[10]; // longest possible string is "AAA"
|
||||||
|
int iMaxCombo; // throw away
|
||||||
|
|
||||||
|
pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores.resize(1);
|
||||||
|
|
||||||
|
iRetVal = sscanf(
|
||||||
|
value,
|
||||||
|
"%d::%[^:]::%d::%d",
|
||||||
|
&pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].iNumTimesPlayed,
|
||||||
|
szGradeLetters,
|
||||||
|
&pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].iScore,
|
||||||
|
&iMaxCombo
|
||||||
|
);
|
||||||
|
if( iRetVal != 4 )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].grade = StringToGrade( szGradeLetters );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProfileManager::SaveCategoryRankingsToFile( CString fn )
|
||||||
|
{
|
||||||
|
LOG->Trace("SongManager::SaveCategoryRankingsToFile");
|
||||||
|
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FileWrite( f, CATEGORY_RANKING_VERSION );
|
||||||
|
|
||||||
|
for( int st=0; st<NUM_STEPS_TYPES; st++ )
|
||||||
|
{
|
||||||
|
for( int rc=0; rc<NUM_RANKING_CATEGORIES; rc++ )
|
||||||
|
{
|
||||||
|
m_CategoryDatas[st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
// tricky: wipe out "name to fill in" markers
|
||||||
|
if( IsRankingToFillIn(m_CategoryDatas[st][rc].vHighScores[l].sName) )
|
||||||
|
m_CategoryDatas[st][rc].vHighScores[l].sName = "";
|
||||||
|
|
||||||
|
FileWrite( f, m_CategoryDatas[st][rc].vHighScores[l].sName );
|
||||||
|
FileWrite( f, m_CategoryDatas[st][rc].vHighScores[l].iScore );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::SaveCourseMemCardDataToFile( CString fn, int mc )
|
||||||
|
{
|
||||||
|
LOG->Trace("SongManager::SaveCourseMemCardDataToFile");
|
||||||
|
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FileWrite( f, COURSE_MEM_CARD_DATA_VERSION );
|
||||||
|
|
||||||
|
vector<Course*> vpCourses;
|
||||||
|
SONGMAN->GetAllCourses( vpCourses, true );
|
||||||
|
|
||||||
|
FileWrite( f, vpCourses.size() );
|
||||||
|
|
||||||
|
for( unsigned c=0; c<vpCourses.size(); c++ ) // foreach course
|
||||||
|
{
|
||||||
|
Course* pCourse = vpCourses[c];
|
||||||
|
ASSERT(pCourse);
|
||||||
|
|
||||||
|
if( pCourse->m_bIsAutogen )
|
||||||
|
FileWrite( f, pCourse->m_sName );
|
||||||
|
else
|
||||||
|
FileWrite( f, pCourse->m_sPath );
|
||||||
|
|
||||||
|
int NumStepsPlayed = 0;
|
||||||
|
int st;
|
||||||
|
for( st=0; st<NUM_STEPS_TYPES; st++ )
|
||||||
|
if( pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed )
|
||||||
|
++NumStepsPlayed;
|
||||||
|
FileWrite( f, NumStepsPlayed );
|
||||||
|
|
||||||
|
for( st=0; st<NUM_STEPS_TYPES; st++ )
|
||||||
|
{
|
||||||
|
if( !pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed )
|
||||||
|
continue;
|
||||||
|
--NumStepsPlayed;
|
||||||
|
|
||||||
|
FileWrite( f, st );
|
||||||
|
FileWrite( f, pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed );
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
// tricky: wipe out "name to fill in" markers
|
||||||
|
if( IsRankingToFillIn(pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName) )
|
||||||
|
pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName = "";
|
||||||
|
|
||||||
|
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName );
|
||||||
|
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].iScore );
|
||||||
|
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].fSurviveTime );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ASSERT( !NumStepsPlayed );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::SaveStepsMemCardDataToFile( CString fn, int mc )
|
||||||
|
{
|
||||||
|
LOG->Trace("SongManager::SaveStepsMemCardDataToFile %s", fn.c_str());
|
||||||
|
|
||||||
|
RageFile f(fn);
|
||||||
|
if (!f.IsOpen() || f.GetError() != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FileWrite( f, STEPS_MEM_CARD_DATA_VERSION );
|
||||||
|
|
||||||
|
const vector<Song*> &vpSongs = SONGMAN->GetAllSongs();
|
||||||
|
|
||||||
|
FileWrite( f, vpSongs.size() );
|
||||||
|
|
||||||
|
for( unsigned s=0; s<vpSongs.size(); s++ ) // foreach song
|
||||||
|
{
|
||||||
|
Song* pSong = vpSongs[s];
|
||||||
|
ASSERT(pSong);
|
||||||
|
|
||||||
|
/* If the song has never been played, don't write anything. This keeps
|
||||||
|
* us from saving a dozen copies of each song for all autogen difficulties,
|
||||||
|
* since most people only use a couple game modes. */
|
||||||
|
vector<Steps*> vNotes;
|
||||||
|
for( unsigned i=0; i<pSong->m_apNotes.size(); ++i )
|
||||||
|
{
|
||||||
|
Steps* pNotes = pSong->m_apNotes[i];
|
||||||
|
if( !pNotes->m_MemCardDatas[mc].iNumTimesPlayed )
|
||||||
|
continue;
|
||||||
|
vNotes.push_back( pNotes );
|
||||||
|
}
|
||||||
|
|
||||||
|
FileWrite( f, pSong->GetSongDir() );
|
||||||
|
FileWrite( f, vNotes.size() );
|
||||||
|
|
||||||
|
if( vNotes.size() == 0 )
|
||||||
|
continue; // skip
|
||||||
|
|
||||||
|
for( unsigned n=0; n<vNotes.size(); n++ )
|
||||||
|
{
|
||||||
|
Steps* pNotes = vNotes[n];
|
||||||
|
ASSERT(pNotes);
|
||||||
|
|
||||||
|
FileWrite( f, pNotes->m_StepsType );
|
||||||
|
FileWrite( f, pNotes->GetDifficulty() );
|
||||||
|
FileWrite( f, pNotes->GetDescription() );
|
||||||
|
FileWrite( f, pNotes->m_MemCardDatas[mc].iNumTimesPlayed );
|
||||||
|
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores.resize(NUM_RANKING_LINES);
|
||||||
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
|
{
|
||||||
|
// tricky: wipe out "name to fill in" markers
|
||||||
|
if( IsRankingToFillIn(pNotes->m_MemCardDatas[mc].vHighScores[l].sName) )
|
||||||
|
pNotes->m_MemCardDatas[mc].vHighScores[l].sName = "";
|
||||||
|
|
||||||
|
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].sName );
|
||||||
|
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].grade );
|
||||||
|
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].iScore );
|
||||||
|
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].fPercentDP );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void HTMLWritePerGameHeader( RageFile &f, Game game )
|
||||||
|
{
|
||||||
|
const GameDef* pGameDef = GAMEMAN->GetGameDefForGame(game);
|
||||||
|
|
||||||
|
vector<StepsType> aStepsTypes;
|
||||||
|
GAMEMAN->GetNotesTypesForGame( game, aStepsTypes );
|
||||||
|
|
||||||
|
f.PutLine( ssprintf("<h1>%s</h1>", pGameDef->m_szName) );
|
||||||
|
|
||||||
|
f.PutLine( "<table border='1'>" );
|
||||||
|
f.Write( "<tr><td>title</td>" );
|
||||||
|
|
||||||
|
unsigned j;
|
||||||
|
for( j=0; j<aStepsTypes.size(); j++ )
|
||||||
|
{
|
||||||
|
StepsType st = aStepsTypes[j];
|
||||||
|
|
||||||
|
f.PutLine( ssprintf("<td colspan='%d'>%s</td>", NUM_DIFFICULTIES, GAMEMAN->NotesTypeToString(st).c_str()) );
|
||||||
|
}
|
||||||
|
f.PutLine( "</tr>" );
|
||||||
|
|
||||||
|
f.Write( "<tr><td> </td>" );
|
||||||
|
for( j=0; j<aStepsTypes.size(); j++ )
|
||||||
|
{
|
||||||
|
for( unsigned k=0; k<NUM_DIFFICULTIES; k++ )
|
||||||
|
{
|
||||||
|
Difficulty d = (Difficulty)k;
|
||||||
|
f.PutLine( ssprintf("<td>%s</td>", Capitalize(DifficultyToString(d).Left(3)).c_str()) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.PutLine( "</tr>" );
|
||||||
|
}
|
||||||
|
|
||||||
|
static CString HTMLQuoteDoubleQuotes( CString str )
|
||||||
|
{
|
||||||
|
str.Replace( "\"", """ );
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfileManager::WriteStatsWebPage()
|
||||||
|
{
|
||||||
|
RageFile f;
|
||||||
|
if( !f.Open( STATS_PATH, RageFile::WRITE ) )
|
||||||
|
return;
|
||||||
|
|
||||||
|
f.PutLine( "<html>" );
|
||||||
|
f.PutLine( "<head>" );
|
||||||
|
f.PutLine( "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">" );
|
||||||
|
f.PutLine( ssprintf("<title>%s</title>", PRODUCT_NAME_VER) );
|
||||||
|
f.PutLine( "</head>" );
|
||||||
|
f.PutLine( "<body>" );
|
||||||
|
|
||||||
|
vector<Song*> vpSongs = SONGMAN->GetAllSongs();
|
||||||
|
SortSongPointerArrayByGroupAndTitle( vpSongs );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print song list
|
||||||
|
//
|
||||||
|
f.PutLine( "<table border='1'>" );
|
||||||
|
for( unsigned i=0; i<vpSongs.size(); i++ )
|
||||||
|
{
|
||||||
|
Song* pSong = vpSongs[i];
|
||||||
|
f.Write( "<tr>" );
|
||||||
|
/* XXX: We can't call pSong->HasBanner on every song; it'll effectively re-traverse the entire
|
||||||
|
* song directory tree checking if each banner file really exists.
|
||||||
|
*
|
||||||
|
* (Note for testing this: remember that we'll cache directories for a time; this is only slow if
|
||||||
|
* the directory cache expires before we get here.) */
|
||||||
|
//CString sImagePath = pSong->HasBanner() ? pSong->GetBannerPath() : (pSong->HasBackground() ? pSong->GetBackgroundPath() : "" );
|
||||||
|
CString sImagePath = pSong->GetBannerPath();
|
||||||
|
if( sImagePath.empty() )
|
||||||
|
f.Write( "<td> </td>" );
|
||||||
|
else
|
||||||
|
f.Write( ssprintf("<td><img src=\"%s\" width='120'></td>", HTMLQuoteDoubleQuotes(sImagePath).c_str()) );
|
||||||
|
|
||||||
|
f.Write( ssprintf("<td>%s<br>", pSong->GetTranslitMainTitle().c_str()) );
|
||||||
|
f.Write( ssprintf("<font size='-1'>%s</font><br>", pSong->GetTranslitSubTitle().c_str()) );
|
||||||
|
f.Write( ssprintf("<font size='-1'><i>%s</i></font></td>", pSong->GetTranslitArtist().c_str()) );
|
||||||
|
f.PutLine( "</tr>" );
|
||||||
|
}
|
||||||
|
f.PutLine( "</table>\n<br>" );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print steps tables
|
||||||
|
//
|
||||||
|
for( int g=0; g<NUM_GAMES; g++ )
|
||||||
|
{
|
||||||
|
Game game = (Game)g;
|
||||||
|
|
||||||
|
vector<StepsType> aStepsTypes;
|
||||||
|
GAMEMAN->GetNotesTypesForGame( game, aStepsTypes );
|
||||||
|
|
||||||
|
bool WroteHeader = false;
|
||||||
|
for( unsigned i=0; i<vpSongs.size(); i++ )
|
||||||
|
{
|
||||||
|
/* Get the steps for this game type. */
|
||||||
|
Song* pSong = vpSongs[i];
|
||||||
|
vector<Steps*> Steps;
|
||||||
|
unsigned j;
|
||||||
|
for( j=0; j < aStepsTypes.size(); j++ )
|
||||||
|
pSong->GetSteps( Steps, (StepsType) aStepsTypes[j], DIFFICULTY_INVALID, -1, -1, "", false );
|
||||||
|
|
||||||
|
/* Don't write anything for songs that have no steps at all for this
|
||||||
|
* game. Otherwise, we'll write pages and pages of empty fields for
|
||||||
|
* all of the less-used game types. */
|
||||||
|
if( Steps.size() == 0 )
|
||||||
|
continue; // skip
|
||||||
|
|
||||||
|
/* We have some steps for this game. Make sure we've written the game header. */
|
||||||
|
if( !WroteHeader )
|
||||||
|
{
|
||||||
|
HTMLWritePerGameHeader( f, game );
|
||||||
|
WroteHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
f.PutLine( "<tr>" );
|
||||||
|
|
||||||
|
f.Write( ssprintf("<td>%s</td>", pSong->GetTranslitMainTitle().c_str()) );
|
||||||
|
|
||||||
|
SortStepsByTypeAndDifficulty( Steps );
|
||||||
|
|
||||||
|
unsigned CurSteps = 0;
|
||||||
|
for( j=0; j<aStepsTypes.size(); j++ )
|
||||||
|
{
|
||||||
|
for( int k=0; k<NUM_DIFFICULTIES; k++ )
|
||||||
|
{
|
||||||
|
if( CurSteps < Steps.size() &&
|
||||||
|
Steps[CurSteps]->m_StepsType == aStepsTypes[j] &&
|
||||||
|
Steps[CurSteps]->GetDifficulty() == k )
|
||||||
|
{
|
||||||
|
f.PutLine( ssprintf("<td>%d</td>", Steps[CurSteps]->GetMeter()) );
|
||||||
|
++CurSteps;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
f.PutLine( "<td> </td>" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Write( "</tr>" );
|
||||||
|
}
|
||||||
|
if( WroteHeader )
|
||||||
|
f.PutLine( "</table>\n<br>" ); // footer
|
||||||
|
}
|
||||||
|
|
||||||
|
f.PutLine( "</body>" );
|
||||||
|
f.PutLine( "</html>" );
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "PlayerNumber.h"
|
#include "PlayerNumber.h"
|
||||||
|
#include "GameConstantsAndTypes.h"
|
||||||
|
|
||||||
struct Profile
|
struct Profile
|
||||||
{
|
{
|
||||||
@@ -54,12 +55,60 @@ public:
|
|||||||
bool SaveProfile( PlayerNumber pn );
|
bool SaveProfile( PlayerNumber pn );
|
||||||
void UnloadProfile( PlayerNumber pn );
|
void UnloadProfile( PlayerNumber pn );
|
||||||
|
|
||||||
|
void SaveMachineProfile();
|
||||||
|
|
||||||
bool IsUsingProfile( PlayerNumber pn ) { return !m_sProfileDir[pn].empty(); }
|
bool IsUsingProfile( PlayerNumber pn ) { return !m_sProfileDir[pn].empty(); }
|
||||||
Profile* GetProfile( PlayerNumber pn );
|
Profile* GetProfile( PlayerNumber pn );
|
||||||
|
|
||||||
|
Profile* GetMachineProfile() { return &m_MachineProfile; }
|
||||||
|
|
||||||
bool IsUsingMemoryCard( PlayerNumber pn ) { return m_bUsingMemoryCard[pn]; }
|
bool IsUsingMemoryCard( PlayerNumber pn ) { return m_bUsingMemoryCard[pn]; }
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// High scores
|
||||||
|
//
|
||||||
|
void InitMachineScoresFromDisk();
|
||||||
|
void SaveMachineScoresToDisk();
|
||||||
|
|
||||||
|
struct CategoryData
|
||||||
|
{
|
||||||
|
struct HighScore
|
||||||
|
{
|
||||||
|
int iScore;
|
||||||
|
CString sName;
|
||||||
|
|
||||||
|
HighScore()
|
||||||
|
{
|
||||||
|
iScore = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=( const HighScore& other ) const
|
||||||
|
{
|
||||||
|
return iScore >= other.iScore;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
vector<HighScore> vHighScores;
|
||||||
|
|
||||||
|
void AddHighScore( HighScore hs, int &iIndexOut );
|
||||||
|
|
||||||
|
} m_CategoryDatas[NUM_STEPS_TYPES][NUM_RANKING_CATEGORIES];
|
||||||
|
|
||||||
|
void AddHighScore( StepsType nt, RankingCategory rc, PlayerNumber pn, CategoryData::HighScore hs, int &iMachineIndexOut )
|
||||||
|
{
|
||||||
|
hs.sName = RANKING_TO_FILL_IN_MARKER[pn];
|
||||||
|
m_CategoryDatas[nt][rc].AddHighScore( hs, iMachineIndexOut );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReadSM300NoteScores();
|
||||||
|
void ReadStepsMemCardDataFromFile( CString fn, int c );
|
||||||
|
void ReadCourseMemCardDataFromFile( CString fn, int c );
|
||||||
|
void ReadCategoryRankingsFromFile( CString fn );
|
||||||
|
|
||||||
|
void SaveStepsMemCardDataToFile( CString fn, int c );
|
||||||
|
void SaveCourseMemCardDataToFile( CString fn, int c );
|
||||||
|
void SaveCategoryRankingsToFile( CString fn );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool LoadDefaultProfileFromMachine( PlayerNumber pn );
|
bool LoadDefaultProfileFromMachine( PlayerNumber pn );
|
||||||
bool LoadProfileFromMemoryCard( PlayerNumber pn );
|
bool LoadProfileFromMemoryCard( PlayerNumber pn );
|
||||||
@@ -74,6 +123,10 @@ private:
|
|||||||
|
|
||||||
// actual loaded profile data
|
// actual loaded profile data
|
||||||
Profile m_Profile[NUM_PLAYERS];
|
Profile m_Profile[NUM_PLAYERS];
|
||||||
|
|
||||||
|
Profile m_MachineProfile;
|
||||||
|
|
||||||
|
void WriteStatsWebPage();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -258,9 +258,5 @@ ScreenCredits::~ScreenCredits()
|
|||||||
|
|
||||||
void ScreenCredits::HandleScreenMessage( const ScreenMessage SM )
|
void ScreenCredits::HandleScreenMessage( const ScreenMessage SM )
|
||||||
{
|
{
|
||||||
/* XXX: is this needed anymore? */
|
|
||||||
if( SM == SM_GoToNextScreen )
|
|
||||||
SONGMAN->SaveMachineScoresToDisk();
|
|
||||||
|
|
||||||
ScreenAttract::HandleScreenMessage( SM );
|
ScreenAttract::HandleScreenMessage( SM );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "UnlockSystem.h"
|
#include "UnlockSystem.h"
|
||||||
#include "Course.h"
|
#include "Course.h"
|
||||||
#include "LightsManager.h"
|
#include "LightsManager.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
const int NUM_SCORE_DIGITS = 9;
|
const int NUM_SCORE_DIGITS = 9;
|
||||||
|
|
||||||
@@ -250,9 +251,9 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName)
|
|||||||
float fAverageMeter = stageStats.iMeter[p] / (float)PREFSMAN->m_iNumArcadeStages;
|
float fAverageMeter = stageStats.iMeter[p] / (float)PREFSMAN->m_iNumArcadeStages;
|
||||||
rc[p] = AverageMeterToRankingCategory( fAverageMeter );
|
rc[p] = AverageMeterToRankingCategory( fAverageMeter );
|
||||||
|
|
||||||
SongManager::CategoryData::HighScore hs;
|
ProfileManager::CategoryData::HighScore hs;
|
||||||
hs.iScore = stageStats.iScore[p];
|
hs.iScore = stageStats.iScore[p];
|
||||||
SONGMAN->AddHighScore( nt, rc[p], (PlayerNumber)p, hs, iMachineHighScoreIndex[p] );
|
PROFILEMAN->AddHighScore( nt, rc[p], (PlayerNumber)p, hs, iMachineHighScoreIndex[p] );
|
||||||
|
|
||||||
// If unlocking is enabled, save the dance points
|
// If unlocking is enabled, save the dance points
|
||||||
if( PREFSMAN->m_bUseUnlockSystem )
|
if( PREFSMAN->m_bUseUnlockSystem )
|
||||||
|
|||||||
@@ -100,9 +100,5 @@ void ScreenMusicScroll::Update( float fDeltaTime )
|
|||||||
|
|
||||||
void ScreenMusicScroll::HandleScreenMessage( const ScreenMessage SM )
|
void ScreenMusicScroll::HandleScreenMessage( const ScreenMessage SM )
|
||||||
{
|
{
|
||||||
/* XXX: is this needed anymore? */
|
|
||||||
if( SM == SM_GoToNextScreen )
|
|
||||||
SONGMAN->SaveMachineScoresToDisk();
|
|
||||||
|
|
||||||
ScreenAttract::HandleScreenMessage( SM );
|
ScreenAttract::HandleScreenMessage( SM );
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,10 +89,10 @@ ScreenNameEntryTraditional::ScreenNameEntryTraditional( CString sClassName ) : S
|
|||||||
|
|
||||||
if( i == 0 )
|
if( i == 0 )
|
||||||
{
|
{
|
||||||
SongManager::CategoryData::HighScore hs;
|
ProfileManager::CategoryData::HighScore hs;
|
||||||
hs.iScore = 1234567;
|
hs.iScore = 1234567;
|
||||||
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
|
StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType;
|
||||||
SONGMAN->AddHighScore( nt, RANKING_A, (PlayerNumber)i, hs, a );
|
PROFILEMAN->AddHighScore( nt, RANKING_A, (PlayerNumber)i, hs, a );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#include "NoteData.h"
|
#include "NoteData.h"
|
||||||
#include "NoteDataUtil.h"
|
#include "NoteDataUtil.h"
|
||||||
#include "ActorUtil.h"
|
#include "ActorUtil.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
static int g_iLastSongShown = 0;
|
static int g_iLastSongShown = 0;
|
||||||
|
|
||||||
@@ -419,9 +420,9 @@ void ScreenRanking::SetPage( PageToShow pts )
|
|||||||
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
||||||
{
|
{
|
||||||
SongManager::CategoryData::HighScore hs;
|
ProfileManager::CategoryData::HighScore hs;
|
||||||
if( l < (int)SONGMAN->m_CategoryDatas[pts.nt][pts.category].vHighScores.size() )
|
if( l < (int)PROFILEMAN->m_CategoryDatas[pts.nt][pts.category].vHighScores.size() )
|
||||||
hs = SONGMAN->m_CategoryDatas[pts.nt][pts.category].vHighScores[l];
|
hs = PROFILEMAN->m_CategoryDatas[pts.nt][pts.category].vHighScores[l];
|
||||||
if( hs.sName.empty() )
|
if( hs.sName.empty() )
|
||||||
hs.sName = EMPTY_SCORE_NAME;
|
hs.sName = EMPTY_SCORE_NAME;
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
#include "UnlockSystem.h"
|
#include "UnlockSystem.h"
|
||||||
#include "ProductInfo.h"
|
#include "ProductInfo.h"
|
||||||
#include "LightsManager.h"
|
#include "LightsManager.h"
|
||||||
|
#include "Bookkeeper.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
|
|
||||||
#define LOGO_ON_COMMAND THEME->GetMetric("ScreenTitleMenu","LogoOnCommand")
|
#define LOGO_ON_COMMAND THEME->GetMetric("ScreenTitleMenu","LogoOnCommand")
|
||||||
@@ -71,6 +73,12 @@ ScreenTitleMenu::ScreenTitleMenu( CString sClassName ) : ScreenSelect( sClassNam
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// HACK: save stats intermitently in case of crash
|
||||||
|
BOOKKEEPER->WriteToDisk();
|
||||||
|
PROFILEMAN->SaveMachineScoresToDisk();
|
||||||
|
|
||||||
|
|
||||||
/* XXX We really need two common calls: 1, something run when exiting from gameplay
|
/* XXX We really need two common calls: 1, something run when exiting from gameplay
|
||||||
* (to do this reset), and 2, something run when entering gameplay, to apply default
|
* (to do this reset), and 2, something run when entering gameplay, to apply default
|
||||||
* options. Having special cases in attract screens and the title menu to reset
|
* options. Having special cases in attract screens and the title menu to reset
|
||||||
|
|||||||
@@ -28,22 +28,14 @@
|
|||||||
#include "ThemeManager.h"
|
#include "ThemeManager.h"
|
||||||
#include "GameManager.h"
|
#include "GameManager.h"
|
||||||
#include "RageFile.h"
|
#include "RageFile.h"
|
||||||
#include "ProductInfo.h"
|
|
||||||
#include "RageTextureManager.h"
|
#include "RageTextureManager.h"
|
||||||
#include "Banner.h"
|
#include "Banner.h"
|
||||||
|
#include "ProfileManager.h"
|
||||||
|
|
||||||
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
|
SongManager* SONGMAN = NULL; // global and accessable from anywhere in our program
|
||||||
|
|
||||||
#define SM_300_STATISTICS_FILE BASE_PATH "statistics.ini"
|
|
||||||
#define SONGS_DIR BASE_PATH "Songs" SLASH
|
#define SONGS_DIR BASE_PATH "Songs" SLASH
|
||||||
#define COURSES_DIR BASE_PATH "Courses" SLASH
|
#define COURSES_DIR BASE_PATH "Courses" SLASH
|
||||||
#define STATS_PATH BASE_PATH "stats.html"
|
|
||||||
const CString CATEGORY_RANKING_FILE = BASE_PATH "Data" SLASH "CategoryRanking.dat";
|
|
||||||
const CString MACHINE_STEPS_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineStepsMemCardData.dat";
|
|
||||||
const CString MACHINE_COURSE_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineCourseMemCardData.dat";
|
|
||||||
const int CATEGORY_RANKING_VERSION = 3;
|
|
||||||
const int STEPS_MEM_CARD_DATA_VERSION = 7;
|
|
||||||
const int COURSE_MEM_CARD_DATA_VERSION = 5;
|
|
||||||
|
|
||||||
|
|
||||||
#define NUM_GROUP_COLORS THEME->GetMetricI("SongManager","NumGroupColors")
|
#define NUM_GROUP_COLORS THEME->GetMetricI("SongManager","NumGroupColors")
|
||||||
@@ -79,7 +71,6 @@ SongManager::SongManager( LoadingWindow *ld )
|
|||||||
InitSongsFromDisk( ld );
|
InitSongsFromDisk( ld );
|
||||||
InitCoursesFromDisk( ld );
|
InitCoursesFromDisk( ld );
|
||||||
InitAutogenCourses();
|
InitAutogenCourses();
|
||||||
InitMachineScoresFromDisk();
|
|
||||||
|
|
||||||
} catch(...) {
|
} catch(...) {
|
||||||
SONGMAN = NULL;
|
SONGMAN = NULL;
|
||||||
@@ -92,36 +83,14 @@ SongManager::SongManager( LoadingWindow *ld )
|
|||||||
|
|
||||||
SongManager::~SongManager()
|
SongManager::~SongManager()
|
||||||
{
|
{
|
||||||
SaveMachineScoresToDisk();
|
|
||||||
|
|
||||||
WriteStatsWebPage();
|
|
||||||
|
|
||||||
FreeSongs();
|
FreeSongs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SongManager::CategoryData::AddHighScore( HighScore hs, int &iIndexOut )
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for( i=0; i<(int)vHighScores.size(); i++ )
|
|
||||||
{
|
|
||||||
if( hs >= vHighScores[i] )
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if( i < NUM_RANKING_LINES )
|
|
||||||
{
|
|
||||||
vHighScores.insert( vHighScores.begin()+i, hs );
|
|
||||||
iIndexOut = i;
|
|
||||||
if( int(vHighScores.size()) > NUM_RANKING_LINES )
|
|
||||||
vHighScores.erase( vHighScores.begin()+NUM_RANKING_LINES, vHighScores.end() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SongManager::Reload()
|
void SongManager::Reload()
|
||||||
{
|
{
|
||||||
FlushDirCache();
|
FlushDirCache();
|
||||||
|
|
||||||
SaveMachineScoresToDisk();
|
PROFILEMAN->SaveMachineScoresToDisk();
|
||||||
FreeSongs();
|
FreeSongs();
|
||||||
FreeCourses();
|
FreeCourses();
|
||||||
|
|
||||||
@@ -131,15 +100,7 @@ void SongManager::Reload()
|
|||||||
InitSongsFromDisk(NULL);
|
InitSongsFromDisk(NULL);
|
||||||
InitCoursesFromDisk(NULL);
|
InitCoursesFromDisk(NULL);
|
||||||
InitAutogenCourses();
|
InitAutogenCourses();
|
||||||
InitMachineScoresFromDisk();
|
PROFILEMAN->InitMachineScoresFromDisk();
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SongManager::SaveMachineScoresToDisk()
|
|
||||||
{
|
|
||||||
SaveCategoryRankingsToFile( CATEGORY_RANKING_FILE );
|
|
||||||
SaveStepsMemCardDataToFile( MACHINE_STEPS_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
|
||||||
SaveCourseMemCardDataToFile( MACHINE_COURSE_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SongManager::InitSongsFromDisk( LoadingWindow *ld )
|
void SongManager::InitSongsFromDisk( LoadingWindow *ld )
|
||||||
@@ -335,490 +296,6 @@ void SongManager::FreeSongs()
|
|||||||
m_sGroupBannerPaths.clear();
|
m_sGroupBannerPaths.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Helper function for reading/writing scores
|
|
||||||
//
|
|
||||||
bool FileRead(RageFile& f, CString& sOut)
|
|
||||||
{
|
|
||||||
if (f.AtEOF())
|
|
||||||
return false;
|
|
||||||
sOut = f.GetLine();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileRead(RageFile& f, int& iOut)
|
|
||||||
{
|
|
||||||
CString s;
|
|
||||||
if (!FileRead(f, s))
|
|
||||||
return false;
|
|
||||||
iOut = atoi(s);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileRead(RageFile& f, unsigned& uOut)
|
|
||||||
{
|
|
||||||
CString s;
|
|
||||||
if (!FileRead(f, s))
|
|
||||||
return false;
|
|
||||||
uOut = atoi(s);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileRead(RageFile& f, float& fOut)
|
|
||||||
{
|
|
||||||
CString s;
|
|
||||||
if (!FileRead(f, s))
|
|
||||||
return false;
|
|
||||||
fOut = (float)atof(s);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileWrite(RageFile& f, const CString& sWrite)
|
|
||||||
{
|
|
||||||
f.PutLine( sWrite );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileWrite(RageFile& f, int iWrite)
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf("%d", iWrite) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileWrite(RageFile& f, size_t uWrite)
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf("%lu", uWrite) );
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileWrite(RageFile& f, float fWrite)
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf("%f", fWrite) );
|
|
||||||
}
|
|
||||||
|
|
||||||
#define WARN_AND_RETURN { LOG->Warn("Error parsing file '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); return; }
|
|
||||||
|
|
||||||
void SongManager::ReadStepsMemCardDataFromFile( CString fn, int mc )
|
|
||||||
{
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return; /* don't warn if it just doesn't exist */
|
|
||||||
|
|
||||||
int version;
|
|
||||||
if( !FileRead(f, version) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
if( version != STEPS_MEM_CARD_DATA_VERSION )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
int iNumSongs;
|
|
||||||
if( !FileRead(f, iNumSongs) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
for( int s=0; s<iNumSongs; s++ )
|
|
||||||
{
|
|
||||||
CString sSongDir;
|
|
||||||
if( !FileRead(f, sSongDir) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
Song* pSong = this->GetSongFromDir( sSongDir );
|
|
||||||
|
|
||||||
int iNumNotes;
|
|
||||||
if( !FileRead(f, iNumNotes) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
for( int n=0; n<iNumNotes; n++ )
|
|
||||||
{
|
|
||||||
StepsType nt;
|
|
||||||
if( !FileRead(f, (int&)nt) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
Difficulty dc;
|
|
||||||
if( !FileRead(f, (int&)dc) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
CString sDescription;
|
|
||||||
if( !FileRead(f, sDescription) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
// Even if pSong or pNotes is null, we still have to skip over that data.
|
|
||||||
|
|
||||||
Steps* pNotes = NULL;
|
|
||||||
if( pSong )
|
|
||||||
{
|
|
||||||
if( dc==DIFFICULTY_INVALID )
|
|
||||||
pNotes = pSong->GetStepsByDescription( nt, sDescription );
|
|
||||||
else
|
|
||||||
pNotes = pSong->GetStepsByDifficulty( nt, dc );
|
|
||||||
}
|
|
||||||
|
|
||||||
int iNumTimesPlayed;
|
|
||||||
if( !FileRead(f, iNumTimesPlayed) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
if( pNotes )
|
|
||||||
pNotes->m_MemCardDatas[mc].iNumTimesPlayed = iNumTimesPlayed;
|
|
||||||
|
|
||||||
if( pNotes )
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
CString sName;
|
|
||||||
if( !FileRead(f, sName) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
Grade grade;
|
|
||||||
if( !FileRead(f, (int&)grade) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
CLAMP( grade, (Grade)0, (Grade)(NUM_GRADES-1) );
|
|
||||||
|
|
||||||
int iScore;
|
|
||||||
if( !FileRead(f, iScore) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
float fPercentDP;
|
|
||||||
if( !FileRead(f, fPercentDP) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
if( pNotes )
|
|
||||||
{
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores[l].sName = sName;
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores[l].grade = grade;
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores[l].iScore = iScore;
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores[l].fPercentDP = fPercentDP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SongManager::ReadCategoryRankingsFromFile( CString fn )
|
|
||||||
{
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return; /* don't warn if it just doesn't exist */
|
|
||||||
|
|
||||||
int version;
|
|
||||||
if( !FileRead(f, version) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
if( version != CATEGORY_RANKING_VERSION )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
for( int st=0; st<NUM_STEPS_TYPES; st++ )
|
|
||||||
{
|
|
||||||
for( int rc=0; rc<NUM_RANKING_CATEGORIES; rc++ )
|
|
||||||
{
|
|
||||||
m_CategoryDatas[st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
CString sName;
|
|
||||||
if( !FileRead(f, sName) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
int iScore;
|
|
||||||
if( !FileRead(f, iScore) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
m_CategoryDatas[st][rc].vHighScores[l].sName = sName;
|
|
||||||
m_CategoryDatas[st][rc].vHighScores[l].iScore = iScore;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongManager::ReadCourseMemCardDataFromFile( CString fn, int mc )
|
|
||||||
{
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return; /* don't warn if it just doesn't exist */
|
|
||||||
|
|
||||||
int version;
|
|
||||||
if( !FileRead(f, version) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
if( version != COURSE_MEM_CARD_DATA_VERSION )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
int iNumCourses;
|
|
||||||
if( !FileRead(f, iNumCourses) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
for( int c=0; c<iNumCourses; c++ )
|
|
||||||
{
|
|
||||||
CString sPath;
|
|
||||||
if( !FileRead(f, sPath) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
Course* pCourse = GetCourseFromPath( sPath );
|
|
||||||
if( pCourse == NULL )
|
|
||||||
pCourse = GetCourseFromName( sPath );
|
|
||||||
|
|
||||||
// even if we don't find the Course*, we still have to read past the input
|
|
||||||
|
|
||||||
int NumStepsPlayed = 0;
|
|
||||||
if( !FileRead(f, NumStepsPlayed) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
while( NumStepsPlayed-- )
|
|
||||||
{
|
|
||||||
int st;
|
|
||||||
if( !FileRead(f, st) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
int iNumTimesPlayed;
|
|
||||||
if( !FileRead(f, iNumTimesPlayed) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
if( pCourse )
|
|
||||||
pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed = iNumTimesPlayed;
|
|
||||||
if( pCourse )
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
CString sName;
|
|
||||||
if( !FileRead(f, sName) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
int iScore;
|
|
||||||
if( !FileRead(f, iScore) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
float fSurviveTime;
|
|
||||||
if( !FileRead(f, fSurviveTime) )
|
|
||||||
WARN_AND_RETURN;
|
|
||||||
|
|
||||||
if( pCourse && st < NUM_STEPS_TYPES )
|
|
||||||
{
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName = sName;
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores[l].iScore = iScore;
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores[l].fSurviveTime = fSurviveTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongManager::InitMachineScoresFromDisk()
|
|
||||||
{
|
|
||||||
// read old style notes scores
|
|
||||||
ReadSM300NoteScores();
|
|
||||||
|
|
||||||
// category ranking
|
|
||||||
ReadCategoryRankingsFromFile( CATEGORY_RANKING_FILE );
|
|
||||||
ReadCourseMemCardDataFromFile( MACHINE_COURSE_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
|
||||||
ReadStepsMemCardDataFromFile( MACHINE_STEPS_MEM_CARD_DATA, MEMORY_CARD_MACHINE );
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongManager::ReadSM300NoteScores()
|
|
||||||
{
|
|
||||||
IniFile ini;
|
|
||||||
ini.SetPath( SM_300_STATISTICS_FILE );
|
|
||||||
if( !ini.ReadFile() ) {
|
|
||||||
LOG->Trace( "WARNING: Could not read SM 3.0 final statistics '%s'.", SM_300_STATISTICS_FILE );
|
|
||||||
return; // load nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
// load song statistics
|
|
||||||
const IniFile::key* pKey = ini.GetKey( "Statistics" );
|
|
||||||
if( pKey )
|
|
||||||
{
|
|
||||||
for( IniFile::key::const_iterator iter = pKey->begin();
|
|
||||||
iter != pKey->end();
|
|
||||||
iter++ )
|
|
||||||
{
|
|
||||||
CString name = iter->first;
|
|
||||||
CString value = iter->second;
|
|
||||||
|
|
||||||
// Each value has the format "SongName::StepsType::StepsDescription=TimesPlayed::TopGrade::TopScore::MaxCombo".
|
|
||||||
char szSongDir[256];
|
|
||||||
char szStepsType[256];
|
|
||||||
char szStepsDescription[256];
|
|
||||||
int iRetVal;
|
|
||||||
|
|
||||||
// Parse for Song name and Notes name
|
|
||||||
iRetVal = sscanf( name, "%[^:]::%[^:]::%[^:]", szSongDir, szStepsType, szStepsDescription );
|
|
||||||
if( iRetVal != 3 )
|
|
||||||
continue; // this line doesn't match what is expected
|
|
||||||
|
|
||||||
CString sSongDir = FixSlashes( szSongDir );
|
|
||||||
|
|
||||||
// Search for the corresponding Song pointer.
|
|
||||||
Song* pSong = GetSongFromDir( sSongDir );
|
|
||||||
if( pSong == NULL ) // didn't find a match
|
|
||||||
continue; // skip this entry
|
|
||||||
|
|
||||||
StepsType st = GAMEMAN->StringToNotesType( szStepsType );
|
|
||||||
Difficulty dc = StringToDifficulty( szStepsDescription );
|
|
||||||
|
|
||||||
// Search for the corresponding Notes pointer.
|
|
||||||
Steps* pNotes = pSong->GetStepsByDifficulty( st, dc );
|
|
||||||
if( pNotes == NULL ) // didn't find a match
|
|
||||||
continue; // skip this entry
|
|
||||||
|
|
||||||
|
|
||||||
// Parse the Notes statistics.
|
|
||||||
char szGradeLetters[10]; // longest possible string is "AAA"
|
|
||||||
int iMaxCombo; // throw away
|
|
||||||
|
|
||||||
pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores.resize(1);
|
|
||||||
|
|
||||||
iRetVal = sscanf(
|
|
||||||
value,
|
|
||||||
"%d::%[^:]::%d::%d",
|
|
||||||
&pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].iNumTimesPlayed,
|
|
||||||
szGradeLetters,
|
|
||||||
&pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].iScore,
|
|
||||||
&iMaxCombo
|
|
||||||
);
|
|
||||||
if( iRetVal != 4 )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].grade = StringToGrade( szGradeLetters );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SongManager::SaveCategoryRankingsToFile( CString fn )
|
|
||||||
{
|
|
||||||
LOG->Trace("SongManager::SaveCategoryRankingsToFile");
|
|
||||||
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FileWrite( f, CATEGORY_RANKING_VERSION );
|
|
||||||
|
|
||||||
for( int st=0; st<NUM_STEPS_TYPES; st++ )
|
|
||||||
{
|
|
||||||
for( int rc=0; rc<NUM_RANKING_CATEGORIES; rc++ )
|
|
||||||
{
|
|
||||||
m_CategoryDatas[st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
// tricky: wipe out "name to fill in" markers
|
|
||||||
if( IsRankingToFillIn(m_CategoryDatas[st][rc].vHighScores[l].sName) )
|
|
||||||
m_CategoryDatas[st][rc].vHighScores[l].sName = "";
|
|
||||||
|
|
||||||
FileWrite( f, m_CategoryDatas[st][rc].vHighScores[l].sName );
|
|
||||||
FileWrite( f, m_CategoryDatas[st][rc].vHighScores[l].iScore );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongManager::SaveCourseMemCardDataToFile( CString fn, int mc )
|
|
||||||
{
|
|
||||||
LOG->Trace("SongManager::SaveCourseMemCardDataToFile");
|
|
||||||
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FileWrite( f, COURSE_MEM_CARD_DATA_VERSION );
|
|
||||||
|
|
||||||
FileWrite( f, m_pCourses.size() );
|
|
||||||
|
|
||||||
for( unsigned c=0; c<m_pCourses.size(); c++ ) // foreach course
|
|
||||||
{
|
|
||||||
Course* pCourse = m_pCourses[c];
|
|
||||||
ASSERT(pCourse);
|
|
||||||
|
|
||||||
if( pCourse->m_bIsAutogen )
|
|
||||||
FileWrite( f, pCourse->m_sName );
|
|
||||||
else
|
|
||||||
FileWrite( f, pCourse->m_sPath );
|
|
||||||
|
|
||||||
int NumStepsPlayed = 0;
|
|
||||||
int st;
|
|
||||||
for( st=0; st<NUM_STEPS_TYPES; st++ )
|
|
||||||
if( pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed )
|
|
||||||
++NumStepsPlayed;
|
|
||||||
FileWrite( f, NumStepsPlayed );
|
|
||||||
|
|
||||||
for( st=0; st<NUM_STEPS_TYPES; st++ )
|
|
||||||
{
|
|
||||||
if( !pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed )
|
|
||||||
continue;
|
|
||||||
--NumStepsPlayed;
|
|
||||||
|
|
||||||
FileWrite( f, st );
|
|
||||||
FileWrite( f, pCourse->m_MemCardDatas[st][mc].iNumTimesPlayed );
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
// tricky: wipe out "name to fill in" markers
|
|
||||||
if( IsRankingToFillIn(pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName) )
|
|
||||||
pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName = "";
|
|
||||||
|
|
||||||
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].sName );
|
|
||||||
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].iScore );
|
|
||||||
FileWrite( f, pCourse->m_MemCardDatas[st][mc].vHighScores[l].fSurviveTime );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ASSERT( !NumStepsPlayed );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SongManager::SaveStepsMemCardDataToFile( CString fn, int mc )
|
|
||||||
{
|
|
||||||
LOG->Trace("SongManager::SaveStepsMemCardDataToFile %s", fn.c_str());
|
|
||||||
|
|
||||||
RageFile f(fn);
|
|
||||||
if (!f.IsOpen() || f.GetError() != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
FileWrite( f, STEPS_MEM_CARD_DATA_VERSION );
|
|
||||||
|
|
||||||
FileWrite( f, m_pSongs.size() );
|
|
||||||
|
|
||||||
for( unsigned s=0; s<m_pSongs.size(); s++ ) // foreach song
|
|
||||||
{
|
|
||||||
Song* pSong = m_pSongs[s];
|
|
||||||
ASSERT(pSong);
|
|
||||||
|
|
||||||
/* If the song has never been played, don't write anything. This keeps
|
|
||||||
* us from saving a dozen copies of each song for all autogen difficulties,
|
|
||||||
* since most people only use a couple game modes. */
|
|
||||||
vector<Steps*> vNotes;
|
|
||||||
for( unsigned i=0; i<pSong->m_apNotes.size(); ++i )
|
|
||||||
{
|
|
||||||
Steps* pNotes = pSong->m_apNotes[i];
|
|
||||||
if( !pNotes->m_MemCardDatas[mc].iNumTimesPlayed )
|
|
||||||
continue;
|
|
||||||
vNotes.push_back( pNotes );
|
|
||||||
}
|
|
||||||
|
|
||||||
FileWrite( f, pSong->GetSongDir() );
|
|
||||||
FileWrite( f, vNotes.size() );
|
|
||||||
|
|
||||||
if( vNotes.size() == 0 )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
for( unsigned n=0; n<vNotes.size(); n++ )
|
|
||||||
{
|
|
||||||
Steps* pNotes = vNotes[n];
|
|
||||||
ASSERT(pNotes);
|
|
||||||
|
|
||||||
FileWrite( f, pNotes->m_StepsType );
|
|
||||||
FileWrite( f, pNotes->GetDifficulty() );
|
|
||||||
FileWrite( f, pNotes->GetDescription() );
|
|
||||||
FileWrite( f, pNotes->m_MemCardDatas[mc].iNumTimesPlayed );
|
|
||||||
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores.resize(NUM_RANKING_LINES);
|
|
||||||
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
||||||
{
|
|
||||||
// tricky: wipe out "name to fill in" markers
|
|
||||||
if( IsRankingToFillIn(pNotes->m_MemCardDatas[mc].vHighScores[l].sName) )
|
|
||||||
pNotes->m_MemCardDatas[mc].vHighScores[l].sName = "";
|
|
||||||
|
|
||||||
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].sName );
|
|
||||||
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].grade );
|
|
||||||
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].iScore );
|
|
||||||
FileWrite( f, pNotes->m_MemCardDatas[mc].vHighScores[l].fPercentDP );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CString SongManager::GetGroupBannerPath( CString sGroupName )
|
CString SongManager::GetGroupBannerPath( CString sGroupName )
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@@ -1390,168 +867,3 @@ void SongManager::UpdateRankingCourses()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CString HTMLQuoteDoubleQuotes( CString str )
|
|
||||||
{
|
|
||||||
str.Replace( "\"", """ );
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool CompareStepsPointersByTypeAndDifficulty(const Steps *pStep1, const Steps *pStep2)
|
|
||||||
{
|
|
||||||
if( pStep1->m_StepsType < pStep2->m_StepsType )
|
|
||||||
return true;
|
|
||||||
if( pStep1->m_StepsType > pStep2->m_StepsType )
|
|
||||||
return false;
|
|
||||||
return pStep1->GetDifficulty() < pStep2->GetDifficulty();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void SortStepsByTypeAndDifficulty( vector<Steps*> &arraySongPointers )
|
|
||||||
{
|
|
||||||
sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByTypeAndDifficulty );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HTMLWritePerGameHeader( RageFile &f, Game game )
|
|
||||||
{
|
|
||||||
const GameDef* pGameDef = GAMEMAN->GetGameDefForGame(game);
|
|
||||||
|
|
||||||
vector<StepsType> aStepsTypes;
|
|
||||||
GAMEMAN->GetNotesTypesForGame( game, aStepsTypes );
|
|
||||||
|
|
||||||
f.PutLine( ssprintf("<h1>%s</h1>", pGameDef->m_szName) );
|
|
||||||
|
|
||||||
f.PutLine( "<table border='1'>" );
|
|
||||||
f.Write( "<tr><td>title</td>" );
|
|
||||||
|
|
||||||
unsigned j;
|
|
||||||
for( j=0; j<aStepsTypes.size(); j++ )
|
|
||||||
{
|
|
||||||
StepsType st = aStepsTypes[j];
|
|
||||||
|
|
||||||
f.PutLine( ssprintf("<td colspan='%d'>%s</td>", NUM_DIFFICULTIES, GAMEMAN->NotesTypeToString(st).c_str()) );
|
|
||||||
}
|
|
||||||
f.PutLine( "</tr>" );
|
|
||||||
|
|
||||||
f.Write( "<tr><td> </td>" );
|
|
||||||
for( j=0; j<aStepsTypes.size(); j++ )
|
|
||||||
{
|
|
||||||
for( unsigned k=0; k<NUM_DIFFICULTIES; k++ )
|
|
||||||
{
|
|
||||||
Difficulty d = (Difficulty)k;
|
|
||||||
f.PutLine( ssprintf("<td>%s</td>", Capitalize(DifficultyToString(d).Left(3)).c_str()) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.PutLine( "</tr>" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this to a different file. No need to clutter SongManager.
|
|
||||||
void SongManager::WriteStatsWebPage()
|
|
||||||
{
|
|
||||||
RageFile f;
|
|
||||||
if( !f.Open( STATS_PATH, RageFile::WRITE ) )
|
|
||||||
return;
|
|
||||||
|
|
||||||
f.PutLine( "<html>" );
|
|
||||||
f.PutLine( "<head>" );
|
|
||||||
f.PutLine( "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=UTF-8\">" );
|
|
||||||
f.PutLine( ssprintf("<title>%s</title>", PRODUCT_NAME_VER) );
|
|
||||||
f.PutLine( "</head>" );
|
|
||||||
f.PutLine( "<body>" );
|
|
||||||
|
|
||||||
vector<Song*> vSongs = m_pSongs;
|
|
||||||
SortSongPointerArrayByGroupAndTitle( vSongs );
|
|
||||||
|
|
||||||
//
|
|
||||||
// Print song list
|
|
||||||
//
|
|
||||||
f.PutLine( "<table border='1'>" );
|
|
||||||
for( unsigned i=0; i<vSongs.size(); i++ )
|
|
||||||
{
|
|
||||||
Song* pSong = m_pSongs[i];
|
|
||||||
f.Write( "<tr>" );
|
|
||||||
/* XXX: We can't call pSong->HasBanner on every song; it'll effectively re-traverse the entire
|
|
||||||
* song directory tree checking if each banner file really exists.
|
|
||||||
*
|
|
||||||
* (Note for testing this: remember that we'll cache directories for a time; this is only slow if
|
|
||||||
* the directory cache expires before we get here.) */
|
|
||||||
//CString sImagePath = pSong->HasBanner() ? pSong->GetBannerPath() : (pSong->HasBackground() ? pSong->GetBackgroundPath() : "" );
|
|
||||||
CString sImagePath = pSong->GetBannerPath();
|
|
||||||
if( sImagePath.empty() )
|
|
||||||
f.Write( "<td> </td>" );
|
|
||||||
else
|
|
||||||
f.Write( ssprintf("<td><img src=\"%s\" width='120'></td>", HTMLQuoteDoubleQuotes(sImagePath).c_str()) );
|
|
||||||
|
|
||||||
f.Write( ssprintf("<td>%s<br>", pSong->GetTranslitMainTitle().c_str()) );
|
|
||||||
f.Write( ssprintf("<font size='-1'>%s</font><br>", pSong->GetTranslitSubTitle().c_str()) );
|
|
||||||
f.Write( ssprintf("<font size='-1'><i>%s</i></font></td>", pSong->GetTranslitArtist().c_str()) );
|
|
||||||
f.PutLine( "</tr>" );
|
|
||||||
}
|
|
||||||
f.PutLine( "</table>\n<br>" );
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Print steps tables
|
|
||||||
//
|
|
||||||
for( int g=0; g<NUM_GAMES; g++ )
|
|
||||||
{
|
|
||||||
Game game = (Game)g;
|
|
||||||
|
|
||||||
vector<StepsType> aStepsTypes;
|
|
||||||
GAMEMAN->GetNotesTypesForGame( game, aStepsTypes );
|
|
||||||
|
|
||||||
bool WroteHeader = false;
|
|
||||||
for( unsigned i=0; i<vSongs.size(); i++ )
|
|
||||||
{
|
|
||||||
/* Get the steps for this game type. */
|
|
||||||
Song* pSong = m_pSongs[i];
|
|
||||||
vector<Steps*> Steps;
|
|
||||||
unsigned j;
|
|
||||||
for( j=0; j < aStepsTypes.size(); j++ )
|
|
||||||
pSong->GetSteps( Steps, (StepsType) aStepsTypes[j], DIFFICULTY_INVALID, -1, -1, "", false );
|
|
||||||
|
|
||||||
/* Don't write anything for songs that have no steps at all for this
|
|
||||||
* game. Otherwise, we'll write pages and pages of empty fields for
|
|
||||||
* all of the less-used game types. */
|
|
||||||
if( Steps.size() == 0 )
|
|
||||||
continue; // skip
|
|
||||||
|
|
||||||
/* We have some steps for this game. Make sure we've written the game header. */
|
|
||||||
if( !WroteHeader )
|
|
||||||
{
|
|
||||||
HTMLWritePerGameHeader( f, game );
|
|
||||||
WroteHeader = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
f.PutLine( "<tr>" );
|
|
||||||
|
|
||||||
f.Write( ssprintf("<td>%s</td>", pSong->GetTranslitMainTitle().c_str()) );
|
|
||||||
|
|
||||||
SortStepsByTypeAndDifficulty( Steps );
|
|
||||||
|
|
||||||
unsigned CurSteps = 0;
|
|
||||||
for( j=0; j<aStepsTypes.size(); j++ )
|
|
||||||
{
|
|
||||||
for( int k=0; k<NUM_DIFFICULTIES; k++ )
|
|
||||||
{
|
|
||||||
if( CurSteps < Steps.size() &&
|
|
||||||
Steps[CurSteps]->m_StepsType == aStepsTypes[j] &&
|
|
||||||
Steps[CurSteps]->GetDifficulty() == k )
|
|
||||||
{
|
|
||||||
f.PutLine( ssprintf("<td>%d</td>", Steps[CurSteps]->GetMeter()) );
|
|
||||||
++CurSteps;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
f.PutLine( "<td> </td>" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Write( "</tr>" );
|
|
||||||
}
|
|
||||||
if( WroteHeader )
|
|
||||||
f.PutLine( "</table>\n<br>" ); // footer
|
|
||||||
}
|
|
||||||
|
|
||||||
f.PutLine( "</body>" );
|
|
||||||
f.PutLine( "</html>" );
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -86,53 +86,9 @@ public:
|
|||||||
Course* GetCourseFromName( CString sName );
|
Course* GetCourseFromName( CString sName );
|
||||||
|
|
||||||
|
|
||||||
//
|
void UpdateBest(); // update Players Best
|
||||||
// High scores
|
|
||||||
//
|
|
||||||
void InitMachineScoresFromDisk();
|
|
||||||
void SaveMachineScoresToDisk();
|
|
||||||
|
|
||||||
struct CategoryData
|
void UpdateRankingCourses(); // courses shown on the ranking screen
|
||||||
{
|
|
||||||
struct HighScore
|
|
||||||
{
|
|
||||||
int iScore;
|
|
||||||
CString sName;
|
|
||||||
|
|
||||||
HighScore()
|
|
||||||
{
|
|
||||||
iScore = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>=( const HighScore& other ) const
|
|
||||||
{
|
|
||||||
return iScore >= other.iScore;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
vector<HighScore> vHighScores;
|
|
||||||
|
|
||||||
void AddHighScore( HighScore hs, int &iIndexOut );
|
|
||||||
|
|
||||||
} m_CategoryDatas[NUM_STEPS_TYPES][NUM_RANKING_CATEGORIES];
|
|
||||||
|
|
||||||
void AddHighScore( StepsType nt, RankingCategory rc, PlayerNumber pn, CategoryData::HighScore hs, int &iMachineIndexOut )
|
|
||||||
{
|
|
||||||
hs.sName = RANKING_TO_FILL_IN_MARKER[pn];
|
|
||||||
m_CategoryDatas[nt][rc].AddHighScore( hs, iMachineIndexOut );
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdateBest();
|
|
||||||
|
|
||||||
void UpdateRankingCourses();
|
|
||||||
|
|
||||||
void ReadSM300NoteScores();
|
|
||||||
void ReadStepsMemCardDataFromFile( CString fn, int c );
|
|
||||||
void ReadCourseMemCardDataFromFile( CString fn, int c );
|
|
||||||
void ReadCategoryRankingsFromFile( CString fn );
|
|
||||||
|
|
||||||
void SaveStepsMemCardDataToFile( CString fn, int c );
|
|
||||||
void SaveCourseMemCardDataToFile( CString fn, int c );
|
|
||||||
void SaveCategoryRankingsToFile( CString fn );
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void LoadStepManiaSongDir( CString sDir, LoadingWindow *ld );
|
void LoadStepManiaSongDir( CString sDir, LoadingWindow *ld );
|
||||||
@@ -144,8 +100,6 @@ protected:
|
|||||||
|
|
||||||
Song *FindSong( CString sGroup, CString sSong );
|
Song *FindSong( CString sGroup, CString sSong );
|
||||||
|
|
||||||
void WriteStatsWebPage();
|
|
||||||
|
|
||||||
vector<Song*> m_pSongs; // all songs that can be played
|
vector<Song*> m_pSongs; // all songs that can be played
|
||||||
vector<Song*> m_pBestSongs[NUM_MEMORY_CARDS];
|
vector<Song*> m_pBestSongs[NUM_MEMORY_CARDS];
|
||||||
CStringArray m_sGroupNames;
|
CStringArray m_sGroupNames;
|
||||||
|
|||||||
@@ -942,6 +942,7 @@ int main(int argc, char* argv[])
|
|||||||
SAFE_DELETE( INPUTQUEUE );
|
SAFE_DELETE( INPUTQUEUE );
|
||||||
SAFE_DELETE( INPUTMAPPER );
|
SAFE_DELETE( INPUTMAPPER );
|
||||||
SAFE_DELETE( INPUTFILTER );
|
SAFE_DELETE( INPUTFILTER );
|
||||||
|
SAFE_DELETE( PROFILEMAN ); // PROFILEMAN needs the songs still loaded
|
||||||
SAFE_DELETE( SONGMAN );
|
SAFE_DELETE( SONGMAN );
|
||||||
SAFE_DELETE( BANNERCACHE );
|
SAFE_DELETE( BANNERCACHE );
|
||||||
SAFE_DELETE( SONGINDEX );
|
SAFE_DELETE( SONGINDEX );
|
||||||
@@ -951,7 +952,6 @@ int main(int argc, char* argv[])
|
|||||||
SAFE_DELETE( NOTESKIN );
|
SAFE_DELETE( NOTESKIN );
|
||||||
SAFE_DELETE( THEME );
|
SAFE_DELETE( THEME );
|
||||||
SAFE_DELETE( ANNOUNCER );
|
SAFE_DELETE( ANNOUNCER );
|
||||||
SAFE_DELETE( PROFILEMAN );
|
|
||||||
SAFE_DELETE( BOOKKEEPER );
|
SAFE_DELETE( BOOKKEEPER );
|
||||||
SAFE_DELETE( LIGHTSMAN );
|
SAFE_DELETE( LIGHTSMAN );
|
||||||
SAFE_DELETE( SOUND );
|
SAFE_DELETE( SOUND );
|
||||||
|
|||||||
@@ -313,6 +313,19 @@ void SortNotesArrayByDifficulty( vector<Steps*> &arraySteps )
|
|||||||
stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByDifficulty );
|
stable_sort( arraySteps.begin(), arraySteps.end(), CompareNotesPointersByDifficulty );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompareStepsPointersByTypeAndDifficulty(const Steps *pStep1, const Steps *pStep2)
|
||||||
|
{
|
||||||
|
if( pStep1->m_StepsType < pStep2->m_StepsType )
|
||||||
|
return true;
|
||||||
|
if( pStep1->m_StepsType > pStep2->m_StepsType )
|
||||||
|
return false;
|
||||||
|
return pStep1->GetDifficulty() < pStep2->GetDifficulty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortStepsByTypeAndDifficulty( vector<Steps*> &arraySongPointers )
|
||||||
|
{
|
||||||
|
sort( arraySongPointers.begin(), arraySongPointers.end(), CompareStepsPointersByTypeAndDifficulty );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Steps::MemCardData::HighScore::operator>=( const Steps::MemCardData::HighScore& other ) const
|
bool Steps::MemCardData::HighScore::operator>=( const Steps::MemCardData::HighScore& other ) const
|
||||||
|
|||||||
@@ -135,5 +135,7 @@ bool CompareNotesPointersByRadarValues(const Steps* pNotes1, const Steps* pNotes
|
|||||||
bool CompareNotesPointersByMeter(const Steps *pNotes1, const Steps* pNotes2);
|
bool CompareNotesPointersByMeter(const Steps *pNotes1, const Steps* pNotes2);
|
||||||
bool CompareNotesPointersByDifficulty(const Steps *pNotes1, const Steps *pNotes2);
|
bool CompareNotesPointersByDifficulty(const Steps *pNotes1, const Steps *pNotes2);
|
||||||
void SortNotesArrayByDifficulty( vector<Steps*> &arrayNotess );
|
void SortNotesArrayByDifficulty( vector<Steps*> &arrayNotess );
|
||||||
|
bool CompareStepsPointersByTypeAndDifficulty(const Steps *pStep1, const Steps *pStep2);
|
||||||
|
void SortStepsByTypeAndDifficulty( vector<Steps*> &arraySongPointers );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user