2003-09-08 03:26:58 +00:00
|
|
|
#include "global.h"
|
|
|
|
|
/*
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
Class: ProfileManager
|
|
|
|
|
|
|
|
|
|
Desc: See header.
|
|
|
|
|
|
|
|
|
|
Copyright (c) 2001-2002 by the person(s) listed below. All rights reserved.
|
|
|
|
|
Chris Danford
|
|
|
|
|
-----------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "ProfileManager.h"
|
|
|
|
|
#include "RageUtil.h"
|
|
|
|
|
#include "arch/arch.h"
|
|
|
|
|
#include "PrefsManager.h"
|
|
|
|
|
#include "RageLog.h"
|
2003-12-05 00:07:18 +00:00
|
|
|
#include "RageFile.h"
|
|
|
|
|
#include "RageFileManager.h"
|
2003-09-08 03:26:58 +00:00
|
|
|
#include "IniFile.h"
|
2003-09-08 07:21:41 +00:00
|
|
|
#include "GameConstantsAndTypes.h"
|
|
|
|
|
#include "SongManager.h"
|
2003-11-10 04:32:12 +00:00
|
|
|
#include "GameState.h"
|
2003-12-07 07:09:13 +00:00
|
|
|
#include "song.h"
|
|
|
|
|
#include "Course.h"
|
|
|
|
|
#include "GameManager.h"
|
|
|
|
|
#include "ProductInfo.h"
|
2003-12-07 08:19:10 +00:00
|
|
|
#include "RageUtil.h"
|
2003-12-08 10:27:45 +00:00
|
|
|
#include "ThemeManager.h"
|
2003-09-08 03:26:58 +00:00
|
|
|
|
2003-11-14 17:17:36 +00:00
|
|
|
|
2003-09-08 03:26:58 +00:00
|
|
|
ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our program
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define PROFILE_FILE "Profile.ini"
|
|
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
#define CATEGORY_SCORES_FILE "CategoryScores.dat"
|
|
|
|
|
#define SONG_SCORES_FILE "SongScores.dat"
|
|
|
|
|
#define COURSE_SCORES_FILE "CourseScores.dat"
|
|
|
|
|
#define STATS_HTML_FILE "stats.html"
|
2003-12-08 10:27:45 +00:00
|
|
|
#define STYLE_CSS_FILE "style.css"
|
2003-12-07 07:46:21 +00:00
|
|
|
#define NEW_MEM_CARD_NAME "NewCard"
|
|
|
|
|
#define NEW_PROFILE_NAME "NewProfile"
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
#define SM_300_STATISTICS_FILE BASE_PATH "statistics.ini"
|
2003-12-07 07:46:21 +00:00
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
#define USER_PROFILES_DIR BASE_PATH "Data" SLASH "LocalProfiles" SLASH
|
2003-12-07 07:46:21 +00:00
|
|
|
#define MACHINE_PROFILE_DIR BASE_PATH "Data" SLASH "MachineProfile" SLASH
|
|
|
|
|
|
|
|
|
|
const int CATEGORY_RANKING_VERSION = 4;
|
|
|
|
|
const int STEPS_SCORES_VERSION = 8;
|
|
|
|
|
const int COURSE_SCORES_VERSION = 6;
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
|
2003-12-05 00:07:18 +00:00
|
|
|
static const char *MemCardDirs[NUM_PLAYERS] =
|
|
|
|
|
{
|
|
|
|
|
/* @ is important; see RageFileManager LoadedDriver::GetPath */
|
|
|
|
|
"@mc1" SLASH,
|
|
|
|
|
"@mc2" SLASH,
|
|
|
|
|
};
|
|
|
|
|
|
2003-09-08 03:26:58 +00:00
|
|
|
ProfileManager::ProfileManager()
|
|
|
|
|
{
|
|
|
|
|
for( int p=0; p<NUM_PLAYERS; p++ )
|
2003-12-05 00:07:18 +00:00
|
|
|
{
|
2003-09-08 03:26:58 +00:00
|
|
|
m_bUsingMemoryCard[p] = false;
|
2003-12-05 00:07:18 +00:00
|
|
|
|
|
|
|
|
if( PREFSMAN->m_sMemoryCardDir[p] != "" )
|
|
|
|
|
FILEMAN->Mount( "dir", PREFSMAN->m_sMemoryCardDir[p], MemCardDirs[p] );
|
|
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
InitMachineScoresFromDisk();
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ProfileManager::~ProfileManager()
|
|
|
|
|
{
|
2003-12-07 07:09:13 +00:00
|
|
|
SaveMachineScoresToDisk();
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
void ProfileManager::GetLocalProfileIDs( vector<CString> &asProfileIDsOut )
|
2003-09-08 03:26:58 +00:00
|
|
|
{
|
2003-12-07 07:46:21 +00:00
|
|
|
GetDirListing( USER_PROFILES_DIR "*", asProfileIDsOut, true, false );
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
void ProfileManager::GetLocalProfileNames( vector<CString> &asNamesOut )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
2003-11-01 19:36:52 +00:00
|
|
|
CStringArray vsProfileIDs;
|
2003-12-07 08:19:10 +00:00
|
|
|
GetLocalProfileIDs( vsProfileIDs );
|
2003-11-01 19:36:52 +00:00
|
|
|
for( unsigned i=0; i<vsProfileIDs.size(); i++ )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
2003-11-01 19:36:52 +00:00
|
|
|
CString sProfileID = vsProfileIDs[i];
|
2003-09-08 07:21:41 +00:00
|
|
|
|
|
|
|
|
Profile pro;
|
2003-12-07 07:46:21 +00:00
|
|
|
pro.LoadFromIni( USER_PROFILES_DIR + sProfileID + SLASH + PROFILE_FILE );
|
2003-11-01 19:36:52 +00:00
|
|
|
asNamesOut.push_back( pro.m_sName );
|
2003-09-08 07:21:41 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-11-01 22:04:43 +00:00
|
|
|
bool ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIsMemCard )
|
2003-09-08 03:26:58 +00:00
|
|
|
{
|
2003-11-01 22:04:43 +00:00
|
|
|
ASSERT( !sProfileDir.empty() );
|
|
|
|
|
ASSERT( sProfileDir.Right(1) == SLASH );
|
2003-09-08 03:26:58 +00:00
|
|
|
|
2003-11-01 22:04:43 +00:00
|
|
|
m_sProfileDir[pn] = sProfileDir;
|
|
|
|
|
m_bUsingMemoryCard[pn] = bIsMemCard;
|
2003-11-01 19:36:52 +00:00
|
|
|
|
|
|
|
|
bool bResult = m_Profile[pn].LoadFromIni( m_sProfileDir[pn]+PROFILE_FILE );
|
|
|
|
|
if( !bResult )
|
2003-09-08 03:26:58 +00:00
|
|
|
{
|
2003-11-01 22:04:43 +00:00
|
|
|
LOG->Warn( "Attempting to load profile from '%s' and does not exist", sProfileDir.c_str() );
|
2003-11-01 19:36:52 +00:00
|
|
|
UnloadProfile( pn );
|
|
|
|
|
return false;
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
2003-09-08 07:21:41 +00:00
|
|
|
// Load scores into SONGMAN
|
2003-12-08 10:27:45 +00:00
|
|
|
PROFILEMAN->ReadCategoryScoresFromDir( m_sProfileDir[pn], (MemoryCard)pn );
|
|
|
|
|
PROFILEMAN->ReadSongScoresFromDir( m_sProfileDir[pn], (MemoryCard)pn );
|
|
|
|
|
PROFILEMAN->ReadCourseScoresFromDir( m_sProfileDir[pn], (MemoryCard)pn );
|
2003-11-01 19:36:52 +00:00
|
|
|
|
2003-11-10 04:32:12 +00:00
|
|
|
// apply saved default modifiers if any
|
|
|
|
|
if( m_Profile[pn].m_bUsingProfileDefaultModifiers )
|
|
|
|
|
{
|
|
|
|
|
GAMESTATE->m_PlayerOptions[pn].Init();
|
|
|
|
|
GAMESTATE->ApplyModifiers( pn, m_Profile[pn].m_sDefaultModifiers );
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
return true;
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-01 22:04:43 +00:00
|
|
|
bool ProfileManager::CreateProfile( CString sProfileDir, CString sName )
|
|
|
|
|
{
|
2003-12-08 06:41:30 +00:00
|
|
|
ASSERT( !sName.empty() );
|
|
|
|
|
|
2003-11-01 22:04:43 +00:00
|
|
|
bool bResult;
|
|
|
|
|
|
|
|
|
|
Profile pro;
|
|
|
|
|
pro.m_sName = sName;
|
|
|
|
|
bResult = pro.SaveToIni( sProfileDir + PROFILE_FILE );
|
|
|
|
|
if( !bResult )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
FlushDirCache();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProfileManager::LoadDefaultProfileFromMachine( PlayerNumber pn )
|
|
|
|
|
{
|
2003-12-07 08:19:10 +00:00
|
|
|
CString sProfileID = PREFSMAN->m_sDefaultLocalProfileID[pn];
|
2003-11-01 22:04:43 +00:00
|
|
|
if( sProfileID.empty() )
|
|
|
|
|
{
|
|
|
|
|
m_sProfileDir[pn] = "";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
CString sDir = USER_PROFILES_DIR + sProfileID + SLASH;
|
2003-11-01 22:04:43 +00:00
|
|
|
|
|
|
|
|
return LoadProfile( pn, sDir, false );
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-08 15:49:48 +00:00
|
|
|
bool ProfileManager::IsMemoryCardInserted( PlayerNumber pn )
|
|
|
|
|
{
|
2003-12-05 00:07:18 +00:00
|
|
|
return FILEMAN->MountpointIsReady( MemCardDirs[pn] );
|
2003-11-01 22:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProfileManager::LoadProfileFromMemoryCard( PlayerNumber pn )
|
|
|
|
|
{
|
2003-12-05 00:07:18 +00:00
|
|
|
CString sDir = MemCardDirs[pn];
|
|
|
|
|
if( !FILEMAN->IsMounted(sDir) )
|
2003-11-01 22:04:43 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_bUsingMemoryCard[pn] = true;
|
|
|
|
|
bool bResult;
|
|
|
|
|
bResult = LoadProfile( pn, sDir, false );
|
2003-11-08 15:49:48 +00:00
|
|
|
return bResult;
|
2003-11-01 22:04:43 +00:00
|
|
|
}
|
2003-11-09 21:39:54 +00:00
|
|
|
|
2003-11-01 22:04:43 +00:00
|
|
|
bool ProfileManager::LoadFirstAvailableProfile( PlayerNumber pn )
|
|
|
|
|
{
|
2003-11-13 00:39:36 +00:00
|
|
|
#ifndef _XBOX
|
2003-11-09 11:50:28 +00:00
|
|
|
// mount card
|
|
|
|
|
if( !PREFSMAN->m_sMemoryCardMountCommand[pn].empty() )
|
|
|
|
|
system( PREFSMAN->m_sMemoryCardMountCommand[pn] );
|
|
|
|
|
|
2003-11-09 10:53:19 +00:00
|
|
|
if( IsMemoryCardInserted(pn) )
|
2003-11-08 15:49:48 +00:00
|
|
|
{
|
2003-11-09 10:53:19 +00:00
|
|
|
if( LoadProfileFromMemoryCard(pn) )
|
|
|
|
|
return true;
|
|
|
|
|
|
2003-12-05 00:07:18 +00:00
|
|
|
CString sDir = MemCardDirs[pn];
|
2003-11-08 15:49:48 +00:00
|
|
|
CreateProfile( sDir, NEW_MEM_CARD_NAME );
|
|
|
|
|
if( LoadProfileFromMemoryCard(pn) )
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2003-11-13 00:39:36 +00:00
|
|
|
#endif
|
2003-11-08 15:49:48 +00:00
|
|
|
|
|
|
|
|
if( LoadDefaultProfileFromMachine(pn) )
|
2003-11-01 22:04:43 +00:00
|
|
|
return true;
|
2003-11-08 15:49:48 +00:00
|
|
|
|
|
|
|
|
return false;
|
2003-11-01 22:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
bool ProfileManager::SaveProfile( PlayerNumber pn )
|
2003-09-08 03:26:58 +00:00
|
|
|
{
|
|
|
|
|
if( m_sProfileDir[pn].empty() )
|
2003-11-01 19:36:52 +00:00
|
|
|
return false;
|
2003-09-08 03:26:58 +00:00
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
m_Profile[pn].SaveToIni( m_sProfileDir[pn]+PROFILE_FILE );
|
2003-09-08 03:26:58 +00:00
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
SaveCategoryScoresToDir( m_sProfileDir[pn], (MemoryCard)pn );
|
|
|
|
|
SaveSongScoresToDir( m_sProfileDir[pn], (MemoryCard)pn );
|
|
|
|
|
SaveCourseScoresToDir( m_sProfileDir[pn], (MemoryCard)pn );
|
|
|
|
|
SaveStatsWebPageToDir( m_sProfileDir[pn], (MemoryCard)pn );
|
2003-11-01 19:36:52 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2003-09-14 20:34:33 +00:00
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
void ProfileManager::UnloadProfile( PlayerNumber pn )
|
|
|
|
|
{
|
|
|
|
|
m_sProfileDir[pn] = "";
|
|
|
|
|
m_bUsingMemoryCard[pn] = false;
|
2003-09-14 20:34:33 +00:00
|
|
|
m_Profile[pn].Init();
|
2003-09-08 07:21:41 +00:00
|
|
|
}
|
|
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
Profile* ProfileManager::GetProfile( PlayerNumber pn )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
2003-11-01 19:36:52 +00:00
|
|
|
if( m_sProfileDir[pn].empty() )
|
|
|
|
|
return NULL;
|
|
|
|
|
else
|
|
|
|
|
return &m_Profile[pn];
|
2003-09-08 07:21:41 +00:00
|
|
|
}
|
2003-09-08 03:26:58 +00:00
|
|
|
|
2003-09-08 07:21:41 +00:00
|
|
|
bool Profile::LoadFromIni( CString sIniPath )
|
|
|
|
|
{
|
|
|
|
|
Init();
|
|
|
|
|
|
|
|
|
|
CStringArray asBits;
|
2003-10-29 20:46:37 +00:00
|
|
|
split( Dirname(sIniPath), SLASH, asBits, true );
|
2003-09-08 07:21:41 +00:00
|
|
|
CString sLastDir = asBits.back(); // this is a number name, e.g. "0000001"
|
|
|
|
|
|
|
|
|
|
// Fill in a default value in case ini doesn't have it.
|
2003-11-01 22:04:43 +00:00
|
|
|
m_sName = NEW_PROFILE_NAME;
|
2003-09-08 07:21:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// read ini
|
|
|
|
|
//
|
|
|
|
|
IniFile ini( sIniPath );
|
|
|
|
|
if( !ini.ReadFile() )
|
|
|
|
|
return false;
|
|
|
|
|
|
2003-12-08 04:02:43 +00:00
|
|
|
ini.GetValue( "Profile", "DisplayName", m_sName );
|
|
|
|
|
ini.GetValue( "Profile", "LastUsedHighScoreName", m_sLastUsedHighScoreName );
|
|
|
|
|
ini.GetValue( "Profile", "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers );
|
|
|
|
|
ini.GetValue( "Profile", "DefaultModifiers", m_sDefaultModifiers );
|
|
|
|
|
ini.GetValue( "Profile", "TotalPlays", m_iTotalPlays );
|
|
|
|
|
ini.GetValue( "Profile", "TotalPlaySeconds", m_iTotalPlaySeconds );
|
|
|
|
|
ini.GetValue( "Profile", "TotalGameplaySeconds", m_iTotalGameplaySeconds );
|
2003-12-08 04:39:29 +00:00
|
|
|
ini.GetValue( "Profile", "CurrentCombo", m_iCurrentCombo );
|
2003-09-08 07:21:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-11-01 19:36:52 +00:00
|
|
|
bool Profile::SaveToIni( CString sIniPath )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
|
|
|
|
IniFile ini( sIniPath );
|
2003-12-08 04:02:43 +00:00
|
|
|
ini.SetValue( "Profile", "DisplayName", m_sName );
|
|
|
|
|
ini.SetValue( "Profile", "LastUsedHighScoreName", m_sLastUsedHighScoreName );
|
|
|
|
|
ini.SetValue( "Profile", "UsingProfileDefaultModifiers", m_bUsingProfileDefaultModifiers );
|
|
|
|
|
ini.SetValue( "Profile", "DefaultModifiers", m_sDefaultModifiers );
|
|
|
|
|
ini.SetValue( "Profile", "TotalPlays", m_iTotalPlays );
|
|
|
|
|
ini.SetValue( "Profile", "TotalPlaySeconds", m_iTotalPlaySeconds );
|
|
|
|
|
ini.SetValue( "Profile", "TotalGameplaySeconds", m_iTotalGameplaySeconds );
|
2003-12-08 04:39:29 +00:00
|
|
|
ini.SetValue( "Profile", "CurrentCombo", m_iCurrentCombo );
|
2003-09-08 03:26:58 +00:00
|
|
|
ini.WriteFile();
|
2003-09-08 07:21:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
bool ProfileManager::CreateLocalProfile( CString sName )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
2003-12-07 08:19:10 +00:00
|
|
|
ASSERT( !sName.empty() );
|
2003-11-01 22:04:43 +00:00
|
|
|
|
2003-09-08 07:21:41 +00:00
|
|
|
//
|
|
|
|
|
// Find a free directory name in the profiles directory
|
|
|
|
|
//
|
2003-11-01 19:36:52 +00:00
|
|
|
CString sProfileID, sProfileDir;
|
|
|
|
|
const int MAX_TRIES = 1000;
|
2003-12-07 08:19:10 +00:00
|
|
|
int i;
|
2003-11-01 23:43:22 +00:00
|
|
|
for( i=0; i<MAX_TRIES; i++ )
|
2003-09-08 07:21:41 +00:00
|
|
|
{
|
2003-11-01 19:36:52 +00:00
|
|
|
sProfileID = ssprintf("%08d",i);
|
2003-12-07 07:46:21 +00:00
|
|
|
sProfileDir = USER_PROFILES_DIR + sProfileID;
|
2003-11-01 19:36:52 +00:00
|
|
|
if( !DoesFileExist(sProfileDir) )
|
2003-09-08 07:21:41 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2003-11-01 19:36:52 +00:00
|
|
|
if( i == MAX_TRIES )
|
|
|
|
|
return false;
|
2003-11-01 22:04:43 +00:00
|
|
|
sProfileDir += SLASH;
|
2003-09-08 07:21:41 +00:00
|
|
|
|
|
|
|
|
Profile pro;
|
2003-11-01 19:36:52 +00:00
|
|
|
pro.m_sName = sName;
|
2003-12-07 04:16:10 +00:00
|
|
|
|
|
|
|
|
bool bResult;
|
2003-11-01 22:04:43 +00:00
|
|
|
bResult = pro.SaveToIni( sProfileDir + PROFILE_FILE );
|
|
|
|
|
if( !bResult )
|
|
|
|
|
return false;
|
2003-09-08 07:21:41 +00:00
|
|
|
|
|
|
|
|
FlushDirCache();
|
2003-11-01 19:36:52 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
bool ProfileManager::RenameLocalProfile( CString sProfileID, CString sNewName )
|
2003-11-01 19:36:52 +00:00
|
|
|
{
|
|
|
|
|
ASSERT( !sProfileID.empty() );
|
|
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
CString sProfileDir = USER_PROFILES_DIR + sProfileID;
|
2003-11-01 19:36:52 +00:00
|
|
|
CString sProfileFile = sProfileDir + SLASH PROFILE_FILE;
|
|
|
|
|
|
|
|
|
|
Profile pro;
|
|
|
|
|
bool bResult;
|
|
|
|
|
bResult = pro.LoadFromIni( sProfileFile );
|
|
|
|
|
if( !bResult )
|
|
|
|
|
return false;
|
|
|
|
|
pro.m_sName = sNewName;
|
|
|
|
|
bResult = pro.SaveToIni( sProfileFile );
|
|
|
|
|
if( !bResult )
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
2003-09-08 03:26:58 +00:00
|
|
|
}
|
2003-11-01 19:36:52 +00:00
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
bool ProfileManager::DeleteLocalProfile( CString sProfileID )
|
2003-11-01 19:36:52 +00:00
|
|
|
{
|
|
|
|
|
// delete all files in profile dir
|
2003-12-07 07:46:21 +00:00
|
|
|
CString sProfileDir = USER_PROFILES_DIR + sProfileID;
|
2003-11-01 19:36:52 +00:00
|
|
|
CStringArray asFilesToDelete;
|
|
|
|
|
GetDirListing( sProfileDir + SLASH "*", asFilesToDelete, false, true );
|
|
|
|
|
for( unsigned i=0; i<asFilesToDelete.size(); i++ )
|
|
|
|
|
remove( asFilesToDelete[i] );
|
|
|
|
|
|
|
|
|
|
// remove profile dir
|
|
|
|
|
// FIXME for non Win32 platforms
|
|
|
|
|
int ret = rmdir( sProfileDir );
|
|
|
|
|
FlushDirCache();
|
|
|
|
|
if( ret != 0 )
|
|
|
|
|
return false;
|
|
|
|
|
else
|
|
|
|
|
return true;
|
2003-11-01 23:43:22 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
void ProfileManager::SaveMachineScoresToDisk()
|
|
|
|
|
{
|
2003-12-08 06:41:30 +00:00
|
|
|
m_MachineProfile.SaveToIni( MACHINE_PROFILE_DIR PROFILE_FILE );
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
SaveCategoryScoresToDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
|
|
|
|
SaveSongScoresToDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
|
|
|
|
SaveCourseScoresToDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
|
|
|
|
SaveStatsWebPageToDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
2003-12-07 07:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define WARN_AND_RETURN { LOG->Warn("Error parsing file '%s' at %s:%d",fn.c_str(),__FILE__,__LINE__); return; }
|
|
|
|
|
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::ReadSongScoresFromDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + SONG_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::READ) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 08:19:10 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
int version;
|
|
|
|
|
if( !FileRead(f, version) )
|
|
|
|
|
WARN_AND_RETURN;
|
2003-12-07 07:46:21 +00:00
|
|
|
if( version != STEPS_SCORES_VERSION )
|
2003-12-07 07:09:13 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::ReadCategoryScoresFromDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + CATEGORY_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::READ) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 08:19:10 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
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++ )
|
|
|
|
|
{
|
2003-12-07 07:46:21 +00:00
|
|
|
m_CategoryDatas[mc][st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
2003-12-07 07:09:13 +00:00
|
|
|
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;
|
2003-12-07 07:46:21 +00:00
|
|
|
m_CategoryDatas[mc][st][rc].vHighScores[l].sName = sName;
|
|
|
|
|
m_CategoryDatas[mc][st][rc].vHighScores[l].iScore = iScore;
|
2003-12-07 07:09:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::ReadCourseScoresFromDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + COURSE_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::READ) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 08:19:10 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
int version;
|
|
|
|
|
if( !FileRead(f, version) )
|
|
|
|
|
WARN_AND_RETURN;
|
2003-12-07 07:46:21 +00:00
|
|
|
if( version != COURSE_SCORES_VERSION )
|
2003-12-07 07:09:13 +00:00
|
|
|
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
|
2003-12-08 10:27:45 +00:00
|
|
|
ReadCategoryScoresFromDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
|
|
|
|
ReadSongScoresFromDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
|
|
|
|
ReadCourseScoresFromDir( MACHINE_PROFILE_DIR, MEMORY_CARD_MACHINE );
|
2003-12-08 06:41:30 +00:00
|
|
|
|
|
|
|
|
if( !m_MachineProfile.LoadFromIni(MACHINE_PROFILE_DIR PROFILE_FILE) )
|
|
|
|
|
{
|
|
|
|
|
CreateProfile(MACHINE_PROFILE_DIR, "Machine");
|
|
|
|
|
m_MachineProfile.LoadFromIni(MACHINE_PROFILE_DIR PROFILE_FILE);
|
|
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ProfileManager::ReadSM300NoteScores()
|
|
|
|
|
{
|
2003-12-07 20:29:42 +00:00
|
|
|
if( !DoesFileExist(SM_300_STATISTICS_FILE) )
|
|
|
|
|
return;
|
|
|
|
|
|
2003-12-07 07:09:13 +00:00
|
|
|
IniFile ini;
|
|
|
|
|
ini.SetPath( SM_300_STATISTICS_FILE );
|
|
|
|
|
|
|
|
|
|
// 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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::SaveCategoryScoresToDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + CATEGORY_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 07:09:13 +00:00
|
|
|
LOG->Trace("SongManager::SaveCategoryRankingsToFile");
|
|
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::WRITE) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 07:09:13 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
FileWrite( f, CATEGORY_RANKING_VERSION );
|
|
|
|
|
|
|
|
|
|
for( int st=0; st<NUM_STEPS_TYPES; st++ )
|
|
|
|
|
{
|
|
|
|
|
for( int rc=0; rc<NUM_RANKING_CATEGORIES; rc++ )
|
|
|
|
|
{
|
2003-12-07 07:46:21 +00:00
|
|
|
m_CategoryDatas[mc][st][rc].vHighScores.resize(NUM_RANKING_LINES);
|
2003-12-07 07:09:13 +00:00
|
|
|
for( int l=0; l<NUM_RANKING_LINES; l++ )
|
|
|
|
|
{
|
|
|
|
|
// tricky: wipe out "name to fill in" markers
|
2003-12-07 07:46:21 +00:00
|
|
|
if( IsRankingToFillIn(m_CategoryDatas[mc][st][rc].vHighScores[l].sName) )
|
|
|
|
|
m_CategoryDatas[mc][st][rc].vHighScores[l].sName = "";
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
FileWrite( f, m_CategoryDatas[mc][st][rc].vHighScores[l].sName );
|
|
|
|
|
FileWrite( f, m_CategoryDatas[mc][st][rc].vHighScores[l].iScore );
|
2003-12-07 07:09:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::SaveCourseScoresToDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + COURSE_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
LOG->Trace("SongManager::SaveCourseScoresToFile");
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::WRITE) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 07:09:13 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
FileWrite( f, COURSE_SCORES_VERSION );
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
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 );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::SaveSongScoresToDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + SONG_SCORES_FILE;
|
|
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
LOG->Trace("SongManager::SaveSongScoresToFile %s", fn.c_str());
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-07 08:19:10 +00:00
|
|
|
RageFile f;
|
|
|
|
|
if( !f.Open(fn, RageFile::WRITE) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 07:09:13 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-07 07:46:21 +00:00
|
|
|
FileWrite( f, STEPS_SCORES_VERSION );
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
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 CString HTMLQuoteDoubleQuotes( CString str )
|
|
|
|
|
{
|
|
|
|
|
str.Replace( "\"", """ );
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
void ProfileManager::SaveStatsWebPageToDir( CString sDir, MemoryCard mc )
|
2003-12-07 07:09:13 +00:00
|
|
|
{
|
2003-12-08 10:27:45 +00:00
|
|
|
CString fn = sDir + STATS_HTML_FILE;
|
|
|
|
|
|
2003-12-08 06:41:30 +00:00
|
|
|
//
|
|
|
|
|
// Get Profile
|
|
|
|
|
//
|
|
|
|
|
Profile* pProfile;
|
|
|
|
|
if( mc == MEMORY_CARD_MACHINE )
|
|
|
|
|
pProfile = GetMachineProfile();
|
|
|
|
|
else
|
|
|
|
|
pProfile = GetProfile( (PlayerNumber)mc );
|
|
|
|
|
ASSERT(pProfile);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Open file
|
|
|
|
|
//
|
2003-12-07 07:09:13 +00:00
|
|
|
RageFile f;
|
2003-12-07 07:46:21 +00:00
|
|
|
if( !f.Open( fn, RageFile::WRITE ) )
|
2003-12-07 20:29:42 +00:00
|
|
|
{
|
|
|
|
|
LOG->Warn( "Couldn't open file '%s'", fn.c_str() );
|
2003-12-07 07:09:13 +00:00
|
|
|
return;
|
2003-12-07 20:29:42 +00:00
|
|
|
}
|
2003-12-07 07:09:13 +00:00
|
|
|
|
2003-12-08 06:41:30 +00:00
|
|
|
//
|
|
|
|
|
// Make local song list
|
|
|
|
|
//
|
|
|
|
|
vector<Song*> vpSongs = SONGMAN->GetAllSongs();
|
|
|
|
|
SortSongPointerArrayByGroupAndTitle( vpSongs );
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// print HTML headers
|
|
|
|
|
//
|
2003-12-07 07:09:13 +00:00
|
|
|
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) );
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "<link rel='stylesheet' type='text/css' href='style.css'>" );
|
2003-12-07 07:09:13 +00:00
|
|
|
f.PutLine( "</head>" );
|
|
|
|
|
f.PutLine( "<body>" );
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
#define PRINT_LINK(szName,szLink) f.Write( ssprintf("<p><a href='%s'>%s</a></p>\n",szLink,szName) )
|
|
|
|
|
#define PRINT_LINE_S(szName,sVal) f.Write( ssprintf("<p>%s = <b>%s</b></p>\n",szName,sVal.c_str()) )
|
|
|
|
|
#define PRINT_LINE_B(szName,bVal) f.Write( ssprintf("<p>%s = <b>%s</b></p>\n",szName,(bVal)?"yes":"no") )
|
|
|
|
|
#define PRINT_LINE_I(szName,iVal) f.Write( ssprintf("<p>%s = <b>%d</b></p>\n",szName,iVal) )
|
2003-12-08 06:41:30 +00:00
|
|
|
//
|
|
|
|
|
// Print table of contents
|
|
|
|
|
//
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "<h2><a name='Table of Contents'>Table of Contents</a></h2>\n" );
|
|
|
|
|
f.PutLine( "<div class='section1'>\n" );
|
|
|
|
|
f.PutLine( "<h3>Sections</h3>\n" );
|
|
|
|
|
PRINT_LINK( "My Statistics", "#My Statistics" );
|
|
|
|
|
PRINT_LINK( "Difficulty Table", "#Difficulty Table" );
|
2003-12-08 10:46:14 +00:00
|
|
|
PRINT_LINK( "Song/Steps List", "#Song/Steps List" );
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "</div>\n" );
|
|
|
|
|
|
|
|
|
|
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
//
|
2003-12-08 06:41:30 +00:00
|
|
|
// Print My Statistics
|
2003-12-07 07:09:13 +00:00
|
|
|
//
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "<h2><a name='My Statistics'>My Statistics</a> <a href='#Table of Contents'>(top)</a></h2>\n" );
|
|
|
|
|
f.PutLine( "<div class='section1'>\n" );
|
|
|
|
|
CString sName = pProfile->m_sLastUsedHighScoreName.empty() ?
|
|
|
|
|
pProfile->m_sName :
|
|
|
|
|
pProfile->m_sLastUsedHighScoreName;
|
|
|
|
|
f.PutLine( ssprintf("<h3>%s</h3>\n",sName.c_str()) );
|
|
|
|
|
PRINT_LINE_S( "LastUsedHighScoreName", pProfile->m_sLastUsedHighScoreName );
|
|
|
|
|
PRINT_LINE_B( "UsingProfileDefaultModifiers", pProfile->m_bUsingProfileDefaultModifiers );
|
|
|
|
|
PRINT_LINE_S( "DefaultModifiers", pProfile->m_sDefaultModifiers );
|
|
|
|
|
PRINT_LINE_I( "TotalPlays", pProfile->m_iTotalPlays );
|
|
|
|
|
PRINT_LINE_I( "TotalPlaySeconds", pProfile->m_iTotalPlaySeconds );
|
|
|
|
|
PRINT_LINE_I( "TotalGameplaySeconds", pProfile->m_iTotalGameplaySeconds );
|
|
|
|
|
PRINT_LINE_I( "CurrentCombo", pProfile->m_iCurrentCombo );
|
|
|
|
|
f.PutLine( "</div>\n" );
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Print Difficulty tables
|
|
|
|
|
//
|
|
|
|
|
f.PutLine( "<h2><a name='Difficulty Table'>Difficulty Table</a> <a href='#Table of Contents'>(top)</a></h2>\n" );
|
|
|
|
|
for( StepsType st=(StepsType)0; st<NUM_STEPS_TYPES; st=(StepsType)(st+1) )
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
// don't print this table if there are no songs that have this StepsType
|
|
|
|
|
bool bOneSongHasStepsForThisStepsType = false;
|
|
|
|
|
for( i=0; i<vpSongs.size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
Song* pSong = vpSongs[i];
|
|
|
|
|
vector<Steps*> vpSteps;
|
|
|
|
|
pSong->GetSteps( vpSteps, st, DIFFICULTY_INVALID, -1, -1, "", false );
|
|
|
|
|
if( !vpSteps.empty() )
|
|
|
|
|
{
|
|
|
|
|
bOneSongHasStepsForThisStepsType = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !bOneSongHasStepsForThisStepsType )
|
|
|
|
|
continue; // don't print this table
|
|
|
|
|
|
|
|
|
|
f.PutLine( "<div class='section1'>\n" );
|
|
|
|
|
f.PutLine( ssprintf("<h3>%s</h3>\n", GAMEMAN->NotesTypeToString(st).c_str()) );
|
|
|
|
|
f.PutLine( "<table border='1' cellpadding='2' cellspacing='0'>\n" );
|
|
|
|
|
|
|
|
|
|
// table header row
|
|
|
|
|
f.Write( "<tr><td> </td>" );
|
|
|
|
|
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>" );
|
|
|
|
|
|
|
|
|
|
// table body rows
|
|
|
|
|
for( i=0; i<vpSongs.size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
Song* pSong = vpSongs[i];
|
|
|
|
|
|
|
|
|
|
f.PutLine( "<tr>" );
|
|
|
|
|
|
|
|
|
|
f.Write( ssprintf("<td><a href='#%u'>%s</a></td>",
|
2003-12-08 10:46:14 +00:00
|
|
|
pSong, // use pointer value as the hash
|
2003-12-08 10:50:52 +00:00
|
|
|
pSong->GetFullDisplayTitle().c_str()) );
|
2003-12-08 10:27:45 +00:00
|
|
|
|
|
|
|
|
for( Difficulty dc=(Difficulty)0; dc<NUM_DIFFICULTIES; dc=(Difficulty)(dc+1) )
|
|
|
|
|
{
|
|
|
|
|
Steps* pSteps = pSong->GetStepsByDifficulty( st, dc, false );
|
|
|
|
|
if( pSteps )
|
2003-12-08 10:46:14 +00:00
|
|
|
f.PutLine( ssprintf("<td><p align='right'><a href='#%u'>%d</a></p></td>",
|
|
|
|
|
pSteps, // use pointer value as the hash
|
|
|
|
|
pSteps->GetMeter()) );
|
2003-12-08 10:27:45 +00:00
|
|
|
else
|
|
|
|
|
f.PutLine( "<td> </td>" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f.Write( "</tr>" );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f.PutLine( "</table>\n" );
|
|
|
|
|
f.PutLine( "</div>\n" );
|
|
|
|
|
}
|
|
|
|
|
|
2003-12-08 06:41:30 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Print song list
|
|
|
|
|
//
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "<h2><a name='Song/Steps List'>Song/Steps List</a> <a href='#Table of Contents'>(top)</a></h2>\n" );
|
2003-12-07 07:09:13 +00:00
|
|
|
for( unsigned i=0; i<vpSongs.size(); i++ )
|
|
|
|
|
{
|
|
|
|
|
Song* pSong = vpSongs[i];
|
2003-12-08 10:27:45 +00:00
|
|
|
vector<Steps*> vpSteps = pSong->GetAllSteps();
|
|
|
|
|
|
2003-12-07 07:09:13 +00:00
|
|
|
/* 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.) */
|
2003-12-08 06:41:30 +00:00
|
|
|
/* Don't print the song banner anyway since this is going on the memory card. -Chris */
|
2003-12-07 07:09:13 +00:00
|
|
|
//CString sImagePath = pSong->HasBanner() ? pSong->GetBannerPath() : (pSong->HasBackground() ? pSong->GetBackgroundPath() : "" );
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "<div class='section1'>\n" );
|
|
|
|
|
f.PutLine( ssprintf("<h3><a name='%u'>%s</a></h3>\n",
|
2003-12-08 10:46:14 +00:00
|
|
|
pSong, // use pointer value as the hash
|
2003-12-08 10:27:45 +00:00
|
|
|
pSong->GetFullDisplayTitle().c_str()) );
|
|
|
|
|
PRINT_LINE_S( "Artist", pSong->GetDisplayArtist() );
|
|
|
|
|
PRINT_LINE_S( "GroupName", pSong->m_sGroupName );
|
|
|
|
|
float fMinBPM, fMaxBPM;
|
|
|
|
|
pSong->GetDisplayBPM( fMinBPM, fMaxBPM );
|
|
|
|
|
CString sBPM = (fMinBPM==fMaxBPM) ? ssprintf("%.1f",fMinBPM) : ssprintf("%.1f - %.1f",fMinBPM,fMaxBPM);
|
|
|
|
|
PRINT_LINE_S( "BPM", sBPM );
|
|
|
|
|
PRINT_LINE_I( "NumTimesPlayed", pSong->GetNumTimesPlayed(mc) );
|
|
|
|
|
PRINT_LINE_S( "Credit", pSong->m_sCredit );
|
|
|
|
|
PRINT_LINE_S( "MusicLength", SecondsToTime(pSong->m_fMusicLengthSeconds) );
|
|
|
|
|
PRINT_LINE_B( "Lyrics", !pSong->m_sLyricsFile.empty() );
|
|
|
|
|
f.PutLine( "</div>\n" );
|
2003-12-08 06:41:30 +00:00
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Print Steps list
|
|
|
|
|
//
|
|
|
|
|
for( unsigned j=0; j<vpSteps.size(); j++ )
|
|
|
|
|
{
|
|
|
|
|
Steps* pSteps = vpSteps[j];
|
|
|
|
|
if( pSteps->IsAutogen() )
|
2003-12-08 10:27:45 +00:00
|
|
|
continue; // skip autogen
|
|
|
|
|
f.PutLine( "<div class='section2'>\n" );
|
2003-12-08 10:46:14 +00:00
|
|
|
f.PutLine( ssprintf("<h4><a name='%u'>%s - %s</a></h4>\n",
|
|
|
|
|
pSteps, // use pointer value as the hash
|
2003-12-08 10:27:45 +00:00
|
|
|
GAMEMAN->NotesTypeToString(pSteps->m_StepsType).c_str(),
|
|
|
|
|
DifficultyToString(pSteps->GetDifficulty()).c_str()) );
|
|
|
|
|
PRINT_LINE_I( "NumTimesPlayed", pSteps->m_MemCardDatas[mc].iNumTimesPlayed );
|
|
|
|
|
f.PutLine( "</div>\n" );
|
2003-12-08 06:41:30 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-07 07:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
2003-12-08 10:27:45 +00:00
|
|
|
f.PutLine( "</body>" );
|
|
|
|
|
f.PutLine( "</html>" );
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
//
|
2003-12-08 10:27:45 +00:00
|
|
|
// Copy CSS file from theme. If the copy fails, oh well...
|
|
|
|
|
//
|
|
|
|
|
CString sStyleFile = THEME->GetPathToO(STYLE_CSS_FILE);
|
|
|
|
|
CopyFile2( sStyleFile, sDir+STYLE_CSS_FILE );
|
2003-12-07 07:09:13 +00:00
|
|
|
|
|
|
|
|
}
|