From 60711154baf5477d6f4c12add1ecdd0a24c0c116 Mon Sep 17 00:00:00 2001 From: aap Date: Fri, 12 Jul 2019 18:01:22 +0200 Subject: [PATCH] more CWanted; added CEventList --- src/audio/DMAudio.cpp | 3 +- src/audio/DMAudio.h | 2 + src/control/Darkel.cpp | 2 +- src/control/Script.cpp | 4 +- src/core/EventList.cpp | 238 +++++++++++++++++++++++++++ src/core/EventList.h | 65 ++++++++ src/core/Pools.cpp | 8 + src/core/Pools.h | 6 + src/core/Wanted.cpp | 304 +++++++++++++++++++++++++++++++---- src/core/Wanted.h | 71 +++++--- src/core/config.h | 1 + src/modelinfo/ModelIndices.h | 18 +++ src/peds/CopPed.h | 33 ---- 13 files changed, 666 insertions(+), 89 deletions(-) create mode 100644 src/core/EventList.cpp create mode 100644 src/core/EventList.h 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: