From a1458b2095d3af2a63dbf634114481b8eef58379 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Mon, 22 Dec 2003 01:55:03 +0000 Subject: [PATCH] simplify and fix up combo/life stats --- stepmania/src/ComboGraph.cpp | 15 ++- stepmania/src/GraphDisplay.h | 2 - stepmania/src/Player.cpp | 5 +- stepmania/src/ScreenEvaluation.cpp | 19 +++- stepmania/src/ScreenGameplay.cpp | 3 - stepmania/src/StageStats.cpp | 165 ++++++++++++++++++++--------- stepmania/src/StageStats.h | 10 +- 7 files changed, 145 insertions(+), 74 deletions(-) diff --git a/stepmania/src/ComboGraph.cpp b/stepmania/src/ComboGraph.cpp index 8880bb415a..2ef6a284fc 100644 --- a/stepmania/src/ComboGraph.cpp +++ b/stepmania/src/ComboGraph.cpp @@ -29,12 +29,14 @@ void ComboGraph::Load( CString Path, const StageStats &s, PlayerNumber pn ) const CString path = ssprintf( "%s %s", Path.c_str(), IsMax? "max":"normal" ); sprite->Load( THEME->GetPathToG(path) ); - sprite->SetCropLeft ( SCALE( combo.size, 0.0f, 1.0f, 0.5f, 0.0f ) ); - sprite->SetCropRight( SCALE( combo.size, 0.0f, 1.0f, 0.5f, 0.0f ) ); + const float start = SCALE( combo.start, s.fFirstPos[pn], s.fLastPos[pn], 0.0f, 1.0f ); + const float size = SCALE( combo.size, 0, s.fLastPos[pn]-s.fFirstPos[pn], 0.0f, 1.0f ); + sprite->SetCropLeft ( SCALE( size, 0.0f, 1.0f, 0.5f, 0.0f ) ); + sprite->SetCropRight( SCALE( size, 0.0f, 1.0f, 0.5f, 0.0f ) ); sprite->BeginTweening( .5f ); - sprite->SetCropLeft( combo.start ); - sprite->SetCropRight( 1 - (combo.size + combo.start) ); + sprite->SetCropLeft( start ); + sprite->SetCropRight( 1 - (size + start) ); if( width < 0 ) width = sprite->GetUnzoomedWidth(); @@ -56,7 +58,10 @@ void ComboGraph::Load( CString Path, const StageStats &s, PlayerNumber pn ) BitmapText *text = new BitmapText; text->LoadFromFont( THEME->GetPathToF(Path) ); - const float CenterPercent = combo.start + combo.size/2; + const float start = SCALE( combo.start, s.fFirstPos[pn], s.fLastPos[pn], 0.0f, 1.0f ); + const float size = SCALE( combo.size, 0, s.fLastPos[pn]-s.fFirstPos[pn], 0.0f, 1.0f ); + + const float CenterPercent = start + size/2; const float CenterXPos = SCALE( CenterPercent, 0.0f, 1.0f, -width/2.0f, width/2.0f ); text->SetX( CenterXPos ); diff --git a/stepmania/src/GraphDisplay.h b/stepmania/src/GraphDisplay.h index 6c23602e42..b378418175 100644 --- a/stepmania/src/GraphDisplay.h +++ b/stepmania/src/GraphDisplay.h @@ -15,8 +15,6 @@ public: void Unload(); void LoadFromStageStats( const StageStats &s, PlayerNumber pn ); - void SetValues( const float *values, int cnt ); - void SetValue( float value, int cnt ) { SetValues( &value, 1 ); } void Update( float fDeltaTime ); void DrawPrimitives(); diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index 23413a8921..e988454f35 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -1142,8 +1142,7 @@ void PlayerMinus::HandleTapRowScore( unsigned row ) /* Use the real current beat, not the beat we've been passed. That's because we * want to record the current life/combo to the current time; eg. if it's a MISS, * the beat we're registering is in the past, but the life is changing now. */ - const float beat = GAMESTATE->m_fSongBeat; - GAMESTATE->m_CurStageStats.UpdateComboList( m_PlayerNumber, GAMESTATE->GetSongPercent(beat) ); + GAMESTATE->m_CurStageStats.UpdateComboList( m_PlayerNumber, GAMESTATE->m_fSongBeat ); float life = -1; if( m_pLifeMeter ) @@ -1155,7 +1154,7 @@ void PlayerMinus::HandleTapRowScore( unsigned row ) life = 1.0f - life; } if( life != -1 ) - GAMESTATE->m_CurStageStats.SetLifeRecord( m_PlayerNumber, life, GAMESTATE->GetSongPercent(beat) ); + GAMESTATE->m_CurStageStats.SetLifeRecord( m_PlayerNumber, life, GAMESTATE->m_fSongBeat ); if (m_pScoreDisplay) m_pScoreDisplay->SetScore(GAMESTATE->m_CurStageStats.iScore[m_PlayerNumber]); diff --git a/stepmania/src/ScreenEvaluation.cpp b/stepmania/src/ScreenEvaluation.cpp index 932b538f2f..c3cec2da74 100644 --- a/stepmania/src/ScreenEvaluation.cpp +++ b/stepmania/src/ScreenEvaluation.cpp @@ -95,6 +95,8 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) { GAMESTATE->m_PlayMode = PLAY_MODE_RAVE; GAMESTATE->m_CurStyle = STYLE_DANCE_VERSUS; + GAMESTATE->m_bSideIsJoined[PLAYER_1] = true; + GAMESTATE->m_bSideIsJoined[PLAYER_2] = true; GAMESTATE->m_MasterPlayerNumber = PLAYER_1; GAMESTATE->m_pCurSong = SONGMAN->GetAllSongs()[0]; // GAMESTATE->m_pCurCourse = SONGMAN->m_pCourses[0]; @@ -103,12 +105,22 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) GAMESTATE->m_PlayerOptions[PLAYER_1].m_fScrollSpeed = 2; GAMESTATE->m_PlayerOptions[PLAYER_2].m_fScrollSpeed = 2; GAMESTATE->m_iCurrentStageIndex = 2; - for( float f = 0; f < 1.0f; f += .005f ) + + for( float f = 0; f < 100.0f; f += 1.0f ) { - float fP1 = fmodf(f*4+.3f,1); + float fP1 = fmodf(f/100*4+.3f,1); GAMESTATE->m_CurStageStats.SetLifeRecord( PLAYER_1, fP1, f ); GAMESTATE->m_CurStageStats.SetLifeRecord( PLAYER_2, 1-fP1, f ); } + + GAMESTATE->m_CurStageStats.iCurCombo[PLAYER_1] = 0; + GAMESTATE->m_CurStageStats.UpdateComboList( PLAYER_1, 0 ); + GAMESTATE->m_CurStageStats.iCurCombo[PLAYER_1] = 1; + GAMESTATE->m_CurStageStats.UpdateComboList( PLAYER_1, 1 ); + GAMESTATE->m_CurStageStats.iCurCombo[PLAYER_1] = 50; + GAMESTATE->m_CurStageStats.UpdateComboList( PLAYER_1, 25 ); + GAMESTATE->m_CurStageStats.iCurCombo[PLAYER_1] = 250; + GAMESTATE->m_CurStageStats.UpdateComboList( PLAYER_1, 100 ); } LOG->Trace( "ScreenEvaluation::ScreenEvaluation()" ); @@ -146,13 +158,11 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) break; case stage: case course: - LOG->Trace("We made it to stage"); stageStats = GAMESTATE->m_CurStageStats; break; default: ASSERT(0); } - stageStats.Finish(); LOG->Trace( "total error: %i, %i", stageStats.iTotalError[0], stageStats.iTotalError[1] ); @@ -745,6 +755,7 @@ ScreenEvaluation::ScreenEvaluation( CString sClassName ) : Screen(sClassName) if( SHOW_FULL_COMBO && stageStats.FullCombo( (PlayerNumber) p ) ) { + LOG->Trace( "Full combo for P%i", p+1 ); m_FullCombo[p].Load( THEME->GetPathToG(ssprintf("ScreenEvaluation full combo P%i",p+1)) ); m_FullCombo[p]->SetName( ssprintf("FullComboP%d",p+1) ); SET_XY_AND_ON_COMMAND( m_FullCombo[p] ); diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 40111355f2..155f20679c 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -1670,9 +1670,6 @@ void ScreenGameplay::ShowSavePrompt( ScreenMessage SM_SendWhenDone ) void ScreenGameplay::SongFinished() { - /* Need to Finish before calling GetActualRadarValue, for GetMaxCombo. */ - GAMESTATE->m_CurStageStats.Finish(); - // save any statistics int p; for( p=0; p::const_iterator it; + for( it = other.fLifeRecord[p].begin(); it != other.fLifeRecord[p].end(); ++it ) + { + const float pos = it->first; + const float life = it->second; + fLifeRecord[p][fOtherFirst+pos] = life; + } + + unsigned i; + for( i=0; i 0.001 ) + continue; + + /* These are really the same combo. */ + prevcombo.size += combo.size; + prevcombo.cnt += combo.cnt; + ComboList[p].erase( ComboList[p].begin()+i ); + --i; + } + + fLastPos[p] = fOtherLast; } } @@ -178,26 +235,68 @@ float StageStats::GetPercentDancePoints( PlayerNumber pn ) const void StageStats::SetLifeRecord( PlayerNumber pn, float life, float pos ) { - pos = clamp( pos, 0, 1 ); + if( pos < 0 ) + return; - int offset = (int) roundf( pos * LIFE_RECORD_RESOLUTION ); - for( int i = 0; i <= offset; ++i ) - if( fLifeRecord[pn][i] < 0 ) - fLifeRecord[pn][i] = life; + fFirstPos[pn] = min( pos, fFirstPos[pn] ); + fLastPos[pn] = max( pos, fLastPos[pn] ); + + if( !fLifeRecord[pn].empty() ) + { + const float old = GetLifeRecordAt( pn, pos ); + if( fabsf(old-pos) < 0.001f ) + return; /* no change */ + } + + fLifeRecord[pn][pos] = life; } +float StageStats::GetLifeRecordAt( PlayerNumber pn, float pos ) const +{ + /* Find the first element whose key is not less than k. */ + map::const_iterator it = fLifeRecord[pn].lower_bound( pos ); + + /* Find the first element whose key is less than k. */ + if( it != fLifeRecord[pn].begin() ) + --it; + + return it->second; + +} + +float StageStats::GetLifeRecordLerpAt( PlayerNumber pn, float pos ) const +{ + /* Find the first element whose key is not less than k. */ + map::const_iterator later = fLifeRecord[pn].lower_bound( pos ); + + /* Find the first element whose key is less than k. */ + map::const_iterator earlier = later; + if( earlier != fLifeRecord[pn].begin() ) + --earlier; + + if( earlier->first == later->first ) + return earlier->second; + + /* earlier <= pos <= later */ + const float f = SCALE( pos, earlier->first, later->first, 1, 0 ); + return earlier->second * f + later->second * (1-f); +} + + void StageStats::GetLifeRecord( PlayerNumber pn, float *life, int nout ) const { for( int i = 0; i < nout; ++i ) { - int from = i * (LIFE_RECORD_RESOLUTION-1) / nout; - life[i] = fLifeRecord[pn][from]; + float from = SCALE( i, 0, (float)nout, fFirstPos[pn], fLastPos[pn] ); + LOG->Trace("get %i from %f", i, from); + life[i] = GetLifeRecordLerpAt( (PlayerNumber)pn, from ); } } void StageStats::UpdateComboList( PlayerNumber pn, float pos ) { - pos = clamp( pos, 0, 1 ); + if( pos < 0 ) + return; fFirstPos[pn] = min( pos, fFirstPos[pn] ); fLastPos[pn] = max( pos, fLastPos[pn] ); @@ -245,44 +344,6 @@ StageStats::Combo_t StageStats::GetMaxCombo( PlayerNumber pn ) const return ComboList[pn][m]; } -/* SetLifeRecord and UpdateComboList take a percentage (0..1) in pos, but the values - * will actually be somewhat off as they're based on Song::m_fFirstBeat and m_fLastBeat, - * which are per-song, not per-Steps. Scale and shift our records so that they're - * really 0..1. */ -void StageStats::Finish() -{ - for( int pn = 0; pn < NUM_PLAYERS; ++pn ) - { - if( ComboList[pn].size() == 0 ) - continue; - - const float First = fFirstPos[pn]; - const float Last = fLastPos[pn]; - - if( fabsf(First-Last) < 0.0001f ) - continue; - - unsigned i; - for( i = 0; i < ComboList[pn].size(); ++i ) - { - ComboList[pn][i].start = SCALE( ComboList[pn][i].start, First, Last, 0.0f, 1.0f ); - ComboList[pn][i].size /= Last - First; - } - - float NewLifeRecord[LIFE_RECORD_RESOLUTION]; - for( i = 0; i < LIFE_RECORD_RESOLUTION; ++i ) - { - int from = (int) roundf( SCALE( i, 0.0f, 1.0f, First, Last ) ); - from = clamp( from, 0, LIFE_RECORD_RESOLUTION-1 ); - NewLifeRecord[i] = fLifeRecord[pn][from]; - } - memcpy( fLifeRecord[pn], NewLifeRecord, sizeof(fLifeRecord[pn]) ); - - fFirstPos[pn] = 0; - fLastPos[pn] = 1; - } -} - bool StageStats::FullCombo( PlayerNumber pn ) const { if( ComboList[pn].size() != 1 ) diff --git a/stepmania/src/StageStats.h b/stepmania/src/StageStats.h index 9d213518fd..539f6024a0 100644 --- a/stepmania/src/StageStats.h +++ b/stepmania/src/StageStats.h @@ -16,6 +16,7 @@ #include "GameConstantsAndTypes.h" #include "Grade.h" #include "Style.h" +#include class Song; class Steps; @@ -63,10 +64,11 @@ struct StageStats int iSongsPlayed[NUM_PLAYERS]; int iTotalError[NUM_PLAYERS]; - enum { LIFE_RECORD_RESOLUTION=1000 }; - float fLifeRecord[NUM_PLAYERS][LIFE_RECORD_RESOLUTION]; + map fLifeRecord[NUM_PLAYERS]; void SetLifeRecord( PlayerNumber pn, float life, float pos ); void GetLifeRecord( PlayerNumber pn, float *life, int nout ) const; + float GetLifeRecordAt( PlayerNumber pn, float pos ) const; + float GetLifeRecordLerpAt( PlayerNumber pn, float pos ) const; /* pos,combo */ struct Combo_t @@ -84,14 +86,12 @@ struct StageStats Combo_t(): start(0), size(0), cnt(0), rollover(0) { } bool IsZero() const { return start < 0; } }; + vector ComboList[NUM_PLAYERS]; float fFirstPos[NUM_PLAYERS], fLastPos[NUM_PLAYERS]; bool FullCombo( PlayerNumber pn ) const; void UpdateComboList( PlayerNumber pn, float pos ); Combo_t GetMaxCombo( PlayerNumber pn ) const; - - void Finish(); - vector ComboList[NUM_PLAYERS]; };