From 668d1974f35c2e68f89ee51954261834d785f9fb Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Tue, 14 Oct 2003 17:06:30 +0000 Subject: [PATCH] add top5 high score saving of Courses and Steps for memory cards/ranking screen --- stepmania/src/Course.cpp | 111 ------ stepmania/src/Course.h | 80 ++++- stepmania/src/GameConstantsAndTypes.h | 4 +- stepmania/src/GameState.cpp | 98 ++++-- stepmania/src/GameState.h | 8 +- stepmania/src/MusicWheelItem.cpp | 4 +- stepmania/src/ProfileManager.cpp | 12 +- stepmania/src/ScreenEvaluation.cpp | 231 +++++++------ stepmania/src/ScreenGameplay.cpp | 1 + stepmania/src/ScreenNameEntry.cpp | 32 +- stepmania/src/ScreenNameEntryTraditional.cpp | 36 +- stepmania/src/ScreenRanking.cpp | 153 +++++++-- stepmania/src/ScreenRanking.h | 5 +- stepmania/src/ScreenSelectMusic.cpp | 12 +- stepmania/src/Song.cpp | 23 +- stepmania/src/SongManager.cpp | 342 +++++++------------ stepmania/src/SongManager.h | 56 ++- stepmania/src/StageStats.cpp | 1 + stepmania/src/StageStats.h | 2 + stepmania/src/Steps.cpp | 44 --- stepmania/src/Steps.h | 84 ++++- stepmania/src/song.h | 4 +- 22 files changed, 703 insertions(+), 640 deletions(-) diff --git a/stepmania/src/Course.cpp b/stepmania/src/Course.cpp index e5bf3de035..1db7df28f7 100644 --- a/stepmania/src/Course.cpp +++ b/stepmania/src/Course.cpp @@ -53,30 +53,6 @@ Course::Course() m_bDifficult = false; m_iLives = -1; m_iMeter = -1; - - SetDefaultScore(); -} - -void Course::SetDefaultScore() -{ - // - // Init high scores - // - for( unsigned i=0; i &apSongs SONGMAN->GetSongs( vSongs, e.group_name ); for( unsigned i = 0; i < vSongs.size(); ++i) m_entries.push_back( e ); - - SetDefaultScore(); } void Course::AutogenNonstopFromGroup( CString sGroupName, vector &apSongsInGroup ) @@ -409,8 +381,6 @@ void Course::AutogenNonstopFromGroup( CString sGroupName, vector &apSongs m_entries.push_back( m_entries[0] ); while( m_entries.size() > 4 ) m_entries.pop_back(); - - SetDefaultScore(); } /* @@ -742,87 +712,6 @@ bool Course::GetTotalSeconds( float& fSecondsOut ) const } -struct RankingToInsert -{ - PlayerNumber pn; - int iScore; - float fSurviveTime; - - static bool CompareDescending( const RankingToInsert &hs1, const RankingToInsert &hs2 ) - { - return hs1.iScore > hs2.iScore; - } - static void SortDescending( vector& vHSout ) - { - sort( vHSout.begin(), vHSout.end(), CompareDescending ); - } -}; - -void Course::AddScores( StepsType nt, bool bPlayerEnabled[NUM_PLAYERS], int iScore[NUM_PLAYERS], float fSurviveTime[NUM_PLAYERS], int iRankingIndexOut[NUM_PLAYERS], bool bNewRecordOut[NUM_PLAYERS] ) -{ - vector vHS; - for( int p=0; p m_MemCardScores[p][nt].iScore ) - { - m_MemCardScores[p][nt].iScore = iScore[p]; - m_MemCardScores[p][nt].fSurviveTime = fSurviveTime[p]; - bNewRecordOut[p] = true; - } - - if( iScore[p] > m_MemCardScores[MEMORY_CARD_MACHINE][nt].iScore ) - { - m_MemCardScores[MEMORY_CARD_MACHINE][nt].iScore = iScore[p]; - m_MemCardScores[MEMORY_CARD_MACHINE][nt].fSurviveTime = fSurviveTime[p]; - } - - - // Update Ranking - RankingToInsert hs; - hs.iScore = iScore[p]; - hs.fSurviveTime = fSurviveTime[p]; - hs.pn = (PlayerNumber)p; - vHS.push_back( hs ); - } - - // Sort descending before inserting. - // This guarantees that a high score will not switch poitions on us when we later insert scores for the other player - RankingToInsert::SortDescending( vHS ); - - for( unsigned i=0; i rankingScores[i].iScore ) - { - // We found the insert point. Shift down. - for( int j=NUM_RANKING_LINES-1; j>i; j-- ) - rankingScores[j] = rankingScores[j-1]; - // insert - rankingScores[i].fSurviveTime = newHS.fSurviveTime; - rankingScores[i].iScore = newHS.iScore; - rankingScores[i].sName = DEFAULT_RANKING_NAME; - iRankingIndexOut[newHS.pn] = i; - break; - } - } - } -} - - // // Sorting stuff // diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index ab62b20baa..368bfc3b9e 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -131,22 +131,75 @@ public: void AutogenNonstopFromGroup( CString sGroupName, vector &apSongsInGroup ); - // Statistics - struct RankingScore - { - /* Dance points for oni, regular score for nonstop. */ - int iScore; - float fSurviveTime; - CString sName; - } m_RankingScores[NUM_STEPS_TYPES][NUM_RANKING_LINES]; // sorted highest to lowest by iDancePoints - struct MemCardScore + struct MemCardData { + MemCardData() + { + iNumTimesPlayed = 0; + } + int iNumTimesPlayed; - int iScore; - float fSurviveTime; - } m_MemCardScores[NUM_MEMORY_CARDS][NUM_STEPS_TYPES]; + + struct HighScore + { + int iScore; + float fSurviveTime; + CString sName; + + HighScore() + { + iScore = 0; + fSurviveTime = 0; + } + + bool operator>( const HighScore& other ) + { + return iScore > other.iScore; + } + }; + vector vHighScores; + + void AddHighScore( HighScore hs, int &iIndexOut ) + { + for( int i=0; i vHighScores[i] ) + { + vHighScores.insert( vHighScores.begin()+i, hs ); + iIndexOut = i; + break; + } + } + if( vHighScores.size() > NUM_RANKING_LINES ) + vHighScores.erase( vHighScores.begin()+NUM_RANKING_LINES, vHighScores.end() ); + } + + HighScore GetTopScore() + { + if( vHighScores.empty() ) + return HighScore(); + else + return vHighScores[0]; + } + + } m_MemCardDatas[NUM_STEPS_TYPES][NUM_MEMORY_CARDS]; - void AddScores( StepsType nt, bool bPlayerEnabled[NUM_PLAYERS], int iDancePoints[NUM_PLAYERS], float fSurviveTime[NUM_PLAYERS], int iRankingIndexOut[NUM_PLAYERS], bool bNewRecordOut[NUM_PLAYERS] ); // iNewRecordIndexOut[p] = -1 if not a new record + void AddHighScore( StepsType st, PlayerNumber pn, MemCardData::HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ) + { + hs.sName = RANKING_TO_FILL_IN_MARKER[pn]; + m_MemCardDatas[st][pn].AddHighScore( hs, iPersonalIndexOut ); + m_MemCardDatas[st][MEMORY_CARD_MACHINE].AddHighScore( hs, iMachineIndexOut ); + } + + MemCardData::HighScore GetTopScore( StepsType st, MemoryCard card ) + { + return m_MemCardDatas[st][card].GetTopScore(); + } + + int GetNumTimesPlayed( StepsType st, MemoryCard card ) + { + return m_MemCardDatas[st][card].iNumTimesPlayed; + } // sorting values int SortOrder_TotalDifficulty; @@ -155,7 +208,6 @@ public: void UpdateCourseStats(); private: - void SetDefaultScore(); void GetMeterRange( int stage, int& iMeterLowOut, int& iMeterHighOut, int Difficult = -1 ) const; }; diff --git a/stepmania/src/GameConstantsAndTypes.h b/stepmania/src/GameConstantsAndTypes.h index a83ad568fb..ed9be6f868 100644 --- a/stepmania/src/GameConstantsAndTypes.h +++ b/stepmania/src/GameConstantsAndTypes.h @@ -13,6 +13,7 @@ ----------------------------------------------------------------------------- */ +#include "PlayerNumber.h" // TODO: Get rid of this dependency. -Chris // // Screen Dimensions @@ -194,7 +195,8 @@ enum RankingCategory NUM_RANKING_CATEGORIES }; -#define DEFAULT_RANKING_NAME CString("STEP") +const CString DEFAULT_RANKING_NAME = ""; +const CString RANKING_TO_FILL_IN_MARKER[NUM_PLAYERS] = {"#P1#","#P2#"}; RankingCategory AverageMeterToRankingCategory( float fAverageMeter ); diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index 31e792b19e..34ab0a1e2c 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -47,7 +47,6 @@ GameState::GameState() m_pPosition = NULL; m_pUnlockingSys = new UnlockSystem; - ResetLastRanking(); ReloadCharacters(); } @@ -160,25 +159,6 @@ void GameState::Update( float fDelta ) } } -void GameState::ResetLastRanking() -{ - for( int p=0; pm_iRankingIndex[pn]; - - if( GAMESTATE->IsCourseMode() ) - GAMESTATE->m_pRankingCourse->m_RankingScores[GAMESTATE->m_RankingNotesType][index].sName = name; - else - SONGMAN->m_MachineScores[GAMESTATE->m_RankingNotesType][GAMESTATE->m_RankingCategory[pn]][index].sName = name; -} - void GameState::ReloadCharacters() { unsigned i; @@ -771,3 +751,81 @@ Character* GameState::GetDefaultCharacter() ASSERT(0); return NULL; } + +void GameState::GetRankingFeats( PlayerNumber pn, CStringArray &asFeatsOut, vector &vpStringsToFillOut ) +{ + switch( GAMESTATE->m_PlayMode ) + { + case PLAY_MODE_ARCADE: + { + int i; + + StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + for( i=0; i &vHighScores = pSteps->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores; + for( int j=0; jGetFullTranslitTitle().c_str() ); + asFeatsOut.push_back( s ); + vpStringsToFillOut.push_back( &vHighScores[j].sName ); + } + } + } + + StageStats stats; + vector vSongs; + GetFinalEvalStatsAndSongs( stats, vSongs ); + + + for( i=0; i &vHighScores = SONGMAN->m_CategoryDatas[nt][i].vHighScores; + for( int j=0; jGetCurrentStyleDef()->m_StepsType; + Course* pCourse = GAMESTATE->m_pCurCourse; + vector &vHighScores = pCourse->m_MemCardDatas[nt][MEMORY_CARD_MACHINE].vHighScores; + for( int i=0; im_sName.c_str() ); + asFeatsOut.push_back( s ); + vpStringsToFillOut.push_back( &vHighScores[i].sName ); + } + } + } + break; + default: + ASSERT(0); + } +} + +void GameState::StoreRankingName( PlayerNumber pn, CString name ) +{ + vector vpStringsToFill; + CStringArray asFeats; + GetRankingFeats( pn, asFeats, vpStringsToFill ); + for( int i=0; i &vpStringsToFillOut ); /* Called by name entry screens: */ void StoreRankingName( PlayerNumber pn, CString name ); diff --git a/stepmania/src/MusicWheelItem.cpp b/stepmania/src/MusicWheelItem.cpp index 16b00f3249..3e6974a8fa 100644 --- a/stepmania/src/MusicWheelItem.cpp +++ b/stepmania/src/MusicWheelItem.cpp @@ -200,9 +200,9 @@ void MusicWheelItem::RefreshGrades() dc = GAMESTATE->m_PreferredDifficulty[p]; Grade grade; if( PROFILEMAN->IsUsingProfile((PlayerNumber)p) ) - grade = data->m_pSong->GetGradeForDifficulty( GAMESTATE->GetCurrentStyleDef(), (MemoryCard)p, dc ); + grade = data->m_pSong->GetHighScoreForDifficulty( GAMESTATE->GetCurrentStyleDef(), (MemoryCard)p, dc ).grade; else - grade = data->m_pSong->GetGradeForDifficulty( GAMESTATE->GetCurrentStyleDef(), MEMORY_CARD_MACHINE, dc ); + grade = data->m_pSong->GetHighScoreForDifficulty( GAMESTATE->GetCurrentStyleDef(), MEMORY_CARD_MACHINE, dc ).grade; m_GradeDisplay[p].SetGrade( (PlayerNumber)p, grade ); } diff --git a/stepmania/src/ProfileManager.cpp b/stepmania/src/ProfileManager.cpp index 04ccad802c..092801f46a 100644 --- a/stepmania/src/ProfileManager.cpp +++ b/stepmania/src/ProfileManager.cpp @@ -24,8 +24,8 @@ ProfileManager* PROFILEMAN = NULL; // global and accessable from anywhere in our #define PROFILE_FILE "Profile.ini" -#define NOTES_SCORES_FILE "NotesScores.dat" -#define COURSE_SCORES_FILE "CourseScores.dat" +#define STEPS_MEM_CARD_DATA_FILE "StepsMemCardData.dat" +#define COURSE_MEM_CARD_DATA_FILE "CourseMemCardData.dat" ProfileManager::ProfileManager() { @@ -90,8 +90,8 @@ void ProfileManager::TryLoadProfile( PlayerNumber pn ) // // Load scores into SONGMAN // - SONGMAN->ReadNoteScoresFromFile( m_sProfileDir[pn]+NOTES_SCORES_FILE, (MemoryCard)pn ); - SONGMAN->ReadCourseScoresFromFile( m_sProfileDir[pn]+COURSE_SCORES_FILE, (MemoryCard)pn ); + SONGMAN->ReadStepsMemCardDataFromFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn ); + SONGMAN->ReadCourseMemCardDataFromFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn ); } void ProfileManager::UnloadProfile( PlayerNumber pn ) @@ -104,8 +104,8 @@ void ProfileManager::UnloadProfile( PlayerNumber pn ) // // Save scores into SONGMAN // - SONGMAN->SaveNoteScoresToFile( m_sProfileDir[pn]+NOTES_SCORES_FILE, (MemoryCard)pn ); - SONGMAN->SaveCourseScoresToFile( m_sProfileDir[pn]+COURSE_SCORES_FILE, (MemoryCard)pn ); + SONGMAN->SaveStepsMemCardDataToFile( m_sProfileDir[pn]+STEPS_MEM_CARD_DATA_FILE, (MemoryCard)pn ); + SONGMAN->SaveCourseMemCardDataToFile( m_sProfileDir[pn]+COURSE_MEM_CARD_DATA_FILE, (MemoryCard)pn ); // clear out the displayname and highscore name when we unload the profile. m_Profile[pn].Init(); diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index a89a83d4ba..bb324b0da3 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -165,119 +165,146 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) // // update persistent statistics // - bool bNewRecord[NUM_PLAYERS]; - ZERO( bNewRecord ); + int iPersonalHighScoreIndex[NUM_PLAYERS]; + int iMachineHighScoreIndex[NUM_PLAYERS]; + RankingCategory rc[NUM_PLAYERS]; + memset( iPersonalHighScoreIndex, -1, sizeof(iPersonalHighScoreIndex) ); + memset( iMachineHighScoreIndex, -1, sizeof(iMachineHighScoreIndex) ); + memset( rc, -1, sizeof(rc) ); - switch( m_Type ) + for( p=0; pIsHumanPlayer(p) ) + continue; // skip + if( !GAMESTATE->m_SongOptions.m_bSaveScore ) + continue; // skip + + switch( m_Type ) { - for( int p=0; pIsHumanPlayer(p) && GAMESTATE->m_SongOptions.m_bSaveScore ) - { - if( GAMESTATE->m_pCurNotes[p] ) - { - float score; - if( PREFSMAN->m_bPercentageScoring ) - score = stageStats.GetPercentDancePoints( (PlayerNumber)p ); - else - score = float(stageStats.iScore[p] + stageStats.iBonus[p]); - GAMESTATE->m_pCurNotes[p]->AddScore( (PlayerNumber)p, grade[p], score, bNewRecord[p] ); - } - - // update unlock data if unlocks are on - if ( PREFSMAN->m_bUseUnlockSystem ) - { - UNLOCKSYS->UnlockClearStage(); - UNLOCKSYS->UnlockAddAP( grade[p] ); - UNLOCKSYS->UnlockAddSP( grade[p] ); - - // we want to save dance points here if we are in event mode. - // otherwise, dance points will never get saved except - // in nonstop mode. - if( PREFSMAN->m_bEventMode ) - UNLOCKSYS->UnlockAddDP( (float)stageStats.iActualDancePoints[p] ); - - } - } - } - } - break; - case summary: - { - StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; - bool bIsHumanPlayer[NUM_PLAYERS]; - for( p=0; pIsHumanPlayer(p); - - RankingCategory cat[NUM_PLAYERS]; - int iRankingIndex[NUM_PLAYERS]; - float fTotalDP = 0; - for( int p=0; pm_iNumArcadeStages; - cat[p] = AverageMeterToRankingCategory( fAverageMeter ); - fTotalDP += stageStats.iActualDancePoints[p]; - } - - SONGMAN->AddScores( nt, bIsHumanPlayer, cat, stageStats.iScore, iRankingIndex ); - - COPY( GAMESTATE->m_RankingCategory, cat ); - COPY( GAMESTATE->m_iRankingIndex, iRankingIndex ); - GAMESTATE->m_RankingNotesType = nt; - - // If unlocking is enabled, save the dance points - if( PREFSMAN->m_bUseUnlockSystem ) - UNLOCKSYS->UnlockAddDP( fTotalDP ); - } - break; - case course: - { - bool bIsHumanPlayer[NUM_PLAYERS]; - for( p=0; pIsHumanPlayer(p); - - int iRankingIndex[NUM_PLAYERS]; - - Course* pCourse = GAMESTATE->m_pCurCourse; - if( pCourse ) - { - int *score; - if( pCourse->IsOni() ) - score = stageStats.iActualDancePoints; + ASSERT( GAMESTATE->m_pCurNotes[p] ); + float score; + if( PREFSMAN->m_bPercentageScoring ) + score = stageStats.GetPercentDancePoints( (PlayerNumber)p ); else - score = stageStats.iScore; - - StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; - pCourse->AddScores( nt, bIsHumanPlayer, score, stageStats.fAliveSeconds, iRankingIndex, bNewRecord ); - COPY( GAMESTATE->m_iRankingIndex, iRankingIndex ); - GAMESTATE->m_pRankingCourse = pCourse; - GAMESTATE->m_RankingNotesType = nt; - } - - // If unlocking is enabled, save the dance points - // (for courses) - if( PREFSMAN->m_bUseUnlockSystem ) - { - for(p=0; p < NUM_PLAYERS; p++) + score = float(stageStats.iScore[p] + stageStats.iBonus[p]); + Steps::MemCardData::HighScore hs; + hs.grade = grade[p]; + hs.fScore = score; + GAMESTATE->m_pCurNotes[p]->AddHighScore( (PlayerNumber)p, hs, iPersonalHighScoreIndex[p], iMachineHighScoreIndex[p] ); + + // update unlock data if unlocks are on + if ( PREFSMAN->m_bUseUnlockSystem ) { - if( !GAMESTATE->IsPlayerEnabled( (PlayerNumber)p ) ) - continue; // skip + UNLOCKSYS->UnlockClearStage(); + UNLOCKSYS->UnlockAddAP( grade[p] ); + UNLOCKSYS->UnlockAddSP( grade[p] ); + + // we want to save dance points here if we are in event mode. + // otherwise, dance points will never get saved except + // in nonstop mode. + if( PREFSMAN->m_bEventMode ) + UNLOCKSYS->UnlockAddDP( (float)stageStats.iActualDancePoints[p] ); - UNLOCKSYS->UnlockAddDP( (float) stageStats.iActualDancePoints[p] ); - UNLOCKSYS->UnlockAddAP( (float) stageStats.iSongsPassed[p] ); - UNLOCKSYS->UnlockAddSP( (float) stageStats.iSongsPassed[p] ); } } - // cannot just use score since it may be nonstop mode + break; + case summary: + { + StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + float fAverageMeter = stageStats.iMeter[p] / (float)PREFSMAN->m_iNumArcadeStages; + rc[p] = AverageMeterToRankingCategory( fAverageMeter ); + float fTotalDP = stageStats.iActualDancePoints[p]; + SongManager::CategoryData::HighScore hs; + hs.iScore = stageStats.iScore[p]; + SONGMAN->AddHighScore( nt, rc[p], (PlayerNumber)p, hs, iMachineHighScoreIndex[p] ); + + // If unlocking is enabled, save the dance points + if( PREFSMAN->m_bUseUnlockSystem ) + UNLOCKSYS->UnlockAddDP( fTotalDP ); + } + break; + case course: + { + Course* pCourse = GAMESTATE->m_pCurCourse; + if( pCourse ) + { + int score; + if( pCourse->IsOni() ) + score = stageStats.iActualDancePoints[p]; + else + score = stageStats.iScore[p]; + + StepsType nt = GAMESTATE->GetCurrentStyleDef()->m_StepsType; + Course::MemCardData::HighScore hs; + hs.iScore = score; + hs.fSurviveTime = stageStats.fAliveSeconds[p]; + pCourse->AddHighScore( nt, (PlayerNumber)p, hs, iPersonalHighScoreIndex[p], iMachineHighScoreIndex[p] ); + } + + // If unlocking is enabled, save the dance points + // (for courses) + if( PREFSMAN->m_bUseUnlockSystem ) + { + for(p=0; p < NUM_PLAYERS; p++) + { + if( !GAMESTATE->IsPlayerEnabled( (PlayerNumber)p ) ) + continue; // skip + + UNLOCKSYS->UnlockAddDP( (float) stageStats.iActualDancePoints[p] ); + UNLOCKSYS->UnlockAddAP( (float) stageStats.iSongsPassed[p] ); + UNLOCKSYS->UnlockAddSP( (float) stageStats.iSongsPassed[p] ); + } + } + // cannot just use score since it may be nonstop mode + + } + break; + default: + ASSERT(0); + } + } + + + // If both players get a machine high score, a player + // whose score is added later may bump the players who were + // added earlier. Adjust for this. + for( p=0; pIsHumanPlayer(p) ) + continue; // skip + if( iMachineHighScoreIndex[p] == -1 ) // no record + continue; // skip + for( int p2=0; p2IsHumanPlayer(p2) ) + continue; // skip + if( iMachineHighScoreIndex[p2] == -1 ) // no record + continue; // skip + bool bPlayedSameSteps; + switch( m_Type ) + { + case stage: + bPlayedSameSteps = GAMESTATE->m_pCurNotes[p]==GAMESTATE->m_pCurNotes[p2]; + break; + case summary: + bPlayedSameSteps = rc[p] == rc[p2]; + break; + case course: + bPlayedSameSteps = true; + break; + } + if( iMachineHighScoreIndex[p] >= iMachineHighScoreIndex[p2] ) + { + iMachineHighScoreIndex[p2]++; + if( iMachineHighScoreIndex[p2] >= NUM_RANKING_LINES ) + iMachineHighScoreIndex[p2] = -1; + } } - break; - default: - ASSERT(0); } m_bTryExtraStage = @@ -628,7 +655,7 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) // for( p=0; pGetPathToG("ScreenEvaluation new record") ); m_sprNewRecord[p].SetName( ssprintf("NewRecordP%d",p+1) ); @@ -639,7 +666,7 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) bool bOneHasNewRecord = false; for( p=0; pIsPlayerEnabled(p) && bNewRecord[p] ) + if( GAMESTATE->IsPlayerEnabled(p) && iPersonalHighScoreIndex[p] == 0 ) bOneHasNewRecord = true; if( m_bTryExtraStage ) diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index d13a6f9692..32da8af191 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -187,6 +187,7 @@ ScreenGameplay::ScreenGameplay( CString sName, bool bDemonstration ) : Screen("S continue; // skip ASSERT( !m_apNotesQueue[p].empty() ); + GAMESTATE->m_CurStageStats.pSteps[p] = m_apNotesQueue[p][0]; GAMESTATE->m_CurStageStats.iMeter[p] = m_apNotesQueue[p][0]->GetMeter(); } diff --git a/stepmania/src/ScreenNameEntry.cpp b/stepmania/src/ScreenNameEntry.cpp index 150bad5826..3eef07d73a 100644 --- a/stepmania/src/ScreenNameEntry.cpp +++ b/stepmania/src/ScreenNameEntry.cpp @@ -129,9 +129,16 @@ ScreenNameEntry::ScreenNameEntry( CString sClassName ) : Screen( sClassName ) } int p; + + CStringArray asFeats[NUM_PLAYERS]; + vector vpStringsToFill[NUM_PLAYERS]; + // Find out if players deserve to enter their name for( p=0; pm_iRankingIndex[p] != -1; + { + GAMESTATE->GetRankingFeats( (PlayerNumber)p, asFeats[p], vpStringsToFill[p] ); + m_bStillEnteringName[p] = asFeats[p].size()>0; + } if( !AnyStillEntering() ) { @@ -201,28 +208,7 @@ ScreenNameEntry::ScreenNameEntry( CString sClassName ) : Screen( sClassName ) m_textCategory[p].LoadFromFont( THEME->GetPathToF("ScreenNameEntry category") ); m_textCategory[p].SetX( (float)GAMESTATE->GetCurrentStyleDef()->m_iCenterX[p] ); m_textCategory[p].SetY( CATEGORY_Y ); - CString sCategoryText = ssprintf("No. %d in\n", GAMESTATE->m_iRankingIndex[p]+1); - switch( GAMESTATE->m_PlayMode ) - { - case PLAY_MODE_ARCADE: - case PLAY_MODE_BATTLE: - case PLAY_MODE_RAVE: - { - StageStats SS; - vector vSongs; - GAMESTATE->GetFinalEvalStatsAndSongs( SS, vSongs ); - sCategoryText += ssprintf("Type %c (%d)", 'A'+GAMESTATE->m_RankingCategory[p], SS.iMeter[p] ); - } - break; - case PLAY_MODE_NONSTOP: - case PLAY_MODE_ONI: - case PLAY_MODE_ENDLESS: - sCategoryText += ssprintf("%s", GAMESTATE->m_pCurCourse->m_sName.c_str()); - break; - default: - ASSERT(0); - } - m_textCategory[p].SetText( sCategoryText ); + m_textCategory[p].SetText( join("\n", asFeats[p]) ); this->AddChild( &m_textCategory[p] ); } diff --git a/stepmania/src/ScreenNameEntryTraditional.cpp b/stepmania/src/ScreenNameEntryTraditional.cpp index 0f09015186..dec19e45c5 100644 --- a/stepmania/src/ScreenNameEntryTraditional.cpp +++ b/stepmania/src/ScreenNameEntryTraditional.cpp @@ -57,16 +57,19 @@ ScreenNameEntryTraditional::ScreenNameEntryTraditional( CString sClassName ) : S GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; GAMESTATE->m_bSideIsJoined[PLAYER_2] = true; GAMESTATE->m_MasterPlayerNumber = PLAYER_1; - GAMESTATE->m_RankingCategory[PLAYER_1] = RANKING_A; - GAMESTATE->m_iRankingIndex[PLAYER_1] = 0; - GAMESTATE->m_RankingCategory[PLAYER_2] = RANKING_A; - GAMESTATE->m_iRankingIndex[PLAYER_2] = 0; GAMESTATE->m_PlayMode = PLAY_MODE_ARCADE; int p; + + CStringArray asFeats[NUM_PLAYERS]; + vector vpStringsToFill[NUM_PLAYERS]; + // Find out if players deserve to enter their name for( p=0; pm_iRankingIndex[p] != -1; + { + GAMESTATE->GetRankingFeats( (PlayerNumber)p, asFeats[p], vpStringsToFill[p] ); + m_bStillEnteringName[p] = asFeats[p].size()>0; + } if( !AnyStillEntering() ) { @@ -146,28 +149,7 @@ ScreenNameEntryTraditional::ScreenNameEntryTraditional( CString sClassName ) : S m_textCategory[p].LoadFromFont( THEME->GetPathToF("ScreenNameEntryTraditional category") ); m_textCategory[p].SetName( ssprintf("Category", p+1) ); SET_XY_AND_ON_COMMAND( m_textCategory[p] ); - CString sCategoryText = ssprintf("No. %d in\n", GAMESTATE->m_iRankingIndex[p]+1); - switch( GAMESTATE->m_PlayMode ) - { - case PLAY_MODE_ARCADE: - case PLAY_MODE_BATTLE: - case PLAY_MODE_RAVE: - { - StageStats SS; - vector vSongs; - GAMESTATE->GetFinalEvalStatsAndSongs( SS, vSongs ); - sCategoryText += ssprintf("Type %c (%d)", 'A'+GAMESTATE->m_RankingCategory[p], SS.iMeter[p] ); - } - break; - case PLAY_MODE_NONSTOP: - case PLAY_MODE_ONI: - case PLAY_MODE_ENDLESS: - sCategoryText += ssprintf("%s", GAMESTATE->m_pCurCourse->m_sName.c_str()); - break; - default: - ASSERT(0); - } - m_textCategory[p].SetText( sCategoryText ); + m_textCategory[p].SetText( join("\n", asFeats[p]) ); this->AddChild( &m_textCategory[p] ); } diff --git a/stepmania/src/ScreenRanking.cpp b/stepmania/src/ScreenRanking.cpp index 52e718ac32..0b6a13f07c 100644 --- a/stepmania/src/ScreenRanking.cpp +++ b/stepmania/src/ScreenRanking.cpp @@ -16,6 +16,7 @@ #include "GameState.h" #include "GameManager.h" #include "Course.h" +#include "Song.h" #include "PrefsManager.h" #define CATEGORY_X THEME->GetMetricF("ScreenRanking","CategoryX") @@ -37,9 +38,19 @@ #define POINTS_START_Y THEME->GetMetricF("ScreenRanking","PointsStartY") #define TIME_START_X THEME->GetMetricF("ScreenRanking","TimeStartX") #define TIME_START_Y THEME->GetMetricF("ScreenRanking","TimeStartY") +#define PERCENT_START_X THEME->GetMetricF("ScreenRanking","PercentStartX") +#define PERCENT_START_Y THEME->GetMetricF("ScreenRanking","PercentStartY") +#define PERCENT_COL_SPACING_X THEME->GetMetricF("ScreenRanking","PercentColSpacingX") +#define PERCENT_COL_SPACING_Y THEME->GetMetricF("ScreenRanking","PercentColSpacingY") #define SECONDS_PER_PAGE THEME->GetMetricF("ScreenRanking","SecondsPerPage") #define SHOW_CATEGORIES THEME->GetMetricB("ScreenRanking","ShowCategories") +#define SHOW_ALL_SONGS THEME->GetMetricB("ScreenRanking","ShowAllSongs") #define NOTES_TYPES_TO_HIDE THEME->GetMetric ("ScreenRanking","NotesTypesToHide") +#define EMPTY_SCORE_NAME THEME->GetMetric ("ScreenRanking","EmptyScoreName") +#define EMPTY_CATEGORY_SCORE THEME->GetMetricI("ScreenRanking","EmptyCategoryScore") +#define EMPTY_COURSE_SCORE THEME->GetMetricI("ScreenRanking","EmptyCourseScore") +#define EMPTY_COURSE_TIME THEME->GetMetricF("ScreenRanking","EmptyCourseTime") +#define EMPTY_SONG_PERCENT THEME->GetMetricF("ScreenRanking","EmptySongPercent") #define COURSES_TO_SHOW PREFSMAN->m_sCoursesToShowRanking @@ -97,6 +108,17 @@ ScreenRanking::ScreenRanking( CString sClassName ) : ScreenAttract( sClassName ) m_textTime[i].SetHorizAlign( Actor::align_right ); this->AddChild( &m_textTime[i] ); + for( int j=0; jGetPathToF("ScreenRanking letters") ); + m_textPercent[i][j].EnableShadow( false ); + m_textPercent[i][j].SetX( PERCENT_START_X+LINE_SPACING_X*i+PERCENT_COL_SPACING_X*j ); + m_textPercent[i][j].SetY( PERCENT_START_Y+LINE_SPACING_Y*i+PERCENT_COL_SPACING_Y*j ); + m_textPercent[i][j].SetZoom( TEXT_ZOOM ); + m_textPercent[i][j].SetHorizAlign( Actor::align_right ); + this->AddChild( &m_textPercent[i][j] ); + } + if( PREFSMAN->m_sCoursesToShowRanking == "" ) PREFSMAN->m_sCoursesToShowRanking = THEME->GetMetric("ScreenRanking","CoursesToShow"); } @@ -157,6 +179,23 @@ ScreenRanking::ScreenRanking( CString sClassName ) : ScreenAttract( sClassName ) } } + if( SHOW_ALL_SONGS ) + { + vector vpSongs = SONGMAN->GetAllSongs(); + for( unsigned i=0; iMoveToTail( &m_In ); // put it in the back so it covers up the stuff we just added this->MoveToTail( &m_Out ); // put it in the back so it covers up the stuff we just added @@ -197,6 +236,16 @@ void ScreenRanking::HandleScreenMessage( const ScreenMessage SM ) void ScreenRanking::SetPage( PageToShow pts ) { + // Clear all text + for( int l=0; lGetPathToG("ScreenRanking type "+GameManager::NotesTypeToString(pts.nt)) ); for( int l=0; lm_CategoryDatas[pts.nt][pts.category].vHighScores.size() ) + { + hs = SONGMAN->m_CategoryDatas[pts.nt][pts.category].vHighScores[l]; + } + else + { + hs.sName = EMPTY_SCORE_NAME; + hs.iScore = EMPTY_CATEGORY_SCORE; + } + m_sprBullets[l].SetDiffuse( RageColor(1,1,1,1) ); - CString sName = SONGMAN->m_MachineScores[pts.nt][pts.category][l].sName; - int iScore = SONGMAN->m_MachineScores[pts.nt][pts.category][l].iScore; - m_textNames[l].SetText( sName ); - m_textScores[l].SetText( ssprintf("%09i",iScore) ); - m_textPoints[l].SetText( "" ); - m_textTime[l].SetText( "" ); + m_textNames[l].SetText( hs.sName ); + m_textScores[l].SetText( ssprintf("%09i",hs.iScore) ); m_textNames[l].SetDiffuse( TEXT_COLOR(pts.colorIndex) ); m_textScores[l].SetDiffuse( TEXT_COLOR(pts.colorIndex) ); bool bRecentHighScore = false; - for( int p=0; pm_RankingNotesType && - GAMESTATE->m_RankingCategory[p] == pts.category && - GAMESTATE->m_iRankingIndex[p] == l; - } + // FIXME +// for( int p=0; pm_RankingNotesType && +// GAMESTATE->m_RankingCategory[p] == pts.category && +// GAMESTATE->m_iRankingIndex[p] == l; +// } if( bRecentHighScore ) { @@ -259,20 +316,29 @@ void ScreenRanking::SetPage( PageToShow pts ) m_sprType.Load( THEME->GetPathToG("ScreenRanking type "+GameManager::NotesTypeToString(pts.nt)) ); for( int l=0; lm_MemCardDatas[pts.nt][MEMORY_CARD_MACHINE].vHighScores.size() ) + { + hs = pts.pCourse->m_MemCardDatas[pts.nt][MEMORY_CARD_MACHINE].vHighScores[l]; + } + else + { + hs.sName = EMPTY_SCORE_NAME; + hs.iScore = EMPTY_COURSE_SCORE; + hs.fSurviveTime = EMPTY_COURSE_TIME; + } + m_sprBullets[l].SetDiffuse( RageColor(1,1,1,1) ); - CString sName = pts.pCourse->m_RankingScores[pts.nt][l].sName; - const int iScore = pts.pCourse->m_RankingScores[pts.nt][l].iScore; - const float fSurviveTime = pts.pCourse->m_RankingScores[pts.nt][l].fSurviveTime; - m_textNames[l].SetText( sName ); + m_textNames[l].SetText( hs.sName ); if( pts.pCourse->IsOni() ) { - m_textPoints[l].SetText( ssprintf("%04d",iScore) ); - m_textTime[l].SetText( SecondsToTime(fSurviveTime) ); + m_textPoints[l].SetText( ssprintf("%04d",hs.iScore) ); + m_textTime[l].SetText( SecondsToTime(hs.fSurviveTime) ); m_textScores[l].SetText( "" ); } else { m_textPoints[l].SetText( "" ); m_textTime[l].SetText( "" ); - m_textScores[l].SetText( ssprintf("%09d",iScore) ); + m_textScores[l].SetText( ssprintf("%09d",hs.iScore) ); } m_textNames[l].SetDiffuse( TEXT_COLOR(pts.colorIndex) ); m_textPoints[l].SetDiffuse( TEXT_COLOR(pts.colorIndex) ); @@ -280,9 +346,12 @@ void ScreenRanking::SetPage( PageToShow pts ) m_textScores[l].SetDiffuse( TEXT_COLOR(pts.colorIndex) ); for( int p=0; pm_pRankingCourse && - pts.nt == GAMESTATE->m_RankingNotesType && - GAMESTATE->m_iRankingIndex[p] == l ) + bool bHighlight = false; + // FIXME +// bHighlight = pts.pCourse == GAMESTATE->m_pRankingCourse && +// pts.nt == GAMESTATE->m_RankingNotesType && +// GAMESTATE->m_iRankingIndex[p] == l; + if( bHighlight ) { m_textNames[l].SetEffectGlowBlink(0.1f); m_textScores[l].SetEffectGlowBlink(0.1f); @@ -296,6 +365,44 @@ void ScreenRanking::SetPage( PageToShow pts ) } } break; + case PageToShow::TYPE_SONG: + { + m_textCategory.SetDiffuseAlpha(0); + m_sprCategory.SetDiffuseAlpha(0); + + m_sprCategory.Load( pts.pSong->GetBannerPath() ); + m_sprCategory.SetDiffuseAlpha(1); + m_textCategory.SetZoom(1); + m_textCategory.SetTextMaxWidth( CATEGORY_WIDTH, pts.pSong->GetFullTranslitTitle() ); + m_textCategory.SetDiffuseAlpha(1); + + m_sprType.SetDiffuse( RageColor(1,1,1,1) ); + m_sprType.Load( THEME->GetPathToG("ScreenRanking type "+GameManager::NotesTypeToString(pts.nt)) ); + for( int l=0; lGetStepsByDifficulty( pts.nt, dc ); + + Steps::MemCardData::HighScore hs; + if( l < pSteps->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores.size() ) + { + hs = pSteps->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[l]; + } + else + { + hs.sName = EMPTY_SCORE_NAME; + hs.fScore = EMPTY_SONG_PERCENT; + } + + m_textPercent[l][d].SetText( ssprintf("%s %f%", hs.sName.c_str(), hs.fScore) ); + } + } + } + break; default: ASSERT(0); } diff --git a/stepmania/src/ScreenRanking.h b/stepmania/src/ScreenRanking.h index 96d3bcddee..3d5339f3c1 100644 --- a/stepmania/src/ScreenRanking.h +++ b/stepmania/src/ScreenRanking.h @@ -16,6 +16,7 @@ #include "BitmapText.h" class Course; +class Song; class ScreenRanking : public ScreenAttract { @@ -27,11 +28,12 @@ public: protected: struct PageToShow { - enum { TYPE_CATEGORY, TYPE_COURSE } type; + enum { TYPE_CATEGORY, TYPE_COURSE, TYPE_SONG } type; int colorIndex; StepsType nt; // used in category and course RankingCategory category; Course* pCourse; + Song* pSong; }; void SetPage( PageToShow pts ); @@ -47,6 +49,7 @@ protected: BitmapText m_textScores[NUM_RANKING_LINES]; // for category BitmapText m_textPoints[NUM_RANKING_LINES]; // for course BitmapText m_textTime[NUM_RANKING_LINES]; // for course + BitmapText m_textPercent[NUM_RANKING_LINES][NUM_DIFFICULTIES]; // for song vector m_vPagesToShow; }; diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index 5aae43764e..0b033892f9 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -900,11 +900,17 @@ void ScreenSelectMusic::AfterNotesChange( PlayerNumber pn ) if( pNotes ) { - float fScore; + float fScore = 0; if( PROFILEMAN->IsUsingProfile(pn) ) - fScore = pNotes->m_MemCardScores[pn].fScore; + { + if( !pNotes->m_MemCardDatas[pn].vHighScores.empty() ) + fScore = pNotes->m_MemCardDatas[pn].vHighScores[0].fScore; + } else - fScore = pNotes->m_MemCardScores[MEMORY_CARD_MACHINE].fScore; + { + if( !pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores.empty() ) + fScore = pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].fScore; + } m_textHighScore[pn].SetText( ssprintf("%*i", NUM_SCORE_DIGITS, (int) fScore) ); } else diff --git a/stepmania/src/Song.cpp b/stepmania/src/Song.cpp index 2e1285c426..26b3cec777 100644 --- a/stepmania/src/Song.cpp +++ b/stepmania/src/Song.cpp @@ -1180,22 +1180,19 @@ void Song::RemoveAutoGenNotes() } -Grade Song::GetGradeForDifficulty( const StyleDef *st, MemoryCard card, Difficulty dc ) const +Steps::MemCardData::HighScore Song::GetHighScoreForDifficulty( const StyleDef *st, MemoryCard card, Difficulty dc ) const { // return max grade of notes in difficulty class vector aNotes; this->GetSteps( aNotes, st->m_StepsType ); SortNotesArrayByDifficulty( aNotes ); - Grade grade = GRADE_NO_DATA; - for( unsigned i=0; iGetDifficulty() == dc ) - grade = max( grade, pNotes->m_MemCardScores[card].grade ); - } - return grade; + Steps* pSteps = GetStepsByDifficulty( st->m_StepsType, dc ); + if( pSteps ) + return pSteps->GetTopScore(card); + else + return Steps::MemCardData::HighScore(); } @@ -1549,7 +1546,7 @@ int Song::GetNumTimesPlayed() const int iTotalNumTimesPlayed = 0; for( unsigned i=0; im_MemCardScores[MEMORY_CARD_MACHINE].iNumTimesPlayed; + iTotalNumTimesPlayed += m_apNotes[i]->GetNumTimesPlayed(MEMORY_CARD_MACHINE); } return iTotalNumTimesPlayed; } @@ -1696,8 +1693,12 @@ int Song::GetNumNotesWithGrade( Grade g ) const vector vNotes; this->GetSteps( vNotes, GAMESTATE->GetCurrentStyleDef()->m_StepsType ); for( unsigned j=0; jm_MemCardScores[MEMORY_CARD_MACHINE].grade == g ) + { + Steps* pSteps = vNotes[j]; + + if( pSteps->GetTopScore(MEMORY_CARD_MACHINE).grade == g ) iCount++; + } return iCount; } diff --git a/stepmania/src/SongManager.cpp b/stepmania/src/SongManager.cpp index cc53a7b4fb..10cd84e089 100644 --- a/stepmania/src/SongManager.cpp +++ b/stepmania/src/SongManager.cpp @@ -36,14 +36,12 @@ SongManager* SONGMAN = NULL; // global and accessable from anywhere in our progr #define SONGS_DIR BASE_PATH "Songs" SLASH #define COURSES_DIR BASE_PATH "Courses" SLASH #define STATS_PATH BASE_PATH "stats.html" -const CString CATEGORY_RANKING_FILE = BASE_PATH "Data" SLASH "CategoryRanking.dat"; -const CString COURSE_RANKING_FILE = BASE_PATH "Data" SLASH "CourseRanking.dat"; -const CString MACHINE_NOTES_SCORES_FILE = "Data" SLASH "MachineNotesScores.dat"; -const CString MACHINE_COURSE_SCORES_FILE = "Data" SLASH "MachineCourseScores.dat"; +const CString CATEGORY_RANKING_FILE = BASE_PATH "Data" SLASH "CategoryRanking.dat"; +const CString MACHINE_STEPS_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineStepsMemCardData.dat"; +const CString MACHINE_COURSE_MEM_CARD_DATA = BASE_PATH "Data" SLASH "MachineCourseMemCardData.dat"; const int CATEGORY_RANKING_VERSION = 1; -const int COURSE_RANKING_VERSION = 1; -const int NOTES_SCORES_VERSION = 2; -const int COURSE_SCORES_VERSION = 1; +const int STEPS_MEM_CARD_DATA_VERSION = 3; +const int COURSE_MEM_CARD_DATA_VERSION = 2; #define NUM_GROUP_COLORS THEME->GetMetricI("SongManager","NumGroupColors") @@ -121,9 +119,8 @@ void SongManager::Reload() void SongManager::SaveMachineScoresToDisk() { SaveCategoryRankingsToFile( CATEGORY_RANKING_FILE ); - SaveCourseRankingsToFile( COURSE_RANKING_FILE ); - SaveNoteScoresToFile( MACHINE_NOTES_SCORES_FILE, MEMORY_CARD_MACHINE ); - SaveCourseScoresToFile( MACHINE_COURSE_SCORES_FILE, MEMORY_CARD_MACHINE ); + SaveStepsMemCardDataToFile( MACHINE_STEPS_MEM_CARD_DATA, MEMORY_CARD_MACHINE ); + SaveCourseMemCardDataToFile( MACHINE_COURSE_MEM_CARD_DATA, MEMORY_CARD_MACHINE ); } void SongManager::InitSongsFromDisk( LoadingWindow *ld ) @@ -308,7 +305,7 @@ static CString ReadLine( FILE *fp ) } -void SongManager::ReadNoteScoresFromFile( CString fn, int c ) +void SongManager::ReadStepsMemCardDataFromFile( CString fn, int c ) { ifstream f(fn); if( !f.good() ) @@ -319,7 +316,7 @@ void SongManager::ReadNoteScoresFromFile( CString fn, int c ) int version; sscanf(line.c_str(), "%i", &version); - if( version != NOTES_SCORES_VERSION ) + if( version != STEPS_MEM_CARD_DATA_VERSION ) return; while( f && !f.eof() ) @@ -357,59 +354,32 @@ void SongManager::ReadNoteScoresFromFile( CString fn, int c ) getline(f, line); int iNumTimesPlayed; - Grade grade; - float fScore; - if( sscanf(line.c_str(), "%d %d %f\n", &iNumTimesPlayed, (int *)&grade, &fScore) != 3 ) - break; + if( sscanf(line.c_str(), "%d\n", &iNumTimesPlayed ) != 1 ) + return; if( pNotes ) + pNotes->m_MemCardDatas[c].iNumTimesPlayed = iNumTimesPlayed; + + if( pNotes ) + pNotes->m_MemCardDatas[c].vHighScores.resize(NUM_RANKING_LINES); + + for( int k=0; km_MemCardScores[c].iNumTimesPlayed = iNumTimesPlayed; - pNotes->m_MemCardScores[c].grade = grade; - pNotes->m_MemCardScores[c].fScore = fScore; + Grade grade; + float fScore; + char szName[256]; // TODO: not overflow safe + if( sscanf(line.c_str(), "%d %f %[^\n]\n", (int *)&grade, &fScore, szName) != 3 ) + return; + if( pNotes ) + { + pNotes->m_MemCardDatas[c].vHighScores[k].grade = grade; + pNotes->m_MemCardDatas[c].vHighScores[k].fScore = fScore; + pNotes->m_MemCardDatas[c].vHighScores[k].sName = szName; + } } } } } -void SongManager::ReadCourseScoresFromFile( CString fn, int c ) -{ - FILE* fp = fopen( fn, "r" ); - - if( !fp ) - return; - - int version; - fscanf(fp, "%d\n", &version ); - - if( version == COURSE_SCORES_VERSION ) - { - while( fp && !feof(fp) ) - { - CString path=ReadLine( fp ); - - Course* pCourse = GetCourseFromPath( path ); - if( pCourse == NULL ) - pCourse = GetCourseFromName( path ); - - for( int i=0; im_MemCardScores[c][i].iNumTimesPlayed = iNumTimesPlayed; - pCourse->m_MemCardScores[c][i].iScore = iScore; - pCourse->m_MemCardScores[c][i].fSurviveTime = fSurviveTime; - } - } - } - } - - fclose(fp); -} void SongManager::ReadCategoryRankingsFromFile( CString fn ) { @@ -422,27 +392,32 @@ void SongManager::ReadCategoryRankingsFromFile( CString fn ) if( version == CATEGORY_RANKING_VERSION ) { for( int i=0; im_MemCardDatas[i][c].iNumTimesPlayed = iNumTimesPlayed; + if( pCourse ) + pCourse->m_MemCardDatas[i][c].vHighScores.resize(NUM_RANKING_LINES); for( int j=0; jm_RankingScores[i][j].iScore = iScore; - pCourse->m_RankingScores[i][j].fSurviveTime = fSurviveTime; - pCourse->m_RankingScores[i][j].sName = szName; + pCourse->m_MemCardDatas[i][c].vHighScores[j].iScore = iScore; + pCourse->m_MemCardDatas[i][c].vHighScores[j].fSurviveTime = fSurviveTime; + pCourse->m_MemCardDatas[i][c].vHighScores[j].sName = szName; } } + } + } } } @@ -475,30 +461,17 @@ void SongManager::ReadCourseRankingsFromFile( CString fn ) void SongManager::InitMachineScoresFromDisk() { - // Init category ranking - { - for( int i=0; im_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores.resize(1); + iRetVal = sscanf( value, "%d::%[^:]::%f::%d", - &pNotes->m_MemCardScores[MEMORY_CARD_MACHINE].iNumTimesPlayed, + &pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].iNumTimesPlayed, szGradeLetters, - &pNotes->m_MemCardScores[MEMORY_CARD_MACHINE].fScore, + &pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].fScore, &iMaxCombo ); if( iRetVal != 4 ) continue; - pNotes->m_MemCardScores[MEMORY_CARD_MACHINE].grade = StringToGrade( szGradeLetters ); + pNotes->m_MemCardDatas[MEMORY_CARD_MACHINE].vHighScores[0].grade = StringToGrade( szGradeLetters ); } } } @@ -568,66 +543,79 @@ void SongManager::ReadSM300NoteScores() void SongManager::SaveCategoryRankingsToFile( CString fn ) { // category ranking - LOG->Trace("Writing category ranking"); + LOG->Trace("SongManager::SaveCategoryRankingsToFile"); FILE* fp = fopen( fn, "w" ); if( fp ) { fprintf(fp,"%d\n",CATEGORY_RANKING_VERSION); for( int i=0; iTrace("Writing course ranking"); + LOG->Trace("SongManager::SaveCourseMemCardDataToFile"); + + FILE* fp = fopen( fn, "w" ); + + if( fp ) { - FILE* fp = fopen( fn, "w" ); - - if( fp ) + fprintf(fp,"%d\n",COURSE_MEM_CARD_DATA_VERSION); + for( unsigned i=0; im_bIsAutogen ) + fprintf(fp, "%s\n", pCourse->m_sName.c_str()); + else + fprintf(fp, "%s\n", pCourse->m_sPath.c_str()); + + for( int j=0; jm_bIsAutogen ) - fprintf(fp, "%s\n", pCourse->m_sName.c_str()); - else - fprintf(fp, "%s\n", pCourse->m_sPath.c_str()); - - for( int i=0; im_RankingScores[i][j].iScore, - pCourse->m_RankingScores[i][j].fSurviveTime, - pCourse->m_RankingScores[i][j].sName.c_str()); - } + fprintf(fp, "%d\n", pCourse->m_MemCardDatas[j][c].iNumTimesPlayed); + pCourse->m_MemCardDatas[j][c].vHighScores.resize(NUM_RANKING_LINES); + for( int k=0; km_MemCardDatas[j][c].vHighScores[k].iScore, + pCourse->m_MemCardDatas[j][c].vHighScores[k].fSurviveTime, + pCourse->m_MemCardDatas[j][c].vHighScores[k].sName.c_str()); + } } - - fclose(fp); } - } + fclose(fp); + } } -void SongManager::SaveNoteScoresToFile( CString fn, int c ) +void SongManager::SaveStepsMemCardDataToFile( CString fn, int c ) { // notes scores - LOG->Trace("Writing note scores to %s", fn.c_str()); + LOG->Trace("SongManager::SaveStepsMemCardDataToFile %s", fn.c_str()); { FILE* fp = fopen( fn, "w" ); if( fp ) { - fprintf(fp,"%d\n",NOTES_SCORES_VERSION); + fprintf(fp,"%d\n",STEPS_MEM_CARD_DATA_VERSION); for( unsigned s=0; s vNotes = pSong->m_apNotes; -/* This prevents the play count from being saved for songs that havn't - * been passed. Though, it seems we only increment this when it's - * passed, anyway ... - for( int n=(int)vNotes.size()-1; n>=0; n-- ) - { - if( vNotes[n]->m_MemCardScores[c].grade <= GRADE_E ) - vNotes.erase( vNotes.begin()+n ); - } -*/ if( vNotes.size() == 0 ) continue; // skip @@ -661,10 +640,17 @@ void SongManager::SaveNoteScoresToFile( CString fn, int c ) pNotes->GetDifficulty(), pNotes->GetDescription().c_str() ); - fprintf(fp, "%d %d %f\n", - pNotes->m_MemCardScores[c].iNumTimesPlayed, - pNotes->m_MemCardScores[c].grade, - pNotes->m_MemCardScores[c].fScore); + + fprintf(fp, "%d\n", pNotes->m_MemCardDatas[c].iNumTimesPlayed ); + + pNotes->m_MemCardDatas[c].vHighScores.resize(NUM_RANKING_LINES); + for( int j=0; jm_MemCardDatas[c].vHighScores[j].grade, + pNotes->m_MemCardDatas[c].vHighScores[j].fScore, + pNotes->m_MemCardDatas[c].vHighScores[j].sName.c_str()); + } } } @@ -673,38 +659,6 @@ void SongManager::SaveNoteScoresToFile( CString fn, int c ) } } -void SongManager::SaveCourseScoresToFile( CString fn, int c ) -{ - // course scores - LOG->Trace("Writing course scores to %s", fn.c_str()); - { - FILE* fp = fopen( fn, "w" ); - if( fp ) - { - fprintf(fp,"%d\n",COURSE_SCORES_VERSION); - - for( unsigned i=0; im_bIsAutogen ) - fprintf(fp, "%s\n", pCourse->m_sName.c_str()); - else - fprintf(fp, "%s\n", pCourse->m_sPath.c_str()); - - for( int nt=0; ntm_MemCardScores[c][nt].iNumTimesPlayed, - pCourse->m_MemCardScores[c][nt].iScore, - pCourse->m_MemCardScores[c][nt].fSurviveTime); - } - - fclose(fp); - } - } -} - CString SongManager::GetGroupBannerPath( CString sGroupName ) { @@ -1183,68 +1137,6 @@ Course* SongManager::GetCourseFromName( CString sName ) } -struct CategoryScoreToInsert -{ - PlayerNumber pn; - RankingCategory cat; - int iScore; - - static int CompareDescending( const CategoryScoreToInsert &hs1, const CategoryScoreToInsert &hs2 ) - { - return hs1.iScore > hs2.iScore; - } - static void SortDescending( vector& vHSout ) - { - sort( vHSout.begin(), vHSout.end(), CompareDescending ); - } -}; - -// set iNewRecordIndex = -1 if not a new record -void SongManager::AddScores( StepsType nt, bool bPlayerEnabled[NUM_PLAYERS], - RankingCategory hsc[NUM_PLAYERS], - int iScore[NUM_PLAYERS], - int iNewRecordIndexOut[NUM_PLAYERS] ) -{ - vector vHS; - for( int p=0; p machineScores[i].iScore ) - { - // We found the insert point. Shift down. - for( int j=NUM_RANKING_LINES-1; j>i; j-- ) - machineScores[j] = machineScores[j-1]; - // insert - machineScores[i].iScore = newHS.iScore; - machineScores[i].sName = DEFAULT_RANKING_NAME; - iNewRecordIndexOut[newHS.pn] = i; - break; - } - } - } -} - /* * GetSongDir() contains a path to the song, possibly a full path, eg: * Songs\Group\SongName or diff --git a/stepmania/src/SongManager.h b/stepmania/src/SongManager.h index bfb479e4bc..8fc78ef768 100644 --- a/stepmania/src/SongManager.h +++ b/stepmania/src/SongManager.h @@ -89,26 +89,60 @@ public: void InitMachineScoresFromDisk(); void SaveMachineScoresToDisk(); - struct MachineScore + struct CategoryData { - int iScore; - CString sName; - } m_MachineScores[NUM_STEPS_TYPES][NUM_RANKING_CATEGORIES][NUM_RANKING_LINES]; - void AddScores( StepsType nt, bool bPlayerEnabled[NUM_PLAYERS], RankingCategory hsc[NUM_PLAYERS], int iScore[NUM_PLAYERS], int iNewRecordIndexOut[NUM_PLAYERS] ); // set iNewRecordIndex = -1 if not a new record + struct HighScore + { + int iScore; + CString sName; + + HighScore() + { + iScore = 0; + } + + bool operator>( const HighScore& other ) + { + return iScore > other.iScore; + } + }; + vector vHighScores; + + void AddHighScore( HighScore hs, int &iIndexOut ) + { + for( int i=0; i vHighScores[i] ) + { + vHighScores.insert( vHighScores.begin()+i, hs ); + iIndexOut = i; + break; + } + } + if( vHighScores.size() > NUM_RANKING_LINES ) + vHighScores.erase( vHighScores.begin()+NUM_RANKING_LINES, vHighScores.end() ); + } + + } m_CategoryDatas[NUM_STEPS_TYPES][NUM_RANKING_CATEGORIES]; + + void AddHighScore( StepsType nt, RankingCategory rc, PlayerNumber pn, CategoryData::HighScore hs, int &iMachineIndexOut ) + { + hs.sName = RANKING_TO_FILL_IN_MARKER[pn]; + m_CategoryDatas[nt][rc].AddHighScore( hs, iMachineIndexOut ); + } + void UpdateBest(); void UpdateRankingCourses(); void ReadSM300NoteScores(); - void ReadNoteScoresFromFile( CString fn, int c ); - void ReadCourseScoresFromFile( CString fn, int c ); + void ReadStepsMemCardDataFromFile( CString fn, int c ); + void ReadCourseMemCardDataFromFile( CString fn, int c ); void ReadCategoryRankingsFromFile( CString fn ); - void ReadCourseRankingsFromFile( CString fn ); - void SaveNoteScoresToFile( CString fn, int c ); - void SaveCourseScoresToFile( CString fn, int c ); + void SaveStepsMemCardDataToFile( CString fn, int c ); + void SaveCourseMemCardDataToFile( CString fn, int c ); void SaveCategoryRankingsToFile( CString fn ); - void SaveCourseRankingsToFile( CString fn ); protected: void LoadStepManiaSongDir( CString sDir, LoadingWindow *ld ); diff --git a/stepmania/src/StageStats.cpp b/stepmania/src/StageStats.cpp index 967a1ff452..cd95db0aca 100644 --- a/stepmania/src/StageStats.cpp +++ b/stepmania/src/StageStats.cpp @@ -34,6 +34,7 @@ void StageStats::AddStats( const StageStats& other ) for( int p=0; p this->fScore ) - return true; - if( vsScore < this->fScore ) - return false; - return vsGrade > this->grade; -} - -void Steps::AddScore( PlayerNumber pn, Grade grade, float fScore, bool& bNewRecordOut ) -{ - bNewRecordOut = false; - - m_MemCardScores[MEMORY_CARD_MACHINE].iNumTimesPlayed++; - m_MemCardScores[pn].iNumTimesPlayed++; - - if( m_MemCardScores[pn].HigherScore(fScore, grade) && fScore > 0) - { - m_MemCardScores[pn].fScore = fScore; - m_MemCardScores[pn].grade = grade; - bNewRecordOut = true; - } - - if( m_MemCardScores[MEMORY_CARD_MACHINE].HigherScore(fScore, grade) ) - { - m_MemCardScores[MEMORY_CARD_MACHINE].fScore = fScore; - m_MemCardScores[MEMORY_CARD_MACHINE].grade = grade; - } -} - - // // Sorting stuff // diff --git a/stepmania/src/Steps.h b/stepmania/src/Steps.h index bcb322a3e8..a3e9fe5c7f 100644 --- a/stepmania/src/Steps.h +++ b/stepmania/src/Steps.h @@ -53,17 +53,87 @@ public: CString GetSMNoteData() const; - // High scores - struct MemCardScore + struct MemCardData { + MemCardData() + { + iNumTimesPlayed = 0; + } + int iNumTimesPlayed; - Grade grade; - float fScore; - bool HigherScore( float fScore, Grade grade ) const; - } m_MemCardScores[NUM_MEMORY_CARDS]; - void AddScore( PlayerNumber pn, Grade grade, float fScore, bool& bNewRecordOut ); + struct HighScore + { + CString sName; + Grade grade; + float fScore; + HighScore() + { + grade = GRADE_NO_DATA; + fScore = 0; + } + + bool operator>( const HighScore& other ) + { + return fScore > other.fScore; + /* Make sure we treat AAAA as higher than AAA, even though the score + * is the same. + * + * XXX: Isn't it possible to beat the grade but not beat the score, since + * grading and scores are on completely different systems? Should we be + * checking for these completely separately? */ + // if( vsScore > this->fScore ) + // return true; + // if( vsScore < this->fScore ) + // return false; + // return vsGrade > this->grade; + } + + }; + vector vHighScores; + + void AddHighScore( MemCardData::HighScore hs, int &iIndexOut ) + { + for( int i=0; i vHighScores[i] ) + { + vHighScores.insert( vHighScores.begin()+i, hs ); + iIndexOut = i; + break; + } + } + if( vHighScores.size() > NUM_RANKING_LINES ) + vHighScores.erase( vHighScores.begin()+NUM_RANKING_LINES, vHighScores.end() ); + } + + HighScore GetTopScore() + { + if( vHighScores.empty() ) + return HighScore(); + else + return vHighScores[0]; + } + + } m_MemCardDatas[NUM_MEMORY_CARDS]; + + void AddHighScore( PlayerNumber pn, MemCardData::HighScore hs, int &iPersonalIndexOut, int &iMachineIndexOut ) + { + hs.sName = RANKING_TO_FILL_IN_MARKER[pn]; + m_MemCardDatas[pn].AddHighScore( hs, iPersonalIndexOut ); + m_MemCardDatas[MEMORY_CARD_MACHINE].AddHighScore( hs, iMachineIndexOut ); + } + + MemCardData::HighScore GetTopScore( MemoryCard card ) + { + return m_MemCardDatas[card].GetTopScore(); + } + + int GetNumTimesPlayed( MemoryCard card ) + { + return m_MemCardDatas[card].iNumTimesPlayed; + } void TidyUpData(); diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 5289c6fa88..b8aaf655fd 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -14,7 +14,7 @@ #include "PlayerNumber.h" #include "GameConstantsAndTypes.h" #include "Grade.h" -class Steps; +#include "Steps.h" // TODO: remove this dependency! class StyleDef; class NotesLoader; class LyricsLoader; @@ -254,7 +254,7 @@ public: bool IsNew() const; bool IsEasy( StepsType nt ) const; bool HasEdits( StepsType nt ) const; - Grade GetGradeForDifficulty( const StyleDef *s, MemoryCard card, Difficulty dc ) const; + Steps::MemCardData::HighScore GetHighScoreForDifficulty( const StyleDef *st, MemoryCard card, Difficulty dc ) const; bool NormallyDisplayed() const; bool RouletteDisplayed() const; int GetNumNotesWithGrade( Grade g ) const;