Skip to content

Commit 3d205cd

Browse files
VC/SA: Add Minimal HUD to VC, document it in SA
1 parent 8301635 commit 3d205cd

File tree

4 files changed

+175
-6
lines changed

4 files changed

+175
-6
lines changed

Config/SilentPatchSA.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ TrueInvincibility=0
2727
; Allows to override units used by the game - 0 forces metric units, 1 forces imperial units,
2828
; -1 makes the game use units based on system locale
2929
Units=-1
30+
; Enables an unfinished "minimal HUD" feature, where health, armour, weapon and money UI elements
31+
; fade out when inactive.
32+
MinimalHUD=0
3033
; Enables the sliding mission title text, based on remnants of this feature in the game code.
3134
SlidingMissionTitleText=0
3235
; Enables the sliding odd job text, based on remnants of this feature in the game code.

Config/SilentPatchVC.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Units=-1
77
; it also adds a siren to FBI Washington, corrects taxi sign light placement on Taxi
88
; and fixes placement of the search light and rear rotor light on Police Maverick.
99
EnableVehicleCoronaFixes=1
10+
; Enables an unfinished "minimal HUD" feature, where health, armour, weapon and money UI elements
11+
; fade out when inactive.
12+
MinimalHUD=0
1013
; Enables the sliding mission title text, based on remnants of this feature in the game code.
1114
SlidingMissionTitleText=0
1215
; Enables the sliding odd job text, based on remnants of this feature in the game code.

SilentPatchSA/SilentPatchSA.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1457,8 +1457,8 @@ static int64_t AudioUtilsGetCurrentTimeInMs()
14571457
return ((currentTime.QuadPart - UtilsStartTime.QuadPart) * 1000) / UtilsFrequency.QuadPart;
14581458
}
14591459

1460-
// Minimal HUD changes
1461-
namespace MinimalHud
1460+
// ============= Minimal HUD changes =============
1461+
namespace MinimalHUD
14621462
{
14631463
static CRGBA* __fastcall SetRGBA_FloatAlpha( CRGBA* rgba, void*, uint8_t red, uint8_t green, uint8_t blue, float alpha )
14641464
{
@@ -4146,9 +4146,9 @@ BOOL InjectDelayedPatches_10()
41464146
}
41474147

41484148
// Minimal HUD
4149-
if ( const int INIoption = GetPrivateProfileIntW(L"SilentPatch", L"MinimalHud", -1, wcModulePath); INIoption != -1 )
4149+
if ( const int INIoption = GetPrivateProfileIntW(L"SilentPatch", L"MinimalHUD", -1, wcModulePath); INIoption != -1 )
41504150
{
4151-
using namespace MinimalHud;
4151+
using namespace MinimalHUD;
41524152

41534153
// Fix original bugs
41544154
Patch( 0x58950E, { 0x90, 0xFF, 0x74, 0x24, 0x1C } );
@@ -4159,14 +4159,14 @@ BOOL InjectDelayedPatches_10()
41594159
InjectHook( 0x58D8FD, &RenderXLUSprite_FloatAlpha );
41604160

41614161
// Re-enable
4162-
if ( INIoption == 1 )
4162+
if ( INIoption != 0 )
41634163
{
41644164
Patch<int32_t>( 0x588905 + 1, 0 );
41654165
}
41664166

41674167
if ( bHasDebugMenu )
41684168
{
4169-
static bool bMinimalHUDEnabled = INIoption == 1;
4169+
static bool bMinimalHUDEnabled = INIoption != 0;
41704170
DebugMenuAddVar( "SilentPatch", "Minimal HUD", &bMinimalHUDEnabled, []() {
41714171
if ( bMinimalHUDEnabled )
41724172
{

SilentPatchVC/SilentPatchVC.cpp

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,59 @@ namespace SlidingTextsScalingFixes
526526
};
527527
}
528528

529+
530+
// ============= Minimal HUD changes =============
531+
namespace MinimalHUD
532+
{
533+
// Wanted level stars
534+
static void (*orgSetDropShadowPosition)(short);
535+
static void (*orgSetDropColor)(const CRGBA&);
536+
537+
static int8_t* pDropShadowSize;
538+
static int8_t* pDropShadowR;
539+
static int8_t* pDropShadowG;
540+
static int8_t* pDropShadowB;
541+
542+
static void (*orgSetColor)(const CRGBA&);
543+
static void SetColor_SetShadow(const CRGBA& color)
544+
{
545+
orgSetDropShadowPosition(*pDropShadowSize);
546+
orgSetDropColor(CRGBA(*pDropShadowR, *pDropShadowG, *pDropShadowB, color.a));
547+
orgSetColor(color);
548+
}
549+
550+
551+
// Show the energy values when losing armor
552+
static uint8_t* pPlayerInFocus;
553+
static uint32_t* pTimeLastArmorLoss;
554+
555+
static uint32_t LastTimeArmorLost;
556+
557+
static float (*orgDrawFadeState)(int state, int force);
558+
static float DrawFadeState_CheckArmor(int state, int force)
559+
{
560+
// This is a bit hacky, but we don't necessarily need better right now
561+
if (pTimeLastArmorLoss[92 * *pPlayerInFocus] != LastTimeArmorLost)
562+
{
563+
force = 1;
564+
LastTimeArmorLost = pTimeLastArmorLoss[92 * *pPlayerInFocus];
565+
}
566+
return orgDrawFadeState(state, force);
567+
}
568+
569+
570+
// Fade the weapon icon - fix the render state and pass the alpha parameter
571+
static void (*orgRenderOneXLUSprite)(float, float, float, float, float, uint8_t, uint8_t, uint8_t, int16_t, float, uint8_t);
572+
static void RenderOneXLUSprite_FloatAlpha(float arg1, float arg2, float arg3, float arg4, float arg5, uint8_t red, uint8_t green, uint8_t blue, int16_t mult, float arg10, float alpha)
573+
{
574+
RwScopedRenderState<rwRENDERSTATEVERTEXALPHAENABLE> vertexAlpha;
575+
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
576+
577+
orgRenderOneXLUSprite(arg1, arg2, arg3, arg4, arg5, red, green, blue, mult, arg10, static_cast<uint8_t>(alpha));
578+
}
579+
}
580+
581+
529582
float FixedRefValue()
530583
{
531584
return 1.0f;
@@ -1688,6 +1741,116 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
16881741
TXN_CATCH();
16891742

16901743

1744+
// Minimal HUD
1745+
if (const int INIoption = GetPrivateProfileIntW(L"SilentPatch", L"MinimalHUD", -1, wcModulePath); INIoption != -1) try
1746+
{
1747+
using namespace MinimalHUD;
1748+
1749+
// Fix original bugs
1750+
1751+
// Wanted level stars losing their shadow if health/armour counters are off
1752+
auto setColor_WantedStars = get_pattern("E8 ? ? ? ? DB 05 ? ? ? ? 8D 84 24 ? ? ? ? 59 50 50 D8 0D ? ? ? ? D8 0D ? ? ? ? D9 1C 24 FF 74 24 24");
1753+
1754+
// Get SetDropShadowPosition and SetDropColor with their corresponding parameters straight from the armor counter,
1755+
// to preserve the current behaviour
1756+
auto setDropShadow = pattern("6A ? E8 ? ? ? ? 59 8D 8C 24 ? ? ? ? 68 ? ? ? ? 6A ? 6A ? 6A ? E8 ? ? ? ? 8D 84 24 ? ? ? ? 50 E8").get_one();
1757+
1758+
1759+
// Show the energy values when losing armor
1760+
auto drawFadeState_Energy = get_pattern("6A 01 E8 ? ? ? ? DD D8", 2);
1761+
1762+
auto timeLastArmorLoss = pattern("0F B6 15 ? ? ? ? A1 ? ? ? ? 6B D2 2E 89 04 D5 ? ? ? ? D9 83").get_one();
1763+
1764+
1765+
// Fade the weapon icon - fix the render state and pass the alpha parameter
1766+
auto drawWeaponIconAlphaPush = get_pattern("68 FF 00 00 00 D8 0D ? ? ? ? FF 35");
1767+
auto renderOneXLUSprite = get_pattern("E8 ? ? ? ? 83 C4 2C 6A 00 6A 08");
1768+
1769+
1770+
// Stuff to let us (re)initialize
1771+
static void (*HUDReInitialise)() = static_cast<decltype(HUDReInitialise)>(get_pattern("31 C0 53 0F EF C0 C6 05"));
1772+
1773+
// This pattern has 5 hits - first 2 are in Reinitialise, the rest is in Initialise
1774+
auto reinitialise1 = pattern("C7 05 ? ? ? ? 05 00 00 00 66 C7 05 ? ? ? ? 00 00 C7 05 ? ? ? ? 00 00 00 00").count(5);
1775+
1776+
// This one covers the rest of Reinitialise
1777+
auto reinitialise2 = pattern("C7 05 ? ? ? ? 05 00 00 00 C6 05 ? ? ? ? 00 C7 05 ? ? ? ? 00 00 00 00").count(2);
1778+
1779+
// This one we touch only once, no need for static
1780+
const std::array<uint32_t*, 4> hudInitialiseVariables = {
1781+
reinitialise1.get(2).get<uint32_t>(6),
1782+
reinitialise1.get(3).get<uint32_t>(6),
1783+
reinitialise1.get(4).get<uint32_t>(6),
1784+
1785+
get_pattern<uint32_t>("8B 83 ? ? ? ? C7 05 ? ? ? ? 05 00 00 00", 6 + 6),
1786+
};
1787+
1788+
static const std::array<uint32_t*, 4> hudReinitialiseVariables = {
1789+
reinitialise1.get(0).get<uint32_t>(6),
1790+
reinitialise1.get(1).get<uint32_t>(6),
1791+
1792+
reinitialise2.get(0).get<uint32_t>(6),
1793+
reinitialise2.get(1).get<uint32_t>(6),
1794+
};
1795+
1796+
1797+
ReadCall(setDropShadow.get<void>(2), orgSetDropShadowPosition);
1798+
ReadCall(setDropShadow.get<void>(39), orgSetDropColor);
1799+
pDropShadowSize = setDropShadow.get<int8_t>(1);
1800+
pDropShadowB = setDropShadow.get<int8_t>(20 + 1);
1801+
pDropShadowG = setDropShadow.get<int8_t>(22 + 1);
1802+
pDropShadowR = setDropShadow.get<int8_t>(24 + 1);
1803+
InterceptCall(setColor_WantedStars, orgSetColor, SetColor_SetShadow);
1804+
1805+
1806+
pPlayerInFocus = *timeLastArmorLoss.get<uint8_t*>(3);
1807+
pTimeLastArmorLoss = *timeLastArmorLoss.get<uint32_t*>(0xF + 3);
1808+
InterceptCall(drawFadeState_Energy, orgDrawFadeState, DrawFadeState_CheckArmor);
1809+
1810+
1811+
// push 0FFh -> push dword ptr [esp+520h+var_4E0]
1812+
Patch(drawWeaponIconAlphaPush, { 0x90, 0xFF, 0x74, 0x24, 0x40 });
1813+
InterceptCall(renderOneXLUSprite, orgRenderOneXLUSprite, RenderOneXLUSprite_FloatAlpha);
1814+
1815+
if (INIoption != 0)
1816+
{
1817+
for (uint32_t* var : hudInitialiseVariables)
1818+
{
1819+
Patch<uint32_t>(var, 0);
1820+
}
1821+
for (uint32_t* var : hudReinitialiseVariables)
1822+
{
1823+
Patch<uint32_t>(var, 0);
1824+
}
1825+
}
1826+
1827+
if (bHasDebugMenu)
1828+
{
1829+
static bool bMinimalHUDEnabled = INIoption != 0;
1830+
DebugMenuAddVar("SilentPatch", "Minimal HUD", &bMinimalHUDEnabled, [] {
1831+
if (bMinimalHUDEnabled)
1832+
{
1833+
for (uint32_t* var : hudReinitialiseVariables)
1834+
{
1835+
Memory::VP::Patch<uint32_t>(var, 0);
1836+
}
1837+
}
1838+
else
1839+
{
1840+
for (uint32_t* var : hudReinitialiseVariables)
1841+
{
1842+
Memory::VP::Patch<uint32_t>(var, 5);
1843+
}
1844+
}
1845+
1846+
// Call CHud::ReInitialise
1847+
HUDReInitialise();
1848+
});
1849+
}
1850+
}
1851+
TXN_CATCH();
1852+
1853+
16911854
// Fix some big messages staying on screen longer at high resolutions due to a cut sliding text feature
16921855
// Also since we're touching it, optionally allow to re-enable this feature.
16931856
try

0 commit comments

Comments
 (0)