diff --git a/Generals/Code/GameEngine/Include/Common/GlobalData.h b/Generals/Code/GameEngine/Include/Common/GlobalData.h index 78688467537..e10943f2e46 100644 --- a/Generals/Code/GameEngine/Include/Common/GlobalData.h +++ b/Generals/Code/GameEngine/Include/Common/GlobalData.h @@ -408,6 +408,9 @@ class GlobalData : public SubsystemInterface Int m_systemTimeFontSize; Int m_gameTimeFontSize; + // TheSuperHackers @feature L3-M 21/08/2025 toggle the money per minute display, false shows only the original current money + Bool m_showMoneyPerMinute; + Real m_shakeSubtleIntensity; ///< Intensity for shaking a camera with SHAKE_SUBTLE Real m_shakeNormalIntensity; ///< Intensity for shaking a camera with SHAKE_NORMAL Real m_shakeStrongIntensity; ///< Intensity for shaking a camera with SHAKE_STRONG diff --git a/Generals/Code/GameEngine/Include/Common/Money.h b/Generals/Code/GameEngine/Include/Common/Money.h index b14e6d19c58..a93eed08b09 100644 --- a/Generals/Code/GameEngine/Include/Common/Money.h +++ b/Generals/Code/GameEngine/Include/Common/Money.h @@ -61,13 +61,14 @@ class Money : public Snapshot public: - inline Money() : m_money(0), m_playerIndex(0) + inline Money() : m_playerIndex(0) { + init(); } void init() { - m_money = 0; + setStartingCash(0); } inline UnsignedInt countMoney() const @@ -77,7 +78,11 @@ class Money : public Snapshot /// returns the actual amount withdrawn, which may be less than you want. (sorry, can't go into debt...) UnsignedInt withdraw(UnsignedInt amountToWithdraw, Bool playSound = TRUE); - void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE); + void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE, Bool trackIncome = TRUE); + + void setStartingCash(UnsignedInt amount); + void updateIncomeBucket(); + UnsignedInt getCashPerMinute() const; void setPlayerIndex(Int ndx) { m_playerIndex = ndx; } @@ -102,4 +107,7 @@ class Money : public Snapshot UnsignedInt m_money; ///< amount of money Int m_playerIndex; ///< what is my player index? + UnsignedInt m_incomeBuckets[60]; ///< circular buffer of 60 seconds for income tracking + UnsignedInt m_currentBucket; + UnsignedInt m_cashPerMinute; }; diff --git a/Generals/Code/GameEngine/Include/Common/STLTypedefs.h b/Generals/Code/GameEngine/Include/Common/STLTypedefs.h index 6d5e8176f3e..484b3f33e80 100644 --- a/Generals/Code/GameEngine/Include/Common/STLTypedefs.h +++ b/Generals/Code/GameEngine/Include/Common/STLTypedefs.h @@ -70,6 +70,7 @@ enum DrawableID CPP_11(: Int); #include #include #include +#include #include #include #include diff --git a/Generals/Code/GameEngine/Include/Common/UserPreferences.h b/Generals/Code/GameEngine/Include/Common/UserPreferences.h index 37278871991..aef49361d36 100644 --- a/Generals/Code/GameEngine/Include/Common/UserPreferences.h +++ b/Generals/Code/GameEngine/Include/Common/UserPreferences.h @@ -145,6 +145,8 @@ class OptionPreferences : public UserPreferences Int getGameTimeFontSize(void); Real getResolutionFontAdjustment(void); + + Bool getShowMoneyPerMinute(void) const; }; //----------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp index aed88c1afaa..9030c358e6e 100644 --- a/Generals/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/Generals/Code/GameEngine/Source/Common/GlobalData.cpp @@ -939,6 +939,8 @@ GlobalData::GlobalData() m_systemTimeFontSize = 8; m_gameTimeFontSize = 8; + m_showMoneyPerMinute = FALSE; + m_debugShowGraphicalFramerate = FALSE; // By default, show all asserts. @@ -1192,6 +1194,7 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_renderFpsFontSize = optionPref.getRenderFpsFontSize(); TheWritableGlobalData->m_systemTimeFontSize = optionPref.getSystemTimeFontSize(); TheWritableGlobalData->m_gameTimeFontSize = optionPref.getGameTimeFontSize(); + TheWritableGlobalData->m_showMoneyPerMinute = optionPref.getShowMoneyPerMinute(); Int val=optionPref.getGammaValue(); //generate a value between 0.6 and 2.0. diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Money.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Money.cpp index 20fcc928f6f..43a1566438f 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Money.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Money.cpp @@ -51,6 +51,7 @@ #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/Xfer.h" +#include "GameLogic/GameLogic.h" // ------------------------------------------------------------------------------------------------ UnsignedInt Money::withdraw(UnsignedInt amountToWithdraw, Bool playSound) @@ -78,7 +79,7 @@ UnsignedInt Money::withdraw(UnsignedInt amountToWithdraw, Bool playSound) } // ------------------------------------------------------------------------------------------------ -void Money::deposit(UnsignedInt amountToDeposit, Bool playSound) +void Money::deposit(UnsignedInt amountToDeposit, Bool playSound, Bool trackIncome) { if (amountToDeposit == 0) return; @@ -88,9 +89,43 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound) triggerAudioEvent(TheAudio->getMiscAudio()->m_moneyDepositSound); } + if (trackIncome) + { + m_incomeBuckets[m_currentBucket] += amountToDeposit; + m_cashPerMinute += amountToDeposit; + } + m_money += amountToDeposit; } +// ------------------------------------------------------------------------------------------------ +void Money::setStartingCash(UnsignedInt amount) +{ + m_money = amount; + std::fill(m_incomeBuckets, m_incomeBuckets + ARRAY_SIZE(m_incomeBuckets), 0u); + m_currentBucket = 0u; + m_cashPerMinute = 0u; +} + +// ------------------------------------------------------------------------------------------------ +void Money::updateIncomeBucket() +{ + UnsignedInt frame = TheGameLogic->getFrame(); + UnsignedInt nextBucket = (frame / LOGICFRAMES_PER_SECOND) % ARRAY_SIZE(m_incomeBuckets); + if (nextBucket != m_currentBucket) + { + m_cashPerMinute -= m_incomeBuckets[nextBucket]; + m_currentBucket = nextBucket; + m_incomeBuckets[m_currentBucket] = 0u; + } +} + +// ------------------------------------------------------------------------------------------------ +UnsignedInt Money::getCashPerMinute() const +{ + return m_cashPerMinute; +} + void Money::triggerAudioEvent(const AudioEventRTS& audioEvent) { Real volume = TheAudio->getAudioSettings()->m_preferredMoneyTransactionVolume; @@ -116,19 +151,35 @@ void Money::crc( Xfer *xfer ) // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: - * 1: Initial version */ + * 1: Initial version + * 2: Add saveload support for the cash per minute income tracking */ // ------------------------------------------------------------------------------------------------ void Money::xfer( Xfer *xfer ) { // version +#if RETAIL_COMPATIBLE_XFER_SAVE XferVersion currentVersion = 1; +#else + XferVersion currentVersion = 2; +#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // money value xfer->xferUnsignedInt( &m_money ); + if (version <= 1) + { + setStartingCash(m_money); + } + else + { + xfer->xferUser(m_incomeBuckets, sizeof(m_incomeBuckets)); + xfer->xferUnsignedInt(&m_currentBucket); + + m_cashPerMinute = std::accumulate(m_incomeBuckets, m_incomeBuckets + ARRAY_SIZE(m_incomeBuckets), 0u); + } } // ------------------------------------------------------------------------------------------------ @@ -147,5 +198,7 @@ void Money::parseMoneyAmount( INI *ini, void *instance, void *store, const void* { // Someday, maybe, have mulitple fields like Gold:10000 Wood:1000 Tiberian:10 Money * money = (Money *)store; - INI::parseUnsignedInt( ini, instance, &money->m_money, userData ); + UnsignedInt moneyAmount; + INI::parseUnsignedInt( ini, instance, &moneyAmount, userData ); + money->setStartingCash(moneyAmount); } diff --git a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp index b43934e9e5c..49e13c02e4d 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -434,11 +434,11 @@ void Player::init(const PlayerTemplate* pt) // Note that copying the entire Money class instead would also copy the player index inside of it. if ( TheGameInfo ) { - m_money.deposit( TheGameInfo->getStartingCash().countMoney(), FALSE ); + m_money.deposit( TheGameInfo->getStartingCash().countMoney(), FALSE, FALSE ); } else { - m_money.deposit( TheGlobalData->m_defaultStartingCash.countMoney(), FALSE ); + m_money.deposit( TheGlobalData->m_defaultStartingCash.countMoney(), FALSE, FALSE ); } } @@ -1771,7 +1771,7 @@ void Player::transferAssetsFromThat(Player *that) // transfer all his money UnsignedInt allMoney = that->getMoney()->countMoney(); that->getMoney()->withdraw(allMoney); - getMoney()->deposit(allMoney); + getMoney()->deposit(allMoney, TRUE, FALSE); } //============================================================================= diff --git a/Generals/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp b/Generals/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp index d7a0fbb3a02..74ae681886e 100644 --- a/Generals/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp +++ b/Generals/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp @@ -171,7 +171,7 @@ AsciiString PlayerTemplate::getStartingUnit( Int i ) const // assign the money into the 'Money' (m_money) pointed to at 'store' Money *theMoney = (Money *)store; theMoney->init(); - theMoney->deposit( money ); + theMoney->setStartingCash(money); } diff --git a/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp b/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp index ec6c3ef6516..985cddbf74d 100644 --- a/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/BuildAssistant.cpp @@ -250,7 +250,7 @@ void BuildAssistant::update( void ) sellValue = REAL_TO_UNSIGNEDINT( obj->getTemplate()->calcCostToBuild( player ) * TheGlobalData->m_sellPercentage ); - player->getMoney()->deposit( sellValue ); + player->getMoney()->deposit( sellValue, TRUE, FALSE ); // this money shouldn't be scored since it wasn't really "earned." // player->getScoreKeeper()->addMoneyEarned( sellValue ); diff --git a/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp b/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp index 7aba8c271ef..b9b089e4cd8 100644 --- a/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp +++ b/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp @@ -700,7 +700,7 @@ Money CustomMatchPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp index 8e8a60605a9..20340df3104 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp @@ -271,7 +271,7 @@ Money LANPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 1e62b663256..bd0e1eec75c 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -943,6 +943,19 @@ Real OptionPreferences::getResolutionFontAdjustment(void) return fontScale; } +Bool OptionPreferences::getShowMoneyPerMinute(void) const +{ + OptionPreferences::const_iterator it = find("ShowMoneyPerMinute"); + if (it == end()) + return TheGlobalData->m_showMoneyPerMinute; + + if (stricmp(it->second.str(), "yes") == 0) + { + return TRUE; + } + return FALSE; +} + static OptionPreferences *pref = NULL; static void setDefaults( void ) @@ -1496,6 +1509,16 @@ static void saveOptions( void ) TheGlobalLanguageData->m_userResolutionFontSizeAdjustment = (Real)val / 100.0f; } + //------------------------------------------------------------------------------------------------- + // Set Money Per Minute + { + Bool show = pref->getShowMoneyPerMinute(); + AsciiString prefString; + prefString = show ? "yes" : "no"; + (*pref)["ShowMoneyPerMinute"] = prefString; + TheWritableGlobalData->m_showMoneyPerMinute = show; + } + //------------------------------------------------------------------------------------------------- // Resolution // diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp index 474d3d0dcf9..ea23a6ac6f2 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp @@ -322,7 +322,7 @@ Money SkirmishPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } diff --git a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp index 05a2cd83fa3..f51e726e373 100644 --- a/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -93,6 +93,39 @@ // ------------------------------------------------------------------------------------------------ static const RGBColor IllegalBuildColor = { 1.0, 0.0, 0.0 }; +// ------------------------------------------------------------------------------------------------ +static UnicodeString formatMoneyValue(UnsignedInt amount) +{ + UnicodeString result; + if (amount >= 100000) + { + result.format(L"%uk", amount / 1000); + } + else + { + result.format(L"%u", amount); + } + return result; +} + +static UnicodeString formatIncomeValue(UnsignedInt cashPerMin) +{ + UnicodeString result; + if (cashPerMin >= 10000) + { + result.format(L"%uk", cashPerMin / 1000); + } + else if (cashPerMin >= 1000) + { + result.format(L"%u", (cashPerMin / 100) * 100); + } + else + { + result.format(L"%u", (cashPerMin / 10) * 10); + } + return result; +} + //------------------------------------------------------------------------------------------------- /// The InGameUI singleton instance. InGameUI *TheInGameUI = NULL; @@ -1830,7 +1863,8 @@ void InGameUI::update( void ) // update the player money window if the money amount has changed // this seems like as good a place as any to do the power hide/show - static Int lastMoney = -1; + static UnsignedInt lastMoney = ~0u; + static UnsignedInt lastIncome = ~0u; static NameKeyType moneyWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:MoneyDisplay" ); static NameKeyType powerWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:PowerWindow" ); @@ -1846,15 +1880,38 @@ void InGameUI::update( void ) Player* moneyPlayer = TheControlBar->getCurrentlyViewedPlayer(); if( moneyPlayer) { - Int currentMoney = moneyPlayer->getMoney()->countMoney(); - if( lastMoney != currentMoney ) + Money *money = moneyPlayer->getMoney(); + Bool showIncome = TheGlobalData->m_showMoneyPerMinute; + if (!showIncome) { - UnicodeString buffer; + UnsignedInt currentMoney = money->countMoney(); + if( lastMoney != currentMoney ) + { + UnicodeString buffer; - buffer.format( TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney ); - GadgetStaticTextSetText( moneyWin, buffer ); - lastMoney = currentMoney; + buffer.format(TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney ); + GadgetStaticTextSetText( moneyWin, buffer ); + lastMoney = currentMoney; + } + } + else + { + // TheSuperHackers @feature L3-M 21/08/2025 player money per minute + money->updateIncomeBucket(); + UnsignedInt currentMoney = money->countMoney(); + UnsignedInt cashPerMin = money->getCashPerMinute(); + if ( lastMoney != currentMoney || lastIncome != cashPerMin ) + { + UnicodeString buffer; + UnicodeString moneyStr = formatMoneyValue(currentMoney); + UnicodeString incomeStr = formatIncomeValue(cashPerMin); + + buffer.format(TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:ControlBarMoneyDisplayIncome", L"$ %ls +%ls/min", moneyStr.str(), incomeStr.str())); + GadgetStaticTextSetText(moneyWin, buffer); + lastMoney = currentMoney; + lastIncome = cashPerMin; + } } moneyWin->winHide(FALSE); powerWin->winHide(FALSE); diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp index e35b8b1b255..be5cafb3b5e 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp @@ -359,7 +359,7 @@ void ProductionUpdate::cancelUpgrade( const UpgradeTemplate *upgrade ) // refund money back to the player Money *money = player->getMoney(); - money->deposit( production->m_upgradeToResearch->calcCostToBuild( player ) ); + money->deposit( production->m_upgradeToResearch->calcCostToBuild( player ), TRUE, FALSE ); // remove this production from the queue removeFromProductionQueue( production ); @@ -475,7 +475,7 @@ void ProductionUpdate::cancelUnitCreate( ProductionID productionID ) // give the player the cost of the object back Player *player = getObject()->getControllingPlayer(); Money *money = player->getMoney(); - money->deposit( production->m_objectToProduce->calcCostToBuild( player ) ); + money->deposit( production->m_objectToProduce->calcCostToBuild( player ), TRUE, FALSE ); // remove from queue list removeFromProductionQueue( production ); diff --git a/Generals/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp b/Generals/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp index 9db41fcfc7e..18983286d4b 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp @@ -3819,7 +3819,7 @@ void ScriptActions::doSetMoney(const AsciiString& playerName, Int money) return; m->withdraw(m->countMoney()); - m->deposit(money); + m->deposit(money, FALSE, FALSE); } //------------------------------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index 1726d021969..eec794d3ede 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -1480,7 +1480,7 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData ) { Money *money = thisPlayer->getMoney(); UnsignedInt amount = building->getTemplate()->calcCostToBuild( thisPlayer ); - money->deposit( amount ); + money->deposit( amount, TRUE, FALSE ); } // diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp index ff608a434c0..f16dea1825c 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp @@ -1126,7 +1126,7 @@ Bool ParseAsciiStringToGameInfo(GameInfo *game, AsciiString options) { UnsignedInt startingCashAmount = strtoul( val.str(), NULL, 10 ); startingCash.init(); - startingCash.deposit( startingCashAmount, FALSE ); + startingCash.deposit( startingCashAmount, FALSE, FALSE ); sawStartingCash = TRUE; } else if (key.compare("O") == 0 ) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h index a4659e77ae3..5ff1ed4039e 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h @@ -415,6 +415,9 @@ class GlobalData : public SubsystemInterface Int m_systemTimeFontSize; Int m_gameTimeFontSize; + // TheSuperHackers @feature L3-M 21/08/2025 toggle the money per minute display, false shows only the original current money + Bool m_showMoneyPerMinute; + Real m_shakeSubtleIntensity; ///< Intensity for shaking a camera with SHAKE_SUBTLE Real m_shakeNormalIntensity; ///< Intensity for shaking a camera with SHAKE_NORMAL Real m_shakeStrongIntensity; ///< Intensity for shaking a camera with SHAKE_STRONG diff --git a/GeneralsMD/Code/GameEngine/Include/Common/Money.h b/GeneralsMD/Code/GameEngine/Include/Common/Money.h index aa19879f430..02e65002b75 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/Money.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/Money.h @@ -61,13 +61,14 @@ class Money : public Snapshot public: - inline Money() : m_money(0), m_playerIndex(0) + inline Money() : m_playerIndex(0) { + init(); } void init() { - m_money = 0; + setStartingCash(0); } inline UnsignedInt countMoney() const @@ -77,7 +78,11 @@ class Money : public Snapshot /// returns the actual amount withdrawn, which may be less than you want. (sorry, can't go into debt...) UnsignedInt withdraw(UnsignedInt amountToWithdraw, Bool playSound = TRUE); - void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE); + void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE, Bool trackIncome = TRUE); + + void setStartingCash(UnsignedInt amount); + void updateIncomeBucket(); + UnsignedInt getCashPerMinute() const; void setPlayerIndex(Int ndx) { m_playerIndex = ndx; } @@ -102,4 +107,7 @@ class Money : public Snapshot UnsignedInt m_money; ///< amount of money Int m_playerIndex; ///< what is my player index? + UnsignedInt m_incomeBuckets[60]; ///< circular buffer of 60 seconds for income tracking + UnsignedInt m_currentBucket; + UnsignedInt m_cashPerMinute; }; diff --git a/GeneralsMD/Code/GameEngine/Include/Common/STLTypedefs.h b/GeneralsMD/Code/GameEngine/Include/Common/STLTypedefs.h index 48eef5289e5..2736316f560 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/STLTypedefs.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/STLTypedefs.h @@ -70,6 +70,7 @@ enum DrawableID CPP_11(: Int); #include #include #include +#include #include #include #include diff --git a/GeneralsMD/Code/GameEngine/Include/Common/UserPreferences.h b/GeneralsMD/Code/GameEngine/Include/Common/UserPreferences.h index 170f6933512..7936cfd8ee6 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/UserPreferences.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/UserPreferences.h @@ -148,6 +148,8 @@ class OptionPreferences : public UserPreferences Int getGameTimeFontSize(void); Real getResolutionFontAdjustment(void); + + Bool getShowMoneyPerMinute(void) const; }; //----------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp index 264a0ddab8c..41bb35cfe38 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp @@ -948,6 +948,8 @@ GlobalData::GlobalData() m_systemTimeFontSize = 8; m_gameTimeFontSize = 8; + m_showMoneyPerMinute = FALSE; + m_debugShowGraphicalFramerate = FALSE; // By default, show all asserts. @@ -1220,6 +1222,7 @@ void GlobalData::parseGameDataDefinition( INI* ini ) TheWritableGlobalData->m_renderFpsFontSize = optionPref.getRenderFpsFontSize(); TheWritableGlobalData->m_systemTimeFontSize = optionPref.getSystemTimeFontSize(); TheWritableGlobalData->m_gameTimeFontSize = optionPref.getGameTimeFontSize(); + TheWritableGlobalData->m_showMoneyPerMinute = optionPref.getShowMoneyPerMinute(); Int val=optionPref.getGammaValue(); //generate a value between 0.6 and 2.0. diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Money.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Money.cpp index 6bcd991d5e3..392baaf90f4 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Money.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Money.cpp @@ -51,6 +51,7 @@ #include "Common/Player.h" #include "Common/PlayerList.h" #include "Common/Xfer.h" +#include "GameLogic/GameLogic.h" // ------------------------------------------------------------------------------------------------ UnsignedInt Money::withdraw(UnsignedInt amountToWithdraw, Bool playSound) @@ -78,7 +79,7 @@ UnsignedInt Money::withdraw(UnsignedInt amountToWithdraw, Bool playSound) } // ------------------------------------------------------------------------------------------------ -void Money::deposit(UnsignedInt amountToDeposit, Bool playSound) +void Money::deposit(UnsignedInt amountToDeposit, Bool playSound, Bool trackIncome) { if (amountToDeposit == 0) return; @@ -88,6 +89,12 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound) triggerAudioEvent(TheAudio->getMiscAudio()->m_moneyDepositSound); } + if (trackIncome) + { + m_incomeBuckets[m_currentBucket] += amountToDeposit; + m_cashPerMinute += amountToDeposit; + } + m_money += amountToDeposit; if( amountToDeposit > 0 ) @@ -100,6 +107,34 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound) } } +// ------------------------------------------------------------------------------------------------ +void Money::setStartingCash(UnsignedInt amount) +{ + m_money = amount; + std::fill(m_incomeBuckets, m_incomeBuckets + ARRAY_SIZE(m_incomeBuckets), 0u); + m_currentBucket = 0u; + m_cashPerMinute = 0u; +} + +// ------------------------------------------------------------------------------------------------ +void Money::updateIncomeBucket() +{ + UnsignedInt frame = TheGameLogic->getFrame(); + UnsignedInt nextBucket = (frame / LOGICFRAMES_PER_SECOND) % ARRAY_SIZE(m_incomeBuckets); + if (nextBucket != m_currentBucket) + { + m_cashPerMinute -= m_incomeBuckets[nextBucket]; + m_currentBucket = nextBucket; + m_incomeBuckets[m_currentBucket] = 0u; + } +} + +// ------------------------------------------------------------------------------------------------ +UnsignedInt Money::getCashPerMinute() const +{ + return m_cashPerMinute; +} + void Money::triggerAudioEvent(const AudioEventRTS& audioEvent) { Real volume = TheAudio->getAudioSettings()->m_preferredMoneyTransactionVolume; @@ -125,19 +160,35 @@ void Money::crc( Xfer *xfer ) // ------------------------------------------------------------------------------------------------ /** Xfer method * Version Info: - * 1: Initial version */ + * 1: Initial version + * 2: Add saveload support for the cash per minute income tracking */ // ------------------------------------------------------------------------------------------------ void Money::xfer( Xfer *xfer ) { // version +#if RETAIL_COMPATIBLE_XFER_SAVE XferVersion currentVersion = 1; +#else + XferVersion currentVersion = 2; +#endif XferVersion version = currentVersion; xfer->xferVersion( &version, currentVersion ); // money value xfer->xferUnsignedInt( &m_money ); + if (version <= 1) + { + setStartingCash(m_money); + } + else + { + xfer->xferUser(m_incomeBuckets, sizeof(m_incomeBuckets)); + xfer->xferUnsignedInt(&m_currentBucket); + + m_cashPerMinute = std::accumulate(m_incomeBuckets, m_incomeBuckets + ARRAY_SIZE(m_incomeBuckets), 0u); + } } // ------------------------------------------------------------------------------------------------ @@ -156,5 +207,7 @@ void Money::parseMoneyAmount( INI *ini, void *instance, void *store, const void* { // Someday, maybe, have mulitple fields like Gold:10000 Wood:1000 Tiberian:10 Money * money = (Money *)store; - INI::parseUnsignedInt( ini, instance, &money->m_money, userData ); + UnsignedInt moneyAmount; + INI::parseUnsignedInt( ini, instance, &moneyAmount, userData ); + money->setStartingCash(moneyAmount); } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp index cfbec09d449..7add71ac2a4 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp @@ -438,11 +438,11 @@ void Player::init(const PlayerTemplate* pt) // Note that copying the entire Money class instead would also copy the player index inside of it. if ( TheGameInfo ) { - m_money.deposit( TheGameInfo->getStartingCash().countMoney(), FALSE ); + m_money.deposit( TheGameInfo->getStartingCash().countMoney(), FALSE, FALSE ); } else { - m_money.deposit( TheGlobalData->m_defaultStartingCash.countMoney(), FALSE ); + m_money.deposit( TheGlobalData->m_defaultStartingCash.countMoney(), FALSE, FALSE ); } } @@ -2156,7 +2156,7 @@ void Player::transferAssetsFromThat(Player *that) // transfer all his money UnsignedInt allMoney = that->getMoney()->countMoney(); that->getMoney()->withdraw(allMoney); - getMoney()->deposit(allMoney); + getMoney()->deposit(allMoney, TRUE, FALSE); } //============================================================================= diff --git a/GeneralsMD/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp b/GeneralsMD/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp index 9c96bf7fec9..59aa492e854 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp @@ -181,7 +181,7 @@ AsciiString PlayerTemplate::getStartingUnit( Int i ) const // assign the money into the 'Money' (m_money) pointed to at 'store' Money *theMoney = (Money *)store; theMoney->init(); - theMoney->deposit( money ); + theMoney->setStartingCash(money); } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp index 2b9dc020b1a..489c7ef0996 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/BuildAssistant.cpp @@ -250,7 +250,7 @@ void BuildAssistant::update( void ) sellValue = REAL_TO_UNSIGNEDINT( obj->getTemplate()->calcCostToBuild( player ) * TheGlobalData->m_sellPercentage ); - player->getMoney()->deposit( sellValue ); + player->getMoney()->deposit( sellValue, TRUE, FALSE ); // this money shouldn't be scored since it wasn't really "earned." // player->getScoreKeeper()->addMoneyEarned( sellValue ); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp b/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp index 15535d94d50..066fc2164d3 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp @@ -716,7 +716,7 @@ Money CustomMatchPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp index 8e34a81e019..b1b662291b3 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanGameOptionsMenu.cpp @@ -616,7 +616,7 @@ static void handleStartingCashSelection() GadgetComboBoxGetSelectedPos(comboBoxStartingCash, &selIndex); Money startingCash; - startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE ); + startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE, FALSE ); myGame->setStartingCash( startingCash ); myGame->resetAccepted(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp index 1f1a8e2b05d..108c60aaf7f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/LanLobbyMenu.cpp @@ -271,7 +271,7 @@ Money LANPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp index 0385a3a6956..3ca68e26b87 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp @@ -987,6 +987,19 @@ Real OptionPreferences::getResolutionFontAdjustment(void) return fontScale; } +Bool OptionPreferences::getShowMoneyPerMinute(void) const +{ + OptionPreferences::const_iterator it = find("ShowMoneyPerMinute"); + if (it == end()) + return TheGlobalData->m_showMoneyPerMinute; + + if (stricmp(it->second.str(), "yes") == 0) + { + return TRUE; + } + return FALSE; +} + static OptionPreferences *pref = NULL; static void setDefaults( void ) @@ -1556,6 +1569,16 @@ static void saveOptions( void ) TheGlobalLanguageData->m_userResolutionFontSizeAdjustment = (Real)val / 100.0f; } + //------------------------------------------------------------------------------------------------- + // Set Money Per Minute + { + Bool show = pref->getShowMoneyPerMinute(); + AsciiString prefString; + prefString = show ? "yes" : "no"; + (*pref)["ShowMoneyPerMinute"] = prefString; + TheWritableGlobalData->m_showMoneyPerMinute = show; + } + //------------------------------------------------------------------------------------------------- // Resolution // diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp index 38eed0671f0..511a1007f63 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/SkirmishGameOptionsMenu.cpp @@ -330,7 +330,7 @@ Money SkirmishPreferences::getStartingCash(void) const } Money money; - money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE ); + money.deposit( strtoul( it->second.str(), NULL, 10 ), FALSE, FALSE ); return money; } @@ -1044,7 +1044,7 @@ static void handleStartingCashSelection() GadgetComboBoxGetSelectedPos(comboBoxStartingCash, &selIndex); Money startingCash; - startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE ); + startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE, FALSE ); myGame->setStartingCash( startingCash ); } } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp index 5768593797d..68deedca1c2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLGameSetupMenu.cpp @@ -767,7 +767,7 @@ static void handleStartingCashSelection() GadgetComboBoxGetSelectedPos(comboBoxStartingCash, &selIndex); Money startingCash; - startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE ); + startingCash.deposit( (UnsignedInt)GadgetComboBoxGetItemData( comboBoxStartingCash, selIndex ), FALSE, FALSE ); myGame->setStartingCash( startingCash ); myGame->resetAccepted(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp index bb8646aca07..2605d4155f7 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp @@ -97,6 +97,39 @@ // ------------------------------------------------------------------------------------------------ static const RGBColor IllegalBuildColor = { 1.0, 0.0, 0.0 }; +// ------------------------------------------------------------------------------------------------ +static UnicodeString formatMoneyValue(UnsignedInt amount) +{ + UnicodeString result; + if (amount >= 100000) + { + result.format(L"%uk", amount / 1000); + } + else + { + result.format(L"%u", amount); + } + return result; +} + +static UnicodeString formatIncomeValue(UnsignedInt cashPerMin) +{ + UnicodeString result; + if (cashPerMin >= 10000) + { + result.format(L"%uk", cashPerMin / 1000); + } + else if (cashPerMin >= 1000) + { + result.format(L"%u", (cashPerMin / 100) * 100); + } + else + { + result.format(L"%u", (cashPerMin / 10) * 10); + } + return result; +} + //------------------------------------------------------------------------------------------------- /// The InGameUI singleton instance. InGameUI *TheInGameUI = NULL; @@ -1886,7 +1919,8 @@ void InGameUI::update( void ) // update the player money window if the money amount has changed // this seems like as good a place as any to do the power hide/show - static Int lastMoney = -1; + static UnsignedInt lastMoney = ~0u; + static UnsignedInt lastIncome = ~0u; static NameKeyType moneyWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:MoneyDisplay" ); static NameKeyType powerWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:PowerWindow" ); @@ -1902,15 +1936,38 @@ void InGameUI::update( void ) Player* moneyPlayer = TheControlBar->getCurrentlyViewedPlayer(); if( moneyPlayer) { - Int currentMoney = moneyPlayer->getMoney()->countMoney(); - if( lastMoney != currentMoney ) + Money *money = moneyPlayer->getMoney(); + Bool showIncome = TheGlobalData->m_showMoneyPerMinute; + if (!showIncome) { - UnicodeString buffer; + UnsignedInt currentMoney = money->countMoney(); + if( lastMoney != currentMoney ) + { + UnicodeString buffer; - buffer.format( TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney ); - GadgetStaticTextSetText( moneyWin, buffer ); - lastMoney = currentMoney; + buffer.format(TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney ); + GadgetStaticTextSetText( moneyWin, buffer ); + lastMoney = currentMoney; + } + } + else + { + // TheSuperHackers @feature L3-M 21/08/2025 player money per minute + money->updateIncomeBucket(); + UnsignedInt currentMoney = money->countMoney(); + UnsignedInt cashPerMin = money->getCashPerMinute(); + if ( lastMoney != currentMoney || lastIncome != cashPerMin ) + { + UnicodeString buffer; + UnicodeString moneyStr = formatMoneyValue(currentMoney); + UnicodeString incomeStr = formatIncomeValue(cashPerMin); + + buffer.format(TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:ControlBarMoneyDisplayIncome", L"$ %ls +%ls/min", moneyStr.str(), incomeStr.str())); + GadgetStaticTextSetText(moneyWin, buffer); + lastMoney = currentMoney; + lastIncome = cashPerMin; + } } moneyWin->winHide(FALSE); powerWin->winHide(FALSE); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp index 37a5ee02bce..999dde93b3b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/ProductionUpdate.cpp @@ -360,7 +360,7 @@ void ProductionUpdate::cancelUpgrade( const UpgradeTemplate *upgrade ) // refund money back to the player Money *money = player->getMoney(); - money->deposit( production->m_upgradeToResearch->calcCostToBuild( player ) ); + money->deposit( production->m_upgradeToResearch->calcCostToBuild( player ), TRUE, FALSE ); // remove this production from the queue removeFromProductionQueue( production ); @@ -476,7 +476,7 @@ void ProductionUpdate::cancelUnitCreate( ProductionID productionID ) // give the player the cost of the object back Player *player = getObject()->getControllingPlayer(); Money *money = player->getMoney(); - money->deposit( production->m_objectToProduce->calcCostToBuild( player ) ); + money->deposit( production->m_objectToProduce->calcCostToBuild( player ), TRUE, FALSE ); // remove from queue list removeFromProductionQueue( production ); diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp index fa89fba3a37..0967db847b2 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp @@ -4082,7 +4082,7 @@ void ScriptActions::doSetMoney(const AsciiString& playerName, Int money) return; m->withdraw(m->countMoney()); - m->deposit(money); + m->deposit(money, FALSE, FALSE); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp index b680f82c4fc..f0c61e718e8 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogicDispatch.cpp @@ -1508,7 +1508,7 @@ void GameLogic::logicMessageDispatcher( GameMessage *msg, void *userData ) { Money *money = thisPlayer->getMoney(); UnsignedInt amount = building->getTemplate()->calcCostToBuild( thisPlayer ); - money->deposit( amount ); + money->deposit( amount, TRUE, FALSE ); } // diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp index 20298e65519..7e8e4c9a373 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp @@ -1126,7 +1126,7 @@ Bool ParseAsciiStringToGameInfo(GameInfo *game, AsciiString options) { UnsignedInt startingCashAmount = strtoul( val.str(), NULL, 10 ); startingCash.init(); - startingCash.deposit( startingCashAmount, FALSE ); + startingCash.deposit( startingCashAmount, FALSE, FALSE ); sawStartingCash = TRUE; } else if (key.compare("O") == 0 )