Files
itgmania212121/stepmania/src/ProfileManager.cpp
T

798 lines
24 KiB
C++
Raw Normal View History

#include "global.h"
#include "ProfileManager.h"
#include "Profile.h"
#include "RageUtil.h"
#include "PrefsManager.h"
#include "RageLog.h"
2003-12-05 00:07:18 +00:00
#include "RageFile.h"
#include "RageFileManager.h"
#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"
#include "song.h"
2003-12-18 03:40:57 +00:00
#include "Steps.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"
#include "MemoryCardManager.h"
2004-02-09 08:10:01 +00:00
#include "XmlFile.h"
#include "StepsUtil.h"
#include "Style.h"
2005-07-01 05:06:00 +00:00
#include "HighScore.h"
2003-11-14 17:17:36 +00:00
ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our program
2004-01-07 02:56:47 +00:00
#define NEW_MEM_CARD_NAME ""
2003-12-10 09:15:40 +00:00
#define USER_PROFILES_DIR "Data/LocalProfiles/"
#define MACHINE_PROFILE_DIR "Data/MachineProfile/"
const CString LAST_GOOD_DIR = "LastGood/";
2005-07-05 23:13:49 +00:00
static ThemeMetric<CString> NEW_PROFILE_DEFAULT_NAME( "ProfileManager", "NewProfileDefaultName" );
2005-04-24 19:18:46 +00:00
// Directories to search for a profile if m_sMemoryCardProfileSubdir doesn't
// exist, separated by ";":
static Preference<CString> g_sMemoryCardProfileImportSubdirs( "MemoryCardProfileImportSubdirs", "" );
2005-04-24 19:18:46 +00:00
static CString LocalProfileIdToDir( const CString &sProfileID ) { return USER_PROFILES_DIR + sProfileID + "/"; }
static map<CString,Profile*> g_mapLocalProfileDirToProfile;
2005-04-24 19:18:46 +00:00
ProfileManager::ProfileManager()
{
m_pMachineProfile = new Profile;
FOREACH_PlayerNumber(pn)
m_pMemoryCardProfile[pn] = new Profile;
}
ProfileManager::~ProfileManager()
{
SAFE_DELETE( m_pMachineProfile );
FOREACH_PlayerNumber(pn)
SAFE_DELETE( m_pMemoryCardProfile[pn] );
}
2004-05-25 05:52:57 +00:00
void ProfileManager::Init()
{
FOREACH_PlayerNumber( p )
{
2004-05-25 05:52:57 +00:00
m_bWasLoadedFromMemoryCard[p] = false;
m_bLastLoadWasTamperedOrCorrupt[p] = false;
m_bLastLoadWasFromLastGood[p] = false;
}
2004-05-25 05:52:57 +00:00
LoadMachineProfile();
2005-07-05 23:13:49 +00:00
RefreshLocalProfilesFromDisk();
2005-07-05 23:13:49 +00:00
}
2003-09-08 07:21:41 +00:00
2005-07-01 05:06:00 +00:00
int ProfileManager::LoadProfile( PlayerNumber pn, CString sProfileDir, bool bIsMemCard )
{
LOG->Trace( "LoadingProfile P%d, %s, %d", pn+1, sProfileDir.c_str(), bIsMemCard );
2004-06-05 19:40:53 +00:00
2003-11-01 22:04:43 +00:00
ASSERT( !sProfileDir.empty() );
2003-12-10 09:26:05 +00:00
ASSERT( sProfileDir.Right(1) == "/" );
2003-11-01 22:04:43 +00:00
m_sProfileDir[pn] = sProfileDir;
2004-01-03 03:42:40 +00:00
m_bWasLoadedFromMemoryCard[pn] = bIsMemCard;
m_bLastLoadWasFromLastGood[pn] = false;
2003-11-01 19:36:52 +00:00
// Try to load the original, non-backup data.
Profile::LoadResult lr = GetProfile(pn)->LoadAllFromDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
CString sBackupDir = m_sProfileDir[pn] + LAST_GOOD_DIR;
// Save a backup of the non-backup profile now that we've loaded it and know
// it's good. This should be reasonably fast because we're only saving Stats.xml
// and signatures - not all of the files in the Profile.
if( lr == Profile::success )
{
2004-10-06 08:54:37 +00:00
Profile::BackupToDir( m_sProfileDir[pn], sBackupDir );
}
m_bLastLoadWasTamperedOrCorrupt[pn] = lr == Profile::failed_tampered;
2004-06-05 19:40:53 +00:00
//
// Try to load from the backup if the original data fails to load
//
if( lr == Profile::failed_tampered )
{
lr = GetProfile(pn)->LoadAllFromDir( sBackupDir, PREFSMAN->m_bSignProfileData );
m_bLastLoadWasFromLastGood[pn] = lr == Profile::success;
2005-05-03 04:03:11 +00:00
/* If the LastGood profile doesn't exist at all, and the actual profile was failed_tampered,
* then the error should be failed_tampered and not failed_no_profile. */
if( lr == Profile::failed_no_profile )
{
LOG->Trace( "Profile was corrupt and LastGood for %s doesn't exist; error is Profile::failed_tampered",
sProfileDir.c_str() );
lr = Profile::failed_tampered;
}
}
2003-11-01 22:04:43 +00:00
LOG->Trace( "Done loading profile - result %d", lr );
2003-11-01 22:04:43 +00:00
2005-04-24 19:18:46 +00:00
return lr;
2003-11-01 22:04:43 +00:00
}
2004-08-09 05:01:24 +00:00
bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn )
2003-11-01 22:04:43 +00:00
{
2005-05-16 09:36:32 +00:00
CString sProfileID = PREFSMAN->GetDefaultLocalProfileID(pn);
2003-11-01 22:04:43 +00:00
if( sProfileID.empty() )
{
m_sProfileDir[pn] = "";
return false;
}
m_sProfileDir[pn] = LocalProfileIdToDir( sProfileID );
m_bWasLoadedFromMemoryCard[pn] = false;
m_bLastLoadWasFromLastGood[pn] = false;
map<CString,Profile*>::iterator iter = g_mapLocalProfileDirToProfile.find( m_sProfileDir[pn] );
if( iter == g_mapLocalProfileDirToProfile.end() )
{
m_sProfileDir[pn] = "";
return false;
}
2003-11-01 22:04:43 +00:00
return true;
2003-11-01 22:04:43 +00:00
}
void ProfileManager::GetMemoryCardProfileDirectoriesToTry( vector<CString> &asDirsToTry ) const
2005-04-24 19:39:54 +00:00
{
/* Try to load the preferred profile. */
asDirsToTry.push_back( PREFSMAN->m_sMemoryCardProfileSubdir );
/* If that failed, try loading from all fallback directories. */
split( g_sMemoryCardProfileImportSubdirs, ";", asDirsToTry, true );
}
2004-08-09 05:01:24 +00:00
bool ProfileManager::LoadProfileFromMemoryCard( PlayerNumber pn )
2003-11-01 22:04:43 +00:00
{
2004-01-03 03:42:40 +00:00
UnloadProfile( pn );
2004-08-09 05:01:24 +00:00
// mount slot
2005-04-22 04:28:46 +00:00
if( MEMCARDMAN->GetCardState(pn) != MEMORY_CARD_STATE_READY )
return false;
2005-04-24 19:18:46 +00:00
vector<CString> asDirsToTry;
2005-04-24 19:39:54 +00:00
GetMemoryCardProfileDirectoriesToTry( asDirsToTry );
2005-04-24 19:18:46 +00:00
2005-04-24 19:39:54 +00:00
int iLoadedFrom = -1;
2005-04-24 19:18:46 +00:00
for( unsigned i = 0; i < asDirsToTry.size(); ++i )
{
const CString &sSubdir = asDirsToTry[i];
CString sDir = MEM_CARD_MOUNT_POINT[pn] + sSubdir + "/";
2005-05-03 04:03:11 +00:00
/* If the load fails with Profile::failed_no_profile, keep searching. However,
2005-04-24 19:18:46 +00:00
* if it fails with failed_tampered, data existed but couldn't be loaded;
* we don't want to mess with it, since it's confusing and may wipe out
* recoverable backup data. The only time we really want to import data
* is on the very first use, when the new profile doesn't exist at all,
* but we also want to import scores in the case where the player created
* a directory for edits before playing, so keep searching if the directory
* exists with exists with no scores. */
2005-07-01 05:06:00 +00:00
Profile::LoadResult res = (Profile::LoadResult) LoadProfile( pn, sDir, true );
2005-04-24 19:39:54 +00:00
if( res == Profile::success )
2005-05-03 04:03:11 +00:00
{
2005-04-24 19:39:54 +00:00
iLoadedFrom = i;
2005-05-03 04:03:11 +00:00
break;
}
if( res == Profile::failed_tampered )
2005-04-24 19:18:46 +00:00
break;
}
2004-01-03 03:42:40 +00:00
2005-04-24 19:39:54 +00:00
/* Store the directory we imported from, for display purposes. */
if( iLoadedFrom > 0 )
{
m_sProfileDirImportedFrom[pn] = asDirsToTry[iLoadedFrom];
}
2005-04-24 19:18:46 +00:00
/* If we imported a profile fallback directory, change the memory card
* directory back to the preferred directory: never write over imported
* scores. */
2005-04-28 08:27:40 +00:00
m_sProfileDir[pn] = MEM_CARD_MOUNT_POINT[pn] + (CString)PREFSMAN->m_sMemoryCardProfileSubdir + "/";
/* Load edits from all fallback directories, newest first. */
for( unsigned i = 0; i < asDirsToTry.size(); ++i )
{
const CString &sSubdir = asDirsToTry[i];
CString sDir = MEM_CARD_MOUNT_POINT[pn] + sSubdir + "/";
SONGMAN->LoadAllFromProfileDir( sDir, (ProfileSlot) pn );
}
2005-04-22 04:28:46 +00:00
return true; // If a card is inserted, we want to use the memory card to save - even if the Profile load failed.
2003-11-01 22:04:43 +00:00
}
2003-11-09 21:39:54 +00:00
2004-08-09 05:01:24 +00:00
bool ProfileManager::LoadFirstAvailableProfile( PlayerNumber pn )
2004-02-22 03:44:04 +00:00
{
2004-08-09 05:01:24 +00:00
if( LoadProfileFromMemoryCard(pn) )
2004-02-22 03:44:04 +00:00
return true;
2004-08-09 05:01:24 +00:00
if( LoadLocalProfileFromMachine(pn) )
2004-02-22 03:44:04 +00:00
return true;
return false;
}
2003-11-01 22:04:43 +00:00
bool ProfileManager::FastLoadProfileNameFromMemoryCard( CString sRootDir, CString &sName ) const
{
vector<CString> asDirsToTry;
GetMemoryCardProfileDirectoriesToTry( asDirsToTry );
for( unsigned i = 0; i < asDirsToTry.size(); ++i )
{
const CString &sSubdir = asDirsToTry[i];
CString sDir = sRootDir + sSubdir + "/";
Profile profile;
Profile::LoadResult res = profile.LoadEditableDataFromDir( sDir );
if( res == Profile::success )
{
sName = profile.GetDisplayNameOrHighScoreName();
return true;
}
else if( res != Profile::failed_no_profile )
break;
}
return false;
}
2004-07-20 01:31:23 +00:00
void ProfileManager::SaveAllProfiles() const
{
this->SaveMachineProfile();
FOREACH_HumanPlayer( pn )
{
if( !IsPersistentProfile(pn) )
2004-07-20 01:31:23 +00:00
continue;
this->SaveProfile( pn );
}
}
2004-02-22 02:01:40 +00:00
bool ProfileManager::SaveProfile( PlayerNumber pn ) const
{
if( m_sProfileDir[pn].empty() )
2003-11-01 19:36:52 +00:00
return false;
bool b = GetProfile(pn)->SaveAllToDir( m_sProfileDir[pn], PREFSMAN->m_bSignProfileData );
return b;
2003-11-01 19:36:52 +00:00
}
2003-11-01 19:36:52 +00:00
void ProfileManager::UnloadProfile( PlayerNumber pn )
{
m_sProfileDir[pn] = "";
2005-04-24 19:39:54 +00:00
m_sProfileDirImportedFrom[pn] = "";
2004-01-03 03:42:40 +00:00
m_bWasLoadedFromMemoryCard[pn] = false;
m_bLastLoadWasTamperedOrCorrupt[pn] = false;
m_bLastLoadWasFromLastGood[pn] = false;
m_pMemoryCardProfile[pn]->InitAll();
2005-04-25 00:25:04 +00:00
SONGMAN->FreeAllLoadedFromProfile( (ProfileSlot) pn );
2003-09-08 07:21:41 +00:00
}
2004-02-10 10:06:34 +00:00
const Profile* ProfileManager::GetProfile( PlayerNumber pn ) const
2003-09-08 07:21:41 +00:00
{
ASSERT( pn >= 0 && pn < NUM_PLAYERS );
if( m_sProfileDir[pn].empty() || ProfileWasLoadedFromMemoryCard(pn) )
{
return m_pMemoryCardProfile[pn];
}
else
{
map<CString,Profile*>::iterator iter = g_mapLocalProfileDirToProfile.find( m_sProfileDir[pn] );
ASSERT( iter != g_mapLocalProfileDirToProfile.end() );
return iter->second;
}
2003-09-08 07:21:41 +00:00
}
2004-02-22 02:01:40 +00:00
CString ProfileManager::GetPlayerName( PlayerNumber pn ) const
2003-12-17 09:42:31 +00:00
{
2004-02-22 02:01:40 +00:00
const Profile *prof = GetProfile( pn );
return prof ? prof->GetDisplayNameOrHighScoreName() : CString();
2003-12-17 09:42:31 +00:00
}
2003-09-08 07:21:41 +00:00
void ProfileManager::RefreshLocalProfilesFromDisk()
{
FOREACHM( CString, Profile*, g_mapLocalProfileDirToProfile, iter )
SAFE_DELETE( iter->second );
g_mapLocalProfileDirToProfile.clear();
vector<CString> vsProfileID;
GetDirListing( USER_PROFILES_DIR "*", vsProfileID, true, false );
FOREACH_CONST( CString, vsProfileID, s )
{
Profile *&pProfile = g_mapLocalProfileDirToProfile[*s];
pProfile = new Profile;
CString sProfileDir = LocalProfileIdToDir( *s );
LOG->Trace(" '%s'", pProfile->GetDisplayNameOrHighScoreName().c_str());
pProfile->LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData );
}
}
Profile &ProfileManager::GetLocalProfile( const CString &sProfileID )
{
map<CString,Profile*>::iterator iter = g_mapLocalProfileDirToProfile.find( sProfileID );
if( iter == g_mapLocalProfileDirToProfile.end() )
{
LOG->Warn( "ProfileID '%s' doesn't exist", sProfileID.c_str() );
static Profile s_pro;
s_pro.InitAll();
return s_pro;
}
return *iter->second;
}
2005-07-16 05:28:34 +00:00
bool ProfileManager::CreateLocalProfile( CString sName, CString &sProfileIDOut )
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;
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);
sProfileDir = LocalProfileIdToDir( 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-09-08 07:21:41 +00:00
bool bResult = Profile::CreateNewProfile( sProfileDir, sName );
2005-07-16 05:28:34 +00:00
if( bResult )
sProfileIDOut = sProfileID;
else
sProfileIDOut = "";
RefreshLocalProfilesFromDisk();
return bResult;
2003-11-01 19:36:52 +00:00
}
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() );
CString sProfileDir = LocalProfileIdToDir( sProfileID );
2003-11-01 19:36:52 +00:00
Profile pro;
Profile::LoadResult lr;
lr = pro.LoadAllFromDir( sProfileDir, PREFSMAN->m_bSignProfileData );
if( lr != Profile::success )
2003-11-01 19:36:52 +00:00
return false;
2004-02-19 03:19:41 +00:00
pro.m_sDisplayName = sNewName;
2003-11-01 19:36:52 +00:00
bool bResult = pro.SaveAllToDir( sProfileDir, PREFSMAN->m_bSignProfileData );
RefreshLocalProfilesFromDisk();
return bResult;
}
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
CString sProfileDir = LocalProfileIdToDir( sProfileID );
2003-11-01 19:36:52 +00:00
CStringArray asFilesToDelete;
GetDirListing( sProfileDir + "*", asFilesToDelete, false, true );
2003-11-01 19:36:52 +00:00
for( unsigned i=0; i<asFilesToDelete.size(); i++ )
2003-12-16 07:59:32 +00:00
FILEMAN->Remove( asFilesToDelete[i] );
2003-11-01 19:36:52 +00:00
// delete edits
GetDirListing( sProfileDir + EDITS_SUBDIR + "*", asFilesToDelete, false, true );
for( unsigned i=0; i<asFilesToDelete.size(); i++ )
FILEMAN->Remove( asFilesToDelete[i] );
2005-01-25 06:21:39 +00:00
// delete lastgood
GetDirListing( sProfileDir + LASTGOOD_SUBDIR + "*", asFilesToDelete, false, true );
2005-01-25 06:21:39 +00:00
for( unsigned i=0; i<asFilesToDelete.size(); i++ )
FILEMAN->Remove( asFilesToDelete[i] );
// remove edits dir
FILEMAN->Remove( sProfileDir + "/" + EDITS_SUBDIR );
2005-01-25 06:21:39 +00:00
// remove lastgood dir
FILEMAN->Remove( sProfileDir + "/" + LASTGOOD_SUBDIR );
2003-11-01 19:36:52 +00:00
// remove profile dir
bool bResult = FILEMAN->Remove( sProfileDir );
RefreshLocalProfilesFromDisk();
return bResult;
}
2004-07-20 01:31:23 +00:00
void ProfileManager::SaveMachineProfile() const
{
2004-02-16 05:35:06 +00:00
// If the machine name has changed, make sure we use the new name.
// It's important that this name be applied before the Player profiles
// are saved, so that the Player's profiles show the right machine name.
const_cast<ProfileManager *> (this)->m_pMachineProfile->m_sDisplayName = PREFSMAN->m_sMachineName;
2004-02-16 05:35:06 +00:00
m_pMachineProfile->SaveAllToDir( MACHINE_PROFILE_DIR, false ); /* don't sign machine profiles */
}
2004-02-16 05:35:06 +00:00
void ProfileManager::LoadMachineProfile()
{
Profile::LoadResult lr = m_pMachineProfile->LoadAllFromDir(MACHINE_PROFILE_DIR, false);
if( lr == Profile::failed_no_profile )
2003-12-08 06:41:30 +00:00
{
Profile::CreateNewProfile(MACHINE_PROFILE_DIR, "Machine");
m_pMachineProfile->LoadAllFromDir( MACHINE_PROFILE_DIR, false );
2003-12-08 06:41:30 +00:00
}
2004-02-16 05:35:06 +00:00
// If the machine name has changed, make sure we use the new name
m_pMachineProfile->m_sDisplayName = PREFSMAN->m_sMachineName;
2005-04-28 06:17:17 +00:00
SONGMAN->FreeAllLoadedFromProfile( PROFILE_SLOT_MACHINE );
SONGMAN->LoadAllFromProfileDir( MACHINE_PROFILE_DIR, PROFILE_SLOT_MACHINE );
}
2004-02-22 02:01:40 +00:00
bool ProfileManager::ProfileWasLoadedFromMemoryCard( PlayerNumber pn ) const
2004-01-03 03:42:40 +00:00
{
return !m_sProfileDir[pn].empty() && m_bWasLoadedFromMemoryCard[pn];
2004-01-03 03:42:40 +00:00
}
2004-02-08 01:05:53 +00:00
bool ProfileManager::LastLoadWasTamperedOrCorrupt( PlayerNumber pn ) const
{
return !m_sProfileDir[pn].empty() && m_bLastLoadWasTamperedOrCorrupt[pn];
}
bool ProfileManager::LastLoadWasFromLastGood( PlayerNumber pn ) const
{
return !m_sProfileDir[pn].empty() && m_bLastLoadWasFromLastGood[pn];
}
2004-02-22 02:01:40 +00:00
CString ProfileManager::GetProfileDir( ProfileSlot slot ) const
2004-02-08 01:05:53 +00:00
{
switch( slot )
{
case PROFILE_SLOT_PLAYER_1:
case PROFILE_SLOT_PLAYER_2:
return m_sProfileDir[slot];
case PROFILE_SLOT_MACHINE:
return MACHINE_PROFILE_DIR;
default:
ASSERT(0);
}
}
2005-04-24 19:39:54 +00:00
CString ProfileManager::GetProfileDirImportedFrom( ProfileSlot slot ) const
{
switch( slot )
{
case PROFILE_SLOT_PLAYER_1:
case PROFILE_SLOT_PLAYER_2:
return m_sProfileDirImportedFrom[slot];
case PROFILE_SLOT_MACHINE:
return "";
default:
ASSERT(0);
}
}
2004-02-10 10:06:34 +00:00
const Profile* ProfileManager::GetProfile( ProfileSlot slot ) const
2004-02-09 06:26:13 +00:00
{
switch( slot )
{
case PROFILE_SLOT_PLAYER_1:
case PROFILE_SLOT_PLAYER_2:
return GetProfile( (PlayerNumber)slot );
2004-02-09 06:26:13 +00:00
case PROFILE_SLOT_MACHINE:
return m_pMachineProfile;
2004-02-09 06:26:13 +00:00
default:
ASSERT(0);
}
}
//
// General
//
void ProfileManager::IncrementToastiesCount( PlayerNumber pn )
{
if( PROFILEMAN->IsPersistentProfile(pn) )
++PROFILEMAN->GetProfile(pn)->m_iNumToasties;
++PROFILEMAN->GetMachineProfile()->m_iNumToasties;
}
2004-02-09 06:26:13 +00:00
2005-04-25 11:42:19 +00:00
void ProfileManager::AddStepTotals( PlayerNumber pn, int iNumTapsAndHolds, int iNumJumps, int iNumHolds, int iNumRolls, int iNumMines, int iNumHands, float fCaloriesBurned )
2004-02-22 19:51:46 +00:00
{
if( PROFILEMAN->IsPersistentProfile(pn) )
2005-04-25 11:42:19 +00:00
PROFILEMAN->GetProfile(pn)->AddStepTotals( iNumTapsAndHolds, iNumJumps, iNumHolds, iNumRolls, iNumMines, iNumHands, fCaloriesBurned );
PROFILEMAN->GetMachineProfile()->AddStepTotals( iNumTapsAndHolds, iNumJumps, iNumHolds, iNumRolls, iNumMines, iNumHands, fCaloriesBurned );
2004-02-22 19:51:46 +00:00
}
2004-02-09 06:26:13 +00:00
//
// Song stats
//
2004-02-10 10:06:34 +00:00
int ProfileManager::GetSongNumTimesPlayed( const Song* pSong, ProfileSlot slot ) const
2004-02-09 06:26:13 +00:00
{
2004-02-10 09:42:01 +00:00
return GetProfile(slot)->GetSongNumTimesPlayed( pSong );
2004-02-09 06:26:13 +00:00
}
2005-07-01 05:06:00 +00:00
void ProfileManager::AddStepsScore( const Song* pSong, const Steps* pSteps, PlayerNumber pn, const HighScore &hs_, int &iPersonalIndexOut, int &iMachineIndexOut )
2004-02-09 06:26:13 +00:00
{
2005-07-01 05:06:00 +00:00
HighScore hs = hs_;
2004-06-26 21:38:38 +00:00
hs.fPercentDP = max( 0, hs.fPercentDP ); // bump up negative scores
iPersonalIndexOut = -1;
iMachineIndexOut = -1;
// In event mode, set the score's name immediately to the Profile's last
// used name. If no profile last used name exists, use "EVNT".
if( GAMESTATE->IsEventMode() )
{
Profile* pProfile = PROFILEMAN->GetProfile(pn);
if( pProfile && !pProfile->m_sLastUsedHighScoreName.empty() )
hs.sName = pProfile->m_sLastUsedHighScoreName;
else
hs.sName = "EVNT";
}
else
{
hs.sName = RANKING_TO_FILL_IN_MARKER[pn];
}
//
// save high score
//
if( PROFILEMAN->IsPersistentProfile(pn) )
PROFILEMAN->GetProfile(pn)->AddStepsHighScore( pSong, pSteps, hs, iPersonalIndexOut );
if( hs.fPercentDP >= PREFSMAN->m_fMinPercentageForMachineSongHighScore )
2004-04-22 22:01:38 +00:00
{
// don't leave machine high scores for edits loaded from the player's card
if( !pSteps->IsAPlayerEdit() )
2004-04-23 02:19:45 +00:00
PROFILEMAN->GetMachineProfile()->AddStepsHighScore( pSong, pSteps, hs, iMachineIndexOut );
2004-04-22 22:01:38 +00:00
}
//
// save recent score
//
if( PROFILEMAN->IsPersistentProfile(pn) )
2004-05-08 10:12:10 +00:00
PROFILEMAN->GetProfile(pn)->AddStepsRecentScore( pSong, pSteps, hs );
PROFILEMAN->GetMachineProfile()->AddStepsRecentScore( pSong, pSteps, hs );
2004-02-09 06:26:13 +00:00
}
void ProfileManager::IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps, PlayerNumber pn )
2004-02-09 06:26:13 +00:00
{
if( PROFILEMAN->IsPersistentProfile(pn) )
PROFILEMAN->GetProfile(pn)->IncrementStepsPlayCount( pSong, pSteps );
PROFILEMAN->GetMachineProfile()->IncrementStepsPlayCount( pSong, pSteps );
2004-02-09 06:26:13 +00:00
}
2005-07-01 05:06:00 +00:00
void ProfileManager::GetHighScoreForDifficulty( const Song *s, const Style *st, ProfileSlot slot, Difficulty dc, HighScore &hsOut ) const
2004-02-09 06:26:13 +00:00
{
// return max grade of notes in difficulty class
vector<Steps*> aNotes;
s->GetSteps( aNotes, st->m_StepsType );
StepsUtil::SortNotesArrayByDifficulty( aNotes );
2004-02-09 06:26:13 +00:00
2004-02-22 02:01:40 +00:00
const Steps* pSteps = s->GetStepsByDifficulty( st->m_StepsType, dc );
2004-02-09 06:26:13 +00:00
if( pSteps && PROFILEMAN->IsPersistentProfile(slot) )
2005-07-01 05:06:00 +00:00
hsOut = PROFILEMAN->GetProfile(slot)->GetStepsHighScoreList(s,pSteps).GetTopScore();
2004-02-09 06:26:13 +00:00
else
2005-07-01 05:06:00 +00:00
hsOut = HighScore();
2004-02-09 06:26:13 +00:00
}
//
// Course stats
//
2005-07-01 05:06:00 +00:00
void ProfileManager::AddCourseScore( const Course* pCourse, const Trail* pTrail, PlayerNumber pn, const HighScore &hs_, int &iPersonalIndexOut, int &iMachineIndexOut )
2004-02-09 06:26:13 +00:00
{
2005-07-01 05:06:00 +00:00
HighScore hs = hs_;
2004-06-26 21:38:38 +00:00
hs.fPercentDP = max( 0, hs.fPercentDP ); // bump up negative scores
iPersonalIndexOut = -1;
iMachineIndexOut = -1;
// In event mode, set the score's name immediately to the Profile's last
// used name. If no profile last used name exists, use "EVNT".
if( GAMESTATE->IsEventMode() )
{
Profile* pProfile = PROFILEMAN->GetProfile(pn);
if( pProfile && !pProfile->m_sLastUsedHighScoreName.empty() )
hs.sName = pProfile->m_sLastUsedHighScoreName;
else
hs.sName = "EVNT";
}
else
2004-04-22 22:01:38 +00:00
{
hs.sName = RANKING_TO_FILL_IN_MARKER[pn];
}
//
// save high score
//
if( PROFILEMAN->IsPersistentProfile(pn) )
PROFILEMAN->GetProfile(pn)->AddCourseHighScore( pCourse, pTrail, hs, iPersonalIndexOut );
if( hs.fPercentDP >= PREFSMAN->m_fMinPercentageForMachineCourseHighScore )
2004-05-23 09:17:10 +00:00
PROFILEMAN->GetMachineProfile()->AddCourseHighScore( pCourse, pTrail, hs, iMachineIndexOut );
2004-04-22 22:01:38 +00:00
//
// save recent score
//
if( PROFILEMAN->IsPersistentProfile(pn) )
2004-05-23 09:17:10 +00:00
PROFILEMAN->GetProfile(pn)->AddCourseRecentScore( pCourse, pTrail, hs );
PROFILEMAN->GetMachineProfile()->AddCourseRecentScore( pCourse, pTrail, hs );
2004-02-09 06:26:13 +00:00
}
2004-05-23 09:17:10 +00:00
void ProfileManager::IncrementCoursePlayCount( const Course* pCourse, const Trail* pTrail, PlayerNumber pn )
2004-02-09 06:26:13 +00:00
{
if( PROFILEMAN->IsPersistentProfile(pn) )
2004-05-23 09:17:10 +00:00
PROFILEMAN->GetProfile(pn)->IncrementCoursePlayCount( pCourse, pTrail );
PROFILEMAN->GetMachineProfile()->IncrementCoursePlayCount( pCourse, pTrail );
2004-02-09 06:26:13 +00:00
}
//
// Category stats
//
2005-07-01 05:06:00 +00:00
void ProfileManager::AddCategoryScore( StepsType st, RankingCategory rc, PlayerNumber pn, const HighScore &hs_, int &iPersonalIndexOut, int &iMachineIndexOut )
2004-02-09 06:26:13 +00:00
{
2005-07-01 05:06:00 +00:00
HighScore hs = hs_;
hs.sName = RANKING_TO_FILL_IN_MARKER[pn];
if( PROFILEMAN->IsPersistentProfile(pn) )
PROFILEMAN->GetProfile(pn)->AddCategoryHighScore( st, rc, hs, iPersonalIndexOut );
if( hs.fPercentDP > PREFSMAN->m_fMinPercentageForMachineSongHighScore )
2004-04-22 22:01:38 +00:00
PROFILEMAN->GetMachineProfile()->AddCategoryHighScore( st, rc, hs, iMachineIndexOut );
2004-02-09 06:26:13 +00:00
}
void ProfileManager::IncrementCategoryPlayCount( StepsType st, RankingCategory rc, PlayerNumber pn )
{
if( PROFILEMAN->IsPersistentProfile(pn) )
2004-02-09 06:26:13 +00:00
PROFILEMAN->GetProfile(pn)->IncrementCategoryPlayCount( st, rc );
PROFILEMAN->GetMachineProfile()->IncrementCategoryPlayCount( st, rc );
}
bool ProfileManager::IsPersistentProfile( ProfileSlot slot ) const
{
switch( slot )
{
case PROFILE_SLOT_PLAYER_1:
case PROFILE_SLOT_PLAYER_2:
return GAMESTATE->IsHumanPlayer((PlayerNumber)slot) && !m_sProfileDir[slot].empty();
case PROFILE_SLOT_MACHINE:
return true;
default:
ASSERT(0);
return false;
}
}
CString ProfileManager::GetNewLocalProfileDefaultName() const
2005-07-05 23:13:49 +00:00
{
vector<CString> vsUsedNames;
PROFILEMAN->GetLocalProfileDisplayNames( vsUsedNames );
2005-07-05 23:13:49 +00:00
CString sPotentialName;
for( int i=1; i<1000; i++ )
{
sPotentialName = ssprintf( "%s%04d", NEW_PROFILE_DEFAULT_NAME.GetValue().c_str(), i );
bool bNameIsUsed = find( vsUsedNames.begin(), vsUsedNames.end(), sPotentialName ) != vsUsedNames.end();
2005-07-05 23:13:49 +00:00
if( !bNameIsUsed )
return sPotentialName;
}
return sPotentialName;
}
void ProfileManager::GetLocalProfileIDs( vector<CString> &vsProfileIDsOut ) const
{
vsProfileIDsOut.clear();
FOREACHM_CONST( CString, Profile*, g_mapLocalProfileDirToProfile, iter )
vsProfileIDsOut.push_back( iter->first );
}
void ProfileManager::GetLocalProfileDisplayNames( vector<CString> &vsProfileDisplayNamesOut ) const
{
vsProfileDisplayNamesOut.clear();
FOREACHM_CONST( CString, Profile*, g_mapLocalProfileDirToProfile, iter )
vsProfileDisplayNamesOut.push_back( iter->second->m_sDisplayName );
}
bool ProfileManager::ValidateLocalProfileName( const CString &sAnswer, CString &sErrorOut )
{
CString sCurrentProfileOldName = PROFILEMAN->GetLocalProfile( GAMESTATE->m_sLastSelectedProfileID ).m_sDisplayName;
vector<CString> vsProfileNames;
PROFILEMAN->GetLocalProfileDisplayNames( vsProfileNames );
bool bAlreadyAProfileWithThisName = find( vsProfileNames.begin(), vsProfileNames.end(), sAnswer ) != vsProfileNames.end();
if( sAnswer == "" )
{
sErrorOut = "Profile name cannot be blank.";
return false;
}
else if( sAnswer == sCurrentProfileOldName )
{
return true;
}
else if( bAlreadyAProfileWithThisName )
{
sErrorOut = "There is already another profile with this name. Please choose a different name.";
return false;
}
return true;
}
// lua start
#include "LuaBinding.h"
2005-06-20 05:02:03 +00:00
class LunaProfileManager: public Luna<ProfileManager>
{
public:
LunaProfileManager() { LUA->Register( Register ); }
static int IsPersistentProfile( T* p, lua_State *L ) { lua_pushboolean(L, p->IsPersistentProfile((PlayerNumber)IArg(1)) ); return 1; }
static int GetProfile( T* p, lua_State *L ) { PlayerNumber pn = (PlayerNumber)IArg(1); Profile* pP = p->GetProfile(pn); ASSERT(pP); pP->PushSelf(L); return 1; }
static int GetMachineProfile( T* p, lua_State *L ) { p->GetMachineProfile()->PushSelf(L); return 1; }
2005-05-15 23:53:54 +00:00
static int SaveMachineProfile( T* p, lua_State *L ) { p->SaveMachineProfile(); return 1; }
static int GetLocalProfile( T* p, lua_State *L ) { Profile &pro = p->GetLocalProfile(SArg(1)); pro.PushSelf(L); return 1; }
static void Register(lua_State *L)
{
ADD_METHOD( IsPersistentProfile )
2005-02-15 23:13:18 +00:00
ADD_METHOD( GetProfile )
2005-02-16 02:48:50 +00:00
ADD_METHOD( GetMachineProfile )
2005-05-15 23:53:54 +00:00
ADD_METHOD( SaveMachineProfile )
ADD_METHOD( GetLocalProfile )
Luna<T>::Register( L );
// Add global singleton if constructed already. If it's not constructed yet,
2005-02-16 00:16:14 +00:00
// then we'll register it later when we reinit Lua just before
// initializing the display.
if( PROFILEMAN )
{
lua_pushstring(L, "PROFILEMAN");
PROFILEMAN->PushSelf( L );
lua_settable(L, LUA_GLOBALSINDEX);
}
}
};
LUA_REGISTER_CLASS( ProfileManager )
// lua end
2004-06-08 01:24:17 +00:00
/*
* (c) 2003-2004 Chris Danford
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/