mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-12-28 06:43:01 +05:00
Migrated several fixes to use HookEach
Gives each hook intercepting functions its own thunk function, so if another modification intercepts only one of X functions patched by SilentPatch, this will now be preserved. Also makes GTA SA's stored car bomb ownership fix work with the Hoodlum EXE.
This commit is contained in:
parent
de34cfec03
commit
ef65dd7c2d
8 changed files with 314 additions and 206 deletions
|
@ -11,4 +11,21 @@
|
|||
#include "Utils/MemoryMgr.h"
|
||||
#include "Utils/MemoryMgr.GTA.h"
|
||||
|
||||
// Move this to ModUtils when it matures a bit more
|
||||
#define HOOK_EACH_FUNC_CTR(name, ctr, origFunc, hook) \
|
||||
template<std::size_t Ctr, typename Tuple, std::size_t... I, typename Func> \
|
||||
static void _HookEachImpl_##name(Tuple&& tuple, std::index_sequence<I...>, Func&& f) \
|
||||
{ \
|
||||
(f(std::get<I>(tuple), origFunc<Ctr << 16 | I>, hook<Ctr << 16 | I>), ...); \
|
||||
} \
|
||||
\
|
||||
template<std::size_t Ctr = ctr, typename Vars, typename Func> \
|
||||
static void HookEach_##name(Vars&& vars, Func&& f) \
|
||||
{ \
|
||||
auto tuple = std::tuple_cat(std::forward<Vars>(vars)); \
|
||||
_HookEachImpl_##name<Ctr>(std::move(tuple), std::make_index_sequence<std::tuple_size_v<decltype(tuple)>>{}, std::forward<Func>(f)); \
|
||||
}
|
||||
|
||||
#define HOOK_EACH_FUNC(name, orig, hook) HOOK_EACH_FUNC_CTR(name, 0, orig, hook)
|
||||
|
||||
#define DISABLE_FLA_DONATION_WINDOW 0
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "VehicleIII.h"
|
||||
#include "ModelInfoIII.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
|
@ -360,11 +361,19 @@ void __declspec(naked) AutoPilotTimerFix_III()
|
|||
}
|
||||
}
|
||||
|
||||
static void (__thiscall *orgGiveWeapon)( void* ped, unsigned int weapon, unsigned int ammo );
|
||||
static void __fastcall GiveWeapon_SP( void* ped, void*, unsigned int weapon, unsigned int ammo )
|
||||
namespace ZeroAmmoFix
|
||||
{
|
||||
if ( ammo == 0 ) ammo = 1;
|
||||
orgGiveWeapon( ped, weapon, ammo );
|
||||
|
||||
template<std::size_t Index>
|
||||
static void (__fastcall *orgGiveWeapon)(void* ped, void*, unsigned int weapon, unsigned int ammo);
|
||||
|
||||
template<std::size_t Index>
|
||||
static void __fastcall GiveWeapon_SP(void* ped, void*, unsigned int weapon, unsigned int ammo)
|
||||
{
|
||||
orgGiveWeapon<Index>(ped, nullptr, weapon, std::max(1u, ammo));
|
||||
}
|
||||
HOOK_EACH_FUNC(GiveWeapon, orgGiveWeapon, GiveWeapon_SP);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1128,12 +1137,13 @@ void Patch_III_Common()
|
|||
|
||||
// Fixed ammo from SCM
|
||||
{
|
||||
auto give_weapon = get_pattern( "6B C0 4F 51 8B 34", 0x13 );
|
||||
ReadCall( give_weapon, orgGiveWeapon );
|
||||
InjectHook( give_weapon, GiveWeapon_SP );
|
||||
using namespace ZeroAmmoFix;
|
||||
|
||||
give_weapon = get_pattern( "89 C7 A1 ? ? ? ? 55 89 F9 50", 11 );
|
||||
InjectHook( give_weapon, GiveWeapon_SP );
|
||||
std::array<void*, 2> give_weapon = {
|
||||
get_pattern( "6B C0 4F 51 8B 34", 0x13 ),
|
||||
get_pattern( "89 C7 A1 ? ? ? ? 55 89 F9 50", 11 ),
|
||||
};
|
||||
HookEach_GiveWeapon(give_weapon, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -390,12 +390,13 @@ public:
|
|||
|
||||
uint8_t GetWeaponSkillForRenderWeaponPedsForPC_SAMP();
|
||||
|
||||
static inline void (CPed::*orgSay)(uint16_t phrase, uint32_t param2, float volume, bool param4, bool param5, bool param6);
|
||||
template<uint16_t blackSample>
|
||||
void Say_SampleBlackList(uint16_t phrase, uint32_t param2 = 0, float volume = 1.0f, bool param4 = false, bool param5 = false, bool param6 = false)
|
||||
{
|
||||
if ( !(phrase == blackSample) )
|
||||
{
|
||||
Say( phrase, param2, volume, param4, param5, param6 );
|
||||
std::invoke(orgSay, this, phrase, param2, volume, param4, param5, param6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "StdAfxSA.h"
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <d3d9.h>
|
||||
#include <Shlwapi.h>
|
||||
#include <ShlObj.h>
|
||||
|
@ -319,7 +320,6 @@ auto RpAnimBlendClumpGetAssociation = AddressByVersion<void*(*)(RpClump*, ui
|
|||
static void (__thiscall* SetVolume)(void*,float);
|
||||
static BOOL (*IsAlreadyRunning)();
|
||||
static void (*TheScriptsLoad)();
|
||||
static void (*WipeLocalVariableMemoryForMissionScript)();
|
||||
static void (*DoSunAndMoon)();
|
||||
|
||||
auto WorldRemove = AddressByVersion<void(*)(CEntity*)>(0x563280, 0, 0x57D370, { "8B 06 8B 50 0C 8B CE FF D2 8A 46 36 24 07 3C 01 76 0D", -7 });
|
||||
|
@ -453,6 +453,9 @@ static CAEWaveDecoder* __stdcall CAEWaveDecoderInit(CAEDataStream* pStream)
|
|||
return new CAEWaveDecoder(pStream);
|
||||
}
|
||||
|
||||
namespace ScriptFixes
|
||||
{
|
||||
|
||||
static void BasketballFix(unsigned char* pBuf, int nSize)
|
||||
{
|
||||
for ( int i = 0, hits = 0; i < nSize && hits < 7; i++, pBuf++ )
|
||||
|
@ -568,9 +571,8 @@ void TheScriptsLoad_BasketballFix()
|
|||
QuadrupleStuntBonus();
|
||||
}
|
||||
|
||||
void StartNewMission_SCMFixes()
|
||||
static void StartNewMission_SCMFixes()
|
||||
{
|
||||
WipeLocalVariableMemoryForMissionScript();
|
||||
InitializeScriptGlobals();
|
||||
|
||||
const int missionID = ScriptParams[0];
|
||||
|
@ -596,6 +598,20 @@ void StartNewMission_SCMFixes()
|
|||
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void (*orgWipeLocalVariableMemoryForMissionScript)();
|
||||
|
||||
template<std::size_t Index>
|
||||
static void WipeLocalVariableMemoryForMissionScript_ApplyFixes()
|
||||
{
|
||||
orgWipeLocalVariableMemoryForMissionScript<Index>();
|
||||
StartNewMission_SCMFixes();
|
||||
}
|
||||
|
||||
HOOK_EACH_FUNC(SCMFixes, orgWipeLocalVariableMemoryForMissionScript, WipeLocalVariableMemoryForMissionScript_ApplyFixes)
|
||||
|
||||
}
|
||||
|
||||
// 1.01 kinda fixed it
|
||||
bool GetCurrentZoneLockedOrUnlocked(float fPosX, float fPosY)
|
||||
{
|
||||
|
@ -792,32 +808,43 @@ void CreateMirrorBuffers()
|
|||
}
|
||||
}
|
||||
|
||||
RwUInt32 (*orgGetMaxMultiSamplingLevels)();
|
||||
RwUInt32 GetMaxMultiSamplingLevels()
|
||||
namespace MSAAFixes
|
||||
{
|
||||
|
||||
static RwUInt32 GetMaxMultiSamplingLevels_BitScan(RwUInt32 maxSamples)
|
||||
{
|
||||
RwUInt32 maxSamples = orgGetMaxMultiSamplingLevels();
|
||||
RwUInt32 option;
|
||||
_BitScanForward( (DWORD*)&option, maxSamples );
|
||||
return option + 1;
|
||||
}
|
||||
|
||||
static void (*orgChangeMultiSamplingLevels)(RwUInt32);
|
||||
void ChangeMultiSamplingLevels( RwUInt32 level )
|
||||
{
|
||||
orgChangeMultiSamplingLevels( 1 << (level - 1) );
|
||||
}
|
||||
template<typename std::size_t Index>
|
||||
static RwUInt32 (*orgGetMaxMultiSamplingLevels)();
|
||||
|
||||
static void (*orgSetMultiSamplingLevels)(RwUInt32);
|
||||
void SetMultiSamplingLevels( RwUInt32 level )
|
||||
template<typename std::size_t Index>
|
||||
static RwUInt32 GetMaxMultiSamplingLevels()
|
||||
{
|
||||
orgSetMultiSamplingLevels( 1 << (level - 1) );
|
||||
return GetMaxMultiSamplingLevels_BitScan(orgGetMaxMultiSamplingLevels<Index>());
|
||||
}
|
||||
HOOK_EACH_FUNC(GetMaxMultiSamplingLevels, orgGetMaxMultiSamplingLevels, GetMaxMultiSamplingLevels);
|
||||
|
||||
template<typename std::size_t Index>
|
||||
static void (*orgSetOrChangeMultiSamplingLevels)(RwUInt32);
|
||||
|
||||
template<typename std::size_t Index>
|
||||
static void SetOrChangeMultiSamplingLevels(RwUInt32 level)
|
||||
{
|
||||
orgSetOrChangeMultiSamplingLevels<Index>( 1 << (level - 1) );
|
||||
}
|
||||
HOOK_EACH_FUNC(SetOrChangeMultiSamplingLevels, orgSetOrChangeMultiSamplingLevels, SetOrChangeMultiSamplingLevels);
|
||||
|
||||
void MSAAText( char* buffer, const char*, DWORD level )
|
||||
{
|
||||
sprintf_s( buffer, 100, "%ux", 1 << level );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static RwInt32 numSavedVideoModes;
|
||||
static RwInt32 (*orgGetNumVideoModes)();
|
||||
|
@ -831,9 +858,11 @@ RwInt32 GetNumVideoModes_Retrieve()
|
|||
return numSavedVideoModes;
|
||||
}
|
||||
|
||||
namespace UnitializedCollisionDataFix
|
||||
{
|
||||
|
||||
static void* (*orgMemMgrMalloc)(RwUInt32, RwUInt32);
|
||||
void* CollisionData_MallocAndInit( RwUInt32 size, RwUInt32 hint )
|
||||
static void* CollisionData_MallocAndInit( RwUInt32 size, RwUInt32 hint )
|
||||
{
|
||||
CColData* mem = (CColData*)orgMemMgrMalloc( size, hint );
|
||||
|
||||
|
@ -844,16 +873,21 @@ void* CollisionData_MallocAndInit( RwUInt32 size, RwUInt32 hint )
|
|||
return mem;
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void* (*orgNewAlloc)(size_t);
|
||||
void* CollisionData_NewAndInit( size_t size )
|
||||
|
||||
template<std::size_t Index>
|
||||
static void* CollisionData_NewAndInit(size_t size)
|
||||
{
|
||||
CColData* mem = (CColData*)orgNewAlloc( size );
|
||||
CColData* mem = (CColData*)orgNewAlloc<Index>(size);
|
||||
|
||||
mem->m_bFlags = 0;
|
||||
|
||||
return mem;
|
||||
}
|
||||
HOOK_EACH_FUNC(CollisionDataNew, orgNewAlloc, CollisionData_NewAndInit);
|
||||
|
||||
}
|
||||
|
||||
static void (*orgEscalatorsUpdate)();
|
||||
void UpdateEscalators()
|
||||
|
@ -1460,20 +1494,27 @@ namespace VariableResets
|
|||
using VarVariant = std::variant< bool*, int*, TimeNextMadDriverChaseCreated_t<float>*, ResetToTrue_t* >;
|
||||
std::vector<VarVariant> GameVariablesToReset;
|
||||
|
||||
static void (*orgReInitGameObjectVariables)();
|
||||
void ReInitGameObjectVariables()
|
||||
static void ReInitOurVariables()
|
||||
{
|
||||
// First reinit "our" variables in case stock ones rely on those during resetting
|
||||
for ( const auto& var : GameVariablesToReset )
|
||||
{
|
||||
std::visit( []( auto&& v ) {
|
||||
*v = {};
|
||||
}, var );
|
||||
}, var );
|
||||
}
|
||||
|
||||
orgReInitGameObjectVariables();
|
||||
}
|
||||
|
||||
template<std::size_t Index>
|
||||
static void (*orgReInitGameObjectVariables)();
|
||||
|
||||
template<std::size_t Index>
|
||||
void ReInitGameObjectVariables()
|
||||
{
|
||||
// First reinit "our" variables in case stock ones rely on those during resetting
|
||||
ReInitOurVariables();
|
||||
orgReInitGameObjectVariables<Index>();
|
||||
}
|
||||
HOOK_EACH_FUNC(ReInitGameObjectVariables, orgReInitGameObjectVariables, ReInitGameObjectVariables);
|
||||
}
|
||||
|
||||
namespace LightbeamFix
|
||||
|
@ -2914,6 +2955,8 @@ BOOL InjectDelayedPatches_10()
|
|||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableScriptFixes", -1, wcModulePath) == 1 )
|
||||
{
|
||||
using namespace ScriptFixes;
|
||||
|
||||
// Gym glitch fix
|
||||
Patch<WORD>(0x470B03, 0xCD8B);
|
||||
Patch<DWORD>(0x470B0A, 0x8B04508B);
|
||||
|
@ -2922,12 +2965,10 @@ BOOL InjectDelayedPatches_10()
|
|||
InjectHook(0x470B05, &CRunningScript::GetDay_GymGlitch, HookType::Call);
|
||||
|
||||
// Basketball fix
|
||||
ReadCall( 0x489A70, WipeLocalVariableMemoryForMissionScript );
|
||||
ReadCall( 0x5D18F0, TheScriptsLoad );
|
||||
InjectHook(0x5D18F0, TheScriptsLoad_BasketballFix);
|
||||
// Fixed for Hoodlum
|
||||
InjectHook(0x489A70, StartNewMission_SCMFixes);
|
||||
InjectHook(0x4899F0, StartNewMission_SCMFixes);
|
||||
InterceptCall( 0x5D18F0, TheScriptsLoad, TheScriptsLoad_BasketballFix );
|
||||
|
||||
std::array<uintptr_t, 2> wipeLocalVars = { 0x489A70, 0x4899F0 };
|
||||
HookEach_SCMFixes(wipeLocalVars, InterceptCall);
|
||||
}
|
||||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"SkipIntroSplashes", -1, wcModulePath) == 1 )
|
||||
|
@ -3360,6 +3401,8 @@ BOOL InjectDelayedPatches_11()
|
|||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableScriptFixes", -1, wcModulePath) == 1 )
|
||||
{
|
||||
using namespace ScriptFixes;
|
||||
|
||||
// Gym glitch fix
|
||||
Patch<WORD>(0x470B83, 0xCD8B);
|
||||
Patch<DWORD>(0x470B8A, 0x8B04508B);
|
||||
|
@ -3368,12 +3411,10 @@ BOOL InjectDelayedPatches_11()
|
|||
InjectHook(0x470B85, &CRunningScript::GetDay_GymGlitch, HookType::Call);
|
||||
|
||||
// Basketball fix
|
||||
ReadCall( 0x489AF0, WipeLocalVariableMemoryForMissionScript );
|
||||
ReadCall( 0x5D20D0, TheScriptsLoad );
|
||||
InjectHook(0x5D20D0, TheScriptsLoad_BasketballFix);
|
||||
// Fixed for Hoodlum
|
||||
InjectHook(0x489A70, StartNewMission_SCMFixes);
|
||||
InjectHook(0x489AF0, StartNewMission_SCMFixes);
|
||||
InterceptCall( 0x5D20D0, TheScriptsLoad, TheScriptsLoad_BasketballFix );
|
||||
|
||||
std::array<uintptr_t, 2> wipeLocalVars = { 0x489A70, 0x489AF0 };
|
||||
HookEach_SCMFixes(wipeLocalVars, InterceptCall);
|
||||
}
|
||||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"SkipIntroSplashes", -1, wcModulePath) == 1 )
|
||||
|
@ -3536,6 +3577,8 @@ BOOL InjectDelayedPatches_Steam()
|
|||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"EnableScriptFixes", -1, wcModulePath) == 1 )
|
||||
{
|
||||
using namespace ScriptFixes;
|
||||
|
||||
// Gym glitch fix
|
||||
Patch<WORD>(0x476C2A, 0xCD8B);
|
||||
Patch<DWORD>(0x476C31, 0x408B088B);
|
||||
|
@ -3544,12 +3587,10 @@ BOOL InjectDelayedPatches_Steam()
|
|||
InjectHook(0x476C2C, &CRunningScript::GetDay_GymGlitch, HookType::Call);
|
||||
|
||||
// Basketball fix
|
||||
ReadCall( 0x4907AE, WipeLocalVariableMemoryForMissionScript );
|
||||
ReadCall( 0x5EE017, TheScriptsLoad );
|
||||
InjectHook(0x5EE017, TheScriptsLoad_BasketballFix);
|
||||
// Fixed for Hoodlum
|
||||
InjectHook(0x4907AE, StartNewMission_SCMFixes);
|
||||
InjectHook(0x49072E, StartNewMission_SCMFixes);
|
||||
InterceptCall( 0x5EE017, TheScriptsLoad, TheScriptsLoad_BasketballFix );
|
||||
|
||||
std::array<uintptr_t, 2> wipeLocalVars = { 0x4907AE, 0x49072E };
|
||||
HookEach_SCMFixes(wipeLocalVars, InterceptCall);
|
||||
}
|
||||
|
||||
if ( GetPrivateProfileIntW(L"SilentPatch", L"SmallSteamTexts", -1, wcModulePath) == 0 )
|
||||
|
@ -3815,10 +3856,8 @@ void Patch_SA_10()
|
|||
{
|
||||
using namespace LightbeamFix;
|
||||
|
||||
ReadCall( 0x6A2EDA, CVehicle::orgDoHeadLightBeam );
|
||||
InjectHook( 0x6A2EDA, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj );
|
||||
InjectHook( 0x6A2EF2, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj );
|
||||
InjectHook( 0x6BDE80, &CVehicle::DoHeadLightBeam_LightBeamFixSaveObj );
|
||||
std::array<uintptr_t, 3> doHeadLightBeam = { 0x6A2EDA, 0x6A2EF2, 0x6BDE80 };
|
||||
CVehicle::HookEach_DoHeadLightBeam(doHeadLightBeam, InterceptCall);
|
||||
|
||||
Patch( 0x6E0F37 + 2, &RenderStateWrapper<rwRENDERSTATEZWRITEENABLE>::PushStatePPtr );
|
||||
Patch( 0x6E0F63 + 1, &RenderStateWrapper<rwRENDERSTATEZTESTENABLE>::PushStatePPtr );
|
||||
|
@ -4038,28 +4077,25 @@ void Patch_SA_10()
|
|||
InjectHook(0x72701D, CreateMirrorBuffers);
|
||||
|
||||
// Fixed MSAA options
|
||||
Patch<BYTE>(0x57D126, 0xEB);
|
||||
Nop(0x57D0E8, 2);
|
||||
{
|
||||
using namespace MSAAFixes;
|
||||
|
||||
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F6C9B), 0xEB);
|
||||
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F60C6), 0xEB);
|
||||
Patch(AddressByRegion_10<BYTE*>(0x7F6683), { 0x90, 0xE9 });
|
||||
Patch<BYTE>(0x57D126, 0xEB);
|
||||
Nop(0x57D0E8, 2);
|
||||
|
||||
ReadCall( 0x57D136, orgGetMaxMultiSamplingLevels );
|
||||
InjectHook(0x57D136, GetMaxMultiSamplingLevels);
|
||||
InjectHook(0x57D0EA, GetMaxMultiSamplingLevels);
|
||||
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F6C9B), 0xEB);
|
||||
Patch<BYTE>(AddressByRegion_10<BYTE*>(0x7F60C6), 0xEB);
|
||||
Patch(AddressByRegion_10<BYTE*>(0x7F6683), { 0x90, 0xE9 });
|
||||
|
||||
ReadCall( 0x5744FD, orgChangeMultiSamplingLevels );
|
||||
InjectHook(0x5744FD, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x57D162, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x57D2A6, ChangeMultiSamplingLevels);
|
||||
std::array<uintptr_t, 2> getMaxMultiSamplingLevels = { 0x57D136, 0x57D0EA };
|
||||
HookEach_GetMaxMultiSamplingLevels(getMaxMultiSamplingLevels, InterceptCall);
|
||||
|
||||
ReadCall( 0x746350, orgSetMultiSamplingLevels );
|
||||
InjectHook(0x746350, SetMultiSamplingLevels);
|
||||
|
||||
Nop(0x57A0FC, 1);
|
||||
InjectHook(0x57A0FD, MSAAText, HookType::Call);
|
||||
std::array<uintptr_t, 4> setOrChangeMultiSamplingLevels = { 0x5744FD, 0x57D162, 0x57D2A6, 0x746350 };
|
||||
HookEach_SetOrChangeMultiSamplingLevels(setOrChangeMultiSamplingLevels, InterceptCall);
|
||||
|
||||
Nop(0x57A0FC, 1);
|
||||
InjectHook(0x57A0FD, MSAAText, HookType::Call);
|
||||
}
|
||||
|
||||
// Fixed car collisions - car you're hitting gets proper damage now
|
||||
InjectHook(0x5428EA, FixedCarDamage, HookType::Call);
|
||||
|
@ -4067,15 +4103,16 @@ void Patch_SA_10()
|
|||
|
||||
// Car explosion crash with multimonitor
|
||||
// Unitialized collision data breaking stencil shadows
|
||||
VP::InterceptCall(ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F870) + 0x63, orgMemMgrMalloc, CollisionData_MallocAndInit);
|
||||
{
|
||||
const uintptr_t pHoodlumCompat = ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F740);
|
||||
const uintptr_t pHoodlumCompat2 = ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F810);
|
||||
using namespace UnitializedCollisionDataFix;
|
||||
|
||||
const uintptr_t pNewAlloc = pHoodlumCompat + 0xC;
|
||||
ReadCall( pNewAlloc, orgNewAlloc );
|
||||
VP::InjectHook(pHoodlumCompat + 0xC, CollisionData_NewAndInit);
|
||||
VP::InjectHook(pHoodlumCompat2 + 0xD, CollisionData_NewAndInit);
|
||||
VP::InterceptCall(ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F870) + 0x63, orgMemMgrMalloc, CollisionData_MallocAndInit);
|
||||
|
||||
std::array<uintptr_t, 2> newAndInit = {
|
||||
ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F740) + 0xC,
|
||||
ModCompat::Utils::GetFunctionAddrIfRerouted(0x40F810) + 0xD,
|
||||
};
|
||||
HookEach_CollisionDataNew(newAndInit, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4173,14 +4210,14 @@ void Patch_SA_10()
|
|||
|
||||
|
||||
// Animated Phoenix hood scoop
|
||||
auto* automobilePreRender = (*(decltype(CAutomobile::orgAutomobilePreRender)**)(0x6B0AD2 + 2)) + 17;
|
||||
CAutomobile::orgAutomobilePreRender = *automobilePreRender;
|
||||
Patch(automobilePreRender, &CAutomobile::PreRender_Stub);
|
||||
|
||||
InjectHook(0x6C7E7A, &CAutomobile::PreRender_Stub);
|
||||
InjectHook(0x6CEAEC, &CAutomobile::PreRender_Stub);
|
||||
InjectHook(0x6CFADC, &CAutomobile::PreRender_Stub);
|
||||
{
|
||||
auto* automobilePreRender = (*(decltype(CAutomobile::orgAutomobilePreRender<0>)**)(0x6B0AD2 + 2)) + 17;
|
||||
CAutomobile::orgAutomobilePreRender<0> = *automobilePreRender;
|
||||
Patch(automobilePreRender, &CAutomobile::PreRender_SilentPatch<0>);
|
||||
|
||||
std::array<uintptr_t, 3> preRender = { 0x6C7E7A, 0x6CEAEC, 0x6CFADC };
|
||||
CAutomobile::HookEach_PreRender(preRender, InterceptCall);
|
||||
}
|
||||
|
||||
// Extra animations for planes
|
||||
auto* planePreRender = (*(decltype(CPlane::orgPlanePreRender)**)(0x6C8E5A + 2)) + 17;
|
||||
|
@ -4236,9 +4273,11 @@ void Patch_SA_10()
|
|||
|
||||
// Fixed bomb ownership/bombs saving for bikes
|
||||
{
|
||||
ReadCall( 0x44856A, CStoredCar::orgRestoreCar );
|
||||
InjectHook( 0x44856A, &CStoredCar::RestoreCar_SilentPatch );
|
||||
InjectHook( 0x4485DB, &CStoredCar::RestoreCar_SilentPatch );
|
||||
std::array<uintptr_t, 2> restoreCar = {
|
||||
ModCompat::Utils::GetFunctionAddrIfRerouted(0x448550) + 0x1A,
|
||||
ModCompat::Utils::GetFunctionAddrIfRerouted(0x4485C0) + 0x1B,
|
||||
};
|
||||
CStoredCar::HookEach_RestoreCar(restoreCar, VP::InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
|
@ -4354,19 +4393,18 @@ void Patch_SA_10()
|
|||
|
||||
|
||||
// Play passenger's voice lines when killing peds with car, not only when hitting them damages player's vehicle
|
||||
ReadCall( 0x5F05CA, CEntity::orgGetColModel );
|
||||
InjectHook( 0x5F05CA, &CVehicle::PlayPedHitSample_GetColModel );
|
||||
InterceptCall(0x5F05CA, CEntity::orgGetColModel, &CVehicle::PlayPedHitSample_GetColModel);
|
||||
|
||||
// Prevent samples from playing where they used to, so passengers don't comment on gently pushing peds
|
||||
InjectHook( 0x6A8298, &CPed::Say_SampleBlackList<CONTEXT_GLOBAL_CAR_HIT_PED> );
|
||||
InterceptCall(0x6A8298, CPed::orgSay, &CPed::Say_SampleBlackList<CONTEXT_GLOBAL_CAR_HIT_PED>);
|
||||
|
||||
|
||||
// Reset variables on New Game
|
||||
{
|
||||
using namespace VariableResets;
|
||||
|
||||
ReadCall( 0x53C6DB, orgReInitGameObjectVariables );
|
||||
InjectHook( 0x53C6DB, ReInitGameObjectVariables );
|
||||
InjectHook( 0x53C76D, ReInitGameObjectVariables );
|
||||
std::array<uintptr_t, 2> reInitGameObjectVariables = { 0x53C6DB, 0x53C76D };
|
||||
HookEach_ReInitGameObjectVariables(reInitGameObjectVariables, InterceptCall);
|
||||
|
||||
// Variables to reset
|
||||
GameVariablesToReset.emplace_back( *(bool**)(0x63E8D8+1) ); // CPlayerPed::bHasDisplayedPlayerQuitEnterCarHelpText
|
||||
|
@ -4834,27 +4872,25 @@ void Patch_SA_11()
|
|||
InjectHook(0x72784D, CreateMirrorBuffers);
|
||||
|
||||
// Fixed MSAA options
|
||||
Patch<BYTE>(0x57D906, 0xEB);
|
||||
Nop(0x57D8C8, 2);
|
||||
{
|
||||
using namespace MSAAFixes;
|
||||
|
||||
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F759B), 0xEB);
|
||||
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F69C6), 0xEB);
|
||||
Patch(AddressByRegion_11<BYTE*>(0x7F6F83), { 0x90, 0xE9 });
|
||||
Patch<BYTE>(0x57D906, 0xEB);
|
||||
Nop(0x57D8C8, 2);
|
||||
|
||||
ReadCall( 0x57D916, orgGetMaxMultiSamplingLevels );
|
||||
InjectHook(0x57D916, GetMaxMultiSamplingLevels);
|
||||
InjectHook(0x57D8CA, GetMaxMultiSamplingLevels);
|
||||
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F759B), 0xEB);
|
||||
Patch<BYTE>(AddressByRegion_11<BYTE*>(0x7F69C6), 0xEB);
|
||||
Patch(AddressByRegion_11<BYTE*>(0x7F6F83), { 0x90, 0xE9 });
|
||||
|
||||
ReadCall( 0x574A6D, orgChangeMultiSamplingLevels );
|
||||
InjectHook(0x574A6D, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x57D942, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x57DA86, ChangeMultiSamplingLevels);
|
||||
std::array<uintptr_t, 2> getMaxMultiSamplingLevels = { 0x57D916, 0x57D8CA };
|
||||
HookEach_GetMaxMultiSamplingLevels(getMaxMultiSamplingLevels, InterceptCall);
|
||||
|
||||
ReadCall( 0x746BD0, orgSetMultiSamplingLevels );
|
||||
InjectHook(0x746BD0, SetMultiSamplingLevels);
|
||||
std::array<uintptr_t, 4> setOrChangeMultiSamplingLevels = { 0x574A6D, 0x57D942, 0x57DA86, 0x746BD0 };
|
||||
HookEach_SetOrChangeMultiSamplingLevels(setOrChangeMultiSamplingLevels, InterceptCall);
|
||||
|
||||
Nop(0x57A66C, 1);
|
||||
InjectHook(0x57A66D, MSAAText, HookType::Call);
|
||||
Nop(0x57A66C, 1);
|
||||
InjectHook(0x57A66D, MSAAText, HookType::Call);
|
||||
}
|
||||
|
||||
// Fixed car collisions - car you're hitting gets proper damage now
|
||||
InjectHook(0x542D8A, FixedCarDamage, HookType::Call);
|
||||
|
@ -5145,27 +5181,25 @@ void Patch_SA_Steam()
|
|||
InjectHook(0x758E91, CreateMirrorBuffers);
|
||||
|
||||
// Fixed MSAA options
|
||||
Patch<BYTE>(0x592BBB, 0xEB);
|
||||
Nop(0x592B7F, 2);
|
||||
{
|
||||
using namespace MSAAFixes;
|
||||
|
||||
Patch<BYTE>(0x830C5B, 0xEB);
|
||||
Patch<BYTE>(0x830086, 0xEB);
|
||||
Patch(0x830643, { 0x90, 0xE9 });
|
||||
Patch<BYTE>(0x592BBB, 0xEB);
|
||||
Nop(0x592B7F, 2);
|
||||
|
||||
ReadCall( 0x592BCF, orgGetMaxMultiSamplingLevels );
|
||||
InjectHook(0x592BCF, GetMaxMultiSamplingLevels);
|
||||
InjectHook(0x592B81, GetMaxMultiSamplingLevels);
|
||||
Patch<BYTE>(0x830C5B, 0xEB);
|
||||
Patch<BYTE>(0x830086, 0xEB);
|
||||
Patch(0x830643, { 0x90, 0xE9 });
|
||||
|
||||
ReadCall( 0x5897CD, orgChangeMultiSamplingLevels );
|
||||
InjectHook(0x5897CD, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x592BFB, ChangeMultiSamplingLevels);
|
||||
InjectHook(0x592D2E, ChangeMultiSamplingLevels);
|
||||
std::array<uintptr_t, 2> getMaxMultiSamplingLevels = { 0x592BCF, 0x592B81 };
|
||||
HookEach_GetMaxMultiSamplingLevels(getMaxMultiSamplingLevels, InterceptCall);
|
||||
|
||||
ReadCall( 0x780206, orgSetMultiSamplingLevels );
|
||||
InjectHook(0x780206, SetMultiSamplingLevels);
|
||||
std::array<uintptr_t, 4> setOrChangeMultiSamplingLevels = { 0x5897CD, 0x592BFB, 0x592D2E, 0x780206 };
|
||||
HookEach_SetOrChangeMultiSamplingLevels(setOrChangeMultiSamplingLevels, InterceptCall);
|
||||
|
||||
Patch(0x58F88C, { 0x90, 0xBA });
|
||||
Patch(0x58F88E, MSAAText);
|
||||
Patch(0x58F88C, { 0x90, 0xBA });
|
||||
Patch(0x58F88E, MSAAText);
|
||||
}
|
||||
|
||||
// Fixed car collisions - car you're hitting gets proper damage now
|
||||
Nop(0x555AB8, 2);
|
||||
|
@ -5174,12 +5208,14 @@ void Patch_SA_Steam()
|
|||
|
||||
// Car explosion crash with multimonitor
|
||||
// Unitialized collision data breaking stencil shadows
|
||||
ReadCall( 0x41A216, orgMemMgrMalloc );
|
||||
InjectHook(0x41A216, CollisionData_MallocAndInit);
|
||||
{
|
||||
using namespace UnitializedCollisionDataFix;
|
||||
|
||||
ReadCall( 0x41A07C, orgNewAlloc );
|
||||
InjectHook(0x41A07C, CollisionData_NewAndInit);
|
||||
InjectHook(0x41A159, CollisionData_NewAndInit);
|
||||
InterceptCall(0x41A216, orgMemMgrMalloc, CollisionData_MallocAndInit);
|
||||
|
||||
std::array<uintptr_t, 2> newAndInit = { 0x41A07C, 0x41A159 };
|
||||
HookEach_CollisionDataNew(newAndInit, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
// Crash when entering advanced display options on a dual monitor machine after:
|
||||
|
@ -5533,6 +5569,8 @@ void Patch_SA_NewBinaries_Common()
|
|||
|
||||
// Fixed MSAA options
|
||||
{
|
||||
using namespace MSAAFixes;
|
||||
|
||||
// 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 );
|
||||
|
@ -5551,17 +5589,19 @@ void Patch_SA_NewBinaries_Common()
|
|||
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);
|
||||
std::array<void*, 2> getMaxMultiSamplingLevels = {
|
||||
getMaxMultisamplingLevels.get<void>( -5 ),
|
||||
func1.get<void>( 7 + 2 ),
|
||||
};
|
||||
HookEach_GetMaxMultiSamplingLevels(getMaxMultiSamplingLevels, InterceptCall);
|
||||
|
||||
ReadCall( changeMultiSamplingLevels, orgChangeMultiSamplingLevels );
|
||||
InjectHook( changeMultiSamplingLevels, ChangeMultiSamplingLevels );
|
||||
InjectHook( getMaxMultisamplingLevels.get<void>( -5 + 0x30 ), ChangeMultiSamplingLevels );
|
||||
InjectHook( changeMultiSamplingLevels2, ChangeMultiSamplingLevels );
|
||||
|
||||
ReadCall( setMultiSamplingLevels, orgSetMultiSamplingLevels );
|
||||
InjectHook( setMultiSamplingLevels, SetMultiSamplingLevels );
|
||||
std::array<void*, 4> setOrChangeMultiSamplingLevels = {
|
||||
changeMultiSamplingLevels,
|
||||
getMaxMultisamplingLevels.get<void>( -5 + 0x30 ),
|
||||
changeMultiSamplingLevels2,
|
||||
setMultiSamplingLevels
|
||||
};
|
||||
HookEach_SetOrChangeMultiSamplingLevels(setOrChangeMultiSamplingLevels, InterceptCall);
|
||||
|
||||
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
|
||||
|
@ -5585,16 +5625,16 @@ void Patch_SA_NewBinaries_Common()
|
|||
// Car explosion crash with multimonitor
|
||||
// Unitialized collision data breaking stencil shadows
|
||||
{
|
||||
using namespace UnitializedCollisionDataFix;
|
||||
|
||||
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 );
|
||||
std::array<void*, 2> newAlloc = {
|
||||
get_pattern( "33 C9 83 C4 04 3B C1 74 36", -5 ),
|
||||
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 );
|
||||
InterceptCall(memMgrAlloc, orgMemMgrMalloc, CollisionData_MallocAndInit);
|
||||
HookEach_CollisionDataNew(newAlloc, InterceptCall);
|
||||
}
|
||||
|
||||
// Crash when entering advanced display options on a dual monitor machine after:
|
||||
|
@ -5730,12 +5770,11 @@ void Patch_SA_NewBinaries_Common()
|
|||
using namespace VariableResets;
|
||||
|
||||
{
|
||||
auto reinit1 = get_pattern( "E8 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? 38 1D" );
|
||||
auto reinit2 = get_pattern( "E8 ? ? ? ? 89 1D ? ? ? ? E8 ? ? ? ? 5E" );
|
||||
|
||||
ReadCall( reinit1, orgReInitGameObjectVariables );
|
||||
InjectHook( reinit1, ReInitGameObjectVariables );
|
||||
InjectHook( reinit2, ReInitGameObjectVariables );
|
||||
std::array<void*, 2> reInitGameObjectVariables = {
|
||||
get_pattern( "E8 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ? 38 1D" ),
|
||||
get_pattern( "E8 ? ? ? ? 89 1D ? ? ? ? E8 ? ? ? ? 5E" )
|
||||
};
|
||||
HookEach_ReInitGameObjectVariables(reInitGameObjectVariables, InterceptCall);
|
||||
}
|
||||
|
||||
// Variables to reset
|
||||
|
@ -5828,12 +5867,11 @@ void Patch_SA_NewBinaries_Common()
|
|||
|
||||
// Fixed bomb ownership/bombs saving for bikes
|
||||
{
|
||||
auto restoreForHideout = get_pattern( "8D 4E EE E8", 3 );
|
||||
auto restoreImpoundGarage = get_pattern( "8D 4F EE E8", 3 );
|
||||
|
||||
ReadCall( restoreForHideout, CStoredCar::orgRestoreCar );
|
||||
InjectHook( restoreForHideout, &CStoredCar::RestoreCar_SilentPatch );
|
||||
InjectHook( restoreImpoundGarage, &CStoredCar::RestoreCar_SilentPatch );
|
||||
std::array<void*, 2> restoreCar = {
|
||||
get_pattern( "8D 4E EE E8", 3 ),
|
||||
get_pattern( "8D 4F EE E8", 3 )
|
||||
};
|
||||
CStoredCar::HookEach_RestoreCar(restoreCar, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,23 @@
|
|||
|
||||
#include "TheFLAUtils.h"
|
||||
|
||||
// Move this to ModUtils when it matures a bit more
|
||||
#define HOOK_EACH_FUNC_CTR(name, ctr, origFunc, hook) \
|
||||
template<std::size_t Ctr, typename Tuple, std::size_t... I, typename Func> \
|
||||
static void _HookEachImpl_##name(Tuple&& tuple, std::index_sequence<I...>, Func&& f) \
|
||||
{ \
|
||||
(f(std::get<I>(tuple), origFunc<Ctr << 16 | I>, hook<Ctr << 16 | I>), ...); \
|
||||
} \
|
||||
\
|
||||
template<std::size_t Ctr = ctr, typename Vars, typename Func> \
|
||||
static void HookEach_##name(Vars&& vars, Func&& f) \
|
||||
{ \
|
||||
auto tuple = std::tuple_cat(std::forward<Vars>(vars)); \
|
||||
_HookEachImpl_##name<Ctr>(std::move(tuple), std::make_index_sequence<std::tuple_size_v<decltype(tuple)>>{}, std::forward<Func>(f)); \
|
||||
}
|
||||
|
||||
#define HOOK_EACH_FUNC(name, orig, hook) HOOK_EACH_FUNC_CTR(name, 0, orig, hook)
|
||||
|
||||
// SA operator delete
|
||||
extern void (*GTAdelete)(void* data);
|
||||
extern const char* (*GetFrameNodeName)(RwFrame*);
|
||||
|
|
|
@ -114,9 +114,7 @@ WRAPPER bool CVehicle::IsLawEnforcementVehicle() { VARJMP(varIsLawEnforcementVeh
|
|||
|
||||
auto GetFrameHierarchyId = AddressByVersion<int32_t(*)(RwFrame*)>(0x732A20, 0x733250, 0x76CC30);
|
||||
|
||||
void (CAutomobile::*CAutomobile::orgAutomobilePreRender)();
|
||||
void (CPlane::*CPlane::orgPlanePreRender)();
|
||||
CVehicle* (CStoredCar::*CStoredCar::orgRestoreCar)();
|
||||
|
||||
static int32_t random(int32_t from, int32_t to)
|
||||
{
|
||||
|
@ -263,14 +261,6 @@ bool CVehicle::IgnoresLightbeamFix() const
|
|||
return SVF::ModelHasFeature( m_nModelIndex.Get(), SVF::Feature::_INTERNAL_NO_LIGHTBEAM_BFC_FIX );
|
||||
}
|
||||
|
||||
|
||||
void CVehicle::DoHeadLightBeam_LightBeamFixSaveObj(int type, CMatrix& m, bool right)
|
||||
{
|
||||
LightbeamFix::SetCurrentVehicle( this );
|
||||
DoHeadLightBeam( type, m, right );
|
||||
LightbeamFix::SetCurrentVehicle( nullptr );
|
||||
}
|
||||
|
||||
bool CVehicle::CustomCarPlate_TextureCreate(CVehicleModelInfo* pModelInfo)
|
||||
{
|
||||
char PlateText[CVehicleModelInfo::PLATE_TEXT_LEN+1];
|
||||
|
@ -551,13 +541,14 @@ RwFrame* CAutomobile::GetTowBarFrame() const
|
|||
return towBar;
|
||||
}
|
||||
|
||||
void CAutomobile::PreRender()
|
||||
void CAutomobile::BeforePreRender()
|
||||
{
|
||||
// For rotating engine components
|
||||
ms_engineCompSpeed = m_nVehicleFlags.bEngineOn ? CTimer::m_fTimeStep : 0.0f;
|
||||
}
|
||||
|
||||
(this->*(orgAutomobilePreRender))();
|
||||
|
||||
void CAutomobile::AfterPreRender()
|
||||
{
|
||||
const int32_t extID = m_nModelIndex.Get();
|
||||
if ( SVF::ModelHasFeature( extID, SVF::Feature::PHOENIX_FLUTTER ) )
|
||||
{
|
||||
|
@ -725,21 +716,19 @@ bool CTrailer::GetTowBarPos(CVector& posnOut, bool defaultPos, CVehicle* trailer
|
|||
return GetTowBarPos_GTA(posnOut, defaultPos, trailer);
|
||||
}
|
||||
|
||||
CVehicle* CStoredCar::RestoreCar_SilentPatch()
|
||||
CVehicle* CStoredCar::RestoreCar_LoadBombOwnership(CVehicle* vehicle)
|
||||
{
|
||||
CVehicle* vehicle = (this->*(orgRestoreCar))();
|
||||
if ( vehicle == nullptr ) return nullptr;
|
||||
|
||||
if ( m_bombType != 0 )
|
||||
if (vehicle != nullptr)
|
||||
{
|
||||
// Fixup bomb stuff
|
||||
if ( vehicle->GetClass() == VEHICLE_AUTOMOBILE || vehicle->GetClass() == VEHICLE_BIKE )
|
||||
if (m_bombType != 0)
|
||||
{
|
||||
vehicle->SetBombOnBoard( m_bombType );
|
||||
vehicle->SetBombOwner( FindPlayerPed() );
|
||||
// Fixup bomb stuff
|
||||
if (vehicle->GetClass() == VEHICLE_AUTOMOBILE || vehicle->GetClass() == VEHICLE_BIKE)
|
||||
{
|
||||
vehicle->SetBombOnBoard(m_bombType);
|
||||
vehicle->SetBombOwner(FindPlayerPed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return vehicle;
|
||||
}
|
||||
|
||||
|
|
|
@ -273,20 +273,26 @@ public:
|
|||
static void SetComponentRotation( RwFrame* component, eRotAxis axis, float angle, bool absolute = true );
|
||||
static void SetComponentAtomicAlpha(RpAtomic* pAtomic, int nAlpha);
|
||||
|
||||
static inline void (CVehicle::*orgDoHeadLightBeam)( int type, CMatrix& m, bool right );
|
||||
|
||||
static inline int8_t ms_lightbeamFixOverride = 0, ms_rotorFixOverride = 0; // 0 - normal, 1 - always on, -1 - always off
|
||||
bool IgnoresLightbeamFix() const;
|
||||
bool IgnoresRotorFix() const;
|
||||
|
||||
bool IsOpenTopCarOrQuadbike() const;
|
||||
|
||||
void DoHeadLightBeam( int type, CMatrix& m, bool right )
|
||||
private:
|
||||
template<std::size_t Index>
|
||||
static void (CVehicle::*orgDoHeadLightBeam)(int type, CMatrix& m, bool right);
|
||||
|
||||
template<std::size_t Index>
|
||||
void DoHeadLightBeam_LightBeamFixSaveObj(int type, CMatrix& m, bool right)
|
||||
{
|
||||
std::invoke( orgDoHeadLightBeam, this, type, m, right );
|
||||
LightbeamFix::SetCurrentVehicle(this);
|
||||
std::invoke(orgDoHeadLightBeam<Index>, this, type, m, right);
|
||||
LightbeamFix::SetCurrentVehicle(nullptr);
|
||||
}
|
||||
|
||||
void DoHeadLightBeam_LightBeamFixSaveObj( int type, CMatrix& m, bool right );
|
||||
public:
|
||||
HOOK_EACH_FUNC(DoHeadLightBeam, orgDoHeadLightBeam, &DoHeadLightBeam_LightBeamFixSaveObj);
|
||||
};
|
||||
|
||||
class NOVMT CAutomobile : public CVehicle
|
||||
|
@ -309,18 +315,27 @@ public:
|
|||
BYTE __pad3[44];
|
||||
|
||||
public:
|
||||
inline void PreRender_Stub()
|
||||
{ CAutomobile::PreRender(); }
|
||||
template<std::size_t Index>
|
||||
static void (CAutomobile::*orgAutomobilePreRender)();
|
||||
|
||||
virtual void PreRender() override;
|
||||
template<std::size_t Index>
|
||||
void PreRender_SilentPatch()
|
||||
{
|
||||
BeforePreRender();
|
||||
std::invoke(orgAutomobilePreRender<Index>, this);
|
||||
AfterPreRender();
|
||||
}
|
||||
|
||||
HOOK_EACH_FUNC_CTR(PreRender, 1, orgAutomobilePreRender, &PreRender_SilentPatch);
|
||||
|
||||
void Fix_SilentPatch();
|
||||
RwFrame* GetTowBarFrame() const;
|
||||
|
||||
static void (CAutomobile::*orgAutomobilePreRender)();
|
||||
static float ms_engineCompSpeed;
|
||||
|
||||
private:
|
||||
void BeforePreRender();
|
||||
void AfterPreRender();
|
||||
void ResetFrames();
|
||||
void ProcessPhoenixBlower( int32_t modelID );
|
||||
void ProcessSweeper();
|
||||
|
@ -397,10 +412,21 @@ private:
|
|||
uint8_t m_nitro;
|
||||
int8_t m_angleX, m_angleY, m_angleZ;
|
||||
|
||||
public:
|
||||
private:
|
||||
template<std::size_t Index>
|
||||
static CVehicle* (CStoredCar::*orgRestoreCar)();
|
||||
|
||||
template<std::size_t Index>
|
||||
CVehicle* RestoreCar_SilentPatch()
|
||||
{
|
||||
return RestoreCar_LoadBombOwnership(std::invoke(orgRestoreCar<Index>, this));
|
||||
}
|
||||
|
||||
CVehicle* RestoreCar_SilentPatch();
|
||||
public:
|
||||
HOOK_EACH_FUNC(RestoreCar, orgRestoreCar, &RestoreCar_SilentPatch);
|
||||
|
||||
private:
|
||||
CVehicle* RestoreCar_LoadBombOwnership(CVehicle* vehicle);
|
||||
};
|
||||
|
||||
void ReadRotorFixExceptions(const wchar_t* pPath);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "VehicleVC.h"
|
||||
#include "SVF.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <Shlwapi.h>
|
||||
|
||||
|
@ -255,11 +256,19 @@ void __declspec(naked) AutoPilotTimerFix_VC()
|
|||
}
|
||||
}
|
||||
|
||||
static void (__thiscall *orgGiveWeapon)( void* ped, unsigned int weapon, unsigned int ammo, bool flag );
|
||||
static void __fastcall GiveWeapon_SP( void* ped, void*, unsigned int weapon, unsigned int ammo, bool flag )
|
||||
namespace ZeroAmmoFix
|
||||
{
|
||||
if ( ammo == 0 ) ammo = 1;
|
||||
orgGiveWeapon( ped, weapon, ammo, flag );
|
||||
|
||||
template<std::size_t Index>
|
||||
static void (__fastcall *orgGiveWeapon)(void* ped, void*, unsigned int weapon, unsigned int ammo);
|
||||
|
||||
template<std::size_t Index>
|
||||
static void __fastcall GiveWeapon_SP(void* ped, void*, unsigned int weapon, unsigned int ammo)
|
||||
{
|
||||
orgGiveWeapon<Index>(ped, nullptr, weapon, std::max(1u, ammo));
|
||||
}
|
||||
HOOK_EACH_FUNC(GiveWeapon, orgGiveWeapon, GiveWeapon_SP);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1029,12 +1038,13 @@ void Patch_VC_Common()
|
|||
|
||||
// Fixed ammo from SCM
|
||||
{
|
||||
auto give_weapon = get_pattern( "6B C0 2E 6A 01 56 8B 3C", 0x15 );
|
||||
ReadCall( give_weapon, orgGiveWeapon );
|
||||
InjectHook( give_weapon, GiveWeapon_SP );
|
||||
using namespace ZeroAmmoFix;
|
||||
|
||||
give_weapon = get_pattern( "89 F9 6A 01 55 50 E8", 6 );
|
||||
InjectHook( give_weapon, GiveWeapon_SP );
|
||||
std::array<void*, 2> give_weapon = {
|
||||
get_pattern( "6B C0 2E 6A 01 56 8B 3C", 0x15 ),
|
||||
get_pattern( "89 F9 6A 01 55 50 E8", 6 ),
|
||||
};
|
||||
HookEach_GiveWeapon(give_weapon, InterceptCall);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue