diff --git a/stepmania/src/GameState.cpp b/stepmania/src/GameState.cpp index fe1252132c..b80e8e2924 100644 --- a/stepmania/src/GameState.cpp +++ b/stepmania/src/GameState.cpp @@ -795,6 +795,9 @@ void GameState::ResetStageStatistics() FOREACH_PlayerNumber( p ) m_pPlayerState[p]->RemoveAllInventory(); m_fOpponentHealthPercent = 1; + m_fHasteRate = 0; + m_fLastHasteUpdateMusicSeconds = 0; + m_fAccumulatedHasteSeconds = 0; m_fTugLifePercentP1 = 0.5f; FOREACH_PlayerNumber( p ) { diff --git a/stepmania/src/GameState.h b/stepmania/src/GameState.h index 3fe1e6b281..801fc5cb42 100644 --- a/stepmania/src/GameState.h +++ b/stepmania/src/GameState.h @@ -193,6 +193,13 @@ public: bool AllAreInDangerOrWorse() const; bool OneIsHot() const; + // + // Haste + // + float m_fHasteRate; // [-1,+1]; 0 = normal speed + float m_fLastHasteUpdateMusicSeconds; + float m_fAccumulatedHasteSeconds; + // used in PLAY_MODE_BATTLE float m_fOpponentHealthPercent; diff --git a/stepmania/src/Player.cpp b/stepmania/src/Player.cpp index 415a3d6d34..b42b08daaf 100644 --- a/stepmania/src/Player.cpp +++ b/stepmania/src/Player.cpp @@ -1091,6 +1091,19 @@ void Player::ChangeLife( TapNoteScore tns ) m_pCombinedLifeMeter->ChangeLife( pn, tns ); ChangeLifeRecord(); + + switch( tns ) + { + case TNS_None: + case TNS_Miss: + case TNS_CheckpointMiss: + case TNS_HitMine: + ++m_pPlayerState->m_iTapsMissedSinceLastHasteUpdate; + break; + default: + ++m_pPlayerState->m_iTapsHitSinceLastHasteUpdate; + break; + } } void Player::ChangeLife( HoldNoteScore hns, TapNoteScore tns ) diff --git a/stepmania/src/PlayerState.cpp b/stepmania/src/PlayerState.cpp index 729e567932..afc9e421e2 100644 --- a/stepmania/src/PlayerState.cpp +++ b/stepmania/src/PlayerState.cpp @@ -33,6 +33,9 @@ void PlayerState::Reset() m_ActiveAttacks.clear(); m_ModsToApply.clear(); + m_iTapsHitSinceLastHasteUpdate = 0; + m_iTapsMissedSinceLastHasteUpdate = 0; + m_fSuperMeter = 0; // between 0 and NUM_ATTACK_LEVELS m_fSuperMeterGrowthScale = 1; diff --git a/stepmania/src/PlayerState.h b/stepmania/src/PlayerState.h index 24875248c4..ffa84ad3d5 100644 --- a/stepmania/src/PlayerState.h +++ b/stepmania/src/PlayerState.h @@ -68,6 +68,12 @@ public: AttackArray m_ActiveAttacks; vector m_ModsToApply; + // + // Haste + // + int m_iTapsHitSinceLastHasteUpdate; + int m_iTapsMissedSinceLastHasteUpdate; + // // Used in Rave // diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 8bc6a3418b..f010859056 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -1613,7 +1613,7 @@ void ScreenGameplay::Update( float fDeltaTime ) if( GAMESTATE->m_SongOptions.GetCurrent().m_fHaste != 0.0f ) { float fHasteRate = GetHasteRate(); - STATSMAN->m_CurStageStats.m_fAccumulatedHaste += (fUnscaledDeltaTime * fHasteRate) - fUnscaledDeltaTime; + GAMESTATE->m_fAccumulatedHasteSeconds += (fUnscaledDeltaTime * fHasteRate) - fUnscaledDeltaTime; } } @@ -1775,33 +1775,57 @@ void ScreenGameplay::Update( float fDeltaTime ) float ScreenGameplay::GetHasteRate() { - float fLife = 0; + if( GAMESTATE->m_fMusicSeconds < GAMESTATE->m_fLastHasteUpdateMusicSeconds || // new song + GAMESTATE->m_fMusicSeconds > GAMESTATE->m_fLastHasteUpdateMusicSeconds + 4 ) + { + bool bAnyPlayerHitAllNotes = false; + FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) + { + if( !GAMESTATE->IsHumanPlayer(pi->m_pn) ) + continue; + + PlayerState *pPS = pi->GetPlayerState(); + if( pPS->m_iTapsHitSinceLastHasteUpdate > 0 && + pPS->m_iTapsMissedSinceLastHasteUpdate == 0 ) + bAnyPlayerHitAllNotes = true; + + pPS->m_iTapsHitSinceLastHasteUpdate = 0; + pPS->m_iTapsMissedSinceLastHasteUpdate = 0; + } + + if( bAnyPlayerHitAllNotes ) + GAMESTATE->m_fHasteRate += 0.05f; + CLAMP( GAMESTATE->m_fHasteRate, -1.0f, +2.0f ); + + GAMESTATE->m_fLastHasteUpdateMusicSeconds = GAMESTATE->m_fMusicSeconds; + } + + /* If the life meter is less than half full, push the haste rate down to let + * the player use his accumulated haste time. */ + float fMaxLife = 0; FOREACH_EnabledPlayerInfo( m_vPlayerInfo, pi ) { if( !GAMESTATE->IsHumanPlayer(pi->m_pn) ) continue; - fLife = max( fLife, pi->m_pLifeMeter->GetLife() ); + fMaxLife = max( fMaxLife, pi->m_pLifeMeter->GetLife() ); } + if( fMaxLife < 0.5f ) + GAMESTATE->m_fHasteRate = SCALE( fMaxLife, 0.0f, 0.5f, -1.0f, 0.0f ); - /* Scale the music nonlinearly. Stick at 1x up to 0.5, so we start at 1x - * if the life meter defaults to 0.5. Increase gradually up to 0.9. - * Accelerate sharply above 0.9. */ float fSpeed = 1.0f; - if( fLife < 0.50f ) - fSpeed = SCALE( fLife, 0.0f, 0.50f, 0.5f, 1.0f ); - else if( fLife > 0.5f && fLife < 0.9f ) - fSpeed = SCALE( fLife, 0.5f, 0.9f, 1.0f, 1.25f ); - else if( fLife >= 0.9f ) - fSpeed = SCALE( fLife, 0.9f, 1.0f, 1.25f, 2.0f ); + if( GAMESTATE->m_fHasteRate < 0 ) + fSpeed = SCALE( GAMESTATE->m_fHasteRate, -1.0f, 0.0f, 0.5f, 1.0f ); + else + fSpeed = SCALE( GAMESTATE->m_fHasteRate, 0.0f, 1.0f, 1.0f, 1.6f ); fSpeed *= GAMESTATE->m_SongOptions.GetCurrent().m_fHaste; - if( STATSMAN->m_CurStageStats.m_fAccumulatedHaste <= 1 ) + if( GAMESTATE->m_fAccumulatedHasteSeconds <= 1 ) { /* Only allow slowing down the song while the players have accumulated * haste. This prevents dragging on the song by keeping the life meter * nearly empty. */ float fClamped = max( 1.0f, fSpeed ); - fSpeed = lerp( STATSMAN->m_CurStageStats.m_fAccumulatedHaste, fClamped, fSpeed ); + fSpeed = lerp( GAMESTATE->m_fAccumulatedHasteSeconds, fClamped, fSpeed ); } return fSpeed; } diff --git a/stepmania/src/StageStats.cpp b/stepmania/src/StageStats.cpp index a9f93abfc5..1de955b62d 100644 --- a/stepmania/src/StageStats.cpp +++ b/stepmania/src/StageStats.cpp @@ -29,7 +29,6 @@ StageStats::StageStats() m_fGameplaySeconds = 0; m_fStepsSeconds = 0; m_fMusicRate = 1; - m_fAccumulatedHaste = 0; } void StageStats::Init() diff --git a/stepmania/src/StageStats.h b/stepmania/src/StageStats.h index acccda8e80..eba31b8a27 100644 --- a/stepmania/src/StageStats.h +++ b/stepmania/src/StageStats.h @@ -42,8 +42,6 @@ public: float m_fStepsSeconds; // this is <= fGameplaySeconds unless the song has steps past the end float m_fMusicRate; - float m_fAccumulatedHaste; - // Total number of seconds between first beat and last beat for every song. float GetTotalPossibleStepsSeconds() const;