From cf8c4f884fba74b4b532e95f9d4c48813d874af8 Mon Sep 17 00:00:00 2001 From: Chris Danford Date: Fri, 24 Jan 2003 02:43:07 +0000 Subject: [PATCH] cleanup of statistics, saving of high scores --- stepmania/TODO.chris | 2 + stepmania/src/Course.cpp | 84 ++++++- stepmania/src/Course.h | 18 +- stepmania/src/GameConstantsAndTypes.cpp | 12 + stepmania/src/GameConstantsAndTypes.h | 13 +- stepmania/src/GameState.cpp | 182 +++------------- stepmania/src/GameState.h | 74 ++----- stepmania/src/LifeMeter.h | 2 +- stepmania/src/LifeMeterBattery.cpp | 6 +- stepmania/src/LifeMeterBattery.h | 2 +- stepmania/src/Notes.cpp | 8 +- stepmania/src/Notes.h | 9 +- stepmania/src/Player.cpp | 10 +- stepmania/src/PrefsManager.cpp | 14 +- stepmania/src/ScoreDisplayOni.cpp | 2 +- stepmania/src/ScoreKeeperMAX2.cpp | 10 +- stepmania/src/ScreenEvaluation.cpp | 279 +++++++++++------------- stepmania/src/ScreenEvaluation.h | 8 +- stepmania/src/ScreenGameplay.cpp | 94 ++++---- stepmania/src/ScreenSelectMusic.cpp | 2 +- stepmania/src/SongManager.cpp | 169 ++++++++++---- stepmania/src/SongManager.h | 20 +- stepmania/src/StageStats.cpp | 48 ++++ stepmania/src/StageStats.h | 40 ++++ stepmania/src/StepMania.vcproj | 6 + 25 files changed, 611 insertions(+), 503 deletions(-) create mode 100644 stepmania/src/StageStats.cpp create mode 100644 stepmania/src/StageStats.h diff --git a/stepmania/TODO.chris b/stepmania/TODO.chris index 225725ad9d..82d79faea0 100644 --- a/stepmania/TODO.chris +++ b/stepmania/TODO.chris @@ -2,6 +2,8 @@ Fix ///////////////////////// +change space so gray arrows aren't so small + groove radar goes wild when random selected take out "it's a new record" diff --git a/stepmania/src/Course.cpp b/stepmania/src/Course.cpp index 622a4ebb2d..b9553abba3 100644 --- a/stepmania/src/Course.cpp +++ b/stepmania/src/Course.cpp @@ -50,7 +50,6 @@ Course::Course() { m_MemCardScores[i][j][k].iDancePoints = 0; m_MemCardScores[i][j][k].fSurviveTime = 0; - m_MemCardScores[i][j][k].sName = "STEP"; } } @@ -302,10 +301,91 @@ int Course::GetNumStages() const return entries.size(); } + +bool Course::IsNewMachineRecord( PlayerNumber pn, int iDancePoints, float fSurviveTime ) const // return true if this would be a new machine record +{ + for( int i=0; im_CurStyle][GAMESTATE->m_PreferredDifficulty[pn]][i]; + if( iDancePoints > hs.iDancePoints ) + return true; + } + return false; +} + +struct MachineScoreAndPlayerNumber : public Course::MachineScore +{ + PlayerNumber pn; + + static int CompareDescending( const MachineScoreAndPlayerNumber &hs1, const MachineScoreAndPlayerNumber &hs2 ) + { + if( hs1.iDancePoints > hs2.iDancePoints ) return -1; + else if( hs1.iDancePoints == hs2.iDancePoints ) return 0; + else return +1; + } + static void SortDescending( vector& vHSout ) + { + sort( vHSout.begin(), vHSout.end(), CompareDescending ); + } +}; + +void Course::AddMachineRecord( int iDancePoints[NUM_PLAYERS], float fSurviveTime[NUM_PLAYERS], int iNewRecordIndexOut[NUM_PLAYERS] ) // set iNewRecordIndex = -1 if not a new record +{ + vector vHS; + for( int p=0; pIsPlayerEnabled(p) ) + continue; // skip + + MachineScoreAndPlayerNumber hs; + hs.iDancePoints = iDancePoints[p]; + hs.fSurviveTime = fSurviveTime[p]; + hs.sName = ""; // this must be filled in later! + 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 + MachineScoreAndPlayerNumber::SortDescending( vHS ); + + for( unsigned i=0; im_CurStyle][GAMESTATE->m_PreferredDifficulty[newHS.pn]]; + for( int i=0; i machineScores[i].iDancePoints ) + { + // We found the insert point. Shift down. + for( int j=i+1; jm_CurStyle][GAMESTATE->m_PreferredDifficulty[pn]][pn]; + if( iDancePoints > hs.iDancePoints ) + { + hs.iDancePoints = iDancePoints; + hs.fSurviveTime = fSurviveTime; + return true; + } + return false; +} + + // // Sorting stuff // - static int CompareCoursePointersByDifficulty(const Course* pCourse1, const Course* pCourse2) { return pCourse1->GetNumStages() < pCourse2->GetNumStages(); diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index e5aa4a05f4..c5108f942f 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -60,14 +60,24 @@ public: // Statistics int m_iNumTimesPlayed; - struct HighScore + struct MachineScore { int iDancePoints; float fSurviveTime; CString sName; - }; - HighScore m_MachineScores[NUM_STYLES][NUM_DIFFICULTIES][NUM_HIGH_SCORE_LINES]; // sorted highest to lowest by iDancePoints - HighScore m_MemCardScores[NUM_STYLES][NUM_DIFFICULTIES][NUM_PLAYERS]; + } m_MachineScores[NUM_STYLES][NUM_DIFFICULTIES][NUM_HIGH_SCORE_LINES]; // sorted highest to lowest by iDancePoints + + bool IsNewMachineRecord( PlayerNumber pn, int iDancePoints, float fSurviveTime ) const; // return true if this is would be a new machine record + void AddMachineRecord( int iDancePoints[NUM_PLAYERS], float fSurviveTime[NUM_PLAYERS], int iNewRecordIndexOut[NUM_PLAYERS] ); // set iNewRecordIndex = -1 if not a new record + + struct MemCardScore + { + int iDancePoints; + float fSurviveTime; + } m_MemCardScores[NUM_STYLES][NUM_DIFFICULTIES][NUM_PLAYERS]; + + bool AddMemCardRecord( PlayerNumber pn, int iDancePoints, float fSurviveTime ); // return true if this is a new record + private: void Shuffle(); diff --git a/stepmania/src/GameConstantsAndTypes.cpp b/stepmania/src/GameConstantsAndTypes.cpp index efa9c832f4..ffd4de4168 100644 --- a/stepmania/src/GameConstantsAndTypes.cpp +++ b/stepmania/src/GameConstantsAndTypes.cpp @@ -55,3 +55,15 @@ RageColor PlayerToColor( int p ) { return PlayerToColor( (PlayerNumber)p ); } + + +HighScoreCategory AverageMeterToHighScoreCategory( float fAverageMeter ) +{ + if( fAverageMeter <= 3 ) return CATEGORY_A; + else if( fAverageMeter <= 6 ) return CATEGORY_B; + else if( fAverageMeter <= 9 ) return CATEGORY_C; + else return CATEGORY_D; + +} + + diff --git a/stepmania/src/GameConstantsAndTypes.h b/stepmania/src/GameConstantsAndTypes.h index 7b19bb74b6..e038373e26 100644 --- a/stepmania/src/GameConstantsAndTypes.h +++ b/stepmania/src/GameConstantsAndTypes.h @@ -116,9 +116,9 @@ enum SongSortOrder { }; -/////////////////////////// +// // Scoring stuff -/////////////////////////// +// enum TapNoteScore { TNS_NONE, @@ -174,16 +174,19 @@ inline int HoldNoteScoreToDancePoints( HoldNoteScore hns ) // -// High Score types +// High Score stuff // -enum SongHighScoreCategory +enum HighScoreCategory { CATEGORY_A, // 1-3 meter per song avg. CATEGORY_B, // 4-6 meter per song avg. CATEGORY_C, // 7-9 meter per song avg. - CATEGORY_D, // 10+ meter per song avg. + CATEGORY_D, // 10+ meter per song avg. // doesn't count extra stage! NUM_HIGH_SCORE_CATEGORIES }; + +HighScoreCategory AverageMeterToHighScoreCategory( float fAverageMeter ); + const int NUM_HIGH_SCORE_LINES = 5; #endif diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index 48165ff538..8482d369b6 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -67,68 +67,18 @@ void GameState::Reset() m_bDemonstration = false; m_iCurrentStageIndex = 0; - m_pCurSong = NULL; for( p=0; pm_fMusicLengthSeconds; - fSecondsTotal += max( 0, m_fMusicSeconds ); - return fSecondsTotal; - } - default: - ASSERT(0); - return 0; - } -} - -float GameState::GetPlayerSurviveTime( PlayerNumber pn ) -{ - if( m_fSecondsBeforeFail[pn] == -1 ) // haven't failed yet - return GetElapsedSeconds(); - else - return m_fSecondsBeforeFail[pn]; -} - Grade GameState::GetCurrentGrade( PlayerNumber pn ) { - if( !GAMESTATE->IsPlayerEnabled(pn) || GAMESTATE->m_fSecondsBeforeFail[pn] != -1 ) + ASSERT( GAMESTATE->IsPlayerEnabled(pn) ); // should be calling this is player isn't joined! + + if( m_CurStageStats.bFailed[pn] ) return GRADE_E; /* Based on the percentage of your total "Dance Points" to the maximum @@ -344,19 +208,19 @@ Grade GameState::GetCurrentGrade( PlayerNumber pn ) * Less - D * Fail - E */ - float fPercentDancePoints = m_iActualDancePoints[pn] / (float)m_iPossibleDancePoints[pn]; - fPercentDancePoints = max( fPercentDancePoints, 0 ); - LOG->Trace( "iActualDancePoints: %i", m_iActualDancePoints[pn] ); - LOG->Trace( "iPossibleDancePoints: %i", m_iPossibleDancePoints[pn] ); + float fPercentDancePoints = m_CurStageStats.iActualDancePoints[pn] / (float)m_CurStageStats.iPossibleDancePoints[pn]; + fPercentDancePoints = max( 0, fPercentDancePoints ); + LOG->Trace( "iActualDancePoints: %i", m_CurStageStats.iActualDancePoints[pn] ); + LOG->Trace( "iPossibleDancePoints: %i", m_CurStageStats.iPossibleDancePoints[pn] ); LOG->Trace( "fPercentDancePoints: %f", fPercentDancePoints ); // check for "AAAA" - if( m_TapNoteScores[pn][TNS_MARVELOUS] > 0 && - m_TapNoteScores[pn][TNS_PERFECT] == 0 && - m_TapNoteScores[pn][TNS_GREAT] == 0 && - m_TapNoteScores[pn][TNS_GOOD] == 0 && - m_TapNoteScores[pn][TNS_BOO] == 0 && - m_TapNoteScores[pn][TNS_MISS] == 0 ) + if( m_CurStageStats.iTapNoteScores[pn][TNS_MARVELOUS] > 0 && + m_CurStageStats.iTapNoteScores[pn][TNS_PERFECT] == 0 && + m_CurStageStats.iTapNoteScores[pn][TNS_GREAT] == 0 && + m_CurStageStats.iTapNoteScores[pn][TNS_GOOD] == 0 && + m_CurStageStats.iTapNoteScores[pn][TNS_BOO] == 0 && + m_CurStageStats.iTapNoteScores[pn][TNS_MISS] == 0 ) return GRADE_AAAA; if ( fPercentDancePoints == 1.00 ) return GRADE_AAA; @@ -366,3 +230,19 @@ Grade GameState::GetCurrentGrade( PlayerNumber pn ) else if( fPercentDancePoints >= 0.45 ) return GRADE_C; else return GRADE_D; } + +bool GameState::HasEarnedExtraStage() +{ + if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) ) + { + for( int p=0; pIsPlayerEnabled(p) ) + continue; // skip + + if( GAMESTATE->m_pCurNotes[p]->GetDifficulty()==DIFFICULTY_HARD && GetCurrentGrade((PlayerNumber)p)==GRADE_AA ) + return true; + } + } + return false; +} \ No newline at end of file diff --git a/stepmania/src/GameState.h b/stepmania/src/GameState.h index 28d3bcc2d9..cc32583609 100644 --- a/stepmania/src/GameState.h +++ b/stepmania/src/GameState.h @@ -17,6 +17,7 @@ #include "Game.h" #include "Style.h" #include "Grade.h" +#include "StageStats.h" class Song; @@ -39,13 +40,13 @@ public: Game m_CurGame; Style m_CurStyle; bool m_bPlayersCanJoin; // true if it's not too late for a player to join - this only has an effect on the credits message - bool m_bSideIsJoined[2]; // left side, right side - int m_iCoins; - PlayerNumber m_MasterPlayerNumber; + bool m_bSideIsJoined[NUM_PLAYERS]; // left side, right side + int m_iCoins; // not "credits" + PlayerNumber m_MasterPlayerNumber; // used in Styles where one player controls both sides int GetNumSidesJoined() { int iNumSidesJoined = 0; - for( int c=0; c<2; c++ ) + for( int c=0; c m_vPassedStageStats; // Only useful in Arcade for final evaluation + // A song is only inserted here if at least one player passed. + // StageStats are added by the Evaluation screen + Grade GetCurrentGrade( PlayerNumber pn ); // grade so far - Grade GetCurrentGrade( PlayerNumber pn ); - - int m_iSongsIntoCourse; // In Arcade, this value is meaningless. - // In Oni and Endless, this is the number of songs played in the current course. - int m_iSongsBeforeFail[NUM_PLAYERS]; // In Arcade, this value is meaningless. - // In Oni and Endless, this is the number of songs played before failing. - float m_fSecondsBeforeFail[NUM_PLAYERS];// -1 means not yet failed - // In Arcade, is the time into the current stage before failing. - // In Oni and Endless this is the time into the current course before failing - - float GetPlayerSurviveTime( PlayerNumber pn ); // Returns time player has survived - - void AccumulateStageStatistics(); // Call this before clearing values. Accumulate values above into the Session values below. - void ResetStageStatistics(); // Clears the values above - - - // - // Session Statistics: Arcade: 3 songs. Oni/Endless: one course. - // - vector m_apSongsPlayed; // an array of completed songs. - // This is useful for the final evaluation screen, - // and used to calculate the time into a course - - // Only used in final evaluation screen in play mode Arcade. - // Before being displayed, these values should be normalized by dividing by number of stages - int m_iAccumPossibleDancePoints[NUM_PLAYERS]; - int m_iAccumActualDancePoints[NUM_PLAYERS]; - int m_AccumTapNoteScores[NUM_PLAYERS][NUM_TAP_NOTE_SCORES]; - int m_AccumHoldNoteScores[NUM_PLAYERS][NUM_HOLD_NOTE_SCORES]; - int m_iAccumMaxCombo[NUM_PLAYERS]; - float m_fAccumScore[NUM_PLAYERS]; - float m_fAccumRadarPossible[NUM_PLAYERS][NUM_RADAR_VALUES]; - float m_fAccumRadarActual[NUM_PLAYERS][NUM_RADAR_VALUES]; - - - // Session statistics are cleared by calling Reset() PlayerOptions m_PlayerOptions[NUM_PLAYERS]; // The currently active options PlayerOptions m_SelectedOptions[NUM_PLAYERS]; // Keep track of player-selected options for @@ -151,7 +113,7 @@ public: SongOptions m_SongOptions; - vector m_asNetworkNames; + bool HasEarnedExtraStage(); }; diff --git a/stepmania/src/LifeMeter.h b/stepmania/src/LifeMeter.h index 82a1d33cf5..664982dd7b 100644 --- a/stepmania/src/LifeMeter.h +++ b/stepmania/src/LifeMeter.h @@ -27,7 +27,7 @@ public: virtual void Load( PlayerNumber pn ) { m_PlayerNumber = pn; } virtual void Update( float fDeltaTime ) { ActorFrame::Update(fDeltaTime); }; - virtual void SongEnded() {}; + virtual void OnSongEnded() {}; /* Change life after receiving a tap note grade. This *is* called for * the head of hold notes. */ virtual void ChangeLife( TapNoteScore score ) = 0; diff --git a/stepmania/src/LifeMeterBattery.cpp b/stepmania/src/LifeMeterBattery.cpp index 0103d20e1e..e8e08f38c1 100644 --- a/stepmania/src/LifeMeterBattery.cpp +++ b/stepmania/src/LifeMeterBattery.cpp @@ -83,7 +83,7 @@ void LifeMeterBattery::Load( PlayerNumber pn ) Refresh(); } -void LifeMeterBattery::SongEnded() +void LifeMeterBattery::OnSongEnded() { if( m_bFailedEarlier ) return; @@ -145,8 +145,8 @@ void LifeMeterBattery::ChangeLife( HoldNoteScore score, TapNoteScore tscore ) void LifeMeterBattery::OnDancePointsChange() { - int iActualDancePoints = GAMESTATE->m_iActualDancePoints[m_PlayerNumber]; - int iPossibleDancePoints = GAMESTATE->m_iPossibleDancePoints[m_PlayerNumber]; + int iActualDancePoints = GAMESTATE->m_CurStageStats.iActualDancePoints[m_PlayerNumber]; + int iPossibleDancePoints = GAMESTATE->m_CurStageStats.iPossibleDancePoints[m_PlayerNumber]; iPossibleDancePoints = max( 1, iPossibleDancePoints ); float fPercentDancePoints = iActualDancePoints / (float)iPossibleDancePoints + 0.00001f; // correct for rounding errors diff --git a/stepmania/src/LifeMeterBattery.h b/stepmania/src/LifeMeterBattery.h index 4385f6741c..a11f102ac7 100644 --- a/stepmania/src/LifeMeterBattery.h +++ b/stepmania/src/LifeMeterBattery.h @@ -27,7 +27,7 @@ public: virtual void Update( float fDeltaTime ); - virtual void SongEnded(); + virtual void OnSongEnded(); virtual void ChangeLife( TapNoteScore score ); virtual void ChangeLife( HoldNoteScore score, TapNoteScore tscore ); virtual void OnDancePointsChange(); // look in GAMESTATE and update the display diff --git a/stepmania/src/Notes.cpp b/stepmania/src/Notes.cpp index f8fbfd1dd7..9f1518ec3d 100644 --- a/stepmania/src/Notes.cpp +++ b/stepmania/src/Notes.cpp @@ -52,7 +52,7 @@ Notes::Notes() for( int p=0; p m_MemCardScores[pn].iScore ) + if( fScore > m_MemCardScores[pn].fScore ) { - m_MemCardScores[pn].iScore = iScore; + m_MemCardScores[pn].fScore = fScore; m_MemCardScores[pn].grade = grade; return true; } diff --git a/stepmania/src/Notes.h b/stepmania/src/Notes.h index f9fecba0ca..2bcefb949a 100644 --- a/stepmania/src/Notes.h +++ b/stepmania/src/Notes.h @@ -52,14 +52,13 @@ public: // High scores; int m_iNumTimesPlayed; - struct HighScore + struct MemCardScore { Grade grade; - int iScore; - }; - HighScore m_MemCardScores[NUM_PLAYERS]; + float fScore; + } m_MemCardScores[NUM_PLAYERS]; - bool AddMemCardScore( PlayerNumber pn, Grade grade, int iScore ); // return true if new high score + bool AddMemCardRecord( PlayerNumber pn, Grade grade, float fScore ); // return true if new high score void TidyUpData(); diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index 66e442619f..05f482127a 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -136,7 +136,7 @@ void Player::Load( PlayerNumber pn, NoteData* pNoteData, LifeMeter* pLM, ScoreDi // copy note data this->CopyAll( pNoteData ); - if( GAMESTATE->m_SongOptions.m_LifeType == SongOptions::LIFE_BATTERY && GAMESTATE->m_fSecondsBeforeFail[m_PlayerNumber] != -1 ) // Oni dead + if( GAMESTATE->m_SongOptions.m_LifeType == SongOptions::LIFE_BATTERY && GAMESTATE->m_CurStageStats.bFailed ) // Oni dead this->ClearAll(); /* The editor reuses Players ... so we really need to make sure everything @@ -341,7 +341,7 @@ void Player::DrawPrimitives() void Player::Step( int col ) { - if( GAMESTATE->m_SongOptions.m_LifeType == SongOptions::LIFE_BATTERY && GAMESTATE->m_fSecondsBeforeFail[m_PlayerNumber] != -1 ) // Oni dead + if( GAMESTATE->m_SongOptions.m_LifeType == SongOptions::LIFE_BATTERY && GAMESTATE->m_CurStageStats.bFailed[m_PlayerNumber] ) // Oni dead return; // do nothing //LOG->Trace( "Player::HandlePlayerStep()" ); @@ -518,7 +518,7 @@ void Player::OnRowDestroyed( int iIndexThatWasSteppedOn ) { HandleNoteScore( score, iNumNotesInThisRow ); // update score m_Combo.UpdateScore( score, iNumNotesInThisRow ); - GAMESTATE->m_iMaxCombo[m_PlayerNumber] = max( GAMESTATE->m_iMaxCombo[m_PlayerNumber], m_Combo.GetCurrentCombo() ); + GAMESTATE->m_CurStageStats.iMaxCombo[m_PlayerNumber] = max( GAMESTATE->m_CurStageStats.iMaxCombo[m_PlayerNumber], m_Combo.GetCurrentCombo() ); } // update the judgement, score, and life @@ -616,7 +616,7 @@ void Player::HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) m_ScoreKeeper->HandleNoteScore(score, iNumTapsInRow); if (m_pScore) - m_pScore->SetScore(GAMESTATE->m_fScore[m_PlayerNumber]); + m_pScore->SetScore(GAMESTATE->m_CurStageStats.fScore[m_PlayerNumber]); if( m_pLifeMeter ) { m_pLifeMeter->ChangeLife( score ); @@ -636,7 +636,7 @@ void Player::HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore } if (m_pScore) - m_pScore->SetScore(GAMESTATE->m_fScore[m_PlayerNumber]); + m_pScore->SetScore(GAMESTATE->m_CurStageStats.fScore[m_PlayerNumber]); if( m_pLifeMeter ) { if( score == HNS_NG ) { diff --git a/stepmania/src/PrefsManager.cpp b/stepmania/src/PrefsManager.cpp index 3e166c9620..5b201dff9d 100644 --- a/stepmania/src/PrefsManager.cpp +++ b/stepmania/src/PrefsManager.cpp @@ -54,11 +54,11 @@ PrefsManager::PrefsManager() m_iNumArcadeStages = 3; m_bAutoPlay = false; m_fJudgeWindowScale = 1.0f; - m_fJudgeWindowMarvelousSeconds = 0.023f; - m_fJudgeWindowPerfectSeconds = 0.043f; - m_fJudgeWindowGreatSeconds = 0.086f; - m_fJudgeWindowGoodSeconds = 0.129f; - m_fJudgeWindowBooSeconds = 0.172f; + m_fJudgeWindowMarvelousSeconds = 0.025f; + m_fJudgeWindowPerfectSeconds = 0.05f; + m_fJudgeWindowGreatSeconds = 0.10f; + m_fJudgeWindowGoodSeconds = 0.15f; + m_fJudgeWindowBooSeconds = 0.2f; m_fLifeDifficultyScale = 1.0f; m_iMovieDecodeMS = 2; m_bUseBGIfNoBanner = false; @@ -119,9 +119,11 @@ void PrefsManager::ReadGlobalPrefsFromDisk( bool bSwitchToLastPlayedGame ) ini.GetValueI( "Options", "NumArcadeStages", m_iNumArcadeStages ); ini.GetValueB( "Options", "AutoPlay", m_bAutoPlay ); ini.GetValueF( "Options", "JudgeWindowScale", m_fJudgeWindowScale ); + ini.GetValueF( "Options", "JudgeWindowMarvelousSeconds",m_fJudgeWindowMarvelousSeconds ); ini.GetValueF( "Options", "JudgeWindowPerfectSeconds", m_fJudgeWindowPerfectSeconds ); ini.GetValueF( "Options", "JudgeWindowGreatSeconds", m_fJudgeWindowGreatSeconds ); ini.GetValueF( "Options", "JudgeWindowGoodSeconds", m_fJudgeWindowGoodSeconds ); + ini.GetValueF( "Options", "JudgeWindowBooSeconds", m_fJudgeWindowBooSeconds ); ini.GetValueF( "Options", "LifeDifficultyScale", m_fLifeDifficultyScale ); ini.GetValueI( "Options", "MovieDecodeMS", m_iMovieDecodeMS ); ini.GetValueB( "Options", "UseBGIfNoBanner", m_bUseBGIfNoBanner ); @@ -184,9 +186,11 @@ void PrefsManager::SaveGlobalPrefsToDisk() ini.SetValueI( "Options", "NumArcadeStages", m_iNumArcadeStages ); ini.SetValueB( "Options", "AutoPlay", m_bAutoPlay ); ini.SetValueF( "Options", "JudgeWindowScale", m_fJudgeWindowScale ); + ini.SetValueF( "Options", "JudgeWindowMarvelousSeconds",m_fJudgeWindowMarvelousSeconds ); ini.SetValueF( "Options", "JudgeWindowPerfectSeconds", m_fJudgeWindowPerfectSeconds ); ini.SetValueF( "Options", "JudgeWindowGreatSeconds", m_fJudgeWindowGreatSeconds ); ini.SetValueF( "Options", "JudgeWindowGoodSeconds", m_fJudgeWindowGoodSeconds ); + ini.SetValueF( "Options", "JudgeWindowBooSeconds", m_fJudgeWindowBooSeconds ); ini.SetValueF( "Options", "LifeDifficultyScale", m_fLifeDifficultyScale ); ini.SetValueI( "Options", "MovieDecodeMS", m_iMovieDecodeMS ); ini.SetValueB( "Options", "UseBGIfNoBanner", m_bUseBGIfNoBanner ); diff --git a/stepmania/src/ScoreDisplayOni.cpp b/stepmania/src/ScoreDisplayOni.cpp index 78f0527e91..bc74d26f91 100644 --- a/stepmania/src/ScoreDisplayOni.cpp +++ b/stepmania/src/ScoreDisplayOni.cpp @@ -50,7 +50,7 @@ void ScoreDisplayOni::Draw() { float fSecsIntoPlay; if( GAMESTATE->IsPlayerEnabled(m_PlayerNumber) ) - fSecsIntoPlay = GAMESTATE->GetPlayerSurviveTime(m_PlayerNumber); + fSecsIntoPlay = GAMESTATE->m_CurStageStats.fAliveSeconds[m_PlayerNumber]; else fSecsIntoPlay = 0; diff --git a/stepmania/src/ScoreKeeperMAX2.cpp b/stepmania/src/ScoreKeeperMAX2.cpp index 43ec4dd899..73a0d79181 100644 --- a/stepmania/src/ScoreKeeperMAX2.cpp +++ b/stepmania/src/ScoreKeeperMAX2.cpp @@ -42,7 +42,7 @@ void ScoreKeeperMAX2::AddScore( TapNoteScore score ) ASSERT(m_lScore >= 0); - GAMESTATE->m_fScore[m_PlayerNumber] = m_lScore * m_fScoreMultiplier; + GAMESTATE->m_CurStageStats.fScore[m_PlayerNumber] = m_lScore * m_fScoreMultiplier; } void ScoreKeeperMAX2::HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) @@ -52,8 +52,8 @@ void ScoreKeeperMAX2::HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) ASSERT( iNumTapsInRow >= 1 ); // update dance points for Oni lifemeter - GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += iNumTapsInRow * TapNoteScoreToDancePoints( score ); - GAMESTATE->m_TapNoteScores[m_PlayerNumber][score] += iNumTapsInRow; + GAMESTATE->m_CurStageStats.iActualDancePoints[m_PlayerNumber] += iNumTapsInRow * TapNoteScoreToDancePoints( score ); + GAMESTATE->m_CurStageStats.iTapNoteScores[m_PlayerNumber][score] += iNumTapsInRow; /* A single step's points are calculated as follows: @@ -100,8 +100,8 @@ void ScoreKeeperMAX2::HandleNoteScore( TapNoteScore score, int iNumTapsInRow ) void ScoreKeeperMAX2::HandleHoldNoteScore( HoldNoteScore score, TapNoteScore TapNoteScore ) { // update dance points totals - GAMESTATE->m_HoldNoteScores[m_PlayerNumber][score] ++; - GAMESTATE->m_iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( score ); + GAMESTATE->m_CurStageStats.iHoldNoteScores[m_PlayerNumber][score] ++; + GAMESTATE->m_CurStageStats.iActualDancePoints[m_PlayerNumber] += HoldNoteScoreToDancePoints( score ); if( score == HNS_OK ) AddScore( TNS_PERFECT ); diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index 380ad89a94..9d6f34ad09 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -115,12 +115,9 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) { LOG->Trace( "ScreenEvaluation::ScreenEvaluation()" ); - int l, p; // for counting - - - /////////////////////////// - // Set m_ResultMode. This enum will make our life easier later when we init different pieces depending on context. - /////////////////////////// + // + // Set m_ResultMode. This enum will make our life easier later when we init different pieces. + // switch( GAMESTATE->m_PlayMode ) { case PLAY_MODE_ARCADE: @@ -129,54 +126,42 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) case PLAY_MODE_NONSTOP: case PLAY_MODE_ONI: case PLAY_MODE_ENDLESS: - m_ResultMode = RM_ONI; + m_ResultMode = RM_COURSE; break; default: ASSERT(0); } - /////////////////////////// - // Figure out which statistics we're going to display - /////////////////////////// - int iPossibleDancePoints[NUM_PLAYERS]; - int iActualDancePoints[NUM_PLAYERS]; - int iTapNoteScores[NUM_PLAYERS][NUM_TAP_NOTE_SCORES]; - int iHoldNoteScores[NUM_PLAYERS][NUM_HOLD_NOTE_SCORES]; - int iMaxCombo[NUM_PLAYERS]; - float fScore[NUM_PLAYERS]; - float fPossibleRadarValues[NUM_PLAYERS][NUM_RADAR_CATEGORIES]; - float fActualRadarValues[NUM_PLAYERS][NUM_RADAR_CATEGORIES]; - + // + // Figure out which statistics and songs we're going to display + // + StageStats stageStats; + vector vSongsToShow; switch( m_ResultMode ) { case RM_ARCADE_SUMMARY: - COPY( iPossibleDancePoints, GAMESTATE->m_iAccumPossibleDancePoints ); - COPY( iActualDancePoints, GAMESTATE->m_iAccumActualDancePoints ); - COPY( iTapNoteScores, GAMESTATE->m_AccumTapNoteScores ); - COPY( iHoldNoteScores, GAMESTATE->m_AccumHoldNoteScores ); - COPY( iMaxCombo, GAMESTATE->m_iAccumMaxCombo ); - COPY( fScore, GAMESTATE->m_fAccumScore ); - COPY( fPossibleRadarValues, GAMESTATE->m_fAccumRadarPossible ); - COPY( fActualRadarValues, GAMESTATE->m_fAccumRadarActual ); + { + // Show stats only for the latest 3 normal songs + passed extra stages + int iNumSongsToThrowAway = max( 0, PREFSMAN->m_iNumArcadeStages-3 ); + for( unsigned i=iNumSongsToThrowAway; im_vPassedStageStats.size(); i++ ) + { + stageStats += GAMESTATE->m_vPassedStageStats[i]; + vSongsToShow.push_back( GAMESTATE->m_vPassedStageStats[i].pSong ); + } + } break; case RM_ARCADE_STAGE: - case RM_ONI: - COPY( iPossibleDancePoints, GAMESTATE->m_iPossibleDancePoints ); - COPY( iActualDancePoints, GAMESTATE->m_iActualDancePoints ); - COPY( iTapNoteScores, GAMESTATE->m_TapNoteScores ); - COPY( iHoldNoteScores, GAMESTATE->m_HoldNoteScores ); - COPY( iMaxCombo, GAMESTATE->m_iMaxCombo ); - COPY( fScore, GAMESTATE->m_fScore ); - COPY( fPossibleRadarValues, GAMESTATE->m_fRadarPossible ); - COPY( fActualRadarValues, GAMESTATE->m_fRadarActual ); + case RM_COURSE: + stageStats = GAMESTATE->m_CurStageStats; break; + default: + ASSERT(0); } - /////////////////////////// + // // Init the song banners depending on m_ResultMode - /////////////////////////// - // EZ2 should hide these things by placing them off screen with theme metrics + // switch( m_ResultMode ) { case RM_ARCADE_STAGE: @@ -205,31 +190,23 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) break; case RM_ARCADE_SUMMARY: { - // crop down to 3 - for( int p=0; pm_apSongsPlayed.size() > STAGES_TO_SHOW_IN_SUMMARY ) - GAMESTATE->m_apSongsPlayed.erase( GAMESTATE->m_apSongsPlayed.begin(), GAMESTATE->m_apSongsPlayed.begin() + (GAMESTATE->m_apSongsPlayed.size() - STAGES_TO_SHOW_IN_SUMMARY) ); - } - - const unsigned iSongsToShow = GAMESTATE->m_apSongsPlayed.size(); - ASSERT( iSongsToShow > 0 ); - - for( unsigned i=0; im_apSongsPlayed[i] ); - float fBannerOffset = i - (iSongsToShow-1)/2.0f; + m_BannerWithFrame[i].LoadFromSong( vSongsToShow[i] ); + float fBannerOffset = i - (vSongsToShow.size()-1)/2.0f; m_BannerWithFrame[i].SetXY( BANNER_X + fBannerOffset*32, BANNER_Y + fBannerOffset*16 ); m_BannerWithFrame[i].SetZoom( 0.70f ); this->AddChild( &m_BannerWithFrame[i] ); } } break; - case RM_ONI: + case RM_COURSE: m_BannerWithFrame[0].LoadFromCourse( GAMESTATE->m_pCurCourse ); m_BannerWithFrame[0].SetXY( BANNER_X, BANNER_Y ); this->AddChild( &m_BannerWithFrame[0] ); break; + default: + ASSERT(0); } @@ -243,7 +220,7 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) ); this->AddChild( &m_Menu ); - for( p=0; pIsPlayerEnabled( (PlayerNumber)p ) ) // If EZ2 wants to hide this graphic, place it somewhere off screen using theme metrics continue; // skip @@ -256,19 +233,16 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) } - // // Calculate grades // Grade grade[NUM_PLAYERS]; for( p=0; pIsPlayerEnabled(p) || GAMESTATE->m_fSecondsBeforeFail[p] != -1 ) - { + if( !GAMESTATE->IsPlayerEnabled(p) || GAMESTATE->m_CurStageStats.bFailed[p] ) grade[p] = GRADE_E; - continue; - } - grade[p] = GAMESTATE->GetCurrentGrade( (PlayerNumber)p ); + else + grade[p] = GAMESTATE->GetCurrentGrade( (PlayerNumber)p ); } Grade max_grade = GRADE_NO_DATA; @@ -276,52 +250,53 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) max_grade = max( max_grade, grade[p] ); - //////////////////////// + // // update persistent statistics - //////////////////////// + // bool bNewRecord[NUM_PLAYERS]; - for( p=0; pIsPlayerEnabled(p) ) - continue; - - if( grade[p] == GRADE_E ) - continue; + if( !GAMESTATE->IsPlayerEnabled(p) || grade[p] == GRADE_E ) + continue; // can't be a new record switch( m_ResultMode ) { case RM_ARCADE_STAGE: - Notes* pNotes = GAMESTATE->m_pCurNotes[p]; - if( SONGMAN->IsUsingMemoryCard((PlayerNumber)p) ) - bNewRecord[p] = pNotes->AddMemCardScore( (PlayerNumber)p, grade[p], (int)fScore[p] ); + { + Notes* pNotes = GAMESTATE->m_pCurNotes[p]; + if( SONGMAN->IsUsingMemoryCard((PlayerNumber)p) ) + bNewRecord[p] = pNotes->AddMemCardRecord( (PlayerNumber)p, grade[p], stageStats.fScore[p] ); + } break; + case RM_ARCADE_SUMMARY: + { + float fAverageMeter = stageStats.iMeter[p] / (float)PREFSMAN->m_iNumArcadeStages; // intentional: doesn't count extra stage + HighScoreCategory hsc = AverageMeterToHighScoreCategory( fAverageMeter ); + m_bGoToNameEntry |= SONGMAN->IsNewMachineRecord( hsc, stageStats.fScore[p] ); + } + break; + case RM_COURSE: + { + Course* pCourse = GAMESTATE->m_pCurCourse; + pCourse->IsNewMachineRecord( (PlayerNumber)p, stageStats.iActualDancePoints[p], stageStats.fAliveSeconds[p] ); + m_bGoToNameEntry |= true; + } + break; + default: + ASSERT(0); } } + m_bTryExtraStage = + GAMESTATE->HasEarnedExtraStage() && + m_ResultMode==RM_ARCADE_STAGE && + !PREFSMAN->m_bEventMode; - - m_bTryExtraStage = false; - if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) && m_ResultMode==RM_ARCADE_STAGE ) - { - for( p=0; pIsPlayerEnabled( (PlayerNumber)p ) ) - continue; // skip - - if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() == DIFFICULTY_HARD && grade[p] >= GRADE_AA ) - m_bTryExtraStage = true; - } - } - if( PREFSMAN->m_bEventMode ) - m_bTryExtraStage = false; - - - ///////////////////////////////// + // // Init ResultMode-specific displays - ///////////////////////////////// + // for( p=0; pIsPlayerEnabled( (PlayerNumber)p ) ) @@ -331,7 +306,7 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) switch( m_ResultMode ) { - case RM_ONI: + case RM_COURSE: { m_sprPercentFrame[p].Load( THEME->GetPathTo("Graphics","evaluation percent frame") ); m_sprPercentFrame[p].StopAnimating(); @@ -356,8 +331,8 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) m_textOniPercentSmall[p].SetEffectGlowing( 1.0f ); this->AddChild( &m_textOniPercentSmall[p] ); - iPossibleDancePoints[p] = max( 1, iPossibleDancePoints[p] ); - float fPercentDancePoints = iActualDancePoints[p] / (float)iPossibleDancePoints[p] + 0.0001f; // correct for rounding errors + stageStats.iPossibleDancePoints[p] = max( 1, stageStats.iPossibleDancePoints[p] ); + float fPercentDancePoints = stageStats.iActualDancePoints[p] / (float)stageStats.iPossibleDancePoints[p] + 0.0001f; // correct for rounding errors fPercentDancePoints = max( fPercentDancePoints, 0 ); int iPercentDancePointsLarge = int(fPercentDancePoints*100); int iPercentDancePointsSmall = int( (fPercentDancePoints*100 - int(fPercentDancePoints*100)) * 10 ); @@ -374,7 +349,7 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) m_textSongsSurvived[p].LoadFromNumbers( THEME->GetPathTo("Numbers","evaluation stage numbers") ); m_textSongsSurvived[p].TurnShadowOff(); m_textSongsSurvived[p].SetXY( SONGS_SURVIVED_X(p), SONGS_SURVIVED_Y ); - m_textSongsSurvived[p].SetText( ssprintf("%02d", GAMESTATE->m_iSongsBeforeFail[p]) ); + m_textSongsSurvived[p].SetText( ssprintf("%02d", stageStats.iSongsPassed[p]+1) ); this->AddChild( &m_textSongsSurvived[p] ); } break; @@ -405,42 +380,41 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) m_sprBonusFrame[p].SetXY( BONUS_X(p), BONUS_Y ); this->AddChild( &m_sprBonusFrame[p] ); - for( int l=0; lGetPathTo("Graphics","evaluation bars possible 1x2") ); - m_sprPossibleBar[p][l].SetState( p ); - m_sprPossibleBar[p][l].SetHorizAlign( Actor::align_left ); - m_sprPossibleBar[p][l].SetX( BAR_BASE_X(p) ); - m_sprPossibleBar[p][l].SetY( BAR_START_Y + BAR_SPACING_Y*l ); - m_sprPossibleBar[p][l].SetRotation( BAR_ROTATION(p) ); - m_sprPossibleBar[p][l].SetZoomX( 0 ); - m_sprPossibleBar[p][l].ZoomToHeight( BAR_HEIGHT ); - m_sprPossibleBar[p][l].BeginTweening( 0.2f + l*0.1f ); // sleep - m_sprPossibleBar[p][l].BeginTweening( 0.5f ); // tween - m_sprPossibleBar[p][l].SetTweenZoomToWidth( BAR_WIDTH*fPossibleRadarValues[p][l] ); - this->AddChild( &m_sprPossibleBar[p][l] ); + m_sprPossibleBar[p][r].Load( THEME->GetPathTo("Graphics","evaluation bars possible 1x2") ); + m_sprPossibleBar[p][r].SetState( p ); + m_sprPossibleBar[p][r].SetHorizAlign( Actor::align_left ); + m_sprPossibleBar[p][r].SetX( BAR_BASE_X(p) ); + m_sprPossibleBar[p][r].SetY( BAR_START_Y + BAR_SPACING_Y*r ); + m_sprPossibleBar[p][r].SetRotation( BAR_ROTATION(p) ); + m_sprPossibleBar[p][r].SetZoomX( 0 ); + m_sprPossibleBar[p][r].ZoomToHeight( BAR_HEIGHT ); + m_sprPossibleBar[p][r].BeginTweening( 0.2f + r*0.1f ); // sleep + m_sprPossibleBar[p][r].BeginTweening( 0.5f ); // tween + m_sprPossibleBar[p][r].SetTweenZoomToWidth( BAR_WIDTH*stageStats.fRadarPossible[p][r] ); + this->AddChild( &m_sprPossibleBar[p][r] ); - m_sprActualBar[p][l].Load( THEME->GetPathTo("Graphics","evaluation bars actual 1x2") ); - m_sprActualBar[p][l].SetState( p ); - m_sprActualBar[p][l].StopAnimating(); - m_sprActualBar[p][l].SetHorizAlign( Actor::align_left ); - m_sprActualBar[p][l].SetX( BAR_BASE_X(p) ); - m_sprActualBar[p][l].SetY( BAR_START_Y + BAR_SPACING_Y*l ); - m_sprActualBar[p][l].SetRotation( BAR_ROTATION(p) ); - m_sprActualBar[p][l].SetZoomX( 0 ); - m_sprActualBar[p][l].ZoomToHeight( BAR_HEIGHT ); - m_sprActualBar[p][l].BeginTweening( 1.0f + l*0.2f ); // sleep - m_sprActualBar[p][l].BeginTweening( 1.0f ); // tween - m_sprActualBar[p][l].SetTweenZoomToWidth( BAR_WIDTH*fActualRadarValues[p][l] ); - if( fActualRadarValues[p][l] == fPossibleRadarValues[p][l] ) - m_sprActualBar[p][l].SetEffectGlowing(); - this->AddChild( &m_sprActualBar[p][l] ); + m_sprActualBar[p][r].Load( THEME->GetPathTo("Graphics","evaluation bars actual 1x2") ); + m_sprActualBar[p][r].SetState( p ); + m_sprActualBar[p][r].StopAnimating(); + m_sprActualBar[p][r].SetHorizAlign( Actor::align_left ); + m_sprActualBar[p][r].SetX( BAR_BASE_X(p) ); + m_sprActualBar[p][r].SetY( BAR_START_Y + BAR_SPACING_Y*r ); + m_sprActualBar[p][r].SetRotation( BAR_ROTATION(p) ); + m_sprActualBar[p][r].SetZoomX( 0 ); + m_sprActualBar[p][r].ZoomToHeight( BAR_HEIGHT ); + m_sprActualBar[p][r].BeginTweening( 1.0f + r*0.2f ); // sleep + m_sprActualBar[p][r].BeginTweening( 1.0f ); // tween + m_sprActualBar[p][r].SetTweenZoomToWidth( BAR_WIDTH*stageStats.fRadarActual[p][r] ); + if( stageStats.fRadarActual[p][r] == stageStats.fRadarPossible[p][r] ) + m_sprActualBar[p][r].SetEffectGlowing(); + this->AddChild( &m_sprActualBar[p][r] ); } break; } } - // Chris: If EZ2 wants to hide these things, place them off screen using theme metrics if( bNewRecord[p] ) { m_sprNewRecord[p].Load( THEME->GetPathTo("Graphics","evaluation new record") ); @@ -450,12 +424,12 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) } } - ////////////////////////// + // // Init non-ResultMode specific displays. // Do this after Result-specific displays so that the text will draw on top of // the bonus frame. - ////////////////////////// - for( l=0; lGetPathTo("Graphics","evaluation judge labels 1x8") ); @@ -467,7 +441,7 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) } m_sprScoreLabel.Load( THEME->GetPathTo("Graphics","evaluation score labels") ); - m_sprScoreLabel.SetState( m_ResultMode==RM_ONI ? 1 : 0 ); + m_sprScoreLabel.SetState( m_ResultMode==RM_COURSE ? 1 : 0 ); m_sprScoreLabel.StopAnimating(); m_sprScoreLabel.SetXY( SCORE_LABELS_X, SCORE_Y ); m_sprScoreLabel.SetZoom( 1.0f ); @@ -483,26 +457,26 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) { m_textJudgeNumbers[l][p].LoadFromNumbers( THEME->GetPathTo("Numbers","evaluation judge numbers") ); m_textJudgeNumbers[l][p].TurnShadowOff(); - m_textJudgeNumbers[l][p].SetXY( JUDGE_X(m_ResultMode==RM_ONI,p,l), JUDGE_Y(l) ); + m_textJudgeNumbers[l][p].SetXY( JUDGE_X(m_ResultMode==RM_COURSE,p,l), JUDGE_Y(l) ); m_textJudgeNumbers[l][p].SetZoom( 1.0f ); m_textJudgeNumbers[l][p].SetDiffuse( PlayerToColor(p) ); this->AddChild( &m_textJudgeNumbers[l][p] ); } - m_textJudgeNumbers[0][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_MARVELOUS]) ); - m_textJudgeNumbers[1][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_PERFECT]) ); - m_textJudgeNumbers[2][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_GREAT]) ); - m_textJudgeNumbers[3][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_GOOD]) ); - m_textJudgeNumbers[4][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_BOO]) ); - m_textJudgeNumbers[5][p].SetText( ssprintf("%4d", iTapNoteScores[p][TNS_MISS]) ); - m_textJudgeNumbers[6][p].SetText( ssprintf("%4d", iHoldNoteScores[p][HNS_OK]) ); - m_textJudgeNumbers[7][p].SetText( ssprintf("%4d", iMaxCombo[p]) ); + m_textJudgeNumbers[0][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_MARVELOUS]) ); + m_textJudgeNumbers[1][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_PERFECT]) ); + m_textJudgeNumbers[2][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_GREAT]) ); + m_textJudgeNumbers[3][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_GOOD]) ); + m_textJudgeNumbers[4][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_BOO]) ); + m_textJudgeNumbers[5][p].SetText( ssprintf("%4d", stageStats.iTapNoteScores[p][TNS_MISS]) ); + m_textJudgeNumbers[6][p].SetText( ssprintf("%4d", stageStats.iHoldNoteScores[p][HNS_OK]) ); + m_textJudgeNumbers[7][p].SetText( ssprintf("%4d", stageStats.iMaxCombo[p]) ); - if( m_ResultMode==RM_ONI ) - m_ScoreDisplay[p].SetText( SecondsToTime(GAMESTATE->GetPlayerSurviveTime( (PlayerNumber)p )) ); + if( m_ResultMode==RM_COURSE ) + m_ScoreDisplay[p].SetText( SecondsToTime(stageStats.fAliveSeconds[p]) ); else - m_ScoreDisplay[p].SetScore( fScore[p] ); + m_ScoreDisplay[p].SetScore( stageStats.fScore[p] ); } @@ -546,7 +520,7 @@ ScreenEvaluation::ScreenEvaluation( bool bSummary ) ASSERT(0); // invalid grade } break; - case RM_ONI: + case RM_COURSE: case RM_ARCADE_SUMMARY: switch( max_grade ) { @@ -594,7 +568,7 @@ void ScreenEvaluation::TweenOnScreen() float fOriginalX, fOriginalY; - for( i=0; im_iCurrentStageIndex++; + GAMESTATE->m_iCurrentStageIndex++; // Increment the stage counter. + + GAMESTATE->m_vPassedStageStats.push_back( GAMESTATE->m_CurStageStats ); // Save this stage's stats } diff --git a/stepmania/src/ScreenEvaluation.h b/stepmania/src/ScreenEvaluation.h index 59cd629feb..c5b5975166 100644 --- a/stepmania/src/ScreenEvaluation.h +++ b/stepmania/src/ScreenEvaluation.h @@ -22,7 +22,7 @@ const int NUM_JUDGE_LINES = 8; // marvelous, perfect, great, good, boo, miss, ok, max_combo -const int STAGES_TO_SHOW_IN_SUMMARY = 3; // only show the latest three stages in a summary +const int MAX_SONGS_TO_SHOW = 5; // In summary, we show last 3 stages, plus extra stages if passed class ScreenEvaluation : public Screen @@ -42,12 +42,12 @@ public: virtual void MenuStart( PlayerNumber pn ); protected: - enum ResultMode { RM_ARCADE_STAGE, RM_ARCADE_SUMMARY, RM_ONI }; + enum ResultMode { RM_ARCADE_STAGE, RM_ARCADE_SUMMARY, RM_COURSE }; ResultMode m_ResultMode; MenuElements m_Menu; - BannerWithFrame m_BannerWithFrame[STAGES_TO_SHOW_IN_SUMMARY]; + BannerWithFrame m_BannerWithFrame[MAX_SONGS_TO_SHOW]; BitmapText m_textStage; DifficultyIcon m_DifficultyIcon[NUM_PLAYERS]; @@ -78,6 +78,8 @@ protected: Sprite m_sprNewRecord[NUM_PLAYERS]; + bool m_bGoToNameEntry; + bool m_bTryExtraStage; Sprite m_sprTryExtraStage; }; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 24d591df4c..4694e9b39f 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -116,10 +116,9 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) SOUNDMAN->StopMusic(); - /* It's OK to operate on GAMESTATE here, but not in the constructor */ - GAMESTATE->ResetStageStatistics(); // clear values + GAMESTATE->m_CurStageStats = StageStats(); // clear values - // Update possible dance points + // Fill in m_CurStageStats for( p=0; pIsPlayerEnabled(p) ) @@ -129,14 +128,20 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) switch( GAMESTATE->m_PlayMode ) { case PLAY_MODE_ARCADE: + GAMESTATE->m_CurStageStats.pSong = GAMESTATE->m_pCurSong; + GAMESTATE->m_CurStageStats.iMeter[p] = GAMESTATE->m_pCurNotes[p]->GetMeter(); + GAMESTATE->m_pCurNotes[p]->GetNoteData( ¬edata ); - GAMESTATE->m_iPossibleDancePoints[p] = notedata.GetPossibleDancePoints(); + GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] = notedata.GetPossibleDancePoints(); break; case PLAY_MODE_NONSTOP: case PLAY_MODE_ONI: case PLAY_MODE_ENDLESS: { - GAMESTATE->m_iPossibleDancePoints[p] = 0; + GAMESTATE->m_CurStageStats.pSong = NULL; + GAMESTATE->m_CurStageStats.iMeter[p] = 0; + + GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] = 0; Course* pCourse = GAMESTATE->m_pCurCourse; vector apSongs; @@ -146,9 +151,10 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) for( unsigned i=0; im_CurStageStats.iMeter[p] += apNotes[i]->GetMeter(); apNotes[i]->GetNoteData( ¬edata ); int iPossibleDancePoints = notedata.GetPossibleDancePoints(); - GAMESTATE->m_iPossibleDancePoints[p] += iPossibleDancePoints; + GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] += iPossibleDancePoints; } } break; @@ -499,7 +505,7 @@ bool ScreenGameplay::IsLastSong() CStringArray asModifiers; pCourse->GetSongAndNotesForCurrentStyle( apSongs, apNotes, asModifiers, true ); - return unsigned(GAMESTATE->m_iSongsIntoCourse) >= apSongs.size(); // there are no more songs left + return unsigned(GAMESTATE->m_CurStageStats.iSongsPassed) >= apSongs.size(); // there are no more songs left } break; default: @@ -523,9 +529,9 @@ void ScreenGameplay::LoadNextSong( bool bFirstLoad ) int p; for( p=0; pm_iSongsBeforeFail[p]+1) ); + m_textCourseSongNumber[p].SetText( ssprintf("%d", GAMESTATE->m_CurStageStats.iSongsPassed[p]+1) ); // If it's the first song, record the options the player selected for later. - if (GAMESTATE->m_iSongsIntoCourse == 0) + if( GAMESTATE->m_CurStageStats.iSongsPassed[p] == 0 ) GAMESTATE->m_SelectedOptions[p] = GAMESTATE->m_PlayerOptions[p]; } Course* pCourse = GAMESTATE->m_pCurCourse; @@ -535,7 +541,10 @@ void ScreenGameplay::LoadNextSong( bool bFirstLoad ) pCourse->GetSongAndNotesForCurrentStyle( apSongs, apNotes, asModifiers, true ); - int iPlaySongIndex = GAMESTATE->m_iSongsIntoCourse; + int iPlaySongIndex = 0; + for( p=0; pIsPlayerEnabled(p) ) + iPlaySongIndex = max( iPlaySongIndex, GAMESTATE->m_CurStageStats.iSongsPassed[p] ); iPlaySongIndex %= apSongs.size(); GAMESTATE->m_pCurSong = apSongs[iPlaySongIndex]; @@ -572,7 +581,7 @@ void ScreenGameplay::LoadNextSong( bool bFirstLoad ) 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 && GAMESTATE->m_fSecondsBeforeFail[p] != -1 ) // already failed + if( GAMESTATE->m_SongOptions.m_LifeType==SongOptions::LIFE_BATTERY && GAMESTATE->m_CurStageStats.bFailed[p] ) // already failed ShowOniGameOver((PlayerNumber)p); @@ -732,6 +741,13 @@ void ScreenGameplay::Update( float fDeltaTime ) { case STATE_DANCING: + // + // Update players' alive time + // + for( int p=0; pIsPlayerEnabled(p) ) + GAMESTATE->m_CurStageStats.fAliveSeconds[p] += fDeltaTime; + // // Check for end of song // @@ -758,8 +774,8 @@ void ScreenGameplay::Update( float fDeltaTime ) // check for individual fail for ( pn=0; pnIsFailing() && GAMESTATE->m_fSecondsBeforeFail[pn] == -1) - GAMESTATE->m_fSecondsBeforeFail[pn] = GAMESTATE->GetElapsedSeconds(); + if ( m_pLifeMeter[pn]->IsFailing() && !GAMESTATE->m_CurStageStats.bFailed[pn] ) + GAMESTATE->m_CurStageStats.bFailed[pn] = true; // fail } break; @@ -769,19 +785,19 @@ void ScreenGameplay::Update( float fDeltaTime ) else m_Background.TurnDangerOff(); // check for individual fail - for( pn=0; pnIsPlayerEnabled(pn) ) continue; if( !m_pLifeMeter[pn]->IsFailing()) - continue; /* hasn't failed */ - - if( GAMESTATE->m_fSecondsBeforeFail[pn] != -1 ) + continue; /* isn't failing */ + if( GAMESTATE->m_CurStageStats.bFailed[pn] ) continue; /* failed and is already dead */ if( !AllFailedEarlier() ) // if not the last one to fail { // kill them! - GAMESTATE->m_fSecondsBeforeFail[pn] = GAMESTATE->GetElapsedSeconds(); + GAMESTATE->m_CurStageStats.bFailed[pn] = true; m_soundOniDie.PlayRandom(); ShowOniGameOver((PlayerNumber)pn); m_Player[pn].Init(); // remove all notes and scoring @@ -1169,38 +1185,29 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) for( int r=0; rm_fRadarPossible[p][r] = NoteDataUtil::GetRadarValue( m_Player[p], rc, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds ); - GAMESTATE->m_fRadarActual[p][r] = m_Player[p].GetActualRadarValue( rc, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds ); + GAMESTATE->m_CurStageStats.fRadarPossible[p][r] = NoteDataUtil::GetRadarValue( m_Player[p], rc, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds ); + GAMESTATE->m_CurStageStats.fRadarActual[p][r] = m_Player[p].GetActualRadarValue( rc, GAMESTATE->m_pCurSong->m_fMusicLengthSeconds ); } } } - GAMESTATE->m_apSongsPlayed.push_back( GAMESTATE->m_pCurSong ); - GAMESTATE->m_iSongsIntoCourse++; for( p=0; pIsPlayerEnabled(p) ) - if( !m_pLifeMeter[p]->FailedEarlier() ) - GAMESTATE->m_iSongsBeforeFail[p]++; - + if( GAMESTATE->IsPlayerEnabled(p) && !GAMESTATE->m_CurStageStats.bFailed[p] ) + GAMESTATE->m_CurStageStats.iSongsPassed[p]++; if( !IsLastSong() ) { for( int p=0; pIsPlayerEnabled(p) ) - if( !m_pLifeMeter[p]->FailedEarlier() ) - m_pLifeMeter[p]->SongEnded(); // let the oni life meter give them back a life - + if( GAMESTATE->IsPlayerEnabled(p) && !GAMESTATE->m_CurStageStats.bFailed[p] ) + m_pLifeMeter[p]->OnSongEnded(); // give a little life back between stages m_OniFade.CloseWipingRight( SM_BeginLoadingNextSong ); } else // IsLastSong { if( m_DancingState == STATE_OUTRO ) // gameplay already ended return; // ignore - m_DancingState = STATE_OUTRO; - GAMESTATE->AccumulateStageStatistics(); // accumulate values for final evaluation - if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_END_OF_SONG && AllFailedEarlier() ) { this->SendScreenMessage( SM_BeginFailed, 0 ); @@ -1210,23 +1217,10 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) m_StarWipe.CloseWipingRight( SM_None ); // do they deserve an extra stage? - - bool bTryExtraStage = false; - if( (GAMESTATE->IsFinalStage() || GAMESTATE->IsExtraStage()) ) - { - for( p=0; pIsPlayerEnabled( (PlayerNumber)p ) ) - continue; // skip - - if( GAMESTATE->m_pCurNotes[p]->GetDifficulty() == DIFFICULTY_HARD && GAMESTATE->GetCurrentGrade((PlayerNumber)p) >= GRADE_AA ) - bTryExtraStage = true; - } - } + bool bTryExtraStage = GAMESTATE->HasEarnedExtraStage(); if( PREFSMAN->m_bEventMode ) bTryExtraStage = false; - if( bTryExtraStage ) { this->SendScreenMessage( SM_ShowTryExtraStage, 1 ); @@ -1458,11 +1452,11 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) // show the survive time if extra stage if( GAMESTATE->IsExtraStage() || GAMESTATE->IsExtraStage2() ) { - float fMaxSurviveSeconds = -1; + float fMaxSurviveSeconds = 0; for( int p=0; pIsPlayerEnabled(p) ) - fMaxSurviveSeconds = max( fMaxSurviveSeconds, GAMESTATE->GetPlayerSurviveTime((PlayerNumber)p) ); - ASSERT( fMaxSurviveSeconds != -1 ); + fMaxSurviveSeconds = max( fMaxSurviveSeconds, GAMESTATE->m_CurStageStats.fAliveSeconds[p] ); + ASSERT( fMaxSurviveSeconds > 0 ); m_textSurviveTime.SetText( "TIME " + SecondsToTime(fMaxSurviveSeconds) ); m_textSurviveTime.BeginTweening( 0.3f ); // sleep m_textSurviveTime.BeginTweening( 0.3f ); // fade in diff --git a/stepmania/src/ScreenSelectMusic.cpp b/stepmania/src/ScreenSelectMusic.cpp index ea9abb6e30..5dd2ddcdaa 100644 --- a/stepmania/src/ScreenSelectMusic.cpp +++ b/stepmania/src/ScreenSelectMusic.cpp @@ -701,7 +701,7 @@ void ScreenSelectMusic::AfterNotesChange( PlayerNumber pn ) Notes* m_pNotes = GAMESTATE->m_pCurNotes[pn]; if( m_pNotes && SONGMAN->IsUsingMemoryCard(pn) ) - m_HighScore[pn].SetScore( (float)m_pNotes->m_MemCardScores[pn].iScore ); + m_HighScore[pn].SetScore( m_pNotes->m_MemCardScores[pn].fScore ); m_DifficultyIcon[pn].SetFromNotes( pn, pNotes ); if( pNotes && pNotes->IsAutogen() ) diff --git a/stepmania/src/SongManager.cpp b/stepmania/src/SongManager.cpp index 64e3d97ae4..00daf3235d 100644 --- a/stepmania/src/SongManager.cpp +++ b/stepmania/src/SongManager.cpp @@ -30,6 +30,8 @@ SongManager* SONGMAN = NULL; // global and accessable from anywhere in our progr const CString CATEGORY_TOP_SCORE_FILE = "CategoryTopScores.dat"; const CString COURSE_TOP_SCORE_FILE = "CourseTopScores.dat"; +const int CATEGORY_TOP_SCORE_VERSION = 1; +const int COURSE_TOP_SCORE_VERSION = 1; #define NUM_GROUP_COLORS THEME->GetMetricI("SongManager","NumGroupColors") @@ -210,7 +212,7 @@ void SongManager::InitMachineScoresFromDisk() for( int j=0; jm_MachineScores[i][j][k].iDancePoints = iDancePoints; - pCourse->m_MachineScores[i][j][k].fSurviveTime = fSurviveTime; - pCourse->m_MachineScores[i][j][k].sName = szName; - } - } - } - if( fp ) + { + int version; + fscanf(fp, "%d\n", &version ); + if( version == COURSE_TOP_SCORE_VERSION ) + { + while( fp && !feof(fp) ) + { + char szPath[256]; + fscanf(fp, "%s\n", szPath); + Course* pCourse = GetCourseFromPath( szPath ); + + for( int i=0; im_MachineScores[i][j][k].iDancePoints = iDancePoints; + pCourse->m_MachineScores[i][j][k].fSurviveTime = fSurviveTime; + pCourse->m_MachineScores[i][j][k].sName = szName; + } + } + } + } fclose(fp); + } } } @@ -271,15 +284,16 @@ void SongManager::SaveMachineScoresToDisk() // Write category top scores { FILE* fp = fopen( CATEGORY_TOP_SCORE_FILE, "w" ); - - for( int i=0; im_CurStyle][hsc][i]; + if( fScore > hs.fScore ) + return true; + } + return false; +} + +struct MachineScoreAndPlayerNumber : public SongManager::MachineScore +{ + PlayerNumber pn; + + static int CompareDescending( const MachineScoreAndPlayerNumber &hs1, const MachineScoreAndPlayerNumber &hs2 ) + { + if( hs1.fScore > hs2.fScore ) return -1; + else if( hs1.fScore == hs2.fScore ) return 0; + else return +1; + } + static void SortDescending( vector& vHSout ) + { + sort( vHSout.begin(), vHSout.end(), CompareDescending ); + } +}; + +void SongManager::AddMachineRecord( HighScoreCategory hsc, float fScore[NUM_PLAYERS], int iNewRecordIndexOut[NUM_PLAYERS] ) // set iNewRecordIndex = -1 if not a new record +{ + vector vHS; + for( int p=0; pIsPlayerEnabled(p) ) + continue; // skip + + MachineScoreAndPlayerNumber hs; + hs.fScore = fScore[p]; + hs.sName = ""; // this must be filled in later! + 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 + MachineScoreAndPlayerNumber::SortDescending( vHS ); + + for( unsigned i=0; im_CurStyle][GAMESTATE->m_PreferredDifficulty[newHS.pn]]; + for( int i=0; i machineScores[i].fScore ) + { + // We found the insert point. Shift down. + for( int j=i+1; j + + + +