Updated newsteam patches to use patterns, adding RGL support

Newsteam r1/r2 specific patches are now alll gone
This commit is contained in:
Silent 2019-09-22 12:15:29 +02:00
parent 31ab59e578
commit 082a9e7156
No known key found for this signature in database
GPG key ID: AE53149BB0C45AF1
2 changed files with 423 additions and 476 deletions

@ -1 +1 @@
Subproject commit 5558e968814daac337afc7f735dcc203d7efc884 Subproject commit b5e3512b90603784a8d4bb8a865eba5b1e5cd032

View file

@ -914,7 +914,7 @@ static char** pStencilShadowsPad = *AddressByVersion<char***>(0x70FC4F, 0, 0x75E
void StencilShadowAlloc( ) void StencilShadowAlloc( )
{ {
static char* pMemory = [] () {; static char* pMemory = [] () {;
char* mem = static_cast<char*>( orgNewAlloc( 3 * 0x6000 ) ); char* mem = static_cast<char*>( ::operator new( 3 * 0x6000 ) );
pStencilShadowsPad[0] = mem; pStencilShadowsPad[0] = mem;
pStencilShadowsPad[1] = mem+0x6000; pStencilShadowsPad[1] = mem+0x6000;
pStencilShadowsPad[2] = mem+(2*0x6000); pStencilShadowsPad[2] = mem+(2*0x6000);
@ -3679,6 +3679,7 @@ void Patch_SA_10()
Patch<DWORD>(&(*(DWORD**)0x438513)[34], 0xE5FC92C3); Patch<DWORD>(&(*(DWORD**)0x438513)[34], 0xE5FC92C3);
// No DirectPlay dependency // No DirectPlay dependency
// mov eax, 0x900
Patch<BYTE>(AddressByRegion_10<DWORD>(0x74754A), 0xB8); Patch<BYTE>(AddressByRegion_10<DWORD>(0x74754A), 0xB8);
Patch<DWORD>(AddressByRegion_10<DWORD>(0x74754B), 0x900); Patch<DWORD>(AddressByRegion_10<DWORD>(0x74754B), 0x900);
@ -3698,17 +3699,20 @@ void Patch_SA_10()
Nop(0x58BA8F, 6); Nop(0x58BA8F, 6);
// Fixed lens flare // Fixed lens flare
Patch<DWORD>(0x70F45A, 0); Patch<DWORD>(0x70F45A, 0); // TODO: Is this needed?
Patch<BYTE>(0x6FB621, 0xC3); Patch<BYTE>(0x6FB621, 0xC3); // nop CSprite::FlushSpriteBuffer
// Add CSprite::FlushSpriteBuffer, jmp loc_6FB605 at the bottom of the function
Patch<BYTE>(0x6FB600, 0x21); Patch<BYTE>(0x6FB600, 0x21);
InjectHook(0x6FB622, 0x70CF20, PATCH_CALL); InjectHook(0x6FB622, 0x70CF20, PATCH_CALL);
Patch<WORD>(0x6FB627, 0xDCEB); Patch<WORD>(0x6FB627, 0xDCEB);
// nop / mov eax, offset FlushLensSwitchZ
Patch<WORD>(0x6FB476, 0xB990); Patch<WORD>(0x6FB476, 0xB990);
Patch(0x6FB478, &FlushLensSwitchZ); Patch(0x6FB478, &FlushLensSwitchZ);
Patch<WORD>(0x6FB480, 0xD1FF); Patch<WORD>(0x6FB480, 0xD1FF);
Nop(0x6FB482, 1); Nop(0x6FB482, 1);
// nop / mov ecx, offset InitBufferSwitchZ
Patch<WORD>(0x6FAF28, 0xB990); Patch<WORD>(0x6FAF28, 0xB990);
Patch(0x6FAF2A, &InitBufferSwitchZ); Patch(0x6FAF2A, &InitBufferSwitchZ);
Patch<WORD>(0x6FAF32, 0xD1FF); Patch<WORD>(0x6FAF32, 0xD1FF);
@ -3729,7 +3733,9 @@ void Patch_SA_10()
InjectHook(0x524071, 0x524139, PATCH_JUMP); InjectHook(0x524071, 0x524139, PATCH_JUMP);
// Fixed mirrors crash // Fixed mirrors crash
Patch<uint64_t>(0x7271CB, 0xC604C4833474C085); // TODO: Change when short jumps are supported
// test eax, eax / je 0727203 / add esp, 4
Patch( 0x7271CB, { 0x85, 0xC0, 0x74, 0x34, 0x83, 0xC4, 0x04 } );
// Mirrors depth fix & bumped quality // Mirrors depth fix & bumped quality
InjectHook(0x72701D, CreateMirrorBuffers); InjectHook(0x72701D, CreateMirrorBuffers);
@ -3740,7 +3746,7 @@ void Patch_SA_10()
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F6C9B), 0xEB); Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F6C9B), 0xEB);
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F60C6), 0xEB); Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F60C6), 0xEB);
Patch<WORD>(AddressByRegion_10<BYTE*>(0x7F6683), 0xE990); Patch(AddressByRegion_10<BYTE*>(0x7F6683), { 0x90, 0xE9 });
ReadCall( 0x57D136, orgGetMaxMultiSamplingLevels ); ReadCall( 0x57D136, orgGetMaxMultiSamplingLevels );
InjectHook(0x57D136, GetMaxMultiSamplingLevels); InjectHook(0x57D136, GetMaxMultiSamplingLevels);
@ -3814,8 +3820,8 @@ void Patch_SA_10()
// Don't allocate constant memory for stencil shadows every frame // Don't allocate constant memory for stencil shadows every frame
InjectHook(0x711DD5, StencilShadowAlloc, PATCH_CALL); InjectHook(0x711DD5, StencilShadowAlloc, PATCH_CALL);
Nop(0x711E0D, 3); Nop(0x711E0D, 3);
Patch<WORD>(0x711DDA, 0x2CEB); Patch(0x711DDA, { 0xEB, 0x2C });
Patch<DWORD>(0x711E5F, 0x90C35D5F); // pop edi, pop ebp, ret Patch(0x711E5F, { 0x5F, 0x5D, 0xC3 }); // pop edi, pop ebp, ret
// "Streaming memory bug" fix // "Streaming memory bug" fix
@ -4416,7 +4422,7 @@ void Patch_SA_11()
InjectHook(0x524511, 0x5245D9, PATCH_JUMP); InjectHook(0x524511, 0x5245D9, PATCH_JUMP);
// Fixed mirrors crash // Fixed mirrors crash
Patch<uint64_t>(0x7279FB, 0xC604C4833474C085); Patch( 0x7279FB, { 0x85, 0xC0, 0x74, 0x34, 0x83, 0xC4, 0x04 } );
// Mirrors depth fix & bumped quality // Mirrors depth fix & bumped quality
InjectHook(0x72784D, CreateMirrorBuffers); InjectHook(0x72784D, CreateMirrorBuffers);
@ -4427,7 +4433,7 @@ void Patch_SA_11()
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F759B), 0xEB); Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F759B), 0xEB);
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F69C6), 0xEB); Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F69C6), 0xEB);
Patch<WORD>(AddressByRegion_11<BYTE*>(0x7F6F83), 0xE990); Patch(AddressByRegion_11<BYTE*>(0x7F6F83), { 0x90, 0xE9 });
ReadCall( 0x57D916, orgGetMaxMultiSamplingLevels ); ReadCall( 0x57D916, orgGetMaxMultiSamplingLevels );
InjectHook(0x57D916, GetMaxMultiSamplingLevels); InjectHook(0x57D916, GetMaxMultiSamplingLevels);
@ -4728,7 +4734,7 @@ void Patch_SA_Steam()
InjectHook(0x534D3E, 0x534DF7, PATCH_JUMP); InjectHook(0x534D3E, 0x534DF7, PATCH_JUMP);
// Fixed mirrors crash // Fixed mirrors crash
Patch<uint64_t>(0x75903A, 0xC604C4833474C085); Patch( 0x75903A, { 0x85, 0xC0, 0x74, 0x34, 0x83, 0xC4, 0x04 } );
// Mirrors depth fix & bumped quality // Mirrors depth fix & bumped quality
InjectHook(0x758E91, CreateMirrorBuffers); InjectHook(0x758E91, CreateMirrorBuffers);
@ -4739,7 +4745,7 @@ void Patch_SA_Steam()
Patch<BYTE>(0x830C5B, 0xEB); Patch<BYTE>(0x830C5B, 0xEB);
Patch<BYTE>(0x830086, 0xEB); Patch<BYTE>(0x830086, 0xEB);
Patch<WORD>(0x830643, 0xE990); Patch(0x830643, { 0x90, 0xE9 });
ReadCall( 0x592BCF, orgGetMaxMultiSamplingLevels ); ReadCall( 0x592BCF, orgGetMaxMultiSamplingLevels );
InjectHook(0x592BCF, GetMaxMultiSamplingLevels); InjectHook(0x592BCF, GetMaxMultiSamplingLevels);
@ -4753,7 +4759,7 @@ void Patch_SA_Steam()
ReadCall( 0x780206, orgSetMultiSamplingLevels ); ReadCall( 0x780206, orgSetMultiSamplingLevels );
InjectHook(0x780206, SetMultiSamplingLevels); InjectHook(0x780206, SetMultiSamplingLevels);
Patch<WORD>(0x58F88C, 0xBA90); Patch(0x58F88C, { 0x90, 0xBA });
Patch(0x58F88E, MSAAText); Patch(0x58F88E, MSAAText);
// Fixed car collisions - car you're hitting gets proper damage now // Fixed car collisions - car you're hitting gets proper damage now
@ -4790,8 +4796,8 @@ void Patch_SA_Steam()
// Don't allocate constant memory for stencil shadows every frame // Don't allocate constant memory for stencil shadows every frame
InjectHook(0x760795, StencilShadowAlloc, PATCH_CALL); InjectHook(0x760795, StencilShadowAlloc, PATCH_CALL);
Nop(0x7607CD, 3); Nop(0x7607CD, 3);
Patch<WORD>(0x76079A, 0x2CEB); Patch(0x76079A, { 0xEB, 0x2C });
Patch<DWORD>(0x76082C, 0x90C35D5F); // pop edi, pop ebp, ret Patch(0x76082C, { 0x5F, 0x5D, 0xC3 }); // pop edi, pop ebp, ret
// "Streaming memory bug" fix // "Streaming memory bug" fix
@ -4868,462 +4874,7 @@ void Patch_SA_Steam()
InjectHook(0x5EDFD9, 0x5EE0FA, PATCH_JUMP); InjectHook(0x5EDFD9, 0x5EE0FA, PATCH_JUMP);
} }
void Patch_SA_NewSteam_r1() void Patch_SA_NewBinaries_Common()
{
using namespace Memory::DynBase;
// Nazi EXE?
if ( *(DWORD*)DynBaseAddress(0x49F810) == 0x64EC8B55 )
{
// Regular
// No framedelay
InjectHook(0x54ECC6, DynBaseAddress(0x54ED0C), PATCH_JUMP);
Patch<BYTE>(0x54ED45, 0x4);
Nop(0x54ED47, 1);
// Unlock 1.0/1.01 saves loading
Patch<WORD>(0x5ED3E9, 0xE990);
// Old .set files working again
static const DWORD dwSetVersion = 6;
Patch<const void*>(0x59058A, &dwSetVersion);
Patch<BYTE>(0x59086D, 6);
Patch<BYTE>(0x53EC4A, 6);
// Disable re-initialization of DirectInput mouse device by the game
Patch<BYTE>(0x58A891, 0xEB);
Patch<BYTE>(0x58AA77, 0xEB);
Patch<BYTE>(0x58AB59, 0xEB);
}
else
{
// Nazi
// No framedelay
InjectHook(0x54EC06, DynBaseAddress(0x54EC4C), PATCH_JUMP);
Patch<BYTE>(0x54EC85, 0x4);
Nop(0x54EC87, 1);
// Unlock 1.0/1.01 saves loading
Patch<WORD>(0x5ED349, 0xE990);
// Old .set files working again
static const DWORD dwSetVersion = 6;
Patch<const void*>(0x5904DA, &dwSetVersion);
Patch<BYTE>(0x5907BD, 6);
Patch<BYTE>(0x53EB9A, 6);
// Disable re-initialization of DirectInput mouse device by the game
Patch<BYTE>(0x58A7D1, 0xEB);
Patch<BYTE>(0x58A9B7, 0xEB);
Patch<BYTE>(0x58AA99, 0xEB);
}
// Unlocked widescreen resolutions
//Patch<WORD>(0x779BAD, 0x607D);
Patch<WORD>(0x779BB8, 0x557D);
Patch<DWORD>(0x7799D8, 0x9090117D);
Nop(0x779A45, 2);
Nop(0x7799DC, 2);
// Make sure DirectInput mouse device is set non-exclusive (may not be needed?)
Nop(0x77AB3F, 1);
Patch<WORD>(0x77AB40, 0x01B0);
// Default resolution to native resolution
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom);
Patch<DWORD>(0x77A3EF, desktop.right);
Patch<DWORD>(0x77A3F4, desktop.bottom);
Patch<const char*>(0x77A44B, aNoDesktopMode);
// Proper aspect ratios
static const float f43 = 4.0f/3.0f, f54 = 5.0f/4.0f, f169 = 16.0f/9.0f;
Patch<const void*>(0x73424B, &f169);
Patch<const void*>(0x734267, &f54);
Patch<const void*>(0x73427A, &f43);
}
void Patch_SA_NewSteam_r2()
{
using namespace Memory::DynBase;
// (Hopefully) more precise frame limiter
ReadCall( 0x77D55F, RsEventHandler );
InjectHook(0x77D55F, NewFrameRender);
InjectHook(0x77D4E8, GetTimeSinceLastFrame);
// No framedelay
InjectHook(0x54ECC6, DynBaseAddress(0x54ED0C), PATCH_JUMP);
Patch<BYTE>(0x54ED45, 0x4);
Nop(0x54ED47, 1);
// Unlock 1.0/1.01 saves loading
Patch<WORD>(0x5ED349, 0xE990);
// Old .set files working again
static const DWORD dwSetVersion = 6;
Patch<const void*>(0x5904CA, &dwSetVersion);
Patch<BYTE>(0x5907AD, 6);
Patch<BYTE>(0x53EC4A, 6);
// Disable re-initialization of DirectInput mouse device by the game
Patch<BYTE>(0x58A881, 0xEB);
Patch<BYTE>(0x58AA67, 0xEB);
Patch<BYTE>(0x58AB49, 0xEB);
// Unlocked widescreen resolutions
//Patch<WORD>(0x779BAD, 0x607D);
Patch<WORD>(0x779BC8, 0x697D);
Patch<DWORD>(0x7799D8, 0x9090117D);
Nop(0x779A56, 2);
Nop(0x7799DC, 2);
// Make sure DirectInput mouse device is set non-exclusive (may not be needed?)
Nop(0x77AB6F, 1);
Patch<WORD>(0x77AB70, 0x01B0);
// Default resolution to native resolution
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom);
Patch<DWORD>(0x77A41F, desktop.right);
Patch<DWORD>(0x77A424, desktop.bottom);
Patch<const char*>(0x77A47B, aNoDesktopMode);
// No DirectPlay dependency
Patch<BYTE>(0x77B46E, 0xB8);
Patch<DWORD>(0x77B46F, 0x900);
// SHGetFolderPath on User Files
InjectHook(0x778FA0, GetMyDocumentsPathSA, PATCH_JUMP);
// Fixed muzzleflash not showing from last bullet
Nop(0x63E8A9, 2);
// Proper randomizations
InjectHook(0x45234C, Int32Rand); // Missing ped paths
InjectHook(0x45284C, Int32Rand); // Missing ped paths
InjectHook(0x69046F, Int32Rand); // Prostitutes
// Help boxes showing with big message
// Game seems to assume they can show together
Nop(0x597EEA, 6);
// Fixed lens flare
Nop(0x7300F8, 5);
Patch<BYTE>(0x7300E3, 0x20);
InjectHook(0x730104, DynBaseAddress(0x753AE0), PATCH_CALL);
Patch<WORD>(0x730109, 0xE1EB);
Nop(0x72FF17, 4);
Patch<BYTE>(0x72FF1B, 0xB8);
Patch(0x72FF1C, &FlushLensSwitchZ);
Patch<DWORD>(0x72F91D, 0xB9909090);
Patch(0x72F921, &InitBufferSwitchZ);
// Y axis sensitivity fix
float* sens = *(float**)DynBaseAddress(0x51B987);
Patch<const void*>(0x51B993 + 0x2, sens);
Patch<const void*>(0x51C68C + 0x2, sens);
Patch<const void*>(0x51D73A + 0x2, sens);
Patch<const void*>(0x51EA3A + 0x2, sens);
Patch<const void*>(0x52FBE1 + 0x2, sens);
// Don't lock mouse Y axis during fadeins
Patch<WORD>(0x51C5CD, 0x29EB);
Patch<WORD>(0x51D053, 0xE990);
InjectHook(0x531BBE, DynBaseAddress(0x531C6F), PATCH_JUMP);
// Fixed mirrors crash
Patch<uint64_t>(0x753941, 0xC604C4832F74C085);
// Mirrors depth fix & bumped quality
InjectHook(0x7537A0, CreateMirrorBuffers);
// Fixed MSAA options
Patch<BYTE>(0x590F77, 0xEB);
Nop(0x590F34, 2);
Patch<BYTE>(0x82B4EB, 0xEB);
Patch<BYTE>(0x82A916, 0xEB);
Patch<WORD>(0x82AED3, 0xE990);
ReadCall( 0x590F8B, orgGetMaxMultiSamplingLevels );
InjectHook(0x590F8B, GetMaxMultiSamplingLevels);
InjectHook(0x590F36, GetMaxMultiSamplingLevels);
ReadCall( 0x5881C0, orgChangeMultiSamplingLevels );
InjectHook(0x5881C0, ChangeMultiSamplingLevels);
InjectHook(0x590FBB, ChangeMultiSamplingLevels);
InjectHook(0x591111, ChangeMultiSamplingLevels);
ReadCall( 0x77A40D, orgSetMultiSamplingLevels );
InjectHook(0x77A40D, SetMultiSamplingLevels);
Patch<WORD>(0x58DDEF, 0xBA90);
Patch(0x58DDF1, MSAAText);
// Fixed car collisions - car you're hitting gets proper damage now
Nop(0x5538D0, 2);
InjectHook(0x5538D2, FixedCarDamage_Newsteam, PATCH_CALL);
// Car explosion crash with multimonitor
// Unitialized collision data breaking stencil shadows
ReadCall( 0x41A661, orgMemMgrMalloc );
InjectHook(0x41A661, CollisionData_MallocAndInit);
ReadCall( 0x41A4CC, orgNewAlloc );
InjectHook(0x41A4CC, CollisionData_NewAndInit);
InjectHook(0x41A5A9, CollisionData_NewAndInit);
// Crash when entering advanced display options on a dual monitor machine after:
// - starting game on primary monitor in maximum resolution, exiting,
// starting again in maximum resolution on secondary monitor.
// Secondary monitor maximum resolution had to be greater than maximum resolution of primary monitor.
// Not in 1.01
ReadCall( 0x779B71, orgGetNumVideoModes );
InjectHook(0x779B71, GetNumVideoModes_Store);
InjectHook(0x779AD1, GetNumVideoModes_Retrieve);
// Fixed escalators crash
orgEscalatorsUpdate = (void(*)())DynBaseAddress(0x735B90);
InjectHook(0x735BC5, UpdateEscalators, PATCH_JUMP);
Patch<WORD>(0x734BAE, 0x4E8D);
Patch<BYTE>(0x734BB0, 0x84);
InjectHook(0x734BB1, &CEscalator::SwitchOffNoRemove, PATCH_CALL);
Patch<WORD>(0x734BB6, 0x52EB);
// Don't allocate constant memory for stencil shadows every frame
InjectHook(0x75ADA9, StencilShadowAlloc, PATCH_CALL);
Nop(0x75ADE1, 3);
Patch<WORD>(0x75ADAE, 0x2CEB);
Patch<DWORD>(0x75AE35, 0x5D5B5E5F); // pop edi, pop esi, pop ebx, pop ebp, retn
Patch<BYTE>(0x75AE39, 0xC3);
// "Streaming memory bug" fix
InjectHook(0x4CF1FB, GTARtAnimInterpolatorSetCurrentAnim);
// Fixed ammo for melee weapons in cheats
Patch<BYTE>(0x43AD0B+1, 1); // knife
Patch<BYTE>(0x43ADF8+1, 1); // knife
Patch<BYTE>(0x43AF9F+1, 1); // chainsaw
Patch<BYTE>(0x43B058+1, 1); // chainsaw
Patch<BYTE>(0x43B9B8+1, 1); // parachute
Patch<BYTE>(0x43C492, 0x53); // katana
Patch<WORD>(0x43C493, 0x016A);
// Proper aspect ratios
static const float f43 = 4.0f/3.0f, f54 = 5.0f/4.0f, f169 = 16.0f/9.0f;
Patch<const void*>(0x73424B, &f169);
Patch<const void*>(0x734267, &f54);
Patch<const void*>(0x73427A, &f43);
}
void Patch_SA_NewSteam_r2_lv()
{
using namespace Memory::DynBase;
// (Hopefully) more precise frame limiter
ReadCall( 0x77D44F, RsEventHandler );
InjectHook(0x77D44F, NewFrameRender);
InjectHook(0x77D3D8, GetTimeSinceLastFrame);
// No framedelay
InjectHook(0x54EC06, DynBaseAddress(0x54EC4C), PATCH_JUMP);
Patch<BYTE>(0x54EC85, 0x4);
Nop(0x54EC87, 1);
// Unlock 1.0/1.01 saves loading
Patch<WORD>(0x5ED299, 0xE990);
// Old .set files working again
static const DWORD dwSetVersion = 6;
Patch<const void*>(0x59040A, &dwSetVersion);
Patch<BYTE>(0x5906ED, 6);
Patch<BYTE>(0x53EB9A, 6);
// Disable re-initialization of DirectInput mouse device by the game
Patch<BYTE>(0x58A7C1, 0xEB);
Patch<BYTE>(0x58A9A7, 0xEB);
Patch<BYTE>(0x58AA89, 0xEB);
// Unlocked widescreen resolutions
//Patch<WORD>(0x779BAD, 0x607D);
Patch<WORD>(0x779AB8, 0x697D);
Patch<DWORD>(0x7798C8, 0x9090117D);
Nop(0x779946, 2);
Nop(0x7798CC, 2);
// Make sure DirectInput mouse device is set non-exclusive (may not be needed?)
Nop(0x77AA5F, 1);
Patch<WORD>(0x77AA60, 0x01B0);
// Default resolution to native resolution
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom);
Patch<DWORD>(0x77A30F, desktop.right);
Patch<DWORD>(0x77A314, desktop.bottom);
Patch<const char*>(0x77A36B, aNoDesktopMode);
// No DirectPlay dependency
Patch<BYTE>(0x77B35E, 0xB8);
Patch<DWORD>(0x77B35F, 0x900);
// SHGetFolderPath on User Files
InjectHook(0x778E90, GetMyDocumentsPathSA, PATCH_JUMP);
// Fixed muzzleflash not showing from last bullet
Nop(0x63E789, 2);
// Proper randomizations
InjectHook(0x45234C, Int32Rand); // Missing ped paths
InjectHook(0x45284C, Int32Rand); // Missing ped paths
InjectHook(0x69034F, Int32Rand); // Prostitutes
// Help boxes showing with big message
// Game seems to assume they can show together
Nop(0x597E3A, 6);
// Fixed lens flare
Nop(0x72FFF8, 5);
Patch<BYTE>(0x72FFE3, 0x20);
InjectHook(0x730004, DynBaseAddress(0x753A00), PATCH_CALL);
Patch<WORD>(0x730009, 0xE1EB);
Nop(0x72FE17, 4);
Patch<BYTE>(0x72FE1B, 0xB8);
Patch(0x72FE1C, &FlushLensSwitchZ);
Patch<DWORD>(0x72F81D, 0xB9909090);
Patch(0x72F821, &InitBufferSwitchZ);
// Y axis sensitivity fix
float* sens = *(float**)DynBaseAddress(0x51B8D7);
Patch<const void*>(0x51B8E3 + 0x2, sens);
Patch<const void*>(0x51C5DC + 0x2, sens);
Patch<const void*>(0x51D68A + 0x2, sens);
Patch<const void*>(0x51E98A + 0x2, sens);
Patch<const void*>(0x52FB31 + 0x2, sens);
// Don't lock mouse Y axis during fadeins
Patch<WORD>(0x51C51D, 0x29EB);
Patch<WORD>(0x51CFA3, 0xE990);
InjectHook(0x531B1E, DynBaseAddress(0x531BCF), PATCH_JUMP);
// Fixed mirrors crash
Patch<uint64_t>(0x753861, 0xC604C4832F74C085);
// Mirrors depth fix & bumped quality
InjectHook(0x7536C0, CreateMirrorBuffers);
// Fixed MSAA options
Patch<BYTE>(0x590EB7, 0xEB);
Nop(0x590E74, 2);
Patch<BYTE>(0x82B3BB, 0xEB);
Patch<BYTE>(0x82A7E6, 0xEB);
Patch<WORD>(0x82ADA3, 0xE990);
ReadCall( 0x590ECB, orgGetMaxMultiSamplingLevels );
InjectHook(0x590ECB, GetMaxMultiSamplingLevels);
InjectHook(0x590E76, GetMaxMultiSamplingLevels);
ReadCall( 0x588100, orgChangeMultiSamplingLevels );
InjectHook(0x588100, ChangeMultiSamplingLevels);
InjectHook(0x590EFB, ChangeMultiSamplingLevels);
InjectHook(0x591051, ChangeMultiSamplingLevels);
ReadCall( 0x77A2FD, orgSetMultiSamplingLevels );
InjectHook(0x77A2FD, SetMultiSamplingLevels);
Patch<WORD>(0x58DD2F, 0xBA90);
Patch(0x58DD31, MSAAText);
// Fixed car collisions - car you're hitting gets proper damage now
Nop(0x553800, 2);
InjectHook(0x553802, FixedCarDamage_Newsteam, PATCH_CALL);
// Car explosion crash with multimonitor
// Unitialized collision data breaking stencil shadows
ReadCall( 0x41A661, orgMemMgrMalloc );
InjectHook(0x41A661, CollisionData_MallocAndInit);
ReadCall( 0x41A4CC, orgNewAlloc );
InjectHook(0x41A4CC, CollisionData_NewAndInit);
InjectHook(0x41A5A9, CollisionData_NewAndInit);
// Crash when entering advanced display options on a dual monitor machine after:
// - starting game on primary monitor in maximum resolution, exiting,
// starting again in maximum resolution on secondary monitor.
// Secondary monitor maximum resolution had to be greater than maximum resolution of primary monitor.
// Not in 1.01
ReadCall( 0x779A61, orgGetNumVideoModes );
InjectHook(0x779A61, GetNumVideoModes_Store);
InjectHook(0x7799C1, GetNumVideoModes_Retrieve);
// Fixed escalators crash
orgEscalatorsUpdate = (void(*)())DynBaseAddress(0x735A90);
InjectHook(0x735AC5, UpdateEscalators, PATCH_JUMP);
Patch<WORD>(0x734AAE, 0x4E8D);
Patch<BYTE>(0x734AB0, 0x84);
InjectHook(0x734AB1, &CEscalator::SwitchOffNoRemove, PATCH_CALL);
Patch<WORD>(0x734AB6, 0x52EB);
// Don't allocate constant memory for stencil shadows every frame
InjectHook(0x75AC99, StencilShadowAlloc, PATCH_CALL);
Nop(0x75ACD1, 3);
Patch<WORD>(0x75AC9E, 0x2CEB);
Patch<DWORD>(0x75AD25, 0x5D5B5E5F); // pop edi, pop esi, pop ebx, pop ebp, retn
Patch<BYTE>(0x75AD29, 0xC3);
// "Streaming memory bug" fix
InjectHook(0x4CF1DB, GTARtAnimInterpolatorSetCurrentAnim);
// Fixed ammo for melee weapons in cheats
Patch<BYTE>(0x43AD0B+1, 1); // knife
Patch<BYTE>(0x43ADF8+1, 1); // knife
Patch<BYTE>(0x43AF9F+1, 1); // chainsaw
Patch<BYTE>(0x43B058+1, 1); // chainsaw
Patch<BYTE>(0x43B9B8+1, 1); // parachute
Patch<BYTE>(0x43C492, 0x53); // katana
Patch<WORD>(0x43C493, 0x016A);
// Proper aspect ratios
static const float f43 = 4.0f/3.0f, f54 = 5.0f/4.0f, f169 = 16.0f/9.0f;
Patch<const void*>(0x73414B, &f169);
Patch<const void*>(0x734167, &f54);
Patch<const void*>(0x73417A, &f43);
}
void Patch_SA_NewSteam_Common()
{ {
using namespace Memory; using namespace Memory;
using namespace hook; using namespace hook;
@ -5334,6 +4885,402 @@ void Patch_SA_NewSteam_Common()
InjectHook(isAlreadyRunning, InjectDelayedPatches_Newsteam); InjectHook(isAlreadyRunning, InjectDelayedPatches_Newsteam);
} }
// (Hopefully) more precise frame limiter
{
void* rsEventHandler = get_pattern( "83 C4 08 39 3D ? ? ? ? 75 23", -5 );
void* getTimeSinceLastFrame = get_pattern( "EB 7F E8 ? ? ? ? 89 45 08", 2 );
ReadCall( rsEventHandler, RsEventHandler );
InjectHook( rsEventHandler, NewFrameRender );
InjectHook( getTimeSinceLastFrame, GetTimeSinceLastFrame );
}
// No framedelay
{
// TODO: Simplify with transactional patching
auto framedelay_jmpSrc = pattern( "83 EC 08 E8 ? ? ? ? E8" ).count(1);
auto framedelay_jmpDest = pattern( "33 D2 8B C6 F7 F1 A3" ).count(1);
auto popEsi = pattern( "83 C4 04 83 7D 08 00 5E" ).count(1);
if ( framedelay_jmpSrc.size() == 1 && framedelay_jmpDest.size() == 1 && popEsi.size() == 1 )
{
// TODO: Let this place long or short jump, whatever it prefers
InjectHook( framedelay_jmpSrc.get_first<void>( 3 ), framedelay_jmpDest.get_first<void>( 11 ), PATCH_JUMP );
auto popEsiMatch = popEsi.get_one();
Patch<BYTE>( popEsiMatch.get<void>( 3 + 2 ), 0x4);
Nop( popEsiMatch.get<void>( 3 + 4 ), 1 );
}
}
// Unlock 1.0/1.01 saves loading
{
auto sizeCheck = pattern( "0F 84 ? ? ? ? 8D 45 FC" ).count(1);
if ( sizeCheck.size() == 1 )
{
Patch( sizeCheck.get_first<void>(), { 0x90, 0xE9 } ); // nop / jmp
}
}
// Old .set files working again
{
void* setFileSave = get_pattern( "C6 45 FD 5F", 0xE + 1 );
auto setCheckVersion1 = pattern( "83 7D F8 07" ).count(1);
auto setCheckVersion2 = pattern( "83 C4 18 83 7D FC 07" ).count(1);
if ( setCheckVersion1.size() == 1 && setCheckVersion2.size() == 1 )
{
static const DWORD dwSetVersion = 6;
Patch( setFileSave, &dwSetVersion );
Patch<BYTE>( setCheckVersion1.get_first<void>( 3 ), dwSetVersion );
Patch<BYTE>( setCheckVersion2.get_first<void>( 3 + 3 ), dwSetVersion );
}
}
// Disable re-initialization of DirectInput mouse device by the game
{
void* reinitMouse1 = get_pattern( "84 C0 ? 0F E8 ? ? ? ? 6A 01 E8", 2 );
auto reinitMouse2 = pattern( "84 C0 ? 0E E8 ? ? ? ? 53 E8" ).count(2);
Patch<BYTE>( reinitMouse1, 0xEB );
reinitMouse2.for_each_result( []( pattern_match match ) {
Patch<BYTE>( match.get<void>( 2 ), 0xEB );
});
void* diInitMouse = get_pattern( "6A 00 83 C1 1C", -3 );
// Make sure DirectInput mouse device is set non-exclusive (may not be needed?)
// nop / mov al, 1
Patch( diInitMouse, { 0x90, 0xB0, 0x01 } );
}
// Unlocked widescreen resolutions
{
// Assume anybody could have changed those, so bail out if ANYTHING goes wrong
// However, all those patches are independent so try one by one
auto wsRes_jmpSrc = pattern( "81 F9 E0 01 00 00 7C").count(1);
auto wsRes1_jmpDest = pattern( "8B 45 EC 0F AF C2" ).count(1);
auto wsRes2 = pattern( "0F 8C ? ? ? ? 81 7D ? ? ? ? ? 0F 8C" ).count(1);
auto wsRes3 = pattern( "7A 4D EB 02" ).count(1);
if ( wsRes_jmpSrc.size() == 1 && wsRes1_jmpDest.size() == 1 )
{
auto wsRes_jmpSrcMatch = wsRes_jmpSrc.get_one();
auto wsRes1_jmpDestMatch = wsRes1_jmpDest.get_one();
const uintptr_t jumpSource = reinterpret_cast<uintptr_t>(wsRes_jmpSrcMatch.get<void>( 6 + 2 ));
const uintptr_t jumpDestination = reinterpret_cast<uintptr_t>(wsRes1_jmpDestMatch.get<void>() );
const ptrdiff_t dist = jumpDestination - jumpSource;
// Can only do a short jump
if ( INT8_MIN <= dist && dist <= INT8_MAX )
{
// jnl 00B19C33
Patch( wsRes_jmpSrcMatch.get<void>( 6 ), { 0x7D, static_cast<uint8_t>(dist) } );
}
}
if ( wsRes2.size() == 1 )
{
auto wsRes2Match = wsRes2.get_one();
Nop( wsRes2Match.get<void>(), 4 );
Patch( wsRes2Match.get<void>( 4 ), { 0x7D, 0xD } );
}
if ( wsRes3.size() == 1 )
{
Nop( wsRes3.get_first<void>(), 2 );
}
}
// Default resolution to native resolution
{
auto resolution = pattern( "BB 20 03 00 00" ).count(1); // Another instance could overwrite it so check first
if ( resolution.size() == 1 )
{
void* cannotFindResMessage = get_pattern( "6A 00 68 ? ? ? ? 68 ? ? ? ? 6A 00", 7 + 1 );
RECT desktop;
GetWindowRect(GetDesktopWindow(), &desktop);
sprintf_s(aNoDesktopMode, "Cannot find %dx%dx32 video mode", desktop.right, desktop.bottom);
auto resolutionMatch = resolution.get_one();
Patch<LONG>( resolutionMatch.get<void>( 1 ), desktop.right );
Patch<LONG>( resolutionMatch.get<void>( 5 + 1 ), desktop.bottom );
Patch<const char*>( cannotFindResMessage, aNoDesktopMode );
}
}
// No DirectPlay dependency
{
auto getDXversion = pattern( "50 68 ? ? ? ? A3" ).get_one();
// mov eax, 0x900
Patch<BYTE>( getDXversion.get<void>( -5 ), 0xB8 );
Patch<DWORD>( getDXversion.get<void>( -5 + 1 ), 0x900 );
}
// SHGetFolderPath on User Files
{
void* getDocumentsPath = get_pattern( "8D 45 FC 50 68 19 00 02 00", -6 );
InjectHook( getDocumentsPath, GetMyDocumentsPathSA, PATCH_JUMP );
}
// Fixed muzzleflash not showing from last bullet
{
void* weaponStateCheck = get_pattern( "83 BC 8E A4 05 00 00 01", 8 );
Nop( weaponStateCheck, 2 );
}
// Proper randomizations
{
pattern( "C1 F8 06 99" ).count(2).for_each_result( []( pattern_match match ) {
InjectHook( match.get<void>( -5 ), Int32Rand ); // Missing ped paths
});
void* prostitutesRand = get_pattern( "8B F8 32 C0", -5 );
InjectHook( prostitutesRand, Int32Rand ); // Prostitutes
}
// Help boxes showing with big message
// Game seems to assume they can show together
{
void* showingBigMessage = get_pattern( "38 1D ? ? ? ? 0F 85 ? ? ? ? 38 1D ? ? ? ? 0F 85 ? ? ? ? 38 1D", 6 );
Nop( showingBigMessage, 6 );
}
// Fixed lens flare
{
auto coronasRenderEpilogue = pattern( "83 C7 3C FF 4D BC" ).get_one();
auto flushLensSwitchZ = pattern( "6A 01 6A 06 FF D0 83 C4 08" ).get_one();
auto initBufferSwitchZ = pattern( "6A 01 6A 06 FF D1 8B 75 A8" ).get_one();
// TODO: This will break badly if applied multiple times, think of something!
void* flushSpriteBuffer;
ReadCall( coronasRenderEpilogue.get<void>( 0xC ), flushSpriteBuffer );
Nop( coronasRenderEpilogue.get<void>( 0xC ), 5); // nop CSprite::FlushSpriteBuffer
// Add CSprite::FlushSpriteBuffer, jmp loc_7300EC at the bottom of the function
Patch<BYTE>( coronasRenderEpilogue.get<void>( -0xA + 1 ), 0x20 );
InjectHook( coronasRenderEpilogue.get<void>( 0x18 ), flushSpriteBuffer, PATCH_CALL );
// TODO: Short jumps
Patch( coronasRenderEpilogue.get<void>( 0x18 + 5 ), { 0xEB, 0xE1 });
// nop / mov eax, offset FlushLensSwitchZ
Nop( flushLensSwitchZ.get<void>( -9 ), 4 );
Patch<BYTE>( flushLensSwitchZ.get<void>( -9 + 4 ), 0xB8 );
Patch( flushLensSwitchZ.get<void>( -9 + 5 ), &FlushLensSwitchZ );
// nop / mov ecx, offset InitBufferSwitchZ
Nop( initBufferSwitchZ.get<void>( -8 ), 3 );
Patch<BYTE>( initBufferSwitchZ.get<void>( -8 + 3 ), 0xB9 );
Patch( initBufferSwitchZ.get<void>( -8 + 4 ), &InitBufferSwitchZ );
}
// Y axis sensitivity fix
{
auto horizontalSens = pattern( "D9 05 ? ? ? ? D8 4D 0C D8 C9" ).get_one();
float* sens = *horizontalSens.get<float*>( 2 );
// Build a pattern for finding all instances of fld CCamera::m_fMouseAccelVertical
const uint8_t mask[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t bytes[6] = { 0xD9, 0x05 };
float* vertSens = *horizontalSens.get<float*>( 0xE + 2 );
memcpy( bytes + 2, &vertSens, sizeof(vertSens) );
pattern( {bytes, _countof(bytes)}, {mask, _countof(mask)} ).count(4).for_each_result( [sens]( pattern_match match ) {
Patch( match.get<void>( 2 ), sens );
} );
void* mulVerticalSens = get_pattern( "D8 0D ? ? ? ? D8 C9 D9 5D F4", 2 );
Patch( mulVerticalSens, sens );
}
// Don't lock mouse Y axis during fadeins
{
void* followPedWithMouse = get_pattern( "D9 5D 08 A0", -7 );
void* followPedWithMouse2 = get_pattern( "66 83 3D ? ? ? ? ? 0F 85 ? ? ? ? 80 3D", -6 );
void* followPedSA = get_pattern( "D9 5D F0 74 14", 3 );
void* folowPedSA_dest = get_pattern( "D9 87 AC 00 00 00 D8 45 F0" );
// TODO: Change when short jumps are supported
Patch( followPedWithMouse, { 0xEB, 0x29 } );
Patch( followPedWithMouse2, { 0x90, 0xE9 } );
InjectHook( followPedSA, folowPedSA_dest, PATCH_JUMP );
}
// Fixed mirrors crash
{
// TODO: Change when short jumps are supported
void* beforeMainRender = get_pattern( "8B 15 ? ? ? ? 83 C4 0C 52", 0xF );
Patch( beforeMainRender, { 0x85, 0xC0, 0x74, 0x34, 0x83, 0xC4, 0x04 } );
}
// Mirrors depth fix & bumped quality
{
void* createBuffers = get_pattern( "7B 0A C7 05 ? ? ? ? 01 00 00 00", 0xC );
InjectHook( createBuffers, CreateMirrorBuffers );
}
// Fixed MSAA options
{
// TODO: Remove wildcards in patterns once transactional patching is implemented
auto func1 = pattern( "83 BE C8 00 00 00 04 ? ? E8" ).get_one();
void* func2 = get_pattern( "05 A3 ? ? ? ? 59", -1 );
void* func3 = get_pattern( "05 A3 ? ? ? ? 8B C7", -1 );
void* func4 = get_pattern( "0F 8C ? ? ? ? 8B 44 24 0C", 0x18 );
Patch<BYTE>( func1.get<void>( 0x4A ), 0xEB ); // jmp
Nop( func1.get<void>( 7 ), 2 ); // nop a jmp
Patch<BYTE>(func2, 0xEB); // jmp
Patch<BYTE>(func3, 0xEB); // jmp
Patch(func4, { 0x90, 0xE9 }); // jmp
auto getMaxMultisamplingLevels = pattern( "5F 89 86 C8 00 00 00 8A 45 FF" ).get_one();
void* changeMultiSamplingLevels = get_pattern( "8B 8E D0 00 00 00 51", -5 );
void* changeMultiSamplingLevels2 = get_pattern( "8B 96 D0 00 00 00 52", -5 );
void* setMultiSamplingLevels = get_pattern( "83 C4 04 8B C7 5F 5E 5B 8B E5 5D C3 BB", -5 );
ReadCall( getMaxMultisamplingLevels.get<void>( -5 ), orgGetMaxMultiSamplingLevels );
InjectHook( getMaxMultisamplingLevels.get<void>( -5 ), GetMaxMultiSamplingLevels );
InjectHook(func1.get<void>( 7 + 2 ), GetMaxMultiSamplingLevels);
ReadCall( changeMultiSamplingLevels, orgChangeMultiSamplingLevels );
InjectHook( changeMultiSamplingLevels, ChangeMultiSamplingLevels );
InjectHook( getMaxMultisamplingLevels.get<void>( -5 + 0x30 ), ChangeMultiSamplingLevels );
InjectHook( changeMultiSamplingLevels2, ChangeMultiSamplingLevels );
ReadCall( setMultiSamplingLevels, orgSetMultiSamplingLevels );
InjectHook( setMultiSamplingLevels, SetMultiSamplingLevels );
auto msaaText = pattern( "48 50 68 ? ? ? ? 53" ).count(1); // Only so newsteam r1 doesn't crash
if ( msaaText.size() == 1 ) // transactional patching will obsolete this
{
auto msaaTextMatch = msaaText.get_one();
// nop / mov edx, offset MSAAText
Patch( msaaTextMatch.get<void>( -6 ), { 0x90, 0xBA } );
Patch( msaaTextMatch.get<void>( -6 + 2 ), MSAAText );
}
}
// Fixed car collisions - car you're hitting gets proper damage now
{
auto fixedCarDamage = pattern( "8B 7D 10 0F B6 47 21" ).get_one();
Nop( fixedCarDamage.get<void>(), 2 );
InjectHook( fixedCarDamage.get<void>( 2 ), FixedCarDamage_Newsteam, PATCH_CALL );
}
// Car explosion crash with multimonitor
// Unitialized collision data breaking stencil shadows
{
void* memMgrAlloc = get_pattern( "E8 ? ? ? ? 66 8B 55 08 8B 4D 10" );
void* newAlloc1 = get_pattern( "33 C9 83 C4 04 3B C1 74 36", -5 );
void* newAlloc2 = get_pattern( "33 C9 83 C4 04 3B C1 74 37", -5 );
ReadCall( memMgrAlloc, orgMemMgrMalloc );
InjectHook( memMgrAlloc, CollisionData_MallocAndInit );
ReadCall( newAlloc1, orgNewAlloc );
InjectHook( newAlloc1, CollisionData_NewAndInit );
InjectHook( newAlloc2, CollisionData_NewAndInit );
}
// Crash when entering advanced display options on a dual monitor machine after:
// - starting game on primary monitor in maximum resolution, exiting,
// starting again in maximum resolution on secondary monitor.
// Secondary monitor maximum resolution had to be greater than maximum resolution of primary monitor.
// Not in 1.01
{
void* storeVideoModes = get_pattern( "6A 00 8B F8 6A 04", -5 );
void* retrieveVideoModes = get_pattern( "57 E8 ? ? ? ? 83 3D", 1 );
ReadCall( storeVideoModes, orgGetNumVideoModes );
InjectHook( storeVideoModes, GetNumVideoModes_Store );
InjectHook( retrieveVideoModes, GetNumVideoModes_Retrieve );
}
// Fixed escalators crash
{
orgEscalatorsUpdate = static_cast<decltype(orgEscalatorsUpdate)>(get_pattern( "80 3D ? ? ? ? ? 74 23 56" ));
// TODO: Simplify when transactional patching is implemented
auto updateEscalators = pattern( "80 3D ? ? ? ? ? 74 22 56" ).count(1);
auto removeEscalatorsForEntity = pattern( "80 7E F5 00 74 56" ).count(1);
if ( updateEscalators.size() == 1 && removeEscalatorsForEntity.size() == 1 )
{
InjectHook( updateEscalators.get_first(), UpdateEscalators, PATCH_JUMP );
// lea ecx, [esi-84] / call CEscalator::SwitchOffNoRemove / jmp loc_734C0A
auto removeEscalatorsMatch = removeEscalatorsForEntity.get_one();
// TODO: Change when short jmps are supported
Patch( removeEscalatorsMatch.get<void>(), { 0x8D, 0x8E } );
Patch<int32_t>( removeEscalatorsMatch.get<void>( 2 ), -0x84 );
InjectHook( removeEscalatorsMatch.get<void>( 6 ), &CEscalator::SwitchOffNoRemove, PATCH_CALL );
Patch( removeEscalatorsMatch.get<void>( 6 + 5 ), { 0xEB, 0x4F } );
}
}
// Don't allocate constant memory for stencil shadows every frame
{
// TODO: Simplify when transactional patching is implemented
auto shadowAlloc = pattern( "83 C4 08 6A 00 68 00 60 00 00" ).count(1);
auto shadowFree = pattern( "A2 ? ? ? ? A1 ? ? ? ? 50 E8" ).count(1);
if ( shadowAlloc.size() == 1 && shadowFree.size() == 1 )
{
auto allocMatch = shadowAlloc.get_one();
InjectHook( allocMatch.get<void>( 3 ), StencilShadowAlloc, PATCH_CALL) ;
Patch( allocMatch.get<void>( 3 + 5 ), { 0xEB, 0x2C } );
Nop( allocMatch.get<void>( 0x3B ), 3 );
Patch( shadowFree.get_first( 5 ), { 0x5F, 0x5E, 0x5B, 0x5D, 0xC3 } ); // pop edi, pop esi, pop ebx, pop ebp, retn
}
}
// "Streaming memory bug" fix
{
void* animInterpolator = get_pattern( "83 C4 1C C7 03 00 30 00 00 5B", -5 );
InjectHook(animInterpolator, GTARtAnimInterpolatorSetCurrentAnim);
}
// Fixed ammo for melee weapons in cheats
{
// TODO: Remove wildcards in patterns once transactional patching is implemented
void* knifeAmmo1 = get_pattern( "6A ? 6A 04 6A FF", 1 );
void* knifeAmmo2 = get_pattern( "6A 01 6A ? 6A 04 6A 01", 2 + 1 );
void* chainsawAmmo1 = get_pattern( "6A ? 6A 09 6A FF", 1 );
void* chainsawAmmo2 = get_pattern( "6A ? 6A 09 6A 01", 1 );
void* parachuteAmmo = get_pattern( "6A ? 6A 2E 6A FF", 1 );
void* katanaAmmo = get_pattern( "83 C4 0C ? ? ? 6A 08 6A FF", 3 );
Patch<BYTE>(knifeAmmo1, 1); // knife
Patch<BYTE>(knifeAmmo2, 1); // knife
Patch<BYTE>(chainsawAmmo1, 1); // chainsaw
Patch<BYTE>(chainsawAmmo2, 1); // chainsaw
Patch<BYTE>(parachuteAmmo, 1); // parachute
// push ebx / push 1
Patch( katanaAmmo, { 0x53, 0x6A, 0x01 } ); // katana
}
// Proper aspect ratios
{
auto calculateAr = pattern( "74 13 D9 05 ? ? ? ? D9 1D" ).get_one(); // 0x734247; has two matches but both from the same function
static const float f43 = 4.0f/3.0f, f54 = 5.0f/4.0f, f169 = 16.0f/9.0f;
Patch<const void*>(calculateAr.get<void>( 2 + 2 ), &f169);
Patch<const void*>(calculateAr.get<void>( 0x1E + 2 ), &f54);
Patch<const void*>(calculateAr.get<void>( 0x31 + 2 ), &f43);
}
// 6 extra directionals on Medium and higher // 6 extra directionals on Medium and higher
// push dword ptr [CGame::currArea] // push dword ptr [CGame::currArea]
// call GetMaxExtraDirectionals // call GetMaxExtraDirectionals
@ -5573,10 +5520,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
else if ( version == 2 ) Patch_SA_Steam(); // Not supported anymore else if ( version == 2 ) Patch_SA_Steam(); // Not supported anymore
else else
{ {
if ( version == 3 ) Patch_SA_NewSteam_r1(); // TODO:
else if ( version == 4 ) Patch_SA_NewSteam_r2(); // Add r1 low violence check to MemoryMgr.GTA via
else if ( version == 5 ) Patch_SA_NewSteam_r2_lv(); // if ( *(DWORD*)DynBaseAddress(0x49F810) == 0x64EC8B55 ) { normal } else { low violence }
Patch_SA_NewSteam_Common(); Patch_SA_NewBinaries_Common();
} }
} }
return TRUE; return TRUE;