Skip to content

Commit a9e02ea

Browse files
committed
feat(display): Implement player money per minute
1 parent 487e5ce commit a9e02ea

File tree

10 files changed

+156
-13
lines changed

10 files changed

+156
-13
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,9 @@ class GlobalData : public SubsystemInterface
414414
Int m_systemTimeFontSize;
415415
Int m_gameTimeFontSize;
416416

417+
// TheSuperHackers @feature L3-M 21/08/2025 toggle the money per minute display, false shows only the original current money
418+
Bool m_showMoneyPerMinute;
419+
417420
Real m_shakeSubtleIntensity; ///< Intensity for shaking a camera with SHAKE_SUBTLE
418421
Real m_shakeNormalIntensity; ///< Intensity for shaking a camera with SHAKE_NORMAL
419422
Real m_shakeStrongIntensity; ///< Intensity for shaking a camera with SHAKE_STRONG

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ class Money : public Snapshot
6464

6565
public:
6666

67-
inline Money() : m_money(0), m_playerIndex(0)
67+
inline Money() : m_playerIndex(0)
6868
{
69+
init();
6970
}
7071

7172
void init()
7273
{
73-
m_money = 0;
74+
setStartingCash(0);
7475
}
7576

7677
inline UnsignedInt countMoney() const
@@ -82,6 +83,10 @@ class Money : public Snapshot
8283
UnsignedInt withdraw(UnsignedInt amountToWithdraw, Bool playSound = TRUE);
8384
void deposit(UnsignedInt amountToDeposit, Bool playSound = TRUE);
8485

86+
void setStartingCash(UnsignedInt amount);
87+
void updateIncomeBucket();
88+
UnsignedInt getCashPerMinute() const;
89+
8590
void setPlayerIndex(Int ndx) { m_playerIndex = ndx; }
8691

8792
static void parseMoneyAmount( INI *ini, void *instance, void *store, const void* userData );
@@ -105,6 +110,9 @@ class Money : public Snapshot
105110

106111
UnsignedInt m_money; ///< amount of money
107112
Int m_playerIndex; ///< what is my player index?
113+
UnsignedInt m_incomeBuckets[60]; ///< circular buffer of 60 seconds for income tracking
114+
UnsignedInt m_currentBucket;
115+
UnsignedInt m_cashPerMinute;
108116
};
109117

110118
#endif // _MONEY_H_

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ enum ObjectID CPP_11(: Int);
7070
enum DrawableID CPP_11(: Int);
7171

7272
#include <algorithm>
73+
#include <numeric>
7374
#include <bitset>
7475
#include <Utility/hash_map_adapter.h>
7576
#include <list>

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ class OptionPreferences : public UserPreferences
149149
Int getGameTimeFontSize(void);
150150

151151
Real getResolutionFontAdjustment(void);
152+
153+
Bool getShowMoneyPerMinute(void) const;
152154
};
153155

154156
//-----------------------------------------------------------------------------

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,8 @@ GlobalData::GlobalData()
947947
m_systemTimeFontSize = 8;
948948
m_gameTimeFontSize = 8;
949949

950+
m_showMoneyPerMinute = FALSE;
951+
950952
m_debugShowGraphicalFramerate = FALSE;
951953

952954
// By default, show all asserts.
@@ -1218,6 +1220,7 @@ void GlobalData::parseGameDataDefinition( INI* ini )
12181220
TheWritableGlobalData->m_renderFpsFontSize = optionPref.getRenderFpsFontSize();
12191221
TheWritableGlobalData->m_systemTimeFontSize = optionPref.getSystemTimeFontSize();
12201222
TheWritableGlobalData->m_gameTimeFontSize = optionPref.getGameTimeFontSize();
1223+
TheWritableGlobalData->m_showMoneyPerMinute = optionPref.getShowMoneyPerMinute();
12211224

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

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

Lines changed: 48 additions & 2 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)
@@ -86,6 +87,7 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound)
8687
if (playSound)
8788
{
8889
triggerAudioEvent(TheAudio->getMiscAudio()->m_moneyDepositSound);
90+
m_incomeBuckets[m_currentBucket] += amountToDeposit;
8991
}
9092

9193
m_money += amountToDeposit;
@@ -100,6 +102,35 @@ void Money::deposit(UnsignedInt amountToDeposit, Bool playSound)
100102
}
101103
}
102104

105+
// ------------------------------------------------------------------------------------------------
106+
void Money::setStartingCash(UnsignedInt amount)
107+
{
108+
m_money = amount;
109+
m_currentBucket = 0;
110+
std::fill(m_incomeBuckets, m_incomeBuckets + ARRAY_SIZE(m_incomeBuckets), 0u);
111+
m_cashPerMinute = 0u;
112+
}
113+
114+
// ------------------------------------------------------------------------------------------------
115+
void Money::updateIncomeBucket()
116+
{
117+
UnsignedInt frame = TheGameLogic->getFrame();
118+
UnsignedInt nextBucket = (frame / LOGICFRAMES_PER_SECOND) % ARRAY_SIZE(m_incomeBuckets);
119+
if (nextBucket != m_currentBucket)
120+
{
121+
m_cashPerMinute += m_incomeBuckets[m_currentBucket];
122+
m_cashPerMinute -= m_incomeBuckets[nextBucket];
123+
m_currentBucket = nextBucket;
124+
m_incomeBuckets[m_currentBucket] = 0u;
125+
}
126+
}
127+
128+
// ------------------------------------------------------------------------------------------------
129+
UnsignedInt Money::getCashPerMinute() const
130+
{
131+
return m_cashPerMinute;
132+
}
133+
103134
void Money::triggerAudioEvent(const AudioEventRTS& audioEvent)
104135
{
105136
Real volume = TheAudio->getAudioSettings()->m_preferredMoneyTransactionVolume;
@@ -131,13 +162,26 @@ void Money::xfer( Xfer *xfer )
131162
{
132163

133164
// version
134-
XferVersion currentVersion = 1;
165+
XferVersion currentVersion = 2;
135166
XferVersion version = currentVersion;
136167
xfer->xferVersion( &version, currentVersion );
137168

138169
// money value
139170
xfer->xferUnsignedInt( &m_money );
140171

172+
if (version >= 2)
173+
{
174+
xfer->xferUnsignedInt(&m_currentBucket);
175+
xfer->xferUser(m_incomeBuckets, sizeof(m_incomeBuckets));
176+
177+
m_cashPerMinute = 0u;
178+
for (UnsignedInt i = 0; i < ARRAY_SIZE(m_incomeBuckets); ++i)
179+
{
180+
if (i != m_currentBucket)
181+
m_cashPerMinute += m_incomeBuckets[i];
182+
}
183+
}
184+
141185
}
142186

143187
// ------------------------------------------------------------------------------------------------
@@ -156,5 +200,7 @@ void Money::parseMoneyAmount( INI *ini, void *instance, void *store, const void*
156200
{
157201
// Someday, maybe, have mulitple fields like Gold:10000 Wood:1000 Tiberian:10
158202
Money * money = (Money *)store;
159-
INI::parseUnsignedInt( ini, instance, &money->m_money, userData );
203+
UnsignedInt moneyAmount;
204+
INI::parseUnsignedInt( ini, instance, &moneyAmount, userData );
205+
money->setStartingCash(moneyAmount);
160206
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ AsciiString PlayerTemplate::getStartingUnit( Int i ) const
181181
// assign the money into the 'Money' (m_money) pointed to at 'store'
182182
Money *theMoney = (Money *)store;
183183
theMoney->init();
184-
theMoney->deposit( money );
184+
theMoney->setStartingCash(money);
185185

186186
}
187187

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,6 +968,19 @@ Real OptionPreferences::getResolutionFontAdjustment(void)
968968
return fontScale;
969969
}
970970

971+
Bool OptionPreferences::getShowMoneyPerMinute(void) const
972+
{
973+
OptionPreferences::const_iterator it = find("ShowMoneyPerMinute");
974+
if (it == end())
975+
return TheGlobalData->m_showMoneyPerMinute;
976+
977+
if (stricmp(it->second.str(), "yes") == 0)
978+
{
979+
return TRUE;
980+
}
981+
return FALSE;
982+
}
983+
971984
static OptionPreferences *pref = NULL;
972985

973986
static void setDefaults( void )
@@ -1556,6 +1569,15 @@ static void saveOptions( void )
15561569
TheGlobalLanguageData->m_userResolutionFontSizeAdjustment = (Real)val / 100.0f;
15571570
}
15581571

1572+
//-------------------------------------------------------------------------------------------------
1573+
// Set Money Per Minute
1574+
{
1575+
Bool showIncome = pref->getShowMoneyPerMinute();
1576+
AsciiString prefString;
1577+
prefString = showIncome ? "yes" : "no";
1578+
(*pref)["ShowMoneyPerMinute"] = prefString;
1579+
}
1580+
15591581
//-------------------------------------------------------------------------------------------------
15601582
// Resolution
15611583
//

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

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,40 @@
9797
// ------------------------------------------------------------------------------------------------
9898
static const RGBColor IllegalBuildColor = { 1.0, 0.0, 0.0 };
9999

100+
// ------------------------------------------------------------------------------------------------
101+
static UnicodeString formatMoneyValue(UnsignedInt amount)
102+
{
103+
UnicodeString result;
104+
if (amount >= 100000)
105+
{
106+
result.format(L"%dk", amount / 1000);
107+
}
108+
else
109+
{
110+
result.format(L"%d", amount);
111+
}
112+
return result;
113+
}
114+
115+
static UnicodeString formatIncomeValue(UnsignedInt cashPerMin)
116+
{
117+
UnicodeString result;
118+
if (cashPerMin >= 10000)
119+
{
120+
result.format(L"%dk", cashPerMin / 1000);
121+
}
122+
else if (cashPerMin >= 1000)
123+
{
124+
UnsignedInt k = cashPerMin / 100;
125+
result.format(L"%d.%dk", k / 10, k % 10);
126+
}
127+
else
128+
{
129+
result.format(L"%d", cashPerMin);
130+
}
131+
return result;
132+
}
133+
100134
//-------------------------------------------------------------------------------------------------
101135
/// The InGameUI singleton instance.
102136
InGameUI *TheInGameUI = NULL;
@@ -1893,6 +1927,7 @@ void InGameUI::update( void )
18931927
// update the player money window if the money amount has changed
18941928
// this seems like as good a place as any to do the power hide/show
18951929
static Int lastMoney = -1;
1930+
static Int lastIncome = -1;
18961931
static NameKeyType moneyWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:MoneyDisplay" );
18971932
static NameKeyType powerWindowKey = TheNameKeyGenerator->nameToKey( "ControlBar.wnd:PowerWindow" );
18981933

@@ -1908,15 +1943,38 @@ void InGameUI::update( void )
19081943
Player* moneyPlayer = TheControlBar->getCurrentlyViewedPlayer();
19091944
if( moneyPlayer)
19101945
{
1911-
Int currentMoney = moneyPlayer->getMoney()->countMoney();
1912-
if( lastMoney != currentMoney )
1946+
Money *money = moneyPlayer->getMoney();
1947+
Bool showIncome = TheGlobalData->m_showMoneyPerMinute;
1948+
if (!showIncome)
19131949
{
1914-
UnicodeString buffer;
1950+
Int currentMoney = money->countMoney();
1951+
if( lastMoney != currentMoney )
1952+
{
1953+
UnicodeString buffer;
19151954

1916-
buffer.format( TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney );
1917-
GadgetStaticTextSetText( moneyWin, buffer );
1918-
lastMoney = currentMoney;
1955+
buffer.format(TheGameText->fetch( "GUI:ControlBarMoneyDisplay" ), currentMoney );
1956+
GadgetStaticTextSetText( moneyWin, buffer );
1957+
lastMoney = currentMoney;
19191958

1959+
}
1960+
}
1961+
else
1962+
{
1963+
// TheSuperHackers @feature L3-M 21/08/2025 player money per minute
1964+
money->updateIncomeBucket();
1965+
UnsignedInt currentMoney = money->countMoney();
1966+
UnsignedInt cashPerMin = money->getCashPerMinute();
1967+
if (lastMoney != (Int)currentMoney || lastIncome != (Int)cashPerMin)
1968+
{
1969+
UnicodeString buffer;
1970+
UnicodeString moneyStr = formatMoneyValue(currentMoney);
1971+
UnicodeString incomeStr = formatIncomeValue(cashPerMin);
1972+
1973+
buffer.format(TheGameText->FETCH_OR_SUBSTITUTE_FORMAT("GUI:ControlBarMoneyDisplayIncome", L"$%ls +%ls/min", moneyStr.str(), incomeStr.str()));
1974+
GadgetStaticTextSetText(moneyWin, buffer);
1975+
lastMoney = currentMoney;
1976+
lastIncome = cashPerMin;
1977+
}
19201978
}
19211979
moneyWin->winHide(FALSE);
19221980
powerWin->winHide(FALSE);

GeneralsMD/Code/GameEngine/Source/GameLogic/ScriptEngine/ScriptActions.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4081,8 +4081,8 @@ void ScriptActions::doSetMoney(const AsciiString& playerName, Int money)
40814081
if (!m)
40824082
return;
40834083

4084-
m->withdraw(m->countMoney());
4085-
m->deposit(money);
4084+
m->withdraw(m->countMoney(), FALSE);
4085+
m->deposit(money, FALSE);
40864086
}
40874087

40884088
//-------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)