diff --git a/Docs/Luadoc/Lua.xml b/Docs/Luadoc/Lua.xml
index 51d69591f0..38b935bfb5 100644
--- a/Docs/Luadoc/Lua.xml
+++ b/Docs/Luadoc/Lua.xml
@@ -1813,7 +1813,8 @@
-
+
+
diff --git a/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua b/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua
index 464287e876..16f54e6cd0 100644
--- a/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua
+++ b/Themes/_themekit-piu/BGAnimations/ScreenSystemLayer overlay.lua
@@ -48,7 +48,13 @@ return Def.ActorFrame {
LoadFont("_arial black 20px")..{
InitCommand=cmd(xy,SCREEN_CENTER_X,SCREEN_HEIGHT-20;zoom,1;shadowlength,0;playcommand,"Text");
TextCommand=function(self)
- if GAMESTATE:GetCoinMode() == 'CoinMode_Free' then
+ if GAMESTATE:GetCoinMode() == 'CoinMode_Pay' then
+ local Coins = GAMESTATE:GetCoins()
+ local CoinForCredit = GAMESTATE:GetCoinsNeededToJoin()
+ local Credits = math.floor(Coins/CoinForCredit)
+ local Remain = Coins % CoinForCredit
+ self:settext(string.format("CREDIT(S) %i[%i/%i]", Credits, Remain, CoinForCredit))
+ elseif GAMESTATE:GetCoinMode() == 'CoinMode_Free' then
self:settext("Free Play")
else --homemode
self:settext("Home Mode");
diff --git a/Themes/_themekit-piu/Scripts/03 branches.lua b/Themes/_themekit-piu/Scripts/03 branches.lua
index 06a808e4ef..712fe33d25 100644
--- a/Themes/_themekit-piu/Scripts/03 branches.lua
+++ b/Themes/_themekit-piu/Scripts/03 branches.lua
@@ -20,7 +20,8 @@ function EvaluationNext()
end
function GameOverNext()
- if GAMESTATE:GetCoinMode() == 'CoinMode_Free'
+ if (GAMESTATE:GetCoinMode() == 'CoinMode_Pay' and GAMESTATE:GetCoins() > 0)
+ or GAMESTATE:GetCoinMode() == 'CoinMode_Free'
then
return "ScreenTitleMenu"
else
diff --git a/src/GameCommand.cpp b/src/GameCommand.cpp
index 11353bd264..4776f98736 100644
--- a/src/GameCommand.cpp
+++ b/src/GameCommand.cpp
@@ -520,6 +520,23 @@ bool GameCommand::IsPlayable( RString *why ) const
return false;
}
+ /* If you've paid too much already, don't allow the mode. (If we allow this,
+ * the credits will be "refunded" in Apply(), but that's confusing.) */
+ /* Do allow the mode if they've already joined in more credits than
+ * are required. Otherwise, people who put in two credits to play
+ * doubles on a doubles-premium machiune will get locked out.
+ * the refund logic isn't that awkward because you never see the
+ * credits number jump up - the credits display is hidden if both
+ * sides are joined. -Chris */
+ /*
+ if( PREFSMAN->m_iCoinMode == COIN_PAY && iNumCreditsPaid > iNumCreditsRequired )
+ {
+ if( why )
+ *why = ssprintf( "too many credits paid (%i > %i)", iNumCreditsPaid, iNumCreditsRequired );
+ return false;
+ }
+ */
+
/* If both sides are joined, disallow singles modes, since easy to select
* them accidentally, instead of versus mode. */
if( m_pStyle->m_StyleType == StyleType_OnePlayerOneSide &&
@@ -645,6 +662,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/GameConstantsAndTypes.cpp b/src/GameConstantsAndTypes.cpp
index 4ff490610f..41c2e0b6e8 100644
--- a/src/GameConstantsAndTypes.cpp
+++ b/src/GameConstantsAndTypes.cpp
@@ -134,6 +134,7 @@ LuaXType( StageResult );
static const char *CoinModeNames[] = {
"Home",
+ "Pay",
"Free",
};
XToString( CoinMode );
diff --git a/src/GameConstantsAndTypes.h b/src/GameConstantsAndTypes.h
index b49fcdc58e..11c94418ba 100644
--- a/src/GameConstantsAndTypes.h
+++ b/src/GameConstantsAndTypes.h
@@ -432,6 +432,7 @@ const int ITEM_NONE = -1;
enum CoinMode
{
CoinMode_Home, /**< The full range of options are available. */
+ CoinMode_Pay, /**< Coins must be inserted before a game can begin. */
CoinMode_Free, /**< It costs no money to play, but otherwise is similar to Pay mode. */
NUM_CoinMode,
CoinMode_Invalid
diff --git a/src/GameState.cpp b/src/GameState.cpp
index adffcf6119..7da1e2dd0a 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;
@@ -485,6 +491,9 @@ int GameState::GetCoinsNeededToJoin() const
{
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 )
@@ -2046,7 +2055,10 @@ bool GameState::IsEventMode() const
CoinMode GameState::GetCoinMode() const
{
- return GamePreferences::m_CoinMode;
+ 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 d52bd9da85..8f122c104c 100644
--- a/src/ScreenAttract.cpp
+++ b/src/ScreenAttract.cpp
@@ -85,6 +85,14 @@ bool ScreenAttract::AttractInput( const InputEventPlus &input, ScreenWithMenuEle
case GAME_BUTTON_COIN:
switch( GAMESTATE->GetCoinMode() )
{
+ case CoinMode_Pay:
+ LOG->Trace("ScreenAttract::AttractInput: COIN_PAY (%i/%i, %i)",
+ GAMESTATE->m_iCoins.Get(),
+ PREFSMAN->m_iCoinsPerCredit.Get(),
+ GAMESTATE->GetNumSidesJoined() );
+ if( GAMESTATE->m_iCoins < PREFSMAN->m_iCoinsPerCredit && GAMESTATE->GetNumSidesJoined() == 0 )
+ return true;
+ // fall through
case CoinMode_Home:
case CoinMode_Free:
if( pScreen->IsTransitioning() )
diff --git a/src/ScreenSystemLayer.cpp b/src/ScreenSystemLayer.cpp
index 0008ddc266..830ad78f18 100644
--- a/src/ScreenSystemLayer.cpp
+++ b/src/ScreenSystemLayer.cpp
@@ -106,6 +106,20 @@ namespace
else
return CREDITS_NOT_PRESENT.GetValue();
+ case CoinMode_Pay:
+ {
+ 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;
+ }
case CoinMode_Free:
if( GAMESTATE->PlayersCanJoin() )
return CREDITS_FREE_PLAY.GetValue();
diff --git a/src/ScreenWithMenuElements.cpp b/src/ScreenWithMenuElements.cpp
index 5cde6d05d6..6ec6ca04cd 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 )