From 9ede0c1c6ab404fe6d25e112fe49f0f6f730ad72 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:32:32 +0100 Subject: [PATCH 01/18] Update signature of ZSecuritySystemCameraManager::OnFrameUpdate and ZSecuritySystemCamera::FrameUpdate --- Mods/Player/Src/Player.cpp | 4 ++-- Mods/Player/Src/Player.h | 16 ++++++++++++++-- ZHMModSDK/Include/Hooks.h | 4 ++-- ZHMModSDK/Src/Hooks.cpp | 4 ++-- 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index a289dd9f..9529fe89 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -614,7 +614,7 @@ DEFINE_PLUGIN_DETOUR( void, ZSecuritySystemCameraManager_OnFrameUpdate, ZSecuritySystemCameraManager* th, - const SGameUpdateEvent* const updateEvent + const SGameUpdateEvent& updateEvent ) { if (m_IsInvisible) { return HookResult(HookAction::Return()); @@ -628,7 +628,7 @@ DEFINE_PLUGIN_DETOUR( void, ZSecuritySystemCamera_FrameUpdate, ZSecuritySystemCamera* th, - const SGameUpdateEvent* const updateEvent + const SGameUpdateEvent& updateEvent ) { if (m_IsInvisible) { return HookResult(HookAction::Return()); diff --git a/Mods/Player/Src/Player.h b/Mods/Player/Src/Player.h index 01e17273..63b22caa 100644 --- a/Mods/Player/Src/Player.h +++ b/Mods/Player/Src/Player.h @@ -28,8 +28,20 @@ class Player : public IPluginInterface { DECLARE_PLUGIN_DETOUR(Player, void, OnClearScene, ZEntitySceneContext* th, bool p_FullyUnloadScene); - DECLARE_PLUGIN_DETOUR(Player, void, ZSecuritySystemCameraManager_OnFrameUpdate, ZSecuritySystemCameraManager* th, const SGameUpdateEvent* const updateEvent); - DECLARE_PLUGIN_DETOUR(Player, void, ZSecuritySystemCamera_FrameUpdate, ZSecuritySystemCamera* th, const SGameUpdateEvent* const updateEvent); + DECLARE_PLUGIN_DETOUR( + Player, + void, + ZSecuritySystemCameraManager_OnFrameUpdate, + ZSecuritySystemCameraManager* th, + const SGameUpdateEvent& updateEvent + ); + DECLARE_PLUGIN_DETOUR( + Player, + void, + ZSecuritySystemCamera_FrameUpdate, + ZSecuritySystemCamera* th, + const SGameUpdateEvent& updateEvent + ); bool m_PlayerMenuActive = false; bool m_IsInvincible = false; diff --git a/ZHMModSDK/Include/Hooks.h b/ZHMModSDK/Include/Hooks.h index 9a1e454b..ee1491ef 100644 --- a/ZHMModSDK/Include/Hooks.h +++ b/ZHMModSDK/Include/Hooks.h @@ -239,8 +239,8 @@ class ZHMSDK_API Hooks { static Hook* ZEntitySceneContext_SetLoadingStage; static Hook* ZSecuritySystemCameraManager_UpdateCameraState; - static Hook* ZSecuritySystemCameraManager_OnFrameUpdate; - static Hook* ZSecuritySystemCamera_FrameUpdate; + static Hook* ZSecuritySystemCameraManager_OnFrameUpdate; + static Hook* ZSecuritySystemCamera_FrameUpdate; static Hook Date: Thu, 5 Feb 2026 15:42:06 +0100 Subject: [PATCH 02/18] Fix indentation in IKControllerOwner declaration --- ZHMModSDK/Include/Glacier/ZHitman5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index 3c9802b1..39d6530c 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -31,7 +31,7 @@ class IInventoryOwner { }; class IIKControllerOwner : - public IComponentInterface { + public IComponentInterface { public: virtual ~IIKControllerOwner() {} virtual void IIKControllerOwner_unk0() = 0; From 098a35442d4a546b7066a120ef638bfb2f887a14 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:43:30 +0100 Subject: [PATCH 03/18] Add IsCustomFlagEnabled virtual function to IIKControllerOwner and add GetAmmoInPocketFor virtual function to ICharacterCoreInventoryState --- ZHMModSDK/Include/Glacier/ZHitman5.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index 39d6530c..30bc5b4a 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -7,6 +7,9 @@ #include "ZOutfit.h" #include "TCheatProtect.h" +class IFirearm; +enum class ECustomFlags; + class IFutureCameraState : public IComponentInterface { public: @@ -65,7 +68,7 @@ class IIKControllerOwner : virtual void IIKControllerOwner_unk28() = 0; virtual void IIKControllerOwner_unk29() = 0; virtual void IIKControllerOwner_unk30() = 0; - virtual void IIKControllerOwner_unk31() = 0; + virtual bool IsCustomFlagEnabled(ECustomFlags eCustomFlags) = 0; virtual void IIKControllerOwner_unk32() = 0; virtual void IIKControllerOwner_unk33() = 0; virtual void IIKControllerOwner_unk34() = 0; @@ -255,7 +258,7 @@ class ICharacterInventoryState : virtual void ICharacterInventoryState_unk17() = 0; virtual void ICharacterInventoryState_unk18() = 0; virtual void ICharacterInventoryState_unk19() = 0; - virtual void ICharacterInventoryState_unk20() = 0; + virtual uint32 GetAmmoInPocketFor(const TEntityRef& rWeapon) = 0; virtual void ICharacterInventoryState_unk21() = 0; virtual void ICharacterInventoryState_unk22() = 0; virtual void ICharacterInventoryState_unk23() = 0; From 2dc0fbb357236e07e71613ccc6380c7db09bf35e Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:43:55 +0100 Subject: [PATCH 04/18] Add missing virtual function to IIKControllerOwner --- ZHMModSDK/Include/Glacier/ZHitman5.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index 30bc5b4a..f57c2005 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -72,6 +72,7 @@ class IIKControllerOwner : virtual void IIKControllerOwner_unk32() = 0; virtual void IIKControllerOwner_unk33() = 0; virtual void IIKControllerOwner_unk34() = 0; + virtual void IIKControllerOwner_unk35() = 0; }; class IControllableCharacter : From 1d50cd0f0f6d9ad8e5e191bc3070e5cb76af99e4 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:44:16 +0100 Subject: [PATCH 05/18] Add offset comment for padding in ZHM5Health --- ZHMModSDK/Include/Glacier/ZHitman5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index f57c2005..d67b5b33 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -405,7 +405,7 @@ class ZFabricColliderBaseEntity; class ZHM5Health { public: - PAD(0x228); + PAD(0x228); // 0x0 TCheatProtect m_fHitPoints; // 0x228 TCheatProtect m_fMaxHitPoints; // 0x238 }; From 706f8556ea8167b2fdc0767890168220ea56a58c Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:44:35 +0100 Subject: [PATCH 06/18] Add and ZHM5WeaponRecoilController and ZHM5BaseController --- ZHMModSDK/Include/Glacier/ZHitman5.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index d67b5b33..751a9879 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -410,6 +410,18 @@ class ZHM5Health { TCheatProtect m_fMaxHitPoints; // 0x238 }; +class ZHM5BaseController { +public: + virtual ~ZHM5BaseController() = 0; +}; + +class ZHM5WeaponRecoilController : public ZHM5BaseController { +public: + PAD(0x40); // 0x8 + SVector2 m_vRecoil; // 0x48 + SVector2 m_vAccumlatedRecoil; // 0x50 +}; + class ZHitman5 : public ZHM5BaseCharacter, public IFutureCameraState, // 720 From 7036c241b0908c397e9fa94c796ae897ac56342f Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:46:53 +0100 Subject: [PATCH 07/18] Add virtual functions to IFirearm and add new fields to ZHM5ItemWeapon --- ZHMModSDK/Include/Glacier/ZItem.h | 101 +++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZItem.h b/ZHMModSDK/Include/Glacier/ZItem.h index 211050f1..1393059a 100644 --- a/ZHMModSDK/Include/Glacier/ZItem.h +++ b/ZHMModSDK/Include/Glacier/ZItem.h @@ -4,6 +4,7 @@ #include "ZSpatialEntity.h" #include "ZGeomEntity.h" #include "ZHitman5.h" +#include "ZGameTime.h" class IItemBase : public IComponentInterface {}; @@ -131,7 +132,97 @@ class ZHM5Item : class IItemWeapon : public IComponentInterface { }; +struct SWeaponConfig; + class IFirearm : public IComponentInterface { +public: + virtual ~IFirearm() = 0; + virtual void IFirearm_unk5() = 0; + virtual void IFirearm_unk6() = 0; + virtual void IFirearm_unk7() = 0; + virtual void IFirearm_unk8() = 0; + virtual void IFirearm_unk9() = 0; + virtual void IFirearm_unk10() = 0; + virtual void IFirearm_unk11() = 0; + virtual void IFirearm_unk12() = 0; + virtual void IFirearm_unk13() = 0; + virtual void IFirearm_unk14() = 0; + virtual void IFirearm_unk15() = 0; + virtual void IFirearm_unk16() = 0; + virtual const SWeaponConfig& GetWeaponConfig() const = 0; + virtual void IFirearm_unk18() = 0; + virtual void IFirearm_unk19() = 0; + virtual void SetBulletsInMagazine(int32_t nBullets) = 0; + virtual uint16_t GetBulletsInMagazine() const = 0; + virtual void IFirearm_unk22() = 0; + virtual void IFirearm_unk23() = 0; + virtual void IFirearm_unk24() = 0; + virtual void IFirearm_unk25() = 0; + virtual void IFirearm_unk26() = 0; + virtual void IFirearm_unk27() = 0; + virtual void IFirearm_unk28() = 0; + virtual int GetMagazineCapacity() const = 0; + virtual eAmmoType GetAmmoType() const = 0; + virtual void IFirearm_unk31() = 0; + virtual void IFirearm_unk32() = 0; + virtual void IFirearm_unk33() = 0; + virtual void IFirearm_unk34() = 0; + virtual void IFirearm_unk35() = 0; + virtual void IFirearm_unk36() = 0; + virtual void IFirearm_unk37() = 0; + virtual void IFirearm_unk38() = 0; + virtual void IFirearm_unk39() = 0; + virtual void IFirearm_unk40() = 0; + virtual void IFirearm_unk41() = 0; + virtual void IFirearm_unk42() = 0; + virtual void IFirearm_unk43() = 0; + virtual void IFirearm_unk44() = 0; + virtual void IFirearm_unk45() = 0; + virtual void IFirearm_unk46() = 0; + virtual void IFirearm_unk47() = 0; + virtual void IFirearm_unk48() = 0; + virtual void IFirearm_unk49() = 0; + virtual void IFirearm_unk50() = 0; + virtual void IFirearm_unk51() = 0; + virtual void IFirearm_unk52() = 0; + virtual void IFirearm_unk53() = 0; + virtual void IFirearm_unk54() = 0; + virtual void IFirearm_unk55() = 0; + virtual void IFirearm_unk56() = 0; + virtual void IFirearm_unk57() = 0; + virtual void IFirearm_unk58() = 0; + virtual bool IsFiring() const = 0; + virtual float GetTimeBetweenBullets() const = 0; + virtual void IFirearm_unk61() = 0; + virtual void IFirearm_unk62() = 0; + virtual void IFirearm_unk63() = 0; + virtual void IFirearm_unk64() = 0; + virtual void IFirearm_unk65() = 0; + virtual void IFirearm_unk66() = 0; + virtual void IFirearm_unk67() = 0; + virtual void IFirearm_unk68() = 0; + virtual void IFirearm_unk69() = 0; + virtual void IFirearm_unk70() = 0; + virtual void IFirearm_unk71() = 0; + virtual void IFirearm_unk72() = 0; + virtual void IFirearm_unk73() = 0; + virtual void IFirearm_unk74() = 0; + virtual void IFirearm_unk75() = 0; + virtual void IFirearm_unk76() = 0; + virtual void IFirearm_unk77() = 0; + virtual void IFirearm_unk78() = 0; + virtual void IFirearm_unk79() = 0; + virtual void IFirearm_unk80() = 0; + virtual void IFirearm_unk81() = 0; + virtual void IFirearm_unk82() = 0; + virtual void IFirearm_unk83() = 0; + virtual void IFirearm_unk84() = 0; + virtual void IFirearm_unk85() = 0; + virtual void IFirearm_unk86() = 0; + virtual void IFirearm_unk87() = 0; + virtual void IFirearm_unk88() = 0; + virtual void IFirearm_unk89() = 0; + virtual void IFirearm_unk90() = 0; }; class IParticleEmitterEntity; @@ -172,7 +263,15 @@ class ZHM5ItemWeapon : ZEntityRef m_rSuperSpecialTriggerEffect; // 0x5E0 TArray> m_rClipMeshProviders; // 0x5E8 TArray> m_aManualReloadSettings; // 0x600 - PAD(0x398); + PAD(0x310); // 0x618 + uint16 m_nBulletsToFire; // 0x928 + PAD(0x6); // 0x92A + uint16 m_nBulletsFired; // 0x930 + PAD(0xE); // 0x932 + ZGameTime m_tLastShootTime; // 0x940 + float32 m_fTimeBetweenBullets; // 0x948 + float m_fPrecisionFactor; // 0x94C + PAD(0x60); }; class ZItemSpawner : public ZSpatialEntity, public IItemOwner, public ISavableEntity //Size: 0x138 From 7e0abab002f34309ea684209b5dafdd859bbf2e0 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:47:15 +0100 Subject: [PATCH 08/18] Fix padding in ZCharacterSubcontrollerInventory --- ZHMModSDK/Include/Glacier/ZInventory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZInventory.h b/ZHMModSDK/Include/Glacier/ZInventory.h index ab8c3fbf..5b926db4 100644 --- a/ZHMModSDK/Include/Glacier/ZInventory.h +++ b/ZHMModSDK/Include/Glacier/ZInventory.h @@ -25,7 +25,7 @@ class ZCharacterSubcontrollerInventory : public ZCharacterSubcontroller //Size: ECIT_ContainerItem = 4 }; - PAD(0x140); + PAD(0x120); uint32 m_nMaxGunAmmo; // 0x158 uint32 m_nMaxRevolverAmmo; // 0x15C uint32 m_nMaxSMGAmmo; // 0x160 From 23cd937508ef7e12f3708f759dc138c264b87ab1 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 15:49:26 +0100 Subject: [PATCH 09/18] Add new cheat options to Player mod --- Mods/Player/Src/Player.cpp | 138 ++++++++++++++++++++++++++++++++++ Mods/Player/Src/Player.h | 31 ++++++++ ZHMModSDK/Include/Functions.h | 7 ++ ZHMModSDK/Include/Hooks.h | 26 +++++++ ZHMModSDK/Src/Functions.cpp | 14 ++++ ZHMModSDK/Src/Hooks.cpp | 43 +++++++++++ 6 files changed, 259 insertions(+) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index 9529fe89..dfe2a26e 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -25,6 +25,16 @@ void Player::Init() { &Player::ZSecuritySystemCameraManager_OnFrameUpdate ); Hooks::ZSecuritySystemCamera_FrameUpdate->AddDetour(this, &Player::ZSecuritySystemCamera_FrameUpdate); + + Hooks::ZHM5ItemWeapon_SetBulletsInMagazine->AddDetour(this, &Player::ZHM5ItemWeapon_SetBulletsInMagazine); + Hooks::ZHitmanMorphemePostProcessor_UpdateWeaponRecoil->AddDetour( + this, + &Player::ZHitmanMorphemePostProcessor_UpdateWeaponRecoil + ); + Hooks::ZHM5WeaponRecoilController_RecoilWeapon->AddDetour(this, &Player::ZHM5WeaponRecoilController_RecoilWeapon); + Hooks::ZHM5ItemWeapon_FireProjectiles->AddDetour(this, &Player::ZHM5ItemWeapon_FireProjectiles); + Hooks::ZHM5ItemWeapon_IsFiring->AddDetour(this, &Player::ZHM5ItemWeapon_IsFiring); + Hooks::ZActor_YouGotHit->AddDetour(this, &Player::ZActor_YouGotHit); } void Player::OnDrawMenu() { @@ -59,6 +69,16 @@ void Player::OnDrawUI(const bool p_HasFocus) { ToggleInfiniteAmmo(); } + ImGui::Checkbox("No Reload", &m_IsNoReloadEnabled); + + ImGui::Checkbox("No Recoil", &m_IsNoRecoilEnabled); + + ImGui::Checkbox("Super Accuracy", &m_IsSuperAccuracyEnabled); + + ImGui::Checkbox("RapidFire", &m_IsRapidFireEnabled); + + ImGui::Checkbox("One Hit Kill", &m_IsOneHitKillEnabled); + static char s_OutfitName[2048] { "" }; static uint8_t s_CurrentCharacterSetIndex = 0; static std::string s_CurrentCharSetCharacterType = "HeroA"; @@ -637,4 +657,122 @@ DEFINE_PLUGIN_DETOUR( return HookResult(HookAction::Continue()); } +DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm* th, int32_t nBullets) { + if (!m_IsNoReloadEnabled) { + return HookResult(HookAction::Continue()); + } + + ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); + + if (s_HM5ItemWeapon->m_nBulletsFired == s_HM5ItemWeapon->m_nBulletsToFire) { + s_HM5ItemWeapon->m_nBulletsFired = 0; + } + + if (nBullets != 0) { + return HookResult(HookAction::Continue()); + } + + const auto s_LocalHitman = SDK()->GetLocalPlayer(); + + if (s_LocalHitman) { + const bool s_IsInfiniteAmmoEnabled = !s_LocalHitman.m_pInterfaceRef->IsCustomFlagEnabled( + static_cast(0x2000000) + ); + + if (!s_IsInfiniteAmmoEnabled) { + auto s_Character = s_LocalHitman.m_pInterfaceRef->m_pCharacter.m_pInterfaceRef; + auto s_Controllers = &s_Character->m_rSubcontrollerContainer.m_pInterfaceRef->m_aReferencedControllers; + auto s_Inventory = static_cast((*s_Controllers)[6].m_pInterfaceRef); + + const eAmmoType s_AmmoType = th->GetAmmoType(); + + uint32 s_AmmoInPocket = Functions::ZCharacterSubcontrollerInventory_GetAmmoInPocketForType->Call( + s_Inventory, + s_AmmoType + ); + + if (s_AmmoInPocket > 0) { + s_AmmoInPocket -= s_HM5ItemWeapon->GetMagazineCapacity(); + + s_Inventory->m_nAmmoInPocket[static_cast(s_AmmoType)] = s_AmmoInPocket; + + nBullets = s_HM5ItemWeapon->GetMagazineCapacity(); + } + } + else { + nBullets = s_HM5ItemWeapon->GetMagazineCapacity(); + } + } + + p_Hook->CallOriginal(th, nBullets); + + return HookResult(HookAction::Return()); +} + +DEFINE_PLUGIN_DETOUR( + Player, + void, + ZHitmanMorphemePostProcessor_UpdateWeaponRecoil, + ZHitmanMorphemePostProcessor* th, + float fDeltaTime, + const THashMap>& charboneMap, + TArrayRef hierarchy +) { + if (m_IsNoRecoilEnabled) { + return HookResult(HookAction::Return()); + } + + return HookResult(HookAction::Continue()); +} + +DEFINE_PLUGIN_DETOUR( + Player, + void, + ZHM5WeaponRecoilController_RecoilWeapon, + ZHM5WeaponRecoilController* th, + const TEntityRef& rWeapon +) { + if (!m_IsNoRecoilEnabled) { + return HookResult(HookAction::Continue()); + } + + p_Hook->CallOriginal(th, rWeapon); + + th->m_vRecoil = SVector2(0.f, 0.f); + + return HookResult(HookAction::Return()); +} + +DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_FireProjectiles, ZHM5ItemWeapon* th, bool bMayStartSound) { + if (!m_IsSuperAccuracyEnabled) { + return HookResult(HookAction::Continue()); + } + + bool s_Result = p_Hook->CallOriginal(th, bMayStartSound); + + th->m_fPrecisionFactor = 0.f; + + return HookResult(HookAction::Return(), s_Result); +} + +DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_IsFiring, IFirearm* th) { + if (m_IsRapidFireEnabled) { + ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); + + s_HM5ItemWeapon->m_tLastShootTime = 0; + } + + return HookResult(HookAction::Continue()); +} + +DEFINE_PLUGIN_DETOUR(Player, bool, ZActor_YouGotHit, IBaseCharacter* th, const SHitInfo& hitInfo) { + if (m_IsOneHitKillEnabled) { + ZActor* s_Actor = static_cast(th); + + s_Actor->m_fCurrentHitPoints = 0.f; + } + + return HookResult(HookAction::Continue()); +} + DEFINE_ZHM_PLUGIN(Player); diff --git a/Mods/Player/Src/Player.h b/Mods/Player/Src/Player.h index 63b22caa..1a1042a7 100644 --- a/Mods/Player/Src/Player.h +++ b/Mods/Player/Src/Player.h @@ -43,10 +43,41 @@ class Player : public IPluginInterface { const SGameUpdateEvent& updateEvent ); + DECLARE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm* th, int32_t nBullets); + + DECLARE_PLUGIN_DETOUR( + Player, + void, + ZHitmanMorphemePostProcessor_UpdateWeaponRecoil, + ZHitmanMorphemePostProcessor* th, + float fDeltaTime, + const THashMap>& charboneMap, + TArrayRef hierarchy + ); + + DECLARE_PLUGIN_DETOUR( + Player, + void, + ZHM5WeaponRecoilController_RecoilWeapon, + ZHM5WeaponRecoilController* th, + const TEntityRef& rWeapon + ); + + DECLARE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_FireProjectiles, ZHM5ItemWeapon* th, bool bMayStartSound); + + DECLARE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_IsFiring, IFirearm* th); + + DECLARE_PLUGIN_DETOUR(Player, bool, ZActor_YouGotHit, IBaseCharacter* th, const SHitInfo& hitInfo); + bool m_PlayerMenuActive = false; bool m_IsInvincible = false; bool m_IsInvisible = false; bool m_IsInfiniteAmmoEnabled = false; + bool m_IsNoReloadEnabled = false; + bool m_IsNoRecoilEnabled = false; + bool m_IsSuperAccuracyEnabled = false; + bool m_IsRapidFireEnabled = false; + bool m_IsOneHitKillEnabled = false; const std::vector m_CharSetCharacterTypes = { "Actor", "Nude", "HeroA" }; diff --git a/ZHMModSDK/Include/Functions.h b/ZHMModSDK/Include/Functions.h index fb5fca5f..d05c1ad8 100644 --- a/ZHMModSDK/Include/Functions.h +++ b/ZHMModSDK/Include/Functions.h @@ -52,6 +52,7 @@ class IItemBase; class ZStashPointEntity; class ZTimeOfDayManager; class ZHM5Health; +class ZHM5WeaponControl; namespace bfx { class AreaHandle; @@ -247,4 +248,10 @@ class ZHMSDK_API Functions { static EngineFunction* ZHM5Health_GetHP; static EngineFunction* ZHM5Health_GetMaxHitpoints; + + static EngineFunction* ZCharacterSubcontrollerInventory_GetAmmoInPocketForType; + + static EngineFunction* ZHM5WeaponControl_GetCrosshairScale; }; \ No newline at end of file diff --git a/ZHMModSDK/Include/Hooks.h b/ZHMModSDK/Include/Hooks.h index ee1491ef..cf21194f 100644 --- a/ZHMModSDK/Include/Hooks.h +++ b/ZHMModSDK/Include/Hooks.h @@ -86,6 +86,12 @@ class ZActorInventoryHandler; class ZItemRepositoryKeyEntity; class ZGlobalOutfitKit; class ZClothBundleEntity; +class ZHM5ItemWeapon; +class IFirearm; +struct SHitInfo; +class IBaseCharacter; +class ZHitmanMorphemePostProcessor; +class ZHM5WeaponRecoilController; class ZHMSDK_API Hooks { public: @@ -312,4 +318,24 @@ class ZHMSDK_API Hooks { bool bSpawnedByHitman, bool bEnableOutfitModifiers )>* ZClothBundleEntity_CreateClothBundle; + + static Hook* ZHM5ItemWeapon_SetBulletsInMagazine; + + static Hook* ZActor_YouGotHit; + + static Hook>& charboneMap, + TArrayRef hierarchy + )>* ZHitmanMorphemePostProcessor_UpdateWeaponRecoil; + + static Hook& rWeapon + )>* ZHM5WeaponRecoilController_RecoilWeapon; + + static Hook* ZHM5ItemWeapon_FireProjectiles; + + static Hook* ZHM5ItemWeapon_IsFiring; }; \ No newline at end of file diff --git a/ZHMModSDK/Src/Functions.cpp b/ZHMModSDK/Src/Functions.cpp index 98c47ba6..7a5c3bff 100644 --- a/ZHMModSDK/Src/Functions.cpp +++ b/ZHMModSDK/Src/Functions.cpp @@ -484,4 +484,18 @@ PATTERN_FUNCTION( "xxxxxxxxxxxxxxxxx?xxxxxxx", ZHM5Health_GetMaxHitpoints, float32(const ZHM5Health* th) +); + +PATTERN_FUNCTION( + "\x48\x89\x5C\x24\x08\x48\x89\x74\x24\x10\x48\x89\x7C\x24\x18\x55\x48\x8B\xEC\x48\x83\xEC\x00\x48\x8B\x41\x20", + "xxxxxxxxxxxxxxxxxxxxxx?xxxx", + ZCharacterSubcontrollerInventory_GetAmmoInPocketForType, + uint32_t(ZCharacterSubcontrollerInventory* th, eAmmoType AmmoType) +); + +PATTERN_FUNCTION( + "\x40\x53\x48\x81\xEC\x00\x00\x00\x00\x48\x8B\xD9\x48\x8B\x49\x38", + "xxxxx????xxxxxxx", + ZHM5WeaponControl_GetCrosshairScale, + float(ZHM5WeaponControl* th) ); \ No newline at end of file diff --git a/ZHMModSDK/Src/Hooks.cpp b/ZHMModSDK/Src/Hooks.cpp index e66819da..271d6abe 100644 --- a/ZHMModSDK/Src/Hooks.cpp +++ b/ZHMModSDK/Src/Hooks.cpp @@ -552,4 +552,47 @@ PATTERN_HOOK( ZClothBundleEntity_CreateClothBundle, TEntityRef* (TEntityRef& result, const SMatrix& mat, ZRepositoryID id, int32_t nOutfitVariation, int32_t nOutfitCharset, bool bSpawnedByHitman, bool bEnableOutfitModifiers) +); + +PATTERN_HOOK( + "\x48\x8B\xC1\x44\x8B\xC2\x48\x81\xC1", + "xxxxxxxxx", + ZHM5ItemWeapon_SetBulletsInMagazine, + void(IFirearm* th, int32_t nBullets) +); + +PATTERN_HOOK( + "\x48\x89\x5C\x24\x08\x57\x48\x83\xEC\x00\x48\x8B\x99\x78\x11\x00\x00", + "xxxxxxxxx?xxxxxxx", + ZActor_YouGotHit, + bool(IBaseCharacter* th, const SHitInfo& hitInfo) +); + +PATTERN_HOOK( + "\x48\x8B\xC4\x4C\x89\x48\x20\x4C\x89\x40\x18\xF3\x0F\x11\x48\x10", + "xxxxxxxxxxxxxxxx", + ZHitmanMorphemePostProcessor_UpdateWeaponRecoil, + void(ZHitmanMorphemePostProcessor* th, float fDeltaTime, + const THashMap>& charboneMap, TArrayRef hierarchy) +); + +PATTERN_HOOK( + "\x40\x53\x48\x83\xEC\x00\x48\x8B\xD9\x0F\x29\x74\x24\x50\x48\x8B\x4A\x08", + "xxxxx?xxxxxxxxxxxx", + ZHM5WeaponRecoilController_RecoilWeapon, + void(ZHM5WeaponRecoilController* th, const TEntityRef& rWeapon) +); + +PATTERN_HOOK( + "\x88\x54\x24\x10\x55\x53\x56\x57\x41\x54\x41\x55\x41\x57", + "xxxxxxxxxxxxxx", + ZHM5ItemWeapon_FireProjectiles, + bool(ZHM5ItemWeapon* th, bool bMayStartSound) +); + +PATTERN_HOOK( + "\x40\x53\x48\x83\xEC\x00\x48\x8B\x01\x48\x8B\xD9\xFF\x90\xE0\x01\x00\x00", + "xxxxx?xxxxxxxxxxxx", + ZHM5ItemWeapon_IsFiring, + bool(IFirearm* th) ); \ No newline at end of file From 5d1ef5f35bdcce8d7557c2065e88cc95d2e22516 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 17:32:36 +0100 Subject: [PATCH 10/18] Extend ZGameTime with constructors, operators, and conversions --- ZHMModSDK/Include/Glacier/ZGameTime.h | 84 ++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 3 deletions(-) diff --git a/ZHMModSDK/Include/Glacier/ZGameTime.h b/ZHMModSDK/Include/Glacier/ZGameTime.h index 71f0ee26..18115c90 100644 --- a/ZHMModSDK/Include/Glacier/ZGameTime.h +++ b/ZHMModSDK/Include/Glacier/ZGameTime.h @@ -2,12 +2,90 @@ #include "Reflection.h" -struct ZGameTime { - int64_t m_nTicks; +class ZGameTime { +public: + ZGameTime() = default; + + explicit ZGameTime(int64_t p_Ticks) { + m_nTicks = p_Ticks; + } + + explicit ZGameTime(float p_Seconds) { + m_nTicks = static_cast(p_Seconds * (1 << FractionBits)); + } + + explicit ZGameTime(double p_Seconds) { + m_nTicks = static_cast(p_Seconds * (1 << FractionBits)); + } + + explicit operator int64_t() const { + return m_nTicks; + } + + explicit operator float() const { + return m_nTicks * TicksToSeconds; + } + + ZGameTime operator+(const ZGameTime& p_Other) const { + return ZGameTime(m_nTicks + p_Other.m_nTicks); + } + + ZGameTime& operator+=(const ZGameTime& p_Other) { + m_nTicks += p_Other.m_nTicks; + + return *this; + } + + ZGameTime operator-(const ZGameTime& p_Other) const { + return ZGameTime(m_nTicks - p_Other.m_nTicks); + } + + ZGameTime& operator-=(const ZGameTime& p_Other) { + m_nTicks -= p_Other.m_nTicks; + + return *this; + } + + ZGameTime operator*(const ZGameTime& p_Other) const { + return ZGameTime((m_nTicks * p_Other.m_nTicks) >> FractionBits); + } + + ZGameTime& operator*=(const ZGameTime& p_Other) { + m_nTicks = (m_nTicks * p_Other.m_nTicks) >> FractionBits; + + return *this; + } + + ZGameTime operator/(const ZGameTime& p_Other) const { + return ZGameTime((m_nTicks << FractionBits) / p_Other.m_nTicks); + } + + ZGameTime& operator/=(const ZGameTime& p_Other) { + m_nTicks = (m_nTicks << FractionBits) / p_Other.m_nTicks; + + return *this; + } + + bool operator<(const ZGameTime& rhs) const { + return m_nTicks < rhs.m_nTicks; + } + + static ZGameTime FromSeconds(float p_Seconds) { + return ZGameTime(static_cast(p_Seconds * (1 << FractionBits))); + } + + static ZGameTime FromSeconds(double p_Seconds) { + return ZGameTime(static_cast(p_Seconds * (1 << FractionBits))); + } double ToSeconds() const { - return static_cast(m_nTicks) / 1024.0 / 1024.0; + return static_cast(m_nTicks) / (1 << FractionBits); } + + int64_t m_nTicks; + + static constexpr int FractionBits = 20; + static constexpr float TicksToSeconds = 1.0f / (1 << FractionBits); }; class ZGameTimeManager : public IComponentInterface { From f25a7fda653901503059e12c4e44d69f9006e212 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 17:34:17 +0100 Subject: [PATCH 11/18] Replace padding with boolean field in ZGameTimeManager --- ZHMModSDK/Include/Glacier/ZGameTime.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZGameTime.h b/ZHMModSDK/Include/Glacier/ZGameTime.h index 18115c90..1d6729b2 100644 --- a/ZHMModSDK/Include/Glacier/ZGameTime.h +++ b/ZHMModSDK/Include/Glacier/ZGameTime.h @@ -100,7 +100,7 @@ class ZGameTimeManager : public IComponentInterface { ZGameTime m_tRealTimeDelta; // 0x40 float m_fGameTimeMultiplier; // 0x48 float m_fDebugTimeMultiplier; // 0x4C - PAD(0x8); // 0x50 + bool m_Unk; // 0x50 ZGameTime m_FrameWait; // 0x58 ZGameTime m_FrameStep; // 0x60 ZGameTime m_FrameRemain; // 0x68 From ebebd2a4bd43de29b1692436135011d9d927d7d2 Mon Sep 17 00:00:00 2001 From: Pavle Date: Thu, 5 Feb 2026 17:59:04 +0100 Subject: [PATCH 12/18] Use default ZGameTime initialization instead of raw zero --- Mods/Player/Src/Player.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index dfe2a26e..b646bdc0 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -759,7 +759,7 @@ DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_IsFiring, IFirearm* th) { if (m_IsRapidFireEnabled) { ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); - s_HM5ItemWeapon->m_tLastShootTime = 0; + s_HM5ItemWeapon->m_tLastShootTime = ZGameTime {}; } return HookResult(HookAction::Continue()); From c8f10ee0a51f62147ab3d8e5d4299d4e20a640b4 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 18:52:49 +0100 Subject: [PATCH 13/18] Apply cheats only to player weapons --- Mods/Player/Src/Player.cpp | 78 ++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index b646bdc0..62409fc5 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -662,8 +662,18 @@ DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm return HookResult(HookAction::Continue()); } + const auto s_LocalHitman = SDK()->GetLocalPlayer(); + + if (!s_LocalHitman) { + return HookResult(HookAction::Continue()); + } + ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); + if (s_HM5ItemWeapon->m_pOwner != s_LocalHitman.m_entityRef) { + return HookResult(HookAction::Continue()); + } + if (s_HM5ItemWeapon->m_nBulletsFired == s_HM5ItemWeapon->m_nBulletsToFire) { s_HM5ItemWeapon->m_nBulletsFired = 0; } @@ -672,37 +682,33 @@ DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm return HookResult(HookAction::Continue()); } - const auto s_LocalHitman = SDK()->GetLocalPlayer(); - - if (s_LocalHitman) { - const bool s_IsInfiniteAmmoEnabled = !s_LocalHitman.m_pInterfaceRef->IsCustomFlagEnabled( - static_cast(0x2000000) - ); + const bool s_IsInfiniteAmmoEnabled = !s_LocalHitman.m_pInterfaceRef->IsCustomFlagEnabled( + static_cast(0x2000000) + ); - if (!s_IsInfiniteAmmoEnabled) { - auto s_Character = s_LocalHitman.m_pInterfaceRef->m_pCharacter.m_pInterfaceRef; - auto s_Controllers = &s_Character->m_rSubcontrollerContainer.m_pInterfaceRef->m_aReferencedControllers; - auto s_Inventory = static_cast((*s_Controllers)[6].m_pInterfaceRef); + if (!s_IsInfiniteAmmoEnabled) { + auto s_Character = s_LocalHitman.m_pInterfaceRef->m_pCharacter.m_pInterfaceRef; + auto s_Controllers = &s_Character->m_rSubcontrollerContainer.m_pInterfaceRef->m_aReferencedControllers; + auto s_Inventory = static_cast((*s_Controllers)[6].m_pInterfaceRef); - const eAmmoType s_AmmoType = th->GetAmmoType(); + const eAmmoType s_AmmoType = th->GetAmmoType(); - uint32 s_AmmoInPocket = Functions::ZCharacterSubcontrollerInventory_GetAmmoInPocketForType->Call( - s_Inventory, - s_AmmoType - ); + uint32 s_AmmoInPocket = Functions::ZCharacterSubcontrollerInventory_GetAmmoInPocketForType->Call( + s_Inventory, + s_AmmoType + ); - if (s_AmmoInPocket > 0) { - s_AmmoInPocket -= s_HM5ItemWeapon->GetMagazineCapacity(); + if (s_AmmoInPocket > 0) { + s_AmmoInPocket -= s_HM5ItemWeapon->GetMagazineCapacity(); - s_Inventory->m_nAmmoInPocket[static_cast(s_AmmoType)] = s_AmmoInPocket; + s_Inventory->m_nAmmoInPocket[static_cast(s_AmmoType)] = s_AmmoInPocket; - nBullets = s_HM5ItemWeapon->GetMagazineCapacity(); - } - } - else { nBullets = s_HM5ItemWeapon->GetMagazineCapacity(); } } + else { + nBullets = s_HM5ItemWeapon->GetMagazineCapacity(); + } p_Hook->CallOriginal(th, nBullets); @@ -748,6 +754,16 @@ DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_FireProjectiles, ZHM5ItemWeapo return HookResult(HookAction::Continue()); } + const auto s_LocalHitman = SDK()->GetLocalPlayer(); + + if (!s_LocalHitman) { + return HookResult(HookAction::Continue()); + } + + if (th->m_pOwner != s_LocalHitman.m_entityRef) { + return HookResult(HookAction::Continue()); + } + bool s_Result = p_Hook->CallOriginal(th, bMayStartSound); th->m_fPrecisionFactor = 0.f; @@ -756,12 +772,24 @@ DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_FireProjectiles, ZHM5ItemWeapo } DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_IsFiring, IFirearm* th) { - if (m_IsRapidFireEnabled) { - ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); + if (!m_IsRapidFireEnabled) { + return HookResult(HookAction::Continue()); + } - s_HM5ItemWeapon->m_tLastShootTime = ZGameTime {}; + const auto s_LocalHitman = SDK()->GetLocalPlayer(); + + if (!s_LocalHitman) { + return HookResult(HookAction::Continue()); + } + + ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); + + if (s_HM5ItemWeapon->m_pOwner != s_LocalHitman.m_entityRef) { + return HookResult(HookAction::Continue()); } + s_HM5ItemWeapon->m_tLastShootTime = ZGameTime {}; + return HookResult(HookAction::Continue()); } From 078bb7ab374bf519ce88a5747d540302d97c2a6b Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 19:21:01 +0100 Subject: [PATCH 14/18] Add m_pOwner to ZHM5Item, add missing offset comments and update offset comment for m_pGeomEntity --- ZHMModSDK/Include/Glacier/ZItem.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ZHMModSDK/Include/Glacier/ZItem.h b/ZHMModSDK/Include/Glacier/ZItem.h index 1393059a..3f1aa46a 100644 --- a/ZHMModSDK/Include/Glacier/ZItem.h +++ b/ZHMModSDK/Include/Glacier/ZItem.h @@ -122,11 +122,13 @@ class ZHM5Item : TEntityRef m_rItemCanTurnOn; // 0x2E8 TEntityRef m_rItemCanTurnOff; // 0x2F8 TEntityRef m_pVariationResource; // 0x308 - ZEntityRef m_rSpawner; - ZEntityRef m_rFactoryEntity; - PAD(0x10); - TEntityRef m_pGeomEntity; //0x2C0 - PAD(0x1A8); + ZEntityRef m_rSpawner; // 0x318 + ZEntityRef m_rFactoryEntity; // 0x320 + PAD(0x10); // 0x328 + TEntityRef m_pGeomEntity; //0x338 + PAD(0x10); // 0x2D0 + ZEntityRef m_pOwner; // 0x358 + PAD(0x190); }; class IItemWeapon : public IComponentInterface { From 5c9ae6c26ddf9d603cdd20f16b45101d32622ce2 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 19:40:12 +0100 Subject: [PATCH 15/18] Add eLIMITED_AMMO item to ECustomFlags --- ZHMModSDK/Include/Glacier/ZHitman5.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index 751a9879..c5cb5daa 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -8,7 +8,10 @@ #include "TCheatProtect.h" class IFirearm; -enum class ECustomFlags; + +enum class ECustomFlags { + eLIMITED_AMMO = 0x2000000 +}; class IFutureCameraState : public IComponentInterface { From ab5054c68c257572948273a46e8825cdb7ecbb33 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 19:40:47 +0100 Subject: [PATCH 16/18] Make IKControllerOwner::IsCustomFlagEnabled const --- ZHMModSDK/Include/Glacier/ZHitman5.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index c5cb5daa..b85d259a 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -71,7 +71,7 @@ class IIKControllerOwner : virtual void IIKControllerOwner_unk28() = 0; virtual void IIKControllerOwner_unk29() = 0; virtual void IIKControllerOwner_unk30() = 0; - virtual bool IsCustomFlagEnabled(ECustomFlags eCustomFlags) = 0; + virtual bool IsCustomFlagEnabled(ECustomFlags eCustomFlags) const = 0; virtual void IIKControllerOwner_unk32() = 0; virtual void IIKControllerOwner_unk33() = 0; virtual void IIKControllerOwner_unk34() = 0; From 627699d03aa5ba7f08bda7f3b388a3ec3bb3abb6 Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 19:41:28 +0100 Subject: [PATCH 17/18] Add IsInfiniteAmmoEnabled method to ZHitman5 --- Mods/Player/Src/Player.cpp | 6 +----- ZHMModSDK/Include/Glacier/ZHitman5.h | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index 62409fc5..b6229bc9 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -682,11 +682,7 @@ DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm return HookResult(HookAction::Continue()); } - const bool s_IsInfiniteAmmoEnabled = !s_LocalHitman.m_pInterfaceRef->IsCustomFlagEnabled( - static_cast(0x2000000) - ); - - if (!s_IsInfiniteAmmoEnabled) { + if (!s_LocalHitman.m_pInterfaceRef->IsInfiniteAmmoEnabled()) { auto s_Character = s_LocalHitman.m_pInterfaceRef->m_pCharacter.m_pInterfaceRef; auto s_Controllers = &s_Character->m_rSubcontrollerContainer.m_pInterfaceRef->m_aReferencedControllers; auto s_Inventory = static_cast((*s_Controllers)[6].m_pInterfaceRef); diff --git a/ZHMModSDK/Include/Glacier/ZHitman5.h b/ZHMModSDK/Include/Glacier/ZHitman5.h index b85d259a..1ec708a6 100644 --- a/ZHMModSDK/Include/Glacier/ZHitman5.h +++ b/ZHMModSDK/Include/Glacier/ZHitman5.h @@ -446,6 +446,10 @@ class ZHitman5 : public ICharacterCameraState // 848 { public: + bool IsInfiniteAmmoEnabled() const { + return !IsCustomFlagEnabled(ECustomFlags::eLIMITED_AMMO); + } + PAD(0x3B8); // 0x358 ZRepositoryID m_InitialOutfitId; // 0x710 ZEntityRef m_MorphemeEntityID; // 0x720 From 591e7e1df39f3236692f16f4bf28c5d2fe6da3bb Mon Sep 17 00:00:00 2001 From: Pavle Date: Sat, 7 Feb 2026 19:45:53 +0100 Subject: [PATCH 18/18] Refactor hook returns to use brace initialization --- Mods/Player/Src/Player.cpp | 46 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Mods/Player/Src/Player.cpp b/Mods/Player/Src/Player.cpp index b6229bc9..fe1cd9a7 100644 --- a/Mods/Player/Src/Player.cpp +++ b/Mods/Player/Src/Player.cpp @@ -626,7 +626,7 @@ DEFINE_PLUGIN_DETOUR(Player, void, OnClearScene, ZEntitySceneContext* th, bool p m_IsInfiniteAmmoEnabled = false; m_GlobalOutfitKit = {}; - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_PLUGIN_DETOUR( @@ -637,10 +637,10 @@ DEFINE_PLUGIN_DETOUR( const SGameUpdateEvent& updateEvent ) { if (m_IsInvisible) { - return HookResult(HookAction::Return()); + return { HookAction::Return() }; } - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_PLUGIN_DETOUR( @@ -651,27 +651,27 @@ DEFINE_PLUGIN_DETOUR( const SGameUpdateEvent& updateEvent ) { if (m_IsInvisible) { - return HookResult(HookAction::Return()); + return { HookAction::Return() }; } - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm* th, int32_t nBullets) { if (!m_IsNoReloadEnabled) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } const auto s_LocalHitman = SDK()->GetLocalPlayer(); if (!s_LocalHitman) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); if (s_HM5ItemWeapon->m_pOwner != s_LocalHitman.m_entityRef) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } if (s_HM5ItemWeapon->m_nBulletsFired == s_HM5ItemWeapon->m_nBulletsToFire) { @@ -679,7 +679,7 @@ DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm } if (nBullets != 0) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } if (!s_LocalHitman.m_pInterfaceRef->IsInfiniteAmmoEnabled()) { @@ -708,7 +708,7 @@ DEFINE_PLUGIN_DETOUR(Player, void, ZHM5ItemWeapon_SetBulletsInMagazine, IFirearm p_Hook->CallOriginal(th, nBullets); - return HookResult(HookAction::Return()); + return { HookAction::Return() }; } DEFINE_PLUGIN_DETOUR( @@ -721,10 +721,10 @@ DEFINE_PLUGIN_DETOUR( TArrayRef hierarchy ) { if (m_IsNoRecoilEnabled) { - return HookResult(HookAction::Return()); + return { HookAction::Return() }; } - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_PLUGIN_DETOUR( @@ -735,58 +735,58 @@ DEFINE_PLUGIN_DETOUR( const TEntityRef& rWeapon ) { if (!m_IsNoRecoilEnabled) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } p_Hook->CallOriginal(th, rWeapon); th->m_vRecoil = SVector2(0.f, 0.f); - return HookResult(HookAction::Return()); + return { HookAction::Return() }; } DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_FireProjectiles, ZHM5ItemWeapon* th, bool bMayStartSound) { if (!m_IsSuperAccuracyEnabled) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } const auto s_LocalHitman = SDK()->GetLocalPlayer(); if (!s_LocalHitman) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } if (th->m_pOwner != s_LocalHitman.m_entityRef) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } bool s_Result = p_Hook->CallOriginal(th, bMayStartSound); th->m_fPrecisionFactor = 0.f; - return HookResult(HookAction::Return(), s_Result); + return { HookAction::Return(), s_Result }; } DEFINE_PLUGIN_DETOUR(Player, bool, ZHM5ItemWeapon_IsFiring, IFirearm* th) { if (!m_IsRapidFireEnabled) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } const auto s_LocalHitman = SDK()->GetLocalPlayer(); if (!s_LocalHitman) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } ZHM5ItemWeapon* s_HM5ItemWeapon = static_cast(th); if (s_HM5ItemWeapon->m_pOwner != s_LocalHitman.m_entityRef) { - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } s_HM5ItemWeapon->m_tLastShootTime = ZGameTime {}; - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_PLUGIN_DETOUR(Player, bool, ZActor_YouGotHit, IBaseCharacter* th, const SHitInfo& hitInfo) { @@ -796,7 +796,7 @@ DEFINE_PLUGIN_DETOUR(Player, bool, ZActor_YouGotHit, IBaseCharacter* th, const S s_Actor->m_fCurrentHitPoints = 0.f; } - return HookResult(HookAction::Continue()); + return { HookAction::Continue() }; } DEFINE_ZHM_PLUGIN(Player);