Files
itgmania212121/stepmania/src/Profile.cpp
T

2167 lines
63 KiB
C++
Raw Normal View History

2004-02-08 18:25:30 +00:00
#include "global.h"
2004-02-09 06:26:13 +00:00
#include "Profile.h"
2004-02-08 18:25:30 +00:00
#include "RageUtil.h"
2004-02-09 06:26:13 +00:00
#include "PrefsManager.h"
2004-02-10 09:42:01 +00:00
#include "XmlFile.h"
#include "IniFile.h"
#include "GameManager.h"
#include "RageLog.h"
#include "Song.h"
2004-02-10 09:42:01 +00:00
#include "SongManager.h"
#include "Steps.h"
#include "Course.h"
#include "ThemeManager.h"
2004-02-15 04:47:32 +00:00
#include "CryptManager.h"
2004-02-16 02:57:55 +00:00
#include "ProfileManager.h"
2007-01-23 07:32:56 +00:00
#include "RageFile.h"
#include "RageFileDriverDeflate.h"
#include "RageFileManager.h"
2005-03-18 07:36:16 +00:00
#include "LuaManager.h"
2005-02-21 06:22:46 +00:00
#include "UnlockManager.h"
2004-05-22 01:35:08 +00:00
#include "XmlFile.h"
#include "XmlFileUtil.h"
2004-05-23 21:08:03 +00:00
#include "Foreach.h"
2004-07-11 01:58:55 +00:00
#include "CatalogXml.h"
#include "Bookkeeper.h"
#include "Game.h"
#include "CharacterManager.h"
2005-07-13 19:11:24 +00:00
#include "Character.h"
2004-02-09 06:26:13 +00:00
2006-01-22 01:00:06 +00:00
const RString STATS_XSL = "Stats.xsl";
const RString COMMON_XSL = "Common.xsl";
const RString STATS_XML = "Stats.xml";
2007-01-23 07:32:56 +00:00
const RString STATS_XML_GZ = "Stats.xml.gz";
2006-01-22 01:00:06 +00:00
const RString EDITABLE_INI = "Editable.ini";
const RString DONT_SHARE_SIG = "DontShare.sig";
const RString PUBLIC_KEY_FILE = "public.key";
const RString SCREENSHOTS_SUBDIR = "Screenshots/";
const RString EDIT_STEPS_SUBDIR = "Edits/";
const RString EDIT_COURSES_SUBDIR = "EditCourses/";
2004-02-10 09:42:01 +00:00
2006-03-20 09:07:58 +00:00
ThemeMetric<bool> SHOW_COIN_DATA( "Profile", "ShowCoinData" );
2007-01-23 07:32:56 +00:00
static Preference<bool> g_bProfileDataCompress( "ProfileDataCompress", false );
static Preference<bool> g_bCopyCatalogToProfiles( "CopyCatalogToProfiles", true );
extern Preference<bool> g_bWriteCatalog;
2007-06-20 22:25:57 +00:00
static ThemeMetric<RString> UNLOCK_AUTH_STRING( "Profile", "UnlockAuthString" );
2004-04-18 05:46:43 +00:00
#define GUID_SIZE_BYTES 8
2004-02-10 09:42:01 +00:00
2004-05-28 05:58:35 +00:00
#define MAX_EDITABLE_INI_SIZE_BYTES 2*1024 // 2KB
#define MAX_PLAYER_STATS_XML_SIZE_BYTES \
100 /* Songs */ \
* 3 /* Steps per Song */ \
* 10 /* HighScores per Steps */ \
* 1024 /* size in bytes of a HighScores XNode */
2005-06-19 00:29:42 +00:00
const unsigned int DEFAULT_WEIGHT_POUNDS = 120;
2005-02-17 05:56:02 +00:00
#if defined(_MSC_VER)
2004-02-22 07:07:03 +00:00
#pragma warning (disable : 4706) // assignment within conditional expression
#endif
2005-08-05 04:20:46 +00:00
int Profile::HighScoresForASong::GetNumTimesPlayed() const
{
int iCount = 0;
FOREACHM_CONST( StepsID, HighScoresForASteps, m_StepsHighScores, i )
{
iCount += i->second.hsl.GetNumTimesPlayed();
}
return iCount;
}
int Profile::HighScoresForACourse::GetNumTimesPlayed() const
{
int iCount = 0;
FOREACHM_CONST( TrailID, HighScoresForATrail, m_TrailHighScores, i )
{
iCount += i->second.hsl.GetNumTimesPlayed();
}
return iCount;
}
void Profile::InitEditableData()
{
2005-07-13 19:11:24 +00:00
m_sDisplayName = "";
2005-08-14 02:00:27 +00:00
m_sCharacterID = "";
2004-02-22 02:41:10 +00:00
m_sLastUsedHighScoreName = "";
2004-02-23 04:53:02 +00:00
m_iWeightPounds = 0;
}
2004-02-10 09:42:01 +00:00
2007-05-06 05:13:58 +00:00
void Profile::ClearStats()
{
// don't reset the Guid
RString sGuid = m_sGuid;
InitAll();
m_sGuid = sGuid;
}
2006-01-22 01:00:06 +00:00
RString Profile::MakeGuid()
2004-02-09 06:26:13 +00:00
{
2006-01-22 01:00:06 +00:00
RString s;
2007-04-17 20:19:08 +00:00
s.reserve( GUID_SIZE_BYTES*2 );
2007-04-24 21:05:45 +00:00
unsigned char buf[GUID_SIZE_BYTES];
2006-12-20 23:17:57 +00:00
CryptManager::GetRandomBytes( buf, GUID_SIZE_BYTES );
2005-03-22 10:33:06 +00:00
for( unsigned i=0; i<GUID_SIZE_BYTES; i++ )
2006-12-20 23:17:57 +00:00
s += ssprintf( "%02x", buf[i] );
2005-03-22 10:33:06 +00:00
return s;
}
2004-03-14 17:49:38 +00:00
2005-03-22 10:33:06 +00:00
void Profile::InitGeneralData()
{
m_sGuid = MakeGuid();
2004-03-14 17:49:38 +00:00
2006-10-07 04:25:28 +00:00
m_SortOrder = SortOrder_Invalid;
2006-10-07 04:39:48 +00:00
m_LastDifficulty = Difficulty_Invalid;
m_LastCourseDifficulty = Difficulty_Invalid;
m_LastStepsType = StepsType_Invalid;
m_lastSong.Unset();
m_lastCourse.Unset();
2004-02-10 09:42:01 +00:00
m_iTotalPlays = 0;
m_iTotalPlaySeconds = 0;
m_iTotalGameplaySeconds = 0;
2004-02-22 20:58:39 +00:00
m_fTotalCaloriesBurned = 0;
2005-02-16 20:24:57 +00:00
m_GoalType = (GoalType)0;
2005-02-15 22:08:42 +00:00
m_iGoalCalories = 0;
2005-02-16 20:24:57 +00:00
m_iGoalSeconds = 0;
m_iTotalDancePoints = 0;
m_iNumExtraStagesPassed = 0;
m_iNumExtraStagesFailed = 0;
m_iNumToasties = 0;
2006-01-28 22:08:16 +00:00
m_UnlockedEntryIDs.clear();
2004-04-18 05:46:43 +00:00
m_sLastPlayedMachineGuid = "";
2004-07-19 08:05:14 +00:00
m_LastPlayedDate.Init();
2004-02-22 19:54:59 +00:00
m_iTotalTapsAndHolds = 0;
m_iTotalJumps = 0;
m_iTotalHolds = 0;
2005-04-25 11:42:19 +00:00
m_iTotalRolls = 0;
2004-02-22 19:54:59 +00:00
m_iTotalMines = 0;
m_iTotalHands = 0;
2004-02-10 09:42:01 +00:00
FOREACH_ENUM( PlayMode, i )
2004-02-10 09:42:01 +00:00
m_iNumSongsPlayedByPlayMode[i] = 0;
m_iNumSongsPlayedByStyle.clear();
FOREACH_ENUM( Difficulty, i )
2004-02-10 09:42:01 +00:00
m_iNumSongsPlayedByDifficulty[i] = 0;
2004-09-21 07:53:39 +00:00
for( int i=0; i<MAX_METER+1; i++ )
2004-02-10 09:42:01 +00:00
m_iNumSongsPlayedByMeter[i] = 0;
m_iNumTotalSongsPlayed = 0;
2004-08-30 06:07:14 +00:00
ZERO( m_iNumStagesPassedByPlayMode );
ZERO( m_iNumStagesPassedByGrade );
2004-02-09 06:26:13 +00:00
}
2004-02-10 09:42:01 +00:00
void Profile::InitSongScores()
2004-02-09 06:26:13 +00:00
{
m_SongHighScores.clear();
2004-02-09 06:26:13 +00:00
}
2004-02-10 09:42:01 +00:00
void Profile::InitCourseScores()
2004-02-09 06:26:13 +00:00
{
2004-02-10 09:42:01 +00:00
m_CourseHighScores.clear();
}
void Profile::InitCategoryScores()
{
FOREACH_ENUM( StepsType,st )
FOREACH_ENUM( RankingCategory,rc )
2004-02-10 09:42:01 +00:00
m_CategoryHighScores[st][rc].Init();
2004-02-09 06:26:13 +00:00
}
2004-02-08 18:25:30 +00:00
2004-02-17 01:16:57 +00:00
void Profile::InitScreenshotData()
{
m_vScreenshots.clear();
}
2004-02-22 23:29:13 +00:00
void Profile::InitCalorieData()
{
m_mapDayToCaloriesBurned.clear();
}
2004-05-08 10:12:10 +00:00
void Profile::InitRecentSongScores()
{
2004-05-08 10:12:10 +00:00
m_vRecentStepsScores.clear();
2004-04-22 22:01:38 +00:00
}
2004-05-08 10:12:10 +00:00
void Profile::InitRecentCourseScores()
2004-04-22 22:01:38 +00:00
{
2004-05-08 10:12:10 +00:00
m_vRecentCourseScores.clear();
}
2006-01-22 01:00:06 +00:00
RString Profile::GetDisplayNameOrHighScoreName() const
2004-02-08 18:25:30 +00:00
{
if( !m_sDisplayName.empty() )
return m_sDisplayName;
2004-02-08 18:25:30 +00:00
else if( !m_sLastUsedHighScoreName.empty() )
return m_sLastUsedHighScoreName;
else
2006-01-22 01:00:06 +00:00
return RString();
2004-02-08 18:25:30 +00:00
}
2005-07-13 19:11:24 +00:00
Character *Profile::GetCharacter() const
{
vector<Character*> vpCharacters;
CHARMAN->GetCharacters( vpCharacters );
2005-07-13 19:11:24 +00:00
FOREACH_CONST( Character*, vpCharacters, c )
{
2005-08-14 02:00:27 +00:00
if( (*c)->m_sCharacterID.CompareNoCase(m_sCharacterID)==0 )
2005-07-13 19:11:24 +00:00
return *c;
}
return CHARMAN->GetDefaultCharacter();
2005-07-13 19:11:24 +00:00
}
2006-01-22 01:00:06 +00:00
static RString FormatCalories( float fCals )
2004-06-22 08:41:25 +00:00
{
return Commify((int)fCals) + " Cal";
}
int Profile::GetCalculatedWeightPounds() const
2004-02-08 18:25:30 +00:00
{
2004-02-23 04:53:02 +00:00
if( m_iWeightPounds == 0 ) // weight not entered
return DEFAULT_WEIGHT_POUNDS;
2004-02-08 18:25:30 +00:00
else
return m_iWeightPounds;
}
2006-01-22 01:00:06 +00:00
RString Profile::GetDisplayTotalCaloriesBurned() const
{
return FormatCalories( m_fTotalCaloriesBurned );
2004-06-22 08:41:25 +00:00
}
2006-01-22 01:00:06 +00:00
RString Profile::GetDisplayTotalCaloriesBurnedToday() const
2004-06-22 08:41:25 +00:00
{
2005-02-15 23:13:18 +00:00
float fCals = GetCaloriesBurnedToday();
return FormatCalories( fCals );
2004-02-08 18:25:30 +00:00
}
2005-02-15 23:13:18 +00:00
float Profile::GetCaloriesBurnedToday() const
{
DateTime now = DateTime::GetNowDate();
return GetCaloriesBurnedForDay(now);
}
int Profile::GetTotalNumSongsPassed() const
{
int iTotal = 0;
FOREACH_ENUM( PlayMode, i )
2004-08-30 06:07:14 +00:00
iTotal += m_iNumStagesPassedByPlayMode[i];
return iTotal;
}
int Profile::GetTotalStepsWithTopGrade( StepsType st, Difficulty d, Grade g ) const
{
int iCount = 0;
2007-04-07 05:36:40 +00:00
FOREACH_CONST( Song*, SONGMAN->GetSongs(), pSong )
{
if( !(*pSong)->NormallyDisplayed() )
continue; // skip
FOREACH_CONST( Steps*, (*pSong)->GetAllSteps(), pSteps )
{
if( (*pSteps)->m_StepsType != st )
continue; // skip
if( (*pSteps)->GetDifficulty() != d )
continue; // skip
const HighScoreList &hsl = GetStepsHighScoreList( *pSong, *pSteps );
if( hsl.vHighScores.empty() )
continue; // skip
2005-08-12 02:19:08 +00:00
if( hsl.vHighScores[0].GetGrade() == g )
iCount++;
}
}
return iCount;
}
int Profile::GetTotalTrailsWithTopGrade( StepsType st, CourseDifficulty d, Grade g ) const
{
int iCount = 0;
// add course high scores
vector<Course*> vCourses;
SONGMAN->GetAllCourses( vCourses, false );
FOREACH_CONST( Course*, vCourses, pCourse )
{
// Don't count any course that has any entries that change over time.
if( !(*pCourse)->AllSongsAreFixed() )
continue;
vector<Trail*> vTrails;
Trail* pTrail = (*pCourse)->GetTrail( st, d );
if( pTrail == NULL )
continue;
const HighScoreList &hsl = GetCourseHighScoreList( *pCourse, pTrail );
if( hsl.vHighScores.empty() )
continue; // skip
2005-08-12 02:19:08 +00:00
if( hsl.vHighScores[0].GetGrade() == g )
iCount++;
}
return iCount;
}
float Profile::GetSongsPossible( StepsType st, Difficulty dc ) const
{
int iTotalSteps = 0;
// add steps high scores
2007-08-13 19:24:54 +00:00
const vector<Song*> &vSongs = SONGMAN->GetSongs();
2004-06-22 08:41:25 +00:00
for( unsigned i=0; i<vSongs.size(); i++ )
{
2004-06-22 08:41:25 +00:00
Song* pSong = vSongs[i];
if( !pSong->NormallyDisplayed() )
2004-06-22 08:41:25 +00:00
continue; // skip
vector<Steps*> vSteps = pSong->GetAllSteps();
for( unsigned j=0; j<vSteps.size(); j++ )
{
2004-06-22 08:41:25 +00:00
Steps* pSteps = vSteps[j];
2004-06-22 08:41:25 +00:00
if( pSteps->m_StepsType != st )
continue; // skip
if( pSteps->GetDifficulty() != dc )
continue; // skip
iTotalSteps++;
}
}
2004-08-15 21:58:13 +00:00
return (float) iTotalSteps;
}
2004-05-08 08:09:18 +00:00
float Profile::GetSongsActual( StepsType st, Difficulty dc ) const
{
2004-11-24 03:49:17 +00:00
CHECKPOINT_M( ssprintf("Profile::GetSongsActual(%d,%d)",st,dc) );
float fTotalPercents = 0;
2004-03-12 05:24:32 +00:00
// add steps high scores
FOREACHM_CONST( SongID, HighScoresForASong, m_SongHighScores, i )
2004-03-11 06:31:30 +00:00
{
2004-06-22 08:41:25 +00:00
const SongID &id = i->first;
Song* pSong = id.ToSong();
2004-11-24 03:49:17 +00:00
CHECKPOINT_M( ssprintf("Profile::GetSongsActual: %p", pSong) );
2004-06-22 08:41:25 +00:00
// If the Song isn't loaded on the current machine, then we can't
// get radar values to compute dance points.
if( pSong == NULL )
continue;
2004-11-24 03:49:17 +00:00
if( !pSong->NormallyDisplayed() )
2004-06-22 08:41:25 +00:00
continue; // skip
2004-11-24 03:49:17 +00:00
2004-12-14 02:11:38 +00:00
CHECKPOINT_M( ssprintf("Profile::GetSongsActual: song %s", pSong->GetSongDir().c_str()) );
2004-06-22 08:41:25 +00:00
const HighScoresForASong &hsfas = i->second;
2004-11-24 03:49:17 +00:00
FOREACHM_CONST( StepsID, HighScoresForASteps, hsfas.m_StepsHighScores, j )
2004-03-11 06:31:30 +00:00
{
2004-06-22 08:41:25 +00:00
const StepsID &id = j->first;
Steps* pSteps = id.ToSteps( pSong, true );
2004-12-14 02:11:38 +00:00
CHECKPOINT_M( ssprintf("Profile::GetSongsActual: song %p, steps %p", pSong, pSteps) );
2004-06-22 08:41:25 +00:00
// If the Steps isn't loaded on the current machine, then we can't
// get radar values to compute dance points.
2004-06-22 08:41:25 +00:00
if( pSteps == NULL )
continue;
2004-11-24 03:49:17 +00:00
2004-06-22 08:41:25 +00:00
if( pSteps->m_StepsType != st )
continue;
2004-11-24 03:49:17 +00:00
2004-12-14 02:11:38 +00:00
CHECKPOINT_M( ssprintf("Profile::GetSongsActual: n %s = %p", id.ToString().c_str(), pSteps) );
2004-06-22 08:41:25 +00:00
if( pSteps->GetDifficulty() != dc )
2004-05-11 02:12:54 +00:00
continue; // skip
2004-12-14 02:11:38 +00:00
CHECKPOINT;
2004-11-24 03:49:17 +00:00
2004-06-22 08:41:25 +00:00
const HighScoresForASteps& h = j->second;
2005-04-25 09:03:24 +00:00
const HighScoreList& hsl = h.hsl;
2004-11-24 03:49:17 +00:00
2005-08-12 02:46:58 +00:00
fTotalPercents += hsl.GetTopScore().GetPercentDP();
2004-03-11 06:31:30 +00:00
}
2004-11-24 03:49:17 +00:00
CHECKPOINT;
2004-03-11 06:31:30 +00:00
}
return fTotalPercents;
2004-05-08 08:09:18 +00:00
}
float Profile::GetSongsPercentComplete( StepsType st, Difficulty dc ) const
{
return GetSongsActual(st,dc) / GetSongsPossible(st,dc);
}
2006-03-19 00:58:26 +00:00
static void GetHighScoreCourses( vector<Course*> &vpCoursesOut )
2004-05-08 08:20:16 +00:00
{
vpCoursesOut.clear();
2004-05-08 08:20:16 +00:00
vector<Course*> vpCourses;
SONGMAN->GetAllCourses( vpCourses, false );
FOREACH_CONST( Course*, vpCourses, c )
2004-05-08 08:20:16 +00:00
{
// Don't count any course that has any entries that change over time.
if( !(*c)->AllSongsAreFixed() )
continue;
vpCoursesOut.push_back( *c );
}
}
float Profile::GetCoursesPossible( StepsType st, CourseDifficulty cd ) const
{
int iTotalTrails = 0;
vector<Course*> vpCourses;
GetHighScoreCourses( vpCourses );
FOREACH_CONST( Course*, vpCourses, c )
{
Trail* pTrail = (*c)->GetTrail(st,cd);
2004-06-22 08:41:25 +00:00
if( pTrail == NULL )
continue;
2004-05-08 08:20:16 +00:00
iTotalTrails++;
2004-05-08 08:20:16 +00:00
}
2004-08-15 21:58:13 +00:00
return (float) iTotalTrails;
}
float Profile::GetCoursesActual( StepsType st, CourseDifficulty cd ) const
{
float fTotalPercents = 0;
2004-05-08 08:09:18 +00:00
vector<Course*> vpCourses;
GetHighScoreCourses( vpCourses );
FOREACH_CONST( Course*, vpCourses, c )
2004-03-12 05:24:32 +00:00
{
Trail *pTrail = (*c)->GetTrail( st, cd );
if( pTrail == NULL )
2004-06-22 08:41:25 +00:00
continue;
const HighScoreList& hsl = GetCourseHighScoreList( *c, pTrail );
fTotalPercents += hsl.GetTopScore().GetPercentDP();
2004-03-12 05:24:32 +00:00
}
return fTotalPercents;
}
float Profile::GetCoursesPercentComplete( StepsType st, CourseDifficulty cd ) const
{
return GetCoursesActual(st,cd) / GetCoursesPossible(st,cd);
2004-03-11 06:31:30 +00:00
}
float Profile::GetSongsAndCoursesPercentCompleteAllDifficulties( StepsType st ) const
{
float fActual = 0;
float fPossible = 0;
FOREACH_ENUM( Difficulty, d )
{
fActual += GetSongsActual(st,d);
fPossible += GetSongsPossible(st,d);
}
FOREACH_ENUM( CourseDifficulty, d )
{
fActual += GetCoursesActual(st,d);
fPossible += GetCoursesPossible(st,d);
}
return fActual / fPossible;
}
2004-02-10 10:06:34 +00:00
int Profile::GetSongNumTimesPlayed( const Song* pSong ) const
{
SongID songID;
songID.FromSong( pSong );
return GetSongNumTimesPlayed( songID );
}
int Profile::GetSongNumTimesPlayed( const SongID& songID ) const
2004-02-10 09:42:01 +00:00
{
2004-05-02 00:08:42 +00:00
const HighScoresForASong *hsSong = GetHighScoresForASong( songID );
if( hsSong == NULL )
return 0;
2004-05-02 00:08:42 +00:00
int iTotalNumTimesPlayed = 0;
FOREACHM_CONST( StepsID, HighScoresForASteps, hsSong->m_StepsHighScores, j )
2004-02-10 09:42:01 +00:00
{
const HighScoresForASteps &hsSteps = j->second;
2005-04-25 22:44:32 +00:00
iTotalNumTimesPlayed += hsSteps.hsl.GetNumTimesPlayed();
2004-02-10 09:42:01 +00:00
}
return iTotalNumTimesPlayed;
}
2004-02-08 18:25:30 +00:00
/*
* Get the profile default modifiers. Return true if set, in which case sModifiersOut
* will be set. Return false if no modifier string is set, in which case the theme
* defaults should be used. Note that the null string means "no modifiers are active",
* which is distinct from no modifier string being set at all.
*
* In practice, we get the default modifiers from the theme the first time a game
* is played, and from the profile every time thereafter.
*/
2006-01-22 01:00:06 +00:00
bool Profile::GetDefaultModifiers( const Game* pGameType, RString &sModifiersOut ) const
{
2006-01-22 01:00:06 +00:00
map<RString,RString>::const_iterator it;
it = m_sDefaultModifiers.find( pGameType->m_szName );
if( it == m_sDefaultModifiers.end() )
return false;
sModifiersOut = it->second;
return true;
}
2006-01-22 01:00:06 +00:00
void Profile::SetDefaultModifiers( const Game* pGameType, const RString &sModifiers )
{
if( sModifiers == "" )
m_sDefaultModifiers.erase( pGameType->m_szName );
else
m_sDefaultModifiers[pGameType->m_szName] = sModifiers;
}
bool Profile::IsCodeUnlocked( RString sUnlockEntryID ) const
2005-02-21 06:59:50 +00:00
{
return m_UnlockedEntryIDs.find( sUnlockEntryID ) != m_UnlockedEntryIDs.end();
2005-02-21 06:59:50 +00:00
}
2005-08-05 04:20:46 +00:00
Song *Profile::GetMostPopularSong() const
{
int iMaxNumTimesPlayed = 0;
SongID id;
FOREACHM_CONST( SongID, HighScoresForASong, m_SongHighScores, i )
{
int iNumTimesPlayed = i->second.GetNumTimesPlayed();
if( iNumTimesPlayed > iMaxNumTimesPlayed )
{
id = i->first;
iMaxNumTimesPlayed = iNumTimesPlayed;
}
}
return id.ToSong();
}
Course *Profile::GetMostPopularCourse() const
{
int iMaxNumTimesPlayed = 0;
CourseID id;
FOREACHM_CONST( CourseID, HighScoresForACourse, m_CourseHighScores, i )
{
int iNumTimesPlayed = i->second.GetNumTimesPlayed();
if( iNumTimesPlayed > iMaxNumTimesPlayed )
{
id = i->first;
iMaxNumTimesPlayed = iNumTimesPlayed;
}
}
return id.ToCourse();
}
2004-02-09 06:26:13 +00:00
//
// Steps high scores
//
void Profile::AddStepsHighScore( const Song* pSong, const Steps* pSteps, HighScore hs, int &iIndexOut )
2004-02-09 06:26:13 +00:00
{
GetStepsHighScoreList(pSong,pSteps).AddHighScore( hs, iIndexOut, IsMachine() );
2004-02-09 06:26:13 +00:00
}
const HighScoreList& Profile::GetStepsHighScoreList( const Song* pSong, const Steps* pSteps ) const
2004-02-10 10:06:34 +00:00
{
return ((Profile*)this)->GetStepsHighScoreList(pSong,pSteps);
2004-02-10 10:06:34 +00:00
}
HighScoreList& Profile::GetStepsHighScoreList( const Song* pSong, const Steps* pSteps )
2004-02-09 06:26:13 +00:00
{
SongID songID;
songID.FromSong( pSong );
StepsID stepsID;
stepsID.FromSteps( pSteps );
2004-04-26 00:06:42 +00:00
HighScoresForASong &hsSong = m_SongHighScores[songID]; // operator[] inserts into map
HighScoresForASteps &hsSteps = hsSong.m_StepsHighScores[stepsID]; // operator[] inserts into map
2005-04-25 09:03:24 +00:00
return hsSteps.hsl;
2004-02-09 06:26:13 +00:00
}
int Profile::GetStepsNumTimesPlayed( const Song* pSong, const Steps* pSteps ) const
2004-02-09 06:26:13 +00:00
{
2005-04-25 22:44:32 +00:00
return GetStepsHighScoreList(pSong,pSteps).GetNumTimesPlayed();
}
DateTime Profile::GetSongLastPlayedDateTime( const Song* pSong ) const
{
SongID id;
id.FromSong( pSong );
std::map<SongID,HighScoresForASong>::const_iterator iter = m_SongHighScores.find( id );
// don't call this unless has been played once
ASSERT( iter != m_SongHighScores.end() );
ASSERT( !iter->second.m_StepsHighScores.empty() );
DateTime dtLatest; // starts out zeroed
FOREACHM_CONST( StepsID, HighScoresForASteps, iter->second.m_StepsHighScores, i )
{
const HighScoreList &hsl = i->second.hsl;
if( hsl.GetNumTimesPlayed() == 0 )
continue;
if( dtLatest < hsl.GetLastPlayed() )
dtLatest = hsl.GetLastPlayed();
}
return dtLatest;
2004-02-09 06:26:13 +00:00
}
2006-03-20 22:41:41 +00:00
bool Profile::HasPassedSteps( const Song* pSong, const Steps* pSteps ) const
{
const HighScoreList &hsl = GetStepsHighScoreList( pSong, pSteps );
Grade grade = hsl.GetTopScore().GetGrade();
switch( grade )
{
case Grade_Failed:
case Grade_NoData:
return false;
default:
return true;
}
}
bool Profile::HasPassedAnyStepsInSong( const Song* pSong ) const
{
2005-09-12 17:49:53 +00:00
FOREACH_CONST( Steps*, pSong->GetAllSteps(), steps )
{
2006-03-20 22:41:41 +00:00
if( HasPassedSteps( pSong, *steps ) )
return true;
}
return false;
}
void Profile::IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps )
2004-02-09 06:26:13 +00:00
{
2005-04-25 22:44:32 +00:00
DateTime now = DateTime::GetNowDate();
GetStepsHighScoreList(pSong,pSteps).IncrementPlayCount( now );
2004-02-09 06:26:13 +00:00
}
void Profile::GetGrades( const Song* pSong, StepsType st, int iCounts[NUM_Grade] ) const
2004-05-02 00:08:42 +00:00
{
SongID songID;
songID.FromSong( pSong );
memset( iCounts, 0, sizeof(int)*NUM_Grade );
2004-05-02 00:08:42 +00:00
const HighScoresForASong *hsSong = GetHighScoresForASong( songID );
if( hsSong == NULL )
return;
FOREACH_ENUM( Grade,g)
2004-05-02 00:08:42 +00:00
{
FOREACHM_CONST( StepsID, HighScoresForASteps, hsSong->m_StepsHighScores, it )
2004-05-02 00:08:42 +00:00
{
const StepsID &id = it->first;
if( !id.MatchesStepsType(st) )
continue;
const HighScoresForASteps &hsSteps = it->second;
2005-08-12 02:19:08 +00:00
if( hsSteps.hsl.GetTopScore().GetGrade() == g )
2004-05-02 00:08:42 +00:00
iCounts[g]++;
}
}
}
2004-02-09 06:26:13 +00:00
//
// Course high scores
//
2004-05-23 21:08:03 +00:00
void Profile::AddCourseHighScore( const Course* pCourse, const Trail* pTrail, HighScore hs, int &iIndexOut )
2004-02-09 06:26:13 +00:00
{
GetCourseHighScoreList(pCourse,pTrail).AddHighScore( hs, iIndexOut, IsMachine() );
2004-02-09 06:26:13 +00:00
}
2004-05-23 21:08:03 +00:00
const HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, const Trail* pTrail ) const
2004-02-10 10:06:34 +00:00
{
2004-05-23 21:08:03 +00:00
return ((Profile *)this)->GetCourseHighScoreList( pCourse, pTrail );
2004-02-10 10:06:34 +00:00
}
2004-05-23 21:08:03 +00:00
HighScoreList& Profile::GetCourseHighScoreList( const Course* pCourse, const Trail* pTrail )
2004-02-09 06:26:13 +00:00
{
CourseID courseID;
courseID.FromCourse( pCourse );
2004-05-23 21:08:03 +00:00
TrailID trailID;
trailID.FromTrail( pTrail );
HighScoresForACourse &hsCourse = m_CourseHighScores[courseID]; // operator[] inserts into map
HighScoresForATrail &hsTrail = hsCourse.m_TrailHighScores[trailID]; // operator[] inserts into map
2005-04-25 09:03:24 +00:00
return hsTrail.hsl;
2004-02-09 06:26:13 +00:00
}
int Profile::GetCourseNumTimesPlayed( const Course* pCourse ) const
{
CourseID courseID;
courseID.FromCourse( pCourse );
return GetCourseNumTimesPlayed( courseID );
}
int Profile::GetCourseNumTimesPlayed( const CourseID &courseID ) const
{
2004-05-23 21:08:03 +00:00
const HighScoresForACourse *hsCourse = GetHighScoresForACourse( courseID );
if( hsCourse == NULL )
2004-02-09 06:26:13 +00:00
return 0;
2004-05-23 21:08:03 +00:00
int iTotalNumTimesPlayed = 0;
FOREACHM_CONST( TrailID, HighScoresForATrail, hsCourse->m_TrailHighScores, j )
2004-02-09 06:26:13 +00:00
{
2004-05-23 21:08:03 +00:00
const HighScoresForATrail &hsTrail = j->second;
2005-04-25 22:44:32 +00:00
iTotalNumTimesPlayed += hsTrail.hsl.GetNumTimesPlayed();
2004-02-09 06:26:13 +00:00
}
2004-05-23 21:08:03 +00:00
return iTotalNumTimesPlayed;
2004-02-09 06:26:13 +00:00
}
2005-04-25 22:44:32 +00:00
DateTime Profile::GetCourseLastPlayedDateTime( const Course* pCourse ) const
{
CourseID id;
id.FromCourse( pCourse );
std::map<CourseID,HighScoresForACourse>::const_iterator iter = m_CourseHighScores.find( id );
// don't call this unless has been played once
ASSERT( iter != m_CourseHighScores.end() );
ASSERT( !iter->second.m_TrailHighScores.empty() );
DateTime dtLatest; // starts out zeroed
FOREACHM_CONST( TrailID, HighScoresForATrail, iter->second.m_TrailHighScores, i )
{
const HighScoreList &hsl = i->second.hsl;
if( hsl.GetNumTimesPlayed() == 0 )
continue;
if( dtLatest < hsl.GetLastPlayed() )
dtLatest = hsl.GetLastPlayed();
}
return dtLatest;
}
2004-05-23 21:08:03 +00:00
void Profile::IncrementCoursePlayCount( const Course* pCourse, const Trail* pTrail )
2004-02-09 06:26:13 +00:00
{
2005-04-25 22:44:32 +00:00
DateTime now = DateTime::GetNowDate();
GetCourseHighScoreList(pCourse,pTrail).IncrementPlayCount( now );
2004-02-09 06:26:13 +00:00
}
//
// Category high scores
//
void Profile::AddCategoryHighScore( StepsType st, RankingCategory rc, HighScore hs, int &iIndexOut )
{
m_CategoryHighScores[st][rc].AddHighScore( hs, iIndexOut, IsMachine() );
2004-02-09 06:26:13 +00:00
}
2004-02-10 10:06:34 +00:00
const HighScoreList& Profile::GetCategoryHighScoreList( StepsType st, RankingCategory rc ) const
{
return ((Profile *)this)->m_CategoryHighScores[st][rc];
}
2004-02-09 06:26:13 +00:00
HighScoreList& Profile::GetCategoryHighScoreList( StepsType st, RankingCategory rc )
{
return m_CategoryHighScores[st][rc];
}
2004-02-10 09:42:01 +00:00
int Profile::GetCategoryNumTimesPlayed( StepsType st ) const
2004-02-09 06:26:13 +00:00
{
int iNumTimesPlayed = 0;
FOREACH_ENUM( RankingCategory,rc )
2005-04-25 22:44:32 +00:00
iNumTimesPlayed += m_CategoryHighScores[st][rc].GetNumTimesPlayed();
2004-02-09 06:26:13 +00:00
return iNumTimesPlayed;
}
void Profile::IncrementCategoryPlayCount( StepsType st, RankingCategory rc )
{
2005-04-25 22:44:32 +00:00
DateTime now = DateTime::GetNowDate();
m_CategoryHighScores[st][rc].IncrementPlayCount( now );
2004-02-09 06:26:13 +00:00
}
2004-02-10 09:42:01 +00:00
//
// Loading and saving
//
#define WARN_PARSER ShowWarningOrTrace( __FILE__, __LINE__, "Error parsing file.", true )
2005-04-30 02:56:38 +00:00
#define WARN_AND_RETURN { WARN_PARSER; return; }
#define WARN_AND_CONTINUE { WARN_PARSER; continue; }
#define WARN_AND_BREAK { WARN_PARSER; break; }
#define WARN_M(m) ShowWarningOrTrace( __FILE__, __LINE__, RString("Error parsing file: ")+(m), true )
2004-09-05 06:25:13 +00:00
#define WARN_AND_RETURN_M(m) { WARN_M(m); return; }
#define WARN_AND_CONTINUE_M(m) { WARN_M(m); continue; }
#define WARN_AND_BREAK_M(m) { WARN_M(m); break; }
#define LOAD_NODE(X) { \
2005-01-08 19:15:56 +00:00
const XNode* X = xml->GetChild(#X); \
if( X==NULL ) LOG->Warn("Failed to read section " #X); \
else Load##X##FromNode(X); }
2006-01-22 01:00:06 +00:00
ProfileLoadResult Profile::LoadAllFromDir( RString sDir, bool bRequireSignature )
2004-02-15 04:47:32 +00:00
{
CHECKPOINT;
2004-06-06 06:54:08 +00:00
LOG->Trace( "Profile::LoadAllFromDir( %s )", sDir.c_str() );
ASSERT( sDir.Right(1) == "/" );
2004-02-15 04:47:32 +00:00
InitAll();
// Not critical if this fails
2004-02-22 02:41:10 +00:00
LoadEditableDataFromDir( sDir );
// Check for the existance of stats.xml
2006-01-22 01:00:06 +00:00
RString fn = sDir + STATS_XML;
2007-01-23 07:32:56 +00:00
bool bCompressed = false;
if( !IsAFile(fn) )
2007-01-23 07:32:56 +00:00
{
// Check for the existance of stats.xml.gz
fn = sDir + STATS_XML_GZ;
bCompressed = true;
if( !IsAFile(fn) )
return ProfileLoadResult_FailedNoProfile;
}
int iError;
auto_ptr<RageFileBasic> pFile( FILEMAN->Open(fn, RageFile::READ, iError) );
if( pFile.get() == NULL )
{
LOG->Trace( "Error opening %s: %s", fn.c_str(), strerror(iError) );
return ProfileLoadResult_FailedTampered;
}
if( bCompressed )
{
RString sError;
uint32_t iCRC32;
RageFileObjInflate *pInflate = GunzipFile( pFile.release(), sError, &iCRC32 );
if( pInflate == NULL )
{
LOG->Trace( "Error opening %s: %s", fn.c_str(), sError.c_str() );
return ProfileLoadResult_FailedTampered;
}
pFile.reset( pInflate );
}
//
// Don't unreasonably large stats.xml files.
//
if( !IsMachine() ) // only check stats coming from the player
{
2007-01-23 07:32:56 +00:00
int iBytes = pFile->GetFileSize();
if( iBytes > MAX_PLAYER_STATS_XML_SIZE_BYTES )
{
LOG->Warn( "The file '%s' is unreasonably large. It won't be loaded.", fn.c_str() );
return ProfileLoadResult_FailedTampered;
}
}
if( bRequireSignature )
{
2006-01-22 01:00:06 +00:00
RString sStatsXmlSigFile = fn+SIGNATURE_APPEND;
RString sDontShareFile = sDir + DONT_SHARE_SIG;
2004-06-06 06:54:08 +00:00
2007-05-06 02:09:33 +00:00
LOG->Trace( "Verifying don't share signature \"%s\" against \"%s\"", sDontShareFile.c_str(), sStatsXmlSigFile.c_str() );
// verify the stats.xml signature with the "don't share" file
if( !CryptManager::VerifyFileWithFile(sStatsXmlSigFile, sDontShareFile) )
{
LOG->Warn( "The don't share check for '%s' failed. Data will be ignored.", sStatsXmlSigFile.c_str() );
return ProfileLoadResult_FailedTampered;
}
LOG->Trace( "Done." );
// verify stats.xml
LOG->Trace( "Verifying stats.xml signature" );
if( !CryptManager::VerifyFileWithFile(fn, sStatsXmlSigFile) )
{
LOG->Warn( "The signature check for '%s' failed. Data will be ignored.", fn.c_str() );
return ProfileLoadResult_FailedTampered;
}
2004-06-06 06:54:08 +00:00
LOG->Trace( "Done." );
}
LOG->Trace( "Loading %s", fn.c_str() );
XNode xml;
2007-01-23 07:32:56 +00:00
if( !XmlFileUtil::LoadFromFileShowErrors(xml, *pFile.get()) )
return ProfileLoadResult_FailedTampered;
LOG->Trace( "Done." );
2005-01-08 19:15:56 +00:00
return LoadStatsXmlFromNode( &xml );
}
ProfileLoadResult Profile::LoadStatsXmlFromNode( const XNode *xml, bool bIgnoreEditable )
2005-01-08 19:15:56 +00:00
{
/* The placeholder stats.xml file has an <html> tag. Don't load it, but don't
* warn about it. */
2006-10-02 06:12:42 +00:00
if( xml->GetName() == "html" )
return ProfileLoadResult_FailedNoProfile;
2006-10-02 06:12:42 +00:00
if( xml->GetName() != "Stats" )
{
2006-10-02 06:12:42 +00:00
WARN_M( xml->GetName() );
return ProfileLoadResult_FailedTampered;
}
2005-08-13 03:16:28 +00:00
/* These are loaded from Editable, so we usually want to ignore them
* here. */
2006-01-22 01:00:06 +00:00
RString sName = m_sDisplayName;
RString sCharacterID = m_sCharacterID;
RString sLastUsedHighScoreName = m_sLastUsedHighScoreName;
2005-08-13 03:16:28 +00:00
int iWeightPounds = m_iWeightPounds;
LOAD_NODE( GeneralData );
LOAD_NODE( SongScores );
LOAD_NODE( CourseScores );
LOAD_NODE( CategoryScores );
LOAD_NODE( ScreenshotData );
LOAD_NODE( CalorieData );
LOAD_NODE( RecentSongScores );
LOAD_NODE( RecentCourseScores );
2005-08-13 03:16:28 +00:00
if( bIgnoreEditable )
{
m_sDisplayName = sName;
2005-08-14 02:00:27 +00:00
m_sCharacterID = sCharacterID;
2005-08-13 03:16:28 +00:00
m_sLastUsedHighScoreName = sLastUsedHighScoreName;
m_iWeightPounds = iWeightPounds;
}
return ProfileLoadResult_Success;
2004-02-15 04:47:32 +00:00
}
2006-01-22 01:00:06 +00:00
bool Profile::SaveAllToDir( RString sDir, bool bSignData ) const
2004-02-15 04:47:32 +00:00
{
2004-04-18 05:46:43 +00:00
m_sLastPlayedMachineGuid = PROFILEMAN->GetMachineProfile()->m_sGuid;
2004-07-18 21:54:19 +00:00
m_LastPlayedDate = DateTime::GetNowDate();
2004-02-16 05:35:06 +00:00
// Save editable.ini
2004-02-22 02:41:10 +00:00
SaveEditableDataToDir( sDir );
bool bSaved = SaveStatsXmlToDir( sDir, bSignData );
SaveStatsWebPageToDir( sDir );
// Empty directories if none exist.
2007-05-27 17:59:41 +00:00
if( ProfileManager::m_bProfileStepEdits )
FILEMAN->CreateDir( sDir + EDIT_STEPS_SUBDIR );
if( ProfileManager::m_bProfileCourseEdits )
FILEMAN->CreateDir( sDir + EDIT_COURSES_SUBDIR );
FILEMAN->CreateDir( sDir + SCREENSHOTS_SUBDIR );
FILEMAN->FlushDirCache( sDir );
return bSaved;
}
2004-12-22 03:49:55 +00:00
XNode *Profile::SaveStatsXmlCreateNode() const
{
2006-10-01 14:51:50 +00:00
XNode *xml = new XNode( "Stats" );
2004-12-22 03:49:55 +00:00
xml->AppendChild( SaveGeneralDataCreateNode() );
xml->AppendChild( SaveSongScoresCreateNode() );
xml->AppendChild( SaveCourseScoresCreateNode() );
xml->AppendChild( SaveCategoryScoresCreateNode() );
xml->AppendChild( SaveScreenshotDataCreateNode() );
xml->AppendChild( SaveCalorieDataCreateNode() );
xml->AppendChild( SaveRecentSongScoresCreateNode() );
xml->AppendChild( SaveRecentCourseScoresCreateNode() );
2006-03-20 09:07:58 +00:00
if( SHOW_COIN_DATA.GetValue() && IsMachine() )
2004-12-22 03:49:55 +00:00
xml->AppendChild( SaveCoinDataCreateNode() );
return xml;
}
2006-01-22 01:00:06 +00:00
bool Profile::SaveStatsXmlToDir( RString sDir, bool bSignData ) const
{
2007-01-23 07:32:56 +00:00
LOG->Trace( "SaveStatsXmlToDir: %s", sDir.c_str() );
auto_ptr<XNode> xml( SaveStatsXmlCreateNode() );
// Save stats.xml
2007-01-23 07:32:56 +00:00
RString fn = sDir + (g_bProfileDataCompress? STATS_XML_GZ:STATS_XML);
2007-01-23 07:32:56 +00:00
{
RString sError;
RageFile f;
if( !f.Open(fn, RageFile::WRITE) )
{
LOG->Warn( "Couldn't open %s for writing: %s", fn.c_str(), f.GetError().c_str() );
return false;
}
2007-01-23 07:32:56 +00:00
if( g_bProfileDataCompress )
{
RageFileObjGzip gzip( &f );
gzip.Start();
if( !XmlFileUtil::SaveToFile( xml.get(), gzip, STATS_XSL, false ) )
return false;
if( gzip.Finish() == -1 )
return false;
/* After successfully saving STATS_XML_GZ, remove any stray STATS_XML. */
2007-04-17 20:48:01 +00:00
if( FILEMAN->IsAFile(sDir + STATS_XML) )
FILEMAN->Remove( sDir + STATS_XML );
2007-01-23 07:32:56 +00:00
}
else
{
if( !XmlFileUtil::SaveToFile( xml.get(), f, STATS_XSL, false ) )
return false;
/* After successfully saving STATS_XML, remove any stray STATS_XML_GZ. */
2007-04-17 20:48:01 +00:00
if( FILEMAN->IsAFile(sDir + STATS_XML_GZ) )
FILEMAN->Remove( sDir + STATS_XML_GZ );
2007-01-23 07:32:56 +00:00
}
}
// Update file cache, or else IsAFile in CryptManager won't see this new file.
FILEMAN->FlushDirCache( sDir );
2007-01-23 07:32:56 +00:00
if( bSignData )
{
2006-01-22 01:00:06 +00:00
RString sStatsXmlSigFile = fn+SIGNATURE_APPEND;
CryptManager::SignFileToFile(fn, sStatsXmlSigFile);
// Update file cache, or else IsAFile in CryptManager won't see sStatsXmlSigFile.
2004-04-22 08:03:02 +00:00
FILEMAN->FlushDirCache( sDir );
// Save the "don't share" file
2006-01-22 01:00:06 +00:00
RString sDontShareFile = sDir + DONT_SHARE_SIG;
CryptManager::SignFileToFile(sStatsXmlSigFile, sDontShareFile);
}
2007-01-23 07:32:56 +00:00
return true;
2004-02-15 04:47:32 +00:00
}
2006-01-22 01:00:06 +00:00
void Profile::SaveEditableDataToDir( RString sDir ) const
2004-02-10 09:42:01 +00:00
{
2004-02-22 02:41:10 +00:00
IniFile ini;
2004-02-10 09:42:01 +00:00
2004-02-22 02:41:10 +00:00
ini.SetValue( "Editable", "DisplayName", m_sDisplayName );
2005-08-14 02:00:27 +00:00
ini.SetValue( "Editable", "CharacterID", m_sCharacterID );
2006-04-05 03:08:42 +00:00
ini.SetValue( "Editable", "LastUsedHighScoreName", m_sLastUsedHighScoreName );
2004-02-23 04:53:02 +00:00
ini.SetValue( "Editable", "WeightPounds", m_iWeightPounds );
2004-02-22 02:41:10 +00:00
2004-05-23 02:27:51 +00:00
ini.WriteFile( sDir + EDITABLE_INI );
}
2004-02-10 09:42:01 +00:00
XNode* Profile::SaveGeneralDataCreateNode() const
{
2006-10-01 14:51:50 +00:00
XNode* pGeneralDataNode = new XNode( "GeneralData" );
2004-05-20 03:51:07 +00:00
2005-08-13 03:16:28 +00:00
// TRICKY: These are write-only elements that are normally never read again.
// This data is required by other apps (like internet ranking), but is
2004-05-28 05:58:35 +00:00
// redundant to the game app.
2006-04-05 03:08:42 +00:00
pGeneralDataNode->AppendChild( "DisplayName", GetDisplayNameOrHighScoreName() );
pGeneralDataNode->AppendChild( "CharacterID", m_sCharacterID );
pGeneralDataNode->AppendChild( "LastUsedHighScoreName", m_sLastUsedHighScoreName );
pGeneralDataNode->AppendChild( "WeightPounds", m_iWeightPounds );
pGeneralDataNode->AppendChild( "IsMachine", IsMachine() );
pGeneralDataNode->AppendChild( "IsWeightSet", m_iWeightPounds != 0 );
pGeneralDataNode->AppendChild( "Guid", m_sGuid );
pGeneralDataNode->AppendChild( "SortOrder", SortOrderToString(m_SortOrder) );
pGeneralDataNode->AppendChild( "LastDifficulty", DifficultyToString(m_LastDifficulty) );
2006-10-07 22:49:04 +00:00
pGeneralDataNode->AppendChild( "LastCourseDifficulty", DifficultyToString(m_LastCourseDifficulty) );
if( m_LastStepsType != StepsType_Invalid )
pGeneralDataNode->AppendChild( "LastStepsType", GameManager::GetStepsTypeInfo(m_LastStepsType).szName );
pGeneralDataNode->AppendChild( m_lastSong.CreateNode() );
pGeneralDataNode->AppendChild( m_lastCourse.CreateNode() );
2006-04-05 03:08:42 +00:00
pGeneralDataNode->AppendChild( "TotalPlays", m_iTotalPlays );
pGeneralDataNode->AppendChild( "TotalPlaySeconds", m_iTotalPlaySeconds );
pGeneralDataNode->AppendChild( "TotalGameplaySeconds", m_iTotalGameplaySeconds );
pGeneralDataNode->AppendChild( "TotalCaloriesBurned", m_fTotalCaloriesBurned );
pGeneralDataNode->AppendChild( "GoalType", m_GoalType );
pGeneralDataNode->AppendChild( "GoalCalories", m_iGoalCalories );
pGeneralDataNode->AppendChild( "GoalSeconds", m_iGoalSeconds );
pGeneralDataNode->AppendChild( "LastPlayedMachineGuid", m_sLastPlayedMachineGuid );
pGeneralDataNode->AppendChild( "LastPlayedDate", m_LastPlayedDate.GetString() );
2006-04-05 03:08:42 +00:00
pGeneralDataNode->AppendChild( "TotalDancePoints", m_iTotalDancePoints );
pGeneralDataNode->AppendChild( "NumExtraStagesPassed", m_iNumExtraStagesPassed );
pGeneralDataNode->AppendChild( "NumExtraStagesFailed", m_iNumExtraStagesFailed );
pGeneralDataNode->AppendChild( "NumToasties", m_iNumToasties );
pGeneralDataNode->AppendChild( "TotalTapsAndHolds", m_iTotalTapsAndHolds );
pGeneralDataNode->AppendChild( "TotalJumps", m_iTotalJumps );
pGeneralDataNode->AppendChild( "TotalHolds", m_iTotalHolds );
pGeneralDataNode->AppendChild( "TotalRolls", m_iTotalRolls );
pGeneralDataNode->AppendChild( "TotalMines", m_iTotalMines );
pGeneralDataNode->AppendChild( "TotalHands", m_iTotalHands );
// Keep declared variables in a very local scope so they aren't
// accidentally used where they're not intended. There's a lot of
// copying and pasting in this code.
{
XNode* pDefaultModifiers = pGeneralDataNode->AppendChild("DefaultModifiers");
2006-01-22 01:00:06 +00:00
FOREACHM_CONST( RString, RString, m_sDefaultModifiers, it )
pDefaultModifiers->AppendChild( it->first, it->second );
}
{
XNode* pUnlocks = pGeneralDataNode->AppendChild("Unlocks");
FOREACHS_CONST( RString, m_UnlockedEntryIDs, it )
2007-06-03 02:39:13 +00:00
{
XNode *pEntry = pUnlocks->AppendChild("UnlockEntry");
RString sUnlockEntry = it->c_str();
pEntry->AppendAttr( "UnlockEntryID", sUnlockEntry );
2007-06-20 22:25:57 +00:00
if( !UNLOCK_AUTH_STRING.GetValue().empty() )
2007-06-03 02:39:13 +00:00
{
2007-06-20 22:25:57 +00:00
RString sUnlockAuth = BinaryToHex( CRYPTMAN->GetMD5ForString(sUnlockEntry + UNLOCK_AUTH_STRING.GetValue()) );
2007-06-03 02:39:13 +00:00
pEntry->AppendAttr( "Auth", sUnlockAuth );
}
}
}
{
XNode* pNumSongsPlayedByPlayMode = pGeneralDataNode->AppendChild("NumSongsPlayedByPlayMode");
FOREACH_ENUM( PlayMode, pm )
2004-02-22 02:51:27 +00:00
{
/* Don't save unplayed PlayModes. */
if( !m_iNumSongsPlayedByPlayMode[pm] )
continue;
pNumSongsPlayedByPlayMode->AppendChild( PlayModeToString(pm), m_iNumSongsPlayedByPlayMode[pm] );
2004-02-22 02:51:27 +00:00
}
}
{
XNode* pNumSongsPlayedByStyle = pGeneralDataNode->AppendChild("NumSongsPlayedByStyle");
FOREACHM_CONST( StyleID, int, m_iNumSongsPlayedByStyle, iter )
{
2004-07-17 21:49:32 +00:00
const StyleID &s = iter->first;
int iNumPlays = iter->second;
2004-07-17 21:49:32 +00:00
XNode *pStyleNode = s.CreateNode();
2007-02-11 07:40:45 +00:00
pStyleNode->AppendAttr(XNode::TEXT_ATTRIBUTE, iNumPlays );
2004-07-17 21:49:32 +00:00
pNumSongsPlayedByStyle->AppendChild( pStyleNode );
}
}
{
XNode* pNumSongsPlayedByDifficulty = pGeneralDataNode->AppendChild("NumSongsPlayedByDifficulty");
FOREACH_ENUM( Difficulty, dc )
2004-02-22 04:20:20 +00:00
{
if( !m_iNumSongsPlayedByDifficulty[dc] )
continue;
pNumSongsPlayedByDifficulty->AppendChild( DifficultyToString(dc), m_iNumSongsPlayedByDifficulty[dc] );
2004-02-22 04:20:20 +00:00
}
}
{
XNode* pNumSongsPlayedByMeter = pGeneralDataNode->AppendChild("NumSongsPlayedByMeter");
for( int i=0; i<MAX_METER+1; i++ )
2004-02-22 04:20:20 +00:00
{
if( !m_iNumSongsPlayedByMeter[i] )
continue;
pNumSongsPlayedByMeter->AppendChild( ssprintf("Meter%d",i), m_iNumSongsPlayedByMeter[i] );
2004-02-22 04:20:20 +00:00
}
}
pGeneralDataNode->AppendChild( "NumTotalSongsPlayed", m_iNumTotalSongsPlayed );
{
2005-02-15 22:08:42 +00:00
XNode* pNumStagesPassedByPlayMode = pGeneralDataNode->AppendChild("NumStagesPassedByPlayMode");
FOREACH_ENUM( PlayMode, pm )
{
2005-02-15 22:08:42 +00:00
/* Don't save unplayed PlayModes. */
if( !m_iNumStagesPassedByPlayMode[pm] )
continue;
2005-02-15 22:08:42 +00:00
pNumStagesPassedByPlayMode->AppendChild( PlayModeToString(pm), m_iNumStagesPassedByPlayMode[pm] );
}
}
{
2005-02-15 22:08:42 +00:00
XNode* pNumStagesPassedByGrade = pGeneralDataNode->AppendChild("NumStagesPassedByGrade");
FOREACH_ENUM( Grade, g )
{
2005-02-15 22:08:42 +00:00
if( !m_iNumStagesPassedByGrade[g] )
continue;
2005-02-15 22:08:42 +00:00
pNumStagesPassedByGrade->AppendChild( GradeToString(g), m_iNumStagesPassedByGrade[g] );
}
}
2004-02-22 20:44:33 +00:00
return pGeneralDataNode;
}
2006-01-22 01:00:06 +00:00
ProfileLoadResult Profile::LoadEditableDataFromDir( RString sDir )
{
2006-01-22 01:00:06 +00:00
RString fn = sDir + EDITABLE_INI;
2004-02-22 02:41:10 +00:00
//
// Don't load unreasonably large editable.xml files.
//
int iBytes = FILEMAN->GetFileSizeInBytes( fn );
2004-04-23 00:26:51 +00:00
if( iBytes > MAX_EDITABLE_INI_SIZE_BYTES )
2004-02-22 02:41:10 +00:00
{
LOG->Warn( "The file '%s' is unreasonably large. It won't be loaded.", fn.c_str() );
return ProfileLoadResult_FailedTampered;
2004-02-22 02:41:10 +00:00
}
2005-04-24 22:56:05 +00:00
if( !IsAFile(fn) )
return ProfileLoadResult_FailedNoProfile;
2004-02-22 02:41:10 +00:00
IniFile ini;
2004-05-23 02:27:51 +00:00
ini.ReadFile( fn );
2004-02-22 02:41:10 +00:00
2005-08-14 02:00:27 +00:00
ini.GetValue( "Editable", "DisplayName", m_sDisplayName );
ini.GetValue( "Editable", "CharacterID", m_sCharacterID );
2006-04-05 03:08:42 +00:00
ini.GetValue( "Editable", "LastUsedHighScoreName", m_sLastUsedHighScoreName );
2005-08-14 02:00:27 +00:00
ini.GetValue( "Editable", "WeightPounds", m_iWeightPounds );
// This is data that the user can change, so we have to validate it.
2005-12-20 08:35:47 +00:00
wstring wstr = RStringToWstring(m_sDisplayName);
2005-07-13 19:11:24 +00:00
if( wstr.size() > PROFILE_MAX_DISPLAY_NAME_LENGTH )
wstr = wstr.substr(0, PROFILE_MAX_DISPLAY_NAME_LENGTH);
2005-12-20 08:35:47 +00:00
m_sDisplayName = WStringToRString(wstr);
// TODO: strip invalid chars?
2004-02-23 04:53:02 +00:00
if( m_iWeightPounds != 0 )
CLAMP( m_iWeightPounds, 20, 1000 );
2005-04-24 22:56:05 +00:00
return ProfileLoadResult_Success;
2004-02-10 09:42:01 +00:00
}
void Profile::LoadGeneralDataFromNode( const XNode* pNode )
{
2006-10-02 06:12:42 +00:00
ASSERT( pNode->GetName() == "GeneralData" );
2006-01-22 01:00:06 +00:00
RString s;
const XNode* pTemp;
2004-03-13 22:18:09 +00:00
2006-04-05 03:08:42 +00:00
pNode->GetChildValue( "DisplayName", m_sDisplayName );
pNode->GetChildValue( "CharacterID", m_sCharacterID );
pNode->GetChildValue( "LastUsedHighScoreName", m_sLastUsedHighScoreName );
2006-04-05 03:08:42 +00:00
pNode->GetChildValue( "WeightPounds", m_iWeightPounds );
pNode->GetChildValue( "Guid", m_sGuid );
pNode->GetChildValue( "SortOrder", s ); m_SortOrder = StringToSortOrder( s );
pNode->GetChildValue( "LastDifficulty", s ); m_LastDifficulty = StringToDifficulty( s );
2006-10-07 22:49:04 +00:00
pNode->GetChildValue( "LastCourseDifficulty", s ); m_LastCourseDifficulty = StringToDifficulty( s );
2008-03-24 12:50:16 +00:00
pNode->GetChildValue( "LastStepsType", s ); m_LastStepsType = GameManager::StringToStepsType( s );
pTemp = pNode->GetChild( "Song" ); if( pTemp ) m_lastSong.LoadFromNode( pTemp );
2006-04-05 03:08:42 +00:00
pTemp = pNode->GetChild( "Course" ); if( pTemp ) m_lastCourse.LoadFromNode( pTemp );
pNode->GetChildValue( "TotalPlays", m_iTotalPlays );
pNode->GetChildValue( "TotalPlaySeconds", m_iTotalPlaySeconds );
pNode->GetChildValue( "TotalGameplaySeconds", m_iTotalGameplaySeconds );
2004-02-22 20:58:39 +00:00
pNode->GetChildValue( "TotalCaloriesBurned", m_fTotalCaloriesBurned );
2006-10-12 02:03:47 +00:00
pNode->GetChildValue( "GoalType", *ConvertValue<int>(&m_GoalType) );
2006-04-05 03:08:42 +00:00
pNode->GetChildValue( "GoalCalories", m_iGoalCalories );
pNode->GetChildValue( "GoalSeconds", m_iGoalSeconds );
2004-04-18 05:46:43 +00:00
pNode->GetChildValue( "LastPlayedMachineGuid", m_sLastPlayedMachineGuid );
pNode->GetChildValue( "LastPlayedDate", s ); m_LastPlayedDate.FromString( s );
2006-04-05 03:08:42 +00:00
pNode->GetChildValue( "TotalDancePoints", m_iTotalDancePoints );
pNode->GetChildValue( "NumExtraStagesPassed", m_iNumExtraStagesPassed );
pNode->GetChildValue( "NumExtraStagesFailed", m_iNumExtraStagesFailed );
2006-04-05 03:08:42 +00:00
pNode->GetChildValue( "NumToasties", m_iNumToasties );
pNode->GetChildValue( "TotalTapsAndHolds", m_iTotalTapsAndHolds );
pNode->GetChildValue( "TotalJumps", m_iTotalJumps );
pNode->GetChildValue( "TotalHolds", m_iTotalHolds );
pNode->GetChildValue( "TotalRolls", m_iTotalRolls );
pNode->GetChildValue( "TotalMines", m_iTotalMines );
pNode->GetChildValue( "TotalHands", m_iTotalHands );
{
const XNode* pDefaultModifiers = pNode->GetChild("DefaultModifiers");
if( pDefaultModifiers )
{
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pDefaultModifiers, game_type )
{
2007-02-11 06:26:06 +00:00
game_type->GetTextValue( m_sDefaultModifiers[game_type->GetName()] );
}
}
}
{
const XNode* pUnlocks = pNode->GetChild("Unlocks");
if( pUnlocks )
{
FOREACH_CONST_Child( pUnlocks, unlock )
{
RString sUnlockEntryID;
2007-06-03 02:39:13 +00:00
if( !unlock->GetAttrValue("UnlockEntryID",sUnlockEntryID) )
continue;
2007-06-20 22:25:57 +00:00
if( !UNLOCK_AUTH_STRING.GetValue().empty() )
2007-06-03 02:39:13 +00:00
{
RString sUnlockAuth;
if( !unlock->GetAttrValue("Auth", sUnlockAuth) )
continue;
2007-06-20 22:25:57 +00:00
RString sExpectedUnlockAuth = BinaryToHex( CRYPTMAN->GetMD5ForString(sUnlockEntryID + UNLOCK_AUTH_STRING.GetValue()) );
2007-06-03 02:39:13 +00:00
if( sUnlockAuth != sExpectedUnlockAuth )
continue;
}
m_UnlockedEntryIDs.insert( sUnlockEntryID );
}
}
}
{
2004-07-23 02:27:07 +00:00
const XNode* pNumSongsPlayedByPlayMode = pNode->GetChild("NumSongsPlayedByPlayMode");
if( pNumSongsPlayedByPlayMode )
FOREACH_ENUM( PlayMode, pm )
pNumSongsPlayedByPlayMode->GetChildValue( PlayModeToString(pm), m_iNumSongsPlayedByPlayMode[pm] );
}
{
2004-07-23 02:27:07 +00:00
const XNode* pNumSongsPlayedByStyle = pNode->GetChild("NumSongsPlayedByStyle");
if( pNumSongsPlayedByStyle )
2004-02-22 07:07:03 +00:00
{
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pNumSongsPlayedByStyle, style )
{
2006-10-02 06:12:42 +00:00
if( style->GetName() != "Style" )
continue;
2004-07-17 21:49:32 +00:00
StyleID s;
s.LoadFromNode( style );
2004-07-17 21:49:32 +00:00
if( !s.IsValid() )
2004-02-22 10:10:00 +00:00
WARN_AND_CONTINUE;
2007-02-11 06:26:06 +00:00
style->GetTextValue( m_iNumSongsPlayedByStyle[s] );
}
2004-02-22 07:07:03 +00:00
}
}
{
2004-07-23 02:27:07 +00:00
const XNode* pNumSongsPlayedByDifficulty = pNode->GetChild("NumSongsPlayedByDifficulty");
if( pNumSongsPlayedByDifficulty )
FOREACH_ENUM( Difficulty, dc )
pNumSongsPlayedByDifficulty->GetChildValue( DifficultyToString(dc), m_iNumSongsPlayedByDifficulty[dc] );
}
{
2004-07-23 02:27:07 +00:00
const XNode* pNumSongsPlayedByMeter = pNode->GetChild("NumSongsPlayedByMeter");
if( pNumSongsPlayedByMeter )
for( int i=0; i<MAX_METER+1; i++ )
pNumSongsPlayedByMeter->GetChildValue( ssprintf("Meter%d",i), m_iNumSongsPlayedByMeter[i] );
}
pNode->GetChildValue("NumTotalSongsPlayed", m_iNumTotalSongsPlayed );
{
2004-08-30 06:07:14 +00:00
const XNode* pNumStagesPassedByGrade = pNode->GetChild("NumStagesPassedByGrade");
if( pNumStagesPassedByGrade )
FOREACH_ENUM( Grade, g )
2004-08-30 06:07:14 +00:00
pNumStagesPassedByGrade->GetChildValue( GradeToString(g), m_iNumStagesPassedByGrade[g] );
}
{
2004-08-30 06:07:14 +00:00
const XNode* pNumStagesPassedByPlayMode = pNode->GetChild("NumStagesPassedByPlayMode");
if( pNumStagesPassedByPlayMode )
FOREACH_ENUM( PlayMode, pm )
2004-08-30 06:07:14 +00:00
pNumStagesPassedByPlayMode->GetChildValue( PlayModeToString(pm), m_iNumStagesPassedByPlayMode[pm] );
}
2004-02-22 20:44:33 +00:00
}
2005-04-25 11:42:19 +00:00
void Profile::AddStepTotals( int iTotalTapsAndHolds, int iTotalJumps, int iTotalHolds, int iTotalRolls, int iTotalMines, int iTotalHands, float fCaloriesBurned )
2004-02-22 19:51:46 +00:00
{
2004-02-22 19:54:59 +00:00
m_iTotalTapsAndHolds += iTotalTapsAndHolds;
m_iTotalJumps += iTotalJumps;
m_iTotalHolds += iTotalHolds;
2005-04-25 11:42:19 +00:00
m_iTotalRolls += iTotalRolls;
2004-02-22 19:54:59 +00:00
m_iTotalMines += iTotalMines;
m_iTotalHands += iTotalHands;
2004-02-22 19:51:46 +00:00
m_fTotalCaloriesBurned += fCaloriesBurned;
2004-02-22 23:29:13 +00:00
DateTime date = DateTime::GetNowDate();
m_mapDayToCaloriesBurned[date].fCals += fCaloriesBurned;
2004-02-22 19:51:46 +00:00
}
XNode* Profile::SaveSongScoresCreateNode() const
2004-02-10 09:42:01 +00:00
{
CHECKPOINT;
2004-02-10 10:06:34 +00:00
const Profile* pProfile = this;
2004-02-10 09:42:01 +00:00
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "SongScores" );
2004-02-10 09:42:01 +00:00
2005-06-02 22:26:11 +00:00
FOREACHM_CONST( SongID, HighScoresForASong, m_SongHighScores, i )
{
const SongID &songID = i->first;
const HighScoresForASong &hsSong = i->second;
2004-02-10 09:42:01 +00:00
// skip songs that have never been played
if( pProfile->GetSongNumTimesPlayed(songID) == 0 )
2004-02-10 09:42:01 +00:00
continue;
2004-05-23 21:08:03 +00:00
XNode* pSongNode = pNode->AppendChild( songID.CreateNode() );
2004-02-10 09:42:01 +00:00
int jCheck2 = hsSong.m_StepsHighScores.size();
int jCheck1 = 0;
2005-06-02 22:26:11 +00:00
FOREACHM_CONST( StepsID, HighScoresForASteps, hsSong.m_StepsHighScores, j )
{
jCheck1++;
2005-05-28 08:52:57 +00:00
ASSERT( jCheck1 <= jCheck2 );
const StepsID &stepsID = j->first;
const HighScoresForASteps &hsSteps = j->second;
2005-04-25 09:03:24 +00:00
const HighScoreList &hsl = hsSteps.hsl;
2004-02-10 09:42:01 +00:00
// skip steps that have never been played
2005-04-25 22:44:32 +00:00
if( hsl.GetNumTimesPlayed() == 0 )
2004-02-10 09:42:01 +00:00
continue;
2004-05-23 21:08:03 +00:00
XNode* pStepsNode = pSongNode->AppendChild( stepsID.CreateNode() );
2004-02-10 09:42:01 +00:00
pStepsNode->AppendChild( hsl.CreateNode() );
}
}
return pNode;
2004-02-10 09:42:01 +00:00
}
2005-01-07 09:09:23 +00:00
void Profile::LoadSongScoresFromNode( const XNode* pSongScores )
2004-02-10 09:42:01 +00:00
{
2004-05-23 21:08:03 +00:00
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pSongScores->GetName() == "SongScores" );
2004-02-10 09:42:01 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pSongScores, pSong )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pSong->GetName() != "Song" )
2004-02-10 09:42:01 +00:00
continue;
SongID songID;
2005-01-07 09:09:23 +00:00
songID.LoadFromNode( pSong );
if( !songID.IsValid() )
continue;
2004-02-10 09:42:01 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pSong, pSteps )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pSteps->GetName() != "Steps" )
2004-02-10 09:42:01 +00:00
continue;
StepsID stepsID;
2005-01-07 09:09:23 +00:00
stepsID.LoadFromNode( pSteps );
if( !stepsID.IsValid() )
2004-02-10 09:42:01 +00:00
WARN_AND_CONTINUE;
2005-01-07 09:09:23 +00:00
const XNode *pHighScoreListNode = pSteps->GetChild("HighScoreList");
2004-02-10 09:42:01 +00:00
if( pHighScoreListNode == NULL )
WARN_AND_CONTINUE;
2005-04-25 09:03:24 +00:00
HighScoreList &hsl = m_SongHighScores[songID].m_StepsHighScores[stepsID].hsl;
2004-02-10 09:42:01 +00:00
hsl.LoadFromNode( pHighScoreListNode );
}
}
}
XNode* Profile::SaveCourseScoresCreateNode() const
2004-02-10 09:42:01 +00:00
{
CHECKPOINT;
2004-02-10 10:06:34 +00:00
const Profile* pProfile = this;
2004-02-10 09:42:01 +00:00
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "CourseScores" );
2004-02-10 09:42:01 +00:00
2005-06-02 22:26:11 +00:00
FOREACHM_CONST( CourseID, HighScoresForACourse, m_CourseHighScores, i )
2004-02-10 09:42:01 +00:00
{
2004-05-23 21:08:03 +00:00
const CourseID &courseID = i->first;
const HighScoresForACourse &hsCourse = i->second;
2004-02-10 09:42:01 +00:00
// skip courses that have never been played
2004-05-23 21:08:03 +00:00
if( pProfile->GetCourseNumTimesPlayed(courseID) == 0 )
2004-02-10 09:42:01 +00:00
continue;
2004-05-23 21:08:03 +00:00
XNode* pCourseNode = pNode->AppendChild( courseID.CreateNode() );
2004-02-10 09:42:01 +00:00
2005-06-02 22:26:11 +00:00
FOREACHM_CONST( TrailID, HighScoresForATrail, hsCourse.m_TrailHighScores, j )
2004-02-10 09:42:01 +00:00
{
2004-05-23 21:08:03 +00:00
const TrailID &trailID = j->first;
const HighScoresForATrail &hsTrail = j->second;
2005-04-25 09:03:24 +00:00
const HighScoreList &hsl = hsTrail.hsl;
2004-02-22 06:04:01 +00:00
2004-05-23 21:08:03 +00:00
// skip steps that have never been played
2005-04-25 22:44:32 +00:00
if( hsl.GetNumTimesPlayed() == 0 )
2004-05-23 21:08:03 +00:00
continue;
XNode* pTrailNode = pCourseNode->AppendChild( trailID.CreateNode() );
2004-02-22 06:04:01 +00:00
2004-05-23 21:08:03 +00:00
pTrailNode->AppendChild( hsl.CreateNode() );
2004-02-10 09:42:01 +00:00
}
}
return pNode;
2004-02-10 09:42:01 +00:00
}
2005-01-07 09:09:23 +00:00
void Profile::LoadCourseScoresFromNode( const XNode* pCourseScores )
2004-02-10 09:42:01 +00:00
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pCourseScores->GetName() == "CourseScores" );
2004-02-10 09:42:01 +00:00
vector<Course*> vpAllCourses;
SONGMAN->GetAllCourses( vpAllCourses, true );
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pCourseScores, pCourse )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pCourse->GetName() != "Course" )
2004-02-10 09:42:01 +00:00
continue;
2004-02-22 04:01:12 +00:00
2004-05-23 21:08:03 +00:00
CourseID courseID;
2005-01-07 09:09:23 +00:00
courseID.LoadFromNode( pCourse );
2004-05-23 21:08:03 +00:00
if( !courseID.IsValid() )
2004-02-22 04:01:12 +00:00
WARN_AND_CONTINUE;
// Backward compatability hack to fix importing scores of old style
// courses that weren't in group folder but have now been moved into
// a group folder:
// If the courseID doesn't resolve, then take the file name part of sPath
// and search for matches of just the file name.
{
Course *pC = courseID.ToCourse();
if( pC == NULL )
{
2006-01-22 01:00:06 +00:00
RString sDir, sFName, sExt;
2006-10-17 08:58:58 +00:00
splitpath( courseID.GetPath(), sDir, sFName, sExt );
2006-01-22 01:00:06 +00:00
RString sFullFileName = sFName + sExt;
FOREACH_CONST( Course*, vpAllCourses, c )
{
2006-01-22 01:00:06 +00:00
RString sOther = (*c)->m_sPath.Right(sFullFileName.size());
if( sFullFileName.CompareNoCase(sOther) == 0 )
{
pC = *c;
courseID.FromCourse( pC );
break;
}
}
}
}
2004-02-22 04:01:12 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pCourse, pTrail )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pTrail->GetName() != "Trail" )
2004-02-10 09:42:01 +00:00
continue;
2004-05-23 21:08:03 +00:00
TrailID trailID;
2005-01-07 09:09:23 +00:00
trailID.LoadFromNode( pTrail );
2004-05-23 21:08:03 +00:00
if( !trailID.IsValid() )
2004-02-22 04:01:12 +00:00
WARN_AND_CONTINUE;
2004-02-22 06:04:01 +00:00
2005-01-07 09:09:23 +00:00
const XNode *pHighScoreListNode = pTrail->GetChild("HighScoreList");
2004-05-23 21:08:03 +00:00
if( pHighScoreListNode == NULL )
WARN_AND_CONTINUE;
2005-04-25 09:03:24 +00:00
HighScoreList &hsl = m_CourseHighScores[courseID].m_TrailHighScores[trailID].hsl;
2004-05-23 21:08:03 +00:00
hsl.LoadFromNode( pHighScoreListNode );
2004-02-10 09:42:01 +00:00
}
}
}
XNode* Profile::SaveCategoryScoresCreateNode() const
2004-02-10 09:42:01 +00:00
{
CHECKPOINT;
2004-02-10 10:06:34 +00:00
const Profile* pProfile = this;
2004-02-10 09:42:01 +00:00
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "CategoryScores" );
2004-02-10 09:42:01 +00:00
FOREACH_ENUM( StepsType,st )
2004-02-10 09:42:01 +00:00
{
// skip steps types that have never been played
if( pProfile->GetCategoryNumTimesPlayed( st ) == 0 )
continue;
XNode* pStepsTypeNode = pNode->AppendChild( "StepsType" );
pStepsTypeNode->AppendAttr( "Type", GameManager::GetStepsTypeInfo(st).szName );
2004-02-10 09:42:01 +00:00
FOREACH_ENUM( RankingCategory,rc )
2004-02-10 09:42:01 +00:00
{
// skip steps types/categories that have never been played
2005-04-25 22:44:32 +00:00
if( pProfile->GetCategoryHighScoreList(st,rc).GetNumTimesPlayed() == 0 )
2004-02-10 09:42:01 +00:00
continue;
XNode* pRankingCategoryNode = pStepsTypeNode->AppendChild( "RankingCategory" );
pRankingCategoryNode->AppendAttr( "Type", RankingCategoryToString(rc) );
2004-02-10 09:42:01 +00:00
2004-02-10 10:06:34 +00:00
const HighScoreList &hsl = pProfile->GetCategoryHighScoreList( (StepsType)st, (RankingCategory)rc );
2004-02-10 09:42:01 +00:00
pRankingCategoryNode->AppendChild( hsl.CreateNode() );
}
}
return pNode;
2004-02-10 09:42:01 +00:00
}
2005-01-07 09:09:23 +00:00
void Profile::LoadCategoryScoresFromNode( const XNode* pCategoryScores )
2004-02-10 09:42:01 +00:00
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pCategoryScores->GetName() == "CategoryScores" );
2004-02-15 04:47:32 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pCategoryScores, pStepsType )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pStepsType->GetName() != "StepsType" )
2004-02-10 09:42:01 +00:00
continue;
2006-01-22 01:00:06 +00:00
RString str;
2005-01-07 09:09:23 +00:00
if( !pStepsType->GetAttrValue( "Type", str ) )
WARN_AND_CONTINUE;
2004-07-12 02:19:24 +00:00
StepsType st = GameManager::StringToStepsType( str );
2006-09-26 20:28:46 +00:00
if( st == StepsType_Invalid )
2004-09-05 06:25:13 +00:00
WARN_AND_CONTINUE_M( str );
2004-02-10 09:42:01 +00:00
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pStepsType, pRadarCategory )
2004-02-10 09:42:01 +00:00
{
2006-10-02 06:12:42 +00:00
if( pRadarCategory->GetName() != "RankingCategory" )
2004-02-10 09:42:01 +00:00
continue;
2005-01-07 09:09:23 +00:00
if( !pRadarCategory->GetAttrValue( "Type", str ) )
WARN_AND_CONTINUE;
2004-02-22 05:26:02 +00:00
RankingCategory rc = StringToRankingCategory( str );
2006-09-26 20:49:10 +00:00
if( rc == RankingCategory_Invalid )
2004-09-05 06:25:13 +00:00
WARN_AND_CONTINUE_M( str );
2004-02-10 09:42:01 +00:00
2005-01-07 09:09:23 +00:00
const XNode *pHighScoreListNode = pRadarCategory->GetChild("HighScoreList");
2004-02-10 09:42:01 +00:00
if( pHighScoreListNode == NULL )
WARN_AND_CONTINUE;
HighScoreList &hsl = this->GetCategoryHighScoreList( st, rc );
hsl.LoadFromNode( pHighScoreListNode );
}
}
}
2006-01-22 01:00:06 +00:00
void Profile::SaveStatsWebPageToDir( RString sDir ) const
2004-02-10 09:42:01 +00:00
{
ASSERT( PROFILEMAN );
2004-08-20 05:22:46 +00:00
FileCopy( THEME->GetPathO("Profile",STATS_XSL), sDir+STATS_XSL );
FileCopy( THEME->GetPathO("Profile",COMMON_XSL), sDir+COMMON_XSL );
if( g_bCopyCatalogToProfiles && g_bWriteCatalog )
{
FileCopy( CATALOG_XML_FILE, sDir+CATALOG_XML );
FileCopy( THEME->GetPathO("Profile",CATALOG_XSL), sDir+CATALOG_XSL );
}
2004-02-10 09:42:01 +00:00
}
2004-02-16 05:35:06 +00:00
2006-01-22 01:00:06 +00:00
void Profile::SaveMachinePublicKeyToDir( RString sDir ) const
2004-02-16 05:35:06 +00:00
{
if( PREFSMAN->m_bSignProfileData && IsAFile(CRYPTMAN->GetPublicKeyFileName()) )
2004-02-23 08:09:21 +00:00
FileCopy( CRYPTMAN->GetPublicKeyFileName(), sDir+PUBLIC_KEY_FILE );
2004-02-16 05:35:06 +00:00
}
2004-02-17 01:16:57 +00:00
2004-06-12 07:01:07 +00:00
void Profile::AddScreenshot( const Screenshot &screenshot )
2004-02-17 01:16:57 +00:00
{
m_vScreenshots.push_back( screenshot );
}
2005-01-07 09:09:23 +00:00
void Profile::LoadScreenshotDataFromNode( const XNode* pScreenshotData )
2004-02-17 01:16:57 +00:00
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pScreenshotData->GetName() == "ScreenshotData" );
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pScreenshotData, pScreenshot )
2004-02-17 01:16:57 +00:00
{
2006-10-02 06:12:42 +00:00
if( pScreenshot->GetName() != "Screenshot" )
WARN_AND_CONTINUE_M( pScreenshot->GetName() );
2004-02-17 01:16:57 +00:00
Screenshot ss;
2005-01-07 09:09:23 +00:00
ss.LoadFromNode( pScreenshot );
2004-02-17 01:16:57 +00:00
m_vScreenshots.push_back( ss );
}
}
XNode* Profile::SaveScreenshotDataCreateNode() const
2004-02-17 01:16:57 +00:00
{
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "ScreenshotData" );
2004-02-17 01:16:57 +00:00
2004-06-12 07:01:07 +00:00
FOREACH_CONST( Screenshot, m_vScreenshots, ss )
2004-02-17 01:16:57 +00:00
{
2004-06-14 01:10:26 +00:00
pNode->AppendChild( ss->CreateNode() );
2004-02-17 01:16:57 +00:00
}
return pNode;
2004-02-17 01:16:57 +00:00
}
2004-02-22 23:29:13 +00:00
2005-01-07 09:09:23 +00:00
void Profile::LoadCalorieDataFromNode( const XNode* pCalorieData )
2004-02-22 23:29:13 +00:00
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pCalorieData->GetName() == "CalorieData" );
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pCalorieData, pCaloriesBurned )
2004-02-22 23:29:13 +00:00
{
2006-10-02 06:12:42 +00:00
if( pCaloriesBurned->GetName() != "CaloriesBurned" )
WARN_AND_CONTINUE_M( pCaloriesBurned->GetName() );
2004-02-22 23:29:13 +00:00
2006-01-22 01:00:06 +00:00
RString sDate;
2005-01-07 09:09:23 +00:00
if( !pCaloriesBurned->GetAttrValue("Date",sDate) )
2004-02-22 23:29:13 +00:00
WARN_AND_CONTINUE;
2004-07-12 06:39:13 +00:00
DateTime date;
if( !date.FromString(sDate) )
2004-09-05 06:25:13 +00:00
WARN_AND_CONTINUE_M( sDate );
2004-02-22 23:29:13 +00:00
float fCaloriesBurned = 0;
2007-02-11 06:26:06 +00:00
pCaloriesBurned->GetTextValue(fCaloriesBurned);
2004-02-22 23:29:13 +00:00
m_mapDayToCaloriesBurned[date].fCals = fCaloriesBurned;
2004-02-22 23:29:13 +00:00
}
}
XNode* Profile::SaveCalorieDataCreateNode() const
{
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "CalorieData" );
2004-02-22 23:29:13 +00:00
FOREACHM_CONST( DateTime, Calories, m_mapDayToCaloriesBurned, i )
2004-02-22 23:29:13 +00:00
{
XNode* pCaloriesBurned = pNode->AppendChild( "CaloriesBurned", i->second.fCals );
2004-02-22 23:29:13 +00:00
2004-07-18 21:54:19 +00:00
pCaloriesBurned->AppendAttr( "Date", i->first.GetString() );
2004-02-22 23:29:13 +00:00
}
return pNode;
}
2004-07-12 06:39:13 +00:00
float Profile::GetCaloriesBurnedForDay( DateTime day ) const
2004-02-22 23:29:13 +00:00
{
2004-07-12 06:39:13 +00:00
day.StripTime();
map<DateTime,Calories>::const_iterator i = m_mapDayToCaloriesBurned.find( day );
2004-02-22 23:29:13 +00:00
if( i == m_mapDayToCaloriesBurned.end() )
return 0;
else
return i->second.fCals;
2004-02-22 23:29:13 +00:00
}
2004-03-07 04:34:49 +00:00
2004-04-22 22:01:38 +00:00
XNode* Profile::HighScoreForASongAndSteps::CreateNode() const
{
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "HighScoreForASongAndSteps" );
2004-04-22 22:01:38 +00:00
pNode->AppendChild( songID.CreateNode() );
pNode->AppendChild( stepsID.CreateNode() );
pNode->AppendChild( hs.CreateNode() );
2004-04-22 22:01:38 +00:00
return pNode;
}
2004-04-22 22:01:38 +00:00
void Profile::HighScoreForASongAndSteps::LoadFromNode( const XNode* pNode )
{
Unset();
2006-10-02 06:12:42 +00:00
ASSERT( pNode->GetName() == "HighScoreForASongAndSteps" );
2004-07-23 02:27:07 +00:00
const XNode* p;
2004-04-26 23:10:16 +00:00
if( (p = pNode->GetChild("Song")) )
2004-04-22 22:01:38 +00:00
songID.LoadFromNode( p );
2004-04-26 23:10:16 +00:00
if( (p = pNode->GetChild("Steps")) )
2004-04-22 22:01:38 +00:00
stepsID.LoadFromNode( p );
2004-04-26 23:10:16 +00:00
if( (p = pNode->GetChild("HighScore")) )
2004-04-22 22:01:38 +00:00
hs.LoadFromNode( p );
}
2005-01-07 09:09:23 +00:00
void Profile::LoadRecentSongScoresFromNode( const XNode* pRecentSongScores )
2004-04-22 22:01:38 +00:00
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pRecentSongScores->GetName() == "RecentSongScores" );
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pRecentSongScores, p )
2004-04-22 22:01:38 +00:00
{
2006-10-02 06:12:42 +00:00
if( p->GetName() == "HighScoreForASongAndSteps" )
2004-04-22 22:01:38 +00:00
{
HighScoreForASongAndSteps h;
2005-01-07 09:09:23 +00:00
h.LoadFromNode( p );
2004-05-08 10:12:10 +00:00
m_vRecentStepsScores.push_back( h );
2004-04-22 22:01:38 +00:00
}
else
2005-01-07 09:09:23 +00:00
{
2006-10-02 06:12:42 +00:00
WARN_AND_CONTINUE_M( p->GetName() );
2005-01-07 09:09:23 +00:00
}
2004-04-22 22:01:38 +00:00
}
}
2004-05-08 10:12:10 +00:00
XNode* Profile::SaveRecentSongScoresCreateNode() const
2004-04-22 22:01:38 +00:00
{
CHECKPOINT;
2004-04-22 22:01:38 +00:00
const Profile* pProfile = this;
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "RecentSongScores" );
FOREACHD_CONST( HighScoreForASongAndSteps, m_vRecentStepsScores, i )
pNode->AppendChild( i->CreateNode() );
2004-04-22 22:01:38 +00:00
return pNode;
}
2004-05-08 10:12:10 +00:00
void Profile::AddStepsRecentScore( const Song* pSong, const Steps* pSteps, HighScore hs )
2004-04-22 22:01:38 +00:00
{
2006-09-14 21:30:35 +00:00
ASSERT( pSong );
ASSERT( pSteps );
2004-04-22 22:01:38 +00:00
HighScoreForASongAndSteps h;
h.songID.FromSong( pSong );
2006-09-14 21:30:35 +00:00
ASSERT( h.songID.IsValid() );
2004-04-22 22:01:38 +00:00
h.stepsID.FromSteps( pSteps );
2006-09-14 21:30:35 +00:00
ASSERT( h.stepsID.IsValid() );
2004-04-22 22:01:38 +00:00
h.hs = hs;
2004-05-08 10:12:10 +00:00
m_vRecentStepsScores.push_back( h );
int iMaxRecentScoresToSave = IsMachine() ? PREFSMAN->m_iMaxRecentScoresForMachine : PREFSMAN->m_iMaxRecentScoresForPlayer;
int iNumToErase = m_vRecentStepsScores.size() - iMaxRecentScoresToSave;
if( iNumToErase > 0 )
m_vRecentStepsScores.erase( m_vRecentStepsScores.begin(), m_vRecentStepsScores.begin() + iNumToErase );
2004-04-22 22:01:38 +00:00
}
2004-07-11 23:17:01 +00:00
XNode* Profile::HighScoreForACourseAndTrail::CreateNode() const
{
XNode* pNode = new XNode( "HighScoreForACourseAndTrail" );
2004-04-22 22:01:38 +00:00
pNode->AppendChild( courseID.CreateNode() );
2004-07-11 23:17:01 +00:00
pNode->AppendChild( trailID.CreateNode() );
pNode->AppendChild( hs.CreateNode() );
return pNode;
}
2004-07-11 23:17:01 +00:00
void Profile::HighScoreForACourseAndTrail::LoadFromNode( const XNode* pNode )
{
Unset();
2006-10-02 06:12:42 +00:00
ASSERT( pNode->GetName() == "HighScoreForACourseAndTrail" );
2004-07-23 02:27:07 +00:00
const XNode* p;
2004-04-26 23:10:16 +00:00
if( (p = pNode->GetChild("Course")) )
2004-04-22 22:01:38 +00:00
courseID.LoadFromNode( p );
2004-07-11 23:17:01 +00:00
if( (p = pNode->GetChild("Trail")) )
trailID.LoadFromNode( p );
2004-04-26 23:10:16 +00:00
if( (p = pNode->GetChild("HighScore")) )
hs.LoadFromNode( p );
}
2005-01-07 09:09:23 +00:00
void Profile::LoadRecentCourseScoresFromNode( const XNode* pRecentCourseScores )
{
CHECKPOINT;
2006-10-02 06:12:42 +00:00
ASSERT( pRecentCourseScores->GetName() == "RecentCourseScores" );
2005-01-07 09:09:23 +00:00
FOREACH_CONST_Child( pRecentCourseScores, p )
{
2006-10-02 06:12:42 +00:00
if( p->GetName() == "HighScoreForACourseAndTrail" )
{
2004-07-11 23:17:01 +00:00
HighScoreForACourseAndTrail h;
2005-01-07 09:09:23 +00:00
h.LoadFromNode( p );
2004-05-08 10:12:10 +00:00
m_vRecentCourseScores.push_back( h );
}
else
2005-01-07 09:09:23 +00:00
{
2006-10-02 06:12:42 +00:00
WARN_AND_CONTINUE_M( p->GetName() );
2005-01-07 09:09:23 +00:00
}
}
}
2004-05-08 10:12:10 +00:00
XNode* Profile::SaveRecentCourseScoresCreateNode() const
{
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "RecentCourseScores" );
FOREACHD_CONST( HighScoreForACourseAndTrail, m_vRecentCourseScores, i )
pNode->AppendChild( i->CreateNode() );
return pNode;
}
2004-05-23 21:08:03 +00:00
void Profile::AddCourseRecentScore( const Course* pCourse, const Trail* pTrail, HighScore hs )
{
2004-07-11 23:17:01 +00:00
HighScoreForACourseAndTrail h;
2004-04-22 22:01:38 +00:00
h.courseID.FromCourse( pCourse );
2004-05-23 21:08:03 +00:00
h.trailID.FromTrail( pTrail );
h.hs = hs;
2004-05-08 10:12:10 +00:00
m_vRecentCourseScores.push_back( h );
int iMaxRecentScoresToSave = IsMachine() ? PREFSMAN->m_iMaxRecentScoresForMachine : PREFSMAN->m_iMaxRecentScoresForPlayer;
int iNumToErase = m_vRecentCourseScores.size() - iMaxRecentScoresToSave;
if( iNumToErase > 0 )
m_vRecentCourseScores.erase( m_vRecentCourseScores.begin(), m_vRecentCourseScores.begin() + iNumToErase );
}
2005-08-03 03:23:52 +00:00
StepsType Profile::GetLastPlayedStepsType() const
{
if( m_vRecentStepsScores.empty() )
2006-09-26 20:28:46 +00:00
return StepsType_Invalid;
2005-08-05 18:18:08 +00:00
const HighScoreForASongAndSteps &h = m_vRecentStepsScores.back();
return h.stepsID.GetStepsType();
2005-08-03 03:23:52 +00:00
}
2004-05-02 00:08:42 +00:00
const Profile::HighScoresForASong *Profile::GetHighScoresForASong( const SongID& songID ) const
{
2005-01-07 02:07:10 +00:00
map<SongID,HighScoresForASong>::const_iterator it;
2004-05-02 00:08:42 +00:00
it = m_SongHighScores.find( songID );
if( it == m_SongHighScores.end() )
return NULL;
return &it->second;
}
2004-05-23 21:08:03 +00:00
const Profile::HighScoresForACourse *Profile::GetHighScoresForACourse( const CourseID& courseID ) const
{
2005-01-07 02:07:10 +00:00
map<CourseID,HighScoresForACourse>::const_iterator it;
2004-05-23 21:08:03 +00:00
it = m_CourseHighScores.find( courseID );
if( it == m_CourseHighScores.end() )
return NULL;
return &it->second;
}
bool Profile::IsMachine() const
{
// TODO: Think of a better way to handle this
return this == PROFILEMAN->GetMachineProfile();
}
2004-05-31 21:55:14 +00:00
XNode* Profile::SaveCoinDataCreateNode() const
{
CHECKPOINT;
const Profile* pProfile = this;
ASSERT( pProfile );
2006-10-01 14:51:50 +00:00
XNode* pNode = new XNode( "CoinData" );
{
int coins[NUM_LAST_DAYS];
BOOKKEEPER->GetCoinsLastDays( coins );
XNode* p = pNode->AppendChild( "LastDays" );
for( int i=0; i<NUM_LAST_DAYS; i++ )
p->AppendChild( LastDayToString(i), coins[i] );
}
{
int coins[NUM_LAST_WEEKS];
BOOKKEEPER->GetCoinsLastWeeks( coins );
XNode* p = pNode->AppendChild( "LastWeeks" );
for( int i=0; i<NUM_LAST_WEEKS; i++ )
p->AppendChild( LastWeekToString(i), coins[i] );
}
{
int coins[DAYS_IN_WEEK];
BOOKKEEPER->GetCoinsByDayOfWeek( coins );
XNode* p = pNode->AppendChild( "DayOfWeek" );
for( int i=0; i<DAYS_IN_WEEK; i++ )
p->AppendChild( DayOfWeekToString(i), coins[i] );
}
{
int coins[HOURS_IN_DAY];
BOOKKEEPER->GetCoinsByHour( coins );
XNode* p = pNode->AppendChild( "Hour" );
for( int i=0; i<HOURS_IN_DAY; i++ )
p->AppendChild( HourInDayToString(i), coins[i] );
}
return pNode;
}
2006-01-22 01:00:06 +00:00
void Profile::MoveBackupToDir( RString sFromDir, RString sToDir )
2004-10-06 08:54:37 +00:00
{
2007-04-17 21:03:07 +00:00
if( FILEMAN->IsAFile(sFromDir + STATS_XML) &&
FILEMAN->IsAFile(sFromDir+STATS_XML+SIGNATURE_APPEND) )
{
FILEMAN->Move( sFromDir+STATS_XML, sToDir+STATS_XML );
FILEMAN->Move( sFromDir+STATS_XML+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND );
}
else if( FILEMAN->IsAFile(sFromDir + STATS_XML_GZ) &&
FILEMAN->IsAFile(sFromDir+STATS_XML_GZ+SIGNATURE_APPEND) )
{
FILEMAN->Move( sFromDir+STATS_XML_GZ, sToDir+STATS_XML );
FILEMAN->Move( sFromDir+STATS_XML_GZ+SIGNATURE_APPEND, sToDir+STATS_XML+SIGNATURE_APPEND );
}
if( FILEMAN->IsAFile(sFromDir + EDITABLE_INI) )
FILEMAN->Move( sFromDir+EDITABLE_INI, sToDir+EDITABLE_INI );
if( FILEMAN->IsAFile(sFromDir + DONT_SHARE_SIG) )
FILEMAN->Move( sFromDir+DONT_SHARE_SIG, sToDir+DONT_SHARE_SIG );
2004-10-06 08:54:37 +00:00
}
2005-02-15 23:13:18 +00:00
// lua start
#include "LuaBinding.h"
2005-06-20 05:02:03 +00:00
class LunaProfile: public Luna<Profile>
2005-02-15 23:13:18 +00:00
{
public:
static int GetDisplayName( T* p, lua_State *L ) { lua_pushstring(L, p->m_sDisplayName ); return 1; }
2007-03-14 04:26:32 +00:00
static int GetHighScoreList( T* p, lua_State *L )
{
if( LuaBinding::CheckLuaObjectType(L, 1, "Song") )
{
const Song *pSong = Luna<Song>::check(L,1);
const Steps *pSteps = Luna<Steps>::check(L,2);
HighScoreList &hsl = p->GetStepsHighScoreList( pSong, pSteps );
hsl.PushSelf( L );
return 1;
}
else if( LuaBinding::CheckLuaObjectType(L, 1, "Course") )
{
const Course *pCourse = Luna<Course>::check(L,1);
const Trail *pTrail = Luna<Trail>::check(L,2);
HighScoreList &hsl = p->GetCourseHighScoreList( pCourse, pTrail );
hsl.PushSelf( L );
return 1;
}
luaL_typerror( L, 1, "Song or Course" );
return 0;
}
2005-07-13 19:11:24 +00:00
static int GetCharacter( T* p, lua_State *L ) { p->GetCharacter()->PushSelf(L); return 1; }
2005-02-17 17:14:33 +00:00
static int GetWeightPounds( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iWeightPounds ); return 1; }
2005-02-18 13:05:17 +00:00
static int SetWeightPounds( T* p, lua_State *L ) { p->m_iWeightPounds = IArg(1); return 0; }
2005-02-16 20:24:57 +00:00
static int GetGoalType( T* p, lua_State *L ) { lua_pushnumber(L, p->m_GoalType ); return 1; }
2006-09-26 08:01:12 +00:00
static int SetGoalType( T* p, lua_State *L ) { p->m_GoalType = Enum::Check<GoalType>(L, 1); return 0; }
2005-02-15 23:13:18 +00:00
static int GetGoalCalories( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iGoalCalories ); return 1; }
2005-02-17 19:36:10 +00:00
static int SetGoalCalories( T* p, lua_State *L ) { p->m_iGoalCalories = IArg(1); return 0; }
2005-02-16 20:24:57 +00:00
static int GetGoalSeconds( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iGoalSeconds ); return 1; }
2005-02-17 19:36:10 +00:00
static int SetGoalSeconds( T* p, lua_State *L ) { p->m_iGoalSeconds = IArg(1); return 0; }
2005-02-15 23:13:18 +00:00
static int GetCaloriesBurnedToday( T* p, lua_State *L ) { lua_pushnumber(L, p->GetCaloriesBurnedToday() ); return 1; }
static int GetTotalNumSongsPlayed( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iNumTotalSongsPlayed ); return 1; }
static int IsCodeUnlocked( T* p, lua_State *L ) { lua_pushboolean(L, p->IsCodeUnlocked(SArg(1)) ); return 1; }
2006-09-27 06:09:52 +00:00
static int GetSongsActual( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongsActual(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
static int GetCoursesActual( T* p, lua_State *L ) { lua_pushnumber(L, p->GetCoursesActual(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
2006-09-27 06:09:52 +00:00
static int GetSongsPossible( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongsPossible(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
static int GetCoursesPossible( T* p, lua_State *L ) { lua_pushnumber(L, p->GetCoursesPossible(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
2006-09-27 06:09:52 +00:00
static int GetSongsPercentComplete( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongsPercentComplete(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
static int GetCoursesPercentComplete( T* p, lua_State *L ) { lua_pushnumber(L, p->GetCoursesPercentComplete(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2)) ); return 1; }
2006-09-27 06:09:52 +00:00
static int GetTotalStepsWithTopGrade( T* p, lua_State *L ) { lua_pushnumber(L, p->GetTotalStepsWithTopGrade(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2),Enum::Check<Grade>(L, 3)) ); return 1; }
static int GetTotalTrailsWithTopGrade( T* p, lua_State *L ) { lua_pushnumber(L, p->GetTotalTrailsWithTopGrade(Enum::Check<StepsType>(L, 1),Enum::Check<Difficulty>(L, 2),Enum::Check<Grade>(L, 3)) ); return 1; }
2005-07-13 19:11:24 +00:00
static int GetNumTotalSongsPlayed( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iNumTotalSongsPlayed ); return 1; }
2005-08-03 03:23:52 +00:00
static int GetLastPlayedStepsType( T* p, lua_State *L ) { lua_pushnumber(L, p->GetLastPlayedStepsType() ); return 1; }
2006-09-27 06:09:52 +00:00
static int GetSongsAndCoursesPercentCompleteAllDifficulties( T* p, lua_State *L ) { lua_pushnumber(L, p->GetSongsAndCoursesPercentCompleteAllDifficulties(Enum::Check<StepsType>(L, 1)) ); return 1; }
2006-06-12 22:49:52 +00:00
static int GetTotalCaloriesBurned( T* p, lua_State *L ) { lua_pushnumber(L, p->m_fTotalCaloriesBurned ); return 1; }
2006-04-05 03:08:42 +00:00
static int GetDisplayTotalCaloriesBurned( T* p, lua_State *L ) { lua_pushstring(L, p->GetDisplayTotalCaloriesBurned() ); return 1; }
2005-08-05 04:20:46 +00:00
static int GetMostPopularSong( T* p, lua_State *L )
{
Song *p2 = p->GetMostPopularSong();
if( p2 )
p2->PushSelf(L);
else
lua_pushnil( L );
return 1;
}
static int GetMostPopularCourse( T* p, lua_State *L )
{
Course *p2 = p->GetMostPopularCourse();
if( p2 )
p2->PushSelf(L);
else
lua_pushnil( L );
return 1;
}
static int GetSongNumTimesPlayed( T* p, lua_State *L )
{
ASSERT( !lua_isnil(L,1) );
Song *pS = Luna<Song>::check(L,1);
lua_pushnumber( L, p->GetSongNumTimesPlayed(pS) );
return 1;
}
static int HasPassedAnyStepsInSong( T* p, lua_State *L )
{
ASSERT( !lua_isnil(L,1) );
Song *pS = Luna<Song>::check(L,1);
lua_pushboolean( L, p->HasPassedAnyStepsInSong(pS) );
return 1;
}
2007-09-23 19:53:09 +00:00
static int GetNumToasties( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iNumToasties ); return 1; }
static int GetTotalTapsAndHolds( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalTapsAndHolds ); return 1; }
static int GetTotalJumps( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalJumps ); return 1; }
static int GetTotalHolds( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalHolds ); return 1; }
static int GetTotalRolls( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalRolls ); return 1; }
static int GetTotalMines( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalMines ); return 1; }
static int GetTotalHands( T* p, lua_State *L ) { lua_pushnumber(L, p->m_iTotalHands ); return 1; }
2005-02-15 23:13:18 +00:00
2006-09-27 19:53:05 +00:00
LunaProfile()
2005-02-15 23:13:18 +00:00
{
ADD_METHOD( GetDisplayName );
2007-03-14 04:26:32 +00:00
ADD_METHOD( GetHighScoreList );
ADD_METHOD( GetCharacter );
ADD_METHOD( GetWeightPounds );
ADD_METHOD( SetWeightPounds );
ADD_METHOD( GetGoalType );
ADD_METHOD( SetGoalType );
ADD_METHOD( GetGoalCalories );
ADD_METHOD( SetGoalCalories );
ADD_METHOD( GetGoalSeconds );
ADD_METHOD( SetGoalSeconds );
ADD_METHOD( GetCaloriesBurnedToday );
ADD_METHOD( GetTotalNumSongsPlayed );
ADD_METHOD( IsCodeUnlocked );
ADD_METHOD( GetSongsActual );
ADD_METHOD( GetCoursesActual );
ADD_METHOD( GetSongsPossible );
ADD_METHOD( GetCoursesPossible );
ADD_METHOD( GetSongsPercentComplete );
ADD_METHOD( GetCoursesPercentComplete );
ADD_METHOD( GetTotalStepsWithTopGrade );
ADD_METHOD( GetTotalTrailsWithTopGrade );
ADD_METHOD( GetNumTotalSongsPlayed );
ADD_METHOD( GetLastPlayedStepsType );
ADD_METHOD( GetSongsAndCoursesPercentCompleteAllDifficulties );
2006-06-12 22:49:52 +00:00
ADD_METHOD( GetTotalCaloriesBurned );
ADD_METHOD( GetDisplayTotalCaloriesBurned );
ADD_METHOD( GetMostPopularSong );
ADD_METHOD( GetMostPopularCourse );
ADD_METHOD( GetSongNumTimesPlayed );
ADD_METHOD( HasPassedAnyStepsInSong );
2007-09-23 19:53:09 +00:00
ADD_METHOD( GetNumToasties );
ADD_METHOD( GetTotalTapsAndHolds );
ADD_METHOD( GetTotalJumps );
ADD_METHOD( GetTotalHolds );
ADD_METHOD( GetTotalRolls );
ADD_METHOD( GetTotalMines );
ADD_METHOD( GetTotalHands );
2005-02-15 23:13:18 +00:00
}
};
LUA_REGISTER_CLASS( Profile )
// lua end
2004-05-31 21:55:14 +00:00
/*
* (c) 2001-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.
*/