Change Nonstop scoring to the DDREX way

Clean up ScreenGameplay by having a Song and Notes Queue (rather than different logic based on the PlayMode)
This commit is contained in:
Chris Danford
2003-03-26 23:08:05 +00:00
parent b1fa4fc1c6
commit 189b37b517
16 changed files with 222 additions and 172 deletions
@@ -1 +1 @@
ScreenEvaluation extra1.mp3
ScreenEvaluation try extra1.mp3
+1
View File
@@ -791,6 +791,7 @@ GradeP1X=82
GradeP2X=118
[MusicWheel]
NumWheelItems=13
FadeSeconds=1
SwitchSeconds=0.10
RouletteSwitchSeconds=0.05
+1 -1
View File
@@ -17,7 +17,7 @@
struct PlayerOptions;
struct SongOptions;
class Song;
struct Notes;
class Notes;
class Course
{
+1 -1
View File
@@ -20,7 +20,7 @@
#include "CourseEntryDisplay.h"
class Course;
class Song;
struct Notes;
class Notes;
const int MAX_VISIBLE_CONTENTS = 5;
+1 -1
View File
@@ -19,7 +19,7 @@
#include "GameConstantsAndTypes.h"
class Course;
class Song;
struct Notes;
class Notes;
class CourseEntryDisplay : public ActorFrame
+1 -1
View File
@@ -13,7 +13,7 @@
#include "Sprite.h"
#include "PlayerNumber.h"
struct Notes;
class Notes;
class DifficultyIcon : public Sprite
+1 -1
View File
@@ -12,7 +12,7 @@
*/
#include "BitmapText.h"
struct Notes;
class Notes;
class DifficultyMeter : public BitmapText
+5 -2
View File
@@ -314,6 +314,7 @@ void GameState::GetFinalEvalStatsAndSongs( StageStats& statsOut, vector<Song*>&
}
}
/* 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; p<NUM_PLAYERS; p++ )
GAMESTATE->m_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;
}
+2 -1
View File
@@ -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();
+1 -1
View File
@@ -18,7 +18,7 @@
#include "Grade.h"
class NoteData;
struct Notes
class Notes
{
public:
Notes();
+4 -1
View File
@@ -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<Notes*>& 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;
+143 -48
View File
@@ -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<Notes*>& apNotes, PlayerNumber pn_ ):
ScoreKeeper(apNotes, pn_)
{
if( notes )
//
// Fill in m_CurStageStats, calculate multiplier
//
NoteData notedata;
switch( GAMESTATE->m_PlayMode )
{
NoteData noteData;
notes->GetNoteData( &noteData );
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( &notedata );
GAMESTATE->m_CurStageStats.iPossibleDancePoints[pn_] = this->GetPossibleDancePoints( &notedata );
}
break;
case PLAY_MODE_NONSTOP:
case PLAY_MODE_ONI:
case PLAY_MODE_ENDLESS:
{
int iTotalPossibleDancePoints = 0;
for( unsigned i=0; i<apNotes.size(); i++ )
{
apNotes[i]->GetNoteData( &notedata );
iTotalPossibleDancePoints += this->GetPossibleDancePoints( &notedata );
}
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( &noteData );
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
+6 -4
View File
@@ -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<Notes*>& 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 );
+50 -105
View File
@@ -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; p<NUM_PLAYERS; p++ )
{
m_apNotesQueue[p] = m_apNotesQueue[0];
m_asModifiersQueue[p] = m_asModifiersQueue[0];
}
}
else
{
m_apSongsQueue.push_back( GAMESTATE->m_pCurSong );
for( int p=0; p<NUM_PLAYERS; p++ )
{
m_apNotesQueue[p].push_back( GAMESTATE->m_pCurNotes[p] );
m_asModifiersQueue[p].push_back( "" );
}
}
//
// Init ScoreKeepers
//
int p;
for( p=0; p<NUM_PLAYERS; p++ )
{
if( !GAMESTATE->IsPlayerEnabled(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; p<NUM_PLAYERS; p++ )
{
if( !GAMESTATE->IsPlayerEnabled(p) )
continue; // skip
GAMESTATE->m_CurStageStats.iMeter[p] = GAMESTATE->m_pCurNotes[p]->GetMeter();
GAMESTATE->m_pCurNotes[p]->GetNoteData( &notedata );
// TODO: Make this more elegant
GAMESTATE->m_CurStageStats.iPossibleDancePoints[p] = m_pScoreKeeper[p]->GetPossibleDancePoints( &notedata );
}
}
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; i<m_apCourseNotes.size(); i++ )
{
iTotalMeter += m_apCourseNotes[i]->GetMeter();
m_apCourseNotes[i]->GetNoteData( &notedata );
iTotalPossibleDancePoints += m_pScoreKeeper[GAMESTATE->m_MasterPlayerNumber]->GetPossibleDancePoints( &notedata );
}
GAMESTATE->m_CurStageStats.pSong = NULL;
for( int p=0; p<NUM_PLAYERS; p++ )
{
if( !GAMESTATE->IsPlayerEnabled(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; p<NUM_PLAYERS; p++ )
m_textCourseSongNumber[p].SetText( ssprintf("%d", GAMESTATE->m_CurStageStats.iSongsPlayed[p]) );
for( p=0; p<NUM_PLAYERS; p++ )
m_textCourseSongNumber[p].SetText( ssprintf("%d", GAMESTATE->m_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; p<NUM_PLAYERS; p++ )
{
GAMESTATE->m_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; i<m_apCourseSongs.size(); i++ )
// m_apCourseSongs[i]->Save();
//for( int i=0; i<m_apSongsQueue.size(); i++ )
// m_apSongsQueue[i]->Save();
}
break;
default:
@@ -1184,9 +1129,9 @@ void DontSaveChanges()
case PLAY_MODE_ENDLESS:
{
// FIXME
// for( unsigned i=0; i<m_apCourseSongs.size(); i++ )
// for( unsigned i=0; i<m_apSongsQueue.size(); i++ )
// {
// Song* pSong = m_apCourseSongs[i];
// Song* pSong = m_apSongsQueue[i];
// ld.LoadFromSMFile( pSong->GetCacheFilePath(), *pSong );
// }
}
+3 -3
View File
@@ -84,9 +84,9 @@ protected:
STATE_OUTRO, // not allowed to press Back
NUM_DANCING_STATES
} m_DancingState;
vector<Song*> m_apCourseSongs; // used only in a GameModes with courses
vector<Notes*> m_apCourseNotes; // used only in a GameModes with courses
CStringArray m_asCourseModifiers; // used only in a GameModes with courses
vector<Song*> m_apSongsQueue; // size may be >1 if playing a course
vector<Notes*> 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
+1 -1
View File
@@ -14,7 +14,7 @@
#include "PlayerNumber.h"
#include "GameConstantsAndTypes.h"
#include "Grade.h"
struct Notes;
class Notes;
class StyleDef;
class NotesLoader;
class LyricsLoader;