summaryrefslogtreecommitdiffstats
path: root/src/peds/PlayerPed.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/peds/PlayerPed.cpp')
-rw-r--r--src/peds/PlayerPed.cpp529
1 files changed, 374 insertions, 155 deletions
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index a4ffdc7c..df234bfb 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -1,116 +1,117 @@
-#include "common.h"
-#include "patcher.h"
-#include "PlayerPed.h"
-#include "Camera.h"
-#include "WeaponEffects.h"
-#include "ModelIndices.h"
-#include "World.h"
-#include "RpAnimBlend.h"
-#include "General.h"
-#include "Pools.h"
-
-CPlayerPed::~CPlayerPed()
-{
- delete m_pWanted;
-}
-
-WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); }
-WRAPPER void CPlayerPed::ProcessControl(void) { EAXJMP(0x4EFD90); }
-
-CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
-{
- m_fMoveSpeed = 0.0f;
- SetModelIndex(MI_PLAYER);
- SetInitialState();
-
- m_pWanted = new CWanted();
- m_pWanted->Initialise();
- m_pArrestingCop = nil;
- m_currentWeapon = WEAPONTYPE_UNARMED;
- m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
- m_nSpeedTimer = 0;
- m_bSpeedTimerFlag = 0;
- m_pPointGunAt = nil;
- m_nPedState = PED_IDLE;
- m_fMaxStamina = 150.0f;
- m_fCurrentStamina = m_fMaxStamina;
- m_fStaminaProgress = 0.0f;
- m_bShouldEvade = 0;
- field_1367 = 0;
- m_nShotDelay = 0;
- field_1376 = 0.0f;
- field_1380 = 0;
- m_bHasLockOnTarget = false;
- m_bCanBeDamaged = true;
- m_fWalkAngle = 0.0f;
- m_fFPSMoveHeading = 0.0f;
- m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1;
- field_1413 = 0;
- for (int i = 0; i < 6; i++) {
- m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f);
- m_pPedAtSafePos[i] = nil;
- }
-}
-
-void CPlayerPed::ClearWeaponTarget()
-{
- if (m_nPedType == PEDTYPE_PLAYER1) {
- m_pPointGunAt = nil;
- TheCamera.ClearPlayerWeaponMode();
- CWeaponEffects::ClearCrosshair();
- }
- ClearPointGunAt();
-}
-
-void
-CPlayerPed::SetWantedLevel(int32 level)
-{
- m_pWanted->SetWantedLevel(level);
-}
-
-void
-CPlayerPed::SetWantedLevelNoDrop(int32 level)
-{
- m_pWanted->SetWantedLevelNoDrop(level);
-}
-
-void
-CPlayerPed::MakeObjectTargettable(int32 handle)
-{
- for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
- if (CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]) == nil) {
- m_nTargettableObjects[i] = handle;
- return;
- }
- }
-}
-
-// I don't know the actual purpose of parameter
-void
-CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
-{
- if (m_pedStats->m_temper < 52) {
- m_pedStats->m_temper++;
- } else {
- if (annoyedByPassingEntity) {
- if (m_pedStats->m_temper < 55) {
- m_pedStats->m_temper++;
- } else {
- m_pedStats->m_temper = 46;
- }
- }
- }
-}
-
-void
-CPlayerPed::ClearAdrenaline(void)
-{
- if (m_bAdrenalineActive && m_nAdrenalineTime != 0) {
- m_nAdrenalineTime = 0;
- CTimer::SetTimeScale(1.0f);
- }
-}
-
+#include "common.h"
+#include "patcher.h"
+#include "PlayerPed.h"
+#include "Camera.h"
+#include "WeaponEffects.h"
+#include "ModelIndices.h"
+#include "World.h"
+#include "RpAnimBlend.h"
+#include "General.h"
+#include "Pools.h"
+#include "Darkel.h"
+
+CPlayerPed::~CPlayerPed()
+{
+ delete m_pWanted;
+}
+
+WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); }
+WRAPPER void CPlayerPed::ProcessControl(void) { EAXJMP(0x4EFD90); }
+
+CPlayerPed::CPlayerPed(void) : CPed(PEDTYPE_PLAYER1)
+{
+ m_fMoveSpeed = 0.0f;
+ SetModelIndex(MI_PLAYER);
+ SetInitialState();
+
+ m_pWanted = new CWanted();
+ m_pWanted->Initialise();
+ m_pArrestingCop = nil;
+ m_currentWeapon = WEAPONTYPE_UNARMED;
+ m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+ m_nSpeedTimer = 0;
+ m_bSpeedTimerFlag = 0;
+ m_pPointGunAt = nil;
+ m_nPedState = PED_IDLE;
+ m_fMaxStamina = 150.0f;
+ m_fCurrentStamina = m_fMaxStamina;
+ m_fStaminaProgress = 0.0f;
+ m_bShouldEvade = 0;
+ field_1367 = 0;
+ m_nShotDelay = 0;
+ field_1376 = 0.0f;
+ field_1380 = 0;
+ m_bHasLockOnTarget = false;
+ m_bCanBeDamaged = true;
+ m_fWalkAngle = 0.0f;
+ m_fFPSMoveHeading = 0.0f;
+ m_nTargettableObjects[0] = m_nTargettableObjects[1] = m_nTargettableObjects[2] = m_nTargettableObjects[3] = -1;
+ field_1413 = 0;
+ for (int i = 0; i < 6; i++) {
+ m_vecSafePos[i] = CVector(0.0f, 0.0f, 0.0f);
+ m_pPedAtSafePos[i] = nil;
+ }
+}
+
+void CPlayerPed::ClearWeaponTarget()
+{
+ if (m_nPedType == PEDTYPE_PLAYER1) {
+ m_pPointGunAt = nil;
+ TheCamera.ClearPlayerWeaponMode();
+ CWeaponEffects::ClearCrosshair();
+ }
+ ClearPointGunAt();
+}
+
+void
+CPlayerPed::SetWantedLevel(int32 level)
+{
+ m_pWanted->SetWantedLevel(level);
+}
+
+void
+CPlayerPed::SetWantedLevelNoDrop(int32 level)
+{
+ m_pWanted->SetWantedLevelNoDrop(level);
+}
+
+void
+CPlayerPed::MakeObjectTargettable(int32 handle)
+{
+ for (int i = 0; i < ARRAY_SIZE(m_nTargettableObjects); i++) {
+ if (CPools::GetObjectPool()->GetAt(m_nTargettableObjects[i]) == nil) {
+ m_nTargettableObjects[i] = handle;
+ return;
+ }
+ }
+}
+
+// I don't know the actual purpose of parameter
+void
+CPlayerPed::AnnoyPlayerPed(bool annoyedByPassingEntity)
+{
+ if (m_pedStats->m_temper < 52) {
+ m_pedStats->m_temper++;
+ } else {
+ if (annoyedByPassingEntity) {
+ if (m_pedStats->m_temper < 55) {
+ m_pedStats->m_temper++;
+ } else {
+ m_pedStats->m_temper = 46;
+ }
+ }
+ }
+}
+
+void
+CPlayerPed::ClearAdrenaline(void)
+{
+ if (m_bAdrenalineActive && m_nAdrenalineTime != 0) {
+ m_nAdrenalineTime = 0;
+ CTimer::SetTimeScale(1.0f);
+ }
+}
+
CPlayerInfo *
CPlayerPed::GetPlayerInfoForThisPlayerPed()
{
@@ -118,8 +119,8 @@ CPlayerPed::GetPlayerInfoForThisPlayerPed()
return &CWorld::Players[0];
return nil;
-}
-
+}
+
void
CPlayerPed::SetupPlayerPed(int32 index)
{
@@ -129,21 +130,21 @@ CPlayerPed::SetupPlayerPed(int32 index)
player->SetOrientation(0.0f, 0.0f, 0.0f);
CWorld::Add(player);
- player->m_wepAccuracy = 100;
-}
-
+ player->m_wepAccuracy = 100;
+}
+
void
CPlayerPed::DeactivatePlayerPed(int32 index)
{
- CWorld::Remove(CWorld::Players[index].m_pPed);
-}
-
+ CWorld::Remove(CWorld::Players[index].m_pPed);
+}
+
void
CPlayerPed::ReactivatePlayerPed(int32 index)
{
- CWorld::Add(CWorld::Players[index].m_pPed);
-}
-
+ CWorld::Add(CWorld::Players[index].m_pPed);
+}
+
void
CPlayerPed::UseSprintEnergy(void)
{
@@ -158,8 +159,8 @@ CPlayerPed::UseSprintEnergy(void)
if (m_fMaxStamina < 1000.0f)
m_fMaxStamina += 10.0f;
}
-}
-
+}
+
void
CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
{
@@ -179,9 +180,9 @@ CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
weaponAnim->SetRun();
weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
}
- TheCamera.ClearPlayerWeaponMode();
-}
-
+ TheCamera.ClearPlayerWeaponMode();
+}
+
void
CPlayerPed::ReApplyMoveAnims(void)
{
@@ -199,8 +200,8 @@ CPlayerPed::ReApplyMoveAnims(void)
}
}
}
-}
-
+}
+
void
CPlayerPed::SetInitialState(void)
{
@@ -236,8 +237,8 @@ CPlayerPed::SetInitialState(void)
m_bCanBeDamaged = true;
m_pedStats->m_temper = 50;
m_fWalkAngle = 0.0f;
-}
-
+}
+
void
CPlayerPed::SetRealMoveAnim(void)
{
@@ -392,7 +393,9 @@ CPlayerPed::SetRealMoveAnim(void)
curRunAssoc->flags &= ~ASSOC_RUNNING;
curRunAssoc->blendAmount = 0.0f;
curRunAssoc->blendDelta = 0.0f;
- } else if (curSprintAssoc->blendDelta < 0.0f) {
+ } else if (curSprintAssoc->blendDelta >= 0.0f) {
+
+ // Stop sprinting when tired
curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
curSprintAssoc->blendDelta = -1.0f;
curRunAssoc->blendDelta = 1.0f;
@@ -460,24 +463,240 @@ CPlayerPed::SetRealMoveAnim(void)
curSprintAssoc->speed = 2.0f;
}
}
-}
-
-class CPlayerPed_ : public CPlayerPed
-{
-public:
- CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
- void dtor(void) { CPlayerPed::~CPlayerPed(); }
- void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); }
-};
-
-STARTPATCHES
- InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP);
- InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
- InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP);
- InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
- InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
- InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP);
- InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP);
- InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP);
- InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP);
-ENDPATCHES
+}
+
+void
+CPlayerPed::RestoreSprintEnergy(float restoreSpeed)
+{
+ if (m_fCurrentStamina < m_fMaxStamina)
+ m_fCurrentStamina += restoreSpeed * CTimer::GetTimeStep() * 0.5f;
+}
+
+bool
+CPlayerPed::DoWeaponSmoothSpray(void)
+{
+ if (m_nPedState == PED_ATTACK && !m_pPointGunAt) {
+ eWeaponType weapon = GetWeapon()->m_eWeaponType;
+ if (weapon == WEAPONTYPE_FLAMETHROWER || weapon == WEAPONTYPE_COLT45 || weapon == WEAPONTYPE_UZI || weapon == WEAPONTYPE_SHOTGUN ||
+ weapon == WEAPONTYPE_AK47 || weapon == WEAPONTYPE_M16 || weapon == WEAPONTYPE_HELICANNON)
+ return true;
+ }
+ return false;
+}
+
+void
+CPlayerPed::DoStuffToGoOnFire(void)
+{
+ if (m_nPedState == PED_SNIPER_MODE)
+ TheCamera.ClearPlayerWeaponMode();
+}
+
+bool
+CPlayerPed::DoesTargetHaveToBeBroken(CVector target, CWeapon *weaponUsed)
+{
+ CVector distVec = target - GetPosition();
+
+ if (distVec.Magnitude() > CWeaponInfo::GetWeaponInfo(weaponUsed->m_eWeaponType)->m_fRange)
+ return true;
+
+ if (weaponUsed->m_eWeaponType != WEAPONTYPE_SHOTGUN && weaponUsed->m_eWeaponType != WEAPONTYPE_AK47)
+ return false;
+
+ distVec.Normalise();
+
+ if (DotProduct(distVec,GetForward()) < 0.4f)
+ return true;
+
+ return false;
+}
+
+// Cancels landing anim while running & jumping? I think
+void
+CPlayerPed::RunningLand(CPad *padUsed)
+{
+ CAnimBlendAssociation *landAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_LAND);
+ if (landAssoc && landAssoc->currentTime == 0.0f && m_fMoveSpeed > 1.5f
+ && padUsed && (padUsed->GetPedWalkLeftRight() != 0.0f || padUsed->GetPedWalkUpDown() != 0.0f)) {
+
+ landAssoc->blendDelta = -1000.0f;
+ landAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+ CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_JUMP_LAND)->SetFinishCallback(FinishJumpCB, this);
+
+ if (m_nPedState == PED_JUMP)
+ RestorePreviousState();
+ }
+}
+
+bool
+CPlayerPed::IsThisPedAttackingPlayer(CPed *suspect)
+{
+ if (suspect->m_pPointGunAt == this)
+ return true;
+
+ switch (suspect->m_objective) {
+ case OBJECTIVE_KILL_CHAR_ON_FOOT:
+ case OBJECTIVE_KILL_CHAR_ANY_MEANS:
+ if (suspect->m_pedInObjective == this)
+ return true;
+
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+void
+CPlayerPed::PlayerControlSniper(CPad *padUsed)
+{
+ ProcessWeaponSwitch(padUsed);
+ TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
+
+ if (!padUsed->GetTarget()) {
+ RestorePreviousState();
+ TheCamera.ClearPlayerWeaponMode();
+ }
+
+ if (padUsed->WeaponJustDown()) {
+ CVector firePos(0.0f, 0.0f, 0.6f);
+ firePos = GetMatrix() * firePos;
+ GetWeapon()->Fire(this, &firePos);
+ }
+ GetWeapon()->Update(m_audioEntityId);
+}
+
+// I think R* also used goto in here.
+void
+CPlayerPed::ProcessWeaponSwitch(CPad *padUsed)
+{
+ if (CDarkel::FrenzyOnGoing())
+ goto switchDetectDone;
+
+ // The fact that m_nSelectedWepSlot is int8 makes below loops circular loop.
+
+ if (padUsed->CycleWeaponRightJustDown() && !m_pPointGunAt) {
+
+ if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON_RUNABOUT
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER_RUNABOUT
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER_RUNABOUT) {
+
+ for (m_nSelectedWepSlot = m_currentWeapon + 1; m_nSelectedWepSlot < WEAPONTYPE_TOTAL_INVENTORY_WEAPONS; ++m_nSelectedWepSlot) {
+ if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
+ goto switchDetectDone;
+ }
+ }
+ m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+ }
+ } else if (padUsed->CycleWeaponLeftJustDown() && !m_pPointGunAt) {
+ if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
+
+ for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) {
+ if (HasWeapon(m_nSelectedWepSlot) && GetWeapon(m_nSelectedWepSlot).HasWeaponAmmoToBeUsed()) {
+ goto switchDetectDone;
+ }
+ }
+ m_nSelectedWepSlot = WEAPONTYPE_DETONATOR;
+ }
+ } else if (CWeaponInfo::GetWeaponInfo((eWeaponType)m_currentWeapon)->m_eWeaponFire != WEAPON_FIRE_MELEE) {
+ if (GetWeapon(m_currentWeapon).m_nAmmoTotal <= 0) {
+ if (TheCamera.PlayerWeaponMode.Mode != CCam::MODE_M16_1STPERSON
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_SNIPER
+ && TheCamera.PlayerWeaponMode.Mode != CCam::MODE_ROCKETLAUNCHER) {
+
+ for (m_nSelectedWepSlot = m_currentWeapon - 1; m_nSelectedWepSlot >= 0; --m_nSelectedWepSlot) {
+ if (m_nSelectedWepSlot == WEAPONTYPE_BASEBALLBAT && HasWeapon(WEAPONTYPE_BASEBALLBAT)
+ || GetWeapon(m_nSelectedWepSlot).m_nAmmoTotal > 0 && m_nSelectedWepSlot != WEAPONTYPE_MOLOTOV && m_nSelectedWepSlot != WEAPONTYPE_GRENADE) {
+ goto switchDetectDone;
+ }
+ }
+ m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
+ }
+ }
+ }
+
+switchDetectDone:
+ if (m_nSelectedWepSlot != m_currentWeapon) {
+ if (m_nPedState != PED_ATTACK && m_nPedState != PED_AIM_GUN && m_nPedState != PED_FIGHT)
+ MakeChangesForNewWeapon(m_nSelectedWepSlot);
+ }
+}
+
+void
+CPlayerPed::PlayerControlM16(CPad *padUsed)
+{
+ ProcessWeaponSwitch(padUsed);
+ TheCamera.PlayerExhaustion = (1.0f - (m_fCurrentStamina - -150.0f) / 300.0f) * 0.9f + 0.1f;
+
+ if (!padUsed->GetTarget()) {
+ RestorePreviousState();
+ TheCamera.ClearPlayerWeaponMode();
+ }
+
+ if (padUsed->GetWeapon()) {
+ CVector firePos(0.0f, 0.0f, 0.6f);
+ firePos = GetMatrix() * firePos;
+ GetWeapon()->Fire(this, &firePos);
+ }
+ GetWeapon()->Update(m_audioEntityId);
+}
+
+void
+CPlayerPed::PlayerControlFighter(CPad *padUsed)
+{
+ float leftRight = padUsed->GetPedWalkLeftRight();
+ float upDown = padUsed->GetPedWalkUpDown();
+ float displacement = sqrt(upDown * upDown + leftRight * leftRight);
+
+ if (displacement > 0.0f) {
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown) - TheCamera.Orientation;
+ m_takeAStepAfterAttack = displacement > 120.0f;
+ if (padUsed->GetSprint() && displacement > 60.0f)
+ bIsAttacking = false;
+ }
+
+ if (!CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bHeavy && padUsed->JumpJustDown()) {
+ if (m_bShouldEvade && m_pEvadingFrom) {
+ SetEvasiveDive((CPhysical*)m_pEvadingFrom, 1);
+ m_bShouldEvade = false;
+ m_pEvadingFrom = nil;
+ } else {
+ SetJump();
+ }
+ }
+}
+
+class CPlayerPed_ : public CPlayerPed
+{
+public:
+ CPlayerPed* ctor(void) { return ::new (this) CPlayerPed(); }
+ void dtor(void) { CPlayerPed::~CPlayerPed(); }
+ void SetMoveAnim_(void) { CPlayerPed::SetMoveAnim(); }
+};
+
+STARTPATCHES
+ InjectHook(0x4EF7E0, &CPlayerPed_::ctor, PATCH_JUMP);
+ InjectHook(0x4EFB30, &CPlayerPed_::dtor, PATCH_JUMP);
+ InjectHook(0x4F3760, &CPlayerPed_::SetMoveAnim_, PATCH_JUMP);
+ InjectHook(0x4F28A0, &CPlayerPed::ClearWeaponTarget, PATCH_JUMP);
+ InjectHook(0x4F3700, &CPlayerPed::AnnoyPlayerPed, PATCH_JUMP);
+ InjectHook(0x4F36C0, &CPlayerPed::GetPlayerInfoForThisPlayerPed, PATCH_JUMP);
+ InjectHook(0x4F2560, &CPlayerPed::MakeChangesForNewWeapon, PATCH_JUMP);
+ InjectHook(0x4F07C0, &CPlayerPed::ReApplyMoveAnims, PATCH_JUMP);
+ InjectHook(0x4F0880, &CPlayerPed::SetRealMoveAnim, PATCH_JUMP);
+ InjectHook(0x4F1810, &CPlayerPed::PlayerControlFighter, PATCH_JUMP);
+ InjectHook(0x4F1340, &CPlayerPed::RestoreSprintEnergy, PATCH_JUMP);
+ InjectHook(0x4F1380, &CPlayerPed::DoWeaponSmoothSpray, PATCH_JUMP);
+ InjectHook(0x4F36E0, &CPlayerPed::DoStuffToGoOnFire, PATCH_JUMP);
+ InjectHook(0x4F3350, &CPlayerPed::DoesTargetHaveToBeBroken, PATCH_JUMP);
+ InjectHook(0x4F31D0, &CPlayerPed::RunningLand, PATCH_JUMP);
+ InjectHook(0x4F2D00, &CPlayerPed::IsThisPedAttackingPlayer, PATCH_JUMP);
+ InjectHook(0x4F1CF0, &CPlayerPed::PlayerControlSniper, PATCH_JUMP);
+ InjectHook(0x4F2310, &CPlayerPed::ProcessWeaponSwitch, PATCH_JUMP);
+ InjectHook(0x4F1DF0, &CPlayerPed::PlayerControlM16, PATCH_JUMP);
+ENDPATCHES