summaryrefslogtreecommitdiff
path: root/src/peds/CopPed.cpp
diff options
context:
space:
mode:
authorclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
committerclaude-bot <[email protected]>2026-07-13 12:27:07 +0000
commit9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686 (patch)
treea84756b82513739a2672db3a1f0ec579db6d18ff /src/peds/CopPed.cpp
downloadre3-9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686.tar.gz
re3-9f61c9e6ac6b1ac5692cf6352d2ebbd47a31a686.zip
Import Cai1Hsu/re3 @ miami (reVC / GTA:VC decompilation)HEADmiami
Snapshot import (no upstream history) into git.ancap.in.ua/claude, per @lzcnt. Source: https://github.com/Cai1Hsu/re3 branch miami.
Diffstat (limited to 'src/peds/CopPed.cpp')
-rw-r--r--src/peds/CopPed.cpp874
1 files changed, 874 insertions, 0 deletions
diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp
new file mode 100644
index 0000000..36bb02b
--- /dev/null
+++ b/src/peds/CopPed.cpp
@@ -0,0 +1,874 @@
+#include "common.h"
+
+#include "World.h"
+#include "PlayerPed.h"
+#include "CopPed.h"
+#include "Wanted.h"
+#include "DMAudio.h"
+#include "ModelIndices.h"
+#include "Vehicle.h"
+#include "RpAnimBlend.h"
+#include "AnimBlendAssociation.h"
+#include "General.h"
+#include "ZoneCull.h"
+#include "PathFind.h"
+#include "RoadBlocks.h"
+#include "CarCtrl.h"
+#include "Renderer.h"
+#include "Camera.h"
+#include "PedPlacement.h"
+#include "Ropes.h"
+#include "Stinger.h"
+
+CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
+{
+ m_nCopType = copType;
+ switch (copType) {
+ case COP_STREET:
+ SetModelIndex(MI_COP);
+ GiveWeapon(WEAPONTYPE_NIGHTSTICK, 1000, true);
+ GiveDelayedWeapon(WEAPONTYPE_COLT45, 1000);
+ m_currentWeapon = WEAPONTYPE_UNARMED;
+ m_fArmour = 0.0f;
+ m_wepSkills = 208; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 60;
+ break;
+ case COP_FBI:
+ SetModelIndex(MI_FBI);
+ GiveDelayedWeapon(WEAPONTYPE_MP5, 1000);
+ SetCurrentWeapon(WEAPONTYPE_MP5);
+ m_fArmour = 100.0f;
+ m_wepSkills = 176; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 76;
+ break;
+ case COP_SWAT:
+ case COP_HELI_SWAT:
+ SetModelIndex(MI_SWAT);
+ GiveDelayedWeapon(WEAPONTYPE_UZI, 1000);
+ SetCurrentWeapon(WEAPONTYPE_UZI);
+ m_fArmour = 50.0f;
+ m_wepSkills = 32; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 68;
+ break;
+ case COP_ARMY:
+ SetModelIndex(MI_ARMY);
+ GiveDelayedWeapon(WEAPONTYPE_MP5, 1000);
+ SetCurrentWeapon(WEAPONTYPE_MP5);
+ m_fArmour = 100.0f;
+ m_wepSkills = 32; /* TODO: what is this? seems unused */
+ m_wepAccuracy = 84;
+ break;
+ case COP_MIAMIVICE:
+ switch (modifier) {
+ case 0: SetModelIndex(MI_VICE1); break;
+ case 1: SetModelIndex(MI_VICE2); break;
+ case 2: SetModelIndex(MI_VICE3); break;
+ case 3: SetModelIndex(MI_VICE4); break;
+ case 4: SetModelIndex(MI_VICE5); break;
+ case 5: SetModelIndex(MI_VICE6); break;
+ case 6: SetModelIndex(MI_VICE7); break;
+ case 7: SetModelIndex(MI_VICE8); break;
+ default: assert(0); break;
+ }
+ GiveDelayedWeapon(WEAPONTYPE_UZI, 1000);
+ SetCurrentWeapon(WEAPONTYPE_UZI);
+ m_fArmour = 100.0f;
+ m_wepSkills = 176;
+ m_wepAccuracy = 76;
+ break;
+ }
+ m_bIsInPursuit = false;
+ field_5FE = 1;
+ m_bIsDisabledCop = false;
+ m_attackTimer = 0;
+ m_bBeatingSuspect = false;
+ m_bStopAndShootDisabledZone = false;
+ m_bDragsPlayerFromCar = false;
+ m_bZoneDisabled = false;
+ field_628 = -1;
+ m_nRoadblockVeh = nil;
+ m_bThrowsSpikeTrap = false;
+ m_pRopeEntity = nil;
+ m_fAbseilPos = 0.0f;
+ m_nHassleTimer = 0;
+ field_61C = 0;
+ field_624 = 0;
+ m_pStinger = new CStinger;
+ SetWeaponLockOnTarget(nil);
+}
+
+CCopPed::~CCopPed()
+{
+ ClearPursuit();
+ m_pStinger->Remove();
+ delete m_pStinger;
+}
+
+// Parameter should always be CPlayerPed, but it seems they considered making civilians arrestable at some point
+void
+CCopPed::SetArrestPlayer(CPed *player)
+{
+ if (!IsPedInControl() || !player)
+ return;
+
+ player->Say(SOUND_PED_PLAYER_REACTTOCOP);
+ Say(SOUND_PED_ARREST_COP);
+
+ if (player->EnteringCar()) {
+ if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer)
+ return;
+
+ // why?
+ player->bGonnaKillTheCarJacker = true;
+
+ // Genius
+ FindPlayerPed()->m_bCanBeDamaged = false;
+ ((CPlayerPed*)player)->m_pArrestingCop = this;
+ this->RegisterReference((CEntity**) &((CPlayerPed*)player)->m_pArrestingCop);
+
+ } else if (player->m_nPedState != PED_DIE && player->m_nPedState != PED_DEAD && player->m_nPedState != PED_ARRESTED) {
+ player->m_nLastPedState = player->m_nPedState;
+ player->SetPedState(PED_ARRESTED);
+
+ FindPlayerPed()->m_bCanBeDamaged = false;
+ ((CPlayerPed*)player)->m_pArrestingCop = this;
+ this->RegisterReference((CEntity**) &((CPlayerPed*)player)->m_pArrestingCop);
+ }
+
+ SetPedState(PED_ARREST_PLAYER);
+ SetObjective(OBJECTIVE_NONE);
+ m_prevObjective = OBJECTIVE_NONE;
+ bIsPointingGunAt = false;
+ m_pSeekTarget = player;
+ m_pSeekTarget->RegisterReference((CEntity**) &m_pSeekTarget);
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ if (player->InVehicle()) {
+ player->m_pMyVehicle->m_nNumGettingIn = 0;
+ player->m_pMyVehicle->m_nGettingInFlags = 0;
+ player->m_pMyVehicle->bIsHandbrakeOn = true;
+ player->m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED);
+ }
+ if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED || GetWeapon()->m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE)
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+}
+
+void
+CCopPed::ClearPursuit(void)
+{
+ CPlayerPed *player = FindPlayerPed();
+ if (!player)
+ return;
+
+ CWanted *wanted = player->m_pWanted;
+ int ourCopId = 0;
+ bool foundMyself = false;
+ int biggestCopId = 0;
+ if (!m_bIsInPursuit)
+ return;
+
+ m_bIsInPursuit = false;
+ for (int i = 0; i < Max(wanted->m_MaxCops, wanted->m_CurrentCops); ++i) {
+ if (!foundMyself && wanted->m_pCops[i] == this) {
+ wanted->m_pCops[i] = nil;
+ --wanted->m_CurrentCops;
+ foundMyself = true;
+ ourCopId = i;
+ biggestCopId = i;
+ } else {
+ if (wanted->m_pCops[i])
+ biggestCopId = i;
+ }
+ }
+ if (foundMyself && biggestCopId > ourCopId) {
+ wanted->m_pCops[ourCopId] = wanted->m_pCops[biggestCopId];
+ wanted->m_pCops[biggestCopId] = nil;
+ }
+ m_objective = OBJECTIVE_NONE;
+ m_prevObjective = OBJECTIVE_NONE;
+ m_nLastPedState = PED_NONE;
+ bIsRunning = false;
+ bNotAllowedToDuck = false;
+ bKindaStayInSamePlace = false;
+ m_bStopAndShootDisabledZone = false;
+ m_bDragsPlayerFromCar = false;
+ m_bZoneDisabled = false;
+ ClearObjective();
+ if (IsPedInControl()) {
+ if (!m_pMyVehicle || wanted->GetWantedLevel() != 0) {
+ if (m_pMyVehicle && (m_pMyVehicle->GetPosition() - GetPosition()).MagnitudeSqr() < sq(5.0f)) {
+ m_nLastPedState = PED_IDLE;
+ SetSeek((CEntity*)m_pMyVehicle, 2.5f);
+ } else {
+ m_nLastPedState = PED_WANDER_PATH;
+ SetFindPathAndFlee(FindPlayerPed()->GetPosition(), 10000, true);
+ }
+ } else {
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ }
+}
+
+// TODO: I don't know why they needed that parameter.
+void
+CCopPed::SetPursuit(bool ignoreCopLimit)
+{
+ if (CTimer::GetTimeInMilliseconds() < field_61C)
+ return;
+
+ CWanted *wanted = FindPlayerPed()->m_pWanted;
+ if (m_bIsInPursuit || !IsPedInControl())
+ return;
+
+ if (wanted->m_CurrentCops < wanted->m_MaxCops || ignoreCopLimit) {
+ for (int i = 0; i < wanted->m_MaxCops; ++i) {
+ if (!wanted->m_pCops[i]) {
+ m_bIsInPursuit = true;
+ ++wanted->m_CurrentCops;
+ wanted->m_pCops[i] = this;
+ break;
+ }
+ }
+ if (m_bIsInPursuit) {
+ ClearObjective();
+ m_prevObjective = OBJECTIVE_NONE;
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, FindPlayerPed());
+ SetObjectiveTimer(0);
+ bNotAllowedToDuck = true;
+ bIsRunning = true;
+ m_bStopAndShootDisabledZone = false;
+ }
+ }
+}
+
+void
+CCopPed::ArrestPlayer(void)
+{
+ m_pVehicleAnim = nil;
+ CPed *suspect = (CPed*)m_pSeekTarget;
+ if (suspect) {
+ if (suspect->CanSetPedState())
+ suspect->SetPedState(PED_ARRESTED);
+
+ if (suspect->bInVehicle && m_pMyVehicle && suspect->m_pMyVehicle == m_pMyVehicle) {
+
+ // BUG? I will never understand why they used LINE_UP_TO_CAR_2...
+ LineUpPedWithCar(LINE_UP_TO_CAR_2);
+ }
+
+ if (suspect && (suspect->m_nPedState == PED_ARRESTED || suspect->DyingOrDead() || suspect->EnteringCar())) {
+
+ CAnimBlendAssociation *arrestAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_STD_ARREST);
+ if (!arrestAssoc || arrestAssoc->blendDelta < 0.0f)
+ CAnimManager::BlendAnimation(GetClump(), ASSOCGRP_STD, ANIM_STD_ARREST, 4.0f);
+
+ CVector suspMidPos;
+ suspect->m_pedIK.GetComponentPosition(suspMidPos, PED_MID);
+ m_fRotationDest = CGeneral::GetRadianAngleBetweenPoints(suspMidPos.x, suspMidPos.y,
+ GetPosition().x, GetPosition().y);
+
+ m_fRotationCur = m_fRotationDest;
+ SetOrientation(0.0f, 0.0f, m_fRotationCur);
+ } else {
+ ClearPursuit();
+ }
+ } else {
+ ClearPursuit();
+ }
+}
+
+void
+CCopPed::ScanForCrimes(void)
+{
+ CVehicle *playerVeh = FindPlayerVehicle();
+
+ // Look for car alarms
+ if (playerVeh && playerVeh->IsCar()) {
+ if (playerVeh->IsAlarmOn()) {
+ if ((playerVeh->GetPosition() - GetPosition()).MagnitudeSqr() < sq(20.0f))
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ }
+ }
+
+ // Look for stolen cop cars
+ if (!m_bIsInPursuit) {
+ CPlayerPed *player = FindPlayerPed();
+ if ((m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER || m_objective == OBJECTIVE_ENTER_CAR_AS_PASSENGER)
+ && player->m_pWanted->GetWantedLevel() == 0) {
+
+ if (player->m_pMyVehicle
+#ifdef FIX_BUGS
+ && m_pMyVehicle == player->m_pMyVehicle
+#endif
+ && player->m_pMyVehicle->bIsLawEnforcer)
+ player->SetWantedLevelNoDrop(1);
+ }
+ }
+}
+
+void
+CCopPed::CopAI(void)
+{
+ CWanted *wanted = FindPlayerPed()->m_pWanted;
+ int wantedLevel = wanted->GetWantedLevel();
+ CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+
+ if (wanted->m_bIgnoredByEveryone || wanted->m_bIgnoredByCops) {
+ if (m_nPedState != PED_ARREST_PLAYER)
+ ClearPursuit();
+
+ return;
+ }
+ if (CCullZones::NoPolice() && m_bIsInPursuit && !m_bIsDisabledCop) {
+ if (bHitSomethingLastFrame) {
+ m_bZoneDisabled = true;
+ m_bIsDisabledCop = true;
+ bKindaStayInSamePlace = true;
+ bIsRunning = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ SetIdle();
+ ClearObjective();
+ ClearPursuit();
+ m_prevObjective = OBJECTIVE_NONE;
+ m_nLastPedState = PED_NONE;
+ SetAttackTimer(0);
+
+ // Safe distance for disabled zone? Or to just make game easier?
+ if (m_fDistanceToTarget > 15.0f)
+ m_bStopAndShootDisabledZone = true;
+ }
+ } else if (m_bZoneDisabled && !CCullZones::NoPolice()) {
+ m_bZoneDisabled = false;
+ m_bIsDisabledCop = false;
+ m_bStopAndShootDisabledZone = false;
+ bKindaStayInSamePlace = false;
+ bCrouchWhenShooting = false;
+ bDuckAndCover = false;
+ ClearPursuit();
+ }
+ if (wantedLevel > 0) {
+ if (!m_bIsDisabledCop) {
+ // Turn and shoot the player's vehicle, if possible
+ if (!m_bIsInPursuit && !GetWeapon()->IsTypeMelee() && FindPlayerVehicle() && m_fDistanceToTarget < CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange) {
+ if (FindPlayerVehicle()->m_vecMoveSpeed.Magnitude2D() > 0.1f) {
+ CVector2D distToVeh = GetPosition() - FindPlayerVehicle()->GetPosition();
+ distToVeh.Normalise();
+ CVector2D vehSpeed = FindPlayerVehicle()->m_vecMoveSpeed;
+ vehSpeed.Normalise();
+
+ if (DotProduct2D(distToVeh, vehSpeed) > 0.8f) {
+ SetLookFlag(playerOrHisVeh, true);
+ SetMoveState(PEDMOVE_STILL);
+ if (TurnBody()) {
+ SetAttack(FindPlayerVehicle());
+ SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f));
+ SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 300.0f));
+ }
+ } else if (m_nPedState == PED_ATTACK)
+ RestorePreviousState();
+ }
+ }
+
+ if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
+ CCopPed *copFarthestToTarget = nil;
+ float copFarthestToTargetDist = m_fDistanceToTarget;
+
+ int oldCopNum = wanted->m_CurrentCops;
+ int maxCops = wanted->m_MaxCops;
+
+ for (int i = 0; i < Max(maxCops, oldCopNum); i++) {
+ CCopPed *cop = wanted->m_pCops[i];
+ if (cop && cop->m_fDistanceToTarget > copFarthestToTargetDist) {
+ copFarthestToTargetDist = cop->m_fDistanceToTarget;
+ copFarthestToTarget = wanted->m_pCops[i];
+ }
+ }
+
+ if (m_bIsInPursuit) {
+ if (copFarthestToTarget && oldCopNum > maxCops) {
+ if (copFarthestToTarget == this && m_fDistanceToTarget > 10.0f) {
+ ClearPursuit();
+ } else if(copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+ }
+ } else {
+ if (oldCopNum < maxCops) {
+ SetPursuit(true);
+ } else {
+ if (m_fDistanceToTarget <= 10.0f || copFarthestToTarget && m_fDistanceToTarget < copFarthestToTargetDist) {
+ if (copFarthestToTarget && copFarthestToTargetDist > 10.0f)
+ copFarthestToTarget->ClearPursuit();
+
+ SetPursuit(true);
+ }
+ }
+ }
+ } else
+ SetPursuit(false);
+
+ if (!m_bIsInPursuit)
+ return;
+
+ if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
+ // i.e. if player is on top of car, cop will still use colt45.
+ SetCurrentWeapon(GetWeaponSlot(WEAPONTYPE_NIGHTSTICK) >= 0 ? WEAPONTYPE_NIGHTSTICK : WEAPONTYPE_UNARMED);
+ }
+
+ if (m_bBeatingSuspect && GetWeapon()->m_eWeaponType == WEAPONTYPE_NIGHTSTICK)
+ Say(SOUND_PED_PULLOUTWEAPON);
+
+ if (FindPlayerVehicle()) {
+ if (m_bBeatingSuspect) {
+ --wanted->m_CopsBeatingSuspect;
+ m_bBeatingSuspect = false;
+ }
+ if (m_fDistanceToTarget * FindPlayerSpeed().Magnitude() > 4.0f)
+ ClearPursuit();
+ }
+ return;
+ }
+ SetCurrentWeapon(WEAPONTYPE_COLT45);
+ CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
+ float weaponRange = weaponInfo->m_fRange;
+ SetLookFlag(playerOrHisVeh, true);
+ TurnBody();
+ if (!bIsDucking || bCrouchWhenShooting && GetCrouchFireAnim(weaponInfo)) {
+ if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
+ if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
+ CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
+ if (m_fDistanceToTarget > 30.0f) {
+ if (bIsDucking)
+ ClearDuck();
+
+ // Target is coming onto us
+ if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ SetObjective(OBJECTIVE_KILL_CHAR_ANY_MEANS, FindPlayerPed());
+ }
+ } else if (m_fDistanceToTarget < 5.0f
+ && (!FindPlayerVehicle() || FindPlayerVehicle()->m_vecMoveSpeed.MagnitudeSqr() < sq(1.f/200.f))) {
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bDuckAndCover = false;
+ } else {
+ float dotProd;
+ if (m_nRoadblockVeh) {
+ dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - m_nRoadblockVeh->GetPosition(), GetPosition() - m_nRoadblockVeh->GetPosition());
+ } else
+ dotProd = -1.0f;
+
+ if(dotProd < 0.0f) {
+ if (bIsDucking)
+ ClearDuck();
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bDuckAndCover = false;
+ SetPursuit(false);
+ } else {
+ bIsPointingGunAt = true;
+ }
+ }
+ }
+ } else {
+ if (m_fDistanceToTarget < weaponRange) {
+ CVector gunPos = weaponInfo->m_vecFireOffset;
+ TransformToNode(gunPos, PED_HANDR);
+
+ CColPoint foundCol;
+ CEntity *foundEnt;
+ if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
+ false, true, false, false, true, false, false)
+ || foundEnt && foundEnt == playerOrHisVeh) {
+
+ SetWeaponLockOnTarget(playerOrHisVeh);
+ SetAttack(playerOrHisVeh);
+ SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
+ }
+ SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 300));
+ }
+ SetMoveState(PEDMOVE_STILL);
+ }
+ }
+ } else {
+ if (!m_bIsDisabledCop || m_bZoneDisabled) {
+ if (m_nPedState != PED_AIM_GUN) {
+ if (m_bIsInPursuit)
+ ClearPursuit();
+
+ if (IsPedInControl()) {
+ // Entering the vehicle
+ if (m_pMyVehicle && !bInVehicle) {
+ if (m_pMyVehicle->IsLawEnforcementVehicle()) {
+ if (m_pMyVehicle->pDriver) {
+ if (m_pMyVehicle->pDriver->m_nPedType == PEDTYPE_COP) {
+ if (m_objective != OBJECTIVE_ENTER_CAR_AS_PASSENGER)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_PASSENGER, m_pMyVehicle);
+ } else if (m_pMyVehicle->pDriver->IsPlayer()) {
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ }
+ } else if (m_objective != OBJECTIVE_ENTER_CAR_AS_DRIVER) {
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ } else {
+ m_pMyVehicle = nil;
+ ClearObjective();
+ SetWanderPath(CGeneral::GetRandomNumber() & 7);
+ }
+ } else {
+ if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_HASSLE_CHAR && CharCreatedBy == RANDOM_CHAR) {
+ for (int i = 0; i < m_numNearPeds; i++) {
+ CPed *nearPed = m_nearPeds[i];
+ if (nearPed->CharCreatedBy == RANDOM_CHAR) {
+ if ((nearPed->m_nPedType == PEDTYPE_CRIMINAL || nearPed->IsGangMember())
+ && nearPed->IsPedInControl()) {
+
+ bool anotherCopChasesHim = false;
+ if (nearPed->m_nPedState == PED_FLEE_ENTITY) {
+ if (nearPed->m_fleeFrom && nearPed->m_fleeFrom->IsPed() &&
+ ((CPed*)nearPed->m_fleeFrom)->m_nPedType == PEDTYPE_COP) {
+ anotherCopChasesHim = true;
+ }
+ }
+ if (!anotherCopChasesHim) {
+ SetObjective(OBJECTIVE_KILL_CHAR_ON_FOOT, nearPed);
+ nearPed->SetObjective(OBJECTIVE_FLEE_CHAR_ON_FOOT_TILL_SAFE, this);
+ nearPed->bBeingChasedByPolice = true;
+ return;
+ }
+ } else {
+ if (nearPed->m_nPedType != PEDTYPE_COP && !nearPed->IsPlayer()
+ && nearPed->IsPedInControl() && m_nHassleTimer < CTimer::GetTimeInMilliseconds()) {
+
+ if (nearPed->m_objective == OBJECTIVE_NONE && nearPed->m_nPedState == PED_WANDER_PATH
+ && !nearPed->m_pLookTarget && nearPed->m_lookTimer < CTimer::GetTimeInMilliseconds()) {
+
+ if ((GetPosition() - nearPed->GetPosition()).MagnitudeSqr() < sq(5.0f)) {
+
+ if (CWorld::GetIsLineOfSightClear(GetPosition(), nearPed->GetPosition(),
+ true, false, false, false, false, false, false)) {
+ Say(SOUND_PED_COP_REACTION);
+ SetObjective(OBJECTIVE_HASSLE_CHAR, nearPed);
+ nearPed->SetObjective(OBJECTIVE_WAIT_ON_FOOT_FOR_COP, this);
+ m_nHassleTimer = CTimer::GetTimeInMilliseconds() + 100000;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } else {
+ if (m_bIsInPursuit && m_nPedState != PED_AIM_GUN)
+ ClearPursuit();
+
+ m_bIsDisabledCop = false;
+ bKindaStayInSamePlace = false;
+ bNotAllowedToDuck = false;
+ bCrouchWhenShooting = false;
+ bDuckAndCover = false;
+ if (bIsDucking)
+ ClearDuck();
+ if (m_pMyVehicle)
+ SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
+ }
+ }
+}
+
+void
+CCopPed::ProcessControl(void)
+{
+ if (m_nCopType == COP_HELI_SWAT)
+ ProcessHeliSwat();
+
+ CPed::ProcessControl();
+
+ if (m_bThrowsSpikeTrap) {
+ if (CGame::currArea != AREA_MALL)
+ ProcessStingerCop();
+ return;
+ }
+
+ if (m_pStinger && m_pStinger->bIsDeployed && m_pStinger->m_nSpikeState == STINGERSTATE_DEPLOYED && CGame::currArea != AREA_MALL)
+ m_pStinger->Process();
+
+ if (bWasPostponed)
+ return;
+
+ if (m_nPedState == PED_DEAD) {
+ ClearPursuit();
+ m_objective = OBJECTIVE_NONE;
+ return;
+ }
+ if (m_nPedState == PED_DIE)
+ return;
+
+ if (m_nPedState == PED_ARREST_PLAYER) {
+ ArrestPlayer();
+ return;
+ }
+ GetWeapon()->Update(m_audioEntityId, nil);
+ if (m_moved.Magnitude() > 0.0f)
+ Avoid();
+
+ CPhysical *playerOrHisVeh = FindPlayerVehicle() ? (CPhysical*)FindPlayerVehicle() : (CPhysical*)FindPlayerPed();
+ CPlayerPed *player = FindPlayerPed();
+
+ m_fDistanceToTarget = (playerOrHisVeh->GetPosition() - GetPosition()).Magnitude();
+ if (player->m_nPedState == PED_ARRESTED || player->DyingOrDead()) {
+ if (m_fDistanceToTarget < 5.0f) {
+ SetArrestPlayer(player);
+ return;
+ }
+ if (IsPedInControl())
+ SetIdle();
+ }
+
+ if (m_bIsInPursuit) {
+ if (player->m_nPedState != PED_ARRESTED && !player->DyingOrDead()) {
+ if (player->m_pWanted->m_CurrentCops == 1) {
+ Say(SOUND_PED_COP_ALONE);
+ } else {
+ int numCopsNear = 0;
+ for (int i = 0; i < player->m_numNearPeds; ++i) {
+ CPed *nearPed = player->m_nearPeds[i];
+ if (nearPed->m_nPedType == PEDTYPE_COP && nearPed->m_nPedState != PED_DEAD)
+ ++numCopsNear;
+ }
+ if (numCopsNear <= 3) {
+ Say(SOUND_PED_COP_LITTLECOPSAROUND);
+ if (!player->bInVehicle) {
+ CVector distToPlayer = player->GetPosition() - GetPosition();
+ if (distToPlayer.MagnitudeSqr() < sq(20.0f)) {
+ player->Say(SOUND_PED_PLAYER_FARFROMCOPS);
+ if (player->m_nPedState != PED_ATTACK && player->m_nPedState != PED_AIM_GUN) {
+ player->SetLookFlag(this, false);
+ player->SetLookTimer(1000);
+ }
+ }
+ }
+ } else if ((CGeneral::GetRandomNumber() % 16) == 1) {
+ Say(SOUND_PED_COP_MANYCOPSAROUND);
+ }
+ }
+ }
+ }
+
+ if (IsPedInControl()) {
+ CopAI();
+ /* switch (m_nCopType)
+ {
+ case COP_FBI:
+ CopAI();
+ break;
+ case COP_SWAT:
+ CopAI();
+ break;
+ case COP_ARMY:
+ CopAI();
+ break;
+ default:
+ CopAI();
+ break;
+ } */
+ } else if (InVehicle()) {
+ if (m_pMyVehicle->pDriver == this && m_pMyVehicle->AutoPilot.m_nCarMission == MISSION_NONE &&
+ CanPedDriveOff() && m_pMyVehicle->VehicleCreatedBy != MISSION_VEHICLE) {
+
+ CCarCtrl::JoinCarWithRoadSystem(m_pMyVehicle);
+ m_pMyVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
+ m_pMyVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
+ m_pMyVehicle->AutoPilot.m_nCruiseSpeed = 17;
+ }
+ }
+ if (IsPedInControl() || m_nPedState == PED_DRIVING)
+ ScanForCrimes();
+
+ // They may have used goto to jump here in case of PED_ATTACK.
+ if (m_nPedState == PED_IDLE || m_nPedState == PED_ATTACK) {
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT &&
+ player && player->EnteringCar() && m_fDistanceToTarget < 1.3f) {
+ SetArrestPlayer(player);
+ }
+ } else {
+ if (m_nPedState == PED_SEEK_POS) {
+ if (player->m_nPedState == PED_ARRESTED) {
+ SetIdle();
+ SetLookFlag(player, false);
+ SetLookTimer(1000);
+ RestorePreviousObjective();
+ } else {
+ if (player->m_pMyVehicle && player->m_pMyVehicle->m_nNumGettingIn != 0) {
+ m_distanceToCountSeekDone = 1.3f;
+ }
+
+ if (!bDuckAndCover && Seek()) {
+ CVehicle *playerVeh = FindPlayerVehicle();
+ if (!playerVeh && player && player->EnteringCar()) {
+ SetArrestPlayer(player);
+ } else if (1.5f + GetPosition().z <= m_vecSeekPos.z || GetPosition().z - 0.3f >= m_vecSeekPos.z) {
+ SetMoveState(PEDMOVE_STILL);
+ } else if (playerVeh && playerVeh->CanPedEnterCar() && playerVeh->m_nNumGettingIn == 0) {
+ SetCarJack(playerVeh);
+ }
+ }
+ }
+ } else if (m_nPedState == PED_SEEK_ENTITY) {
+ if (!m_pSeekTarget) {
+ RestorePreviousState();
+ } else {
+ m_vecSeekPos = m_pSeekTarget->GetPosition();
+ if (Seek()) {
+ if (m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT && m_fDistanceToTarget < 2.5f && player) {
+ if (player->m_nPedState == PED_ARRESTED || player->m_nPedState == PED_ENTER_CAR ||
+ (player->m_nPedState == PED_CARJACK && m_fDistanceToTarget < 1.3f)) {
+ SetArrestPlayer(player);
+ } else
+ RestorePreviousState();
+ } else {
+ RestorePreviousState();
+ }
+
+ }
+ }
+ }
+ }
+
+ if (m_pPointGunAt)
+ Say(SOUND_PED_COP_UNK_129);
+
+ if (m_bStopAndShootDisabledZone) {
+ bool dontShoot = false;
+ if (GetIsOnScreen()) {
+ if (((CTimer::GetFrameCounter() + m_randomSeed) & 0x1F) == 17) {
+ CEntity* foundBuilding = nil;
+ CColPoint foundCol;
+ CVector lookPos = GetPosition() + CVector(0.0f, 0.0f, 0.7f);
+ CVector camPos = TheCamera.GetGameCamPosition();
+ CWorld::ProcessLineOfSight(camPos, lookPos, foundCol, foundBuilding,
+ true, false, false, false, false, false, false);
+
+ // He's at least 15.0 far, in disabled zone, collided into somewhere (that's why m_bStopAndShootDisabledZone set),
+ // and now has building on front of him. He's stupid, we don't need him.
+ if (foundBuilding) {
+ FlagToDestroyWhenNextProcessed();
+ dontShoot = true;
+ }
+ }
+ } else {
+ FlagToDestroyWhenNextProcessed();
+ dontShoot = true;
+ }
+
+ if (!dontShoot) {
+ bStopAndShoot = true;
+ bKindaStayInSamePlace = true;
+ bIsPointingGunAt = true;
+ SetAttack(m_pedInObjective);
+ }
+ }
+
+ if (field_624 >= 2 && m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) {
+ CVector centre = GetPosition() + CVector(0.f, 0.f, 0.65f);
+ if (CWorld::TestSphereAgainstWorld(centre, 0.35f, this, true, false, false, false, false, false)) {
+ field_624 = 0;
+ m_bStopAndShootDisabledZone = true;
+ ClearPursuit();
+ SetObjective(OBJECTIVE_NONE);
+ SetWanderPath(CGeneral::GetRandomNumberInRange(0,8));
+ field_61C = CTimer::GetTimeInMilliseconds() + 30000;
+ } else {
+ field_624 = 0;
+ if (GetWeapon()->IsTypeMelee()) {
+ // TODO(Miami): enum
+ for (int i = 3; i < 7; i++) {
+ if (HasWeaponSlot(i)) {
+ SetCurrentWeapon(i);
+ break;
+ }
+ }
+ SetMoveState(PEDMOVE_STILL);
+ bStopAndShoot = true;
+ }
+ }
+ } else if (CTimer::GetTimeStep() / 100.f <= m_fDistanceTravelled)
+ field_624 = 0;
+}
+
+void
+CCopPed::ProcessHeliSwat(void)
+{
+ CVector bestPos = GetPosition();
+ SetPedState(PED_ABSEIL);
+ CPedPlacement::FindZCoorForPed(&bestPos);
+ if (GetPosition().z - 2.0f >= bestPos.z && m_pRopeEntity) {
+ m_fAbseilPos += 0.003f * CTimer::GetTimeStep();
+ m_vecMoveSpeed.z = -0.03f;
+ m_vecTurnSpeed = CVector(0.f, 0.f, (m_randomSeed % 32) * 0.003f - 0.05f);
+ CPhysical::ApplyTurnSpeed();
+ GetMatrix().Reorthogonalise();
+ CVector posOnRope;
+
+ if (CRopes::FindCoorsAlongRope(m_nRopeID, m_fAbseilPos, &posOnRope)) {
+ SetPosition(posOnRope);
+ } else {
+ bUsesCollision = true;
+ m_vecMoveSpeed = CVector(0.f, 0.f, 0.f);
+ SetPedState(PED_IDLE);
+ m_nCopType = COP_SWAT;
+ SetInTheAir();
+ bKnockedUpIntoAir = true;
+ }
+ Say(SOUND_PED_COP_HELIPILOTPHRASE);
+ } else {
+ bUsesCollision = true;
+ m_vecMoveSpeed = CVector(0.f, 0.f, 0.f);
+ SetPedState(PED_IDLE);
+ m_nCopType = COP_SWAT;
+ SetInTheAir();
+ bKnockedUpIntoAir = true;
+ }
+}
+
+void
+CCopPed::ProcessStingerCop(void)
+{
+ if (m_pStinger->bIsDeployed || FindPlayerVehicle() && (FindPlayerVehicle()->IsCar() || FindPlayerVehicle()->IsBike())) {
+ if (m_pStinger->bIsDeployed) {
+ m_pStinger->Process();
+ } else {
+ CVector2D vehDist = GetPosition() - FindPlayerVehicle()->GetPosition();
+ CVector2D dirVehGoing = FindPlayerVehicle()->m_vecMoveSpeed;
+ if (vehDist.MagnitudeSqr() < sq(30.0f)) {
+ if (dirVehGoing.MagnitudeSqr() > 0.0f) {
+ vehDist.Normalise();
+ dirVehGoing.Normalise();
+ if (DotProduct2D(vehDist, dirVehGoing) > 0.8f) {
+ float angle = (CrossProduct2D(vehDist, dirVehGoing - vehDist) < 0.0f ?
+ FindPlayerVehicle()->GetForward().Heading() - HALFPI :
+ HALFPI + FindPlayerVehicle()->GetForward().Heading());
+
+ SetHeading(angle);
+ m_fRotationCur = angle;
+ m_fRotationDest = angle;
+ m_pStinger->Deploy(this);
+ }
+ }
+ }
+ }
+ } else {
+ ClearPursuit();
+ }
+}