diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index 9a082585a7..c858c1af0f 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -1262,7 +1262,7 @@ void GameState::GetRankingFeats( PlayerNumber pn, vector &asFeatsOu // Find Machine Records { - HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps); + HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps); for( j=0; j &asFeatsOu // Find Personal Records if( pProf ) { - HighScoreList &hsl = pProf->GetStepsHighScoreList(pSteps); + HighScoreList &hsl = pProf->GetStepsHighScoreList(pSong,pSteps); for( j=0; jGetProfile(m_PlayerNumber)->GetStepsHighScoreList(pSteps).GetTopScore().fPercentDP; + val = 100.0f * PROFILEMAN->GetProfile(m_PlayerNumber)->GetStepsHighScoreList(pSong,pSteps).GetTopScore().fPercentDP; break; case SONG_PROFILE_NUM_PLAYS: - val = (float) PROFILEMAN->GetProfile(m_PlayerNumber)->GetStepsNumTimesPlayed(pSteps); + val = (float) PROFILEMAN->GetProfile(m_PlayerNumber)->GetStepsNumTimesPlayed(pSong,pSteps); break; case SONG_MACHINE_HIGH_NAME: /* set val for color */ case SONG_MACHINE_HIGH_SCORE: CHECKPOINT; - val = 100.0f * PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps).GetTopScore().fPercentDP; + val = 100.0f * PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps).GetTopScore().fPercentDP; break; case SONG_MACHINE_RANK: @@ -265,7 +265,7 @@ void PaneDisplay::SetContent( PaneContents c ) switch( c ) { case SONG_MACHINE_HIGH_NAME: - str = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps).GetTopScore().sName; + str = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps).GetTopScore().sName; break; case COURSE_MACHINE_HIGH_NAME: str = PROFILEMAN->GetMachineProfile()->GetCourseHighScoreList(pCourse,st,cd).GetTopScore().sName; diff --git a/stepmania/src/Profile.cpp b/stepmania/src/Profile.cpp index dbe3336b44..bbd09ad912 100644 --- a/stepmania/src/Profile.cpp +++ b/stepmania/src/Profile.cpp @@ -116,7 +116,7 @@ void Profile::InitGeneralData() void Profile::InitSongScores() { - m_StepsHighScores.clear(); + m_SongHighScores.clear(); } void Profile::InitCourseScores() @@ -195,19 +195,40 @@ int Profile::GetTotalHighScoreDancePointsForStepsType( StepsType st ) const // add steps high scores { - for( std::map::const_iterator iter = m_StepsHighScores.begin(); - iter != m_StepsHighScores.end(); - iter++ ) + for( std::map::const_iterator i = m_SongHighScores.begin(); + i != m_SongHighScores.end(); + i++ ) { - const Steps* pSteps = iter->first; - ASSERT( pSteps ); - const HighScoresForASteps& h = iter->second; - const HighScoreList& hs = h.hs; - if( pSteps->m_StepsType == st ) + SongID id = i->first; + Song* pSong = id.ToSong(); + + // 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; + + const HighScoresForASong &hsfas = i->second; + + for( std::map::const_iterator j = hsfas.m_StepsHighScores.begin(); + j != hsfas.m_StepsHighScores.end(); + j++ ) { - const RadarValues& fRadars = pSteps->GetRadarValues(); - int iPossibleDP = ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); - iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP ); + StepsID id = j->first; + Steps* pSteps = id.ToSteps( pSong, true ); + + // If the Steps isn't loaded on the current machine, then we can't + // get radar values to compute dance points. + if( pSteps == NULL ) + continue; + + const HighScoresForASteps& h = j->second; + const HighScoreList& hs = h.hs; + if( pSteps->m_StepsType == st ) + { + const RadarValues& fRadars = pSteps->GetRadarValues(); + int iPossibleDP = ScoreKeeperMAX2::GetPossibleDancePoints( fRadars ); + iTotal += (int)truncf( hs.GetTopScore().fPercentDP * iPossibleDP ); + } } } } @@ -248,14 +269,26 @@ CString Profile::GetProfileDisplayNameFromDir( CString sDir ) } int Profile::GetSongNumTimesPlayed( const Song* pSong ) const +{ + SongID songID; + songID.FromSong( pSong ); + return GetSongNumTimesPlayed( songID ); +} + +int Profile::GetSongNumTimesPlayed( const SongID& songID ) const { int iTotalNumTimesPlayed = 0; - vector vpSteps; - pSong->GetSteps( vpSteps ); - for( unsigned i=0; i &songHighScores = ((Profile*)(this))->m_SongHighScores; + const HighScoresForASong& hsSong = songHighScores[songID]; + + for( std::map::const_iterator j = hsSong.m_StepsHighScores.begin(); + j != hsSong.m_StepsHighScores.end(); + j++ ) { - const Steps* pSteps = vpSteps[i]; - iTotalNumTimesPlayed += ((Profile*) this)->GetStepsHighScoreList(pSteps).iNumTimesPlayed; + const HighScoresForASteps &hsSteps = j->second; + + iTotalNumTimesPlayed += hsSteps.hs.iNumTimesPlayed; } return iTotalNumTimesPlayed; } @@ -263,46 +296,38 @@ int Profile::GetSongNumTimesPlayed( const Song* pSong ) const // // Steps high scores // -void Profile::AddStepsHighScore( const Steps* pSteps, HighScore hs, int &iIndexOut ) +void Profile::AddStepsHighScore( const Song* pSong, const Steps* pSteps, HighScore hs, int &iIndexOut ) { - ASSERT(pSteps); - std::map::iterator iter = m_StepsHighScores.find( pSteps ); - if( iter == m_StepsHighScores.end() ) - m_StepsHighScores[pSteps].hs.AddHighScore( hs, iIndexOut ); // operator[] inserts into map - else - iter->second.hs.AddHighScore( hs, iIndexOut ); + GetStepsHighScoreList(pSong,pSteps).AddHighScore( hs, iIndexOut ); } -const HighScoreList& Profile::GetStepsHighScoreList( const Steps* pSteps ) const +const HighScoreList& Profile::GetStepsHighScoreList( const Song* pSong, const Steps* pSteps ) const { - ASSERT(pSteps); - /* We're const, but insert a blank entry anyway if the requested pointer doesn't exist. */ - return ((Profile *) this)->m_StepsHighScores[pSteps].hs; + return ((Profile*)this)->GetStepsHighScoreList(pSong,pSteps); } -HighScoreList& Profile::GetStepsHighScoreList( const Steps* pSteps ) +HighScoreList& Profile::GetStepsHighScoreList( const Song* pSong, const Steps* pSteps ) { - ASSERT(pSteps); - std::map::iterator iter = m_StepsHighScores.find( pSteps ); - if( iter == m_StepsHighScores.end() ) - return m_StepsHighScores[pSteps].hs; // operator[] inserts into map - else - return iter->second.hs; + SongID songID; + songID.FromSong( pSong ); + + StepsID stepsID; + stepsID.FromSteps( pSteps ); + + HighScoresForASong &hsSong = m_SongHighScores[songID]; // operator[] inserts into map + HighScoresForASteps &hsSteps = hsSong.m_StepsHighScores[stepsID]; // operator[] inserts into map + + return hsSteps.hs; } -int Profile::GetStepsNumTimesPlayed( const Steps* pSteps ) const +int Profile::GetStepsNumTimesPlayed( const Song* pSong, const Steps* pSteps ) const { - ASSERT(pSteps); - std::map::const_iterator iter = m_StepsHighScores.find( pSteps ); - if( iter == m_StepsHighScores.end() ) - return 0; - else - return iter->second.hs.iNumTimesPlayed; + return GetStepsHighScoreList(pSong,pSteps).iNumTimesPlayed; } -void Profile::IncrementStepsPlayCount( const Steps* pSteps ) +void Profile::IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps ) { - GetStepsHighScoreList(pSteps).iNumTimesPlayed++; + GetStepsHighScoreList(pSong,pSteps).iNumTimesPlayed++; } @@ -862,38 +887,34 @@ XNode* Profile::SaveSongScoresCreateNode() const XNode* pNode = new XNode; pNode->name = "SongScores"; - const vector &vpSongs = SONGMAN->GetAllSongs(); - - for( unsigned s=0; s::const_iterator i = m_SongHighScores.begin(); + i != m_SongHighScores.end(); + i++ ) + { + const SongID &songID = i->first; + const HighScoresForASong &hsSong = i->second; // skip songs that have never been played - if( pProfile->GetSongNumTimesPlayed(pSong) == 0 ) + if( pProfile->GetSongNumTimesPlayed(songID) == 0 ) continue; - LPXNode pSongNode = pNode->AppendChild( "Song" ); - pSongNode->AppendAttr( "Dir", pSong->GetSongDir() ); - const vector vSteps = pSong->GetAllSteps(); + LPXNode pSongNode = pNode->AppendChild( songID.CreateNode() ); - for( unsigned n=0; n::const_iterator j = hsSong.m_StepsHighScores.begin(); + j != hsSong.m_StepsHighScores.end(); + j++ ) + { + const StepsID &stepsID = j->first; + const HighScoresForASteps &hsSteps = j->second; + + const HighScoreList &hsl = hsSteps.hs; // skip steps that have never been played - if( pProfile->GetStepsHighScoreList(pSteps).iNumTimesPlayed == 0 ) + if( hsl.iNumTimesPlayed == 0 ) continue; - LPXNode pStepsNode = pSongNode->AppendChild( "Steps" ); - - const HighScoreList &hsl = pProfile->GetStepsHighScoreList( pSteps ); - - pStepsNode->AppendAttr( "StepsType", GameManager::NotesTypeToString(pSteps->m_StepsType) ); - pStepsNode->AppendAttr( "Difficulty", DifficultyToString(pSteps->GetDifficulty()) ); - if( pSteps->GetDifficulty() == DIFFICULTY_EDIT ) - pStepsNode->AppendChild( "Description", pSteps->GetDescription() ); + LPXNode pStepsNode = pSongNode->AppendChild( stepsID.CreateNode() ); pStepsNode->AppendChild( hsl.CreateNode() ); } @@ -913,17 +934,11 @@ void Profile::LoadSongScoresFromNode( const XNode* pNode ) if( (*song)->name != "Song" ) continue; - CString sSongDir; - if( !(*song)->GetAttrValue( "Dir", sSongDir ) ) + SongID songID; + songID.LoadFromNode( *song ); + if( !songID.IsValid() ) WARN_AND_CONTINUE; - Song* pSong = SONGMAN->GetSongFromDir( sSongDir ); - if( pSong == NULL ) - { - LOG->Trace("Couldn't find song \"%s\"; scoring data will be lost", sSongDir.c_str() ); - continue; - } - for( XNodes::iterator steps = (*song)->childs.begin(); steps != (*song)->childs.end(); steps++ ) @@ -931,48 +946,16 @@ void Profile::LoadSongScoresFromNode( const XNode* pNode ) if( (*steps)->name != "Steps" ) continue; - CString str; - if( !(*steps)->GetAttrValue("StepsType", str) ) + StepsID stepsID; + stepsID.LoadFromNode( *steps ); + if( !stepsID.IsValid() ) WARN_AND_CONTINUE; - const StepsType st = GameManager::StringToNotesType( str ); - if( st == STEPS_TYPE_INVALID ) - WARN_AND_CONTINUE; - - if( !(*steps)->GetAttrValue("Difficulty", str) ) - WARN_AND_CONTINUE; - const Difficulty dc = StringToDifficulty( str ); - if( dc == DIFFICULTY_INVALID ) - WARN_AND_CONTINUE; - - Steps* pSteps = NULL; - if( dc == DIFFICULTY_EDIT ) - { - CString sDescription; - if( !(*steps)->GetChildValue("Description", sDescription) ) - WARN_AND_CONTINUE; - - pSteps = pSong->GetStepsByDescription( st, sDescription ); - if( pSteps == NULL ) - { - LOG->Trace("Edit steps \"%s\" missing in song \"%s\"; scoring data will be lost", sDescription.c_str(), sSongDir.c_str() ); - continue; - } - } - else - { - pSteps = pSong->GetStepsByDifficulty( st, dc ); - if( pSteps == NULL ) - { - LOG->Trace("\"%s\" steps missing in song \"%s\"; scoring data will be lost", DifficultyToString(dc).c_str(), sSongDir.c_str() ); - continue; - } - } XNode *pHighScoreListNode = (*steps)->GetChild("HighScoreList"); if( pHighScoreListNode == NULL ) WARN_AND_CONTINUE; - HighScoreList &hsl = this->GetStepsHighScoreList( pSteps ); + HighScoreList &hsl = m_SongHighScores[songID].m_StepsHighScores[stepsID].hs; hsl.LoadFromNode( pHighScoreListNode ); } } @@ -1069,7 +1052,7 @@ void Profile::LoadSongScoresFromDirSM390a12( CString sDir ) if( !FileRead(f, iNumTimesPlayed) ) WARN_AND_RETURN; - HighScoreList &hsl = pProfile->GetStepsHighScoreList(pSteps); + HighScoreList &hsl = pProfile->GetStepsHighScoreList(pSong,pSteps); if( pSteps ) hsl.iNumTimesPlayed = iNumTimesPlayed; diff --git a/stepmania/src/Profile.h b/stepmania/src/Profile.h index e9051568bc..c9c7452cb4 100644 --- a/stepmania/src/Profile.h +++ b/stepmania/src/Profile.h @@ -20,6 +20,8 @@ #include "XmlFile.h" #include "HighScore.h" #include "TimeConstants.h" +#include "SongUtil.h" // for SongID +#include "StepsUtil.h" // for StepsID // @@ -73,6 +75,7 @@ public: int GetTotalHighScoreDancePointsForStepsType( StepsType st ) const; static CString GetProfileDisplayNameFromDir( CString sDir ); int GetSongNumTimesPlayed( const Song* pSong ) const; + int GetSongNumTimesPlayed( const SongID& songID ) const; void AddStepTotals( int iNumTapsAndHolds, int iNumJumps, int iNumHolds, int iNumMines, int iNumHands ); @@ -117,19 +120,23 @@ public: int m_iNumSongsPassedByGrade[NUM_GRADES]; // - // Steps high scores + // Song high scores // struct HighScoresForASteps { HighScoreList hs; }; - std::map m_StepsHighScores; + struct HighScoresForASong + { + std::map m_StepsHighScores; + }; + std::map m_SongHighScores; - void AddStepsHighScore( const Steps* pSteps, HighScore hs, int &iIndexOut ); - HighScoreList& GetStepsHighScoreList( const Steps* pSteps ); - const HighScoreList& GetStepsHighScoreList( const Steps* pSteps ) const; - int GetStepsNumTimesPlayed( const Steps* pSteps ) const; - void IncrementStepsPlayCount( const Steps* pSteps ); + void AddStepsHighScore( const Song* pSong, const Steps* pSteps, HighScore hs, int &iIndexOut ); + const HighScoreList& GetStepsHighScoreList( const Song* pSong, const Steps* pSteps ) const; + HighScoreList& GetStepsHighScoreList( const Song* pSong, const Steps* pSteps ); + int GetStepsNumTimesPlayed( const Song* pSong, const Steps* pSteps ) const; + void IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps ); // diff --git a/stepmania/src/ProfileHtml.cpp b/stepmania/src/ProfileHtml.cpp index b7be9a1b67..864ca5607e 100644 --- a/stepmania/src/ProfileHtml.cpp +++ b/stepmania/src/ProfileHtml.cpp @@ -347,17 +347,24 @@ void PrintStatistics( RageFile &f, const Profile *pProfile, CString sTitle, vect int iGradeCount[NUM_GRADES]; ZERO( iGradeCount ); - for( unsigned i=0; iGetStepsHighScoreList(pSteps); - if( hsl.vHighScores.empty() ) - continue; // no data, skip this one - Grade g = hsl.GetTopScore().grade; - ASSERT( g != GRADE_NO_DATA ); - ASSERT( g < NUM_GRADES ); - ASSERT( g >= 0 ); - iGradeCount[g] ++; + Song* pSong = vpSongs[i]; + const vector vpSteps = pSong->GetAllSteps(); + + for( unsigned j=0; jGetStepsHighScoreList(pSong,pSteps); + if( hsl.vHighScores.empty() ) + continue; // no data, skip this one + Grade g = hsl.GetTopScore().grade; + ASSERT( g != GRADE_NO_DATA ); + ASSERT( g < NUM_GRADES ); + ASSERT( g >= 0 ); + iGradeCount[g] ++; + } } BEGIN_TABLE(6); @@ -445,10 +452,10 @@ void PrintPopularity( RageFile &f, const Profile *pProfile, CString sTitle, vect for( i=0; iGetStepsNumTimesPlayed(pSteps); + Song* pSong = mapStepsToSong[pSteps]; + int iNumTimesPlayed = pProfile->GetStepsNumTimesPlayed(pSong,pSteps); if( iNumTimesPlayed==0 ) continue; // skip - Song* pSong = mapStepsToSong[pSteps]; CString s; s += GAMEMAN->NotesTypeToString(pSteps->m_StepsType); s += " "; @@ -633,10 +640,10 @@ bool PrintHighScoresForSong( RageFile &f, const Profile *pProfile, Song* pSong ) Steps* pSteps = vpSteps[j]; if( pSteps->IsAutogen() ) continue; // skip autogen - if( pProfile->GetStepsNumTimesPlayed(pSteps)==0 ) + if( pProfile->GetStepsNumTimesPlayed(pSong,pSteps)==0 ) continue; // skip - const HighScoreList &hsl = pProfile->GetStepsHighScoreList( pSteps ); + const HighScoreList &hsl = pProfile->GetStepsHighScoreList( pSong,pSteps ); if( hsl.vHighScores.empty() ) continue; @@ -737,7 +744,7 @@ bool PrintGradeTableForStepsType( RageFile &f, const Profile *pProfile, StepsTyp { f.PutLine(""); f.PutLine( ssprintf("%d",pSteps->GetMeter()) ); - HighScore hs = pProfile->GetStepsHighScoreList( pSteps ).GetTopScore(); + HighScore hs = pProfile->GetStepsHighScoreList( pSong,pSteps ).GetTopScore(); Grade grade = hs.grade; if( grade != GRADE_NO_DATA ) f.PutLine( ssprintf("%s",GradeToThemedString(grade).c_str()) ); @@ -803,7 +810,7 @@ bool PrintInventoryForSong( RageFile &f, const Profile *pProfile, Song* pSong ) BEGIN_TABLE(3); TABLE_LINE2( "Meter", pSteps->GetMeter() ); TABLE_LINE2( "Description", pSteps->GetDescription() ); - TABLE_LINE2( "NumTimesPlayed", pProfile->GetStepsNumTimesPlayed(pSteps) ); + TABLE_LINE2( "NumTimesPlayed", pProfile->GetStepsNumTimesPlayed(pSong,pSteps) ); END_TABLE; BEGIN_TABLE(2); diff --git a/stepmania/src/ProfileManager.cpp b/stepmania/src/ProfileManager.cpp index 1cb58fc787..895690f789 100644 --- a/stepmania/src/ProfileManager.cpp +++ b/stepmania/src/ProfileManager.cpp @@ -432,21 +432,21 @@ int ProfileManager::GetSongNumTimesPlayed( const Song* pSong, ProfileSlot slot ) return GetProfile(slot)->GetSongNumTimesPlayed( pSong ); } -void ProfileManager::AddStepsHighScore( const Steps* pSteps, PlayerNumber pn, HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ) +void ProfileManager::AddStepsHighScore( const Song* pSong, const Steps* pSteps, PlayerNumber pn, HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ) { hs.sName = RANKING_TO_FILL_IN_MARKER[pn]; if( PROFILEMAN->IsUsingProfile(pn) ) - PROFILEMAN->GetProfile(pn)->AddStepsHighScore( pSteps, hs, iPersonalIndexOut ); + PROFILEMAN->GetProfile(pn)->AddStepsHighScore( pSong, pSteps, hs, iPersonalIndexOut ); else iPersonalIndexOut = -1; - PROFILEMAN->GetMachineProfile()->AddStepsHighScore( pSteps, hs, iMachineIndexOut ); + PROFILEMAN->GetMachineProfile()->AddStepsHighScore( pSong, pSteps, hs, iMachineIndexOut ); } -void ProfileManager::IncrementStepsPlayCount( const Steps* pSteps, PlayerNumber pn ) +void ProfileManager::IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps, PlayerNumber pn ) { if( PROFILEMAN->IsUsingProfile(pn) ) - PROFILEMAN->GetProfile(pn)->IncrementStepsPlayCount( pSteps ); - PROFILEMAN->GetMachineProfile()->IncrementStepsPlayCount( pSteps ); + PROFILEMAN->GetProfile(pn)->IncrementStepsPlayCount( pSong, pSteps ); + PROFILEMAN->GetMachineProfile()->IncrementStepsPlayCount( pSong, pSteps ); } HighScore ProfileManager::GetHighScoreForDifficulty( const Song *s, const StyleDef *st, ProfileSlot slot, Difficulty dc ) const @@ -459,7 +459,7 @@ HighScore ProfileManager::GetHighScoreForDifficulty( const Song *s, const StyleD const Steps* pSteps = s->GetStepsByDifficulty( st->m_StepsType, dc ); if( pSteps && PROFILEMAN->IsUsingProfile(slot) ) - return PROFILEMAN->GetProfile(slot)->GetStepsHighScoreList(pSteps).GetTopScore(); + return PROFILEMAN->GetProfile(slot)->GetStepsHighScoreList(s,pSteps).GetTopScore(); else return HighScore(); } diff --git a/stepmania/src/ProfileManager.h b/stepmania/src/ProfileManager.h index 063d28cf15..4b3b7bab0f 100644 --- a/stepmania/src/ProfileManager.h +++ b/stepmania/src/ProfileManager.h @@ -83,8 +83,8 @@ public: // int GetSongNumTimesPlayed( const Song* pSong, ProfileSlot card ) const; bool IsSongNew( const Song* pSong ) const { return GetSongNumTimesPlayed(pSong,PROFILE_SLOT_MACHINE)==0; } - void AddStepsHighScore( const Steps* pSteps, PlayerNumber pn, HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ); - void IncrementStepsPlayCount( const Steps* pSteps, PlayerNumber pn ); + void AddStepsHighScore( const Song* pSong, const Steps* pSteps, PlayerNumber pn, HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ); + void IncrementStepsPlayCount( const Song* pSong, const Steps* pSteps, PlayerNumber pn ); HighScore GetHighScoreForDifficulty( const Song *s, const StyleDef *st, ProfileSlot slot, Difficulty dc ) const; // diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index 4a15b1cb57..13b2408235 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -919,6 +919,9 @@ void ScreenEvaluation::CommitScores( if( GAMESTATE->IsDisqualified((PlayerNumber)p) ) continue; + Song* pSong = GAMESTATE->m_pCurSong; + Steps* pSteps = GAMESTATE->m_pCurNotes[p]; + // // Add step totals // @@ -952,10 +955,10 @@ void ScreenEvaluation::CommitScores( if( stageStats.bFailed[p] ) continue; - ASSERT( GAMESTATE->m_pCurNotes[p] ); + ASSERT( pSteps ); if( hs.fPercentDP >= PREFSMAN->m_fMinPercentageForHighScore ) - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, iPersonalHighScoreIndexOut[p], iMachineHighScoreIndexOut[p] ); + PROFILEMAN->AddStepsHighScore( pSong, pSteps, (PlayerNumber)p, hs, iPersonalHighScoreIndexOut[p], iMachineHighScoreIndexOut[p] ); } break; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 17a7164691..bedffa2002 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -853,13 +853,14 @@ void ScreenGameplay::LoadCourseSongNumber( int SongNumber ) void ScreenGameplay::LoadNextSong() { GAMESTATE->ResetMusicStatistics(); - int p; - for( p=0; pIsPlayerEnabled(p) ) + + { + FOREACH_EnabledPlayer( p ) { g_CurStageStats.iSongsPlayed[p]++; m_textCourseSongNumber[p].SetText( ssprintf("%d", g_CurStageStats.iSongsPlayed[p]) ); } + } LoadCourseSongNumber( GetMaxSongsPlayed() ); @@ -875,71 +876,74 @@ void ScreenGameplay::LoadNextSong() m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() ); - for( p=0; pIsPlayerEnabled(p) ) - continue; - - SetupSong( p, iPlaySongIndex ); - - ASSERT( GAMESTATE->m_pCurNotes[p] ); - m_textStepsDescription[p].SetText( GAMESTATE->m_pCurNotes[p]->GetDescription() ); - - /* Increment the play count even if the player fails. (It's still popular, - * even if the people playing it aren't good at it.) */ - if( !m_bDemonstration ) - PROFILEMAN->IncrementStepsPlayCount( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p ); - - m_textPlayerOptions[p].SetText( GAMESTATE->m_PlayerOptions[p].GetString() ); - - // reset oni game over graphic - m_sprOniGameOver[p].SetY( SCREEN_TOP - m_sprOniGameOver[p].GetZoomedHeight()/2 ); - m_sprOniGameOver[p].SetDiffuse( RageColor(1,1,1,0) ); // 0 alpha so we don't waste time drawing while not visible - - if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BATTERY && g_CurStageStats.bFailed[p] ) // already failed - ShowOniGameOver((PlayerNumber)p); - - if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR && GAMESTATE->m_PlayMode == PLAY_MODE_ARCADE && !PREFSMAN->m_bEventMode && !m_bDemonstration) + FOREACH_EnabledPlayer( p ) { - m_pLifeMeter[p]->UpdateNonstopLifebar( - GAMESTATE->GetStageIndex(), - PREFSMAN->m_iNumArcadeStages, - PREFSMAN->m_iProgressiveStageLifebar); - } - if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR && GAMESTATE->m_PlayMode == PLAY_MODE_NONSTOP ) - { - m_pLifeMeter[p]->UpdateNonstopLifebar( - GAMESTATE->GetCourseSongIndex(), - GAMESTATE->m_pCurCourse->GetEstimatedNumStages(), - PREFSMAN->m_iProgressiveNonstopLifebar); - } + SetupSong( p, iPlaySongIndex ); - m_DifficultyIcon[p].SetFromNotes( PlayerNumber(p), GAMESTATE->m_pCurNotes[p] ); + Song* pSong = GAMESTATE->m_pCurSong; + Steps* pSteps = GAMESTATE->m_pCurNotes[p]; - /* The actual note data for scoring is the base class of Player. This includes - * transforms, like Wide. Otherwise, the scoring will operate on the wrong data. */ - m_pPrimaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurNotes[p], &m_Player[p] ); - if( m_pSecondaryScoreKeeper[p] ) - m_pSecondaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurNotes[p], &m_Player[p] ); + ASSERT( GAMESTATE->m_pCurNotes[p] ); + m_textStepsDescription[p].SetText( GAMESTATE->m_pCurNotes[p]->GetDescription() ); - if( m_bDemonstration ) - { - GAMESTATE->m_PlayerController[p] = PC_CPU; - GAMESTATE->m_iCpuSkill[p] = 5; + /* Increment the play count even if the player fails. (It's still popular, + * even if the people playing it aren't good at it.) */ + if( !m_bDemonstration ) + PROFILEMAN->IncrementStepsPlayCount( pSong, pSteps, p ); + + m_textPlayerOptions[p].SetText( GAMESTATE->m_PlayerOptions[p].GetString() ); + + // reset oni game over graphic + m_sprOniGameOver[p].SetY( SCREEN_TOP - m_sprOniGameOver[p].GetZoomedHeight()/2 ); + m_sprOniGameOver[p].SetDiffuse( RageColor(1,1,1,0) ); // 0 alpha so we don't waste time drawing while not visible + + if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BATTERY && g_CurStageStats.bFailed[p] ) // already failed + ShowOniGameOver((PlayerNumber)p); + + if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR && GAMESTATE->m_PlayMode == PLAY_MODE_ARCADE && !PREFSMAN->m_bEventMode && !m_bDemonstration) + { + m_pLifeMeter[p]->UpdateNonstopLifebar( + GAMESTATE->GetStageIndex(), + PREFSMAN->m_iNumArcadeStages, + PREFSMAN->m_iProgressiveStageLifebar); + } + if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BAR && GAMESTATE->m_PlayMode == PLAY_MODE_NONSTOP ) + { + m_pLifeMeter[p]->UpdateNonstopLifebar( + GAMESTATE->GetCourseSongIndex(), + GAMESTATE->m_pCurCourse->GetEstimatedNumStages(), + PREFSMAN->m_iProgressiveNonstopLifebar); + } + + m_DifficultyIcon[p].SetFromNotes( PlayerNumber(p), GAMESTATE->m_pCurNotes[p] ); + + /* The actual note data for scoring is the base class of Player. This includes + * transforms, like Wide. Otherwise, the scoring will operate on the wrong data. */ + m_pPrimaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurNotes[p], &m_Player[p] ); + if( m_pSecondaryScoreKeeper[p] ) + m_pSecondaryScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurNotes[p], &m_Player[p] ); + + if( m_bDemonstration ) + { + GAMESTATE->m_PlayerController[p] = PC_CPU; + GAMESTATE->m_iCpuSkill[p] = 5; + } + else if( GAMESTATE->IsCpuPlayer(p) ) + { + GAMESTATE->m_PlayerController[p] = PC_CPU; + int iMeter = GAMESTATE->m_pCurNotes[p]->GetMeter(); + int iNewSkill = SCALE( iMeter, MIN_METER, MAX_METER, 0, NUM_SKILL_LEVELS-1 ); + /* Watch out: songs aren't actually bound by MAX_METER. */ + iNewSkill = clamp( iNewSkill, 0, NUM_SKILL_LEVELS-1 ); + GAMESTATE->m_iCpuSkill[p] = iNewSkill; + } + else if( PREFSMAN->m_bAutoPlay ) + GAMESTATE->m_PlayerController[p] = PC_AUTOPLAY; + else + GAMESTATE->m_PlayerController[p] = PC_HUMAN; } - else if( GAMESTATE->IsCpuPlayer(p) ) - { - GAMESTATE->m_PlayerController[p] = PC_CPU; - int iMeter = GAMESTATE->m_pCurNotes[p]->GetMeter(); - int iNewSkill = SCALE( iMeter, MIN_METER, MAX_METER, 0, NUM_SKILL_LEVELS-1 ); - /* Watch out: songs aren't actually bound by MAX_METER. */ - iNewSkill = clamp( iNewSkill, 0, NUM_SKILL_LEVELS-1 ); - GAMESTATE->m_iCpuSkill[p] = iNewSkill; - } - else if( PREFSMAN->m_bAutoPlay ) - GAMESTATE->m_PlayerController[p] = PC_AUTOPLAY; - else - GAMESTATE->m_PlayerController[p] = PC_HUMAN; } m_textSongTitle.SetText( GAMESTATE->m_pCurSong->m_sMainTitle ); @@ -962,13 +966,15 @@ void ScreenGameplay::LoadNextSong() GAMESTATE->m_PlayerOptions[1].m_fScrolls[PlayerOptions::SCROLL_REVERSE] == 1 }; - for( p=0; pIsPlayerEnabled(PlayerNumber(p)) ) - continue; + FOREACH_EnabledPlayer( p ) + { + if( !GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) ) + continue; - m_DifficultyIcon[p].SetName( ssprintf("DifficultyP%d%s%s",p+1,bExtra?"Extra":"",bReverse[p]?"Reverse":"") ); - SET_XY( m_DifficultyIcon[p] ); + m_DifficultyIcon[p].SetName( ssprintf("DifficultyP%d%s%s",p+1,bExtra?"Extra":"",bReverse[p]?"Reverse":"") ); + SET_XY( m_DifficultyIcon[p] ); + } } const bool bBothReverse = bReverse[PLAYER_1] && bReverse[PLAYER_2]; @@ -1003,9 +1009,11 @@ void ScreenGameplay::LoadNextSong() // Note: steps can be different if turn modifiers are used. if( PREFSMAN->m_bShowBeginnerHelper ) { - for( p=0; pIsHumanPlayer(p) && GAMESTATE->m_pCurNotes[p]->GetDifficulty() == DIFFICULTY_BEGINNER ) + FOREACH_HumanPlayer( p ) + { + if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() == DIFFICULTY_BEGINNER ) m_BeginnerHelper.AddPlayer( p, &m_Player[p] ); + } } if( m_BeginnerHelper.Initialize( 2 ) ) // Init for doubles diff --git a/stepmania/src/ScreenNameEntryTraditional.cpp b/stepmania/src/ScreenNameEntryTraditional.cpp index 592dae9d7f..9ba227499d 100644 --- a/stepmania/src/ScreenNameEntryTraditional.cpp +++ b/stepmania/src/ScreenNameEntryTraditional.cpp @@ -168,11 +168,11 @@ ScreenNameEntryTraditional::ScreenNameEntryTraditional( CString sClassName ) : S hs.iScore = st.iScore[p]; StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; int a, b; - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); - PROFILEMAN->AddStepsHighScore( GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); + PROFILEMAN->AddStepsHighScore( st.pSong, GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); + PROFILEMAN->AddStepsHighScore( st.pSong, GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); + PROFILEMAN->AddStepsHighScore( st.pSong, GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); + PROFILEMAN->AddStepsHighScore( st.pSong, GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); + PROFILEMAN->AddStepsHighScore( st.pSong, GAMESTATE->m_pCurNotes[p], (PlayerNumber)p, hs, a, b ); PROFILEMAN->AddCategoryHighScore( nt, RANKING_A, (PlayerNumber)p, hs, a, b ); } @@ -332,7 +332,7 @@ ScreenNameEntryTraditional::ScreenNameEntryTraditional( CString sClassName ) : S const HighScoreList& hsl = GAMESTATE->IsCourseMode() ? PROFILEMAN->GetMachineProfile()->GetCourseHighScoreList(pCourse, GAMESTATE->GetCurrentStyleDef()->m_StepsType, GAMESTATE->m_PreferredCourseDifficulty[p]) : - PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps); + PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps); for( unsigned h=0; hGetMachineProfile()->GetStepsHighScoreList(pSteps); + HighScoreList &hsl = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps); HighScore hs = hsl.GetTopScore(); bool bRecentHighScore = false; if( !hsl.vHighScores.empty() ) diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index a1ef12a6ad..bca96eee68 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -1164,6 +1164,7 @@ void ScreenSelectMusic::AfterNotesChange( PlayerNumber pn ) m_iSelection[pn] = clamp( m_iSelection[pn], 0, int(m_arrayNotes.size()-1) ); // bounds clamping + Song* pSong = GAMESTATE->m_pCurSong; Steps* pSteps = m_arrayNotes.empty()? NULL: m_arrayNotes[m_iSelection[pn]]; GAMESTATE->m_pCurNotes[pn] = pSteps; @@ -1176,9 +1177,9 @@ void ScreenSelectMusic::AfterNotesChange( PlayerNumber pn ) { int iScore = 0; if( PROFILEMAN->IsUsingProfile(pn) ) - iScore = PROFILEMAN->GetProfile(pn)->GetStepsHighScoreList(pSteps).GetTopScore().iScore; + iScore = PROFILEMAN->GetProfile(pn)->GetStepsHighScoreList(pSong,pSteps).GetTopScore().iScore; else - iScore = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps).GetTopScore().iScore; + iScore = PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSong,pSteps).GetTopScore().iScore; m_textHighScore[pn].SetText( ssprintf("%*i", NUM_SCORE_DIGITS, iScore) ); } else diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index b96d13242c..c44af87ba1 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -1278,7 +1278,7 @@ int Song::GetNumNotesWithGrade( Grade g ) const { Steps* pSteps = vNotes[j]; - if( PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(pSteps).GetTopScore().grade == g ) + if( PROFILEMAN->GetMachineProfile()->GetStepsHighScoreList(this,pSteps).GetTopScore().grade == g ) iCount++; } return iCount; diff --git a/stepmania/src/SongUtil.cpp b/stepmania/src/SongUtil.cpp index 9756b52dd0..901d40a2d8 100644 --- a/stepmania/src/SongUtil.cpp +++ b/stepmania/src/SongUtil.cpp @@ -368,3 +368,26 @@ Song *SongID::ToSong() const { return SONGMAN->GetSongFromDir( sDir ); } + + +XNode* SongID::CreateNode() const +{ + XNode* pNode = new XNode; + pNode->name = "Song"; + + pNode->AppendAttr( "Dir", sDir ); + + return pNode; +} + +void SongID::LoadFromNode( const XNode* pNode ) +{ + ASSERT( pNode->name == "Song" ); + pNode->GetAttrValue("Dir", sDir); +} + +bool SongID::IsValid() const +{ + return !sDir.empty(); +} + diff --git a/stepmania/src/SongUtil.h b/stepmania/src/SongUtil.h index 3005ce2928..ac96c37d6c 100644 --- a/stepmania/src/SongUtil.h +++ b/stepmania/src/SongUtil.h @@ -15,6 +15,7 @@ class Song; class Profile; +struct XNode; namespace SongUtil { @@ -41,6 +42,15 @@ public: SongID() { FromSong(NULL); } void FromSong( const Song *p ); Song *ToSong() const; + bool operator<( const SongID &other ) const + { + return sDir < other.sDir; + } + + XNode* CreateNode() const; + void LoadFromNode( const XNode* pNode ); + + bool IsValid() const; }; diff --git a/stepmania/src/StepsUtil.cpp b/stepmania/src/StepsUtil.cpp index 6027ba60c9..c805d0b158 100644 --- a/stepmania/src/StepsUtil.cpp +++ b/stepmania/src/StepsUtil.cpp @@ -16,6 +16,8 @@ #include "Steps.h" #include "ProfileManager.h" #include "song.h" +#include "SongManager.h" +#include "GameManager.h" // // Sorting stuff @@ -42,9 +44,34 @@ void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, void StepsUtil::SortStepsPointerArrayByNumPlays( vector &vStepsPointers, const Profile* pProfile, bool bDecending ) { + // ugly... + vector vpSongs = SONGMAN->GetAllSongs(); + vector vpAllSteps; + map mapStepsToSong; + { + for( unsigned i=0; i vpSteps = pSong->GetAllSteps(); + for( unsigned j=0; jIsAutogen() ) + continue; // skip + vpAllSteps.push_back( pSteps ); + mapStepsToSong[pSteps] = pSong; + } + } + } + + ASSERT( pProfile ); for(unsigned i = 0; i < vStepsPointers.size(); ++i) - steps_sort_val[vStepsPointers[i]] = ssprintf("%9i", pProfile->GetStepsNumTimesPlayed(vStepsPointers[i])); + { + Steps* pSteps = vStepsPointers[i]; + Song* pSong = mapStepsToSong[pSteps]; + steps_sort_val[vStepsPointers[i]] = ssprintf("%9i", pProfile->GetStepsNumTimesPlayed(pSong,pSteps)); + } stable_sort( vStepsPointers.begin(), vStepsPointers.end(), bDecending ? CompareStepsPointersBySortValueDescending : CompareStepsPointersBySortValueAscending ); steps_sort_val.clear(); } @@ -133,4 +160,37 @@ Steps *StepsID::ToSteps( const Song *p, bool bAllowNull ) const RageException::Throw( "%i, %i, \"%s\"", st, dc, sDescription.c_str() ); } +XNode* StepsID::CreateNode() const +{ + XNode* pNode = new XNode; + pNode->name = "Steps"; + + pNode->AppendAttr( "StepsType", GameManager::NotesTypeToString(st) ); + pNode->AppendAttr( "Difficulty", DifficultyToString(dc) ); + if( dc == DIFFICULTY_EDIT ) + pNode->AppendAttr( "Description", sDescription ); + + return pNode; +} + +void StepsID::LoadFromNode( const XNode* pNode ) +{ + ASSERT( pNode->name == "Steps" ); + + CString sTemp; + + pNode->GetAttrValue("StepsType", sTemp); + st = GameManager::StringToNotesType( sTemp ); + + pNode->GetAttrValue("Difficulty", sTemp); + dc = StringToDifficulty( sTemp ); + + if( dc == DIFFICULTY_EDIT ) + pNode->GetChildValue("Description", sDescription); +} + +bool StepsID::IsValid() const +{ + return st != STEPS_TYPE_INVALID && dc != DIFFICULTY_INVALID; +} diff --git a/stepmania/src/StepsUtil.h b/stepmania/src/StepsUtil.h index a0f5fa1e4e..2415446329 100644 --- a/stepmania/src/StepsUtil.h +++ b/stepmania/src/StepsUtil.h @@ -18,6 +18,7 @@ class Steps; class Song; class Profile; +struct XNode; namespace StepsUtil { @@ -41,6 +42,15 @@ public: StepsID() { FromSteps(NULL); } void FromSteps( const Steps *p ); Steps *ToSteps( const Song *p, bool bAllowNull ) const; + bool operator<( const StepsID &other ) const + { + return st < other.st || dc < other.dc || sDescription < other.sDescription; + } + + XNode* CreateNode() const; + void LoadFromNode( const XNode* pNode ); + + bool IsValid() const; }; #endif