summaryrefslogtreecommitdiffstats
path: root/src/peds
diff options
context:
space:
mode:
Diffstat (limited to 'src/peds')
-rw-r--r--src/peds/Ped.cpp2262
-rw-r--r--src/peds/Ped.h92
-rw-r--r--src/peds/PedRoutes.cpp6
-rw-r--r--src/peds/PedRoutes.h7
4 files changed, 2207 insertions, 160 deletions
diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp
index 077cb89d..d0ceedff 100644
--- a/src/peds/Ped.cpp
+++ b/src/peds/Ped.cpp
@@ -31,6 +31,9 @@
#include "FileMgr.h"
#include "TempColModels.h"
#include "Pickups.h"
+#include "Train.h"
+#include "TrafficLights.h"
+#include "PedRoutes.h"
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
WRAPPER void CPed::SpawnFlyingComponent(int, int8) { EAXJMP(0x4EB060); }
@@ -43,31 +46,44 @@ WRAPPER void CPed::SetMoveAnim(void) { EAXJMP(0x4C5A40); }
WRAPPER void CPed::SetFollowRoute(int16, int16) { EAXJMP(0x4DD690); }
WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); }
WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); }
-WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); }
WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); }
WRAPPER void CPed::RemoveInCarAnims(void) { EAXJMP(0x4E4E20); }
WRAPPER void CPed::StartFightDefend(uint8, uint8, uint8) { EAXJMP(0x4E7780); }
WRAPPER void CPed::SetDirectionToWalkAroundObject(CEntity*) { EAXJMP(0x4CCEB0); }
WRAPPER void CPed::SetRadioStation(void) { EAXJMP(0x4D7BC0); }
WRAPPER void CPed::MakeTyresMuddySectorList(CPtrList&) { EAXJMP(0x53CFD0); }
+WRAPPER void CPed::ProcessObjective(void) { EAXJMP(0x4D94E0); }
+
+CPed *gapTempPedList[50];
+uint16 gnNumTempPedList;
bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44;
bool &CPed::bPedCheat2 = *(bool*)0x95CD5A;
bool &CPed::bPedCheat3 = *(bool*)0x95CD59;
-CColPoint &CPed::ms_tempColPoint = *(CColPoint*)0x62DB14;
+CColPoint &aTempPedColPts = *(CColPoint*)0x62DB14;
+
+// TODO: CommentWaitTime should be hardcoded into exe, and it isn't reversed yet.
+CPedAudioData (&CPed::CommentWaitTime)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4;
-// TODO: PedAudioData should be hardcoded into exe, and it isn't reversed yet.
-CPedAudioData (&CPed::PedAudioData)[38] = *(CPedAudioData(*)[38]) * (uintptr*)0x5F94C4;
+uint16 nPlayerInComboMove;
-uint16 &CPed::unknownFightThing = *(uint16*)0x95CC58;
-FightMove (&CPed::ms_fightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
+FightMove (&tFightMoves)[24] = * (FightMove(*)[24]) * (uintptr*)0x5F9844;
-uint16 &CPed::distanceMultToCountPedNear = *(uint16*)0x5F8C98;
+uint16 &CPed::nThreatReactionRangeMultiplier = *(uint16*)0x5F8C98;
-CVector &CPed::offsetToOpenRegularCarDoor = *(CVector*)0x62E030;
-CVector &CPed::offsetToOpenLowCarDoor = *(CVector*)0x62E03C;
-CVector &CPed::offsetToOpenVanDoor = *(CVector*)0x62E048;
+CVector vecPedCarDoorAnimOffset;
+CVector vecPedCarDoorLoAnimOffset;
+CVector vecPedVanRearDoorAnimOffset;
+CVector &vecPedQuickDraggedOutCarAnimOffset = *(CVector*)0x62E06C;
+CVector &vecPedDraggedOutCarAnimOffset = *(CVector*)0x62E060;
+CVector &vecPedTrainDoorAnimOffset = *(CVector*)0x62E054;
+
+CVector2D &CPed::ms_vec2DFleePosition = *(CVector2D*)0x6EDF70;
+
+#ifndef FINAL
+bool CPed::bUnusedFightThingOnPlayer = false;
+#endif
void *CPed::operator new(size_t sz) { return CPools::GetPedPool()->New(); }
void *CPed::operator new(size_t sz, int handle) { return CPools::GetPedPool()->New(handle); }
@@ -283,7 +299,6 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_type = ENTITY_TYPE_PED;
bPedPhysics = true;
bUseCollisionRecords = true;
-// m_status = STATUS_SIMPLE;
m_vecAnimMoveDelta.x = 0.0f;
m_vecAnimMoveDelta.y = 0.0f;
@@ -307,7 +322,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_vecOffsetSeek.y = 0.0f;
m_vecOffsetSeek.z = 0.0f;
m_pedFormation = 0;
- m_lastThreatTimer = 0;
+ m_collidingThingTimer = 0;
m_nPedStateTimer = 0;
m_actionX = 0;
m_actionY = 0;
@@ -331,9 +346,9 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_pCurrentPhysSurface = nil;
m_vecOffsetFromPhysSurface = CVector(0.0f, 0.0f, 0.0f);
m_pSeekTarget = nil;
- m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+ m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f);
m_wepSkills = 0;
- field_318 = 1.0f;
+ m_distanceToCountSeekDone = 1.0f;
bRunningToPhone = false;
m_phoneId = -1;
m_lastAccident = 0;
@@ -359,11 +374,11 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
m_nPathNodes = 0;
m_nCurPathNode = 0;
m_nPathState = 0;
- m_pNextPathNode = nil;
m_pLastPathNode = nil;
+ m_pNextPathNode = nil;
m_routeLastPoint = -1;
- m_routePoints = 0;
- m_routePos = 0;
+ m_routeStartPoint = 0;
+ m_routePointsPassed = 0;
m_routeType = 0;
m_bodyPartBleeding = -1;
@@ -374,7 +389,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bIsStanding = false;
m_ped_flagA2 = false;
- m_ped_flagA4 = false;
+ bIsAttacking = false;
bIsPointingGunAt = false;
bIsLooking = false;
m_ped_flagA20 = false;
@@ -386,7 +401,7 @@ CPed::CPed(uint32 pedType) : m_pedIK(this)
bIsTalking = false;
bIsInTheAir = false;
bIsLanding = false;
- m_ped_flagB20 = false;
+ bIsRunning = false;
m_ped_flagB40 = false;
m_ped_flagB80 = false;
@@ -531,7 +546,7 @@ RemoveAllModelCB(RwObject *object, void *data)
}
static PedOnGroundState
-CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
+CheckForPedsOnGroundToAttack(CPed *attacker, CPed **pedOnGround)
{
PedOnGroundState stateToReturn;
float angleToFace;
@@ -549,22 +564,22 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
if (!CGame::nastyGame)
return NO_PED;
- for (int currentPedId = 0; currentPedId < player->m_numNearPeds; currentPedId++) {
+ for (int currentPedId = 0; currentPedId < attacker->m_numNearPeds; currentPedId++) {
- currentPed = player->m_nearPeds[currentPedId];
+ currentPed = attacker->m_nearPeds[currentPedId];
- CVector posDifference = currentPed->GetPosition() - player->GetPosition();
+ CVector posDifference = currentPed->GetPosition() - attacker->GetPosition();
distance = posDifference.Magnitude();
if (distance < 2.0f) {
angleToFace = CGeneral::GetRadianAngleBetweenPoints(
currentPed->GetPosition().x, currentPed->GetPosition().y,
- player->GetPosition().x, player->GetPosition().y);
+ attacker->GetPosition().x, attacker->GetPosition().y);
angleToFace = CGeneral::LimitRadianAngle(angleToFace);
- player->m_fRotationCur = CGeneral::LimitRadianAngle(player->m_fRotationCur);
+ attacker->m_fRotationCur = CGeneral::LimitRadianAngle(attacker->m_fRotationCur);
- angleDiff = Abs(angleToFace - player->m_fRotationCur);
+ angleDiff = Abs(angleToFace - attacker->m_fRotationCur);
if (angleDiff > PI)
angleDiff = 2 * PI - angleDiff;
@@ -583,20 +598,21 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
pedOnTheFloor = currentPed;
}
}
- } else if ((distance >= 0.8f || angleDiff >= DEGTORAD(75.0f))
- && (distance >= 1.3f || angleDiff >= DEGTORAD(55.0f))
- && (distance >= 1.7f || angleDiff >= DEGTORAD(35.0f))
- && (distance >= 2.0f || angleDiff >= DEGTORAD(30.0f))) {
+ } else if ((distance < 0.8f && angleDiff < DEGTORAD(75.0f))
+ || (distance < 1.3f && angleDiff < DEGTORAD(55.0f))
+ || (distance < 1.7f && angleDiff < DEGTORAD(35.0f))
+ || (distance < 2.0f && angleDiff < DEGTORAD(30.0f))) {
+ // Either this condition or below one was probably returning 4 early in development. See Fight().
+ foundBelow = 1;
+ pedBelow = currentPed;
+ break;
+ } else {
if (angleDiff < DEGTORAD(75.0f)) {
foundBelow = 1;
if (!pedBelow)
pedBelow = currentPed;
}
- } else {
- foundBelow = 1;
- pedBelow = currentPed;
- break;
}
}
}
@@ -609,7 +625,7 @@ CheckForPedsOnGroundToAttack(CPlayerPed *player, CPed **pedOnGround)
stateToReturn = PED_DEAD_ON_THE_FLOOR;
} else if (foundBelow) {
currentPed = pedBelow;
- stateToReturn = PED_BELOW_PLAYER;
+ stateToReturn = PED_IN_FRONT_OF_ATTACKER;
} else {
currentPed = nil;
stateToReturn = NO_PED;
@@ -992,7 +1008,7 @@ CPed::FinishedAttackCB(CAnimBlendAssociation *attackAssoc, void *arg)
}
}
- if (!ped->m_ped_flagA4)
+ if (!ped->bIsAttacking)
ped->ClearAttack();
}
@@ -1018,7 +1034,7 @@ CPed::Attack(void)
ourWeapon = CWeaponInfo::GetWeaponInfo(ourWeaponType);
ourWeaponFire = ourWeapon->m_eWeaponFire;
weaponAnimAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ourWeapon->m_AnimToPlay);
- lastReloadWasInFuture = m_ped_flagA4;
+ lastReloadWasInFuture = bIsAttacking;
reloadAnimAssoc = nil;
reloadAnim = NUM_ANIMS;
delayBetweenAnimAndFire = ourWeapon->m_fAnimFrameFire;
@@ -1059,7 +1075,7 @@ CPed::Attack(void)
if (!weaponAnimAssoc) {
if (lastReloadWasInFuture) {
if (ourWeaponFire != WEAPON_FIRE_PROJECTILE || !IsPlayer() || ((CPlayerPed*)this)->field_1380) {
- if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
+ if (!CGame::nastyGame || ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
weaponAnimAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ourWeapon->m_AnimToPlay, 8.0f);
}
else {
@@ -1131,7 +1147,7 @@ CPed::Attack(void)
CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, reloadAnim, 8.0f);
ClearLookFlag();
ClearAimFlag();
- m_ped_flagA4 = false;
+ bIsAttacking = false;
bIsPointingGunAt = false;
m_lastHitTime = CTimer::GetTimeInMilliseconds();
return;
@@ -1145,8 +1161,7 @@ CPed::Attack(void)
weaponAnimAssoc->speed = 0.5f;
- // BUG: We currently don't know any situation this cond. could be true.
- if (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
+ if (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_lastHitTime) {
weaponAnimAssoc->callbackType = 0;
}
}
@@ -1187,11 +1202,11 @@ CPed::Attack(void)
if (weaponAnimTime > animLoopEnd || !weaponAnimAssoc->IsRunning() && ourWeaponFire != WEAPON_FIRE_PROJECTILE) {
if (weaponAnimTime - 2.0f * weaponAnimAssoc->timeStep <= animLoopEnd
- && (m_ped_flagA4 || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
+ && (bIsAttacking || CTimer::GetTimeInMilliseconds() < m_lastHitTime)
&& GetWeapon()->m_eWeaponState != WEAPONSTATE_RELOADING) {
weaponAnim = weaponAnimAssoc->animId;
- if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(((CPlayerPed*)this), nil) < PED_ON_THE_FLOOR) {
+ if (ourWeaponFire != WEAPON_FIRE_MELEE || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
if (weaponAnim != ourWeapon->m_Anim2ToPlay || weaponAnim == ANIM_RBLOCK_CSHOOT) {
weaponAnimAssoc->Start(ourWeapon->m_fAnimLoopStart);
} else {
@@ -1234,7 +1249,7 @@ CPed::Attack(void)
if (weaponAnimAssoc->currentTime > delayBetweenAnimAndFire)
lastReloadWasInFuture = false;
- m_ped_flagA4 = lastReloadWasInFuture;
+ bIsAttacking = lastReloadWasInFuture;
}
void
@@ -1470,13 +1485,13 @@ CPed::GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatP
vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(veh->m_modelIndex);
if (veh->bIsVan && (component == CAR_DOOR_LR || component == CAR_DOOR_RR)) {
seatOffset = 0.0f;
- vehDoorOffset = offsetToOpenVanDoor;
+ vehDoorOffset = vecPedVanRearDoorAnimOffset;
} else {
seatOffset = veh->pHandling->fSeatOffsetDistance * seatPosMult;
if (veh->bLowVehicle) {
- vehDoorOffset = offsetToOpenLowCarDoor;
+ vehDoorOffset = vecPedCarDoorLoAnimOffset;
} else {
- vehDoorOffset = offsetToOpenRegularCarDoor;
+ vehDoorOffset = vecPedCarDoorAnimOffset;
}
}
@@ -1537,12 +1552,12 @@ CPed::GetPositionToOpenCarDoor(CVehicle *veh, uint32 component)
CVector localVehDoorOffset;
if (veh->bIsVan && (component == VEHICLE_ENTER_REAR_LEFT || component == VEHICLE_ENTER_REAR_RIGHT)) {
- localVehDoorOffset = offsetToOpenVanDoor;
+ localVehDoorOffset = vecPedVanRearDoorAnimOffset;
} else {
if (veh->bIsLow) {
- localVehDoorOffset = offsetToOpenLowCarDoor;
+ localVehDoorOffset = vecPedCarDoorLoAnimOffset;
} else {
- localVehDoorOffset = offsetToOpenRegularCarDoor;
+ localVehDoorOffset = vecPedCarDoorAnimOffset;
}
}
@@ -1885,7 +1900,7 @@ CPed::PlayFootSteps(void)
CVector2D top(forward * 0.26f);
CVector2D right(GetRight() * 0.14f);
- CShadows::AddPermanentShadow(1, gpBloodPoolTex, &footPos,
+ CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &footPos,
top.x, top.y,
right.x, right.y,
255, 255, 0, 0, 4.0f, 3000.0f, 1.0f);
@@ -1986,9 +2001,6 @@ CPed::SortPeds(CPed **list, int min, int max)
void
CPed::BuildPedLists(void)
{
- static CPed *unsortedNearPeds[10];
- uint16 nextNearPedSlot = 0;
-
if ((CTimer::GetFrameCounter() + (m_randomSeed % 256)) % 16) {
for(int i = 0; i < 10; ) {
@@ -2019,6 +2031,7 @@ CPed::BuildPedLists(void)
(centre.y - 20.0f) * 0.025f + 50.0f,
(centre.x + 20.0f) * 0.025f + 50.0f,
(centre.y + 20.0f) * 0.025f + 50.0f);
+ gnNumTempPedList = 0;
for(int y = rect.top; y <= rect.bottom; y++) {
for(int x = rect.left; x <= rect.right; x++) {
@@ -2026,19 +2039,18 @@ CPed::BuildPedLists(void)
CPed *ped = (CPed*)pedPtrNode->item;
if (ped != this && !ped->bInVehicle) {
float dist = (ped->GetPosition() - GetPosition()).Magnitude2D();
- if (distanceMultToCountPedNear * 30.0f > dist)
- {
- unsortedNearPeds[nextNearPedSlot] = ped;
- nextNearPedSlot++;
+ if (nThreatReactionRangeMultiplier * 30.0f > dist) {
+ gapTempPedList[gnNumTempPedList] = ped;
+ gnNumTempPedList++;
}
}
}
}
}
- unsortedNearPeds[nextNearPedSlot] = nil;
- SortPeds(unsortedNearPeds, 0, nextNearPedSlot - 1);
+ gapTempPedList[gnNumTempPedList] = nil;
+ SortPeds(gapTempPedList, 0, gnNumTempPedList - 1);
for (m_numNearPeds = 0; m_numNearPeds < 10; m_numNearPeds++) {
- CPed *ped = unsortedNearPeds[m_numNearPeds];
+ CPed *ped = gapTempPedList[m_numNearPeds];
if (!ped)
break;
@@ -2482,9 +2494,9 @@ CPed::SetObjective(eObjective newObj, void *entity)
case OBJECTIVE_KILL_CHAR_ON_FOOT:
case OBJECTIVE_KILL_CHAR_ANY_MEANS:
case OBJECTIVE_MUG_CHAR:
- m_pLastPathNode = nil;
+ m_pNextPathNode = nil;
bIsFleeing = false;
- m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+ m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f);
m_pedInObjective = (CPed*)entity;
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
m_pLookTarget = (CEntity*)entity;
@@ -2494,7 +2506,7 @@ CPed::SetObjective(eObjective newObj, void *entity)
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_vecSeekPos = CVector(0.0f, 0.0f, 0.0f);
m_pedInObjective = (CPed*)entity;
m_pedInObjective->RegisterReference((CEntity**)&m_pedInObjective);
break;
@@ -2535,7 +2547,7 @@ CPed::SetObjective(eObjective newObj, void *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);
+ m_vecSeekPos = 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 && CharCreatedBy == MISSION_CHAR &&
@@ -3124,7 +3136,7 @@ CPed::ClearAll(void)
m_nPedState = PED_NONE;
m_nMoveState = PEDMOVE_NONE;
m_pSeekTarget = nil;
- m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+ m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f);
m_fleeFromPosX = 0.0f;
m_fleeFromPosY = 0.0f;
m_fleeFrom = nil;
@@ -3708,7 +3720,7 @@ CPed::SetGetUp(void)
&& ((CTimer::GetFrameCounter() + m_randomSeed % 256 + 5) % 8
|| CCollision::ProcessColModels(GetMatrix(), *CModelInfo::GetModelInfo(m_modelIndex)->GetColModel(),
collidingVeh->GetMatrix(), *CModelInfo::GetModelInfo(collidingVeh->m_modelIndex)->GetColModel(),
- &ms_tempColPoint, nil, nil) > 0)) {
+ &aTempPedColPts, nil, nil) > 0)) {
bGetUpAnimStarted = false;
if (IsPlayer())
@@ -3849,11 +3861,11 @@ CPed::SetWanderPath(int8 pathStateDest)
if (pathStateDest == 0)
pathStateDest = CGeneral::GetRandomNumberInRange(1, 7);
- ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
+ ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode,
m_nPathState, &nextPathState);
// Circular loop until we find a node for current m_nPathState
- while (!m_pLastPathNode) {
+ while (!m_pNextPathNode) {
m_nPathState = (m_nPathState+1) % 8;
// We're at where we started and couldn't find any node
@@ -3862,7 +3874,7 @@ CPed::SetWanderPath(int8 pathStateDest)
SetIdle();
return false;
}
- ThePaths.FindNextNodeWandering(1, GetPosition(), &m_pNextPathNode, &m_pLastPathNode,
+ ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode,
m_nPathState, &nextPathState);
}
@@ -3870,7 +3882,7 @@ CPed::SetWanderPath(int8 pathStateDest)
m_nPathState = nextPathState;
m_nPedState = PED_WANDER_PATH;
SetMoveState(PEDMOVE_WALK);
- m_ped_flagB20 = false;
+ bIsRunning = false;
return true;
}
} else {
@@ -3955,10 +3967,10 @@ CPed::RestorePreviousState(void)
break;
case PED_WANDER_PATH:
m_nPedState = PED_WANDER_PATH;
- m_ped_flagB20 = false;
+ bIsRunning = false;
if (!m_ped_flagC80) {
- if (m_pLastPathNode) {
- CVector diff = m_pLastPathNode->pos - GetPosition();
+ if (m_pNextPathNode) {
+ CVector diff = m_pNextPathNode->pos - GetPosition();
if (diff.MagnitudeSqr() < 49.0f) {
SetMoveState(PEDMOVE_WALK);
break;
@@ -4058,8 +4070,7 @@ CPed::GrantAmmo(eWeaponType weaponType, uint32 ammo)
{
if (HasWeapon(weaponType)) {
GetWeapon(weaponType).m_nAmmoTotal += ammo;
- }
- else {
+ } else {
GetWeapon(weaponType).Initialise(weaponType, ammo);
m_maxWeaponTypeAllowed++;
}
@@ -4270,15 +4281,15 @@ CPed::SetAttack(CEntity* victim)
return;
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HGUN_RELOAD)) {
- m_ped_flagA4 = false;
+ bIsAttacking = false;
return;
}
if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_AK_RELOAD)) {
if (!IsPlayer() || m_nPedState != PED_ATTACK || ((CPlayerPed*)this)->field_1380)
- m_ped_flagA4 = false;
+ bIsAttacking = false;
else
- m_ped_flagA4 = true;
+ bIsAttacking = true;
return;
}
@@ -4295,7 +4306,7 @@ CPed::SetAttack(CEntity* victim)
if (m_nPedState != PED_ATTACK) {
m_nPedState = PED_ATTACK;
- m_ped_flagA4 = false;
+ bIsAttacking = false;
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, 8.0f);
animAssoc->SetRun();
if (animAssoc->currentTime != animAssoc->hierarchy->totalLength)
@@ -4334,7 +4345,7 @@ CPed::SetAttack(CEntity* victim)
}
}
if (m_nPedState == PED_ATTACK) {
- m_ped_flagA4 = true;
+ bIsAttacking = true;
return;
}
@@ -4370,7 +4381,7 @@ CPed::SetAttack(CEntity* victim)
animDelta = 1000.0f;
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_BASEBALLBAT
- || CheckForPedsOnGroundToAttack((CPlayerPed*)this, nil) < PED_ON_THE_FLOOR) {
+ || CheckForPedsOnGroundToAttack(this, nil) < PED_ON_THE_FLOOR) {
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_AnimToPlay, animDelta);
} else {
animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curWeapon->m_Anim2ToPlay, animDelta);
@@ -4378,7 +4389,7 @@ CPed::SetAttack(CEntity* victim)
}
animAssoc->SetRun();
- if (animAssoc->currentTime != animAssoc->hierarchy->totalLength)
+ if (animAssoc->currentTime == animAssoc->hierarchy->totalLength)
animAssoc->SetCurrentTime(0.0f);
animAssoc->SetFinishCallback(FinishedAttackCB, this);
@@ -4438,7 +4449,7 @@ CPed::StartFightAttack(uint8 buttonPressure)
CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT_IDLE)->blendAmount = 1.0f;
CPed *pedOnGround = nil;
- if (IsPlayer() && CheckForPedsOnGroundToAttack((CPlayerPed*)this, &pedOnGround) > PED_BELOW_PLAYER) {
+ if (IsPlayer() && CheckForPedsOnGroundToAttack(this, &pedOnGround) > PED_IN_FRONT_OF_ATTACKER) {
m_lastFightMove = FIGHTMOVE_GROUNDKICK;
} else if (m_pedStats->m_flags & STAT_SHOPPING_BAGS) {
m_lastFightMove = FIGHTMOVE_ROUNDHOUSE;
@@ -4457,14 +4468,18 @@ CPed::StartFightAttack(uint8 buttonPressure)
SetLookFlag(pedOnGround, 1);
SetLookTimer(1500);
}
- animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ms_fightMoves[m_lastFightMove].animId, 4.0f);
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 4.0f);
animAssoc->SetFinishCallback(FinishFightMoveCB, this);
m_fightUnk2 = 0;
- m_fightUnk1 = 0;
- m_ped_flagA4 = true;
+ m_takeAStepAfterAttack = false;
+#ifndef FINAL
+ m_takeAStepAfterAttack = IsPlayer() && bUnusedFightThingOnPlayer;
+#endif
+
+ bIsAttacking = true;
if (IsPlayer())
- unknownFightThing = 0;
+ nPlayerInComboMove = 0;
}
void
@@ -4513,28 +4528,28 @@ CPed::LoadFightData(void)
if (strncmp(moveName, "ENDWEAPONDATA", 13) == 0)
return;
- ms_fightMoves[moveId].startFireTime = startFireTime / 30.0f;
- ms_fightMoves[moveId].endFireTime = endFireTime / 30.0f;
- ms_fightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f;
- ms_fightMoves[moveId].strikeRadius = strikeRadius;
- ms_fightMoves[moveId].damage = damage;
- ms_fightMoves[moveId].flags = flags;
+ tFightMoves[moveId].startFireTime = startFireTime / 30.0f;
+ tFightMoves[moveId].endFireTime = endFireTime / 30.0f;
+ tFightMoves[moveId].comboFollowOnTime = comboFollowOnTime / 30.0f;
+ tFightMoves[moveId].strikeRadius = strikeRadius;
+ tFightMoves[moveId].damage = damage;
+ tFightMoves[moveId].flags = flags;
switch (hitLevel) {
case 'G':
- ms_fightMoves[moveId].hitLevel = 1;
+ tFightMoves[moveId].hitLevel = 1;
break;
case 'H':
- ms_fightMoves[moveId].hitLevel = 4;
+ tFightMoves[moveId].hitLevel = 4;
break;
case 'L':
- ms_fightMoves[moveId].hitLevel = 2;
+ tFightMoves[moveId].hitLevel = 2;
break;
case 'M':
- ms_fightMoves[moveId].hitLevel = 3;
+ tFightMoves[moveId].hitLevel = 3;
break;
case 'N':
- ms_fightMoves[moveId].hitLevel = 0;
+ tFightMoves[moveId].hitLevel = 0;
break;
default:
break;
@@ -4542,9 +4557,9 @@ CPed::LoadFightData(void)
if (strncmp(animName, "null", 4) != 0) {
animAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, animName);
- ms_fightMoves[moveId].animId = (AnimationId)animAssoc->animId;
+ tFightMoves[moveId].animId = (AnimationId)animAssoc->animId;
} else {
- ms_fightMoves[moveId].animId = ANIM_WALK;
+ tFightMoves[moveId].animId = ANIM_WALK;
}
moveId++;
}
@@ -4584,9 +4599,9 @@ CPed::FightStrike(CVector &touchedNodePos)
for (int i = 0; i < m_numNearPeds; i++) {
nearPed = m_nearPeds[i];
if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED)
- maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius + 0.1f;
+ maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_lastFightMove].strikeRadius + 0.1f;
else
- maxDistanceToBeBeaten = nearPed->GetBoundRadius() + ms_fightMoves[m_lastFightMove].strikeRadius;
+ maxDistanceToBeBeaten = nearPed->GetBoundRadius() + tFightMoves[m_lastFightMove].strikeRadius;
if (nearPed->bUsesCollision || nearPed->m_nPedState == PED_DEAD) {
CVector nearPedCentre;
@@ -4605,7 +4620,7 @@ CPed::FightStrike(CVector &touchedNodePos)
attackDistance = nearPed->GetPosition() + ourCol->spheres[j].center;
attackDistance -= touchedNodePos;
CColSphere *ourPieces = ourCol->spheres;
- float maxDistanceToBeat = ourPieces[j].radius + ms_fightMoves[m_lastFightMove].strikeRadius;
+ float maxDistanceToBeat = ourPieces[j].radius + tFightMoves[m_lastFightMove].strikeRadius;
// We can beat him too
if (sq(maxDistanceToBeat) > attackDistance.MagnitudeSqr()) {
@@ -4626,7 +4641,7 @@ CPed::FightStrike(CVector &touchedNodePos)
float oldVictimHealth = nearPed->m_fHealth;
CVector bloodPos = 0.5f * attackDistance + touchedNodePos;
- int damageMult = ms_fightMoves[m_lastFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
+ int damageMult = tFightMoves[m_lastFightMove].damage * ((CGeneral::GetRandomNumber() & 1) + 2) + 1;
CVector2D diff (GetPosition() - nearPed->GetPosition());
int direction = nearPed->GetLocalDirection(diff);
@@ -4654,16 +4669,16 @@ CPed::FightStrike(CVector &touchedNodePos)
else
unk2 = damageMult;
- nearPed->StartFightDefend(direction, ms_fightMoves[m_lastFightMove].hitLevel, unk2);
+ nearPed->StartFightDefend(direction, tFightMoves[m_lastFightMove].hitLevel, unk2);
PlayHitSound(nearPed);
m_fightUnk2 = -1;
- RpAnimBlendClumpGetAssociation(GetClump(), ms_fightMoves[m_lastFightMove].animId)->speed = 0.6f;
+ RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].animId)->speed = 0.6f;
if (nearPed->m_nPedState != PED_DIE && nearPed->m_nPedState != PED_DEAD) {
nearPed->InflictDamage(this, WEAPONTYPE_UNARMED, damageMult * 3.0f, closestPedPiece, direction);
}
if (CGame::nastyGame
- && ms_fightMoves[m_lastFightMove].hitLevel > 3
+ && tFightMoves[m_lastFightMove].hitLevel > 3
&& nearPed->m_nPedState == PED_DIE
&& nearPed->GetIsOnScreen()) {
@@ -4803,7 +4818,7 @@ CPed::SetFlee(CVector2D &from, int time)
}
bIsFleeing = true;
- m_pLastPathNode = nil;
+ m_pNextPathNode = nil;
m_fleeTimer = CTimer::GetTimeInMilliseconds() + time;
float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
@@ -4869,6 +4884,7 @@ CPed::SetWaitState(eWaitState state, void *time)
if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
ClearObjective();
RestorePreviousState();
+ m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000;
}
break;
case WAITSTATE_TURN180:
@@ -4894,6 +4910,7 @@ CPed::SetWaitState(eWaitState state, void *time)
if (m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER && CharCreatedBy == RANDOM_CHAR && m_nPedState == PED_SEEK_CAR) {
ClearObjective();
RestorePreviousState();
+ m_hitRecoverTimer = CTimer::GetTimeInMilliseconds() + 30000;
}
break;
case WAITSTATE_LOOK_ABOUT:
@@ -5060,9 +5077,9 @@ CPed::Say(uint16 audio)
if (audioToPlay < m_queuedSound) {
if (audioToPlay != m_lastQueuedSound || audioToPlay == SOUND_PED_DEATH
- || PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime
+ || CommentWaitTime[audioToPlay - SOUND_PED_DEATH].m_nOverrideMaxRandomDelayTime
+ m_lastSoundStart
- + (uint32) CGeneral::GetRandomNumberInRange(0, PedAudioData[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) {
+ + (uint32) CGeneral::GetRandomNumberInRange(0, CommentWaitTime[audioToPlay - SOUND_PED_DEATH].m_nMaxRandomDelayTime) <= CTimer::GetTimeInMilliseconds()) {
m_queuedSound = audioToPlay;
}
}
@@ -5098,10 +5115,10 @@ CPed::CollideWithPed(CPed *collideWith)
if (collideWith->m_nMoveState != PEDMOVE_STILL
&& (!collideWith->IsPlayer() || collideWith->IsPlayer() && CPad::GetPad(0)->ArePlayerControlsDisabled())) {
- float weAndCarDist = (GetPosition() - m_vecSeekVehicle).MagnitudeSqr2D();
- float heAndCarDist = (collideWith->GetPosition() - m_vecSeekVehicle).MagnitudeSqr2D();
+ float seekPosDist = (GetPosition() - m_vecSeekPos).MagnitudeSqr2D();
+ float heAndSeekPosDist = (collideWith->GetPosition() - m_vecSeekPos).MagnitudeSqr2D();
- if (weAndCarDist <= heAndCarDist) {
+ if (seekPosDist <= heAndSeekPosDist) {
waitTime = 1000;
collideWith->SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &waitTime);
collideWith->m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + waitTime;
@@ -5273,7 +5290,7 @@ CPed::CollideWithPed(CPed *collideWith)
SetFlee(collideWith, 5000);
bIsFleeing = true;
- m_pLastPathNode = nil;
+ m_pNextPathNode = nil;
if (!doWeRun)
SetMoveState(PEDMOVE_WALK);
}
@@ -5349,12 +5366,12 @@ CPed::CreateDeadPedWeaponPickups(void)
// otherwise try another position (but disregard second check apparently)
angleToPed += 3.14f;
pickupPos = GetPosition();
- pickupPos.x = 1.5f * Sin(angleToPed);
- pickupPos.y = 1.5f * Cos(angleToPed);
+ pickupPos.x += 1.5f * Sin(angleToPed);
+ pickupPos.y += 1.5f * Cos(angleToPed);
pickupPos.z = CWorld::FindGroundZFor3DCoord(pickupPos.x, pickupPos.y, pickupPos.z, &found) + 0.5f;
}
if (found)
- CPickups::GenerateNewOne_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, min(weaponAmmo, CPickups::ms_maxAmmosForWeapons[weapon]));
+ CPickups::GenerateNewOne_WeaponType(pickupPos, weapon, PICKUP_ONCE_TIMEOUT, min(weaponAmmo, AmmoForWeapon_OnStreet[weapon]));
}
ClearWeapons();
}
@@ -5464,7 +5481,7 @@ CPed::SetDead(void)
}
void
-CPed::SetSeek(CEntity *seeking, float unk)
+CPed::SetSeek(CEntity *seeking, float distanceToCountDone)
{
if (!IsPedInControl())
return;
@@ -5479,17 +5496,17 @@ CPed::SetSeek(CEntity *seeking, float unk)
SetStoredState();
m_nPedState = PED_SEEK_ENTITY;
- field_318 = unk;
+ m_distanceToCountSeekDone = distanceToCountDone;
m_pSeekTarget = seeking;
m_pSeekTarget->RegisterReference((CEntity **) &m_pSeekTarget);
SetMoveState(PEDMOVE_STILL);
}
void
-CPed::SetSeek(CVector pos, float unk)
+CPed::SetSeek(CVector pos, float distanceToCountDone)
{
if (!IsPedInControl()
- || (m_nPedState == PED_SEEK_POS && m_vecSeekVehicle.x != pos.x && m_vecSeekVehicle.y != pos.y))
+ || (m_nPedState == PED_SEEK_POS && m_vecSeekPos.x == pos.x && m_vecSeekPos.y == pos.y))
return;
if (GetWeapon()->m_eWeaponType == WEAPONTYPE_M16
@@ -5504,8 +5521,8 @@ CPed::SetSeek(CVector pos, float unk)
SetStoredState();
m_nPedState = PED_SEEK_POS;
- field_318 = unk;
- m_vecSeekVehicle = pos;
+ m_distanceToCountSeekDone = distanceToCountDone;
+ m_vecSeekPos = pos;
}
void
@@ -5649,7 +5666,7 @@ CPed::DuckAndCover(void)
&& CWorld::GetIsLineOfSightClear(GetPosition(), duckPos, 1, 0, 0, 1, 0, 0, 0)) {
SetSeek(duckPos, 1.0f);
m_headingRate = 15.0f;
- m_ped_flagB20 = true;
+ bIsRunning = true;
bDuckAndCover = true;
justDucked = true;
m_leaveCarTimer = CTimer::GetTimeInMilliseconds() + 500;
@@ -5676,7 +5693,7 @@ CPed::DuckAndCover(void)
bKindaStayInSamePlace = true;
bDuckAndCover = false;
- m_vecSeekVehicle = CVector(0.0f, 0.0f, 0.0f);
+ m_vecSeekPos = CVector(0.0f, 0.0f, 0.0f);
if (m_pSeekTarget && m_pSeekTarget->IsVehicle())
((CVehicle*)m_pSeekTarget)->m_numPedsUseItAsCover++;
@@ -5692,13 +5709,1962 @@ CPed::DuckAndCover(void)
return false;
}
+void
+CPed::EndFight(uint8 endType)
+{
+ if (m_nPedState != PED_FIGHT)
+ return;
+
+ m_lastFightMove = FIGHTMOVE_NULL;
+ RestorePreviousState();
+ CAnimBlendAssociation *animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FIGHT_IDLE);
+ if (animAssoc)
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+
+ switch (endType) {
+ case ENDFIGHT_NORMAL:
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f);
+ break;
+ case ENDFIGHT_WITH_A_STEP:
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 1.0f);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_WALK_START, 8.0f);
+ break;
+ case ENDFIGHT_FAST:
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 8.0f);
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FIGHT2_IDLE, 8.0f)->speed = 2.0f;
+ break;
+ default:
+ break;
+ }
+ m_nWaitTimer = 0;
+}
+
+void
+CPed::EnterCar(void)
+{
+ if (m_pMyVehicle && m_pMyVehicle->m_status != STATUS_WRECKED && m_fHealth > 0.0f) {
+ CVehicle* veh = (CVehicle*)m_pSeekTarget;
+
+ // Not used.
+ // CVector posForDoor = GetPositionToOpenCarDoor(veh, m_vehEnterType);
+
+ if (veh->CanPedOpenLocks(this)) {
+ if (m_vehEnterType) {
+ CAnimBlendAssociation *enterAssoc = m_pVehicleAnim;
+ if (enterAssoc)
+ veh->ProcessOpenDoor(m_vehEnterType, enterAssoc->animId, enterAssoc->currentTime);
+ }
+ }
+ bIsInTheAir = false;
+ LineUpPedWithCar(LINE_UP_TO_CAR_START);
+ } else {
+ QuitEnteringCar();
+ SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f);
+ }
+}
+
+uint8
+CPed::GetNearestTrainPedPosition(CVehicle *train, CVector &enterPos)
+{
+ CVector enterStepOffset;
+ CVehicleModelInfo *trainModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(train->m_modelIndex);
+ CMatrix trainMat = CMatrix(train->GetMatrix());
+ CVector leftEntryPos, rightEntryPos, midEntryPos;
+ float distLeftEntry, distRightEntry, distMidEntry;
+
+ // enterStepOffset = vecPedCarDoorAnimOffset;
+ enterStepOffset = CVector(1.5f, 0.0f, 0.0f);
+
+ if (train->pPassengers[TRAIN_POS_LEFT_ENTRY]) {
+ distLeftEntry = 999.0f;
+ } else {
+ leftEntryPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterStepOffset;
+ leftEntryPos = Multiply3x3(trainMat, leftEntryPos);
+ leftEntryPos += train->GetPosition();
+ distLeftEntry = (leftEntryPos - GetPosition()).Magnitude();
+ }
+
+ if (train->pPassengers[TRAIN_POS_MID_ENTRY]) {
+ distMidEntry = 999.0f;
+ } else {
+ midEntryPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterStepOffset;
+ midEntryPos = Multiply3x3(trainMat, midEntryPos);
+ midEntryPos += train->GetPosition();
+ distMidEntry = (midEntryPos - GetPosition()).Magnitude();
+ }
+
+ if (train->pPassengers[TRAIN_POS_RIGHT_ENTRY]) {
+ distRightEntry = 999.0f;
+ } else {
+ rightEntryPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterStepOffset;
+ rightEntryPos = Multiply3x3(trainMat, rightEntryPos);
+ rightEntryPos += train->GetPosition();
+ distRightEntry = (rightEntryPos - GetPosition()).Magnitude();
+ }
+
+ if (distMidEntry < distLeftEntry) {
+ if (distMidEntry < distRightEntry) {
+ enterPos = midEntryPos;
+ m_vehEnterType = TRAIN_POS_MID_ENTRY;
+ } else {
+ enterPos = rightEntryPos;
+ m_vehEnterType = TRAIN_POS_RIGHT_ENTRY;
+ }
+ } else if (distRightEntry < distLeftEntry) {
+ enterPos = rightEntryPos;
+ m_vehEnterType = TRAIN_POS_RIGHT_ENTRY;
+ } else {
+ enterPos = leftEntryPos;
+ m_vehEnterType = TRAIN_POS_LEFT_ENTRY;
+ }
+
+ return 1;
+}
+
+uint8
+CPed::GetNearestTrainDoor(CVehicle *train, CVector &doorPos)
+{
+ GetNearestTrainPedPosition(train, doorPos);
+/*
+ // Not used.
+ CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(train->m_modelIndex);
+ CMatrix trainMat = CMatrix(train->GetMatrix());
+
+ doorPos = trainModel->m_positions[m_vehEnterType];
+ doorPos.x -= 1.5f;
+ doorPos = Multiply3x3(trainMat, doorPos);
+ doorPos += train->GetPosition();
+*/
+ return 1;
+}
+
+void
+CPed::LineUpPedWithTrain(void)
+{
+ CVector lineUpPos;
+ CVehicleModelInfo* trainModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_pMyVehicle->m_modelIndex);
+ CVector enterOffset(1.5f, 0.0f, -0.2f);
+
+ m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
+ m_fRotationCur = m_pMyVehicle->GetForward().Heading() - HALFPI;
+ m_fRotationDest = m_fRotationCur;
+
+ if (!bInVehicle) {
+ GetNearestTrainDoor(m_pMyVehicle, lineUpPos);
+ lineUpPos.z += 0.2f;
+ } else {
+ if (m_pMyVehicle->pPassengers[TRAIN_POS_LEFT_ENTRY] == this) {
+
+ lineUpPos = trainModel->m_positions[TRAIN_POS_LEFT_ENTRY] - enterOffset;
+
+ } else if (m_pMyVehicle->pPassengers[TRAIN_POS_MID_ENTRY] == this) {
+
+ lineUpPos = trainModel->m_positions[TRAIN_POS_MID_ENTRY] - enterOffset;
+
+ } else if (m_pMyVehicle->pPassengers[TRAIN_POS_RIGHT_ENTRY] == this) {
+
+ lineUpPos = trainModel->m_positions[TRAIN_POS_RIGHT_ENTRY] - enterOffset;
+ }
+ lineUpPos = Multiply3x3(m_pMyVehicle->GetMatrix(), lineUpPos);
+ lineUpPos += m_pMyVehicle->GetPosition();
+ }
+
+ if (m_pVehicleAnim) {
+ float percentageLeft = m_pVehicleAnim->GetTimeLeft() / m_pVehicleAnim->hierarchy->totalLength;
+ lineUpPos += (GetPosition() - lineUpPos) * percentageLeft;
+ }
+
+ GetPosition() = lineUpPos;
+// CVector pedPos = GetPosition();
+ GetMatrix().SetRotate(0.0f, 0.0f, m_fRotationCur);
+ GetPosition() += lineUpPos;
+}
+
+void
+CPed::EnterTrain(void)
+{
+ LineUpPedWithTrain();
+}
+
+void
+CPed::ExitTrain(void)
+{
+ LineUpPedWithTrain();
+}
+
+void
+CPed::ExitCar(void)
+{
+ if (!m_pVehicleAnim)
+ return;
+
+ AnimationId exitAnim = (AnimationId) m_pVehicleAnim->animId;
+ float animTime = m_pVehicleAnim->currentTime;
+
+ m_pMyVehicle->ProcessOpenDoor(m_vehEnterType, exitAnim, animTime);
+
+ if (m_pSeekTarget) {
+ // Car is upside down
+ if (m_pMyVehicle->GetUp().z > -0.8f) {
+ if (exitAnim != ANIM_CAR_CLOSE_RHS && exitAnim != ANIM_CAR_CLOSE_LHS && animTime <= 0.3f)
+ LineUpPedWithCar((m_pMyVehicle->m_modelIndex == MI_DODO ? LINE_UP_TO_CAR_END : LINE_UP_TO_CAR_START));
+ else
+ LineUpPedWithCar(LINE_UP_TO_CAR_END);
+ } else {
+ LineUpPedWithCar(LINE_UP_TO_CAR_END);
+ }
+ }
+
+ // If there is someone in front of the door, make him fall while we exit.
+ if (m_nPedState == PED_EXIT_CAR) {
+ CPed *foundPed = nil;
+ for (int i = 0; i < m_numNearPeds; i++) {
+ if ((m_nearPeds[i]->GetPosition() - GetPosition()).MagnitudeSqr2D() < 0.04f) {
+ foundPed = m_nearPeds[i];
+ break;
+ }
+ }
+ if (foundPed && animTime > 0.4f && foundPed->IsPedInControl())
+ foundPed->SetFall(1000, ANIM_KO_SKID_FRONT, 1);
+ }
+}
+
+void
+CPed::Fall(void)
+{
+ if (m_getUpTimer != -1 && CTimer::GetTimeInMilliseconds() > m_getUpTimer)
+ ClearFall();
+}
+
+void
+CPed::Fight(void)
+{
+ CAnimBlendAssociation *currentAssoc = nil, *animAssoc;
+ bool hasShoppingBags, punchOnly, canKick, canKneeHead, canRoundhouse;
+ float angleToFace, nextAngle;
+ bool goForward = false;
+ int nextFightMove;
+
+ switch (m_lastFightMove) {
+ case FIGHTMOVE_NULL:
+ return;
+ case FIGHTMOVE_IDLE2NORM:
+ m_lastFightMove = FIGHTMOVE_NULL;
+ RestorePreviousState();
+ break;
+ case FIGHTMOVE_IDLE:
+ // currentAssoc = nil;
+ break;
+ default:
+ currentAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].animId);
+ break;
+ }
+
+ if (!bIsAttacking && IsPlayer()) {
+ if (currentAssoc) {
+ currentAssoc->blendDelta = -1000.0f;
+ currentAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ currentAssoc->flags &= ~ASSOC_RUNNING;
+ }
+ if (m_takeAStepAfterAttack)
+ EndFight(ENDFIGHT_WITH_A_STEP);
+ else
+ EndFight(ENDFIGHT_FAST);
+
+ } else if (currentAssoc && m_fightUnk2 > -2) {
+ float animTime = currentAssoc->currentTime;
+ FightMove &curMove = tFightMoves[m_lastFightMove];
+ if (curMove.hitLevel != 0 && animTime > curMove.startFireTime && animTime <= curMove.endFireTime && m_fightUnk2 >= 0) {
+
+ CVector touchingNodePos(0.0f, 0.0f, 0.0f);
+ RwFrame *touchingFrame = nil;
+
+ switch (m_lastFightMove) {
+ case FIGHTMOVE_STDPUNCH:
+ case FIGHTMOVE_PUNCHHOOK:
+ case FIGHTMOVE_BODYBLOW:
+ touchingFrame = GetNodeFrame(PED_HANDR);
+ break;
+ case FIGHTMOVE_IDLE:
+ case FIGHTMOVE_SHUFFLE_F:
+ break;
+ case FIGHTMOVE_KNEE:
+ touchingFrame = GetNodeFrame(PED_LOWERLEGR);
+ break;
+ case FIGHTMOVE_HEADBUTT:
+ touchingFrame = GetNodeFrame(PED_HEAD);
+ break;
+ case FIGHTMOVE_PUNCHJAB:
+ touchingFrame = GetNodeFrame(PED_HANDL);
+ break;
+ case FIGHTMOVE_KICK:
+ case FIGHTMOVE_LONGKICK:
+ case FIGHTMOVE_ROUNDHOUSE:
+ case FIGHTMOVE_GROUNDKICK:
+ touchingFrame = GetNodeFrame(PED_FOOTR);
+ break;
+ }
+ while (touchingFrame) {
+ RwV3dTransformPoints(touchingNodePos, touchingNodePos, 1, RwFrameGetMatrix(touchingFrame));
+ touchingFrame = RwFrameGetParent(touchingFrame);
+ }
+
+ if (m_lastFightMove == FIGHTMOVE_PUNCHJAB) {
+ touchingNodePos += 0.1f * GetForward();
+ } else if (m_lastFightMove == FIGHTMOVE_PUNCHHOOK) {
+ touchingNodePos += 0.22f * GetForward();
+ }
+ FightStrike(touchingNodePos);
+ m_fightButtonPressure = 0;
+ return;
+ }
+
+ if (curMove.hitLevel != 0) {
+ if (animTime > curMove.endFireTime) {
+ if (IsPlayer())
+ currentAssoc->speed = 1.0f;
+ else
+ currentAssoc->speed = 0.8f;
+ }
+
+ if (IsPlayer() && !nPlayerInComboMove) {
+ if (curMove.comboFollowOnTime > 0.0f && m_fightButtonPressure != 0 && animTime > curMove.comboFollowOnTime) {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, curMove.animId, 8.0f);
+ animAssoc->SetFinishCallback(FinishFightMoveCB, this);
+ animAssoc->SetCurrentTime(0.1f * animAssoc->hierarchy->totalLength);
+ m_fightButtonPressure = 0;
+ nPlayerInComboMove = 1;
+ }
+ }
+ } else {
+ if (curMove.startFireTime > 0.0f && m_lastFightMove != FIGHTMOVE_SHUFFLE_F && animTime > curMove.startFireTime) {
+ if (IsPlayer())
+ currentAssoc->speed = 1.3f;
+ else
+ currentAssoc->speed = 0.8f;
+ }
+ }
+ } else if (GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED) {
+ EndFight(ENDFIGHT_FAST);
+
+ } else if (m_fightButtonPressure != 0) {
+ bool canAffectMultiplePeople = true;
+ nextAngle = m_fRotationCur;
+ bool kickGround = false;
+ float angleForGroundKick = 0.0f;
+ CPed *pedOnGround = nil;
+
+ Say(SOUND_PED_ATTACK);
+
+ if (IsPlayer()) {
+ canRoundhouse = false;
+ punchOnly = false;
+ canKick = true;
+ nextFightMove = (m_fightButtonPressure > 190 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE);
+ hasShoppingBags = false;
+ canKneeHead = true;
+ nPlayerInComboMove = 0;
+ } else {
+ nextFightMove = (m_fightButtonPressure > 120 ? FIGHTMOVE_HEADBUTT : FIGHTMOVE_KNEE);
+ uint16 pedFeatures = m_pedStats->m_flags;
+ punchOnly = pedFeatures & STAT_PUNCH_ONLY;
+ canRoundhouse = pedFeatures & STAT_CAN_ROUNDHOUSE;
+ canKneeHead = pedFeatures & STAT_CAN_KNEE_HEAD;
+ canKick = pedFeatures & STAT_CAN_KICK;
+ hasShoppingBags = pedFeatures & STAT_SHOPPING_BAGS;
+ }
+
+ // Attack isn't scripted, find the victim
+ if (IsPlayer() || !m_pedInObjective) {
+
+ for (int i = 0; i < m_numNearPeds; i++) {
+
+ CPed *nearPed = m_nearPeds[i];
+ float nearPedDist = (nearPed->GetPosition() - GetPosition()).Magnitude();
+ if (nearPedDist < 3.0f) {
+ float angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ nearPed->GetPosition().x, nearPed->GetPosition().y,
+ GetPosition().x, GetPosition().y);
+
+ nextAngle = CGeneral::LimitRadianAngle(angleToFace);
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+
+ float neededTurn = Abs(nextAngle - m_fRotationCur);
+ if (neededTurn > PI)
+ neededTurn = TWOPI - neededTurn;
+
+ PedState nearPedState = nearPed->m_nPedState;
+ if (nearPedState != PED_FALL && nearPedState != PED_GETUP && nearPedState != PED_DIE && nearPedState != PED_DEAD) {
+
+ if (nearPedDist < 0.8f && neededTurn < DEGTORAD(75.0f) && canKneeHead) {
+ canAffectMultiplePeople = false;
+ } else if (nearPedDist >= 1.3f || neededTurn >= DEGTORAD(55.0f) || hasShoppingBags) {
+
+ if (nearPedDist < 1.7f
+ && neededTurn < DEGTORAD(35.0f)
+ && (canKick || hasShoppingBags)) {
+
+ nextFightMove = FIGHTMOVE_KICK;
+ if (hasShoppingBags) {
+ nextFightMove = FIGHTMOVE_ROUNDHOUSE;
+ } else if (canRoundhouse && CGeneral::GetRandomNumber() & 1) {
+ nextFightMove = FIGHTMOVE_ROUNDHOUSE;
+ }
+ canAffectMultiplePeople = false;
+ } else if (nearPedDist < 2.0f && neededTurn < DEGTORAD(30.0f) && canKick) {
+ canAffectMultiplePeople = false;
+ nextFightMove = FIGHTMOVE_LONGKICK;
+ } else if (neededTurn < DEGTORAD(30.0f)) {
+ goForward = true;
+ }
+ } else {
+ nextFightMove += 2; // Makes it 6 or 7
+ if (punchOnly)
+ nextFightMove = FIGHTMOVE_PUNCHJAB;
+
+ canAffectMultiplePeople = false;
+ }
+ } else if (!CGame::nastyGame
+ || nearPedDist >= 1.3f
+ || neededTurn >= DEGTORAD(55.0f)
+ || punchOnly) {
+
+ if (nearPedDist > 0.8f
+ && nearPedDist < 3.0f
+ && neededTurn < DEGTORAD(30.0f)) {
+ goForward = true;
+ }
+
+ } else if (nearPedState != PED_DEAD || pedOnGround) {
+ if (!nearPed->IsPedHeadAbovePos(-0.3f)) {
+ canAffectMultiplePeople = false;
+ nextFightMove = FIGHTMOVE_GROUNDKICK;
+ }
+
+ } else {
+ pedOnGround = nearPed;
+ kickGround = true;
+ angleForGroundKick = nextAngle;
+ }
+ }
+
+ if (!canAffectMultiplePeople) {
+ m_fRotationDest = nextAngle;
+ if (IsPlayer()) {
+ m_fRotationCur = m_fRotationDest;
+ m_lookTimer = 0;
+ SetLookFlag(nearPed, 1);
+ SetLookTimer(1500);
+ }
+ break;
+ }
+ }
+ } else {
+ // Because we're in a scripted fight with some particular ped.
+ canAffectMultiplePeople = false;
+
+ float fightingPedDist = (m_pedInObjective->GetPosition() - GetPosition()).Magnitude();
+ if (hasShoppingBags) {
+ if (fightingPedDist >= 1.7f)
+ nextFightMove = FIGHTMOVE_SHUFFLE_F;
+ else
+ nextFightMove = FIGHTMOVE_ROUNDHOUSE;
+
+ } else if (punchOnly) {
+ if (fightingPedDist >= 1.3f)
+ nextFightMove = FIGHTMOVE_SHUFFLE_F;
+ else
+ nextFightMove = FIGHTMOVE_PUNCHJAB;
+
+ } else if (fightingPedDist >= 3.0f) {
+ nextFightMove = FIGHTMOVE_STDPUNCH;
+
+ } else {
+ angleToFace = CGeneral::GetRadianAngleBetweenPoints(
+ m_pedInObjective->GetPosition().x,
+ m_pedInObjective->GetPosition().y,
+ GetPosition().x,
+ GetPosition().y);
+
+ nextAngle = CGeneral::LimitRadianAngle(angleToFace);
+ m_fRotationDest = nextAngle;
+ m_fRotationCur = m_fRotationDest;
+ PedState fightingPedState = m_pedInObjective->m_nPedState;
+ if (fightingPedState != PED_FALL && fightingPedState != PED_GETUP && fightingPedState != PED_DIE && fightingPedState != PED_DEAD) {
+
+ if (fightingPedDist >= 0.8f || !canKneeHead) {
+
+ if (fightingPedDist >= 1.3f) {
+
+ if (fightingPedDist < 1.7f && canKick) {
+ nextFightMove = FIGHTMOVE_KICK;
+ if (canRoundhouse && CGeneral::GetRandomNumber() & 1)
+ nextFightMove = FIGHTMOVE_ROUNDHOUSE;
+
+ } else if (fightingPedDist < 2.0f && canKick) {
+ nextFightMove += 5; // Makes it 9 or 10
+
+ } else {
+ nextFightMove = FIGHTMOVE_SHUFFLE_F;
+
+ }
+ } else {
+ nextFightMove += 2; // Makes it 6 or 7
+ }
+ }
+ } else if (!CGame::nastyGame
+ || fightingPedDist >= 1.3f
+ || m_pedInObjective->IsPlayer()
+ || m_pedInObjective->m_nPedState != PED_DEAD && m_pedInObjective->IsPedHeadAbovePos(-0.3f)) {
+ nextFightMove = FIGHTMOVE_IDLE;
+ } else {
+ nextFightMove = FIGHTMOVE_GROUNDKICK;
+ }
+ }
+ }
+
+ if (canAffectMultiplePeople) {
+ if (kickGround && IsPlayer()) {
+ m_fRotationDest = angleForGroundKick;
+ nextFightMove = FIGHTMOVE_GROUNDKICK;
+ m_fRotationCur = m_fRotationDest;
+ m_lookTimer = 0;
+ SetLookFlag(pedOnGround, 1);
+ SetLookTimer(1500);
+ } else if (goForward) {
+ nextFightMove = FIGHTMOVE_SHUFFLE_F;
+ } else {
+ nextFightMove = FIGHTMOVE_STDPUNCH;
+ }
+ }
+
+ if (nextFightMove != FIGHTMOVE_IDLE) {
+ m_lastFightMove = (PedFightMoves) nextFightMove;
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 4.0f);
+
+ animAssoc->SetFinishCallback(FinishFightMoveCB, this);
+ if (m_fightUnk2 == -2 && animAssoc->currentTime != 0.0f) {
+ animAssoc->SetCurrentTime(0.0f);
+ animAssoc->SetRun();
+ }
+ m_fightButtonPressure = 0;
+ }
+ m_fightUnk2 = 0;
+ } else if (m_takeAStepAfterAttack && m_lastFightMove != FIGHTMOVE_SHUFFLE_F
+#ifndef FIX_BUGS
+ && CheckForPedsOnGroundToAttack(this, nil) == 4) {
+#else
+ && CheckForPedsOnGroundToAttack(this, nil) == PED_IN_FRONT_OF_ATTACKER) {
+#endif
+ m_lastFightMove = FIGHTMOVE_SHUFFLE_F;
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), tFightMoves[m_lastFightMove].animId);
+
+ if (animAssoc) {
+ animAssoc->SetCurrentTime(0.0f);
+ animAssoc->blendDelta = 4.0f;
+ animAssoc->SetRun();
+ } else {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, tFightMoves[m_lastFightMove].animId, 32.0f);
+ }
+ animAssoc->SetFinishCallback(FinishFightMoveCB, this);
+ m_fightUnk2 = 0;
+ m_fightButtonPressure = 0;
+ m_takeAStepAfterAttack = false;
+
+ } else if (m_takeAStepAfterAttack) {
+ EndFight(ENDFIGHT_FAST);
+
+ } else if (m_lastFightMove == FIGHTMOVE_IDLE) {
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ EndFight(ENDFIGHT_NORMAL);
+ }
+
+ } else {
+ m_lastFightMove = FIGHTMOVE_IDLE;
+ if (IsPlayer())
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 500;
+ else
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 2000;
+ }
+}
+
+// Some helper function which doesn't exist in og game.
+inline void
+SelectClosestNodeForSeek(CPed *ped, CPathNode *node, CVector2D closeDist, CVector2D farDist, CPathNode *closeNode, CPathNode *closeNode2, int runCount = 3)
+{
+ for (int i = 0; i < node->numLinks; i++) {
+
+ CPathNode *testNode = &ThePaths.m_pathNodes[ThePaths.m_connections[i + node->firstLink]];
+
+ if (testNode && testNode != closeNode && testNode != closeNode2) {
+ CVector2D posDiff(ped->m_vecSeekPos - testNode->pos);
+ float dist = posDiff.MagnitudeSqr();
+
+ if (farDist.MagnitudeSqr() > dist) {
+
+ if (closeDist.MagnitudeSqr() <= dist) {
+ ped->m_pNextPathNode = closeNode;
+ closeDist = posDiff;
+ } else {
+ ped->m_pNextPathNode = (closeNode2 ? closeNode2 : testNode);
+ farDist = posDiff;
+ }
+ }
+
+ if (--runCount > 0)
+ SelectClosestNodeForSeek(ped, testNode, closeDist, farDist, closeNode, (closeNode2 ? closeNode2 : testNode), runCount);
+ }
+ }
+}
+
+bool
+CPed::FindBestCoordsFromNodes(CVector unused, CVector *bestCoords)
+{
+ if (m_pNextPathNode || !bIsFleeing)
+ return false;
+
+ CVector ourPos = GetPosition();
+
+ int closestNodeId = ThePaths.FindNodeClosestToCoors(GetPosition(), 1, 999999.9f, false, false);
+
+ CVector seekObjPos = m_vecSeekPos;
+ seekObjPos.z += 1.0f;
+
+ if (CWorld::GetIsLineOfSightClear(ourPos, seekObjPos, true, false, false, true, false, false, false))
+ return false;
+
+ m_pNextPathNode = nil;
+
+ CVector2D seekPosDist (m_vecSeekPos - ourPos);
+
+ CPathNode *closestNode = &ThePaths.m_pathNodes[closestNodeId];
+ CVector2D closeDist(m_vecSeekPos - closestNode->pos);
+
+ SelectClosestNodeForSeek(this, closestNode, closeDist, seekPosDist, closestNode, nil);
+
+ // Above function decided that going to the next node is more logical than seeking the object.
+ if (m_pNextPathNode) {
+
+ CVector pathToNextNode = m_pNextPathNode->pos - ourPos;
+ if (pathToNextNode.MagnitudeSqr2D() < seekPosDist.MagnitudeSqr()) {
+ *bestCoords = m_pNextPathNode->pos;
+ return true;
+ }
+ m_pNextPathNode = nil;
+ }
+
+ return false;
+}
+
+void
+CPed::FinishDieAnimCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed *ped = (CPed*)arg;
+
+ if (ped->bIsPedDieAnimPlaying)
+ ped->bIsPedDieAnimPlaying = false;
+}
+
+void
+CPed::FinishFightMoveCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed *ped = (CPed*)arg;
+
+ if (tFightMoves[ped->m_lastFightMove].animId == animAssoc->animId) {
+ ped->m_fightUnk2 = -2;
+ animAssoc->blendDelta = -1000.0f;
+ }
+}
+
+void
+CPed::FinishHitHeadCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed *ped = (CPed*)arg;
+
+ if (animAssoc) {
+ animAssoc->blendDelta = -4.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+
+ if (ped->m_nPedState == PED_JUMP)
+ ped->RestorePreviousState();
+
+ ped->bIsLanding = false;
+}
+
+void
+CPed::FinishJumpCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed* ped = (CPed*)arg;
+
+ ped->m_ped_flagG4 = true;
+ ped->bIsLanding = false;
+
+ animAssoc->blendDelta = -1000.0f;
+}
+
+void
+CPed::FinishLaunchCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed *ped = (CPed*)arg;
+
+ if (ped->m_nPedState != PED_JUMP)
+ return;
+
+ CVector forward(0.15f * ped->GetForward() + ped->GetPosition());
+ forward.z += CModelInfo::GetModelInfo(ped->m_modelIndex)->GetColModel()->spheres->center.z + 0.25f;
+
+ CEntity *foundEnt = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false);
+ if (!foundEnt) {
+ // Forward of forward
+ forward += 0.15f * ped->GetForward();
+ forward.z += 0.15f;
+ foundEnt = CWorld::TestSphereAgainstWorld(forward, 0.25f, nil, true, true, false, true, false, false);
+ }
+
+ if (foundEnt) {
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ CAnimBlendAssociation *handsCoverAssoc = CAnimManager::BlendAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_HANDSCOWER, 8.0f);
+ handsCoverAssoc->flags &= ~ASSOC_FADEOUTWHENDONE;
+ handsCoverAssoc->SetFinishCallback(FinishHitHeadCB, ped);
+ ped->bIsLanding = true;
+ return;
+ }
+
+ float velocityFromAnim = 0.1f;
+ CAnimBlendAssociation *sprintAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_SPRINT);
+
+ if (sprintAssoc) {
+ velocityFromAnim = 0.05f * sprintAssoc->blendAmount + 0.17f;
+ } else {
+ CAnimBlendAssociation *runAssoc = RpAnimBlendClumpGetAssociation(ped->GetClump(), ANIM_RUN);
+ if (runAssoc) {
+ velocityFromAnim = 0.07f * runAssoc->blendAmount + 0.1f;
+ }
+ }
+
+ if (ped->IsPlayer())
+ ped->ApplyMoveForce(0.0f, 0.0f, 8.5f);
+ else
+ ped->ApplyMoveForce(0.0f, 0.0f, 4.5f);
+
+ if (sq(velocityFromAnim) > ped->m_vecMoveSpeed.MagnitudeSqr2D()) {
+
+ if (TheCamera.Cams[0].Using3rdPersonMouseCam()) {
+ float fpsAngle = ped->WorkOutHeadingForMovingFirstPerson(ped->m_fRotationCur);
+ ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(fpsAngle);
+ ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(fpsAngle);
+ } else {
+ ped->m_vecMoveSpeed.x = -velocityFromAnim * Sin(ped->m_fRotationCur);
+ ped->m_vecMoveSpeed.y = velocityFromAnim * Cos(ped->m_fRotationCur);
+ }
+ }
+
+ ped->bIsStanding = false;
+ ped->bIsInTheAir = true;
+ animAssoc->blendDelta = -1000.0f;
+ CAnimManager::AddAnimation(ped->GetClump(), ASSOCGRP_STD, ANIM_JUMP_GLIDE);
+
+ if (ped->bDoBloodyFootprints) {
+ CVector bloodPos(0.0f, 0.0f, 0.0f);
+ for (RwFrame *i = ped->GetNodeFrame(PED_FOOTL); i; i = RwFrameGetParent(i))
+ RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(i));
+
+ bloodPos.z -= 0.1f;
+ bloodPos += 0.2f * ped->GetForward();
+
+ CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos,
+ 0.26f * ped->GetForward().x,
+ 0.26f * ped->GetForward().y,
+ 0.14f * ped->GetRight().x,
+ 0.14f * ped->GetRight().y,
+ 255, 255, 0, 0, 4.0f, 3000, 1.0f);
+
+ bloodPos = CVector(0.0f, 0.0f, 0.0f);
+ for (RwFrame* j = ped->GetNodeFrame(PED_FOOTR); j; j = RwFrameGetParent(j))
+ RwV3dTransformPoints(bloodPos, bloodPos, 1, RwFrameGetMatrix(j));
+
+ bloodPos.z -= 0.1f;
+ bloodPos += 0.2f * ped->GetForward();
+ CShadows::AddPermanentShadow(SHADOWTYPE_DARK, gpBloodPoolTex, &bloodPos,
+ 0.26f * ped->GetForward().x,
+ 0.26f * ped->GetForward().y,
+ 0.14f * ped->GetRight().x,
+ 0.14f * ped->GetRight().y,
+ 255, 255, 0, 0, 4.0f, 3000, 1.0f);
+
+ if (ped->m_bloodyFootprintCount <= 40) {
+ ped->m_bloodyFootprintCount = 0;
+ ped->bDoBloodyFootprints = false;
+ } else {
+ ped->m_bloodyFootprintCount -= 40;
+ }
+ }
+}
+
+void
+CPed::FinishedWaitCB(CAnimBlendAssociation *animAssoc, void *arg)
+{
+ CPed* ped = (CPed*)arg;
+
+ ped->m_nWaitTimer = 0;
+ ped->RestoreHeadingRate();
+ ped->Wait();
+}
+
+void
+CPed::Wait(void)
+{
+ AnimationId mustHaveAnim = NUM_ANIMS;
+ CAnimBlendAssociation *animAssoc;
+ CPed *pedWeLook;
+
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD) {
+ m_nWaitState = WAITSTATE_FALSE;
+ RestoreHeadingRate();
+ return;
+ }
+
+ switch (m_nWaitState) {
+
+ case WAITSTATE_TRAFFIC_LIGHTS:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ if (CTrafficLights::LightForPeds() == PED_LIGHTS_WALK) {
+ m_nWaitState = WAITSTATE_FALSE;
+ SetMoveState(PEDMOVE_WALK);
+ }
+ }
+ break;
+
+ case WAITSTATE_CROSS_ROAD:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ if (CGeneral::GetRandomNumber() & 1 || !m_nWaitTimer)
+ m_nWaitState = WAITSTATE_FALSE;
+ else
+ SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, nil);
+
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
+ if (animAssoc) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ break;
+
+ case WAITSTATE_LOOK_PED:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ m_nWaitState = WAITSTATE_FALSE;
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
+ if (animAssoc) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ break;
+
+ case WAITSTATE_DOUBLEBACK:
+ if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) {
+ uint32 timeLeft = m_nWaitTimer - CTimer::GetTimeInMilliseconds();
+ if (timeLeft < 2500 && timeLeft > 2000) {
+ m_nWaitTimer -= 500;
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
+ }
+ } else {
+ m_nWaitState = WAITSTATE_FALSE;
+ SetMoveState(PEDMOVE_WALK);
+ }
+ break;
+
+ case WAITSTATE_HITWALL:
+ if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) {
+ if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) {
+ m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500;
+ }
+ } else {
+ m_nWaitState = WAITSTATE_FALSE;
+ }
+ break;
+
+ case WAITSTATE_TURN180:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ m_nWaitState = WAITSTATE_FALSE;
+ SetMoveState(PEDMOVE_WALK);
+ m_fRotationCur = m_fRotationCur + PI;
+ if (m_nPedState == PED_INVESTIGATE)
+ ClearInvestigateEvent();
+ }
+
+ if (m_collidingThingTimer > CTimer::GetTimeInMilliseconds()) {
+ m_collidingThingTimer = CTimer::GetTimeInMilliseconds() + 2500;
+ }
+ break;
+
+ case WAITSTATE_SURPRISE:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ if (RpAnimBlendClumpGetAssociation(GetClump(), ANIM_HIT_WALL)) {
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_XPRESS_SCRATCH, 4.0f);
+ animAssoc->SetFinishCallback(FinishedWaitCB, this);
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ } else {
+ m_nWaitState = WAITSTATE_FALSE;
+ }
+ }
+ break;
+
+ case WAITSTATE_STUCK:
+ if (CTimer::GetTimeInMilliseconds() <= m_nWaitTimer)
+ break;
+
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_TURN_180);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_XPRESS_SCRATCH);
+ if (!animAssoc)
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_ROAD_CROSS);
+
+ if (animAssoc) {
+ if (animAssoc->IsPartial()) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ } else {
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ }
+
+ if (animAssoc->animId == ANIM_TURN_180) {
+ m_fRotationCur = CGeneral::LimitRadianAngle(PI + m_fRotationCur);
+ m_nWaitState = WAITSTATE_FALSE;
+ SetMoveState(PEDMOVE_WALK);
+ m_nStoredMoveState = PEDMOVE_NONE;
+ m_panicCounter = 0;
+ return;
+ }
+ }
+
+ AnimationId animToRun;
+
+ switch (CGeneral::GetRandomNumber() & 3) {
+ case 0:
+ animToRun = ANIM_ROAD_CROSS;
+ break;
+ case 1:
+ animToRun = ANIM_IDLE_TIRED;
+ break;
+ case 2:
+ animToRun = ANIM_XPRESS_SCRATCH;
+ break;
+ case 3:
+ animToRun = ANIM_TURN_180;
+ break;
+ default:
+ break;
+ }
+
+ animAssoc = CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, animToRun, 4.0f);
+
+ if (animToRun == ANIM_TURN_180)
+ animAssoc->SetFinishCallback(FinishedWaitCB, this);
+
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + CGeneral::GetRandomNumberInRange(1500, 5000);
+ break;
+
+ case WAITSTATE_LOOK_ABOUT:
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ m_nWaitState = WAITSTATE_FALSE;
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_HBHB);
+ if (animAssoc) {
+ animAssoc->blendDelta = -8.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ break;
+
+ case WAITSTATE_PLAYANIM_HANDSUP:
+ mustHaveAnim = ANIM_HANDSUP;
+
+ case WAITSTATE_PLAYANIM_HANDSCOWER:
+ if (mustHaveAnim == NUM_ANIMS)
+ mustHaveAnim = ANIM_HANDSCOWER;
+
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
+ pedWeLook = (CPed*) m_pLookTarget;
+
+ if ((!m_pLookTarget || !m_pLookTarget->IsPed() || pedWeLook->m_pPointGunAt)
+ && m_nPedState != PED_FLEE_ENTITY
+ && m_nPedState != PED_ATTACK
+ && CTimer::GetTimeInMilliseconds() <= m_nWaitTimer
+ && animAssoc) {
+
+ TurnBody();
+ } else {
+ m_nWaitState = WAITSTATE_FALSE;
+ m_nWaitTimer = 0;
+ if (m_pLookTarget && m_pLookTarget->IsPed()) {
+
+ if (m_nPedState != PED_FLEE_ENTITY && m_nPedState != PED_ATTACK) {
+
+ if (m_pedStats->m_fear <= 100 - pedWeLook->m_pedStats->m_temper) {
+
+ if (GetWeapon()->IsTypeMelee()) {
+
+ SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget);
+ if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS) {
+
+ bIsFleeing = true;
+ m_pNextPathNode = nil;
+ }
+ if (m_nMoveState != PEDMOVE_RUN)
+ SetMoveState(PEDMOVE_WALK);
+
+ if (m_nPedType != PEDTYPE_COP) {
+ ProcessObjective();
+ SetMoveState(PEDMOVE_WALK);
+ }
+ } else {
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, m_pLookTarget);
+ SetObjectiveTimer(20000);
+ }
+ } else {
+ SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, m_pLookTarget);
+ if (m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_FLEE_POS)
+ {
+ bIsFleeing = true;
+ m_pNextPathNode = nil;
+ }
+ SetMoveState(PEDMOVE_RUN);
+ Say(SOUND_PED_FLEE_RUN);
+ }
+ }
+ }
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
+ if (animAssoc) {
+ animAssoc->blendDelta = -4.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ }
+ break;
+ case WAITSTATE_PLAYANIM_COWER:
+ mustHaveAnim = ANIM_HANDSCOWER;
+
+ case WAITSTATE_PLAYANIM_DUCK:
+ if (mustHaveAnim == NUM_ANIMS)
+ mustHaveAnim = ANIM_DUCK_DOWN;
+
+ case WAITSTATE_PLAYANIM_TAXI:
+ if (mustHaveAnim == NUM_ANIMS)
+ mustHaveAnim = ANIM_IDLE_TAXI;
+
+ case WAITSTATE_PLAYANIM_CHAT:
+ if (mustHaveAnim == NUM_ANIMS)
+ mustHaveAnim = ANIM_IDLE_CHAT;
+
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), mustHaveAnim);
+ if (animAssoc) {
+ animAssoc->blendDelta = -4.0f;
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ }
+ m_nWaitState = WAITSTATE_FALSE;
+ }
+ break;
+
+ case WAITSTATE_FINISH_FLEE:
+ animAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_TIRED);
+ if (animAssoc) {
+ if (CTimer::GetTimeInMilliseconds() > m_nWaitTimer) {
+ animAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ CAnimManager::BlendAnimation(GetClump(), m_animGroup, ANIM_IDLE_STANCE, 4.0f);
+ int timer = 2000;
+ m_nWaitState = WAITSTATE_FALSE;
+ SetWaitState(WAITSTATE_CROSS_ROAD_LOOK, &timer);
+ }
+ } else {
+ m_nWaitState = WAITSTATE_FALSE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if(!m_nWaitState)
+ RestoreHeadingRate();
+}
+
+bool
+CPed::Seek(void)
+{
+ float distanceToCountItDone = m_distanceToCountSeekDone;
+ eMoveState nextMove = PEDMOVE_NONE;
+
+ if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+
+ if (m_nPedState != PED_EXIT_TRAIN && m_nPedState != PED_ENTER_TRAIN && m_nPedState != PED_SEEK_IN_BOAT &&
+ m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER && m_objective != OBJECTIVE_SOLICIT && !bDuckAndCover) {
+
+ if ((!m_pedInObjective || !m_pedInObjective->bInVehicle)
+ && !((CTimer::GetFrameCounter() + (m_randomSeed % 256) + 17) & 7)) {
+
+ CEntity *foundEnt = CWorld::TestSphereAgainstWorld(m_vecSeekPos, 0.4f, nil,
+ false, true, false, false, false, false);
+
+ if (foundEnt) {
+ if (!foundEnt->IsVehicle() || ((CVehicle*)foundEnt)->m_vehType == VEHICLE_TYPE_CAR) {
+ distanceToCountItDone = 2.5f;
+ } else {
+ CVehicleModelInfo *vehModel = (CVehicleModelInfo*) CModelInfo::GetModelInfo(foundEnt->m_modelIndex);
+ float yLength = vehModel->GetColModel()->boundingBox.max.y
+ - vehModel->GetColModel()->boundingBox.min.y;
+ distanceToCountItDone = yLength * 0.55f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!m_pSeekTarget && m_nPedState == PED_SEEK_ENTITY)
+ ClearSeek();
+
+ float seekPosDist = (m_vecSeekPos - GetPosition()).Magnitude2D();
+ if (seekPosDist < 2.0f || m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT) {
+
+ if (m_objective == OBJECTIVE_FOLLOW_PED_IN_FORMATION) {
+
+ if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL)
+ nextMove = m_pedInObjective->m_nMoveState;
+ } else
+ nextMove = PEDMOVE_WALK;
+
+ } else if (m_objective != OBJECTIVE_FOLLOW_PED_IN_FORMATION) {
+
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT || m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS || m_objective == OBJECTIVE_RUN_TO_AREA || bIsRunning)
+ nextMove = PEDMOVE_RUN;
+ else
+ nextMove = PEDMOVE_WALK;
+
+ } else if (seekPosDist <= 2.0f) {
+
+ if (m_pedInObjective->m_nMoveState != PEDMOVE_STILL)
+ nextMove = m_pedInObjective->m_nMoveState;
+
+ } else {
+ nextMove = PEDMOVE_RUN;
+ }
+
+ if (m_nPedState == PED_SEEK_ENTITY) {
+ if (m_pSeekTarget->IsPed()) {
+ if (((CPed*)m_pSeekTarget)->bInVehicle)
+ distanceToCountItDone += 2.0f;
+ }
+ }
+
+ if (seekPosDist >= distanceToCountItDone) {
+ if (bIsRunning)
+ nextMove = PEDMOVE_RUN;
+
+ if (CTimer::GetTimeInMilliseconds() <= m_nPedStateTimer) {
+
+ if (m_actionX != 0.0f && m_actionY != 0.0f) {
+
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(
+ m_actionX, m_actionY,
+ GetPosition().x, GetPosition().y);
+
+ float neededTurn = Abs(m_fRotationDest - m_fRotationCur);
+
+ if (neededTurn > PI)
+ neededTurn = TWOPI - neededTurn;
+
+ if (neededTurn > HALFPI) {
+ if (seekPosDist >= 1.0f) {
+ if (seekPosDist < 2.0f) {
+ if (bIsRunning)
+ nextMove = PEDMOVE_RUN;
+ else
+ nextMove = PEDMOVE_WALK;
+ }
+ } else {
+ nextMove = PEDMOVE_STILL;
+ }
+ }
+
+ CVector2D moveDist(GetPosition().x - m_actionX, GetPosition().y - m_actionY);
+ if (moveDist.Magnitude() < 0.5f) {
+ m_nPedStateTimer = 0;
+ m_actionX = 0;
+ m_actionY = 0;
+ }
+ }
+ } else {
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(
+ m_vecSeekPos.x, m_vecSeekPos.y,
+ GetPosition().x, GetPosition().y);
+
+ float neededTurn = Abs(m_fRotationDest - m_fRotationCur);
+
+ if (neededTurn > PI)
+ neededTurn = TWOPI - neededTurn;
+
+ if (neededTurn > HALFPI) {
+ if (seekPosDist >= 1.0 && neededTurn <= DEGTORAD(135.0f)) {
+ if (seekPosDist < 2.0f)
+ nextMove = PEDMOVE_WALK;
+ } else {
+ nextMove = PEDMOVE_STILL;
+ }
+ }
+ }
+
+ if (((m_nPedState == PED_FLEE_POS || m_nPedState == PED_FLEE_ENTITY) && m_nMoveState < nextMove)
+ || (m_nPedState != PED_FLEE_POS && m_nPedState != PED_FLEE_ENTITY && m_objective != OBJECTIVE_GOTO_CHAR_ON_FOOT && m_nWaitState == WAITSTATE_FALSE)) {
+
+ SetMoveState(nextMove);
+ }
+
+ SetMoveAnim();
+ return false;
+ }
+
+ if ((m_objective != OBJECTIVE_FOLLOW_PED_IN_FORMATION || m_pedInObjective->m_nMoveState == PEDMOVE_STILL) && m_nMoveState != PEDMOVE_STILL) {
+ m_nPedStateTimer = 0;
+ m_actionX = 0;
+ m_actionY = 0;
+ }
+
+ if (m_objective == OBJECTIVE_GOTO_AREA_ON_FOOT || m_objective == OBJECTIVE_RUN_TO_AREA || m_objective == OBJECTIVE_GOTO_AREA_ANY_MEANS) {
+ if (m_pNextPathNode)
+ m_pNextPathNode = nil;
+ else
+ bScriptObjectiveCompleted = true;
+
+ bIsFleeing = true;
+ }
+
+ if (SeekFollowingPath(nil))
+ m_nCurPathNode++;
+
+ return true;
+}
+
+bool
+CPed::SeekFollowingPath(CVector *unused)
+{
+ return m_nCurPathNode <= m_nPathNodes && m_nPathNodes;
+}
+
+void
+CPed::Flee(void)
+{
+ if (CTimer::GetTimeInMilliseconds() > m_fleeTimer && m_fleeTimer) {
+ bool mayFinishFleeing = true;
+ if (m_nPedState == PED_FLEE_ENTITY) {
+ if ((CVector2D(GetPosition()) - ms_vec2DFleePosition).MagnitudeSqr() < 900.0f)
+ mayFinishFleeing = false;
+ }
+
+ if (mayFinishFleeing) {
+ eMoveState moveState = m_nMoveState;
+ ClearFlee();
+
+ if (m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE || m_objective == OBJECTIVE_FLEE_CHAR_ON_FOOT_ALWAYS)
+ RestorePreviousObjective();
+
+ if ((m_nPedState == PED_IDLE || m_nPedState == PED_WANDER_PATH) && CGeneral::GetRandomNumber() & 1) {
+ SetWaitState(moveState <= PEDMOVE_WALK ? WAITSTATE_CROSS_ROAD_LOOK : WAITSTATE_FINISH_FLEE, nil);
+ }
+ return;
+ }
+ m_fleeTimer = CTimer::GetTimeInMilliseconds() + 5000;
+ }
+
+ if (bIsFleeing) {
+ CPathNode *realLastNode = nil;
+ uint8 nextDirection = 0;
+ uint8 curDirectionShouldBe = 9; // means not defined yet
+
+ if (m_nPedStateTimer < CTimer::GetTimeInMilliseconds()
+ && m_collidingThingTimer < CTimer::GetTimeInMilliseconds()) {
+
+ if (m_pNextPathNode && CTimer::GetTimeInMilliseconds() > m_standardTimer) {
+
+ curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y);
+ if (m_nPathState < curDirectionShouldBe)
+ m_nPathState += 8;
+
+ int dirDiff = m_nPathState - curDirectionShouldBe;
+ if (dirDiff > 2 && dirDiff < 6) {
+ realLastNode = nil;
+ m_pLastPathNode = m_pNextPathNode;
+ m_pNextPathNode = 0;
+ }
+ }
+
+ if (m_pNextPathNode) {
+ m_vecSeekPos = m_pNextPathNode->pos;
+ if (m_nMoveState == PEDMOVE_RUN)
+ bIsRunning = true;
+
+ eMoveState moveState = m_nMoveState;
+ if (Seek()) {
+ realLastNode = m_pLastPathNode;
+ m_pLastPathNode = m_pNextPathNode;
+ m_pNextPathNode = nil;
+ }
+ bIsRunning = false;
+ SetMoveState(moveState);
+ }
+ }
+
+ if (!m_pNextPathNode) {
+ if (curDirectionShouldBe == 9) {
+ curDirectionShouldBe = CGeneral::GetNodeHeadingFromVector(GetPosition().x - ms_vec2DFleePosition.x, GetPosition().y - ms_vec2DFleePosition.y);
+ }
+ ThePaths.FindNextNodeWandering(PATH_PED, GetPosition(), &m_pLastPathNode, &m_pNextPathNode,
+ curDirectionShouldBe,
+ &nextDirection);
+
+ if (curDirectionShouldBe < nextDirection)
+ curDirectionShouldBe += 8;
+
+ if (m_pNextPathNode && m_pNextPathNode != realLastNode && m_pNextPathNode != m_pLastPathNode && curDirectionShouldBe - nextDirection != 4) {
+ m_nPathState = nextDirection;
+ m_standardTimer = CTimer::GetTimeInMilliseconds() + 2000;
+ } else {
+ bIsFleeing = false;
+ SetMoveState(PEDMOVE_RUN);
+ Flee();
+ }
+ }
+ return;
+ }
+
+ if ((m_nPedState == PED_FLEE_ENTITY || m_nPedState == PED_ON_FIRE) && m_nPedStateTimer < CTimer::GetTimeInMilliseconds()) {
+
+ float angleToFleeFromPos = CGeneral::GetRadianAngleBetweenPoints(
+ GetPosition().x,
+ GetPosition().y,
+ ms_vec2DFleePosition.x,
+ ms_vec2DFleePosition.y);
+
+ m_fRotationDest = CGeneral::LimitRadianAngle(angleToFleeFromPos);
+
+ if (m_fRotationCur - PI > m_fRotationDest)
+ m_fRotationDest += TWOPI;
+ else if (PI + m_fRotationCur < m_fRotationDest)
+ m_fRotationDest -= TWOPI;
+ }
+
+ if (CTimer::GetTimeInMilliseconds() & 0x20) {
+ //CVector forwardPos = GetPosition();
+ CMatrix forwardMat(GetMatrix());
+ forwardMat.GetPosition() += Multiply3x3(forwardMat, CVector(0.0f, 4.0f, 0.0f));
+ CVector forwardPos = forwardMat.GetPosition();
+
+ CEntity *foundEnt;
+ CColPoint foundCol;
+ bool found = CWorld::ProcessVerticalLine(forwardPos, forwardMat.GetPosition().z - 100.0f, foundCol, foundEnt, 1, 0, 0, 0, 1, 0, 0);
+
+ if (!found || Abs(forwardPos.z - forwardMat.GetPosition().z) > 1.0f) {
+ m_fRotationDest += DEGTORAD(112.5f);
+ m_nPedStateTimer = CTimer::GetTimeInMilliseconds() + 2000;
+ }
+ }
+
+ if (CTimer::GetTimeInMilliseconds() >= m_collidingThingTimer)
+ return;
+
+ if (!m_collidingEntityWhileFleeing)
+ return;
+
+ double damagingThingPriorityMult = (double)(m_collidingThingTimer - CTimer::GetTimeInMilliseconds()) * 2.0 / 2500;
+
+ if (damagingThingPriorityMult <= 1.5) {
+
+ double angleToFleeEntity = CGeneral::GetRadianAngleBetweenPoints(
+ GetPosition().x,
+ GetPosition().y,
+ m_collidingEntityWhileFleeing->GetPosition().x,
+ m_collidingEntityWhileFleeing->GetPosition().y);
+ angleToFleeEntity = CGeneral::LimitRadianAngle(angleToFleeEntity);
+
+ // It includes projectiles, but is everything collides with us included?
+ double angleToFleeDamagingThing = CGeneral::GetRadianAngleBetweenPoints(
+ m_vecDamageNormal.x,
+ m_vecDamageNormal.y,
+ 0.0,
+ 0.0);
+ angleToFleeDamagingThing = CGeneral::LimitRadianAngle(angleToFleeDamagingThing);
+
+ if (angleToFleeEntity - PI > angleToFleeDamagingThing)
+ angleToFleeDamagingThing += TWOPI;
+ else if (PI + angleToFleeEntity < angleToFleeDamagingThing)
+ angleToFleeDamagingThing -= TWOPI;
+
+ if (damagingThingPriorityMult <= 1.0) {
+ // Range [0.0, 1.0]
+
+ double angleToFleeBoth = (angleToFleeDamagingThing + angleToFleeEntity) * 0.5;
+
+ if (m_fRotationDest - PI > angleToFleeBoth)
+ angleToFleeBoth += TWOPI;
+ else if (PI + m_fRotationDest < angleToFleeBoth)
+ angleToFleeBoth -= TWOPI;
+
+ m_fRotationDest = (1.0 - damagingThingPriorityMult) * m_fRotationDest + damagingThingPriorityMult * angleToFleeBoth;
+ } else {
+ // Range (1.0, 1.5]
+
+ double adjustedMult = (damagingThingPriorityMult - 1.0) * 2.0;
+ m_fRotationDest = angleToFleeEntity * (1.0 - adjustedMult) + adjustedMult * angleToFleeDamagingThing;
+ }
+ } else {
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(
+ m_vecDamageNormal.x,
+ m_vecDamageNormal.y,
+ 0.0f,
+ 0.0f);
+ m_fRotationDest = CGeneral::LimitRadianAngle(m_fRotationDest);
+ }
+
+ m_fRotationCur = CGeneral::LimitRadianAngle(m_fRotationCur);
+
+ if (m_fRotationCur - PI > m_fRotationDest)
+ m_fRotationDest += TWOPI;
+ else if (PI + m_fRotationCur < m_fRotationDest)
+ m_fRotationDest -= TWOPI;
+
+}
+
+void
+CPed::FollowPath(void)
+{
+ m_vecSeekPos.x = m_stPathNodeStates[m_nCurPathNode].x;
+ m_vecSeekPos.y = m_stPathNodeStates[m_nCurPathNode].y;
+ m_vecSeekPos.z = GetPosition().z;
+
+ // Mysterious code
+/* int v4 = 0;
+ int maxNodeIndex = m_nPathNodes - 1;
+ if (maxNodeIndex > 0) {
+ if (maxNodeIndex > 8) {
+ while (v4 < maxNodeIndex - 8)
+ v4 += 8;
+ }
+
+ while (v4 < maxNodeIndex)
+ v4++;
+
+ }
+*/
+ if (Seek()) {
+ m_nCurPathNode++;
+ if (m_nCurPathNode == m_nPathNodes)
+ RestorePreviousState();
+ }
+}
+
+CVector
+CPed::GetFormationPosition(void)
+{
+ CPed *referencePed = m_pedInObjective;
+
+ if (referencePed->m_nPedState == PED_DEAD) {
+ CPed *referencePedOfReference = referencePed->m_pedInObjective;
+ if (!referencePedOfReference) {
+ m_pedInObjective = nil;
+ return GetPosition();
+ }
+ m_pedInObjective = referencePed = referencePedOfReference;
+ }
+
+ CVector formationOffset;
+ switch (m_pedFormation) {
+ case 1:
+ formationOffset = CVector(0.0f, -1.5f, 0.0f);
+ break;
+ case 2:
+ formationOffset = CVector(-1.5f, -1.5f, 0.0f);
+ break;
+ case 3:
+ formationOffset = CVector(1.5f, -1.5f, 0.0f);
+ break;
+ case 4:
+ formationOffset = CVector(-1.5f, 1.5f, 0.0f);
+ break;
+ case 5:
+ formationOffset = CVector(1.5f, 1.5f, 0.0f);
+ break;
+ case 6:
+ formationOffset = CVector(-1.5f, 0.0f, 0.0f);
+ break;
+ case 7:
+ formationOffset = CVector(1.5f, 0.0f, 0.0f);
+ break;
+ case 8:
+ formationOffset = CVector(0.0f, 1.5f, 0.0f);
+ break;
+ default:
+ formationOffset = CVector(0.0f, 0.0f, 0.0f);
+ break;
+ }
+ return formationOffset + referencePed->GetPosition();
+}
+
+void
+CPed::GetNearestDoor(CVehicle *veh, CVector &posToOpen)
+{
+ CVector *enterOffset = nil;
+ if (m_vehEnterType == CAR_DOOR_LF && veh->pDriver
+ || m_vehEnterType == CAR_DOOR_RF && veh->pPassengers[0]
+ || m_vehEnterType == CAR_DOOR_LR && veh->pPassengers[1]
+ || m_vehEnterType == CAR_DOOR_RR && veh->pPassengers[2])
+ {
+ enterOffset = &vecPedQuickDraggedOutCarAnimOffset;
+ }
+
+ CVector lfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LF);
+ CVector rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF);
+
+ // Right front door is closer
+ if ((lfPos - GetPosition()).MagnitudeSqr2D() >= (rfPos - GetPosition()).MagnitudeSqr2D()) {
+
+ if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) {
+
+ CPed *rfPassenger = veh->pPassengers[0];
+ if (!rfPassenger
+ || rfPassenger->m_leader != this && !m_ped_flagF4 && (veh->VehicleCreatedBy != MISSION_VEHICLE || m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER)
+ || veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) == 0) {
+
+ if ((veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF) == 0
+ || veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset) == 0) {
+ m_vehEnterType = CAR_DOOR_RF;
+ posToOpen = rfPos;
+ return;
+ }
+ }
+ } else {
+ if (!veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset))
+ return;
+ }
+ m_vehEnterType = CAR_DOOR_LF;
+ posToOpen = lfPos;
+ return;
+ }
+
+ if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_LF, enterOffset)) {
+ m_vehEnterType = CAR_DOOR_LF;
+ posToOpen = lfPos;
+ return;
+ }
+
+ if (veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, enterOffset)) {
+ m_vehEnterType = CAR_DOOR_RF;
+ posToOpen = rfPos;
+ }
+}
+
+bool
+CPed::GetNearestPassengerDoor(CVehicle *veh, CVector &posToOpen)
+{
+ CVector rfPos, lrPos, rrPos;
+ bool canEnter = false;
+
+ CVehicleModelInfo *vehModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(veh->m_modelIndex);
+
+ if (veh->m_modelIndex > MI_RHINO || veh->m_modelIndex != MI_BUS) {
+
+ CVector2D rfPosDist(999.0f, 999.0f);
+ CVector2D lrPosDist(999.0f, 999.0f);
+ CVector2D rrPosDist(999.0f, 999.0f);
+
+ if (!veh->pPassengers[0]
+ && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RF)
+ && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RF, nil)) {
+
+ rfPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF);
+ canEnter = true;
+ rfPosDist = rfPos - GetPosition();
+ }
+ if (vehModel->m_numDoors == 4) {
+ if (!veh->pPassengers[1]
+ && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_LR)
+ && veh->IsRoomForPedToLeaveCar(CAR_DOOR_LR, nil)) {
+ lrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_LR);
+ canEnter = true;
+ lrPosDist = lrPos - GetPosition();
+ }
+ if (!veh->pPassengers[2]
+ && !(veh->m_nGettingInFlags & CAR_DOOR_FLAG_RR)
+ && veh->IsRoomForPedToLeaveCar(CAR_DOOR_RR, nil)) {
+ rrPos = GetPositionToOpenCarDoor(veh, CAR_DOOR_RR);
+ canEnter = true;
+ rrPosDist = rrPos - GetPosition();
+ }
+
+ // When the door we should enter is blocked by some object.
+ if (!canEnter)
+ veh->ShufflePassengersToMakeSpace();
+ }
+
+ CVector2D nextToCompare = rfPosDist;
+ posToOpen = rfPos;
+ m_vehEnterType = CAR_DOOR_RF;
+ if (lrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) {
+ m_vehEnterType = CAR_DOOR_LR;
+ posToOpen = lrPos;
+ nextToCompare = lrPosDist;
+ }
+
+ if (rrPosDist.MagnitudeSqr() < nextToCompare.MagnitudeSqr()) {
+ m_vehEnterType = CAR_DOOR_RR;
+ posToOpen = rrPos;
+ }
+ return canEnter;
+
+ } else {
+ m_vehEnterType = CAR_DOOR_RF;
+ posToOpen = GetPositionToOpenCarDoor(veh, CAR_DOOR_RF);
+ return true;
+ }
+}
+
+int
+CPed::GetNextPointOnRoute(void)
+{
+ int16 nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint;
+
+ // Route is complete
+ if (nextPoint < 0 || nextPoint > 200 || m_routeLastPoint != CRouteNode::GetRouteThisPointIsOn(nextPoint)) {
+
+ switch (m_routeType) {
+ case PEDROUTE_STOP_WHEN_DONE:
+ nextPoint = -1;
+ break;
+ case PEDROUTE_GO_BACKWARD_WHEN_DONE:
+ m_routePointsBeingPassed = -m_routePointsBeingPassed;
+ nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint;
+ break;
+ case PEDROUTE_GO_TO_START_WHEN_DONE:
+ m_routePointsPassed = -1;
+ nextPoint = m_routePointsBeingPassed + m_routePointsPassed + m_routeStartPoint;
+ break;
+ default:
+ break;
+ }
+ }
+ return nextPoint;
+}
+
+// TODO: enum
+uint8
+CPed::GetPedRadioCategory(uint32 modelIndex)
+{
+ switch (modelIndex) {
+ case MI_MALE01:
+ case MI_FEMALE03:
+ case MI_PROSTITUTE2:
+ case MI_WORKER1:
+ case MI_MOD_MAN:
+ case MI_MOD_WOM:
+ case MI_ST_WOM:
+ case MI_FAN_WOM:
+ return 3;
+ case MI_TAXI_D:
+ case MI_PIMP:
+ case MI_MALE02:
+ case MI_FEMALE02:
+ case MI_FATFEMALE01:
+ case MI_FATFEMALE02:
+ case MI_DOCKER1:
+ case MI_WORKER2:
+ case MI_FAN_MAN2:
+ return 9;
+ case MI_GANG01:
+ case MI_GANG02:
+ case MI_SCUM_MAN:
+ case MI_SCUM_WOM:
+ case MI_HOS_WOM:
+ case MI_CONST1:
+ return 1;
+ case MI_GANG03:
+ case MI_GANG04:
+ case MI_GANG07:
+ case MI_GANG08:
+ case MI_CT_MAN2:
+ case MI_CT_WOM2:
+ case MI_B_MAN3:
+ case MI_SHOPPER3:
+ return 4;
+ case MI_GANG05:
+ case MI_GANG06:
+ case MI_GANG11:
+ case MI_GANG12:
+ case MI_CRIMINAL02:
+ case MI_B_WOM2:
+ case MI_ST_MAN:
+ case MI_HOS_MAN:
+ return 5;
+ case MI_FATMALE01:
+ case MI_LI_MAN2:
+ case MI_SHOPPER1:
+ case MI_CAS_MAN:
+ return 6;
+ case MI_PROSTITUTE:
+ case MI_P_WOM2:
+ case MI_LI_WOM2:
+ case MI_B_WOM3:
+ case MI_CAS_WOM:
+ return 2;
+ case MI_P_WOM1:
+ case MI_DOCKER2:
+ case MI_STUD_MAN:
+ return 7;
+ case MI_CT_MAN1:
+ case MI_CT_WOM1:
+ case MI_LI_MAN1:
+ case MI_LI_WOM1:
+ case MI_B_MAN1:
+ case MI_B_MAN2:
+ case MI_B_WOM1:
+ case MI_SHOPPER2:
+ case MI_STUD_WOM:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+// Some kind of VC leftover I think
+int
+CPed::GetWeaponSlot(eWeaponType weaponType)
+{
+ if (HasWeapon(weaponType))
+ return weaponType;
+ else
+ return -1;
+}
+
+void
+CPed::GoToNearestDoor(CVehicle *veh)
+{
+ CVector posToOpen;
+ GetNearestDoor(veh, posToOpen);
+ SetSeek(posToOpen, 0.5f);
+ SetMoveState(PEDMOVE_RUN);
+}
+
+bool
+CPed::HaveReachedNextPointOnRoute(float distToCountReached)
+{
+ if ((m_nextRoutePointPos - GetPosition()).Magnitude2D() >= distToCountReached)
+ return false;
+
+ m_routePointsPassed += m_routePointsBeingPassed;
+ return true;
+}
+
+void
+CPed::Idle(void)
+{
+ CVehicle *veh = m_pMyVehicle;
+ if (veh && veh->m_nGettingOutFlags && m_vehEnterType) {
+
+ if (veh->m_nGettingOutFlags & GetCarDoorFlag(m_vehEnterType)) {
+
+ if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT) {
+
+ CVector doorPos = GetPositionToOpenCarDoor(veh, m_vehEnterType);
+ CVector doorDist = GetPosition() - doorPos;
+
+ if (doorDist.MagnitudeSqr() < 0.25f) {
+ SetMoveState(PEDMOVE_WALK);
+ return;
+ }
+ }
+ }
+ }
+
+ CAnimBlendAssociation *armedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_ARMED);
+ CAnimBlendAssociation* unarmedIdleAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_IDLE_STANCE);
+ int waitTime;
+
+ if (m_nMoveState == PEDMOVE_STILL) {
+
+ eWeaponType curWeapon = GetWeapon()->m_eWeaponType;
+ if (!armedIdleAssoc ||
+ CTimer::GetTimeInMilliseconds() <= m_nWaitTimer && curWeapon != WEAPONTYPE_UNARMED && curWeapon != WEAPONTYPE_MOLOTOV && curWeapon != WEAPONTYPE_GRENADE) {
+
+ if ((!GetWeapon()->IsType2Handed() || curWeapon == WEAPONTYPE_SHOTGUN) && curWeapon != WEAPONTYPE_BASEBALLBAT
+ || !unarmedIdleAssoc || unarmedIdleAssoc->blendAmount <= 0.95f || m_nWaitState != WAITSTATE_FALSE || CTimer::GetTimeInMilliseconds() <= m_nWaitTimer) {
+
+ m_moved = CVector2D(0.0f, 0.0f);
+ return;
+ }
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_IDLE_ARMED, 3.0f);
+ waitTime = CGeneral::GetRandomNumberInRange(4000, 7500);
+ } else {
+ armedIdleAssoc->blendDelta = -2.0f;
+ armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ waitTime = CGeneral::GetRandomNumberInRange(3000, 8500);
+ }
+ m_nWaitTimer = CTimer::GetTimeInMilliseconds() + waitTime;
+ } else {
+ if (armedIdleAssoc) {
+ armedIdleAssoc->blendDelta = -8.0f;
+ armedIdleAssoc->flags |= ASSOC_DELETEFADEDOUT;
+ m_nWaitTimer = 0;
+ }
+ if (!IsPlayer())
+ SetMoveState(PEDMOVE_STILL);
+ }
+ m_moved = CVector2D(0.0f, 0.0f);
+}
+
+void
+CPed::InTheAir(void)
+{
+ CColPoint foundCol;
+ CEntity *foundEnt;
+
+ CVector ourPos = GetPosition();
+ CVector bitBelow = GetPosition();
+ bitBelow.z -= 4.04f;
+
+ if (m_vecMoveSpeed.z < 0.0f && !bIsPedDieAnimPlaying) {
+ if (m_nPedState != PED_DIE && m_nPedState != PED_DEAD) {
+ if (CWorld::ProcessLineOfSight(ourPos, bitBelow, foundCol, foundEnt, true, true, false, true, false, false, false)) {
+ if (GetPosition().z - foundCol.point.z < 1.3f)
+ SetLanding();
+ } else {
+ if (!RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL)) {
+ if (m_vecMoveSpeed.z < -0.1f)
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_FALL, 4.0f);
+ }
+ }
+ }
+ }
+}
+
+void
+CPed::SetLanding(void)
+{
+ if (m_nPedState == PED_DIE || m_nPedState == PED_DEAD)
+ return;
+
+ CAnimBlendAssociation *fallAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_FALL_FALL);
+ CAnimBlendAssociation *landAssoc;
+
+ RpAnimBlendClumpSetBlendDeltas(GetClump(), ASSOC_PARTIAL, -1000.0f);
+ if (fallAssoc) {
+ landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_COLLAPSE);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_COLLAPSE, 1.0f);
+
+ if (IsPlayer())
+ Say(SOUND_PED_LAND);
+
+ } else {
+ landAssoc = CAnimManager::AddAnimation(GetClump(), ASSOCGRP_STD, ANIM_FALL_LAND);
+ DMAudio.PlayOneShot(m_audioEntityId, SOUND_FALL_LAND, 1.0f);
+ }
+
+ landAssoc->SetFinishCallback(PedLandCB, this);
+ bIsInTheAir = false;
+ bIsLanding = true;
+}
+
+void
+CPed::Initialise(void)
+{
+ debug("Initialising CPed...\n");
+ CPedType::Initialise();
+ LoadFightData();
+ SetAnimOffsetForEnterOrExitVehicle();
+ debug("CPed ready\n");
+}
+
+void
+CPed::SetAnimOffsetForEnterOrExitVehicle(void)
+{
+ // FIX: If there were no translations on enter anims, there were overflows all over this function.
+
+ CAnimBlendHierarchy *enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_JACKED_LHS)->hierarchy;
+ CAnimBlendSequence *seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedDraggedOutCarAnimOffset = lastFrame->translation;
+ }
+ }
+
+ enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LHS)->hierarchy;
+ seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedCarDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedCarDoorAnimOffset = lastFrame->translation;
+ }
+ }
+
+ enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_GETIN_LOW_LHS)->hierarchy;
+ seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedCarDoorLoAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedCarDoorLoAnimOffset = lastFrame->translation;
+ }
+ }
+
+ enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_CAR_QJACKED)->hierarchy;
+ seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedQuickDraggedOutCarAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedQuickDraggedOutCarAnimOffset = lastFrame->translation;
+ }
+ }
+
+ enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_VAN_GETIN_L)->hierarchy;
+ seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedVanRearDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedVanRearDoorAnimOffset = lastFrame->translation;
+ }
+ }
+
+ enterAssoc = CAnimManager::GetAnimAssociation(ASSOCGRP_STD, ANIM_TRAIN_GETOUT)->hierarchy;
+ seq = enterAssoc->sequences;
+ CAnimManager::UncompressAnimation(enterAssoc);
+ if (seq->numFrames > 0) {
+ if (!seq->HasTranslation())
+ vecPedTrainDoorAnimOffset = CVector(0.0f, 0.0f, 0.0f);
+ else {
+ KeyFrameTrans* lastFrame = (KeyFrameTrans*)seq->GetKeyFrame(seq->numFrames - 1);
+ vecPedTrainDoorAnimOffset = lastFrame->translation;
+ }
+ }
+}
+
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); }
-WRAPPER void CPed::FinishDieAnimCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D3950); }
-WRAPPER void CPed::FinishedWaitCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D6520); }
-WRAPPER void CPed::FinishLaunchCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7490); }
-WRAPPER void CPed::FinishHitHeadCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A80); }
WRAPPER void CPed::PedAnimGetInCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEC80); }
WRAPPER void CPed::PedAnimDoorOpenCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DE500); }
WRAPPER void CPed::PedAnimPullPedOutCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4DEAF0); }
@@ -5711,9 +7677,7 @@ WRAPPER void CPed::PedSetQuickDraggedOutCarPositionCB(CAnimBlendAssociation* dra
WRAPPER void CPed::PedSetDraggedOutCarPositionCB(CAnimBlendAssociation* dragAssoc, void* arg) { EAXJMP(0x4E2920); }
WRAPPER void CPed::PedSetInTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E3290); }
WRAPPER void CPed::PedSetOutTrainCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E36E0); }
-WRAPPER void CPed::FinishFightMoveCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E9830); }
WRAPPER void CPed::PedAnimDoorCloseRollingCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4E4B90); }
-WRAPPER void CPed::FinishJumpCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4D7A50); }
WRAPPER void CPed::PedLandCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4CE8A0); }
WRAPPER void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg) { EAXJMP(0x4C6580); }
@@ -5825,7 +7789,6 @@ STARTPATCHES
InjectHook(0x4D09B0, &CPed::SetFall, PATCH_JUMP);
InjectHook(0x4E6220, &CPed::SetAttack, PATCH_JUMP);
InjectHook(0x4E7530, &CPed::StartFightAttack, PATCH_JUMP);
- InjectHook(0x4E9870, &CPed::LoadFightData, PATCH_JUMP);
InjectHook(0x4E8EC0, &CPed::FightStrike, PATCH_JUMP);
InjectHook(0x4CCE20, &CPed::GetLocalDirection, PATCH_JUMP);
InjectHook(0x4E8E20, &CPed::PlayHitSound, PATCH_JUMP);
@@ -5846,4 +7809,35 @@ STARTPATCHES
InjectHook(0x4D15A0, (void (CPed::*)(CEntity*, float)) &CPed::SetSeek, PATCH_JUMP);
InjectHook(0x4EB5C0, &CPed::DoesLOSBulletHitPed, PATCH_JUMP);
InjectHook(0x4E3EC0, &CPed::DuckAndCover, PATCH_JUMP);
-ENDPATCHES
+ InjectHook(0x4E8D30, &CPed::EndFight, PATCH_JUMP);
+ InjectHook(0x4E0D30, &CPed::EnterCar, PATCH_JUMP);
+ InjectHook(0x4E2E50, &CPed::GetNearestTrainPedPosition, PATCH_JUMP);
+ InjectHook(0x4E2D70, &CPed::GetNearestTrainDoor, PATCH_JUMP);
+ InjectHook(0x4E33D0, &CPed::LineUpPedWithTrain, PATCH_JUMP);
+ InjectHook(0x4E18D0, &CPed::ExitCar, PATCH_JUMP);
+ InjectHook(0x4E7EE0, &CPed::Fight, PATCH_JUMP);
+ InjectHook(0x4D3950, &CPed::FinishDieAnimCB, PATCH_JUMP);
+ InjectHook(0x4E9830, &CPed::FinishFightMoveCB, PATCH_JUMP);
+ InjectHook(0x4D7A80, &CPed::FinishHitHeadCB, PATCH_JUMP);
+ InjectHook(0x4D7A50, &CPed::FinishJumpCB, PATCH_JUMP);
+ InjectHook(0x4D7490, &CPed::FinishLaunchCB, PATCH_JUMP);
+ InjectHook(0x4D6520, &CPed::FinishedWaitCB, PATCH_JUMP);
+ InjectHook(0x4D5D80, &CPed::Wait, PATCH_JUMP);
+ InjectHook(0x4E3A90, &CPed::FindBestCoordsFromNodes, PATCH_JUMP);
+ InjectHook(0x4D2E70, &CPed::SeekFollowingPath, PATCH_JUMP);
+ InjectHook(0x4D1640, &CPed::Seek, PATCH_JUMP);
+ InjectHook(0x4D3020, &CPed::FollowPath, PATCH_JUMP);
+ InjectHook(0x4D1ED0, &CPed::Flee, PATCH_JUMP);
+ InjectHook(0x4E1CF0, &CPed::GetNearestDoor, PATCH_JUMP);
+ InjectHook(0x4DF420, &CPed::GetFormationPosition, PATCH_JUMP);
+ InjectHook(0x4E1F30, &CPed::GetNearestPassengerDoor, PATCH_JUMP);
+ InjectHook(0x4D0690, &CPed::Idle, PATCH_JUMP);
+ InjectHook(0x4DD720, &CPed::GetNextPointOnRoute, PATCH_JUMP);
+ InjectHook(0x4D7B50, &CPed::GetPedRadioCategory, PATCH_JUMP);
+ InjectHook(0x4CFA40, &CPed::GetWeaponSlot, PATCH_JUMP);
+ InjectHook(0x4E2220, &CPed::GoToNearestDoor, PATCH_JUMP);
+ InjectHook(0x4DD7B0, &CPed::HaveReachedNextPointOnRoute, PATCH_JUMP);
+ InjectHook(0x4D0D10, &CPed::InTheAir, PATCH_JUMP);
+ InjectHook(0x4C5270, &CPed::Initialise, PATCH_JUMP);
+ InjectHook(0x4D0E40, &CPed::SetLanding, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/peds/Ped.h b/src/peds/Ped.h
index db19619b..264a67a8 100644
--- a/src/peds/Ped.h
+++ b/src/peds/Ped.h
@@ -22,6 +22,20 @@ struct CPedAudioData
int m_nMaxRandomDelayTime;
};
+enum
+{
+ ENDFIGHT_NORMAL,
+ ENDFIGHT_WITH_A_STEP,
+ ENDFIGHT_FAST
+};
+
+enum PedRouteType
+{
+ PEDROUTE_STOP_WHEN_DONE = 1,
+ PEDROUTE_GO_BACKWARD_WHEN_DONE,
+ PEDROUTE_GO_TO_START_WHEN_DONE
+};
+
struct FightMove
{
AnimationId animId;
@@ -152,7 +166,7 @@ enum PedLineUpPhase {
enum PedOnGroundState {
NO_PED,
- PED_BELOW_PLAYER,
+ PED_IN_FRONT_OF_ATTACKER,
PED_ON_THE_FLOOR,
PED_DEAD_ON_THE_FLOOR
};
@@ -241,7 +255,7 @@ public:
// cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CPed.h from R*
uint8 bIsStanding : 1;
uint8 m_ped_flagA2 : 1;
- uint8 m_ped_flagA4 : 1; // stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
+ uint8 bIsAttacking : 1; // doesn't reset after fist fight, also stores (CTimer::GetTimeInMilliseconds() < m_lastHitTime)
uint8 bIsPointingGunAt : 1;
uint8 bIsLooking : 1;
uint8 m_ped_flagA20 : 1; // "look" method? - probably missing in SA
@@ -253,7 +267,7 @@ public:
uint8 bIsTalking : 1;
uint8 bIsInTheAir : 1;
uint8 bIsLanding : 1;
- uint8 m_ped_flagB20 : 1;
+ uint8 bIsRunning : 1; // not fleeing
uint8 m_ped_flagB40 : 1;
uint8 m_ped_flagB80 : 1;
@@ -296,7 +310,7 @@ public:
uint8 m_ped_flagG1 : 1;
uint8 m_ped_flagG2 : 1;
uint8 m_ped_flagG4 : 1;
- uint8 m_ped_flagG8 : 1;
+ uint8 m_ped_flagG8 : 1; // ped starts to go somewhere when set
uint8 m_ped_flagG10 : 1;
uint8 m_ped_flagG20 : 1;
uint8 m_ped_flagG40 : 1;
@@ -328,9 +342,7 @@ public:
eObjective m_prevObjective;
CPed *m_pedInObjective;
CVehicle *m_carInObjective;
- uint32 field_174;
- uint32 field_178;
- uint32 field_17C;
+ CVector m_nextRoutePointPos;
CPed *m_leader;
uint32 m_pedFormation;
uint32 m_fearFlags;
@@ -363,15 +375,15 @@ public:
private:
int8 _pad2B5[3];
public:
- CPathNode *m_pNextPathNode;
CPathNode *m_pLastPathNode;
+ CPathNode *m_pNextPathNode;
float m_fHealth;
float m_fArmour;
int16 m_routeLastPoint;
- uint16 m_routePoints;
- int16 m_routePos;
+ uint16 m_routeStartPoint;
+ int16 m_routePointsPassed;
int16 m_routeType;
- int16 m_routeCurDir;
+ int16 m_routePointsBeingPassed;
uint16 field_2D2;
CVector2D m_moved;
float m_fRotationCur;
@@ -382,12 +394,12 @@ public:
CEntity *m_pCurrentPhysSurface;
CVector m_vecOffsetFromPhysSurface;
CEntity *m_pCurSurface;
- CVector m_vecSeekVehicle;
+ CVector m_vecSeekPos;
CEntity *m_pSeekTarget;
CVehicle *m_pMyVehicle;
bool bInVehicle;
uint8 pad_315[3];
- float field_318;
+ float m_distanceToCountSeekDone;
bool bRunningToPhone;
uint8 field_31D;
int16 m_phoneId;
@@ -400,8 +412,8 @@ public:
float m_fleeFromPosY;
CEntity *m_fleeFrom;
uint32 m_fleeTimer;
- uint32 field_344;
- uint32 m_lastThreatTimer;
+ CEntity* m_collidingEntityWhileFleeing;
+ uint32 m_collidingThingTimer;
CEntity *m_pCollidingEntity;
uint8 m_stateUnused;
uint8 pad_351[3];
@@ -418,7 +430,7 @@ public:
PedFightMoves m_lastFightMove;
uint8 m_fightButtonPressure;
int8 m_fightUnk2; // TODO
- uint8 m_fightUnk1; // TODO
+ bool m_takeAStepAfterAttack;
uint8 pad_4B3;
CFire *m_pFire;
CEntity *m_pLookTarget;
@@ -429,7 +441,7 @@ public:
uint32 m_lookTimer;
uint32 m_standardTimer;
uint32 m_attackTimer;
- uint32 m_lastHitTime;
+ uint32 m_lastHitTime; // obviously not correct
uint32 m_hitRecoverTimer;
uint32 m_objectiveTimer;
uint32 m_duckTimer;
@@ -560,7 +572,6 @@ public:
void SetEvasiveDive(CPhysical*, uint8);
void SetAttack(CEntity*);
void StartFightAttack(uint8);
- void LoadFightData(void);
void SetWaitState(eWaitState, void*);
bool FightStrike(CVector&);
int GetLocalDirection(CVector2D&);
@@ -583,11 +594,38 @@ public:
void MakeTyresMuddySectorList(CPtrList&);
uint8 DoesLOSBulletHitPed(CColPoint &point);
bool DuckAndCover(void);
+ void EndFight(uint8);
+ void EnterCar(void);
+ uint8 GetNearestTrainPedPosition(CVehicle*, CVector&);
+ uint8 GetNearestTrainDoor(CVehicle*, CVector&);
+ void LineUpPedWithTrain(void);
+ void ExitCar(void);
+ void Fight(void);
+ bool FindBestCoordsFromNodes(CVector unused, CVector* a6);
+ void Wait(void);
+ void ProcessObjective(void);
+ bool SeekFollowingPath(CVector*);
+ void Flee(void);
+ void FollowPath(void);
+ CVector GetFormationPosition(void);
+ void GetNearestDoor(CVehicle*, CVector&);
+ bool GetNearestPassengerDoor(CVehicle*, CVector&);
+ int GetNextPointOnRoute(void);
+ uint8 GetPedRadioCategory(uint32);
+ int GetWeaponSlot(eWeaponType);
+ void GoToNearestDoor(CVehicle*);
+ bool HaveReachedNextPointOnRoute(float a2);
+ void Idle(void);
+ void InTheAir(void);
+ void SetLanding(void);
// Static methods
static CVector GetLocalPositionToOpenCarDoor(CVehicle *veh, uint32 component, float offset);
static CVector GetPositionToOpenCarDoor(CVehicle *veh, uint32 component, float seatPosMult);
static CVector GetPositionToOpenCarDoor(CVehicle* veh, uint32 component);
+ static void Initialise(void);
+ static void SetAnimOffsetForEnterOrExitVehicle(void);
+ static void LoadFightData(void);
// Callbacks
static RwObject *SetPedAtomicVisibilityCB(RwObject *object, void *data);
@@ -640,6 +678,9 @@ public:
void SetPedStats(ePedStats);
bool IsGangMember(void);
void Die(void);
+ void EnterTrain(void);
+ void ExitTrain(void);
+ void Fall(void);
bool HasWeapon(uint8 weaponType) { return m_weapons[weaponType].m_eWeaponType == weaponType; }
CWeapon &GetWeapon(uint8 weaponType) { return m_weapons[weaponType]; }
@@ -649,18 +690,17 @@ public:
void SetPedState(PedState state) { m_nPedState = state; }
// set by 0482:set_threat_reaction_range_multiplier opcode
- static uint16 &distanceMultToCountPedNear;
+ static uint16 &nThreatReactionRangeMultiplier;
- static CVector &offsetToOpenRegularCarDoor;
- static CVector &offsetToOpenLowCarDoor;
- static CVector &offsetToOpenVanDoor;
static bool &bNastyLimbsCheat;
static bool &bPedCheat2;
static bool &bPedCheat3;
- static CColPoint &ms_tempColPoint;
- static uint16 &unknownFightThing; // TODO
- static FightMove (&ms_fightMoves)[24];
- static CPedAudioData (&PedAudioData)[38];
+ static CVector2D &ms_vec2DFleePosition;
+ static CPedAudioData (&CommentWaitTime)[38];
+
+#ifndef FINAL
+ static bool bUnusedFightThingOnPlayer;
+#endif
};
void FinishFuckUCB(CAnimBlendAssociation *assoc, void *arg);
diff --git a/src/peds/PedRoutes.cpp b/src/peds/PedRoutes.cpp
new file mode 100644
index 00000000..c572d8be
--- /dev/null
+++ b/src/peds/PedRoutes.cpp
@@ -0,0 +1,6 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "PedRoutes.h"
+
+WRAPPER int16 CRouteNode::GetRouteThisPointIsOn(int16) { EAXJMP(0x4EE7A0); } \ No newline at end of file
diff --git a/src/peds/PedRoutes.h b/src/peds/PedRoutes.h
new file mode 100644
index 00000000..2530ebe6
--- /dev/null
+++ b/src/peds/PedRoutes.h
@@ -0,0 +1,7 @@
+#pragma once
+
+class CRouteNode
+{
+public:
+ static int16 GetRouteThisPointIsOn(int16 point);
+}; \ No newline at end of file