From 43ed6770457e3683e6ab858bf292ed81b5ed1c94 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Mon, 3 Nov 2003 19:42:06 +0000 Subject: [PATCH] Fix PlayerOptions::GetString percentage rounding. Merge ScreenGameplay::SM_NotesEnded code paths. Replace FAIL_PASSMARK with PlayerOptions FailMark: It's simpler: only one test (in SM_NotesEnded). It can be 1: changed easily: say "80% FailMark" for BM; 2: set per-player, if some mode wants an easier setting for easier difficulties; 3: changed during courses (if you really wanted to). It coexists with fail types. In some BeatMania games, you have to be over 80% at the end to pass, but you also fail immediately if the bar empties. One thing to be careful of: since it coexists with fail types, setting FailOff doesn't disable FailMark failing. If you want that, too, use "No FailMark". The danger background works consistently. (If FailOff is set, the behavior is what it was--no danger at all.) --- stepmania/src/LifeMeterBar.cpp | 4 +- stepmania/src/PlayerOptions.cpp | 9 +- stepmania/src/PlayerOptions.h | 4 + stepmania/src/ScreenGameplay.cpp | 142 +++++++++++---------- stepmania/src/ScreenGameplay.h | 8 +- stepmania/src/ScreenOptionsMasterPrefs.cpp | 5 +- stepmania/src/SongOptions.cpp | 2 - stepmania/src/SongOptions.h | 2 +- 8 files changed, 94 insertions(+), 82 deletions(-) diff --git a/stepmania/src/LifeMeterBar.cpp b/stepmania/src/LifeMeterBar.cpp index a173e3b3c1..a2d51e9c94 100644 --- a/stepmania/src/LifeMeterBar.cpp +++ b/stepmania/src/LifeMeterBar.cpp @@ -359,8 +359,8 @@ void LifeMeterBar::ChangeLife( TapNoteScore score ) m_iComboToRegainLife = max( m_iComboToRegainLife, NewComboToRegainLife ); } - /* If we've already failed, there's no point in letting them fill up the bar again. Except for passmark mode */ - if( GAMESTATE->m_CurStageStats.bFailed[m_PlayerNumber] && GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_PASSMARK) + /* If we've already failed, there's no point in letting them fill up the bar again. */ + if( GAMESTATE->m_CurStageStats.bFailed[m_PlayerNumber] ) fDeltaLife = 0; switch( GAMESTATE->m_SongOptions.m_DrainType ) diff --git a/stepmania/src/PlayerOptions.cpp b/stepmania/src/PlayerOptions.cpp index a7b91a74ef..a59f7b8821 100644 --- a/stepmania/src/PlayerOptions.cpp +++ b/stepmania/src/PlayerOptions.cpp @@ -34,6 +34,7 @@ void PlayerOptions::Init() m_fBlind = 0; m_SpeedfBlind = 1.0f; m_fPerspectiveTilt = 0; m_SpeedfPerspectiveTilt = 1.0f; m_fSkew = 0; m_SpeedfSkew = 1.0f; + m_fPassmark = 0; m_SpeedfPassmark = 1.0f; m_Turn = TURN_NONE; m_Transform = TRANSFORM_NONE; m_bHoldNotes = true; @@ -62,6 +63,7 @@ void PlayerOptions::Approach( const PlayerOptions& other, float fDeltaSeconds ) APP( fBlind ); APP( fPerspectiveTilt ); APP( fSkew ); + APP( fPassmark ); } static CString AddPart( float level, CString name ) @@ -69,7 +71,7 @@ static CString AddPart( float level, CString name ) if( level == 0 ) return ""; - const CString LevelStr = (level == 1)? "": ssprintf( "%i%% ", int(level*100) ); + const CString LevelStr = (level == 1)? "": ssprintf( "%i%% ", (int) roundf(level*100) ); return LevelStr + name + ", "; } @@ -130,6 +132,8 @@ CString PlayerOptions::GetString() const sReturn += AddPart( m_fBlind, "Blind"); + sReturn += AddPart( m_fPassmark, "Passmark"); + switch( m_Turn ) { case TURN_NONE: break; @@ -187,6 +191,7 @@ void PlayerOptions::FromString( CString sOptions ) CStringArray asBits; split( sOptions, ",", asBits, true ); + LOG->Trace("parse %s", sOptions.c_str()); for( unsigned i=0; iTrace("'%s' %f %f", asParts[j].c_str(), level, speed); } sBit = asParts[asParts.size()-1]; @@ -282,6 +288,7 @@ void PlayerOptions::FromString( CString sOptions ) else if( sBit == "nofreeze" ) m_bHoldNotes = !on; else if( sBit == "dark" ) SET_FLOAT( fDark ) else if( sBit == "blind" ) SET_FLOAT( fBlind ) + else if( sBit == "passmark" ) SET_FLOAT( fPassmark ) else if( sBit == "timingassist")m_bTimingAssist = on; else if( sBit == "protiming") m_bProTiming = on; else if( sBit == "overhead" ) { m_fSkew = 0; m_fPerspectiveTilt = 0; m_SpeedfSkew = m_SpeedfPerspectiveTilt = speed; } diff --git a/stepmania/src/PlayerOptions.h b/stepmania/src/PlayerOptions.h index f7e7e887c3..5b633ba844 100644 --- a/stepmania/src/PlayerOptions.h +++ b/stepmania/src/PlayerOptions.h @@ -91,6 +91,10 @@ struct PlayerOptions float m_fPerspectiveTilt, m_SpeedfPerspectiveTilt; // -1 = near, 0 = overhead, +1 = space float m_fSkew, m_SpeedfSkew; // 0 = vanish point is in center of player, 1 = vanish point is in center of screen + /* If this is > 0, then the player must have life above this value at the end of + * the song to pass. This is independent of SongOptions::m_FailType. */ + float m_fPassmark, m_SpeedfPassmark; + Turn m_Turn; Transform m_Transform; bool m_bHoldNotes; diff --git a/stepmania/src/ScreenGameplay.cpp b/stepmania/src/ScreenGameplay.cpp index 81eb9a04ae..ebd9c1e9ab 100644 --- a/stepmania/src/ScreenGameplay.cpp +++ b/stepmania/src/ScreenGameplay.cpp @@ -911,7 +911,7 @@ float ScreenGameplay::StartPlayingSong(float MinTimeToNotes, float MinTimeToMusi return fFirstSecond - fStartSecond; } -bool ScreenGameplay::OneIsHot() +bool ScreenGameplay::OneIsHot() const { for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) @@ -921,7 +921,7 @@ bool ScreenGameplay::OneIsHot() return false; } -bool ScreenGameplay::AllAreInDanger() +bool ScreenGameplay::AllAreInDanger() const { for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) @@ -931,37 +931,18 @@ bool ScreenGameplay::AllAreInDanger() return true; } -bool ScreenGameplay::AllAreFailing() +bool ScreenGameplay::AllAreFailing() const { - - if( GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_PASSMARK ) - { - bool bFoundAPasser = true; // assume nobody passed until proven otherwise - - for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) - if( (m_pLifeMeter[p]->GetLife()) > 0.7f ) // 70 % is the pass mark - { - bFoundAPasser = false; - } - } - return bFoundAPasser; - } - else - { - for( int p=0; pIsPlayerEnabled(PlayerNumber(p)) ) if( (m_pLifeMeter[p] && !m_pLifeMeter[p]->IsFailing()) || (m_pCombinedLifeMeter && !m_pCombinedLifeMeter->IsFailing((PlayerNumber)p)) ) return false; - } return true; } -bool ScreenGameplay::AllFailedEarlier() +bool ScreenGameplay::AllFailedEarlier() const { for( int p=0; pIsPlayerEnabled(p) && !GAMESTATE->m_CurStageStats.bFailedEarlier[p] ) @@ -1101,7 +1082,7 @@ void ScreenGameplay::Update( float fDeltaTime ) // show it if everyone is already failing: it's already too late and it's // annoying for it to show for the entire duration of a song. // - if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF || GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_PASSMARK ) + if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF ) { if( AllAreInDanger() && !AllAreFailing() ) m_Background.TurnDangerOn(); @@ -1624,23 +1605,40 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) if( !GAMESTATE->IsPlayerEnabled(p) ) continue; + /* If either player's passmark is enabled, check it. */ + if( GAMESTATE->m_PlayerOptions[p].m_fPassmark > 0 && + m_pLifeMeter[p] && + m_pLifeMeter[p]->GetLife() < GAMESTATE->m_PlayerOptions[p].m_fPassmark ) + { + LOG->Trace("Player %i failed: life %f is under %f", + p+1, m_pLifeMeter[p]->GetLife(), GAMESTATE->m_PlayerOptions[p].m_fPassmark ); + GAMESTATE->m_CurStageStats.bFailed[p] = true; + } + if( !GAMESTATE->m_CurStageStats.bFailed[p] ) GAMESTATE->m_CurStageStats.iSongsPassed[p]++; } - - if( (GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_END_OF_SONG || GAMESTATE->m_SongOptions.m_FailType == SongOptions::FAIL_PASSMARK ) && AllAreFailing() ) + /* Mark failure. This was possibly already done by UpdateCheckFail, but + * not always, if m_bTwoPlayerRecovery is set. */ + if( GAMESTATE->m_SongOptions.m_FailType != SongOptions::FAIL_OFF ) { - if( m_DancingState == STATE_OUTRO ) // ScreenGameplay already ended - return; // ignore - m_DancingState = STATE_OUTRO; - - GAMESTATE->RemoveAllActiveAttacks(); - - this->PostScreenMessage( SM_BeginFailed, 0 ); + if( (m_pLifeMeter[p] && !m_pLifeMeter[p]->IsFailing()) || + (m_pCombinedLifeMeter && !m_pCombinedLifeMeter->IsFailing((PlayerNumber)p)) ) + GAMESTATE->m_CurStageStats.bFailed[p] = true; } - else if( !IsLastSong() ) + + /* If all players have *really* failed (bFailed, not the life meter or + * bFailedEarlier): */ + bool bAllReallyFailed = true; + for( p=0; pIsPlayerEnabled(PlayerNumber(p)) ) + if( !GAMESTATE->m_CurStageStats.bFailed[p] ) + bAllReallyFailed = false; + + if( !bAllReallyFailed && !IsLastSong() ) { + /* Next song. */ for( p=0; pIsPlayerEnabled(p) && !GAMESTATE->m_CurStageStats.bFailed[p] ) { @@ -1663,50 +1661,56 @@ void ScreenGameplay::HandleScreenMessage( const ScreenMessage SM ) GAMESTATE->m_pCurSong = pCurSong; m_NextSongOut.StartTransitioning( SM_LoadNextSong ); + return; } - else // IsLastSong + + /* End round. */ + if( m_DancingState == STATE_OUTRO ) // ScreenGameplay already ended + return; // ignore + m_DancingState = STATE_OUTRO; + + GAMESTATE->RemoveAllActiveAttacks(); + + if( bAllReallyFailed ) { - if( m_DancingState == STATE_OUTRO ) // ScreenGameplay already ended - return; // ignore - m_DancingState = STATE_OUTRO; + this->PostScreenMessage( SM_BeginFailed, 0 ); + return; + } - GAMESTATE->RemoveAllActiveAttacks(); - - // do they deserve an extra stage? - if( GAMESTATE->HasEarnedExtraStage() ) + // do they deserve an extra stage? + if( GAMESTATE->HasEarnedExtraStage() ) + { + TweenOffScreen(); + m_Extra.StartTransitioning( SM_GoToStateAfterCleared ); + SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("gameplay extra") ); + } + else + { + TweenOffScreen(); + + switch( GAMESTATE->m_PlayMode ) { - TweenOffScreen(); - m_Extra.StartTransitioning( SM_GoToStateAfterCleared ); - SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("gameplay extra") ); - } - else - { - TweenOffScreen(); - - switch( GAMESTATE->m_PlayMode ) + case PLAY_MODE_BATTLE: + case PLAY_MODE_RAVE: { - case PLAY_MODE_BATTLE: - case PLAY_MODE_RAVE: + PlayerNumber winner = GAMESTATE->GetBestPlayer(); + switch( winner ) { - PlayerNumber winner = GAMESTATE->GetBestPlayer(); - switch( winner ) - { - case PLAYER_INVALID: - m_Draw.StartTransitioning( SM_GoToStateAfterCleared ); - break; - default: - m_Win[winner].StartTransitioning( SM_GoToStateAfterCleared ); - break; - } + case PLAYER_INVALID: + m_Draw.StartTransitioning( SM_GoToStateAfterCleared ); + break; + default: + m_Win[winner].StartTransitioning( SM_GoToStateAfterCleared ); + break; } - break; - default: - m_Cleared.StartTransitioning( SM_GoToStateAfterCleared ); - break; } - - SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("gameplay cleared") ); + break; + default: + m_Cleared.StartTransitioning( SM_GoToStateAfterCleared ); + break; } + + SOUND->PlayOnceFromDir( ANNOUNCER->GetPathTo("gameplay cleared") ); } } break; diff --git a/stepmania/src/ScreenGameplay.h b/stepmania/src/ScreenGameplay.h index 2002aeaa36..2a61afdc89 100644 --- a/stepmania/src/ScreenGameplay.h +++ b/stepmania/src/ScreenGameplay.h @@ -76,10 +76,10 @@ protected: float StartPlayingSong(float MinTimeToNotes, float MinTimeToMusic); void ShowSavePrompt( ScreenMessage SM_SendWhenDone ); - bool OneIsHot(); - bool AllAreInDanger(); - bool AllAreFailing(); - bool AllFailedEarlier(); + bool OneIsHot() const; + bool AllAreInDanger() const; + bool AllAreFailing() const; + bool AllFailedEarlier() const; bool IsTimeToPlayTicks() const; void UpdateLyrics( float fDeltaTime ); void UpdateCheckFail(); diff --git a/stepmania/src/ScreenOptionsMasterPrefs.cpp b/stepmania/src/ScreenOptionsMasterPrefs.cpp index af8af3012c..33f09c946b 100644 --- a/stepmania/src/ScreenOptionsMasterPrefs.cpp +++ b/stepmania/src/ScreenOptionsMasterPrefs.cpp @@ -320,8 +320,7 @@ static void DefaultFailType( int &sel, bool ToSel, const CStringArray &choices ) { case 0: so.m_FailType = SongOptions::FAIL_ARCADE; break; case 1: so.m_FailType = SongOptions::FAIL_END_OF_SONG; break; - case 2: so.m_FailType = SongOptions::FAIL_PASSMARK; break; - case 3: so.m_FailType = SongOptions::FAIL_OFF; break; + case 2: so.m_FailType = SongOptions::FAIL_OFF; break; default: ASSERT(0); } @@ -451,7 +450,7 @@ static const ConfOption g_ConfOptions[] = ConfOption( "Progressive\nLifebar", ProgressiveLifebar, "OFF","1","2","3","4","5","6","7","8"), ConfOption( "Progressive\nStage Lifebar",ProgressiveStageLifebar, "OFF","1","2","3","4","5","6","7","8","INSANITY"), ConfOption( "Progressive\nNonstop Lifebar",ProgressiveNonstopLifebar,"OFF","1","2","3","4","5","6","7","8","INSANITY"), - ConfOption( "Default\nFail Type", DefaultFailType, "ARCADE","END OF SONG","PASSMARK","OFF" ), + ConfOption( "Default\nFail Type", DefaultFailType, "ARCADE","END OF SONG","OFF" ), ConfOption( "Coins Per\nCredit", CoinsPerCredit, "1","2","3","4","5","6","7","8" ), ConfOption( "Joint\nPremium", JointPremium, "OFF","ON" ), ConfOption( "Show Song\nOptions", ShowSongOptions, "HIDE","SHOW","ASK" ), diff --git a/stepmania/src/SongOptions.cpp b/stepmania/src/SongOptions.cpp index 67d722afdc..ce7857018c 100644 --- a/stepmania/src/SongOptions.cpp +++ b/stepmania/src/SongOptions.cpp @@ -49,7 +49,6 @@ CString SongOptions::GetString() const { case FAIL_ARCADE: break; case FAIL_END_OF_SONG: sReturn += "FailEndOfSong, "; break; - case FAIL_PASSMARK: sReturn += "FailPassMark"; break; case FAIL_OFF: sReturn += "FailOff, "; break; } @@ -117,7 +116,6 @@ void SongOptions::FromString( CString sOptions ) else if( sBit == "death" ) m_DrainType = DRAIN_SUDDEN_DEATH; else if( sBit == "normal-drain" ) m_DrainType = DRAIN_NORMAL; else if( sBit == "failarcade" ) m_FailType = FAIL_ARCADE; - else if( sBit == "failpassmark" ) m_FailType = FAIL_PASSMARK; else if( sBit == "failendofsong" ) m_FailType = FAIL_END_OF_SONG; else if( sBit == "failoff" ) m_FailType = FAIL_OFF; else if( sBit == "assisttick" ) m_bAssistTick = on; diff --git a/stepmania/src/SongOptions.h b/stepmania/src/SongOptions.h index f3ae8dae88..df111d1f6b 100644 --- a/stepmania/src/SongOptions.h +++ b/stepmania/src/SongOptions.h @@ -20,7 +20,7 @@ struct SongOptions enum DrainType { DRAIN_NORMAL, DRAIN_NO_RECOVER, DRAIN_SUDDEN_DEATH }; DrainType m_DrainType; // only used with LifeBar int m_iBatteryLives; - enum FailType { FAIL_ARCADE=0, FAIL_END_OF_SONG, FAIL_PASSMARK, FAIL_OFF }; + enum FailType { FAIL_ARCADE=0, FAIL_END_OF_SONG, FAIL_OFF }; FailType m_FailType; float m_fMusicRate; bool m_bAssistTick, m_bAutoSync, m_bSaveScore;