mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2025-01-01 16:53:01 +05:00
Compare commits
5 commits
6a524dcf46
...
9f705a3dc3
Author | SHA1 | Date | |
---|---|---|---|
|
9f705a3dc3 | ||
|
5aaec719ed | ||
|
cdcf979a54 | ||
|
2de40406d2 | ||
|
09bb67220e |
4 changed files with 197 additions and 166 deletions
|
@ -1,7 +1,7 @@
|
||||||
# SilentPatch
|
# SilentPatch
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img height="350" src="https://i.imgur.com/sCDzq12.png" alt="Logo">
|
<img src="https://i.imgur.com/sCDzq12.png" alt="Logo">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
SilentPatch for the 3D-era Grand Theft Auto games is the first and flagship release of the "SilentPatch family", providing numerous fixes for this beloved franchise.
|
SilentPatch for the 3D-era Grand Theft Auto games is the first and flagship release of the "SilentPatch family", providing numerous fixes for this beloved franchise.
|
||||||
|
|
|
@ -3073,9 +3073,7 @@ namespace MapScreenScalingFixes
|
||||||
((CursorYSize_Recalculated<I> = ScaleY(*orgCursorYSize<I>)), ...);
|
((CursorYSize_Recalculated<I> = ScaleY(*orgCursorYSize<I>)), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*orgLimitToMap)(float* x, float* y);
|
static void (*orgLimitToMap_Scale)(float* x, float* y);
|
||||||
|
|
||||||
template<std::size_t NumXSize, std::size_t NumYSize>
|
|
||||||
static void LimitToMap_Scale(float* x, float* y)
|
static void LimitToMap_Scale(float* x, float* y)
|
||||||
{
|
{
|
||||||
// LimitToMap assumes it's given scaled coordinates, but then the caller assumes it returns unscaled coordinates.
|
// LimitToMap assumes it's given scaled coordinates, but then the caller assumes it returns unscaled coordinates.
|
||||||
|
@ -3085,12 +3083,17 @@ namespace MapScreenScalingFixes
|
||||||
|
|
||||||
*x *= XScale;
|
*x *= XScale;
|
||||||
*y *= YScale;
|
*y *= YScale;
|
||||||
orgLimitToMap(x, y);
|
orgLimitToMap_Scale(x, y);
|
||||||
|
|
||||||
*x /= XScale;
|
*x /= XScale;
|
||||||
*y /= YScale;
|
*y /= YScale;
|
||||||
|
}
|
||||||
|
|
||||||
// This is also a comfortable spot to scale the cursor dimensions
|
static void (*orgLimitToMap_RecalculateSizes)(float* x, float* y);
|
||||||
|
template<std::size_t NumXSize, std::size_t NumYSize>
|
||||||
|
static void LimitToMap_RecalculateSizes(float* x, float* y)
|
||||||
|
{
|
||||||
|
orgLimitToMap_RecalculateSizes(x, y);
|
||||||
RecalculateXSize(std::make_index_sequence<NumXSize>{});
|
RecalculateXSize(std::make_index_sequence<NumXSize>{});
|
||||||
RecalculateYSize(std::make_index_sequence<NumYSize>{});
|
RecalculateYSize(std::make_index_sequence<NumYSize>{});
|
||||||
}
|
}
|
||||||
|
@ -4181,6 +4184,16 @@ BOOL InjectDelayedPatches_10()
|
||||||
|
|
||||||
const bool bHasDebugMenu = DebugMenuLoad();
|
const bool bHasDebugMenu = DebugMenuLoad();
|
||||||
|
|
||||||
|
auto PatchFloat = [](float** address, const float*& org, float& replaced)
|
||||||
|
{
|
||||||
|
org = *address;
|
||||||
|
Patch(address, &replaced);
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::initializer_list<uint8_t> fadd = { 0xD8, 0x05 };
|
||||||
|
const std::initializer_list<uint8_t> fsub = { 0xD8, 0x25 };
|
||||||
|
const std::initializer_list<uint8_t> fld = { 0xD9, 0x05 };
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
if ( bHasDebugMenu )
|
if ( bHasDebugMenu )
|
||||||
{
|
{
|
||||||
|
@ -4643,6 +4656,63 @@ BOOL InjectDelayedPatches_10()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||||
|
// Debugged by Wesser
|
||||||
|
// Moved here for compatibility with wshps.asi
|
||||||
|
{
|
||||||
|
using namespace MapScreenScalingFixes;
|
||||||
|
|
||||||
|
// Even though those two patch the same function, treating them as separate patches makes retaining compatibility
|
||||||
|
// with the widescreen fix easy.
|
||||||
|
if (MemEquals(0x588251, fld) && MemEquals(0x588265, fadd) && MemEquals(0x5882A8, fld) && MemEquals(0x5882C6, fadd))
|
||||||
|
{
|
||||||
|
std::array<float**, 2> cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) };
|
||||||
|
std::array<float**, 2> cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) };
|
||||||
|
|
||||||
|
HookEach_CursorXSize(cursorXSizes, PatchFloat);
|
||||||
|
HookEach_CursorYSize(cursorYSizes, PatchFloat);
|
||||||
|
InterceptCall(0x58822D, orgLimitToMap_RecalculateSizes, LimitToMap_RecalculateSizes<cursorXSizes.size(), cursorYSizes.size()>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only patch this function if wshps.asi hasn't changed the way it's being called
|
||||||
|
// The expected code:
|
||||||
|
// lea edx, [esp+70h+a1.y]
|
||||||
|
// push edx
|
||||||
|
// lea eax, [esp+74h+a1]
|
||||||
|
// push eax
|
||||||
|
if (MemEquals(0x588223, {0x8D, 0x54, 0x24, 0x4C, 0x52, 0x8D, 0x44, 0x24, 0x4C, 0x50 }))
|
||||||
|
{
|
||||||
|
InterceptCall(0x58822D, orgLimitToMap_Scale, LimitToMap_Scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fix text background padding not scaling to resolution
|
||||||
|
// Debugged by Wesser
|
||||||
|
// Moved here for compatibility with wshps.asi
|
||||||
|
{
|
||||||
|
using namespace TextRectPaddingScalingFixes;
|
||||||
|
|
||||||
|
// Verify that all fadd and fsub instructions are intact
|
||||||
|
// Patterns would do it for us for free, but 1.0 does not use them...
|
||||||
|
if (MemEquals(0x71A653, fadd) && MemEquals(0x71A66B, fadd) && MemEquals(0x71A69D, fsub) && MemEquals(0x71A6AB, fadd) &&
|
||||||
|
MemEquals(0x71A6BF, fsub) && MemEquals(0x71A6EC, fadd))
|
||||||
|
{
|
||||||
|
std::array<float**, 4> paddingXSizes = {
|
||||||
|
(float**)(0x71A653 + 2), (float**)(0x71A66B + 2),
|
||||||
|
(float**)(0x71A69D + 2), (float**)(0x71A6AB + 2),
|
||||||
|
};
|
||||||
|
std::array<float**, 2> paddingYSizes = {
|
||||||
|
(float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2),
|
||||||
|
};
|
||||||
|
|
||||||
|
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
||||||
|
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
||||||
|
InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale<paddingXSizes.size(), paddingYSizes.size()>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if ( const int QPCDays = GetPrivateProfileIntW(L"Debug", L"AddDaysToQPC", 0, wcModulePath); QPCDays != 0 )
|
if ( const int QPCDays = GetPrivateProfileIntW(L"Debug", L"AddDaysToQPC", 0, wcModulePath); QPCDays != 0 )
|
||||||
{
|
{
|
||||||
|
@ -5027,6 +5097,12 @@ BOOL InjectDelayedPatches_NewBinaries()
|
||||||
|
|
||||||
const bool bHasDebugMenu = DebugMenuLoad();
|
const bool bHasDebugMenu = DebugMenuLoad();
|
||||||
|
|
||||||
|
auto PatchDouble = [](double** address, const double*& org, double& replaced)
|
||||||
|
{
|
||||||
|
org = *address;
|
||||||
|
Patch(address, &replaced);
|
||||||
|
};
|
||||||
|
|
||||||
// Race condition in CdStream fixed
|
// Race condition in CdStream fixed
|
||||||
// Not taking effect with modloader
|
// Not taking effect with modloader
|
||||||
//if ( !ModCompat::ModloaderCdStreamRaceConditionAware( modloaderModule ) )
|
//if ( !ModCompat::ModloaderCdStreamRaceConditionAware( modloaderModule ) )
|
||||||
|
@ -5123,6 +5199,61 @@ BOOL InjectDelayedPatches_NewBinaries()
|
||||||
TXN_CATCH();
|
TXN_CATCH();
|
||||||
|
|
||||||
|
|
||||||
|
// Fix Map screen boundaries and the cursor not scaling to resolution
|
||||||
|
// Debugged by Wesser
|
||||||
|
// Moved here for compatibility with wshps.asi
|
||||||
|
{
|
||||||
|
using namespace MapScreenScalingFixes;
|
||||||
|
|
||||||
|
// These two are entirely separate fixes
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Updated the pattern to also ensure this function's arguments are not changed by other mods
|
||||||
|
auto limitToMap = get_pattern("8D 45 F0 50 8B CA 51 E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C", 7);
|
||||||
|
InterceptCall(limitToMap, orgLimitToMap_Scale, LimitToMap_Scale);
|
||||||
|
}
|
||||||
|
TXN_CATCH();
|
||||||
|
|
||||||
|
// Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one();
|
||||||
|
auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one();
|
||||||
|
|
||||||
|
Nop(scaleX.get<void>(), 1);
|
||||||
|
InjectHook(scaleX.get<void>(1), ScaleX_NewBinaries, HookType::Call);
|
||||||
|
|
||||||
|
Nop(scaleY.get<void>(), 1);
|
||||||
|
InjectHook(scaleY.get<void>(1), ScaleY_NewBinaries, HookType::Call);
|
||||||
|
}
|
||||||
|
TXN_CATCH();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Fix text background padding not scaling to resolution
|
||||||
|
// Debugged by Wesser
|
||||||
|
// Moved here for compatibility with wshps.asi
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using namespace TextRectPaddingScalingFixes;
|
||||||
|
|
||||||
|
auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08");
|
||||||
|
|
||||||
|
// In new binaries, 4.0f is shared for width and height.
|
||||||
|
// Make height determine the scale, so it works nicer in widescreen.
|
||||||
|
auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2);
|
||||||
|
std::array<double**, 3> paddingYSizes = {
|
||||||
|
get_pattern<double*>("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2),
|
||||||
|
paddingSize.get(0).get<double*>(2),
|
||||||
|
paddingSize.get(1).get<double*>(2),
|
||||||
|
};
|
||||||
|
|
||||||
|
HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble);
|
||||||
|
InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries<paddingYSizes.size()>);
|
||||||
|
}
|
||||||
|
TXN_CATCH();
|
||||||
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -6270,39 +6401,6 @@ void Patch_SA_10(HINSTANCE hInstance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
|
||||||
// Debugged by Wesser
|
|
||||||
{
|
|
||||||
using namespace MapScreenScalingFixes;
|
|
||||||
|
|
||||||
std::array<float**, 2> cursorXSizes = { (float**)(0x588251 + 2), (float**)(0x588265 + 2) };
|
|
||||||
std::array<float**, 2> cursorYSizes = { (float**)(0x5882A8 + 2), (float**)(0x5882C6 + 2) };
|
|
||||||
|
|
||||||
HookEach_CursorXSize(cursorXSizes, PatchFloat);
|
|
||||||
HookEach_CursorYSize(cursorYSizes, PatchFloat);
|
|
||||||
InterceptCall(0x58822D, orgLimitToMap, LimitToMap_Scale<cursorXSizes.size(), cursorYSizes.size()>);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Fix text background padding not scaling to resolution
|
|
||||||
// Debugged by Wesser
|
|
||||||
{
|
|
||||||
using namespace TextRectPaddingScalingFixes;
|
|
||||||
|
|
||||||
std::array<float**, 4> paddingXSizes = {
|
|
||||||
(float**)(0x71A653 + 2), (float**)(0x71A66B + 2),
|
|
||||||
(float**)(0x71A69D + 2), (float**)(0x71A6AB + 2),
|
|
||||||
};
|
|
||||||
std::array<float**, 2> paddingYSizes = {
|
|
||||||
(float**)(0x71A6BF + 2), (float**)(0x71A6EC + 2),
|
|
||||||
};
|
|
||||||
|
|
||||||
HookEach_PaddingXSize(paddingXSizes, PatchFloat);
|
|
||||||
HookEach_PaddingYSize(paddingYSizes, PatchFloat);
|
|
||||||
InterceptCall(0x71A631, orgProcessCurrentString, ProcessCurrentString_Scale<paddingXSizes.size(), paddingYSizes.size()>);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Fix nitrous recharging faster when reversing the car
|
// Fix nitrous recharging faster when reversing the car
|
||||||
// By Wesser
|
// By Wesser
|
||||||
{
|
{
|
||||||
|
@ -8482,52 +8580,6 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
|
||||||
TXN_CATCH();
|
TXN_CATCH();
|
||||||
|
|
||||||
|
|
||||||
// Fix Map screen boundaries and the cursor not scaling to resolution
|
|
||||||
// Debugged by Wesser
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using namespace MapScreenScalingFixes;
|
|
||||||
|
|
||||||
auto limitToMap = get_pattern("E8 ? ? ? ? DB 05 ? ? ? ? 83 C4 1C");
|
|
||||||
|
|
||||||
// Cursor X/Y scaling need to be done differently than in 1.0, as the game has one fld1 for width and one fld1 for height
|
|
||||||
auto scaleX = pattern("D9 E8 DC E9 D9 C9 D9 5D 94").get_one();
|
|
||||||
auto scaleY = pattern("D9 E8 DC E9 D9 C9 D9 5D B0").get_one();
|
|
||||||
|
|
||||||
InterceptCall(limitToMap, orgLimitToMap, LimitToMap_Scale<0, 0>);
|
|
||||||
|
|
||||||
Nop(scaleX.get<void>(), 1);
|
|
||||||
InjectHook(scaleX.get<void>(1), ScaleX_NewBinaries, HookType::Call);
|
|
||||||
|
|
||||||
Nop(scaleY.get<void>(), 1);
|
|
||||||
InjectHook(scaleY.get<void>(1), ScaleY_NewBinaries, HookType::Call);
|
|
||||||
}
|
|
||||||
TXN_CATCH();
|
|
||||||
|
|
||||||
|
|
||||||
// Fix text background padding not scaling to resolution
|
|
||||||
// Debugged by Wesser
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using namespace TextRectPaddingScalingFixes;
|
|
||||||
|
|
||||||
auto processCurrentString = get_pattern("E8 ? ? ? ? DD 05 ? ? ? ? 8B 4D 08");
|
|
||||||
|
|
||||||
// In new binaries, 4.0f is shared for width and height.
|
|
||||||
// Make height determine the scale, so it works nicer in widescreen.
|
|
||||||
auto paddingSize = pattern("DD 05 ? ? ? ? DC E9 D9 C9 D9 19").count(2);
|
|
||||||
std::array<double**, 3> paddingYSizes = {
|
|
||||||
get_pattern<double*>("D8 CA DD 05 ? ? ? ? DC C1", 2 + 2),
|
|
||||||
paddingSize.get(0).get<double*>(2),
|
|
||||||
paddingSize.get(1).get<double*>(2),
|
|
||||||
};
|
|
||||||
|
|
||||||
HookEach_PaddingYSize_Double(paddingYSizes, PatchDouble);
|
|
||||||
InterceptCall(processCurrentString, orgProcessCurrentString, ProcessCurrentString_Scale_NewBinaries<paddingYSizes.size()>);
|
|
||||||
}
|
|
||||||
TXN_CATCH();
|
|
||||||
|
|
||||||
|
|
||||||
// Fix nitrous recharging faster when reversing the car
|
// Fix nitrous recharging faster when reversing the car
|
||||||
// By Wesser
|
// By Wesser
|
||||||
try
|
try
|
||||||
|
|
|
@ -582,66 +582,56 @@ void CAutomobile::AfterPreRender()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAutomobile::HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int nodeID, unsigned int modelID)
|
void CAutomobile::HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int, unsigned int modelID)
|
||||||
{
|
{
|
||||||
auto hideWheel = [this](int nodeID)
|
auto trySpawnAndHideWheel = [this, spawnFlyingComponentCB, modelID](int nodeID)
|
||||||
{
|
{
|
||||||
bool bHasWheel = false;
|
|
||||||
|
|
||||||
RwFrame* wheelNode = m_pCarNode[nodeID];
|
RwFrame* wheelNode = m_pCarNode[nodeID];
|
||||||
if (wheelNode != nullptr)
|
if (wheelNode != nullptr)
|
||||||
{
|
{
|
||||||
RwFrameForAllObjects(wheelNode, [&bHasWheel](RwObject* object)
|
bool bWheelVisible = false;
|
||||||
|
RwFrameForAllObjects(wheelNode, [&bWheelVisible](RwObject* object) -> RwObject*
|
||||||
{
|
{
|
||||||
if ((rwObjectGetFlags(object) & rpATOMICRENDER) != 0)
|
if ((rwObjectGetFlags(object) & rpATOMICRENDER) != 0)
|
||||||
{
|
{
|
||||||
rwObjectSetFlags(object, 0);
|
bWheelVisible = true;
|
||||||
bHasWheel = true;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (bWheelVisible)
|
||||||
|
{
|
||||||
|
std::invoke(spawnFlyingComponentCB, this, nodeID, modelID);
|
||||||
|
RwFrameForAllObjects(wheelNode, [](RwObject* object)
|
||||||
|
{
|
||||||
|
rwObjectSetFlags(object, 0);
|
||||||
|
return object;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return bHasWheel;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if (m_DamageManager.GetWheelStatus(0) == 2)
|
if (m_DamageManager.GetWheelStatus(0) == 2)
|
||||||
{
|
{
|
||||||
if (hideWheel(5))
|
trySpawnAndHideWheel(5);
|
||||||
{
|
|
||||||
std::invoke(spawnFlyingComponentCB, this, 5, modelID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_DamageManager.GetWheelStatus(2) == 2)
|
if (m_DamageManager.GetWheelStatus(2) == 2)
|
||||||
{
|
{
|
||||||
if (hideWheel(2))
|
trySpawnAndHideWheel(2);
|
||||||
{
|
|
||||||
std::invoke(spawnFlyingComponentCB, this, 2, modelID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For rear wheels, also hide and spawn the middle wheel (if it exists)
|
// For rear wheels, also hide and spawn the middle wheel (if it exists)
|
||||||
if (m_DamageManager.GetWheelStatus(1) == 2)
|
if (m_DamageManager.GetWheelStatus(1) == 2)
|
||||||
{
|
{
|
||||||
if (hideWheel(6))
|
trySpawnAndHideWheel(6);
|
||||||
{
|
trySpawnAndHideWheel(7);
|
||||||
std::invoke(spawnFlyingComponentCB, this, 6, modelID);
|
|
||||||
}
|
|
||||||
if (hideWheel(7))
|
|
||||||
{
|
|
||||||
std::invoke(spawnFlyingComponentCB, this, 7, modelID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (m_DamageManager.GetWheelStatus(3) == 2)
|
if (m_DamageManager.GetWheelStatus(3) == 2)
|
||||||
{
|
{
|
||||||
if (hideWheel(3))
|
trySpawnAndHideWheel(3);
|
||||||
{
|
trySpawnAndHideWheel(4);
|
||||||
std::invoke(spawnFlyingComponentCB, this, 3, modelID);
|
|
||||||
}
|
|
||||||
if (hideWheel(4))
|
|
||||||
{
|
|
||||||
std::invoke(spawnFlyingComponentCB, this, 4, modelID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -211,32 +211,9 @@ namespace PrintStringShadows
|
||||||
namespace RadardiscFixes
|
namespace RadardiscFixes
|
||||||
{
|
{
|
||||||
static const float RADARDISC_SHRINK = 2.0f; // We are shrinking the radardisc by that
|
static const float RADARDISC_SHRINK = 2.0f; // We are shrinking the radardisc by that
|
||||||
|
|
||||||
template<std::size_t Index>
|
|
||||||
static const float* orgRadarXPos;
|
|
||||||
|
|
||||||
template<std::size_t Index>
|
static float orgRadarXPosVal;
|
||||||
static float RadarXPos_Recalculated;
|
static float* orgRadarXPosPtr;
|
||||||
|
|
||||||
template<std::size_t... I>
|
|
||||||
static void RecalculateXPositions(std::index_sequence<I...>)
|
|
||||||
{
|
|
||||||
const float multiplier = GetWidthMult() * RsGlobal->MaximumWidth;
|
|
||||||
((RadarXPos_Recalculated<I> = *orgRadarXPos<I> * multiplier), ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t Index>
|
|
||||||
static const float* orgRadarYPos;
|
|
||||||
|
|
||||||
template<std::size_t Index>
|
|
||||||
static float RadarYPos_Recalculated;
|
|
||||||
|
|
||||||
template<std::size_t... I>
|
|
||||||
static void RecalculateYPositions(std::index_sequence<I...>)
|
|
||||||
{
|
|
||||||
const float multiplier = GetHeightMult() * RsGlobal->MaximumHeight;
|
|
||||||
((RadarYPos_Recalculated<I> = *orgRadarYPos<I> * multiplier), ...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t Index>
|
template<std::size_t Index>
|
||||||
static const float* orgRadarXPos_RadardiscShrink;
|
static const float* orgRadarXPos_RadardiscShrink;
|
||||||
|
@ -265,18 +242,15 @@ namespace RadardiscFixes
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*orgDrawMap)();
|
static void (*orgDrawMap)();
|
||||||
template<std::size_t NumXPos, std::size_t NumYPos, std::size_t NumXPosRadardisc, std::size_t NumYPosRadardisc>
|
template<std::size_t NumXPosRadardisc, std::size_t NumYPosRadardisc>
|
||||||
static void DrawMap_RecalculatePositions()
|
static void DrawMap_RecalculatePositions()
|
||||||
{
|
{
|
||||||
RecalculateXPositions(std::make_index_sequence<NumXPos>{});
|
*orgRadarXPosPtr = orgRadarXPosVal * GetWidthMult() * RsGlobal->MaximumWidth;
|
||||||
RecalculateYPositions(std::make_index_sequence<NumYPos>{});
|
|
||||||
RecalculateXPositions_RadardiscShrink(std::make_index_sequence<NumXPosRadardisc>{});
|
RecalculateXPositions_RadardiscShrink(std::make_index_sequence<NumXPosRadardisc>{});
|
||||||
RecalculateYPositions_RadardiscShrink(std::make_index_sequence<NumYPosRadardisc>{});
|
RecalculateYPositions_RadardiscShrink(std::make_index_sequence<NumYPosRadardisc>{});
|
||||||
orgDrawMap();
|
orgDrawMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
HOOK_EACH_INIT(CalculateRadarXPos, orgRadarXPos, RadarXPos_Recalculated);
|
|
||||||
HOOK_EACH_INIT(CalculateRadarYPos, orgRadarYPos, RadarYPos_Recalculated);
|
|
||||||
HOOK_EACH_INIT(CalculateRadarXPos_RadardiscShrink, orgRadarXPos_RadardiscShrink, RadarXPos_Recalculated_RadardiscShrink);
|
HOOK_EACH_INIT(CalculateRadarXPos_RadardiscShrink, orgRadarXPos_RadardiscShrink, RadarXPos_Recalculated_RadardiscShrink);
|
||||||
HOOK_EACH_INIT(CalculateRadarYPos_RadardiscShrink, orgRadarYPos_RadardiscShrink, RadarYPos_Recalculated_RadardiscShrink);
|
HOOK_EACH_INIT(CalculateRadarYPos_RadardiscShrink, orgRadarYPos_RadardiscShrink, RadarYPos_Recalculated_RadardiscShrink);
|
||||||
|
|
||||||
|
@ -1537,21 +1511,9 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
||||||
{
|
{
|
||||||
using namespace RadardiscFixes;
|
using namespace RadardiscFixes;
|
||||||
|
|
||||||
auto draw_entity_coord_blip = pattern("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 5C 24 18").count(2);
|
|
||||||
auto draw_radar_disc1 = pattern("D8 25 ? ? ? ? DD DB D9 C2 D9 9C 24 ? ? ? ? DB 05 ? ? ? ? D8 0D ? ? ? ? D8 0D ? ? ? ? D8 05 ? ? ? ? D8 05").count(2);
|
auto draw_radar_disc1 = pattern("D8 25 ? ? ? ? DD DB D9 C2 D9 9C 24 ? ? ? ? DB 05 ? ? ? ? D8 0D ? ? ? ? D8 0D ? ? ? ? D8 05 ? ? ? ? D8 05").count(2);
|
||||||
auto draw_radar_disc2 = pattern("D8 C1 D8 05 ? ? ? ? D9 9C 24 ? ? ? ? DE D9 DD D8").count(2);
|
auto draw_radar_disc2 = pattern("D8 C1 D8 05 ? ? ? ? D9 9C 24 ? ? ? ? DE D9 DD D8").count(2);
|
||||||
|
|
||||||
std::array<float**, 8> radarXPos = {
|
|
||||||
get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2),
|
|
||||||
get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C EC 30", 2),
|
|
||||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 9C C4", 6 + 2),
|
|
||||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 D9 5C 24 08", 6 + 2),
|
|
||||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 DD D9 DB 44 24 18", 6 + 2),
|
|
||||||
get_pattern<float*>("D8 0D ? ? ? ? D8 05 ? ? ? ? DE C1 DD DB DB 44 24 18", 6 + 2),
|
|
||||||
draw_entity_coord_blip.get(0).get<float*>(6 + 2),
|
|
||||||
draw_entity_coord_blip.get(1).get<float*>(6 + 2),
|
|
||||||
};
|
|
||||||
|
|
||||||
std::array<float**, 4> radarXPos_RadardiscShrink = {
|
std::array<float**, 4> radarXPos_RadardiscShrink = {
|
||||||
draw_radar_disc1.get(0).get<float*>(35 + 2),
|
draw_radar_disc1.get(0).get<float*>(35 + 2),
|
||||||
draw_radar_disc1.get(0).get<float*>(35 + 6 + 2),
|
draw_radar_disc1.get(0).get<float*>(35 + 6 + 2),
|
||||||
|
@ -1574,13 +1536,18 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
||||||
drawRadarDiscSprite.get(1).get<void>(17),
|
drawRadarDiscSprite.get(1).get<void>(17),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Use exactly the same patterns as widescreen fix
|
||||||
|
float* radarPos = *get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2);
|
||||||
|
std::array<float**, 2> youAreHereSize = {
|
||||||
|
get_pattern<float*>("DD D9 D9 05 ? ? ? ? D8 C9 D9 7C 24 04", 2 + 2),
|
||||||
|
get_pattern<float*>("8B 5C 24 18 D8 0D ? ? ? ? D8 0D ? ? ? ? D9 7C 24 04", 10 + 2),
|
||||||
|
};
|
||||||
|
|
||||||
// Undo the damage caused by IVRadarScaling from the widescreen fix moving the radar way too far to the right
|
// Undo the damage caused by IVRadarScaling from the widescreen fix moving the radar way too far to the right
|
||||||
// It's moved from 40.0f to 71.0f, which is way too much now that we're scaling the horizontal placement correctly!
|
// It's moved from 40.0f to 71.0f, which is way too much now that we're scaling the horizontal placement correctly!
|
||||||
// This is removed from the most up-to-date widescreen fix, but keep it so we don't break with older builds.
|
// This is removed from the most up-to-date widescreen fix, but keep it so we don't break with older builds.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Use exactly the same patterns as widescreen fix
|
|
||||||
float* radarPos = *get_pattern<float*>("D8 05 ? ? ? ? DE C1 D9 5C 24 28", 2);
|
|
||||||
// No need to undo CRadar::DrawYouAreHereSprite, as wsfix keeps it as 40.0f
|
// No need to undo CRadar::DrawYouAreHereSprite, as wsfix keeps it as 40.0f
|
||||||
|
|
||||||
// This hardcodes a patched constant inside so the pattern will fail to match without IV radar scaling
|
// This hardcodes a patched constant inside so the pattern will fail to match without IV radar scaling
|
||||||
|
@ -1604,11 +1571,33 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
|
||||||
}
|
}
|
||||||
TXN_CATCH();
|
TXN_CATCH();
|
||||||
|
|
||||||
HookEach_CalculateRadarXPos(radarXPos, PatchFloat);
|
// Normally we would "wrap" the global variable 40.0f used as a X radar position, but that causes issues with plugin-sdk.
|
||||||
HookEach_CalculateRadarXPos_RadardiscShrink(radarXPos_RadardiscShrink, PatchFloat);
|
// Vice City inlined CRadar::TransformRadarPointToScreenSpace and plugin-sdk reimplements it using this global directly, so we need to patch it.
|
||||||
HookEach_CalculateRadarYPos_RadardiscShrink(radarYPos_RadardiscShrink, PatchFloat);
|
// Therefore, we instead do the following:
|
||||||
HookEach_DrawRadarDisc(spriteDraw, InterceptCall);
|
// 1. Patch the float directly, reading the original value once and rescaling as usual in-place.
|
||||||
InterceptCall(drawMap, orgDrawMap, DrawMap_RecalculatePositions<radarXPos.size(), 0, radarXPos_RadardiscShrink.size(), radarYPos_RadardiscShrink.size()>);
|
// 2. If CRadar::DrawYouAreHereSprite still points at the same global variable, give it a dedicated one.
|
||||||
|
// Otherwise do nothing, as some other mod (like the wsfix above) may have already done it.
|
||||||
|
// 3. If we can't safely change the radar position because it was relocated, bail out of the fix entirely, just to be safe.
|
||||||
|
// Missing out on a fix is better than breaking something.
|
||||||
|
if (hGameModule == ModCompat::Utils::GetModuleHandleFromAddress(radarPos))
|
||||||
|
{
|
||||||
|
static float fYouAreHereSize;
|
||||||
|
orgRadarXPosVal = fYouAreHereSize = *radarPos;
|
||||||
|
orgRadarXPosPtr = radarPos;
|
||||||
|
|
||||||
|
for (float** val : youAreHereSize)
|
||||||
|
{
|
||||||
|
if (*val == radarPos)
|
||||||
|
{
|
||||||
|
Patch(val, &fYouAreHereSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HookEach_CalculateRadarXPos_RadardiscShrink(radarXPos_RadardiscShrink, PatchFloat);
|
||||||
|
HookEach_CalculateRadarYPos_RadardiscShrink(radarYPos_RadardiscShrink, PatchFloat);
|
||||||
|
HookEach_DrawRadarDisc(spriteDraw, InterceptCall);
|
||||||
|
InterceptCall(drawMap, orgDrawMap, DrawMap_RecalculatePositions<radarXPos_RadardiscShrink.size(), radarYPos_RadardiscShrink.size()>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TXN_CATCH();
|
TXN_CATCH();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue