diff --git a/stepmania/Themes/default/Sounds/ScreenEvaluation try extra2.redir b/stepmania/Themes/default/Sounds/ScreenEvaluation try extra2.redir index 2c97260a8c..a3b41e3209 100644 --- a/stepmania/Themes/default/Sounds/ScreenEvaluation try extra2.redir +++ b/stepmania/Themes/default/Sounds/ScreenEvaluation try extra2.redir @@ -1 +1 @@ -ScreenEvaluation extra1.mp3 \ No newline at end of file +ScreenEvaluation try extra1.mp3 \ No newline at end of file diff --git a/stepmania/Themes/default/metrics.ini b/stepmania/Themes/default/metrics.ini index ca3c12568c..7069cab0fa 100644 --- a/stepmania/Themes/default/metrics.ini +++ b/stepmania/Themes/default/metrics.ini @@ -791,6 +791,7 @@ GradeP1X=82 GradeP2X=118 [MusicWheel] +NumWheelItems=13 FadeSeconds=1 SwitchSeconds=0.10 RouletteSwitchSeconds=0.05 diff --git a/stepmania/src/Course.h b/stepmania/src/Course.h index 9d8db97119..d27f0ddeca 100644 --- a/stepmania/src/Course.h +++ b/stepmania/src/Course.h @@ -17,7 +17,7 @@ struct PlayerOptions; struct SongOptions; class Song; -struct Notes; +class Notes; class Course { diff --git a/stepmania/src/CourseContentsList.h b/stepmania/src/CourseContentsList.h index 8401f14933..646fe09d7b 100644 --- a/stepmania/src/CourseContentsList.h +++ b/stepmania/src/CourseContentsList.h @@ -20,7 +20,7 @@ #include "CourseEntryDisplay.h" class Course; class Song; -struct Notes; +class Notes; const int MAX_VISIBLE_CONTENTS = 5; diff --git a/stepmania/src/CourseEntryDisplay.h b/stepmania/src/CourseEntryDisplay.h index abe5030b95..fdcc577668 100644 --- a/stepmania/src/CourseEntryDisplay.h +++ b/stepmania/src/CourseEntryDisplay.h @@ -19,7 +19,7 @@ #include "GameConstantsAndTypes.h" class Course; class Song; -struct Notes; +class Notes; class CourseEntryDisplay : public ActorFrame diff --git a/stepmania/src/DifficultyIcon.h b/stepmania/src/DifficultyIcon.h index 20b1ef1f27..dba7c513c9 100644 --- a/stepmania/src/DifficultyIcon.h +++ b/stepmania/src/DifficultyIcon.h @@ -13,7 +13,7 @@ #include "Sprite.h" #include "PlayerNumber.h" -struct Notes; +class Notes; class DifficultyIcon : public Sprite diff --git a/stepmania/src/DifficultyMeter.h b/stepmania/src/DifficultyMeter.h index b8bc3c5a9e..68b0bbdc22 100644 --- a/stepmania/src/DifficultyMeter.h +++ b/stepmania/src/DifficultyMeter.h @@ -12,7 +12,7 @@ */ #include "BitmapText.h" -struct Notes; +class Notes; class DifficultyMeter : public BitmapText diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index ccd22b0c2d..3a1580d702 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -314,6 +314,7 @@ void GameState::GetFinalEvalStatsAndSongs( StageStats& statsOut, vector& } } + /* XXX: Should we store song options, too? */ /* Store the player's preferred options. This is called at the very beginning * of gameplay. */ @@ -321,6 +322,7 @@ void GameState::StoreSelectedOptions() { for( int p=0; pm_StoredPlayerOptions[p] = GAMESTATE->m_PlayerOptions[p]; + m_StoredSongOptions = m_SongOptions; } /* Restore the preferred options. This is called after a song ends, before @@ -335,6 +337,7 @@ void GameState::RestoreSelectedOptions() * to stick around for the length of the course (for regaining). Let's * just reset the options that can actually be set per-song. XXX */ // GAMESTATE->m_SongOptions.Init(); - GAMESTATE->m_SongOptions.m_DrainType = SongOptions::DRAIN_NORMAL; - GAMESTATE->m_SongOptions.m_fMusicRate = 1.0f; + m_SongOptions = m_StoredSongOptions; +// GAMESTATE->m_SongOptions.m_DrainType = SongOptions::DRAIN_NORMAL; +// GAMESTATE->m_SongOptions.m_fMusicRate = 1.0f; } diff --git a/stepmania/src/GameState.h b/stepmania/src/GameState.h index beee5a0198..2a8720f7d5 100644 --- a/stepmania/src/GameState.h +++ b/stepmania/src/GameState.h @@ -20,7 +20,7 @@ #include "StageStats.h" class Song; -struct Notes; +class Notes; class Course; class GameDef; class StyleDef; @@ -129,6 +129,7 @@ public: PlayerOptions m_PlayerOptions[NUM_PLAYERS]; // change this, and current will move gradually toward it PlayerOptions m_StoredPlayerOptions[NUM_PLAYERS]; // user's choices on the PlayerOptions screen SongOptions m_SongOptions; + SongOptions m_StoredSongOptions; void StoreSelectedOptions(); void RestoreSelectedOptions(); diff --git a/stepmania/src/Notes.h b/stepmania/src/Notes.h index 85e10cf15d..1cb2b6f9f5 100644 --- a/stepmania/src/Notes.h +++ b/stepmania/src/Notes.h @@ -18,7 +18,7 @@ #include "Grade.h" class NoteData; -struct Notes +class Notes { public: Notes(); diff --git a/stepmania/src/ScoreKeeper.h b/stepmania/src/ScoreKeeper.h index 08828efd3b..65e5dd0d47 100644 --- a/stepmania/src/ScoreKeeper.h +++ b/stepmania/src/ScoreKeeper.h @@ -23,6 +23,7 @@ #include "GameConstantsAndTypes.h" // for TapNoteScore and HoldNoteScore class NoteData; class Inventory; +class Notes; class ScoreKeeper: public Actor @@ -37,9 +38,11 @@ protected: // bool Stats_DoublesCount; public: - ScoreKeeper(PlayerNumber pn) { m_PlayerNumber=pn; } + ScoreKeeper(const vector& apNotes, PlayerNumber pn) { m_PlayerNumber=pn; } virtual void DrawPrimitives() { } + virtual void OnNextSong( int iSongInCourseIndex, Notes* pNotes ) = 0; // before a song plays (called multiple times if course) + virtual void HandleTapRowScore( TapNoteScore scoreOfLastTap, int iNumTapsInRow, Inventory* pInventory ) = 0; virtual void HandleHoldScore( HoldNoteScore holdScore, TapNoteScore tapScore ) = 0; diff --git a/stepmania/src/ScoreKeeperMAX2.cpp b/stepmania/src/ScoreKeeperMAX2.cpp index e6a2254e54..1305f8c44b 100644 --- a/stepmania/src/ScoreKeeperMAX2.cpp +++ b/stepmania/src/ScoreKeeperMAX2.cpp @@ -17,58 +17,147 @@ #include "ScreenManager.h" #include "ScreenGameplay.h" #include "GameState.h" +#include "Course.h" -ScoreKeeperMAX2::ScoreKeeperMAX2(Notes *notes, PlayerNumber pn_): - ScoreKeeper(pn_) +ScoreKeeperMAX2::ScoreKeeperMAX2( const vector& apNotes, PlayerNumber pn_ ): + ScoreKeeper(apNotes, pn_) { - if( notes ) + // + // Fill in m_CurStageStats, calculate multiplier + // + NoteData notedata; + switch( GAMESTATE->m_PlayMode ) { - NoteData noteData; - notes->GetNoteData( ¬eData ); + case PLAY_MODE_ARCADE: + case PLAY_MODE_BATTLE: + { + ASSERT( !apNotes.empty() ); + Notes* pNotes = apNotes[0]; + GAMESTATE->m_CurStageStats.pSong = GAMESTATE->m_pCurSong; + GAMESTATE->m_CurStageStats.iMeter[pn_] = pNotes->GetMeter(); + pNotes->GetNoteData( ¬edata ); + GAMESTATE->m_CurStageStats.iPossibleDancePoints[pn_] = this->GetPossibleDancePoints( ¬edata ); + } + break; + case PLAY_MODE_NONSTOP: + case PLAY_MODE_ONI: + case PLAY_MODE_ENDLESS: + { + int iTotalPossibleDancePoints = 0; + for( unsigned i=0; iGetNoteData( ¬edata ); + iTotalPossibleDancePoints += this->GetPossibleDancePoints( ¬edata ); + } - int Meter = notes->GetMeter(); - Meter = min(Meter, 10); - - int N = noteData.GetNumRowsWithTaps() + noteData.GetNumHoldNotes(); - - int sum = (N * (N + 1)) / 2; - - if(sum) - m_fScoreMultiplier = float(Meter * 1000000) / sum; - else /* avoid div/0 on empty songs */ - m_fScoreMultiplier = 0.f; - - ASSERT(m_fScoreMultiplier >= 0.0); - } - else - { - ASSERT( GAMESTATE->IsCourseMode() ); - m_fScoreMultiplier = 0.f; + GAMESTATE->m_CurStageStats.pSong = NULL; + GAMESTATE->m_CurStageStats.iPossibleDancePoints[pn_] = iTotalPossibleDancePoints; + } + break; + default: + ASSERT(0); } - m_iTapNotesHit = 0; - m_lScore = 0; + + + m_fScore = 0; m_iCurToastyCombo = 0; } -void ScoreKeeperMAX2::AddScore( TapNoteScore score ) +void ScoreKeeperMAX2::OnNextSong( int iSongInCourseIndex, Notes* pNotes ) { - int p; // score multiplier - - switch( score ) +/* + http://www.aaroninjapan.com/ddr2.html + + Note on NONSTOP Mode scoring + + Nonstop mode requires the player to play 4 songs in succession, with the total maximum possible score for the four song set being 100,000,000. This comes from the sum of the four stages' maximum possible scores, which, regardless of song or difficulty is: + + 10,000,000 for the first song + 20,000,000 for the second song + 30,000,000 for the third song + 40,000,000 for the fourth song +*/ + // + // Calculate the score multiplier + // + NoteData noteData; + pNotes->GetNoteData( ¬eData ); + int N = noteData.GetNumRowsWithTaps() + noteData.GetNumHoldNotes(); + int sum = (N * (N + 1)) / 2; + + int iMaxPossiblePoints; // fill this in below + if( GAMESTATE->IsCourseMode() ) { - case TNS_MARVELOUS: p = 10; break; - case TNS_PERFECT: p = 10; break; - case TNS_GREAT: p = 5; break; - default: p = 0; break; + iMaxPossiblePoints = (iSongInCourseIndex+1) * 1000000; + } + else + { + int iMeter = pNotes->GetMeter(); + CLAMP( iMeter, 1, 10 ); + iMaxPossiblePoints = iMeter * 100000; } - m_lScore += p * ++m_iTapNotesHit; + m_fScoreMultiplier = (float)iMaxPossiblePoints / sum; - ASSERT(m_lScore >= 0); + ASSERT(m_fScoreMultiplier >= 0.0); - GAMESTATE->m_CurStageStats.fScore[m_PlayerNumber] = m_lScore * m_fScoreMultiplier; + m_iTapNotesHit = 0; +} + + +void ScoreKeeperMAX2::AddScore( TapNoteScore score ) +{ + int p = 0; // score multiplier +/* + http://www.aaroninjapan.com/ddr2.html + + Regular scoring: + + Let p = score multiplier (Perfect = 10, Great = 5, other = 0) + + Note on NONSTOP Mode scoring + + Let p = score multiplier (Marvelous = 10, Perfect = 9, Great = 5, other = 0) + +*/ + switch( GAMESTATE->m_PlayMode ) + { + case PLAY_MODE_ARCADE: + case PLAY_MODE_BATTLE: + switch( score ) + { + case TNS_MARVELOUS: p = 10; break; + case TNS_PERFECT: p = 10; break; + case TNS_GREAT: p = 5; break; + default: p = 0; break; + } + break; + case PLAY_MODE_NONSTOP: + case PLAY_MODE_ONI: + case PLAY_MODE_ENDLESS: + switch( score ) + { + case TNS_MARVELOUS: p = 10; break; + case TNS_PERFECT: p = 9; break; + case TNS_GREAT: p = 5; break; + default: p = 0; break; + } + break; + default: + ASSERT(0); + } + + m_iTapNotesHit++; + + m_fScore += (p * m_iTapNotesHit) * m_fScoreMultiplier; + + ASSERT(m_fScore >= 0); + + printf( "score: %10.0f\n", m_fScore ); + + GAMESTATE->m_CurStageStats.fScore[m_PlayerNumber] = m_fScore; } void ScoreKeeperMAX2::HandleTapRowScore( TapNoteScore scoreOfLastTap, int iNumTapsInRow, Inventory* pInventory ) @@ -118,7 +207,7 @@ void ScoreKeeperMAX2::HandleTapRowScore( TapNoteScore scoreOfLastTap, int iNumTa 3dfsux: I redid this code so it will store the score as a long, then correct the score for each song based on that value. - lScore == p * n + m_lScore == p * n m_fScoreMultiplier = (B/S) keeping these seperate for as long as possible improves accuracy. @@ -140,20 +229,26 @@ void ScoreKeeperMAX2::HandleTapRowScore( TapNoteScore scoreOfLastTap, int iNumTa // // Toasty combo // - switch( scoreOfLastTap ) + if( GAMESTATE->IsCourseMode() ) { - case TNS_MARVELOUS: - case TNS_PERFECT: - m_iCurToastyCombo += iNumTapsInRow; - - if( m_iCurToastyCombo==250 && !GAMESTATE->m_bDemonstrationOrJukebox ) - SCREENMAN->PostMessageToTopScreen( SM_PlayToasty, 0 ); - break; - default: - m_iCurToastyCombo = 0; - break; + // don't play Toasty in a course. It's distracting. } + else + { + switch( scoreOfLastTap ) + { + case TNS_MARVELOUS: + case TNS_PERFECT: + m_iCurToastyCombo += iNumTapsInRow; + if( m_iCurToastyCombo==250 && !GAMESTATE->m_bDemonstrationOrJukebox ) + SCREENMAN->PostMessageToTopScreen( SM_PlayToasty, 0 ); + break; + default: + m_iCurToastyCombo = 0; + break; + } + } // // Regular combo diff --git a/stepmania/src/ScoreKeeperMAX2.h b/stepmania/src/ScoreKeeperMAX2.h index 82382bc9ae..c64da39fd7 100644 --- a/stepmania/src/ScoreKeeperMAX2.h +++ b/stepmania/src/ScoreKeeperMAX2.h @@ -14,12 +14,12 @@ #include "ScoreKeeper.h" #include "NoteDataWithScoring.h" -struct Notes; +class Notes; class ScoreKeeperMAX2: public ScoreKeeper { - long m_lScore; - float m_fScoreMultiplier; + double m_fScore; + double m_fScoreMultiplier; int m_iTapNotesHit; // number of notes judged so far, needed by scoring int m_iCurToastyCombo; @@ -27,7 +27,9 @@ class ScoreKeeperMAX2: public ScoreKeeper void AddScore( TapNoteScore score ); public: - ScoreKeeperMAX2(Notes *notes, PlayerNumber pn); + ScoreKeeperMAX2( const vector& apNotes, PlayerNumber pn); + + void OnNextSong( int iSongInCourseIndex, Notes* pNotes ); // before a song plays (called multiple times if course) void HandleTapRowScore( TapNoteScore scoreOfLastTap, int iNumTapsInRow, Inventory* pInventory ); void HandleHoldScore( HoldNoteScore holdScore, TapNoteScore tapScore ); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index df90be4c55..627a7ed1e9 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -132,64 +132,42 @@ ScreenGameplay::ScreenGameplay( bool bDemonstration ) GAMESTATE->m_CurStageStats = StageStats(); // clear values + // + // fill in m_apSongsQueue, m_apNotesQueue, m_asModifiersQueue + // + if( GAMESTATE->IsCourseMode() ) + { + Course* pCourse = GAMESTATE->m_pCurCourse; + pCourse->GetStageInfo( m_apSongsQueue, m_apNotesQueue[0], m_asModifiersQueue[0], GAMESTATE->GetCurrentStyleDef()->m_NotesType, false ); + for( int p=1; pm_pCurSong ); + for( int p=0; pm_pCurNotes[p] ); + m_asModifiersQueue[p].push_back( "" ); + } + } + + + // + // Init ScoreKeepers + // int p; for( p=0; pIsPlayerEnabled(p) ) continue; // skip - m_pScoreKeeper[p] = new ScoreKeeperMAX2(GAMESTATE->m_pCurNotes[p], (PlayerNumber)p); + m_pScoreKeeper[p] = new ScoreKeeperMAX2( m_apNotesQueue[p], (PlayerNumber)p ); } - // Fill in m_CurStageStats - NoteData notedata; - switch( GAMESTATE->m_PlayMode ) - { - case PLAY_MODE_ARCADE: - case PLAY_MODE_BATTLE: - { - GAMESTATE->m_CurStageStats.pSong = GAMESTATE->m_pCurSong; - for( int p=0; pIsPlayerEnabled(p) ) - continue; // skip - GAMESTATE->m_CurStageStats.iMeter[p] = GAMESTATE->m_pCurNotes[p]->GetMeter(); - GAMESTATE->m_pCurNotes[p]->GetNoteData( ¬edata ); - // TODO: Make this more elegant - GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] = m_pScoreKeeper[p]->GetPossibleDancePoints( ¬edata ); - } - } - break; - case PLAY_MODE_NONSTOP: - case PLAY_MODE_ONI: - case PLAY_MODE_ENDLESS: - { - Course* pCourse = GAMESTATE->m_pCurCourse; - pCourse->GetStageInfo( m_apCourseSongs, m_apCourseNotes, m_asCourseModifiers, GAMESTATE->GetCurrentStyleDef()->m_NotesType, false ); - - int iTotalMeter = 0; - int iTotalPossibleDancePoints = 0; - for( unsigned i=0; iGetMeter(); - m_apCourseNotes[i]->GetNoteData( ¬edata ); - iTotalPossibleDancePoints += m_pScoreKeeper[GAMESTATE->m_MasterPlayerNumber]->GetPossibleDancePoints( ¬edata ); - } - - GAMESTATE->m_CurStageStats.pSong = NULL; - for( int p=0; pIsPlayerEnabled(p) ) - continue; // skip - GAMESTATE->m_CurStageStats.iMeter[p] = iTotalMeter; - GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] = iTotalPossibleDancePoints; - } - } - break; - default: - ASSERT(0); - } - m_bChangedOffsetOrBPM = GAMESTATE->m_SongOptions.m_bAutoSync; @@ -529,26 +507,10 @@ ScreenGameplay::~ScreenGameplay() bool ScreenGameplay::IsLastSong() { - switch( GAMESTATE->m_PlayMode ) - { - case PLAY_MODE_ARCADE: - case PLAY_MODE_BATTLE: - return true; - case PLAY_MODE_NONSTOP: - case PLAY_MODE_ONI: - case PLAY_MODE_ENDLESS: - { - Course* pCourse = GAMESTATE->m_pCurCourse; - if( pCourse->m_bRepeat ) - return false; - else - return GAMESTATE->GetCourseSongIndex()+1 == (int)m_apCourseSongs.size(); // GetCourseSongIndex() is 0-based but size() is not - } - break; - default: - ASSERT(0); - return true; - } + if( GAMESTATE->m_pCurCourse && GAMESTATE->m_pCurCourse->m_bRepeat ) + return false; + + return GAMESTATE->GetCourseSongIndex()+1 == (int)m_apSongsQueue.size(); // GetCourseSongIndex() is 0-based but size() is not } void ScreenGameplay::LoadNextSong() @@ -559,39 +521,15 @@ void ScreenGameplay::LoadNextSong() if( GAMESTATE->IsPlayerEnabled(p) ) GAMESTATE->m_CurStageStats.iSongsPlayed[p]++; - switch( GAMESTATE->m_PlayMode ) - { - case PLAY_MODE_ARCADE: - case PLAY_MODE_BATTLE: - break; - case PLAY_MODE_NONSTOP: - case PLAY_MODE_ONI: - case PLAY_MODE_ENDLESS: - { - for( p=0; pm_CurStageStats.iSongsPlayed[p]) ); + for( p=0; pm_CurStageStats.iSongsPlayed[p]) ); - int iPlaySongIndex = GAMESTATE->GetCourseSongIndex(); - iPlaySongIndex %= m_apCourseSongs.size(); - GAMESTATE->m_pCurSong = m_apCourseSongs[iPlaySongIndex]; + int iPlaySongIndex = GAMESTATE->GetCourseSongIndex(); + iPlaySongIndex %= m_apSongsQueue.size(); + GAMESTATE->m_pCurSong = m_apSongsQueue[iPlaySongIndex]; - // Restore the player's originally selected options. - GAMESTATE->RestoreSelectedOptions(); - - for( p=0; pm_pCurNotes[p] = m_apCourseNotes[iPlaySongIndex]; - - // Put courses options into effect. - GAMESTATE->m_PlayerOptions[p].FromString( m_asCourseModifiers[iPlaySongIndex] ); - GAMESTATE->m_SongOptions.FromString( m_asCourseModifiers[iPlaySongIndex] ); - } - } - break; - default: - ASSERT(0); - break; - } + // Restore the player's originally selected options. + GAMESTATE->RestoreSelectedOptions(); m_textSongOptions.SetText( GAMESTATE->m_SongOptions.GetString() ); @@ -600,6 +538,13 @@ void ScreenGameplay::LoadNextSong() if( !GAMESTATE->IsPlayerEnabled(p) ) continue; + GAMESTATE->m_pCurNotes[p] = m_apNotesQueue[p][iPlaySongIndex]; + m_pScoreKeeper[p]->OnNextSong( GAMESTATE->GetCourseSongIndex(), GAMESTATE->m_pCurNotes[p] ); + + // Put courses options into effect. + GAMESTATE->m_PlayerOptions[p].FromString( m_asModifiersQueue[p][iPlaySongIndex] ); + GAMESTATE->m_SongOptions.FromString( m_asModifiersQueue[p][iPlaySongIndex] ); + m_textPlayerOptions[p].SetText( GAMESTATE->m_PlayerOptions[p].GetString() ); // reset oni game over graphic @@ -1160,8 +1105,8 @@ void SaveChanges() case PLAY_MODE_ENDLESS: { // FIXME - //for( int i=0; iSave(); + //for( int i=0; iSave(); } break; default: @@ -1184,9 +1129,9 @@ void DontSaveChanges() case PLAY_MODE_ENDLESS: { // FIXME -// for( unsigned i=0; iGetCacheFilePath(), *pSong ); // } } diff --git a/stepmania/src/ScreenGameplay.h b/stepmania/src/ScreenGameplay.h index 7f14b401c7..80b1a805c0 100644 --- a/stepmania/src/ScreenGameplay.h +++ b/stepmania/src/ScreenGameplay.h @@ -84,9 +84,9 @@ protected: STATE_OUTRO, // not allowed to press Back NUM_DANCING_STATES } m_DancingState; - vector m_apCourseSongs; // used only in a GameModes with courses - vector m_apCourseNotes; // used only in a GameModes with courses - CStringArray m_asCourseModifiers; // used only in a GameModes with courses + vector m_apSongsQueue; // size may be >1 if playing a course + vector m_apNotesQueue[NUM_PLAYERS]; // size may be >1 if playing a course + CStringArray m_asModifiersQueue[NUM_PLAYERS];// size may be >1 if playing a course bool m_bChangedOffsetOrBPM; float m_fTimeLeftBeforeDancingComment; // this counter is only running while STATE_DANCING diff --git a/stepmania/src/song.h b/stepmania/src/song.h index 93fca13971..bb5fe80bd6 100644 --- a/stepmania/src/song.h +++ b/stepmania/src/song.h @@ -14,7 +14,7 @@ #include "PlayerNumber.h" #include "GameConstantsAndTypes.h" #include "Grade.h" -struct Notes; +class Notes; class StyleDef; class NotesLoader; class LyricsLoader;