diff --git a/Themes/_fallback/metrics.ini b/Themes/_fallback/metrics.ini index 639cf607f7..d0a6e46d72 100644 --- a/Themes/_fallback/metrics.ini +++ b/Themes/_fallback/metrics.ini @@ -3016,7 +3016,7 @@ Fallback="ScreenOptionsServiceChild" NextScreen="ScreenOptionsService" PrevScreen="ScreenOptionsService" # stuff tied to arcade features -LineNames="1,2,3,6" +LineNames="1,2,3,4,5,6" Line1="conf,GetRankingName" Line2="conf,CoinMode" Line3="conf,SongsPerPlay" diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp index fbc10b0f7e..4c589aaf8e 100644 --- a/src/GameCommand.cpp +++ b/src/GameCommand.cpp @@ -493,10 +493,15 @@ bool GameCommand::IsPlayable( RString *why ) const if ( m_pStyle ) { - int iCredits = NUM_PLAYERS; + int iCredits; + if( GAMESTATE->GetCoinMode() == CoinMode_Pay ) + iCredits = GAMESTATE->m_iCoins / PREFSMAN->m_iCoinsPerCredit; + else + iCredits = NUM_PLAYERS; + const int iNumCreditsPaid = GetNumCreditsPaid(); const int iNumCreditsRequired = GetCreditsRequiredToPlayStyle(m_pStyle); - + /* With PREFSMAN->m_bDelayedCreditsReconcile disabled, enough credits must * be paid. (This means that enough sides must be joined.) Enabled, simply * having enough credits lying in the machine is sufficient; we'll deduct the @@ -637,6 +642,19 @@ void GameCommand::ApplySelf( const vector &vpns ) const { GAMESTATE->SetCurrentStyle( m_pStyle ); + // It's possible to choose a style that didn't have enough players joined. + // If enough players aren't joined, then we need to subtract credits + // for the sides that will be joined as a result of applying this option. + if( GAMESTATE->GetCoinMode() == CoinMode_Pay ) + { + int iNumCreditsRequired = GetCreditsRequiredToPlayStyle(m_pStyle); + int iNumCreditsPaid = GetNumCreditsPaid(); + int iNumCreditsOwed = iNumCreditsRequired - iNumCreditsPaid; + GAMESTATE->m_iCoins.Set( GAMESTATE->m_iCoins - iNumCreditsOwed * PREFSMAN->m_iCoinsPerCredit ); + LOG->Trace( "Deducted %i coins, %i remaining", + iNumCreditsOwed * PREFSMAN->m_iCoinsPerCredit, GAMESTATE->m_iCoins.Get() ); + } + // If only one side is joined and we picked a style that requires both // sides, join the other side. switch( m_pStyle->m_StyleType ) diff --git a/src/GameState.cpp b/src/GameState.cpp index cf7c2ebd9b..5902ee152e 100644 --- a/src/GameState.cpp +++ b/src/GameState.cpp @@ -361,7 +361,13 @@ void GameState::Reset() void GameState::JoinPlayer( PlayerNumber pn ) { - m_iPlayerStageTokens[pn] = PREFSMAN->m_iSongsPerPlay; + /* If joint premium and we're not taking away a credit for the 2nd join, + * give the new player the same number of stage tokens that the old player + * has. */ + if( GetCoinMode() == CoinMode_Pay && GetPremium() == Premium_2PlayersFor1Credit && GetNumSidesJoined() == 1 ) + m_iPlayerStageTokens[pn] = m_iPlayerStageTokens[this->GetMasterPlayerNumber()]; + else + m_iPlayerStageTokens[pn] = PREFSMAN->m_iSongsPerPlay; m_bSideIsJoined[pn] = true; @@ -483,7 +489,17 @@ bool GameState::JoinPlayers() int GameState::GetCoinsNeededToJoin() const { - return 0; + int iCoinsToCharge = 0; + + if( GetCoinMode() == CoinMode_Pay ) + iCoinsToCharge = PREFSMAN->m_iCoinsPerCredit; + + // If joint premium, don't take away a credit for the second join. + if( GetPremium() == Premium_2PlayersFor1Credit && + GetNumSidesJoined() == 1 ) + iCoinsToCharge = 0; + + return iCoinsToCharge; } /* Game flow: @@ -2039,9 +2055,11 @@ bool GameState::IsEventMode() const CoinMode GameState::GetCoinMode() const { - if( GamePreferences::m_CoinMode == CoinMode_Home ) - return CoinMode_Home; - return CoinMode_Free; + // XXX: Event mode shouldn't be valid if CoinMode_Pay + if( IsEventMode() && GamePreferences::m_CoinMode == CoinMode_Pay ) + return CoinMode_Free; + else + return GamePreferences::m_CoinMode; } ThemeMetric DISABLE_PREMIUM_IN_EVENT_MODE("GameState","DisablePremiumInEventMode"); diff --git a/src/ScreenAttract.cpp b/src/ScreenAttract.cpp index 7477967ce3..1479986346 100644 --- a/src/ScreenAttract.cpp +++ b/src/ScreenAttract.cpp @@ -83,6 +83,12 @@ bool ScreenAttract::AttractInput( const InputEventPlus &input, ScreenWithMenuEle // fall through case GAME_BUTTON_START: case GAME_BUTTON_COIN: + // If we're not in a game and there aren't enough credits to start, + // eat the input and do nothing. + if( GAMESTATE->GetCoinMode() == CoinMode_Pay && + GAMESTATE->m_iCoins < PREFSMAN->m_iCoinsPerCredit && + GAMESTATE->GetNumSidesJoined() == 0 ) + return true; if( pScreen->IsTransitioning() ) return false; diff --git a/src/ScreenOptionsMasterPrefs.cpp b/src/ScreenOptionsMasterPrefs.cpp index ea174f1642..211b227ed7 100644 --- a/src/ScreenOptionsMasterPrefs.cpp +++ b/src/ScreenOptionsMasterPrefs.cpp @@ -383,43 +383,34 @@ static void MusicWheelSwitchSpeed( int &sel, bool ToSel, const ConfOption *pConf MoveMap( sel, pConfOption, ToSel, mapping, ARRAYLEN(mapping) ); } -// Gameplay options -static void CoinModeWithHome( int &sel, bool ToSel, const ConfOption *pConfOption ) -{ - if( ToSel ) - { - // Two options: Home and Free - MovePref( sel, ToSel, pConfOption ); - if( sel != 0 ) - sel = 1; - } - else - { - int tmp = static_cast(CoinMode_Home); - if( sel != 0 ) - { - sel = 1; - tmp = static_cast(CoinMode_Free); - } - MovePref( tmp , ToSel, pConfOption ); - } -} - static void CoinModeNoHome( int &sel, bool ToSel, const ConfOption *pConfOption ) { - // We only have one play mode that isn't Home - sel = 0; - if( !ToSel ) + // 0 = Pay, 1 = Free + // But MovePref thinks 0 = Home, 1 = Pay, 2 = Free + if( ToSel ) { - int tmp = static_cast(CoinMode_Free); - MovePref( tmp, ToSel, pConfOption ); + MovePref( sel, ToSel, pConfOption ); + sel--; + } + else + { + int tmp = sel + 1; + MovePref( sel, ToSel, pConfOption ); } } static void CoinsPerCredit( int &sel, bool ToSel, const ConfOption *pConfOption ) { - const int mapping[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }; - MoveMap( sel, pConfOption, ToSel, mapping, ARRAYLEN(mapping) ); + if( ToSel ) + { + MovePref( sel, ToSel, pConfOption ); + sel--; + } + else + { + int tmp = sel + 1; + MovePref( tmp, ToSel, pConfOption ); + } } static void JointPremium( int &sel, bool ToSel, const ConfOption *pConfOption ) @@ -729,9 +720,10 @@ static void InitializeConfOptions() // Machine options ADD( ConfOption( "MenuTimer", MovePref, "Off","On" ) ); - ADD( ConfOption( "CoinMode", CoinModeWithHome, "Home","Free Play" ) ); - ADD( ConfOption( "CoinModeNoHome", CoinModeNoHome, "Free Play" ) ); + ADD( ConfOption( "CoinMode", MovePref, "Home","Pay","Free Play" ) ); + ADD( ConfOption( "CoinModeNoHome", CoinModeNoHome, "Pay","Free Play" ) ); g_ConfOptions.back().m_sPrefName = "CoinMode"; + ADD( ConfOption( "CoinsPerCredit", CoinsPerCredit, "|1","|2","|3","|4","|5","|6","|7","|8","|9","|10","|11","|12","|13","|14","|15","|16" ) ); ADD( ConfOption( "SongsPerPlay", SongsPerPlay, "|1","|2","|3","|4","|5" ) ); ADD( ConfOption( "SongsPerPlayOrEvent", SongsPerPlayOrEventMode,"|1","|2","|3","|4","|5","Event" ) ); diff --git a/src/ScreenSystemLayer.cpp b/src/ScreenSystemLayer.cpp index 3904c99a16..8c600b9a1a 100644 --- a/src/ScreenSystemLayer.cpp +++ b/src/ScreenSystemLayer.cpp @@ -97,13 +97,29 @@ namespace } else // bShowCreditsMessage { - if( GAMESTATE->PlayersCanJoin() ) - return CREDITS_NOT_PRESENT.GetValue(); - - CoinMode mode = GAMESTATE->GetCoinMode(); - if( mode == CoinMode_Home ) + switch( GAMESTATE->GetCoinMode() ) + { + case CoinMode_Home: return CREDITS_PRESS_START.GetValue(); - return CREDITS_FREE_PLAY.GetValue(); + case CoinMode_Pay: + // GCC is picky and needs this to be bracketed + { + int iCredits = GAMESTATE->m_iCoins / PREFSMAN->m_iCoinsPerCredit; + int iCoins = GAMESTATE->m_iCoins % PREFSMAN->m_iCoinsPerCredit; + RString sCredits = CREDITS_CREDITS; + // todo: allow themers to change these strings -aj + if( iCredits > 0 || PREFSMAN->m_iCoinsPerCredit == 1 ) + sCredits += ssprintf(" %d", iCredits); + if( PREFSMAN->m_iCoinsPerCredit > 1 ) + sCredits += ssprintf(" %d/%d", iCoins, PREFSMAN->m_iCoinsPerCredit.Get() ); + if( iCredits >= MAX_NUM_CREDITS ) + sCredits += " " + CREDITS_MAX.GetValue(); + return sCredits; + } + default: // CoinMode_Free + if( GAMESTATE->PlayersCanJoin() ) + return CREDITS_FREE_PLAY.GetValue(); + } } } diff --git a/src/ScreenWithMenuElements.cpp b/src/ScreenWithMenuElements.cpp index 575ed7a7ec..f02d2e1cb4 100644 --- a/src/ScreenWithMenuElements.cpp +++ b/src/ScreenWithMenuElements.cpp @@ -134,6 +134,14 @@ void ScreenWithMenuElements::BeginScreen() /* Evaluate FirstUpdateCommand. */ this->PlayCommand( "FirstUpdate" ); + + /* If AutoJoin and a player is already joined, then try to join a player. (If no players + * are joined, they'll join on the first JoinInput.) */ + if( GAMESTATE->GetCoinMode() == CoinMode_Pay && GAMESTATE->m_bAutoJoin.Get() ) + { + if( GAMESTATE->GetNumSidesJoined() > 0 && GAMESTATE->JoinPlayers() ) + SCREENMAN->PlayStartSound(); + } } void ScreenWithMenuElements::HandleScreenMessage( const ScreenMessage SM )