III/VC/SA: Fix credits scaling and timing

This commit is contained in:
Silent 2024-10-10 18:53:36 +02:00
parent 2b64e74069
commit 5cb14580b5
No known key found for this signature in database
GPG Key ID: AE53149BB0C45AF1
3 changed files with 283 additions and 10 deletions

View File

@ -99,15 +99,15 @@ static const void* SubtitlesShadowFix_JumpBack;
auto WorldRemove = reinterpret_cast<void(*)(void*)>(hook::get_pattern("8A 43 50 56 24 07", -5)); auto WorldRemove = reinterpret_cast<void(*)(void*)>(hook::get_pattern("8A 43 50 56 24 07", -5));
static const float& ResolutionWidthMult = **AddressByVersion<float**>(0x57E956, 0x57ECA6, 0x57EBA6); float GetWidthMult()
inline float GetWidthMult()
{ {
static const float& ResolutionWidthMult = **AddressByVersion<float**>(0x57E956, 0x57ECA6, 0x57EBA6);
return ResolutionWidthMult; return ResolutionWidthMult;
} }
static const float& ResolutionHeightMult = **AddressByVersion<float**>(0x57E940, 0x57EC90, 0x57EB90); float GetHeightMult()
inline float GetHeightMult()
{ {
static const float& ResolutionHeightMult = **AddressByVersion<float**>(0x57E940, 0x57EC90, 0x57EB90);
return ResolutionHeightMult; return ResolutionHeightMult;
} }
@ -987,6 +987,29 @@ namespace OnscreenCounterBarFixes
HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated); HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated);
} }
// ============= Fix credits not scaling to resolution =============
namespace CreditsScalingFixes
{
static const unsigned int FIXED_RES_HEIGHT_SCALE = 448;
template<std::size_t Index>
static void (*orgPrintString)(float,float,const wchar_t*);
template<std::size_t Index>
static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText)
{
orgPrintString<Index>(fX, fY * GetHeightMult() * RsGlobal->MaximumHeight, pText);
}
static void (*orgSetScale)(float X, float Y);
static void SetScale_ScaleToRes(float X, float Y)
{
orgSetScale(X * GetWidthMult() * RsGlobal->MaximumWidth, Y * GetHeightMult() * RsGlobal->MaximumHeight);
}
HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY);
}
namespace ModelIndicesReadyHook namespace ModelIndicesReadyHook
{ {
static void (*orgInitialiseObjectData)(const char*); static void (*orgInitialiseObjectData)(const char*);
@ -1252,6 +1275,41 @@ void InjectDelayedPatches_III_Common( bool bHasDebugMenu, const wchar_t* wcModul
} }
TXN_CATCH(); TXN_CATCH();
// Fix credits not scaling to resolution
try
{
using namespace CreditsScalingFixes;
std::array<void*, 1> creditPrintString = {
get_pattern("D9 1C 24 E8 ? ? ? ? 83 C4 0C 8B 03", 3),
};
auto setScale = get_pattern("E8 ? ? ? ? 8B 44 24 28 59 59");
// Credits are timed for 640x480, but the PC version scales to 640x448 internally - speed credits up a bit,
// especially since ours are longer and even the PS2 version cuts them a bit late.
float** creditsSpeed = get_pattern<float*>("D8 0D ? ? ? ? D9 5D E8", 2);
// As we now scale everything on PrintString time, the resolution height checks need to be unscaled.
void* resHeightScales[] = {
get_pattern("DF 6C 24 08 DB 05 ? ? ? ? D8 05", 4 + 2),
get_pattern("8B 35 ? ? ? ? 03 75 F4", 2),
};
HookEach_PrintString(creditPrintString, InterceptCall);
InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes);
static float newSpeed = **creditsSpeed * (480.0f/448.0f);
Patch(creditsSpeed, &newSpeed);
for (void* addr : resHeightScales)
{
Patch(addr, &FIXED_RES_HEIGHT_SCALE);
}
}
TXN_CATCH();
FLAUtils::Init(moduleList); FLAUtils::Init(moduleList);
} }

View File

@ -322,6 +322,21 @@ struct AlphaObjectInfo
{ return a.fCompareValue < b.fCompareValue; } { return a.fCompareValue < b.fCompareValue; }
}; };
struct PsGlobalType;
struct RsGlobalType
{
const char* AppName;
signed int MaximumWidth;
signed int MaximumHeight;
unsigned int frameLimit;
BOOL quit;
PsGlobalType* ps;
void* keyboard;
void* mouse;
void* pad;
};
// Other wrappers // Other wrappers
void (*GTAdelete)(void*) = AddressByVersion<void(*)(void*)>(0x82413F, 0x824EFF, 0x85E58C); void (*GTAdelete)(void*) = AddressByVersion<void(*)(void*)>(0x82413F, 0x824EFF, 0x85E58C);
const char* (*GetFrameNodeName)(RwFrame*) = AddressByVersion<const char*(*)(RwFrame*)>(0x72FB30, 0x730360, 0x769C20); const char* (*GetFrameNodeName)(RwFrame*) = AddressByVersion<const char*(*)(RwFrame*)>(0x72FB30, 0x730360, 0x769C20);
@ -345,6 +360,8 @@ auto WorldRemove = AddressByVersion<void(*)(CEntity*)>(0x563280, 0, 0x57D37
// SA variables // SA variables
void** rwengine = *AddressByVersion<void***>(0x58FFC0, 0x53F032, 0x48C194, { "8B 48 20 53 56 57 6A 01", -5 + 1 }); void** rwengine = *AddressByVersion<void***>(0x58FFC0, 0x53F032, 0x48C194, { "8B 48 20 53 56 57 6A 01", -5 + 1 });
RsGlobalType* RsGlobal = *AddressByVersion<RsGlobalType**>(0x619602 + 2, { "33 C0 C7 05 ? ? ? ? ? ? ? ? C7 05", 2 + 2 });
unsigned char& nGameClockDays = **AddressByVersion<unsigned char**>(0x4E841D, 0x4E886D, 0x4F3871); unsigned char& nGameClockDays = **AddressByVersion<unsigned char**>(0x4E841D, 0x4E886D, 0x4F3871);
unsigned char& nGameClockMonths = **AddressByVersion<unsigned char**>(0x4E842D, 0x4E887D, 0x4F3861); unsigned char& nGameClockMonths = **AddressByVersion<unsigned char**>(0x4E842D, 0x4E887D, 0x4F3861);
void*& pUserTracksStuff = **AddressByVersion<void***>(0x4D9B7B, 0x4DA06C, 0x4E4A43); void*& pUserTracksStuff = **AddressByVersion<void***>(0x4D9B7B, 0x4DA06C, 0x4E4A43);
@ -468,6 +485,39 @@ static CAEWaveDecoder* __stdcall CAEWaveDecoderInit(CAEDataStream* pStream)
return new CAEWaveDecoder(pStream); return new CAEWaveDecoder(pStream);
} }
namespace ScalingInternals
{
// 1.0 - fast math uses a scaling multiplier
float ScaleX_Multiplier(float val)
{
static const float& ResolutionWidthMult = **(float**)(0x43CF57 + 2);
return val * RsGlobal->MaximumWidth * ResolutionWidthMult;
}
float ScaleY_Multiplier(float val)
{
static const float& ResolutionHeightMult = **(float**)(0x43CF47 + 2);
return val * RsGlobal->MaximumHeight * ResolutionHeightMult;
}
// New binaries - precise math uses a scaling divisor
float ScaleX_Divisor(float val)
{
static const double& ResolutionWidthDiv = **hook::get_pattern<double*>("DC 35 ? ? ? ? DC 0D ? ? ? ? DE E9 D9 5D F0", 2);
return static_cast<float>(val * RsGlobal->MaximumWidth / ResolutionWidthDiv);
}
float ScaleY_Divisor(float val)
{
static const double& ResolutionHeightDiv = **hook::get_pattern<double*>("50 DC 35 ? ? ? ? DC 0D", 1 + 2);
return static_cast<float>(val * RsGlobal->MaximumHeight / ResolutionHeightDiv);
}
}
// Default to 1.0, update these pointers with a pointer to the new binaries function if needed
auto ScaleX = &ScalingInternals::ScaleX_Multiplier;
auto ScaleY = &ScalingInternals::ScaleY_Multiplier;
namespace ScriptFixes namespace ScriptFixes
{ {
@ -2759,6 +2809,38 @@ namespace NewResolutionSelectionDialog
} }
// ============= Fix credits not scaling to resolution =============
// Also makes the shadow scale properly, as they haven't done that either...
// But since this seems to be the only place, don't pull in the fix from Vice City,
// fix it here instead
namespace CreditsScalingFixes
{
static const unsigned int FIXED_RES_HEIGHT_SCALE = 448;
template<std::size_t Index>
static void (*orgPrintString)(float,float,const wchar_t*);
template<std::size_t Index>
static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText)
{
if constexpr (Index == 1)
{
// Fix the shadow X scale - the Y scale will be fixed below
fX = fX + 1.0f - ScaleX(1.0f);
}
orgPrintString<Index>(fX, ScaleY(fY), pText);
}
static void (*orgSetScale)(float X, float Y);
static void SetScale_ScaleToRes(float X, float Y)
{
orgSetScale(ScaleX(X), ScaleY(Y));
}
HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY);
}
// ============= LS-RP Mode stuff ============= // ============= LS-RP Mode stuff =============
namespace LSRPMode namespace LSRPMode
{ {
@ -5614,6 +5696,29 @@ void Patch_SA_10(HINSTANCE hInstance)
} }
// Fix credits not scaling to resolution
{
using namespace CreditsScalingFixes;
std::array<uintptr_t, 2> creditPrintString = { 0x5A8707, 0x5A8785 };
HookEach_PrintString(creditPrintString, InterceptCall);
InterceptCall(0x5A86C0, orgSetScale, SetScale_ScaleToRes);
// Fix the credits cutting off on the bottom early, they don't do that in III
// but it regressed in VC and SA
static const float topMargin = 1.0f;
static const float bottomMargin = -(**(float**)(0x5A869A + 2));
Patch(0x5A8689 + 2, &topMargin);
Patch(0x5A869A + 2, &bottomMargin);
// As we now scale everything on PrintString time, the resolution height checks need to be unscaled.
Patch(0x5A8660 + 2, &FIXED_RES_HEIGHT_SCALE);
Patch(0x5AF8C9 + 2, &FIXED_RES_HEIGHT_SCALE);
}
#if FULL_PRECISION_D3D #if FULL_PRECISION_D3D
// Test - full precision D3D device // Test - full precision D3D device
Patch<uint8_t>( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE ); Patch<uint8_t>( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE );
@ -6374,6 +6479,9 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
using namespace Memory; using namespace Memory;
using namespace hook::txn; using namespace hook::txn;
ScaleX = &ScalingInternals::ScaleX_Divisor;
ScaleY = &ScalingInternals::ScaleY_Divisor;
try try
{ {
void* isAlreadyRunning = get_pattern( "85 C0 74 08 33 C0 8B E5 5D C2 10 00", -5 ); void* isAlreadyRunning = get_pattern( "85 C0 74 08 33 C0 8B E5 5D C2 10 00", -5 );
@ -7635,6 +7743,40 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
InjectHook(rwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings); InjectHook(rwEngineGetCurrentSubSystem, RwEngineGetCurrentSubSystem_FromSettings);
} }
TXN_CATCH(); TXN_CATCH();
// Fix credits not scaling to resolution
{
using namespace CreditsScalingFixes;
std::array<void*, 2> creditPrintString = {
get_pattern("E8 ? ? ? ? 83 C4 0C 80 7D 1C 00"),
get_pattern("D9 1C 24 E8 ? ? ? ? DD 05 ? ? ? ? 83 C4 0C 5E", 3),
};
auto setScale = get_pattern("D9 1C 24 E8 ? ? ? ? 83 C4 08 68 FF 00 00 00 6A 00 6A 00 6A 00", 3);
// Fix the credits cutting off on the bottom early, they don't do that in III
// but it regressed in VC and SA
auto positionOffset = get_pattern("DE C2 D9 45 18 DE EA D9 C9 D9 5D 14 D9 05", 12 + 2);
// As we now scale everything on PrintString time, the resolution height checks need to be unscaled.
void* resHeightScales[] = {
get_pattern("DB 05 ? ? ? ? 57 8B 7D 14", 2),
get_pattern("A1 ? ? ? ? 03 45 FC 89 45 F4", 1)
};
static const float topMargin = 1.0f;
Patch(positionOffset, &topMargin);
HookEach_PrintString(creditPrintString, InterceptCall);
InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes);
for (void* addr : resHeightScales)
{
Patch(addr, &FIXED_RES_HEIGHT_SCALE);
}
}
} }

View File

@ -72,13 +72,13 @@ void* (*GetModelInfo)(const char*, int*);
CVehicleModelInfo**& ms_modelInfoPtrs = *hook::get_pattern<CVehicleModelInfo**>("8B 15 ? ? ? ? 8D 04 24", 2); CVehicleModelInfo**& ms_modelInfoPtrs = *hook::get_pattern<CVehicleModelInfo**>("8B 15 ? ? ? ? 8D 04 24", 2);
int32_t& numModelInfos = *hook::get_pattern<int32_t>("81 FD ? ? ? ? 7C B7", 2); int32_t& numModelInfos = *hook::get_pattern<int32_t>("81 FD ? ? ? ? 7C B7", 2);
inline float GetWidthMult() float GetWidthMult()
{ {
static const float& ResolutionWidthMult = **AddressByVersion<float**>(0x5FA15E, 0x5FA17E, 0x5F9DBE); static const float& ResolutionWidthMult = **AddressByVersion<float**>(0x5FA15E, 0x5FA17E, 0x5F9DBE);
return ResolutionWidthMult; return ResolutionWidthMult;
} }
inline float GetHeightMult() float GetHeightMult()
{ {
static const float& ResolutionHeightMult = **AddressByVersion<float**>(0x5FA148, 0x5FA168, 0x5F9DA8); static const float& ResolutionHeightMult = **AddressByVersion<float**>(0x5FA148, 0x5FA168, 0x5F9DA8);
return ResolutionHeightMult; return ResolutionHeightMult;
@ -176,6 +176,21 @@ namespace PrintStringShadows
} }
}; };
template<uintptr_t pFltX>
struct XMinus
{
static inline void (*orgPrintString)(float,float,const wchar_t*);
static void PrintString(float fX, float fY, const wchar_t* pText)
{
PrintString_Internal(orgPrintString, fX, fY, -(**margin<pFltX>), 0.0f, pText);
}
static void Hook(uintptr_t addr)
{
Memory::DynBase::InterceptCall(addr, orgPrintString, PrintString);
}
};
template<uintptr_t pFltY> template<uintptr_t pFltY>
struct Y struct Y
{ {
@ -429,6 +444,28 @@ namespace LoadingBarOutlineFixes
HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated); HOOK_EACH_INIT(YPos, orgYPos, YPos_Recalculated);
} }
// ============= Fix credits not scaling to resolution =============
namespace CreditsScalingFixes
{
static const unsigned int FIXED_RES_HEIGHT_SCALE = 448;
template<std::size_t Index>
static void (*orgPrintString)(float,float,const wchar_t*);
template<std::size_t Index>
static void PrintString_ScaleY(float fX, float fY, const wchar_t* pText)
{
orgPrintString<Index>(fX, fY * GetHeightMult() * RsGlobal->MaximumHeight, pText);
}
static void (*orgSetScale)(float X, float Y);
static void SetScale_ScaleToRes(float X, float Y)
{
orgSetScale(X * GetWidthMult() * RsGlobal->MaximumWidth, Y * GetHeightMult() * RsGlobal->MaximumHeight);
}
HOOK_EACH_INIT(PrintString, orgPrintString, PrintString_ScaleY);
}
float FixedRefValue() float FixedRefValue()
{ {
@ -1555,6 +1592,42 @@ void InjectDelayedPatches_VC_Common( bool bHasDebugMenu, const wchar_t* wcModule
TXN_CATCH(); TXN_CATCH();
// Fix credits not scaling to resolution
try
{
using namespace CreditsScalingFixes;
std::array<void*, 2> creditPrintString = {
get_pattern("E8 ? ? ? ? 83 C4 0C 8D 4C 24 14"),
get_pattern("E8 ? ? ? ? 83 C4 0C 8B 03"),
};
auto setScale = get_pattern("E8 ? ? ? ? 59 59 8D 4C 24 10");
// Fix the credits cutting off on the bottom early, they don't do that in III
// but it regressed in VC and SA
auto positionOffset = pattern("D8 1D ? ? ? ? DF E0 F6 C4 45 0F 85 ? ? ? ? 89 4C 24 08 DB 44 24 08 D8 25").get_one();
// As we now scale everything on PrintString time, the resolution height checks need to be unscaled.
void* resHeightScales[] = {
get_pattern("8B 0D ? ? ? ? 8B 03", 2),
get_pattern("8B 0D ? ? ? ? C7 44 24 ? ? ? ? ? 03 4C 24 14 ", 2),
};
static const float floatStorage[2] = { 1.0f, -(**positionOffset.get<float*>(0x19 + 2)) };
Patch(positionOffset.get<void>(2), &floatStorage[0]);
Patch(positionOffset.get<void>(0x19 + 2), &floatStorage[0]);
HookEach_PrintString(creditPrintString, InterceptCall);
InterceptCall(setScale, orgSetScale, SetScale_ScaleToRes);
for (void* addr : resHeightScales)
{
Patch(addr, &FIXED_RES_HEIGHT_SCALE);
}
}
TXN_CATCH();
FLAUtils::Init(moduleList); FLAUtils::Init(moduleList);
} }
@ -1600,7 +1673,7 @@ void Patch_VC_10(uint32_t width, uint32_t height)
using namespace PrintStringShadows; using namespace PrintStringShadows;
XY<0x5FA1F6, 0x5FA1D5>::Hook(0x5FA1FD); XY<0x5FA1F6, 0x5FA1D5>::Hook(0x5FA1FD);
XYMinus<0x544727, 0x544727>::Hook(0x54474D); XMinus<0x544727/*, 0x544727*/>::Hook(0x54474D); // Don't patch Y as we're doing it in the credits scale fix
} }
// Mouse fucking fix! // Mouse fucking fix!
@ -1688,7 +1761,7 @@ void Patch_VC_11(uint32_t width, uint32_t height)
using namespace PrintStringShadows; using namespace PrintStringShadows;
XY<0x5FA216, 0x5FA1F5>::Hook(0x5FA21D); XY<0x5FA216, 0x5FA1F5>::Hook(0x5FA21D);
XYMinus<0x544747, 0x544747>::Hook(0x54476D); XMinus<0x544747/*, 0x544747*/>::Hook(0x54476D); // Don't patch Y as we're doing it in the credits scale fix
} }
// Mouse fucking fix! // Mouse fucking fix!
@ -1775,7 +1848,7 @@ void Patch_VC_Steam(uint32_t width, uint32_t height)
using namespace PrintStringShadows; using namespace PrintStringShadows;
XY<0x5F9E56, 0x5F9E35>::Hook(0x5F9E5D); XY<0x5F9E56, 0x5F9E35>::Hook(0x5F9E5D);
XYMinus<0x544617, 0x544617>::Hook(0x54463D); XMinus<0x544617/*, 0x544617*/>::Hook(0x54463D); // Don't patch Y as we're doing it in the credits scale fix
} }
// Mouse fucking fix! // Mouse fucking fix!