Skip to content

Commit aa4a814

Browse files
committed
feat(display): Implement player money per minute
1 parent a4a57a2 commit aa4a814

File tree

9 files changed

+145
-8
lines changed

9 files changed

+145
-8
lines changed

GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,9 @@ class GlobalData : public SubsystemInterface
405405
Bool m_saveCameraInReplay;
406406
Bool m_useCameraInReplay;
407407

408+
// TheSuperHackers @feature L3-M 21/08/2025 toggle the money per minute display; 'no' shows only the original current money
409+
Bool m_moneyPerMinute;
410+
408411
// TheSuperHackers @feature Mauller 21/06/2025 allow the system time and game time font size to be set, a size of zero disables them
409412
Int m_systemTimeFontSize;
410413
Int m_gameTimeFontSize;

GeneralsMD/Code/GameEngine/Include/Common/Money.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,24 @@ class Money : public Snapshot
6464

6565
public:
6666

67-
inline Money() : m_money(0), m_playerIndex(0)
67+
inline Money() : m_money(0), m_playerIndex(0), m_startingCash(0), m_currentBucket(0), m_lastBucketFrame(0)
6868
{
69+
for (UnsignedInt i = 0; i < 60; ++i)
70+
{
71+
m_incomeBuckets[i] = 0;
72+
}
6973
}
7074

7175
void init()
7276
{
7377
m_money = 0;
78+
m_startingCash = 0;
79+
m_currentBucket = 0;
80+
m_lastBucketFrame = 0;
81+
for (UnsignedInt i = 0; i < 60; ++i)
82+
{
83+
m_incomeBuckets[i] = 0;
84+
}
7485
}
7586

7687
inline UnsignedInt countMoney() const
@@ -82,6 +93,10 @@ class Money : public Snapshot
8293
UnsignedInt withdraw(UnsignedInt amountToWithdraw, Bool playSound = TRUE);
8394
void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE);
8495

96+
void setStartingCash(UnsignedInt amount);
97+
void updateIncomeBucket();
98+
UnsignedInt getCashPerMinute() const;
99+
85100
void setPlayerIndex(Int ndx) { m_playerIndex = ndx; }
86101

87102
static void parseMoneyAmount( INI *ini, void *instance, void *store, const void* userData );
@@ -105,6 +120,10 @@ class Money : public Snapshot
105120

106121
UnsignedInt m_money; ///< amount of money
107122
Int m_playerIndex; ///< what is my player index?
123+
UnsignedInt m_startingCash;
124+
UnsignedInt m_incomeBuckets[60];
125+
UnsignedInt m_currentBucket;
126+
UnsignedInt m_lastBucketFrame;
108127
};
109128

110129
#endif // _MONEY_H_

GeneralsMD/Code/GameEngine/Include/Common/UserPreferences.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ class OptionPreferences : public UserPreferences
128128
Bool getFPSLimitEnabled(void);
129129
Bool getNoDynamicLODEnabled(void);
130130
Bool getBuildingOcclusionEnabled(void);
131+
Bool getMoneyPerMinute(void);
131132
Int getParticleCap(void);
132133

133134
Int getCampaignDifficulty(void);

GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,8 @@ GlobalData::GlobalData()
934934
m_saveCameraInReplay = FALSE;
935935
m_useCameraInReplay = FALSE;
936936

937+
m_moneyPerMinute = TRUE;
938+
937939
m_systemTimeFontSize = 8;
938940
m_gameTimeFontSize = 8;
939941

@@ -1203,6 +1205,7 @@ void GlobalData::parseGameDataDefinition( INI* ini )
12031205

12041206
TheWritableGlobalData->m_systemTimeFontSize = optionPref.getSystemTimeFontSize();
12051207
TheWritableGlobalData->m_gameTimeFontSize = optionPref.getGameTimeFontSize();
1208+
TheWritableGlobalData->m_moneyPerMinute = optionPref.getMoneyPerMinute();
12061209

12071210
Int val=optionPref.getGammaValue();
12081211
//generate a value between 0.6 and 2.0.

GeneralsMD/Code/GameEngine/Source/Common/RTS/Money.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include "Common/Player.h"
5252
#include "Common/PlayerList.h"
5353
#include "Common/Xfer.h"
54+
#include "GameLogic/GameLogic.h"
5455

5556
// ------------------------------------------------------------------------------------------------
5657
UnsignedInt Money::withdraw(UnsignedInt amountToWithdraw, Bool playSound)
@@ -89,6 +90,7 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound)
8990
}
9091

9192
m_money += amountToDeposit;
93+
m_incomeBuckets[m_currentBucket] += amountToDeposit;
9294

9395
if( amountToDeposit > 0 )
9496
{
@@ -100,6 +102,46 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound)
100102
}
101103
}
102104

105+
// ------------------------------------------------------------------------------------------------
106+
void Money::setStartingCash(UnsignedInt amount)
107+
{
108+
m_startingCash = amount;
109+
m_money = amount;
110+
m_currentBucket = 0;
111+
m_lastBucketFrame = 0;
112+
for (UnsignedInt i = 0; i < 60; ++i)
113+
m_incomeBuckets[i] = 0;
114+
}
115+
116+
// ------------------------------------------------------------------------------------------------
117+
void Money::updateIncomeBucket()
118+
{
119+
UnsignedInt frame = TheGameLogic->getFrame();
120+
UnsignedInt lastSec = m_lastBucketFrame / LOGICFRAMES_PER_SECOND;
121+
UnsignedInt curSec = frame / LOGICFRAMES_PER_SECOND;
122+
UnsignedInt diff = (curSec > lastSec) ? curSec - lastSec : 0;
123+
if (diff > 0)
124+
{
125+
if (diff > 60)
126+
diff = 60;
127+
for (UnsignedInt i = 0; i < diff; ++i)
128+
{
129+
m_currentBucket = (m_currentBucket + 1) % 60;
130+
m_incomeBuckets[m_currentBucket] = 0;
131+
}
132+
}
133+
m_lastBucketFrame = frame;
134+
}
135+
136+
// ------------------------------------------------------------------------------------------------
137+
UnsignedInt Money::getCashPerMinute() const
138+
{
139+
UnsignedInt sum = 0;
140+
for (UnsignedInt i = 0; i < 60; ++i)
141+
sum += m_incomeBuckets[i];
142+
return sum;
143+
}
144+
103145
void Money::triggerAudioEvent(const AudioEventRTS& audioEvent)
104146
{
105147
Real volume = TheAudio->getAudioSettings()->m_preferredMoneyTransactionVolume;
@@ -157,4 +199,5 @@ void Money::parseMoneyAmount( INI *ini, void *instance, void *store, const void*
157199
// Someday, maybe, have mulitple fields like Gold:10000 Wood:1000 Tiberian:10
158200
Money * money = (Money *)store;
159201
INI::parseUnsignedInt( ini, instance, &money->m_money, userData );
202+
money->setStartingCash(money->m_money);
160203
}

GeneralsMD/Code/GameEngine/Source/Common/RTS/Player.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,7 @@ void Player::init(const PlayerTemplate* pt)
462462
{
463463
m_money.deposit( TheGlobalData->m_defaultStartingCash.countMoney(), FALSE );
464464
}
465+
m_money.setStartingCash(m_money.countMoney());
465466
}
466467

467468
m_playerDisplayName.clear();

GeneralsMD/Code/GameEngine/Source/Common/RTS/PlayerTemplate.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ AsciiString PlayerTemplate::getStartingUnit( Int i ) const
182182
Money *theMoney = (Money *)store;
183183
theMoney->init();
184184
theMoney->deposit( money );
185+
theMoney->setStartingCash(money);
185186

186187
} // end parseStartMoney
187188

GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,19 @@ Int OptionPreferences::getGameTimeFontSize(void)
828828
return fontSize;
829829
}
830830

831+
Bool OptionPreferences::getMoneyPerMinute(void)
832+
{
833+
OptionPreferences::const_iterator it = find("MoneyPerMinute");
834+
if (it == end())
835+
return TheGlobalData->m_moneyPerMinute;
836+
837+
if (stricmp(it->second.str(), "yes") == 0)
838+
{
839+
return TRUE;
840+
}
841+
return FALSE;
842+
}
843+
831844
static OptionPreferences *pref = NULL;
832845

833846
static void setDefaults( void )
@@ -1354,6 +1367,15 @@ static void saveOptions( void )
13541367
TheInGameUI->refreshGameTimeResources();
13551368
}
13561369

1370+
//-------------------------------------------------------------------------------------------------
1371+
// Set Money Per Minute
1372+
{
1373+
Bool showIncome = pref->getMoneyPerMinute();
1374+
AsciiString prefString;
1375+
prefString = showIncome ? "yes" : "no";
1376+
(*pref)["MoneyPerMinute"] = prefString;
1377+
}
1378+
13571379
//-------------------------------------------------------------------------------------------------
13581380
// Resolution
13591381
//

GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,6 +1837,7 @@ void InGameUI::update( void )
18371837
// update the player money window if the money amount has changed
18381838
// this seems like as good a place as any to do the power hide/show
18391839
static Int lastMoney = -1;
1840+
static Int lastIncome = -1;
18401841
static NameKeyType moneyWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:MoneyDisplay" );
18411842
static NameKeyType powerWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:PowerWindow" );
18421843

@@ -1852,16 +1853,59 @@ void InGameUI::update( void )
18521853
Player* moneyPlayer = TheControlBar->getCurrentlyViewedPlayer();
18531854
if( moneyPlayer)
18541855
{
1855-
Int currentMoney = moneyPlayer->getMoney()->countMoney();
1856-
if( lastMoney != currentMoney )
1856+
Money *money = moneyPlayer->getMoney();
1857+
Bool showIncome = TheGlobalData->m_moneyPerMinute;
1858+
if (!showIncome)
18571859
{
1858-
UnicodeString buffer;
1860+
Int currentMoney = money->countMoney();
1861+
if( lastMoney != currentMoney )
1862+
{
1863+
UnicodeString buffer;
18591864

1860-
buffer.format( TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney );
1861-
GadgetStaticTextSetText( moneyWin, buffer );
1862-
lastMoney = currentMoney;
1865+
buffer.format(TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney );
1866+
GadgetStaticTextSetText( moneyWin, buffer );
1867+
lastMoney = currentMoney;
18631868

1864-
} // end if
1869+
} // end if
1870+
}
1871+
else
1872+
{
1873+
// TheSuperHackers @feature L3-M 21/08/2025 player money per minute
1874+
money->updateIncomeBucket();
1875+
UnsignedInt currentMoney = money->countMoney();
1876+
UnsignedInt cashPerMin = money->getCashPerMinute();
1877+
if (lastMoney != (Int)currentMoney || lastIncome != (Int)cashPerMin)
1878+
{
1879+
UnicodeString buffer;
1880+
UnicodeString moneyStr;
1881+
UnicodeString incomeStr;
1882+
if (currentMoney >= 100000)
1883+
{
1884+
moneyStr.format(L"%dK", currentMoney / 1000);
1885+
}
1886+
else
1887+
{
1888+
moneyStr.format(L"%d", currentMoney);
1889+
}
1890+
if (cashPerMin >= 10000)
1891+
{
1892+
incomeStr.format(L"%dK", cashPerMin / 1000);
1893+
}
1894+
else if (cashPerMin >= 1000)
1895+
{
1896+
UnsignedInt k = cashPerMin / 100;
1897+
incomeStr.format(L"%d.%dK", k / 10, k % 10);
1898+
}
1899+
else
1900+
{
1901+
incomeStr.format(L"%d", cashPerMin);
1902+
}
1903+
buffer.format(TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:ControlBarMoneyDisplayIncome", L"%ls (%ls)", moneyStr.str(), incomeStr.str()));
1904+
GadgetStaticTextSetText(moneyWin, buffer);
1905+
lastMoney = currentMoney;
1906+
lastIncome = cashPerMin;
1907+
}
1908+
}
18651909
moneyWin->winHide(FALSE);
18661910
powerWin->winHide(FALSE);
18671911
}

0 commit comments

Comments
 (0)