From d4ea6912f5deb303f1ce75acf6c680d00244ea66 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?eray=20or=C3=A7unus?= <erayorcunus@gmail.com>
Date: Wed, 3 Jul 2019 19:34:42 +0300
Subject: [PATCH] Even more CPed
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: eray orçunus <erayorcunus@gmail.com>
---
 src/Camera.cpp               |  13 +-
 src/Camera.h                 |   1 +
 src/General.h                |  15 +-
 src/entities/Ped.cpp         | 547 +++++++++++++++++++++++++++++++++--
 src/entities/Ped.h           | 108 +++++--
 src/entities/PedIK.cpp       |  56 ++++
 src/entities/PedIK.h         |   4 +
 src/entities/PlayerPed.h     |   2 +-
 src/modelinfo/PedModelInfo.h |   6 +-
 src/weapons/WeaponInfo.cpp   |  10 +-
 10 files changed, 705 insertions(+), 57 deletions(-)

diff --git a/src/Camera.cpp b/src/Camera.cpp
index e5e50ef2..45172c44 100644
--- a/src/Camera.cpp
+++ b/src/Camera.cpp
@@ -1252,7 +1252,8 @@ CCam::FixCamWhenObscuredByVehicle(const CVector &TargetCoors)
 	Source.z += HeightFixerCarsObscuring;
 }
 
-bool CCam::Using3rdPersonMouseCam() 
+bool
+CCam::Using3rdPersonMouseCam() 
 {
 	return CCamera::m_bUseMouse3rdPerson &&
 		(Mode == MODE_FOLLOWPED ||
@@ -1261,6 +1262,16 @@ bool CCam::Using3rdPersonMouseCam()
 			Mode != MODE_TOPDOWN1 && this->CamTargetEntity == FindPlayerPed());
 }
 
+bool
+CCam::GetWeaponFirstPersonOn()
+{
+	CEntity *target = this->CamTargetEntity;
+	if (target && target->IsPed())
+		return ((CPed*)target)->GetWeapon()->m_bAddRotOffset;
+	
+	return false;
+}
+
 STARTPATCHES
 	InjectHook(0x42C760, &CCamera::IsSphereVisible, PATCH_JUMP);
 	InjectHook(0x46FD00, &CCamera::SetFadeColour, PATCH_JUMP);
diff --git a/src/Camera.h b/src/Camera.h
index 6d20de72..c4bcb674 100644
--- a/src/Camera.h
+++ b/src/Camera.h
@@ -171,6 +171,7 @@ struct CCam
 	void Cam_On_A_String_Unobscured(const CVector &TargetCoors, float BaseDist);
 	void FixCamWhenObscuredByVehicle(const CVector &TargetCoors);
 	bool Using3rdPersonMouseCam();
+	bool GetWeaponFirstPersonOn();
 
 	void Process_Debug(float *vec, float a, float b, float c);
 	void Process_FollowPed(const CVector &CameraTarget, float TargetOrientation, float, float);
diff --git a/src/General.h b/src/General.h
index fd78edaa..d315d50b 100644
--- a/src/General.h
+++ b/src/General.h
@@ -42,13 +42,14 @@ public:
 
 	static float LimitRadianAngle(float angle)
 	{
+		float result;
+
 		if (angle < -25.0f)
-			angle = -25.0f;
-
-		if (angle > 25.0f)
-			angle = 25.0f;
-
-		float result = angle;
+			result = -25.0f;
+		else if (angle > 25.0f)
+			result = 25.0f;
+		else
+			result = angle;
 
 		while (result >= PI) {
 			result -= 2 * PI;
@@ -71,7 +72,7 @@ public:
 
 		if (x > 0.0f) {
 			if (y > 0.0f)
-				return 2 * PI - atan2(x / y, 1.0f);
+				return PI - atan2(x / y, 1.0f);
 			else
 				return -atan2(x / y, 1.0f);
 		} else {
diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp
index e908f14c..537f089f 100644
--- a/src/entities/Ped.cpp
+++ b/src/entities/Ped.cpp
@@ -1,5 +1,6 @@
 #include "common.h"
 #include "patcher.h"
+#include "main.h"
 #include "Pools.h"
 #include "Particle.h"
 #include "Stats.h"
@@ -18,6 +19,10 @@
 #include "Weather.h"
 #include "CullZones.h"
 #include "Population.h"
+#include "Renderer.h"
+#include "Lights.h"
+#include "PointLights.h"
+#include "Pad.h"
 
 WRAPPER void CPed::QuitEnteringCar() { EAXJMP(0x4E0E00); }
 WRAPPER void CPed::KillPedWithCar(CVehicle* veh, float impulse) { EAXJMP(0x4EC430); }
@@ -30,11 +35,8 @@ WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dra
 WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); }
 WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
 WRAPPER void CPed::ProcessControl(void) { EAXJMP(0x4C8910); }
-WRAPPER void CPed::Teleport(CVector) { EAXJMP(0x4D3E70); }
 WRAPPER void CPed::PreRender(void) { EAXJMP(0x4CFDD0); }
 WRAPPER void CPed::Render(void) { EAXJMP(0x4D03F0); }
-WRAPPER bool CPed::SetupLighting(void) { EAXJMP(0x4A7D30); }
-WRAPPER void CPed::RemoveLighting(bool) { EAXJMP(0x4A7DC0); }
 WRAPPER int32 CPed::ProcessEntityCollision(CEntity*, CColPoint*) { EAXJMP(0x4CBB30); }
 WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); }
 
@@ -102,7 +104,7 @@ CPed::FlagToDestroyWhenNextProcessed(void)
 	}
 	bInVehicle = false;
 	m_pMyVehicle = nil;
-	if (m_nCreatedBy == 2) /* TODO: enum (MISSION) */
+	if (m_nCreatedBy == CREATED_BY_SCRIPT)
 		m_nPedState = PED_DEAD;
 	else
 		m_nPedState = PED_NONE;
@@ -279,12 +281,12 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
 	m_talkTimer = 0;
 	m_talkTypeLast = 167;
 	m_talkType = 167;
-	m_objective = 0;
-	m_prevObjective = 0;
-	m_nCreatedBy = 1;
-	field_180 = 0;
-	m_field_16C = nil;
-	field_170 = 0;
+	m_objective = OBJECTIVE_NONE;
+	m_prevObjective = OBJECTIVE_NONE;
+	m_nCreatedBy = CREATED_BY_RANDOM;
+	m_leader = nil;
+	m_pedInObjective = nil;
+	m_carInObjective = nil;
 	bInVehicle = 0;
 	m_pMyVehicle = nil;
 	m_pVehicleAnim = nil;
@@ -307,8 +309,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
 	m_lastHitTime = 0;
 	m_hitRecoverTimer = 0;
 	field_4E8 = 0;
-	m_movedX = 0;
-	m_movedY = 0;
+	m_moved = CVector2D(0.0f, 0.0f);
 	m_fRotationCur = 0.0f;
 	m_headingRate = 15.0f;
 	m_fRotationDest = 0.0f;
@@ -334,13 +335,13 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
 	m_pCollidingEntity = nil;
 	m_nPedState = PED_IDLE;
 	m_nLastPedState = PED_NONE;
-	m_nMoveState = 1;
+	m_nMoveState = PEDMOVE_STILL;
 	m_nStoredActionState = 0;
 	m_pFire = nil;
 	m_pPointGunAt = nil;
-	m_pLookTarget = 0;
+	m_pLookTarget = nil;
 	m_fLookDirection = 0.0f;
-	m_pCurSurface = 0;
+	m_pCurSurface = nil;
 	m_targetUnused = nil;
 	m_nPathNodes = 0;
 	m_nCurPathNode = 0;
@@ -630,6 +631,21 @@ CPed::CanSetPedState(void)
 		m_nPedState != PED_ENTER_CAR && m_nPedState != PED_DEAD && m_nPedState != PED_CARJACK && m_nPedState != PED_STEAL_CAR;
 }
 
+bool
+CPed::IsPedInControl(void)
+{
+	return m_nPedState <= PED_STATES_NO_AI
+		&& !m_ped_flagB8 && !m_ped_flagB10
+		&& m_fHealth > 0.0f;
+}
+
+bool
+CPed::CanStrafeOrMouseControl(void)
+{
+	return m_nPedState == PED_NONE || m_nPedState == PED_IDLE || m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY ||
+		m_nPedState == PED_ATTACK || m_nPedState == PED_FIGHT || m_nPedState == PED_AIM_GUN || m_nPedState == PED_JUMP;
+}
+
 void
 CPed::AddWeaponModel(int id)
 {
@@ -847,7 +863,7 @@ CPed::Avoid(void)
 		if (m_nMoveState != PEDMOVE_NONE && m_nMoveState != PEDMOVE_STILL) {
 			nearestPed = m_nearPeds[0];
 
-			if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_field_16C) {
+			if (nearestPed && nearestPed->m_nPedState != PED_DEAD && nearestPed != m_pSeekTarget && nearestPed != m_pedInObjective) {
 
 				// Check if this ped wants to avoid the nearest one
 				if (CPedType::GetAvoid(this->m_nPedType) & CPedType::GetFlag(nearestPed->m_nPedType)) {
@@ -2037,15 +2053,496 @@ CPed::SetModelIndex(uint32 mi)
 	RpAnimBlendClumpInit((RpClump*) m_rwObject);
 	RpAnimBlendClumpFillFrameArray((RpClump*) m_rwObject, m_pFrames);
 	CPedModelInfo *modelInfo = (CPedModelInfo*)CModelInfo::GetModelInfo(m_modelIndex);
-	SetPedStats(static_cast<ePedStats>(modelInfo->m_pedStatType));
+	SetPedStats((ePedStats) modelInfo->m_pedStatType);
 	m_headingRate = m_pedStats->m_headingChangeRate;
-	m_animGroup = static_cast<AssocGroupId>(modelInfo->m_animGroup);
+	m_animGroup = (AssocGroupId) modelInfo->m_animGroup;
 	CAnimManager::AddAnimation((RpClump*) m_rwObject, m_animGroup, ANIM_IDLE_STANCE);
 
 	// This is a mistake by R*, velocity is CVector, whereas m_vecAnimMoveDelta is CVector2D. 
 	(*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = (CVector*) &m_vecAnimMoveDelta;
 }
 
+void
+CPed::RemoveLighting(bool reset)
+{
+	CRenderer::RemoveVehiclePedLights(this, reset);
+}
+
+bool
+CPed::SetupLighting(void)
+{
+	ActivateDirectional();
+	SetAmbientColoursForPedsCarsAndObjects();
+	if (m_ped_flagB10) {
+		WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+	} else {
+		// Note that this lightMult is only affected by LIGHT_DARKEN. If there's no LIGHT_DARKEN, it will be 1.0.
+		float lightMult = CPointLights::GenerateLightsAffectingObject(&GetPosition());
+		if (!m_ped_flagB20 && lightMult != 1.0f) {
+			SetAmbientAndDirectionalColours(lightMult);
+			return true;
+		}
+	}
+	return false;
+}
+
+void
+CPed::Teleport(CVector pos)
+{
+	CWorld::Remove(this);
+	GetPosition() = pos;
+	bIsStanding = false;
+	m_nPedStateTimer = 0;
+	m_actionX = 0.0f;
+	m_actionY = 0.0f;
+	m_pDamageEntity = nil;
+	CWorld::Add(this);
+}
+
+void
+CPed::CalculateNewOrientation(void)
+{
+	if (CReplay::IsPlayingBack() || !IsPedInControl())
+		return;
+
+	CVector pos = *GetPosition();
+
+	GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur);
+	
+	// Because SetRotate makes pos. all 0
+	GetPosition() = pos;
+}
+
+float
+CPed::WorkOutHeadingForMovingFirstPerson(float offset)
+{
+	if (!IsPlayer())
+		return 0.0f;
+
+	CPad *pad0 = CPad::GetPad(0);
+	float leftRight = pad0->GetPedWalkLeftRight();
+	float upDown = pad0->GetPedWalkUpDown();
+	float &angle = ((CPlayerPed*)this)->m_fWalkAngle;
+
+	if (upDown != 0.0f) {
+		angle = CGeneral::GetRadianAngleBetweenPoints(0.0f, 0.0f, -leftRight, upDown);
+	} else {
+		if (leftRight < 0.0f)
+			angle = 0.5 * PI;
+		else if (leftRight > 0.0f)
+			angle = -0.5 * PI;
+	}
+
+	return CGeneral::LimitRadianAngle(offset + angle);
+}
+
+void
+CPed::CalculateNewVelocity(void)
+{
+	if (IsPedInControl()) {
+		float headAmount = DEGTORAD(m_headingRate) * CTimer::GetTimeStep();
+		m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+		float limitedRotDest = CGeneral::LimitRadianAngle(m_fRotationDest);
+
+		if (m_fRotationCur - PI > limitedRotDest) {
+				limitedRotDest += 2 * PI;
+		} else if(PI + m_fRotationCur < limitedRotDest) {
+			limitedRotDest -= 2 * PI;
+		}
+
+		if (IsPlayer() && m_nPedState == PED_ATTACK)
+			headAmount /= 4.0f;
+
+		float neededTurn = limitedRotDest - m_fRotationCur;
+		if (neededTurn <= headAmount) {
+			if (neededTurn > (-headAmount))
+				m_fRotationCur += neededTurn;
+			else
+				m_fRotationCur -= headAmount;
+		} else {
+			m_fRotationCur += headAmount;
+		}
+	}
+
+	CVector2D forward(sin(m_fRotationCur), cos(m_fRotationCur));
+
+	m_moved.x = CrossProduct2D(m_vecAnimMoveDelta, forward); // (m_vecAnimMoveDelta.x * cos(m_fRotationCur)) + -sin(m_fRotationCur) * m_vecAnimMoveDelta.y;
+	m_moved.y = DotProduct2D(m_vecAnimMoveDelta, forward);  // m_vecAnimMoveDelta.y* cos(m_fRotationCur) + (m_vecAnimMoveDelta.x * sin(m_fRotationCur));
+
+	if (CTimer::GetTimeStep() >= 0.01f) {
+		m_moved = m_moved * (1 / CTimer::GetTimeStep());
+	} else {
+		m_moved = m_moved * (1 / 100.0f);
+	}
+
+	if ((!TheCamera.Cams[TheCamera.ActiveCam].GetWeaponFirstPersonOn() && !TheCamera.Cams[0].Using3rdPersonMouseCam())
+		|| FindPlayerPed() != this || !CanStrafeOrMouseControl())
+		return;
+
+	float walkAngle = WorkOutHeadingForMovingFirstPerson(m_fRotationCur);
+	float pedSpeed = m_moved.Magnitude();
+	float localWalkAngle = CGeneral::LimitRadianAngle(walkAngle - m_fRotationCur);
+
+	if (localWalkAngle < -0.5 * PI) {
+		localWalkAngle += PI;
+	} else if (localWalkAngle > 0.5 * PI) {
+		localWalkAngle -= PI;
+	}
+
+	// Interestingly this part is responsible for diagonal walking.
+	if (localWalkAngle > -DEGTORAD(50.0f) && localWalkAngle < DEGTORAD(50.0f)) {
+		TheCamera.Cams[TheCamera.ActiveCam].m_fPlayerVelocity = pedSpeed;
+		m_moved = CVector2D(-sin(walkAngle), cos(walkAngle)) * pedSpeed;
+	}
+
+	CAnimBlendAssociation *idleAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_IDLE_STANCE);
+	CAnimBlendAssociation* fightAssoc = RpAnimBlendClumpGetAssociation((RpClump*) m_rwObject, ANIM_FIGHT_IDLE);
+
+	if ((!idleAssoc || idleAssoc->blendAmount < 0.5f) && !fightAssoc) {
+		LimbOrientation newUpperLegs;
+		newUpperLegs.phi = localWalkAngle;
+
+		if (newUpperLegs.phi < -DEGTORAD(100.0f)) {
+			newUpperLegs.phi += PI;
+		} else if (newUpperLegs.phi > DEGTORAD(100.0f)) {
+			newUpperLegs.phi -= PI;
+		}
+
+		if (newUpperLegs.phi > -DEGTORAD(50.0f) && newUpperLegs.phi < DEGTORAD(50.0f)) {
+			newUpperLegs.theta = 0.0f;
+			m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGL], &newUpperLegs, false);
+			m_pedIK.RotateTorso(m_pFrames[PED_UPPERLEGR], &newUpperLegs, false);
+		}
+	}
+}
+
+bool
+CPed::CanBeDeleted(void)
+{
+	if (this->bInVehicle)
+		return false;
+
+	switch (m_nCreatedBy) {
+		case CREATED_BY_RANDOM:
+			return true;
+		case CREATED_BY_SCRIPT:
+			return false;
+		default:
+			return true;
+	}
+}
+
+bool
+CPed::CanPedDriveOff(void)
+{
+	if (m_nPedState != PED_DRIVING || m_lookTimer > CTimer::GetTimeInMilliseconds())
+		return false;
+
+	for (int i = 0; i < m_numNearPeds; i++) {
+		CPed *ped = m_nearPeds[i];
+		if (ped->m_nPedType == m_nPedType && ped->m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && ped->m_carInObjective == m_carInObjective) {
+			m_lookTimer = CTimer::GetTimeInMilliseconds() + 1000;
+			return false;
+		}
+	}
+	return true;
+}
+
+// I couldn't find where it is used.
+bool
+CPed::CanPedJumpThis(int32 unused)
+{
+	CVector2D forward(-sin(m_fRotationCur), -cos(m_fRotationCur));
+	CVector pos = GetPosition();
+	// wat?
+	CVector forwardPos(
+		forward.x + pos.x,
+		forward.y + pos.y,
+		pos.z);
+	return CWorld::GetIsLineOfSightClear(pos, forwardPos, true, false, false, true, false, false, false);
+}
+
+bool
+CPed::CanPedReturnToState(void)
+{
+	return m_nPedState <= PED_STATES_NO_AI && m_nPedState != PED_AIM_GUN && m_nPedState != PED_ATTACK &&
+		m_nPedState != PED_FIGHT && m_nPedState != PED_STEP_AWAY && m_nPedState != PED_SNIPER_MODE && m_nPedState != PED_LOOK_ENTITY;
+}
+
+bool
+CPed::CanSeeEntity(CEntity *entity, float threshold)
+{
+	float neededAngle = CGeneral::GetRadianAngleBetweenPoints(
+		entity->GetPosition().x,
+		entity->GetPosition().x,
+		GetPosition().x,
+		GetPosition().y);
+
+	if (neededAngle < 0.0f)
+		neededAngle += 2 * PI;
+	else if (neededAngle > 2 * PI)
+		neededAngle -= 2 * PI;
+
+	float ourAngle = m_fRotationCur;
+	if (ourAngle < 0.0f)
+		ourAngle += 2 * PI;
+	else if (ourAngle > 2 * PI)
+		ourAngle -= 2 * PI;
+
+	float neededTurn = fabs(neededAngle - ourAngle);
+
+	return neededTurn < threshold || 2 * PI - threshold < neededTurn;
+}
+
+bool
+CPed::IsTemporaryObjective(eObjective objective)
+{
+	return objective == OBJECTIVE_LEAVE_VEHICLE || objective == OBJECTIVE_SET_LEADER ||
+		objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER;
+}
+
+void
+CPed::SetMoveState(eMoveState state)
+{
+	m_nMoveState = state;
+}
+
+void
+CPed::SetObjectiveTimer(int time)
+{
+	if (time == 0) {
+		m_objectiveTimer = 0;
+	} else if (CTimer::GetTimeInMilliseconds() > m_objectiveTimer) {
+		m_objectiveTimer = CTimer::GetTimeInMilliseconds() + time;
+	}
+}
+
+void
+CPed::ForceStoredObjective(eObjective objective)
+{
+	if (objective != OBJECTIVE_ENTER_CAR_AS_DRIVER && objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER) {
+		m_prevObjective = m_objective;
+		return;
+	}
+
+	switch (m_objective)
+	{
+		case OBJECTIVE_FLEE_TILL_SAFE:
+		case OBJECTIVE_KILL_CHAR_ON_FOOT:
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE:
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS:
+		case OBJECTIVE_GOTO_CHAR_ON_FOOT:
+		case OBJECTIVE_ENTER_CAR_AS_PASSENGER:
+		case OBJECTIVE_ENTER_CAR_AS_DRIVER:
+		case OBJECTIVE_GOTO_AREA_ON_FOOT:
+		case OBJECTIVE_RUN_TO_AREA:
+			return;
+		default:
+			m_prevObjective = m_objective;
+	}
+}
+
+void
+CPed::SetStoredObjective(void)
+{
+	if (m_objective == m_prevObjective)
+		return;
+
+	switch (m_objective)
+	{
+		case OBJECTIVE_FLEE_TILL_SAFE:
+		case OBJECTIVE_KILL_CHAR_ON_FOOT:
+		case OBJECTIVE_KILL_CHAR_ANY_MEANS:
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE:
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS:
+		case OBJECTIVE_GOTO_CHAR_ON_FOOT:
+		case OBJECTIVE_FOLLOW_PED_IN_FORMATION:
+		case OBJECTIVE_LEAVE_VEHICLE:
+		case OBJECTIVE_ENTER_CAR_AS_PASSENGER:
+		case OBJECTIVE_ENTER_CAR_AS_DRIVER:
+		case OBJECTIVE_GOTO_AREA_ON_FOOT:
+		case OBJECTIVE_RUN_TO_AREA:
+			return;
+		default:
+			m_prevObjective = m_objective;
+	}
+}
+
+void
+CPed::RestorePreviousObjective(void)
+{
+	if (m_objective == OBJECTIVE_NONE)
+		return;
+
+	if (m_objective != OBJECTIVE_LEAVE_VEHICLE && m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER)
+		m_pedInObjective = nil;
+
+	if (m_objective == OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT) {
+		m_objective = OBJECTIVE_NONE;
+		if (m_pMyVehicle)
+			SetObjective(OBJECTIVE_LEAVE_VEHICLE, m_pMyVehicle);
+
+	} else {
+		m_objective = m_prevObjective;
+		m_prevObjective = OBJECTIVE_NONE;
+	}
+	m_ped_flagD40 = false;
+}
+
+void
+CPed::SetLeader(CEntity *leader)
+{
+	m_leader = (CPed*)leader;
+
+	if(m_leader)
+		m_leader->RegisterReference((CEntity **)m_leader);
+}
+
+void
+CPed::SetObjective(eObjective newObj, void *entity)
+{
+	if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+		return;
+
+	if (m_prevObjective == newObj) {
+		// Why?
+		if (m_prevObjective != OBJECTIVE_NONE)
+			return;
+	}
+
+	if (entity == this)
+		return;
+
+	SetObjectiveTimer(0);
+	if (m_objective == newObj) {
+		switch (newObj) {
+			case OBJECTIVE_KILL_CHAR_ON_FOOT:
+			case OBJECTIVE_KILL_CHAR_ANY_MEANS:
+			case OBJECTIVE_GOTO_CHAR_ON_FOOT:
+			case OBJECTIVE_FOLLOW_PED_IN_FORMATION:
+			case OBJECTIVE_GOTO_AREA_ANY_MEANS:
+			case OBJECTIVE_FIGHT_CHAR:
+				if (m_pedInObjective == entity)
+					return;
+
+				break;
+			case OBJECTIVE_LEAVE_VEHICLE:
+			case OBJECTIVE_FLEE_CAR:
+				return;
+			case OBJECTIVE_ENTER_CAR_AS_PASSENGER:
+			case OBJECTIVE_ENTER_CAR_AS_DRIVER:
+			case OBJECTIVE_DESTROY_CAR:
+			case OBJECTIVE_SOLICIT:
+			case OBJECTIVE_BUY_ICE_CREAM:
+				if (m_carInObjective == entity)
+					return;
+
+				break;
+			case OBJECTIVE_SET_LEADER:
+				if (m_leader == entity)
+					return;
+
+				break;
+			default:
+				break;
+		}
+	} else {
+		if (newObj == OBJECTIVE_LEAVE_VEHICLE && !bInVehicle)
+			return;
+	}
+
+	m_ped_flagD40 = false;
+	if (!IsTemporaryObjective(m_objective) || IsTemporaryObjective(newObj)) {
+		if (m_objective != newObj) {
+			if (IsTemporaryObjective(newObj))
+				ForceStoredObjective(newObj);
+			else
+				SetStoredObjective();
+		}
+		m_objective = newObj;
+	} else {
+		m_prevObjective = newObj;
+	}
+
+	switch (newObj) {
+		case OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT:
+
+			// In this special case, entity parameter isn't CEntity, but int.
+			SetObjectiveTimer((int)entity);
+			return;
+		case OBJECTIVE_KILL_CHAR_ON_FOOT:
+		case OBJECTIVE_KILL_CHAR_ANY_MEANS:
+		case OBJECTIVE_MUG_CHAR:
+			m_pLastPathNode = nil;
+			m_ped_flagD20 = false;
+			m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+			m_pedInObjective = (CPed*)entity;
+			m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective);
+			m_pLookTarget = (CEntity*)entity;
+			m_pLookTarget->RegisterReference((CEntity**)m_pLookTarget);
+			return;
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE:
+		case OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS:
+		case OBJECTIVE_GOTO_CHAR_ON_FOOT:
+		case OBJECTIVE_FIGHT_CHAR:
+			m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+			m_pedInObjective = (CPed*)entity;
+			m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective);
+			return;
+		case OBJECTIVE_FOLLOW_PED_IN_FORMATION:
+			m_pedInObjective = (CPed*)entity;
+			m_pedInObjective->RegisterReference((CEntity**)m_pedInObjective);
+			m_pedFormation = 1;
+			return;
+		case OBJECTIVE_LEAVE_VEHICLE:
+		case OBJECTIVE_FLEE_CAR:
+			m_carInObjective = (CVehicle*)entity;
+			m_carInObjective->RegisterReference((CEntity **)m_carInObjective);
+			if (!m_carInObjective->bIsBus || m_leaveCarTimer)
+				return;
+			break;
+		case OBJECTIVE_ENTER_CAR_AS_PASSENGER:
+		case OBJECTIVE_ENTER_CAR_AS_DRIVER:
+			if (m_nMoveState == PEDMOVE_STILL)
+				SetMoveState(PEDMOVE_RUN);
+
+			if (((CVehicle*)entity)->m_vehType == VEHICLE_TYPE_BOAT && !IsPlayer()) {
+				RestorePreviousObjective();
+				return;
+			}
+			// fall through
+		case OBJECTIVE_DESTROY_CAR:
+		case OBJECTIVE_SOLICIT:
+		case OBJECTIVE_BUY_ICE_CREAM:
+			m_carInObjective = (CVehicle*)entity;
+			m_carInObjective->RegisterReference((CEntity**)m_carInObjective);
+			m_pSeekTarget = m_carInObjective;
+			m_pSeekTarget->RegisterReference((CEntity**)m_pSeekTarget);
+			m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+			if (newObj == OBJECTIVE_SOLICIT) {
+				m_objectiveTimer = CTimer::GetTimeInMilliseconds() + 10000;
+			} else if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_nCreatedBy == CREATED_BY_SCRIPT &&
+					(m_carInObjective->m_status == STATUS_PLAYER_DISABLED || CPad::GetPad(CWorld::PlayerInFocus)->DisablePlayerControls)) {
+				SetObjectiveTimer(14000);
+			} else {
+				m_objectiveTimer = 0;
+			}
+			return;
+		case OBJECTIVE_SET_LEADER:
+			SetLeader((CEntity*)entity);
+			RestorePreviousObjective();
+			return;
+		default:
+			return;
+	}
+	for (int i=0; i < m_carInObjective->m_nNumMaxPassengers; i++) {
+		if (m_carInObjective->pPassengers[i] == this) {
+			m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 1200 * i;
+			return;
+		}
+	}
+}
+
 WRAPPER void CPed::PedGetupCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE810); }
 WRAPPER void CPed::PedStaggerCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8D0); }
 WRAPPER void CPed::PedEvadeCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D36E0); }
@@ -2084,13 +2581,12 @@ STARTPATCHES
 	InjectHook(0x4D2BB0, &CPed::Avoid, PATCH_JUMP);
 	InjectHook(0x4C6A50, &CPed::ClearAimFlag, PATCH_JUMP);
 	InjectHook(0x4C64F0, &CPed::ClearLookFlag, PATCH_JUMP);
-	InjectHook(0x4E5BD0, &CPed::IsPedHeadAbovePos, PATCH_JUMP);
+	InjectHook(0x4EB670, &CPed::IsPedHeadAbovePos, PATCH_JUMP);
 	InjectHook(0x4E68A0, &CPed::FinishedAttackCB, PATCH_JUMP);
 	InjectHook(0x4E5BD0, &CheckForPedsOnGroundToAttack, PATCH_JUMP);
 	InjectHook(0x4E6BA0, &CPed::Attack, PATCH_JUMP);
 	InjectHook(0x4CF980, &CPed::RemoveWeaponModel, PATCH_JUMP);
 	InjectHook(0x4CFA60, &CPed::SetCurrentWeapon, PATCH_JUMP);
-	InjectHook(0x4DD920, &CPed::SelectGunIfArmed, PATCH_JUMP);
 	InjectHook(0x4E4A10, &CPed::Duck, PATCH_JUMP);
 	InjectHook(0x4E4A30, &CPed::ClearDuck, PATCH_JUMP);
 	InjectHook(0x4E6180, &CPed::ClearPointGunAt, PATCH_JUMP);
@@ -2104,7 +2600,16 @@ STARTPATCHES
 	InjectHook(0x4CC6C0, &CPed::PlayFootSteps, PATCH_JUMP);
 	InjectHook(0x4C5350, &CPed::BuildPedLists, PATCH_JUMP);
 	InjectHook(0x4CF9B0, &CPed::GiveWeapon, PATCH_JUMP);
-	InjectHook(0x4C5330, &CPed::SetPedStats, PATCH_JUMP);
 	InjectHook(0x4C52A0, &CPed::SetModelIndex_, PATCH_JUMP);
 	InjectHook(0x4D6570, &CPed::FlagToDestroyWhenNextProcessed_, PATCH_JUMP);
+	InjectHook(0x4A7D30, &CPed::SetupLighting_, PATCH_JUMP);
+	InjectHook(0x4A7DC0, &CPed::RemoveLighting_, PATCH_JUMP);
+	InjectHook(0x4D3E70, &CPed::Teleport_, PATCH_JUMP);
+	InjectHook(0x4C7EA0, &CPed::CalculateNewOrientation, PATCH_JUMP);
+	InjectHook(0x4C78F0, &CPed::WorkOutHeadingForMovingFirstPerson, PATCH_JUMP);
+	InjectHook(0x4C73F0, &CPed::CalculateNewVelocity, PATCH_JUMP);
+	InjectHook(0x4D72F0, &CPed::CanPedJumpThis, PATCH_JUMP);
+	InjectHook(0x4DD820, &CPed::CanSeeEntity, PATCH_JUMP);
+	InjectHook(0x4D9460, &CPed::RestorePreviousObjective, PATCH_JUMP);
+	InjectHook(0x4D83E0, (void (CPed::*)(eObjective, void*)) &CPed::SetObjective, PATCH_JUMP);
 ENDPATCHES
diff --git a/src/entities/Ped.h b/src/entities/Ped.h
index 92fa32c1..558ec9c1 100644
--- a/src/entities/Ped.h
+++ b/src/entities/Ped.h
@@ -13,6 +13,45 @@
 
 struct CPathNode;
 
+enum eObjective {
+	OBJECTIVE_NONE,
+	OBJECTIVE_IDLE,
+	OBJECTIVE_FLEE_TILL_SAFE,
+	OBJECTIVE_GUARD_SPOT,
+	OBJECTIVE_GUARD_AREA,
+	OBJECTIVE_WAIT_IN_CAR,
+	OBJECTIVE_WAIT_IN_CAR_THEN_GETOUT,
+	OBJECTIVE_KILL_CHAR_ON_FOOT,
+	OBJECTIVE_KILL_CHAR_ANY_MEANS,
+	OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE,
+	OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS,
+	OBJECTIVE_GOTO_CHAR_ON_FOOT,
+	OBJECTIVE_FOLLOW_PED_IN_FORMATION,
+	OBJECTIVE_LEAVE_VEHICLE,
+	OBJECTIVE_ENTER_CAR_AS_PASSENGER,
+	OBJECTIVE_ENTER_CAR_AS_DRIVER,
+	OBJECTIVE_FOLLOW_CAR_IN_CAR,
+	OBJECTIVE_FIRE_AT_OBJ_FROM_VEHICLE,
+	OBJECTIVE_DESTROY_OBJ,
+	OBJECTIVE_DESTROY_CAR,
+	OBJECTIVE_GOTO_AREA_ANY_MEANS,
+	OBJECTIVE_GOTO_AREA_ON_FOOT,
+	OBJECTIVE_RUN_TO_AREA,
+	OBJECTIVE_23,
+	OBJECTIVE_24,
+	OBJECTIVE_FIGHT_CHAR,
+	OBJECTIVE_SET_LEADER,
+	OBJECTIVE_FOLLOW_ROUTE,
+	OBJECTIVE_SOLICIT,
+	OBJECTIVE_HAIL_TAXI,
+	OBJECTIVE_CATCH_TRAIN,
+	OBJECTIVE_BUY_ICE_CREAM,
+	OBJECTIVE_STEAL_ANY_CAR,
+	OBJECTIVE_MUG_CHAR,
+	OBJECTIVE_FLEE_CAR,
+	OBJECTIVE_35
+};
+
 enum {
 	VEHICLE_ENTER_FRONT_RIGHT = 11,
 	VEHICLE_ENTER_REAR_RIGHT = 12,
@@ -20,6 +59,11 @@ enum {
 	VEHICLE_ENTER_REAR_LEFT = 16,
 };
 
+enum {
+	CREATED_BY_RANDOM = 1,
+	CREATED_BY_SCRIPT
+};
+
 enum PedLineUpPhase {
 	LINE_UP_TO_CAR_START,
 	LINE_UP_TO_CAR_END,
@@ -97,7 +141,7 @@ enum PedState
 	PED_ARRESTED = 56,
 };
 
-enum {
+enum eMoveState {
 	PEDMOVE_NONE,
 	PEDMOVE_STILL,
 	PEDMOVE_WALK,
@@ -146,7 +190,7 @@ public:
 	uint8 m_ped_flagD8 : 1;
 	uint8 m_ped_flagD10 : 1;
 	uint8 m_ped_flagD20 : 1;
-	uint8 m_ped_flagD40 : 1;
+	uint8 m_ped_flagD40 : 1;	// reset when objective changes
 	uint8 m_ped_flagD80 : 1;
 
 	uint8 m_ped_flagE1 : 1;
@@ -197,14 +241,14 @@ public:
 	uint8 m_nCreatedBy;
 	uint8 field_161;
 	uint8 pad_162[2];
-	uint32 m_objective;
-	uint32 m_prevObjective;
-	CPed* m_field_16C;
-	uint32 field_170;
+	eObjective m_objective;
+	eObjective m_prevObjective;
+	CPed *m_pedInObjective;
+	CVehicle *m_carInObjective;
 	uint32 field_174;
 	uint32 field_178;
 	uint32 field_17C;
-	uint32 field_180;
+	CPed *m_leader;
 	uint32 m_pedFormation;
 	uint32 m_fearFlags;
 	CEntity *m_threatEntity;
@@ -223,7 +267,7 @@ public:
 	uint32 m_nPedStateTimer;
 	PedState m_nPedState;
 	PedState m_nLastPedState;
-	int32 m_nMoveState;
+	eMoveState m_nMoveState;
 	int32 m_nStoredActionState;
 	int32 m_nPrevActionState;
 	int32 m_nWaitState;
@@ -246,8 +290,7 @@ public:
 	uint16 m_routeType;
 	uint16 m_routeCurDir;
 	uint16 field_2D2;
-	float m_movedX;
-	float m_movedY;
+	CVector2D m_moved;
 	float m_fRotationCur;
 	float m_fRotationDest;
 	float m_headingRate;
@@ -304,7 +347,7 @@ public:
 	uint32 m_attackTimer;
 	uint32 m_lastHitTime;
 	uint32 m_hitRecoverTimer;
-	uint32 field_4E0;
+	uint32 m_objectiveTimer;
 	uint32 m_duckTimer;
 	uint32 field_4E8;
 	int32 m_bloodyFootprintCount;
@@ -345,9 +388,6 @@ public:
 	CPed* ctor(uint32 pedType) { return ::new (this) CPed(pedType); }
 	void dtor(void) { this->CPed::~CPed(); }
 
-	bool IsPlayer(void);
-	bool UseGroundColModel(void);
-	bool CanSetPedState(void);
 	void AddWeaponModel(int id);
 	void AimGun(void);
 	void KillPedWithCar(CVehicle *veh, float impulse);
@@ -369,7 +409,6 @@ public:
 	bool IsPedHeadAbovePos(float zOffset);
 	void RemoveWeaponModel(int modelId);
 	void SetCurrentWeapon(uint32 weaponType);
-	bool SelectGunIfArmed(void);
 	void Duck(void);
 	void ClearDuck(void);
 	void ClearPointGunAt(void);
@@ -379,14 +418,22 @@ public:
 	void SetPedPositionInCar(void);
 	void PlayFootSteps(void);
 	void QuitEnteringCar(void);
-	bool IsPointerValid(void);
-	void SortPeds(CPed**, int, int);
 	void BuildPedLists(void);
 	uint32 GiveWeapon(eWeaponType weaponType, uint32 ammo);
-	void SetPedStats(ePedStats);
+	void CalculateNewOrientation(void);
+	float WorkOutHeadingForMovingFirstPerson(float);
+	void CalculateNewVelocity(void);
+	bool CanPedJumpThis(int32);
+	bool CanSeeEntity(CEntity*, float);
+	void RestorePreviousObjective(void);
+	void SetObjective(eObjective, void*);
+
+	// Static methods
 	static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset);
 	static void GetPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float seatPosMult);
 	static void GetPositionToOpenCarDoor(CVector* output, CVehicle* veh, uint32 enterType);
+
+	// Callbacks
 	static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data);
 	static RwFrame *RecurseFrameChildrenVisibilityCB(RwFrame *frame, void *data);
 	static void PedGetupCB(CAnimBlendAssociation *assoc, void *arg);
@@ -416,6 +463,26 @@ public:
 	static void PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg);
 	static void PedSetDraggedOutCarPositionCB(CAnimBlendAssociation *assoc, void *arg);
 
+	// functions that I see unnecessary to hook
+	bool IsPlayer(void);
+	bool UseGroundColModel(void);
+	bool CanSetPedState(void);
+	bool IsPedInControl(void);
+	bool CanPedDriveOff(void);
+	bool CanBeDeleted(void);
+	bool CanStrafeOrMouseControl(void);
+	bool CanPedReturnToState(void);
+	void SetMoveState(eMoveState);
+	bool IsTemporaryObjective(eObjective objective);
+	void SetObjectiveTimer(int);
+	bool SelectGunIfArmed(void);
+	bool IsPointerValid(void);
+	void SortPeds(CPed**, int, int);
+	void ForceStoredObjective(eObjective);
+	void SetStoredObjective(void);
+	void SetLeader(CEntity* leader);
+	void SetPedStats(ePedStats);
+
 	inline bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; }
 	inline CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }
 	inline CWeapon *GetWeapon(void) { return &m_weapons[m_currentWeapon]; }
@@ -424,6 +491,9 @@ public:
 	// to make patching virtual functions possible
 	void SetModelIndex_(uint32 mi) { CPed::SetModelIndex(mi); }
 	void FlagToDestroyWhenNextProcessed_(void) { CPed::FlagToDestroyWhenNextProcessed(); }
+	bool SetupLighting_(void) { return CPed::SetupLighting(); }
+	void RemoveLighting_(bool reset) { CPed::RemoveLighting(reset); }
+	void Teleport_(CVector pos) { CPed::Teleport(pos); }
 
 	// set by 0482:set_threat_reaction_range_multiplier opcode
 	static uint16 &distanceMultToCountPedNear;
@@ -447,6 +517,6 @@ static_assert(offsetof(CPed, m_weapons) == 0x35C, "CPed: error");
 static_assert(offsetof(CPed, m_currentWeapon) == 0x498, "CPed: error");
 static_assert(offsetof(CPed, m_lookTimer) == 0x4CC, "CPed: error");
 static_assert(offsetof(CPed, m_bodyPartBleeding) == 0x4F2, "CPed: error");
-static_assert(offsetof(CPed, m_field_16C) == 0x16C, "CPed: error");
+static_assert(offsetof(CPed, m_pedInObjective) == 0x16C, "CPed: error");
 static_assert(offsetof(CPed, m_pEventEntity) == 0x19C, "CPed: error");
 static_assert(sizeof(CPed) == 0x53C, "CPed: error");
diff --git a/src/entities/PedIK.cpp b/src/entities/PedIK.cpp
index fa773bbf..b9baf49c 100644
--- a/src/entities/PedIK.cpp
+++ b/src/entities/PedIK.cpp
@@ -5,6 +5,8 @@
 
 WRAPPER bool CPedIK::PointGunInDirection(float phi, float theta) { EAXJMP(0x4ED9B0); }
 WRAPPER bool CPedIK::PointGunAtPosition(CVector *position) { EAXJMP(0x4ED920); }
+WRAPPER void CPedIK::ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED2C0); }
+WRAPPER void CPedIK::ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*) { EAXJMP(0x4ED140); }
 
 CPedIK::CPedIK(CPed *ped)
 {
@@ -20,6 +22,59 @@ CPedIK::CPedIK(CPed *ped)
 	m_lowerArmOrient.theta = 0.0f;
 }
 
+void
+CPedIK::RotateTorso(AnimBlendFrameData *animBlend, LimbOrientation *limb, bool changeRoll)
+{
+	RwFrame *f = animBlend->frame;
+	RwMatrix *mat = CPedIK::GetWorldMatrix(RwFrameGetParent(f), RwMatrixCreate());
+
+	RwV3d upVector = { mat->right.z, mat->up.z, mat->at.z };
+	RwV3d rightVector;
+	RwV3d pos = RwFrameGetMatrix(f)->pos;
+
+	// rotation == 0 -> looking in y direction
+	// left? vector
+	float c = cos(m_ped->m_fRotationCur);
+	float s = sin(m_ped->m_fRotationCur);
+	rightVector.x = -(c*mat->right.x + s*mat->right.y);
+	rightVector.y = -(c*mat->up.x + s*mat->up.y);
+	rightVector.z = -(c*mat->at.x + s*mat->at.y);
+
+	if(changeRoll){
+		// Used when aiming only involves over the legs.(canAimWithArm)
+		// Automatically changes roll(forward rotation) axis of the parts above upper legs while moving, based on position of upper legs.
+		// Not noticeable in normal conditions...
+
+		RwV3d forwardVector;
+		CVector inversedForward = CrossProduct(CVector(0.0f, 0.0f, 1.0f), mat->up);
+		inversedForward.Normalise();
+		float dotProduct = DotProduct(mat->at, inversedForward);
+		if(dotProduct > 1.0f) dotProduct = 1.0f;
+		if(dotProduct < -1.0f) dotProduct = -1.0f;
+		float alpha = acos(dotProduct);
+
+		if(mat->at.z < 0.0f)
+			alpha = -alpha;
+
+		forwardVector.x = s * mat->right.x - c * mat->right.y;
+		forwardVector.y = s * mat->up.x - c * mat->up.y;
+		forwardVector.z = s * mat->at.x - c * mat->at.y;
+
+		float curYaw, curPitch;
+		CPedIK::ExtractYawAndPitchWorld(mat, &curYaw, &curPitch);
+		RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT);
+		RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi - (curYaw - m_ped->m_fRotationCur)), rwCOMBINEPOSTCONCAT);
+		RwMatrixRotate(RwFrameGetMatrix(f), &forwardVector, RADTODEG(alpha), rwCOMBINEPOSTCONCAT);
+	}else{
+		// pitch
+		RwMatrixRotate(RwFrameGetMatrix(f), &rightVector, RADTODEG(limb->theta), rwCOMBINEPOSTCONCAT);
+		// yaw
+		RwMatrixRotate(RwFrameGetMatrix(f), &upVector, RADTODEG(limb->phi), rwCOMBINEPOSTCONCAT);
+	}
+	RwFrameGetMatrix(f)->pos = pos;
+	RwMatrixDestroy(mat);
+}
+
 void
 CPedIK::GetComponentPosition(RwV3d *pos, PedNode node)
 {
@@ -50,4 +105,5 @@ CPedIK::GetWorldMatrix(RwFrame *source, RwMatrix *destination)
 STARTPATCHES
 	InjectHook(0x4ED0F0, &CPedIK::GetComponentPosition, PATCH_JUMP);
 	InjectHook(0x4ED060, &CPedIK::GetWorldMatrix, PATCH_JUMP);
+	InjectHook(0x4EDDB0, &CPedIK::RotateTorso, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/entities/PedIK.h b/src/entities/PedIK.h
index 7c798dc2..e17d52eb 100644
--- a/src/entities/PedIK.h
+++ b/src/entities/PedIK.h
@@ -1,6 +1,7 @@
 #pragma once
 #include "common.h"
 #include "PedModelInfo.h"
+#include "AnimBlendClumpData.h"
 
 struct LimbOrientation
 {
@@ -32,5 +33,8 @@ public:
 	bool PointGunAtPosition(CVector *position);
 	void GetComponentPosition(RwV3d *pos, PedNode node);
 	static RwMatrix *GetWorldMatrix(RwFrame *source, RwMatrix *destination);
+	void RotateTorso(AnimBlendFrameData* animBlend, LimbOrientation* limb, bool changeRoll);
+	void ExtractYawAndPitchLocal(RwMatrixTag*, float*, float*);
+	void ExtractYawAndPitchWorld(RwMatrixTag*, float*, float*);
 };
 static_assert(sizeof(CPedIK) == 0x28, "CPedIK: error");
diff --git a/src/entities/PlayerPed.h b/src/entities/PlayerPed.h
index d09deb49..15ad74a6 100644
--- a/src/entities/PlayerPed.h
+++ b/src/entities/PlayerPed.h
@@ -36,7 +36,7 @@ public:
 	int8 field_1415;
 	CVector field_1416[6];
 	int32 field_1488[6];
-	float field_1512;
+	float m_fWalkAngle;
 	float m_fFPSMoveHeading;
 
 	~CPlayerPed();
diff --git a/src/modelinfo/PedModelInfo.h b/src/modelinfo/PedModelInfo.h
index 04d1ba02..7be2c195 100644
--- a/src/modelinfo/PedModelInfo.h
+++ b/src/modelinfo/PedModelInfo.h
@@ -21,9 +21,9 @@ enum PedNode {
 class CPedModelInfo : public CClumpModelInfo
 {
 public:
-	int32 m_animGroup;
-	int32 m_pedType;
-	int32 m_pedStatType;
+	uint32 m_animGroup;
+	uint32 m_pedType;
+	uint32 m_pedStatType;
 	uint32 m_carsCanDrive;
 	CColModel *m_hitColModel;
 	RpAtomic *m_head;
diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp
index 4830c86a..5be18c3c 100644
--- a/src/weapons/WeaponInfo.cpp
+++ b/src/weapons/WeaponInfo.cpp
@@ -137,7 +137,7 @@ CWeaponInfo::LoadWeaponData(void)
 
 		if (strncmp(anim2ToPlay, "null", 4) != 0) {
 			animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, anim2ToPlay);
-			ms_apWeaponInfos[weaponType].m_Anim2ToPlay = static_cast<AnimationId>(animAssoc->animId);
+			ms_apWeaponInfos[weaponType].m_Anim2ToPlay = (AnimationId) animAssoc->animId;
 		}
 
 		CVector vecFireOffset(fireOffsetX, fireOffsetY, fireOffsetZ);
@@ -154,10 +154,10 @@ CWeaponInfo::LoadWeaponData(void)
 		ms_apWeaponInfos[weaponType].m_fSpread = spread;
 		ms_apWeaponInfos[weaponType].m_vecFireOffset = vecFireOffset;
 		ms_apWeaponInfos[weaponType].m_AnimToPlay = animId;
-		ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart * 0.03f;
-		ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd * 0.03f;
-		ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire * 0.03f;
-		ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire * 0.03f;
+		ms_apWeaponInfos[weaponType].m_fAnimLoopStart = animLoopStart / 30.0f;
+		ms_apWeaponInfos[weaponType].m_fAnimLoopEnd = animLoopEnd / 30.0f;
+		ms_apWeaponInfos[weaponType].m_fAnimFrameFire = delayBetweenAnimAndFire / 30.0f;
+		ms_apWeaponInfos[weaponType].m_fAnim2FrameFire = delayBetweenAnim2AndFire / 30.0f;
 		ms_apWeaponInfos[weaponType].m_nModelId = modelId;
 		ms_apWeaponInfos[weaponType].m_bUseGravity = flags;
 		ms_apWeaponInfos[weaponType].m_bSlowsDown = flags >> 1;