#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"
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);
}
// 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()
{
if (CWorld::Players[0].m_pPed == this)
return &CWorld::Players[0];
return nil;
}
void
CPlayerPed::SetupPlayerPed(int32 index)
{
CPlayerPed *player = new CPlayerPed();
CWorld::Players[index].m_pPed = player;
player->SetOrientation(0.0f, 0.0f, 0.0f);
CWorld::Add(player);
player->m_wepAccuracy = 100;
}
void
CPlayerPed::DeactivatePlayerPed(int32 index)
{
CWorld::Remove(CWorld::Players[index].m_pPed);
}
void
CPlayerPed::ReactivatePlayerPed(int32 index)
{
CWorld::Add(CWorld::Players[index].m_pPed);
}
void
CPlayerPed::UseSprintEnergy(void)
{
if (m_fCurrentStamina > -150.0f && !CWorld::Players[CWorld::PlayerInFocus].m_bInfiniteSprint
&& !m_bAdrenalineActive) {
m_fCurrentStamina = m_fCurrentStamina - CTimer::GetTimeStep();
m_fStaminaProgress = m_fStaminaProgress + CTimer::GetTimeStep();
}
if (m_fStaminaProgress >= 500.0f) {
m_fStaminaProgress = 0;
if (m_fMaxStamina < 1000.0f)
m_fMaxStamina += 10.0f;
}
}
void
CPlayerPed::MakeChangesForNewWeapon(int8 weapon)
{
if (m_nPedState == PED_SNIPER_MODE) {
RestorePreviousState();
TheCamera.ClearPlayerWeaponMode();
}
SetCurrentWeapon(weapon);
GetWeapon()->m_nAmmoInClip = min(GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
if (!(CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_bCanAim))
ClearWeaponTarget();
CAnimBlendAssociation *weaponAnim = RpAnimBlendClumpGetAssociation(GetClump(), CWeaponInfo::GetWeaponInfo(WEAPONTYPE_SNIPERRIFLE)->m_AnimToPlay);
if (weaponAnim) {
weaponAnim->SetRun();
weaponAnim->flags |= ASSOC_FADEOUTWHENDONE;
}
TheCamera.ClearPlayerWeaponMode();
}
void
CPlayerPed::ReApplyMoveAnims(void)
{
static AnimationId moveAnims[] = { ANIM_WALK, ANIM_RUN, ANIM_SPRINT, ANIM_IDLE_STANCE, ANIM_WALK_START };
for(int i = 0; i < ARRAY_SIZE(moveAnims); i++) {
CAnimBlendAssociation *curMoveAssoc = RpAnimBlendClumpGetAssociation(GetClump(), moveAnims[i]);
if (curMoveAssoc) {
if (strcmp(CAnimManager::GetAnimAssociation(m_animGroup, moveAnims[i])->hierarchy->name, curMoveAssoc->hierarchy->name) != 0) {
CAnimBlendAssociation *newMoveAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, moveAnims[i]);
newMoveAssoc->blendDelta = curMoveAssoc->blendDelta;
newMoveAssoc->blendAmount = curMoveAssoc->blendAmount;
curMoveAssoc->blendDelta = -1000.0f;
curMoveAssoc->flags |= ASSOC_DELETEFADEDOUT;
}
}
}
}
void
CPlayerPed::SetInitialState(void)
{
m_bAdrenalineActive = false;
m_nAdrenalineTime = 0;
CTimer::SetTimeStep(1.0f);
m_pSeekTarget = nil;
m_vecSeekPos = { 0.0f, 0.0f, 0.0f };
m_fleeFromPosX = 0.0f;
m_fleeFromPosY = 0.0f;
m_fleeFrom = nil;
m_fleeTimer = 0;
m_objective = OBJECTIVE_NONE;
m_prevObjective = OBJECTIVE_NONE;
bUsesCollision = true;
ClearAimFlag();
ClearLookFlag();
bIsPointingGunAt = false;
bRenderPedInCar = true;
if (m_pFire)
m_pFire->Extinguish();
RpAnimBlendClumpRemoveAllAssociations(GetClump());
m_nPedState = PED_IDLE;
SetMoveState(PEDMOVE_STILL);
m_nLastPedState = PED_NONE;
m_animGroup = ASSOCGRP_PLAYER;
m_fMoveSpeed = 0.0f;
m_nSelectedWepSlot = WEAPONTYPE_UNARMED;
m_bShouldEvade = false;
m_pEvadingFrom = nil;
bIsPedDieAnimPlaying = false;
SetRealMoveAnim();
m_bCanBeDamaged = true;
m_pedStats->m_temper = 50;
m_fWalkAngle = 0.0f;
}
void
CPlayerPed::SetRealMoveAnim(void)
{
CAnimBlendAssociation *curWalkAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK);
CAnimBlendAssociation *curRunAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN);
CAnimBlendAssociation *curSprintAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_SPRINT);
CAnimBlendAssociation *curWalkStartAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_WALK_START);
CAnimBlendAssociation *curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
CAnimBlendAssociation *curRunStopAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP);
CAnimBlendAssociation *curRunStopRAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RUN_STOP_R);
if (bResetWalkAnims) {
if (curWalkAssoc)
curWalkAssoc->SetCurrentTime(0.0f);
if (curRunAssoc)
curRunAssoc->SetCurrentTime(0.0f);
if (curSprintAssoc)
curSprintAssoc->SetCurrentTime(0.0f);
bResetWalkAnims = false;
}
if (!curIdleAssoc)
curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
if (!curIdleAssoc)
curIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
if ((!curRunStopAssoc || !(curRunStopAssoc->IsRunning())) && (!curRunStopRAssoc || !(curRunStopRAssoc->IsRunning()))) {
if (curRunStopAssoc && curRunStopAssoc->blendDelta >= 0.0f || curRunStopRAssoc && curRunStopRAssoc->blendDelta >= 0.0f) {
if (curRunStopAssoc) {
curRunStopAssoc->flags |= ASSOC_DELETEFADEDOUT;
curRunStopAssoc->blendAmount = 1.0f;
curRunStopAssoc->blendDelta = -8.0f;
} else if (curRunStopRAssoc) {
curRunStopRAssoc->flags |= ASSOC_DELETEFADEDOUT;
curRunStopRAssoc->blendAmount = 1.0f;
curRunStopRAssoc->blendDelta = -8.0f;
}
RestoreHeadingRate();
if (!curIdleAssoc) {
if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
nil, true, false, false, false, false, false)) {
curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 8.0f);
} else {
curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
}
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
}
curIdleAssoc->blendAmount = 0.0f;
curIdleAssoc->blendDelta = 8.0f;
} else if (m_fMoveSpeed == 0.0f && !curSprintAssoc) {
if (!curIdleAssoc) {
if (m_fCurrentStamina < 0.0f && !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f,
nil, true, false, false, false, false, false)) {
curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
} else {
curIdleAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
}
m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2500, 4000);
}
if (m_fCurrentStamina > 0.0f && curIdleAssoc->animId == ANIM_IDLE_TIRED) {
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
} else if (m_nPedState != PED_FIGHT) {
if (m_fCurrentStamina < 0.0f && curIdleAssoc->animId != ANIM_IDLE_TIRED
&& !CWorld::TestSphereAgainstWorld(GetPosition(), 0.0f, nil, true, false, false, false, false, false)) {
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 4.0f);
} else if (curIdleAssoc->animId != ANIM_IDLE_STANCE) {
CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
}
}
m_nMoveState = PEDMOVE_STILL;
} else {
if (curIdleAssoc) {
if (curWalkStartAssoc) {
curWalkStartAssoc->blendAmount = 1.0f;
curWalkStartAssoc->blendDelta = 0.0f;
} else {
curWalkStartAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK_START);
}
if (curWalkAssoc)
curWalkAssoc->SetCurrentTime(0.0f);
if (curRunAssoc)
curRunAssoc->SetCurrentTime(0.0f);
delete curIdleAssoc;
delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
delete RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
delete curSprintAssoc;
curSprintAssoc = nil;
m_nMoveState = PEDMOVE_WALK;
}
if (curRunStopAssoc) {
delete curRunStopAssoc;
RestoreHeadingRate();
}
if (curRunStopRAssoc) {
delete curRunStopRAssoc;
RestoreHeadingRate();
}
if (!curWalkAssoc) {
curWalkAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_WALK);
curWalkAssoc->blendAmount = 0.0f;
}
if (!curRunAssoc) {
curRunAssoc = CAnimManager::AddAnimation(GetClump(), m_animGroup, ANIM_RUN);
curRunAssoc->blendAmount = 0.0f;
}
if (curWalkStartAssoc && !(curWalkStartAssoc->IsRunning())) {
delete curWalkStartAssoc;
curWalkStartAssoc = nil;
curWalkAssoc->SetRun();
curRunAssoc->SetRun();
}
if (m_nMoveState == PEDMOVE_SPRINT) {
if (m_fCurrentStamina < 0.0f && (m_fCurrentStamina <= -150.0f || !curSprintAssoc || curSprintAssoc->blendDelta < 0.0f))
m_nMoveState = PEDMOVE_STILL;
if (curWalkStartAssoc)
m_nMoveState = PEDMOVE_STILL;
}
if (curSprintAssoc && (m_nMoveState != PEDMOVE_SPRINT || m_fMoveSpeed < 0.4f)) {
if (curSprintAssoc->blendAmount == 0.0f) {
curSprintAssoc->blendDelta = -1000.0f;
curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
} else if (curSprintAssoc->blendDelta >= 0.0f || curSprintAssoc->blendAmount >= 0.8f) {
if (m_fMoveSpeed < 0.4f) {
AnimationId runStopAnim;
if (curSprintAssoc->currentTime / curSprintAssoc->hierarchy->totalLength < 0.5) // double
runStopAnim = ANIM_RUN_STOP;
else
runStopAnim = ANIM_RUN_STOP_R;
CAnimBlendAssociation* newRunStopAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, runStopAnim);
newRunStopAssoc->blendAmount = 1.0f;
newRunStopAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
m_headingRate = 0.0f;
curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
curSprintAssoc->blendDelta = -1000.0f;
curWalkAssoc->flags &= ~ASSOC_RUNNING;
curWalkAssoc->blendAmount = 0.0f;
curWalkAssoc->blendDelta = 0.0f;
curRunAssoc->flags &= ~ASSOC_RUNNING;
curRunAssoc->blendAmount = 0.0f;
curRunAssoc->blendDelta = 0.0f;
} else if (curSprintAssoc->blendDelta < 0.0f) {
curSprintAssoc->flags |= ASSOC_DELETEFADEDOUT;
curSprintAssoc->blendDelta = -1.0f;
curRunAssoc->blendDelta = 1.0f;
}
} else if (m_fMoveSpeed < 1.0f) {
curSprintAssoc->blendDelta = -8.0f;
curRunAssoc->blendDelta = 8.0f;
}
} else if (curWalkStartAssoc) {
curWalkAssoc->flags &= ~ASSOC_RUNNING;
curRunAssoc->flags &= ~ASSOC_RUNNING;
curWalkAssoc->blendAmount = 0.0f;
curRunAssoc->blendAmount = 0.0f;
} else if (m_nMoveState == PEDMOVE_SPRINT) {
if (curSprintAssoc) {
if (curSprintAssoc->blendDelta < 0.0f) {
curSprintAssoc->blendDelta = 2.0f;
curRunAssoc->blendDelta = -2.0f;
}
} else {
curWalkAssoc->blendAmount = 0.0f;
curRunAssoc->blendAmount = 1.0f;
curSprintAssoc = CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_SPRINT, 2.0f);
}
UseSprintEnergy();
} else {
if (m_fMoveSpeed < 1.0f) {
curWalkAssoc->blendAmount = 1.0f;
curRunAssoc->blendAmount = 0.0f;
m_nMoveState = PEDMOVE_WALK;
} else if (m_fMoveSpeed < 2.0f) {
curWalkAssoc->blendAmount = 2.0f - m_fMoveSpeed;
curRunAssoc->blendAmount = m_fMoveSpeed - 1.0f;
m_nMoveState = PEDMOVE_RUN;
} else {
curWalkAssoc->blendAmount = 0.0f;
curRunAssoc->blendAmount = 1.0f;
m_nMoveState = PEDMOVE_RUN;
}
}
}
}
if (m_bAdrenalineActive) {
if (CTimer::GetTimeInMilliseconds() > m_nAdrenalineTime) {
m_bAdrenalineActive = false;
CTimer::SetTimeScale(1.0f);
if (curWalkStartAssoc)
curWalkStartAssoc->speed = 1.0f;
if (curWalkAssoc)
curWalkAssoc->speed = 1.0f;
if (curRunAssoc)
curRunAssoc->speed = 1.0f;
if (curSprintAssoc)
curSprintAssoc->speed = 1.0f;
} else {
CTimer::SetTimeScale(1.0f / 3);
if (curWalkStartAssoc)
curWalkStartAssoc->speed = 2.0f;
if (curWalkAssoc)
curWalkAssoc->speed = 2.0f;
if (curRunAssoc)
curRunAssoc->speed = 2.0f;
if (curSprintAssoc)
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