From 8102ace7b67dcf8d511a708072f6f032120df949 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?eray=20or=C3=A7unus?= <erayorcunus@gmail.com>
Date: Sun, 28 Jul 2019 20:39:39 +0300
Subject: [PATCH] Peds, mainly audio

---
 src/audio/DMAudio.h |  24 ++--
 src/peds/Ped.cpp    | 323 ++++++++++++++++++++++++++++++++++++++++++--
 src/peds/Ped.h      |  39 +++++-
 3 files changed, 359 insertions(+), 27 deletions(-)

diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 4428c958..907755b9 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -35,18 +35,18 @@ enum eSound : int16
 	SOUND_STEP_END = 30,
 	SOUND_FALL_LAND = 31,
 	SOUND_FALL_COLLAPSE = 32,
-	SOUND_21 = 33,
-	SOUND_22 = 34,
-	SOUND_23 = 35,
-	SOUND_24 = 36,
-	SOUND_25 = 37,
-	SOUND_26 = 38,
-	SOUND_WEAPON_PUNCH_ATTACK = 39,
-	SOUND_28 = 40,
-	SOUND_29 = 41,
-	SOUND_2A = 42,
-	SOUND_2B = 43,
-	SOUND_2C = 44,
+	SOUND_FIGHT_PUNCH_33 = 33,
+	SOUND_FIGHT_KICK_34 = 34,
+	SOUND_FIGHT_HEADBUTT_35 = 35,
+	SOUND_FIGHT_PUNCH_36 = 36,
+	SOUND_FIGHT_PUNCH_37 = 37,
+	SOUND_FIGHT_CLOSE_PUNCH_38 = 38,
+	SOUND_FIGHT_PUNCH_39 = 39,
+	SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 = 40,
+	SOUND_FIGHT_PUNCH_41 = 41,
+	SOUND_FIGHT_PUNCH_FROM_BEHIND_42 = 42,
+	SOUND_FIGHT_KNEE_OR_KICK_43 = 43,
+	SOUND_FIGHT_KICK_44 = 44,
 	SOUND_2D = 45,
 	SOUND_WEAPON_BAT_ATTACK = 46,
 	SOUND_WEAPON_SHOT_FIRED = 47,
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 1e3b7394..0728777b 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -5,7 +5,6 @@
 #include "Particle.h"
 #include "Stats.h"
 #include "World.h"
-#include "DMAudio.h"
 #include "RpAnimBlend.h"
 #include "Ped.h"
 #include "PlayerPed.h"
@@ -33,7 +32,6 @@
 #include "TempColModels.h"
 
 WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
-WRAPPER void CPed::Say(uint16 audio) { EAXJMP(0x4E5A10); }
 WRAPPER void CPed::SetDead(void) { EAXJMP(0x4D3970); }
 WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
 WRAPPER void CPed::SetPedPositionInCar(void) { EAXJMP(0x4D4970); }
@@ -50,14 +48,16 @@ WRAPPER void CPed::SetSeek(CVector, float) { EAXJMP(0x4D14B0); }
 WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); }
 WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); }
 WRAPPER void CPed::RemoveInCarAnims(void) { EAXJMP(0x4E4E20); }
-WRAPPER void CPed::SetWaitState(eWaitState, void*) { EAXJMP(0x4D58D0); }
 WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); }
-WRAPPER void CPed::PlayHitSound(CPed*) { EAXJMP(0x4E8E20); }
 
 bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
 bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
 bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
+
 CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14;
+
+CPedAudioData (&CPed::PedAudioData)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4;
+
 uint16 &CPed::unknownFightThing = *(uint16*)0x95CC58;
 FightMove (&CPed::ms_fightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
 
@@ -287,10 +287,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
 	m_fHealth = 100.0f;
 	m_fArmour = 0.0f;
 	m_nPedType = pedType;
-	field_520 = 0;
+	m_currentSoundStart = 0;
 	m_talkTimer = 0;
-	m_talkTypeLast = 167;
-	m_talkType = 167;
+	m_lastQueuedSound = SOUND_TOTAL_PED_SOUNDS;
+	m_queuedSound = SOUND_TOTAL_PED_SOUNDS;
 	m_objective = OBJECTIVE_NONE;
 	m_prevObjective = OBJECTIVE_NONE;
 	CharCreatedBy = RANDOM_CHAR;
@@ -401,7 +401,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
 	m_ped_flagD4 = false;
 	m_ped_flagD8 = false;
 	bIsPedDieAnimPlaying = false;
-	m_ped_flagD20 = false;
+	bIsFleeing = false;
 	m_ped_flagD40 = false;
 	bScriptObjectiveCompleted = false;
 
@@ -1137,7 +1137,7 @@ CPed::Attack(void)
 			if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) {
 				DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f);
 			} else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) {
-				DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f);
+				DMAudio.PlayOneShot(m_audioEntityId, SOUND_FIGHT_PUNCH_39, 0.0f);
 			}
 
 			weaponAnimAssoc->speed = 0.5f;
@@ -2471,7 +2471,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
 		case OBJECTIVE_KILL_CHAR_ANY_MEANS:
 		case OBJECTIVE_MUG_CHAR:
 			m_pLastPathNode = nil;
-			m_ped_flagD20 = false;
+			bIsFleeing = false;
 			m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
 			m_pedInObjective = (CPed*)entity;
 			m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
@@ -3659,7 +3659,7 @@ void
 CPed::ClearFlee(void)
 {
 	RestorePreviousState();
-	m_ped_flagD20 = false;
+	bIsFleeing = false;
 	m_standardTimer = 0;
 	m_fleeTimer = 0;
 }
@@ -4748,6 +4748,302 @@ CPed::SetFall(int extraTime, AnimationId animId, uint8 evenIfNotInControl)
 	bIsFell = true;
 }
 
+void
+CPed::SetFlee(CEntity* fleeFrom, int time)
+{
+	if (!IsPedInControl() || bKindaStayInSamePlace || !fleeFrom)
+		return;
+
+	SetStoredState();
+	m_nPedState = PED_FLEE_ENTITY;
+	bIsFleeing = true;
+	SetMoveState(PEDMOVE_RUN);
+	m_fleeFrom = fleeFrom;
+	m_fleeFrom->RegisterReference((CEntity **) &m_fleeFrom);
+
+	if (time <= 0)
+		m_fleeTimer = 0;
+	else
+		m_fleeTimer = CTimer::GetTimeInMilliseconds() + time;
+
+	float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+			GetPosition().x, GetPosition().y,
+			fleeFrom->GetPosition().x, fleeFrom->GetPosition().y);
+
+	m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace);
+	if (m_fRotationCur - PI > m_fRotationDest) {
+		m_fRotationDest += 2 * PI;
+	} else if (PI + m_fRotationCur < m_fRotationDest) {
+		m_fRotationDest -= 2 * PI;
+	}
+}
+
+void
+CPed::SetFlee(CVector2D &from, int time)
+{
+	if (CTimer::GetTimeInMilliseconds() < m_nPedStateTimer || !IsPedInControl() || bKindaStayInSamePlace)
+		return;
+
+	if (m_nPedState != PED_FLEE_ENTITY) {
+		SetStoredState();
+		m_nPedState = PED_FLEE_POS;
+		SetMoveState(PEDMOVE_RUN);
+		m_fleeFromPosX = from.x;
+		m_fleeFromPosY = from.y;
+	}
+
+	bIsFleeing = true;
+	m_pLastPathNode = nil;
+	m_fleeTimer = CTimer::GetTimeInMilliseconds() + time;
+
+	float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+		GetPosition().x, GetPosition().y,
+		from.x, from.y);
+
+	m_fRotationDest = CGeneral::LimitRadianAngle(angleToFace);
+	if (m_fRotationCur - PI > m_fRotationDest) {
+		m_fRotationDest += 2 * PI;
+	} else if (PI + m_fRotationCur < m_fRotationDest) {
+		m_fRotationDest -= 2 * PI;
+	}
+}
+
+void
+CPed::SetWaitState(eWaitState state, void *time)
+{
+	AnimationId waitAnim = NUM_ANIMS;
+	CAnimBlendAssociation *animAssoc;
+
+	if (!IsPedInControl())
+		return;
+
+	if (state != m_nWaitState)
+		FinishedWaitCB(nil, this);
+
+	switch (state) {
+		case WAITSTATE_TRAFFIC_LIGHTS:
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500;
+			SetMoveState(PEDMOVE_STILL);
+			break;
+		case WAITSTATE_CROSS_ROAD:
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 1000;
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+			break;
+		case WAITSTATE_CROSS_ROAD_LOOK:
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_ROAD_CROSS, 8.0f);
+
+			if (time)
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+			else
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(2000,5000);
+
+			break;
+		case WAITSTATE_LOOK_PED:
+		case WAITSTATE_LOOK_SHOP:
+		case WAITSTATE_LOOK_ACCIDENT:
+		case WAITSTATE_FACEOFF_GANG:
+			break;
+		case WAITSTATE_DOUBLEBACK:
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3500;
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+			break;
+		case WAITSTATE_HITWALL:
+			m_headingRate = 2.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+			animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 16.0f);
+			animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+			animAssoc->flags |= ASSOC_FADEOUTWHENDONE;
+			animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+
+			if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
+				ClearObjective();
+				RestorePreviousState();
+			}
+			break;
+		case WAITSTATE_TURN180:
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+			animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_TURN_180, 3000.0f);
+			animAssoc->SetFinishCallback(FinishedWaitCB, this);
+			animAssoc->SetDeleteCallback(RestoreHeadingRateCB, this);
+			break;
+		case WAITSTATE_SURPRISE:
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000;
+			animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_HIT_WALL, 3000.0f);
+			animAssoc->SetFinishCallback(FinishedWaitCB, this);
+			break;
+		case WAITSTATE_STUCK:
+			SetMoveState(PEDMOVE_STILL);
+			SetMoveAnim();
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f);
+
+			if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
+				ClearObjective();
+				RestorePreviousState();
+			}
+			break;
+		case WAITSTATE_LOOK_ABOUT:
+			SetMoveState(PEDMOVE_STILL);
+			SetMoveAnim();
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_HBHB, 3000.0f);
+			break;
+		case WAITSTATE_PLAYANIM_COWER:
+			waitAnim = ANIM_HANDSCOWER;
+		case WAITSTATE_PLAYANIM_HANDSUP:
+			if (waitAnim == NUM_ANIMS)
+				waitAnim = ANIM_HANDSUP;
+		case WAITSTATE_PLAYANIM_HANDSCOWER:
+			if (waitAnim == NUM_ANIMS)
+				waitAnim = ANIM_HANDSCOWER;
+			m_headingRate = 0.0f;
+			if (time)
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+			else
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000;
+
+			animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f);
+			animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+			break;
+		case WAITSTATE_PLAYANIM_DUCK:
+			waitAnim = ANIM_DUCK_DOWN;
+		case WAITSTATE_PLAYANIM_TAXI:
+			if (waitAnim == NUM_ANIMS)
+				waitAnim = ANIM_IDLE_TAXI;
+		case WAITSTATE_PLAYANIM_CHAT:
+			if (waitAnim == NUM_ANIMS)
+				waitAnim = ANIM_IDLE_CHAT;
+			if (time)
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + *(int*)time;
+			else
+				m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 3000;
+
+			animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, waitAnim, 3000.0f);
+			animAssoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+			animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+			animAssoc->SetDeleteCallback(FinishedWaitCB, this);
+			break;
+		case WAITSTATE_FINISH_FLEE:
+			SetMoveState(PEDMOVE_STILL);
+			SetMoveAnim();
+			m_headingRate = 0.0f;
+			m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2500;
+			CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_TIRED, 3000.0f);
+			break;
+		default:
+			m_nWaitState = WAITSTATE_FALSE;
+			RestoreHeadingRate();
+			return;
+	}
+	m_nWaitState = state;
+}
+
+
+void
+CPed::PlayHitSound(CPed *hitTo)
+{
+	// That was very complicated to reverse for me...
+	// First index is our fight move ID (from 1 to 12, total 12), second is the one of we fight with (from 13 to 22, total 10).
+
+	uint16 hitSoundsByFightMoves[12][10] = {
+		{S39,S42,S43,S43,S39,S39,S39,S39,S39,S42},
+		{NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND},
+		{NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND,NO_SND},
+		{S39,S39,S39,S39,S33,S43,S39,S39,S39,S39},
+		{S39,S39,S39,S39,S35,S39,S38,S38,S39,S39},
+		{S39,S39,S39,S39,S33,S39,S41,S36,S39,S39},
+		{S39,S39,S39,S39,S37,S40,S38,S38,S39,S39},
+		{S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
+		{S39,S39,S39,S39,S34,S43,S44,S37,S39,S39},
+		{S39,S39,S39,S39,S34,S43,S44,S37,S39,S40},
+		{S39,S39,S39,S39,S33,S39,S41,S37,S39,S40},
+		{S39,S39,S39,S39,S39,S39,S39,S39,S33,S33}
+	};
+
+	// This is why first dimension is between FightMove 1 and 12.
+	if (m_lastFightMove == FIGHTMOVE_NULL || m_lastFightMove >= FIGHTMOVE_HITFRONT)
+		return;
+
+	uint16 soundId;
+
+	// And this is why second dimension is between 13 and 22.
+	if (hitTo->m_lastFightMove <= FIGHTMOVE_GROUNDKICK || hitTo->m_lastFightMove >= FIGHTMOVE_IDLE2NORM) {
+
+		if (hitTo->m_nPedState == PED_DEAD || hitTo->UseGroundColModel()) {	
+			soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITONFLOOR - FIGHTMOVE_HITFRONT];
+		} else {
+			soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][FIGHTMOVE_HITFRONT - FIGHTMOVE_HITFRONT];
+		}
+	} else {
+		soundId = hitSoundsByFightMoves[m_lastFightMove - FIGHTMOVE_STDPUNCH][hitTo->m_lastFightMove - FIGHTMOVE_HITFRONT];
+	}
+
+	if (soundId != NO_SND)
+		DMAudio.PlayOneShot(m_audioEntityId, soundId, 0.0f);
+}
+
+void
+CPed::Say(uint16 audio)
+{
+	uint16 audioToPlay = audio;
+
+	if (IsPlayer()) {
+		switch (audio) {
+			case SOUND_PED_DEATH:
+				audioToPlay = SOUND_PED_DAMAGE;
+				break;
+			case SOUND_PED_DAMAGE:
+			case SOUND_PED_HIT:
+			case SOUND_PED_LAND:
+				break;
+			case SOUND_PED_BULLET_HIT:
+			case SOUND_PED_CAR_JACKED:
+			case SOUND_PED_DEFEND:
+				audioToPlay = SOUND_PED_HIT;
+				break;
+			default:
+				return;
+		}
+	} else {
+		if (3.0f + TheCamera.GetPosition().z < GetPosition().z)
+			return;
+
+		if (TheCamera.m_CameraAverageSpeed > 1.65f) {
+			return;
+		} else if (TheCamera.m_CameraAverageSpeed > 1.25f) {
+			if (audio != SOUND_PED_DEATH && audio != SOUND_PED_TAXI_WAIT && audio != SOUND_PED_EVADE)
+				return;
+
+		} else if (TheCamera.m_CameraAverageSpeed > 0.9f) {
+			switch (audio) {
+				case SOUND_PED_DEATH:
+				case SOUND_PED_BURNING:
+				case SOUND_PED_FLEE_SPRINT:
+				case SOUND_PED_TAXI_WAIT:
+				case SOUND_PED_EVADE:
+				case SOUND_PED_CAR_COLLISION:
+					break;
+				default:
+					return;
+			}
+		}
+	}
+
+	if (audioToPlay < m_queuedSound) {
+		if (audioToPlay != m_lastQueuedSound || audioToPlay == SOUND_PED_DEATH
+			|| PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime
+				+ m_currentSoundStart
+				+ (uint32) CGeneral::GetRandomNumberInRange(0, PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) {
+			m_queuedSound = audioToPlay;
+		}
+	}
+}
+
 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); }
@@ -4884,4 +5180,9 @@ STARTPATCHES
 	InjectHook(0x4E9870, &CPed::LoadFightData, PATCH_JUMP);
 	InjectHook(0x4E8EC0, &CPed::FightStrike, PATCH_JUMP);
 	InjectHook(0x4CCE20, &CPed::GetLocalDirection, PATCH_JUMP);
+	InjectHook(0x4E8E20, &CPed::PlayHitSound, PATCH_JUMP);
+	InjectHook(0x4E5A10, &CPed::Say, PATCH_JUMP);
+	InjectHook(0x4D58D0, &CPed::SetWaitState, PATCH_JUMP);
+	InjectHook(0x4D1D70, (void (CPed::*)(CEntity*, int)) &CPed::SetFlee, PATCH_JUMP);
+	InjectHook(0x4D1D70, (void (CPed::*)(CVector2D&, int)) &CPed::SetFlee, PATCH_JUMP);
 ENDPATCHES
\ No newline at end of file
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index be7442b0..c526d023 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -10,9 +10,35 @@
 #include "AnimBlendAssociation.h"
 #include "WeaponInfo.h"
 #include "Fire.h"
+#include "DMAudio.h"
 
 struct CPathNode;
 
+struct CPedAudioData
+{
+	int m_nFixedDelayTime;
+	int m_nOverrideFixedDelayTime;
+	int m_nOverrideMaxRandomDelayTime;
+	int m_nMaxRandomDelayTime;
+};
+
+// For hit sounds in fight
+enum {
+	S33 = SOUND_FIGHT_PUNCH_33,
+	S34 = SOUND_FIGHT_KICK_34,
+	S35 = SOUND_FIGHT_HEADBUTT_35,
+	S36 = SOUND_FIGHT_PUNCH_36,
+	S37 = SOUND_FIGHT_PUNCH_37,
+	S38 = SOUND_FIGHT_CLOSE_PUNCH_38,
+	S39 = SOUND_FIGHT_PUNCH_39,
+	S40 = SOUND_FIGHT_PUNCH_OR_KICK_BELOW_40 ,
+	S41 = SOUND_FIGHT_PUNCH_41,
+	S42 = SOUND_FIGHT_PUNCH_FROM_BEHIND_42,
+	S43 = SOUND_FIGHT_KNEE_OR_KICK_43,
+	S44 = SOUND_FIGHT_KICK_44,
+	NO_SND = SOUND_TOTAL_PED_SOUNDS
+};
+
 struct FightMove
 {
 	AnimationId animId;
@@ -29,6 +55,7 @@ static_assert(sizeof(FightMove) == 0x18, "FightMove: error");
 enum PedFightMoves
 {
 	FIGHTMOVE_NULL,
+	// Attacker
 	FIGHTMOVE_STDPUNCH,
 	FIGHTMOVE_IDLE,
 	FIGHTMOVE_SHUFFLE_F,
@@ -41,6 +68,7 @@ enum PedFightMoves
 	FIGHTMOVE_ROUNDHOUSE,
 	FIGHTMOVE_BODYBLOW,
 	FIGHTMOVE_GROUNDKICK,
+	// Opponent
 	FIGHTMOVE_HITFRONT,
 	FIGHTMOVE_HITBACK,
 	FIGHTMOVE_HITRIGHT,
@@ -260,7 +288,7 @@ public:
 	uint8 m_ped_flagD4 : 1;
 	uint8 m_ped_flagD8 : 1;
 	uint8 bIsPedDieAnimPlaying : 1;
-	uint8 m_ped_flagD20 : 1;
+	uint8 bIsFleeing : 1;
 	uint8 m_ped_flagD40 : 1;	// reset when objective changes
 	uint8 bScriptObjectiveCompleted : 1;
 
@@ -431,11 +459,11 @@ public:
 	uint16 m_numNearPeds;
 	int8 m_lastWepDam;
 	uint8 pad_51F;
-	uint8 field_520;
+	uint8 m_currentSoundStart;
 	uint8 pad_521[3];
 	uint32 m_talkTimer;
-	uint16 m_talkTypeLast;
-	uint16 m_talkType;
+	uint16 m_lastQueuedSound;
+	uint16 m_queuedSound;
 	CVector m_vecSeekPosEx;
 	float m_seekExAngle;
 
@@ -556,6 +584,8 @@ public:
 	void StartFightDefend(uint8, uint8, uint8);
 	void PlayHitSound(CPed*);
 	void SetFall(int, AnimationId, uint8);
+	void SetFlee(CEntity*, int);
+	void SetFlee(CVector2D&, int);
 
 	// Static methods
 	static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset);
@@ -633,6 +663,7 @@ public:
 	static CColPoint &ms_tempColPoint;
 	static uint16 &unknownFightThing; // TODO
 	static FightMove (&ms_fightMoves)[24];
+	static CPedAudioData (&PedAudioData)[38];
 };
 
 void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);