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.)
This commit is contained in:
@@ -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 )
|
||||
|
||||
@@ -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; i<asBits.size(); i++ )
|
||||
{
|
||||
CString& sBit = asBits[i];
|
||||
@@ -238,6 +243,7 @@ void PlayerOptions::FromString( CString sOptions )
|
||||
}
|
||||
else if( asParts[j][0]=='*' )
|
||||
sscanf( asParts[j], "*%f", &speed );
|
||||
LOG->Trace("'%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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
|
||||
@@ -921,7 +921,7 @@ bool ScreenGameplay::OneIsHot()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScreenGameplay::AllAreInDanger()
|
||||
bool ScreenGameplay::AllAreInDanger() const
|
||||
{
|
||||
for( int p=0; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(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; p<NUM_PLAYERS; p++ )
|
||||
{
|
||||
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
|
||||
if( (m_pLifeMeter[p]->GetLife()) > 0.7f ) // 70 % is the pass mark
|
||||
{
|
||||
bFoundAPasser = false;
|
||||
}
|
||||
}
|
||||
return bFoundAPasser;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
for( int p=0; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(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; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(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; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(PlayerNumber(p)) )
|
||||
if( !GAMESTATE->m_CurStageStats.bFailed[p] )
|
||||
bAllReallyFailed = false;
|
||||
|
||||
if( !bAllReallyFailed && !IsLastSong() )
|
||||
{
|
||||
/* Next song. */
|
||||
for( p=0; p<NUM_PLAYERS; p++ )
|
||||
if( GAMESTATE->IsPlayerEnabled(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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" ),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user