summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio/DMAudio.cpp3
-rw-r--r--src/audio/DMAudio.h2
-rw-r--r--src/control/Darkel.cpp2
-rw-r--r--src/control/Script.cpp4
-rw-r--r--src/core/EventList.cpp238
-rw-r--r--src/core/EventList.h65
-rw-r--r--src/core/Pools.cpp8
-rw-r--r--src/core/Pools.h6
-rw-r--r--src/core/Wanted.cpp304
-rw-r--r--src/core/Wanted.h73
-rw-r--r--src/core/config.h1
-rw-r--r--src/modelinfo/ModelIndices.h18
-rw-r--r--src/peds/CopPed.h33
13 files changed, 667 insertions, 90 deletions
diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp
index b4fee67f..1c1316a8 100644
--- a/src/audio/DMAudio.cpp
+++ b/src/audio/DMAudio.cpp
@@ -33,4 +33,5 @@ WRAPPER int32 cDMAudio::CreateEntity(int, void*) { EAXJMP(0x57C7C0); }
WRAPPER void cDMAudio::SetEntityStatus(int32 id, uint8 enable) { EAXJMP(0x57C810); }
WRAPPER void cDMAudio::SetRadioInCar(int32) { EAXJMP(0x57CE60); }
WRAPPER void cDMAudio::DestroyEntity(int32) { EAXJMP(0x57C7F0); }
-WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); } \ No newline at end of file
+WRAPPER void cDMAudio::ClearMissionAudio(void) { EAXJMP(0x57CE20); }
+WRAPPER void cDMAudio::ReportCrime(eCrimeType crime, const CVector &pos) { EAXJMP(0x57CAD0); }
diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h
index 8be09ac6..0a2ce6ac 100644
--- a/src/audio/DMAudio.h
+++ b/src/audio/DMAudio.h
@@ -173,6 +173,7 @@ enum eSound : int16
};
class CEntity;
+enum eCrimeType;
class cDMAudio
{
@@ -204,5 +205,6 @@ public:
uint8 IsMP3RadioChannelAvailable();
void DestroyEntity(int32);
void ClearMissionAudio(void);
+ void ReportCrime(eCrimeType crime, const CVector &pos);
};
extern cDMAudio &DMAudio;
diff --git a/src/control/Darkel.cpp b/src/control/Darkel.cpp
index ab28f96e..678fcd45 100644
--- a/src/control/Darkel.cpp
+++ b/src/control/Darkel.cpp
@@ -300,7 +300,7 @@ void CDarkel::Update()
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
- FindPlayerPed()->m_pWanted->SetWantedLevel(NOTWANTED);
+ FindPlayerPed()->m_pWanted->SetWantedLevel(0);
if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
WeaponType = WEAPONTYPE_UZI;
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index b50c101e..f3a18195 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -124,8 +124,8 @@ void CMissionCleanup::Process()
CHud::m_ItemToFlash = -1;
CHud::SetHelpMessage(nil, false);
CUserDisplay::OnscnTimer.m_bDisabled = false;
- CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByCops = false;
- CWorld::Players[0].m_pPed->m_pWanted->m_IsIgnoredByEveryOne = false;
+ CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByCops = false;
+ CWorld::Players[0].m_pPed->m_pWanted->m_bIgnoredByEveryone = false;
CWorld::Players[0].MakePlayerSafe(false);
CTheScripts::StoreVehicleIndex = -1;
CTheScripts::StoreVehicleWasRandom = true;
diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp
new file mode 100644
index 00000000..15ad49dd
--- /dev/null
+++ b/src/core/EventList.cpp
@@ -0,0 +1,238 @@
+#include "common.h"
+#include "patcher.h"
+#include "Pools.h"
+#include "ModelIndices.h"
+#include "World.h"
+#include "Wanted.h"
+#include "Eventlist.h"
+
+int32 CEventList::ms_nFirstFreeSlotIndex;
+//CEvent gaEvent[NUMEVENTS];
+CEvent *gaEvent = (CEvent*)0x6EF830;
+
+enum
+{
+ EVENT_STATE_0,
+ EVENT_STATE_CANDELETE,
+ EVENT_STATE_CLEAR,
+};
+
+void
+CEventList::Initialise(void)
+{
+ int i;
+
+ debug("Initialising CEventList...");
+ for(i = 0; i < NUMEVENTS; i++){
+ gaEvent[i].type = EVENT_NULL;
+ gaEvent[i].entityType = EVENT_ENTITY_NONE;
+ gaEvent[i].entityRef = 0;
+ gaEvent[i].posn.x = 0.0f;
+ gaEvent[i].posn.y = 0.0f;
+ gaEvent[i].posn.z = 0.0f;
+ gaEvent[i].timeout = 0;
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+ ms_nFirstFreeSlotIndex = 0;
+}
+
+void
+CEventList::Update(void)
+{
+ int i;
+
+ ms_nFirstFreeSlotIndex = 0;
+ for(i = 0; i < NUMEVENTS; i++){
+ if(gaEvent[i].type == EVENT_NULL)
+ continue;
+ if(CTimer::GetTimeInMilliseconds() > gaEvent[i].timeout || gaEvent[i].state == EVENT_STATE_CANDELETE){
+ gaEvent[i].type = EVENT_NULL;
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+ if(gaEvent[i].state == EVENT_STATE_CLEAR)
+ gaEvent[i].state = EVENT_STATE_CANDELETE;
+ }
+}
+
+void
+CEventList::RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout)
+{
+ int i;
+ int ref;
+ bool copsDontCare;
+
+ copsDontCare = false;
+ switch(entityType){
+ case EVENT_ENTITY_PED:
+ ref = CPools::GetPedRef((CPed*)ent);
+ if(ent->GetModelIndex() >= MI_GANG01 && ent->GetModelIndex() <= MI_CRIMINAL02)
+ copsDontCare = true;
+ break;
+ case EVENT_ENTITY_VEHICLE:
+ ref = CPools::GetVehicleRef((CVehicle*)ent);
+ break;
+ case EVENT_ENTITY_OBJECT:
+ ref = CPools::GetObjectRef((CObject*)ent);
+ break;
+ default:
+ Error("Undefined entity type, RegisterEvent, EventList.cpp");
+ ref = 0;
+ break;
+ }
+
+ // only update time if event exists already
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type &&
+ gaEvent[i].entityType == entityType &&
+ gaEvent[i].entityRef == ref){
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ return;
+ }
+
+ for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == EVENT_NULL){
+ ms_nFirstFreeSlotIndex = i;
+ break;
+ }
+ if(i < NUMEVENTS){
+ gaEvent[i].type = type;
+ gaEvent[i].entityType = entityType;
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ gaEvent[i].entityRef = ref;
+ gaEvent[i].posn = ent->GetPosition();
+ gaEvent[i].criminal = criminal;
+ if(gaEvent[i].criminal)
+ gaEvent[i].criminal->RegisterReference((CEntity**)&gaEvent[i].criminal);
+ if(type == EVENT_GUNSHOT)
+ gaEvent[i].state = EVENT_STATE_CLEAR;
+ else
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+
+ if(criminal == FindPlayerPed())
+ ReportCrimeForEvent(type, (uintptr)ent, copsDontCare);
+}
+
+void
+CEventList::RegisterEvent(eEventType type, CVector posn, int32 timeout)
+{
+ int i;
+
+ // only update time if event exists already
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type &&
+ gaEvent[i].posn.x == posn.x &&
+ gaEvent[i].posn.y == posn.y &&
+ gaEvent[i].posn.z == posn.z &&
+ gaEvent[i].entityType == EVENT_ENTITY_NONE){
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ return;
+ }
+
+ for(i = ms_nFirstFreeSlotIndex; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == EVENT_NULL){
+ ms_nFirstFreeSlotIndex = i;
+ break;
+ }
+ if(i < NUMEVENTS){
+ gaEvent[i].type = type;
+ gaEvent[i].entityType = EVENT_ENTITY_NONE;
+ gaEvent[i].timeout = CTimer::GetTimeInMilliseconds() + timeout;
+ gaEvent[i].posn = posn;
+ gaEvent[i].entityRef = 0;
+ if(type == EVENT_GUNSHOT)
+ gaEvent[i].state = EVENT_STATE_CLEAR;
+ else
+ gaEvent[i].state = EVENT_STATE_0;
+ }
+}
+
+bool
+CEventList::GetEvent(eEventType type, int32 *event)
+{
+ int i;
+ for(i = 0; i < NUMEVENTS; i++)
+ if(gaEvent[i].type == type){
+ *event = i;
+ return true;
+ }
+ return false;
+}
+
+void
+CEventList::ClearEvent(int32 event)
+{
+ if(gaEvent[event].state != EVENT_STATE_CANDELETE)
+ gaEvent[event].state = EVENT_STATE_CLEAR;
+}
+
+bool
+CEventList::FindClosestEvent(eEventType type, CVector posn, int32 *event)
+{
+ int i;
+ float dist;
+ bool found = false;
+ float mindist = 60.0f;
+
+ for(i = 0; i < NUMEVENTS; i++){
+ if(gaEvent[i].type == EVENT_NULL)
+ continue;
+ dist = (posn - gaEvent[i].posn).Magnitude();
+ if(dist < mindist){
+ mindist = dist;
+ found = true;
+ *event = i;
+ }
+ }
+ return found;
+}
+
+void
+CEventList::ReportCrimeForEvent(eEventType type, int32 crimeId, bool copsDontCare)
+{
+ eCrimeType crime;
+ switch(type){
+ case EVENT_ASSAULT: crime = CRIME_HIT_PED; break;
+ case EVENT_RUN_REDLIGHT: crime = CRIME_RUN_REDLIGHT; break;
+ case EVENT_ASSAULT_POLICE: crime = CRIME_HIT_COP; break;
+ case EVENT_GUNSHOT: crime = CRIME_POSSESSION_GUN; break;
+ case EVENT_STEAL_CAR: crime = CRIME_STEAL_CAR; break;
+ case EVENT_HIT_AND_RUN: crime = CRIME_RUNOVER_PED; break;
+ case EVENT_HIT_AND_RUN_COP: crime = CRIME_RUNOVER_COP; break;
+ case EVENT_SHOOT_PED: crime = CRIME_SHOOT_PED; break;
+ case EVENT_SHOOT_COP: crime = CRIME_SHOOT_COP; break;
+ case EVENT_PED_SET_ON_FIRE: crime = CRIME_PED_BURNED; break;
+ case EVENT_COP_SET_ON_FIRE: crime = CRIME_COP_BURNED; break;
+ case EVENT_CAR_SET_ON_FIRE: crime = CRIME_VEHICLE_BURNED; break;
+ default: crime = CRIME_NONE; break;
+ }
+
+ if(crime == CRIME_NONE)
+ return;
+
+ CVector playerPedCoors = FindPlayerPed()->GetPosition();
+ CVector playerCoors = FindPlayerCoors();
+
+ if(CWanted::WorkOutPolicePresence(playerCoors, 14.0f) != 0){
+ FindPlayerPed()->m_pWanted->RegisterCrime_Immediately(crime, playerPedCoors, crimeId, copsDontCare);
+ FindPlayerPed()->m_pWanted->SetWantedLevelNoDrop(1);
+ }else
+ FindPlayerPed()->m_pWanted->RegisterCrime(crime, playerPedCoors, crimeId, copsDontCare);
+
+ if(type == EVENT_ASSAULT_POLICE)
+ FindPlayerPed()->SetWantedLevelNoDrop(1);
+ if(type == EVENT_SHOOT_COP)
+ FindPlayerPed()->SetWantedLevelNoDrop(2);
+
+}
+
+STARTPATCHES
+ InjectHook(0x475B60, CEventList::Initialise, PATCH_JUMP);
+ InjectHook(0x475BE0, CEventList::Update, PATCH_JUMP);
+ InjectHook(0x475C50, (void (*)(eEventType,eEventEntity,CEntity *,CPed *,int32))CEventList::RegisterEvent, PATCH_JUMP);
+ InjectHook(0x475E10, (void (*)(eEventType,CVector,int32))CEventList::RegisterEvent, PATCH_JUMP);
+ InjectHook(0x475F40, CEventList::GetEvent, PATCH_JUMP);
+ InjectHook(0x475F70, CEventList::ClearEvent, PATCH_JUMP);
+ InjectHook(0x475F90, CEventList::FindClosestEvent, PATCH_JUMP);
+ InjectHook(0x476070, CEventList::ReportCrimeForEvent, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/EventList.h b/src/core/EventList.h
new file mode 100644
index 00000000..d0fc0847
--- /dev/null
+++ b/src/core/EventList.h
@@ -0,0 +1,65 @@
+#pragma once
+
+class CEntity;
+class CPed;
+
+enum eEventType
+{
+ EVENT_NULL,
+ EVENT_ASSAULT,
+ EVENT_RUN_REDLIGHT,
+ EVENT_ASSAULT_POLICE,
+ EVENT_GUNSHOT,
+ EVENT_INJURED_PED,
+ EVENT_DEAD_PED,
+ EVENT_FIRE,
+ EVENT_STEAL_CAR,
+ EVENT_HIT_AND_RUN,
+ EVENT_HIT_AND_RUN_COP,
+ EVENT_SHOOT_PED,
+ EVENT_SHOOT_COP,
+ EVENT_EXPLOSION,
+ EVENT_PED_SET_ON_FIRE,
+ EVENT_COP_SET_ON_FIRE,
+ EVENT_CAR_SET_ON_FIRE,
+ EVENT_ASSAULT_NASTYWEAPON,
+ EVENT_ASSAULT_NASTYWEAPON_POLICE,
+ EVENT_ICECREAM,
+ EVENT_ATM,
+ EVENT_SHOPSTALL,
+ EVENT_SHOPWINDOW,
+ EVENT_LAST_EVENT
+};
+
+enum eEventEntity
+{
+ EVENT_ENTITY_NONE,
+ EVENT_ENTITY_PED,
+ EVENT_ENTITY_VEHICLE,
+ EVENT_ENTITY_OBJECT
+};
+
+struct CEvent
+{
+ eEventType type;
+ eEventEntity entityType;
+ int32 entityRef;
+ CPed *criminal;
+ CVector posn;
+ uint32 timeout;
+ int32 state;
+};
+
+class CEventList
+{
+ static int32 ms_nFirstFreeSlotIndex;
+public:
+ static void Initialise(void);
+ static void Update(void);
+ static void RegisterEvent(eEventType type, eEventEntity entityType, CEntity *ent, CPed *criminal, int32 timeout);
+ static void RegisterEvent(eEventType type, CVector posn, int32 timeout);
+ static bool GetEvent(eEventType type, int32 *event);
+ static void ClearEvent(int32 event);
+ static bool FindClosestEvent(eEventType type, CVector posn, int32 *event);
+ static void ReportCrimeForEvent(eEventType type, int32, bool);
+};
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index f7f93292..1f07cf54 100644
--- a/src/core/Pools.cpp
+++ b/src/core/Pools.cpp
@@ -14,6 +14,7 @@ void
CPools::Initialise(void)
{
// TODO: unused right now
+ assert(0);
ms_pPtrNodePool = new CCPtrNodePool(NUMPTRNODES);
ms_pEntryInfoNodePool = new CEntryInfoNodePool(NUMENTRYINFOS);
ms_pPedPool = new CPedPool(NUMPEDS);
@@ -23,3 +24,10 @@ CPools::Initialise(void)
ms_pObjectPool = new CObjectPool(NUMOBJECTS);
ms_pDummyPool = new CDummyPool(NUMDUMMIES);
}
+
+int32 CPools::GetPedRef(CPed *ped) { return ms_pPedPool->GetIndex(ped); }
+CPed *CPools::GetPed(int32 handle) { return ms_pPedPool->GetAt(handle); }
+int32 CPools::GetVehicleRef(CVehicle *vehicle) { return ms_pVehiclePool->GetIndex(vehicle); }
+CVehicle *CPools::GetVehicle(int32 handle) { return ms_pVehiclePool->GetAt(handle); }
+int32 CPools::GetObjectRef(CObject *object) { return ms_pObjectPool->GetIndex(object); }
+CObject *CPools::GetObject(int32 handle) { return ms_pObjectPool->GetAt(handle); }
diff --git a/src/core/Pools.h b/src/core/Pools.h
index 3496064c..e364798c 100644
--- a/src/core/Pools.h
+++ b/src/core/Pools.h
@@ -40,4 +40,10 @@ public:
static CDummyPool *GetDummyPool(void) { return ms_pDummyPool; }
static void Initialise(void);
+ static int32 GetPedRef(CPed *ped);
+ static CPed *GetPed(int32 handle);
+ static int32 GetVehicleRef(CVehicle *vehicle);
+ static CVehicle *GetVehicle(int32 handle);
+ static int32 GetObjectRef(CObject *object);
+ static CObject *GetObject(int32 handle);
};
diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp
index 4608bfef..2868eb8c 100644
--- a/src/core/Wanted.cpp
+++ b/src/core/Wanted.cpp
@@ -1,65 +1,102 @@
#include "common.h"
#include "patcher.h"
+#include "Pools.h"
+#include "ModelIndices.h"
+#include "Timer.h"
+#include "World.h"
+#include "ZoneCull.h"
+#include "Darkel.h"
+#include "DMAudio.h"
#include "Wanted.h"
-int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714;
+int32 &CWanted::MaximumWantedLevel = *(int32*)0x5F7714; // 6
+int32 &CWanted::nMaximumWantedLevel = *(int32*)0x5F7718; // 6400
-bool CWanted::AreSwatRequired()
+void
+CWanted::Initialise()
+{
+ int i;
+
+ m_nChaos = 0;
+ m_nLastUpdateTime = 0;
+ m_nLastWantedLevelChange = 0;
+ m_CurrentCops = 0;
+ m_MaxCops = 0;
+ m_MaximumLawEnforcerVehicles = 0;
+ m_RoadblockDensity = 0;
+ m_bIgnoredByCops = false;
+ m_bIgnoredByEveryone = false;
+ m_bSwatRequired = false;
+ m_bFbiRequired = false;
+ m_bArmyRequired = false;
+ m_fCrimeSensitivity = 1.0f;
+ m_nWantedLevel = 0;
+ m_CopsBeatingSuspect = 0;
+ for(i = 0; i < 10; i++)
+ m_pCops[i] = nil;
+ ClearQdCrimes();
+}
+
+bool
+CWanted::AreSwatRequired()
{
return m_nWantedLevel >= 4;
}
-bool CWanted::AreFbiRequired()
+bool
+CWanted::AreFbiRequired()
{
return m_nWantedLevel >= 5;
}
-bool CWanted::AreArmyRequired()
+bool
+CWanted::AreArmyRequired()
{
return m_nWantedLevel >= 6;
}
-int CWanted::NumOfHelisRequired()
+int32
+CWanted::NumOfHelisRequired()
{
- if (m_IsIgnoredByCops)
+ if (m_bIgnoredByCops)
return 0;
- // Return value is number of helicopters, no need to name them.
switch (m_nWantedLevel) {
- case WANTEDLEVEL_3:
- case WANTEDLEVEL_4:
+ case 3:
+ case 4:
return 1;
- case WANTEDLEVEL_5:
- case WANTEDLEVEL_6:
+ case 5:
+ case 6:
return 2;
default:
return 0;
}
}
-void CWanted::SetWantedLevel(int32 level)
+void
+CWanted::SetWantedLevel(int32 level)
{
ClearQdCrimes();
switch (level) {
- case NOTWANTED:
+ case 0:
m_nChaos = 0;
break;
- case WANTEDLEVEL_1:
+ case 1:
m_nChaos = 60;
break;
- case WANTEDLEVEL_2:
+ case 2:
m_nChaos = 220;
break;
- case WANTEDLEVEL_3:
+ case 3:
m_nChaos = 420;
break;
- case WANTEDLEVEL_4:
+ case 4:
m_nChaos = 820;
break;
- case WANTEDLEVEL_5:
+ case 5:
m_nChaos = 1620;
break;
- case WANTEDLEVEL_6:
+ case 6:
m_nChaos = 3220;
break;
default:
@@ -70,61 +107,210 @@ void CWanted::SetWantedLevel(int32 level)
UpdateWantedLevel();
}
-void CWanted::SetWantedLevelNoDrop(int32 level)
+void
+CWanted::SetWantedLevelNoDrop(int32 level)
{
if (level > m_nWantedLevel)
SetWantedLevel(level);
}
-void CWanted::ClearQdCrimes()
+void
+CWanted::SetMaximumWantedLevel(int32 level)
{
- for (int i = 0; i < 16; i++) {
- m_sCrimes[i].m_eCrimeType = CRIME_NONE;
+ switch(level){
+ case 0:
+ nMaximumWantedLevel = 0;
+ MaximumWantedLevel = 0;
+ break;
+ case 1:
+ nMaximumWantedLevel = 120;
+ MaximumWantedLevel = 1;
+ break;
+ case 2:
+ nMaximumWantedLevel = 300;
+ MaximumWantedLevel = 2;
+ break;
+ case 3:
+ nMaximumWantedLevel = 600;
+ MaximumWantedLevel = 3;
+ break;
+ case 4:
+ nMaximumWantedLevel = 1200;
+ MaximumWantedLevel = 4;
+ break;
+ case 5:
+ nMaximumWantedLevel = 2400;
+ MaximumWantedLevel = 5;
+ break;
+ case 6:
+ nMaximumWantedLevel = 4800;
+ MaximumWantedLevel = 6;
+ break;
}
}
-void CWanted::UpdateWantedLevel()
+void
+CWanted::RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
+{
+ AddCrimeToQ(type, id, coors, false, policeDoesntCare);
+}
+
+void
+CWanted::RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare)
+{
+ if(!AddCrimeToQ(type, id, coors, false, policeDoesntCare))
+ ReportCrimeNow(type, coors, policeDoesntCare);
+}
+
+void
+CWanted::ClearQdCrimes()
+{
+ for (int i = 0; i < 16; i++)
+ m_aCrimes[i].m_nType = CRIME_NONE;
+}
+
+// returns whether the crime had been reported already
+bool
+CWanted::AddCrimeToQ(eCrimeType type, int32 id, const CVector &coors, bool reported, bool policeDoesntCare)
+{
+ int i;
+
+ for(i = 0; i < 16; i++)
+ if(m_aCrimes[i].m_nType == type && m_aCrimes[i].m_nId == id){
+ if(m_aCrimes[i].m_bReported)
+ return true;
+ if(reported)
+ m_aCrimes[i].m_bReported = reported;
+ return false;
+ }
+
+ for(i = 0; i < 16; i++)
+ if(m_aCrimes[i].m_nType == CRIME_NONE)
+ break;
+ if(i < 16){
+ m_aCrimes[i].m_nType = type;
+ m_aCrimes[i].m_nId = id;
+ m_aCrimes[i].m_vecPosn = coors;
+ m_aCrimes[i].m_nTime = CTimer::GetTimeInMilliseconds();
+ m_aCrimes[i].m_bReported = reported;
+ m_aCrimes[i].m_bPoliceDoesntCare = policeDoesntCare;
+ }
+ return false;
+}
+
+void
+CWanted::ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare)
+{
+ float sensitivity, chaos;
+ int wantedLevelDrop;
+
+ if(CDarkel::FrenzyOnGoing())
+ sensitivity = m_fCrimeSensitivity*0.3f;
+ else
+ sensitivity = m_fCrimeSensitivity;
+
+ wantedLevelDrop = min(CCullZones::GetWantedLevelDrop(), 100);
+
+ chaos = (1.0f - wantedLevelDrop/100.0f) * sensitivity;
+ switch(type){
+ case CRIME_POSSESSION_GUN:
+ break;
+ case CRIME_HIT_PED:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_HIT_COP:
+ m_nChaos += 45.0f*chaos;
+ break;
+ case CRIME_SHOOT_PED:
+ m_nChaos += 30.0f*chaos;
+ break;
+ case CRIME_SHOOT_COP:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_STEAL_CAR:
+ m_nChaos += 15.0f*chaos;
+ break;
+ case CRIME_RUN_REDLIGHT:
+ m_nChaos += 10.0f*chaos;
+ break;
+ case CRIME_RECKLESS_DRIVING:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_SPEEDING:
+ m_nChaos += 5.0f*chaos;
+ break;
+ case CRIME_RUNOVER_PED:
+ m_nChaos += 18.0f*chaos;
+ break;
+ case CRIME_RUNOVER_COP:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_SHOOT_HELI:
+ m_nChaos += 400.0f*chaos;
+ break;
+ case CRIME_PED_BURNED:
+ m_nChaos += 20.0f*chaos;
+ break;
+ case CRIME_COP_BURNED:
+ m_nChaos += 80.0f*chaos;
+ break;
+ case CRIME_VEHICLE_BURNED:
+ m_nChaos += 20.0f*chaos;
+ break;
+ case CRIME_DESTROYED_CESSNA:
+ m_nChaos += 500.0f*chaos;
+ break;
+ default:
+ // Error("Undefined crime type, RegisterCrime, Crime.cpp"); // different file for some reason
+ Error("Undefined crime type, RegisterCrime, Wanted.cpp");
+ }
+ DMAudio.ReportCrime(type, coors);
+ UpdateWantedLevel();
+}
+
+void
+CWanted::UpdateWantedLevel()
{
int32 CurrWantedLevel = m_nWantedLevel;
if (m_nChaos >= 0 && m_nChaos < 40) {
- m_nWantedLevel = NOTWANTED;
+ m_nWantedLevel = 0;
m_MaximumLawEnforcerVehicles = 0;
m_MaxCops = 0;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 40 && m_nChaos < 200) {
- m_nWantedLevel = WANTEDLEVEL_1;
+ m_nWantedLevel = 1;
m_MaximumLawEnforcerVehicles = 1;
m_MaxCops = 1;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 200 && m_nChaos < 400) {
- m_nWantedLevel = WANTEDLEVEL_2;
+ m_nWantedLevel = 2;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 3;
m_RoadblockDensity = 0;
}
else if (m_nChaos >= 400 && m_nChaos < 800) {
- m_nWantedLevel = WANTEDLEVEL_3;
+ m_nWantedLevel = 3;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 4;
m_RoadblockDensity = 4;
}
else if (m_nChaos >= 800 && m_nChaos < 1600) {
- m_nWantedLevel = WANTEDLEVEL_4;
+ m_nWantedLevel = 4;
m_MaximumLawEnforcerVehicles = 2;
m_MaxCops = 6;
m_RoadblockDensity = 8;
}
else if (m_nChaos >= 1600 && m_nChaos < 3200) {
- m_nWantedLevel = WANTEDLEVEL_5;
+ m_nWantedLevel = 5;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 8;
m_RoadblockDensity = 10;
}
else if (m_nChaos >= 3200) {
- m_nWantedLevel = WANTEDLEVEL_6;
+ m_nWantedLevel = 6;
m_MaximumLawEnforcerVehicles = 3;
m_MaxCops = 10;
m_RoadblockDensity = 12;
@@ -132,4 +318,58 @@ void CWanted::UpdateWantedLevel()
if (CurrWantedLevel != m_nWantedLevel)
m_nLastWantedLevelChange = CTimer::GetTimeInMilliseconds();
-} \ No newline at end of file
+}
+
+int32
+CWanted::WorkOutPolicePresence(CVector posn, float radius)
+{
+ int i;
+ CPed *ped;
+ CVehicle *vehicle;
+ int numPolice = 0;
+
+ i = CPools::GetPedPool()->GetSize();
+ while(--i >= 0){
+ ped = CPools::GetPedPool()->GetSlot(i);
+ if(ped &&
+ IsPolicePedModel(ped->GetModelIndex()) &&
+ (posn - ped->GetPosition()).Magnitude() < radius)
+ numPolice++;
+ }
+
+ i = CPools::GetVehiclePool()->GetSize();
+ while(--i >= 0){
+ vehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if(vehicle &&
+ vehicle->bIsLawEnforcer &&
+ IsPoliceVehicleModel(vehicle->GetModelIndex()) &&
+ vehicle != FindPlayerVehicle() &&
+ vehicle->m_status != STATUS_ABANDONED && vehicle->m_status != STATUS_WRECKED &&
+ (posn - vehicle->GetPosition()).Magnitude() < radius)
+ numPolice++;
+ }
+
+ return numPolice;
+}
+
+STARTPATCHES
+ InjectHook(0x4AD6E0, &CWanted::Initialise, PATCH_JUMP);
+// InjectHook(0x4AD790, &CWanted::Reset, PATCH_JUMP);
+// InjectHook(0x4AD7B0, &CWanted::Update, PATCH_JUMP);
+ InjectHook(0x4AD900, &CWanted::UpdateWantedLevel, PATCH_JUMP);
+ InjectHook(0x4AD9F0, &CWanted::RegisterCrime, PATCH_JUMP);
+ InjectHook(0x4ADA10, &CWanted::RegisterCrime_Immediately, PATCH_JUMP);
+ InjectHook(0x4ADA50, &CWanted::SetWantedLevel, PATCH_JUMP);
+ InjectHook(0x4ADAC0, &CWanted::SetWantedLevelNoDrop, PATCH_JUMP);
+ InjectHook(0x4ADAE0, &CWanted::SetMaximumWantedLevel, PATCH_JUMP);
+ InjectHook(0x4ADBA0, &CWanted::AreSwatRequired, PATCH_JUMP);
+ InjectHook(0x4ADBC0, &CWanted::AreFbiRequired, PATCH_JUMP);
+ InjectHook(0x4ADBE0, &CWanted::AreArmyRequired, PATCH_JUMP);
+ InjectHook(0x4ADC00, &CWanted::NumOfHelisRequired, PATCH_JUMP);
+// InjectHook(0x4ADC40, &CWanted::ResetPolicePursuit, PATCH_JUMP);
+ InjectHook(0x4ADD00, &CWanted::WorkOutPolicePresence, PATCH_JUMP);
+ InjectHook(0x4ADF20, &CWanted::ClearQdCrimes, PATCH_JUMP);
+ InjectHook(0x4ADFD0, &CWanted::AddCrimeToQ, PATCH_JUMP);
+// InjectHook(0x4AE090, &CWanted::UpdateCrimesQ, PATCH_JUMP);
+ InjectHook(0x4AE110, &CWanted::ReportCrimeNow, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/core/Wanted.h b/src/core/Wanted.h
index d3f6638b..1a72f839 100644
--- a/src/core/Wanted.h
+++ b/src/core/Wanted.h
@@ -1,16 +1,38 @@
#pragma once
-#include "Entity.h"
-#include "math/Vector.h"
-#include "CopPed.h"
-
-enum eWantedLevel {
- NOTWANTED,
- WANTEDLEVEL_1,
- WANTEDLEVEL_2,
- WANTEDLEVEL_3,
- WANTEDLEVEL_4,
- WANTEDLEVEL_5,
- WANTEDLEVEL_6,
+
+class CEntity;
+class CCopPed;
+
+enum eCrimeType
+{
+ CRIME_NONE,
+ CRIME_POSSESSION_GUN,
+ CRIME_HIT_PED,
+ CRIME_HIT_COP,
+ CRIME_SHOOT_PED,
+ CRIME_SHOOT_COP,
+ CRIME_STEAL_CAR,
+ CRIME_RUN_REDLIGHT,
+ CRIME_RECKLESS_DRIVING,
+ CRIME_SPEEDING,
+ CRIME_RUNOVER_PED,
+ CRIME_RUNOVER_COP,
+ CRIME_SHOOT_HELI,
+ CRIME_PED_BURNED,
+ CRIME_COP_BURNED,
+ CRIME_VEHICLE_BURNED,
+ CRIME_DESTROYED_CESSNA,
+};
+
+class CCrimeBeingQd
+{
+public:
+ eCrimeType m_nType;
+ uint32 m_nId;
+ int32 m_nTime;
+ CVector m_vecPosn;
+ bool m_bReported;
+ bool m_bPoliceDoesntCare;
};
class CWanted
@@ -23,28 +45,37 @@ public:
uint8 m_CurrentCops;
uint8 m_MaxCops;
uint8 m_MaximumLawEnforcerVehicles;
- int8 field_19;
+ uint8 m_CopsBeatingSuspect;
int16 m_RoadblockDensity;
- uint8 m_IsIgnoredByCops : 1;
- uint8 m_IsIgnoredByEveryOne : 1;
- uint8 m_IsSwatRequired : 1;
- uint8 m_IsFbiRequired : 1;
- uint8 m_IdArmyRequired : 1;
- int8 field_23;
+ uint8 m_bIgnoredByCops : 1;
+ uint8 m_bIgnoredByEveryone : 1;
+ uint8 m_bSwatRequired : 1;
+ uint8 m_bFbiRequired : 1;
+ uint8 m_bArmyRequired : 1;
int32 m_nWantedLevel;
- CCrime m_sCrimes[16];
+ CCrimeBeingQd m_aCrimes[16];
CCopPed *m_pCops[10];
+
static int32 &MaximumWantedLevel;
+ static int32 &nMaximumWantedLevel;
public:
+ void Initialise();
bool AreSwatRequired();
bool AreFbiRequired();
bool AreArmyRequired();
- int NumOfHelisRequired();
+ int32 NumOfHelisRequired();
void SetWantedLevel(int32);
void SetWantedLevelNoDrop(int32 level);
+ void RegisterCrime(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare);
+ void RegisterCrime_Immediately(eCrimeType type, const CVector &coors, uint32 id, bool policeDoesntCare);
void ClearQdCrimes();
+ bool AddCrimeToQ(eCrimeType type, int32 id, const CVector &pos, bool reported, bool policeDoesntCare);
+ void ReportCrimeNow(eCrimeType type, const CVector &coors, bool policeDoesntCare);
void UpdateWantedLevel();
+
+ static int32 WorkOutPolicePresence(CVector posn, float radius);
+ static void SetMaximumWantedLevel(int32 level);
};
static_assert(sizeof(CWanted) == 0x204, "CWanted: error");
diff --git a/src/core/config.h b/src/core/config.h
index b1efd4b6..0736d343 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -62,6 +62,7 @@ enum Config {
NUMONSCREENTIMERENTRIES = 1,
NUMRADARBLIPS = 32,
NUMPICKUPS = 336,
+ NUMEVENTS = 64,
};
// We'll use this once we're ready to become independent of the game
diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h
index 0d9ffb53..135f3424 100644
--- a/src/modelinfo/ModelIndices.h
+++ b/src/modelinfo/ModelIndices.h
@@ -465,3 +465,21 @@ IsPickupModel(int16 id)
id == MI_PICKUP_KILLFRENZY ||
id == MI_PICKUP_CAMERA;
}
+
+inline bool
+IsPolicePedModel(int16 id)
+{
+ return id == MI_COP ||
+ id == MI_SWAT ||
+ id == MI_FBI ||
+ id == MI_ARMY;
+}
+
+inline bool
+IsPoliceVehicleModel(int16 id)
+{
+ return id == MI_CHOPPER ||
+ id == MI_PREDATOR ||
+ id == MI_POLICE ||
+ id == MI_ENFORCER;
+}
diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h
index 5827f9bc..f8139046 100644
--- a/src/peds/CopPed.h
+++ b/src/peds/CopPed.h
@@ -1,27 +1,6 @@
#pragma once
#include "Ped.h"
-enum eCrimeType
-{
- CRIME_NONE,
- CRIME_POSSESSION_GUN,
- CRIME_HIT_PED,
- CRIME_HIT_COP,
- CRIME_SHOOT_PED,
- CRIME_SHOOT_COP,
- CRIME_STEAL_CAR,
- CRIME_RUN_REDLIGHT,
- CRIME_RECKLESS_DRIVING,
- CRIME_SPEEDING,
- CRIME_RUNOVER_PED,
- CRIME_RUNOVER_COP,
- CRIME_SHOOT_HELI,
- CRIME_PED_BURNED,
- CRIME_COP_BURNED,
- CRIME_VEHICLE_BURNED,
- CRIME_DESTROYED_CESSNA,
-};
-
enum eCopType
{
COP_STREET = 0,
@@ -30,18 +9,6 @@ enum eCopType
COP_ARMY = 3,
};
-class CCrime
-{
-public:
- eCrimeType m_eCrimeType;
- CEntity *m_pVictim;
- int32 m_nCrimeTime;
- CVector m_vecCrimePos;
- int8 m_bReported;
- int8 m_bMultiplier;
- int8 pad_20[2];
-};
-
class CCopPed : public CPed
{
public: