summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/Pad.h4
-rw-r--r--src/core/Pools.cpp8
-rw-r--r--src/core/Pools.h6
-rw-r--r--src/core/Wanted.cpp306
-rw-r--r--src/core/Wanted.h73
-rw-r--r--src/core/config.h1
-rw-r--r--src/core/re3.cpp13
-rw-r--r--src/modelinfo/ModelIndices.h18
-rw-r--r--src/peds/CopPed.h33
-rw-r--r--src/peds/PlayerPed.cpp2
-rw-r--r--src/peds/PlayerPed.h1
-rw-r--r--src/render/Draw.h5
-rw-r--r--src/vehicles/Automobile.cpp132
-rw-r--r--src/vehicles/Vehicle.cpp4
-rw-r--r--src/vehicles/Vehicle.h6
21 files changed, 827 insertions, 99 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/Pad.h b/src/core/Pad.h
index 30cdb8df..30a9980b 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -289,6 +289,10 @@ public:
// mouse
bool GetLeftMouseJustDown() { return !!(NewMouseControllerState.LMB && !OldMouseControllerState.LMB); }
+ bool GetRightMouseJustDown() { return !!(NewMouseControllerState.RMB && !OldMouseControllerState.RMB); }
+ bool GetMiddleMouseJustDown() { return !!(NewMouseControllerState.MMB && !OldMouseControllerState.MMB); }
+ float GetMouseX() { return NewMouseControllerState.x; }
+ float GetMouseY() { return NewMouseControllerState.y; }
// keyboard
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..7b865311 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,212 @@ 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;
+ if (policeDoesntCare)
+ chaos *= 0.333f;
+ 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 +320,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/core/re3.cpp b/src/core/re3.cpp
index 8bb9caee..4876c555 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -154,7 +154,7 @@ spawnCar(int id)
}
#endif
-void
+static void
FixCar(void)
{
CVehicle *veh = FindPlayerVehicle();
@@ -167,6 +167,15 @@ FixCar(void)
((CAutomobile*)veh)->Fix();
}
+static void
+ToggleComedy(void)
+{
+ CVehicle *veh = FindPlayerVehicle();
+ if(veh == nil)
+ return;
+ veh->bComedyControls = !veh->bComedyControls;
+}
+
void
DebugMenuPopulate(void)
{
@@ -212,6 +221,8 @@ DebugMenuPopulate(void)
DebugMenuAddCmd("Cheats", "Nasty limbs", NastyLimbsCheat);
DebugMenuAddCmd("Debug", "Fix Car", FixCar);
+ DebugMenuAddCmd("Debug", "Toggle Comedy Controls", ToggleComedy);
+
DebugMenuAddVarBool8("Debug", "Show Ped Road Groups", (int8*)&gbShowPedRoadGroups, nil);
DebugMenuAddVarBool8("Debug", "Show Car Road Groups", (int8*)&gbShowCarRoadGroups, nil);
DebugMenuAddVarBool8("Debug", "Show Collision Polys", (int8*)&gbShowCollisionPolys, nil);
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:
diff --git a/src/peds/PlayerPed.cpp b/src/peds/PlayerPed.cpp
index 4b484a7f..3bab2d31 100644
--- a/src/peds/PlayerPed.cpp
+++ b/src/peds/PlayerPed.cpp
@@ -13,6 +13,8 @@ WRAPPER void CPlayerPed::ReApplyMoveAnims(void) { EAXJMP(0x4F07C0); }
WRAPPER void CPlayerPed::SetupPlayerPed(int32) { EAXJMP(0x4EFB60); }
WRAPPER void CPlayerPed::DeactivatePlayerPed(int32) { EAXJMP(0x4EFC00); }
WRAPPER void CPlayerPed::ReactivatePlayerPed(int32) { EAXJMP(0x4EFC20); }
+WRAPPER void CPlayerPed::KeepAreaAroundPlayerClear(void) { EAXJMP(0x4F3460); }
+
void CPlayerPed::ClearWeaponTarget()
{
diff --git a/src/peds/PlayerPed.h b/src/peds/PlayerPed.h
index 51a45203..1dfa33fa 100644
--- a/src/peds/PlayerPed.h
+++ b/src/peds/PlayerPed.h
@@ -45,6 +45,7 @@ public:
void ClearWeaponTarget();
void SetWantedLevel(int32 level);
void SetWantedLevelNoDrop(int32 level);
+ void KeepAreaAroundPlayerClear(void);
static void SetupPlayerPed(int32);
static void DeactivatePlayerPed(int32);
diff --git a/src/render/Draw.h b/src/render/Draw.h
index ad14e5a9..75b2b75f 100644
--- a/src/render/Draw.h
+++ b/src/render/Draw.h
@@ -2,9 +2,12 @@
enum eAspectRatio
{
- AR_AUTO,
+ // Make sure these work the same as FrontEndMenuManager.m_PrefsUseWideScreen
+ // without widescreen support
AR_4_3,
AR_16_9,
+
+ AR_AUTO,
};
class CDraw
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index 7d3f8ee3..1f64228b 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -1,6 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "General.h"
+#include "Pad.h"
#include "ModelIndices.h"
#include "VisibilityPlugins.h"
#include "DMAudio.h"
@@ -141,8 +142,134 @@ CAutomobile::ProcessEntityCollision(CEntity *ent, CColPoint *colpoints)
return numCollisions;
}
+static int16 nLastControlInput;
+static float fMouseCentreRange = 0.35f;
+static float fMouseSteerSens = -0.0035f;
+static float fMouseCentreMult = 0.975f;
-WRAPPER void CAutomobile::ProcessControlInputs(uint8) { EAXJMP(0x53B660); }
+void
+CAutomobile::ProcessControlInputs(uint8 pad)
+{
+ float speed = DotProduct(m_vecMoveSpeed, GetForward());
+
+ if(CPad::GetPad(pad)->GetExitVehicle())
+ bIsHandbrakeOn = true;
+ else
+ bIsHandbrakeOn = !!CPad::GetPad(pad)->GetHandBrake();
+
+ // Steer left/right
+ if(CCamera::m_bUseMouse3rdPerson && !CVehicle::m_bDisableMouseSteering){
+ if(CPad::GetPad(pad)->GetMouseX() != 0.0f){
+ m_fSteerRatio += fMouseSteerSens*CPad::GetPad(pad)->GetMouseX();
+ nLastControlInput = 2;
+ if(Abs(m_fSteerRatio) < fMouseCentreRange)
+ m_fSteerRatio *= Pow(fMouseCentreMult, CTimer::GetTimeStep());
+ }else if(CPad::GetPad(pad)->GetSteeringLeftRight() || nLastControlInput != 2){
+ // mouse hasn't move, steer with pad like below
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ }else{
+ m_fSteerRatio += (-CPad::GetPad(pad)->GetSteeringLeftRight()/128.0f - m_fSteerRatio)*
+ 0.2f*CTimer::GetTimeStep();
+ nLastControlInput = 0;
+ }
+ m_fSteerRatio = clamp(m_fSteerRatio, -1.0f, 1.0f);
+
+ // Accelerate/Brake
+ float acceleration = (CPad::GetPad(pad)->GetAccelerate() - CPad::GetPad(pad)->GetBrake())/255.0f;
+ if(GetModelIndex() == MI_DODO && acceleration < 0.0f)
+ acceleration *= 0.3f;
+ if(Abs(speed) < 0.01f){
+ // standing still, go into direction we want
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+#if 1
+ // simpler than the code below
+ if(speed * acceleration < 0.0f){
+ // if opposite directions, have to brake first
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = Abs(acceleration);
+ }else{
+ // accelerating in same direction we were already going
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+#else
+ if(speed < 0.0f){
+ // moving backwards currently
+ if(acceleration < 0.0f){
+ // still go backwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }else{
+ // want to go forwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = acceleration;
+ }
+ }else{
+ // moving forwards currently
+ if(acceleration < 0.0f){
+ // want to go backwards, so brake
+ m_fGasPedal = 0.0f;
+ m_fBrakePedal = -acceleration;
+ }else{
+ // still go forwards
+ m_fGasPedal = acceleration;
+ m_fBrakePedal = 0.0f;
+ }
+ }
+#endif
+ }
+
+ // Actually turn wheels
+ static float fValue; // why static?
+ if(m_fSteerRatio < 0.0f)
+ fValue = -sq(m_fSteerRatio);
+ else
+ fValue = sq(m_fSteerRatio);
+ m_fSteerAngle = DEGTORAD(m_handling->fSteeringLock) * fValue;
+
+ if(bComedyControls){
+ int rnd = CGeneral::GetRandomNumber() % 10;
+ switch(m_comedyControlState){
+ case 0:
+ if(rnd < 2)
+ m_comedyControlState = 1;
+ else if(rnd < 4)
+ m_comedyControlState = 2;
+ break;
+ case 1:
+ m_fSteerAngle += 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ case 2:
+ m_fSteerAngle -= 0.05f;
+ if(rnd < 2)
+ m_comedyControlState = 0;
+ break;
+ }
+ }else
+ m_comedyControlState = 0;
+
+ // Brake if player isn't in control
+ // BUG: game always uses pad 0 here
+ if(CPad::GetPad(pad)->DisablePlayerControls){
+ m_fBrakePedal = 1.0f;
+ bIsHandbrakeOn = true;
+ m_fGasPedal = 0.0f;
+
+ FindPlayerPed()->KeepAreaAroundPlayerClear();
+
+ // slow down car immediately
+ speed = m_vecMoveSpeed.Magnitude();
+ if(speed > 0.28f)
+ m_vecMoveSpeed *= 0.28f/speed;
+ }
+}
void
CAutomobile::GetComponentWorldPosition(int32 component, CVector &pos)
@@ -1091,7 +1218,7 @@ public:
int32 ProcessEntityCollision_(CEntity *ent, CColPoint *colpoints){ return CAutomobile::ProcessEntityCollision(ent, colpoints); }
- void ProcessControlInputs_(uint8 x) { CAutomobile::ProcessControlInputs(x); }
+ void ProcessControlInputs_(uint8 pad) { CAutomobile::ProcessControlInputs(pad); }
void GetComponentWorldPosition_(int32 component, CVector &pos) { CAutomobile::GetComponentWorldPosition(component, pos); }
bool IsComponentPresent_(int32 component) { return CAutomobile::IsComponentPresent(component); }
void SetComponentRotation_(int32 component, CVector rotation) { CAutomobile::SetComponentRotation(component, rotation); }
@@ -1115,6 +1242,7 @@ STARTPATCHES
InjectHook(0x52D190, &CAutomobile_::SetModelIndex_, PATCH_JUMP);
InjectHook(0x535180, &CAutomobile_::Teleport_, PATCH_JUMP);
InjectHook(0x53B270, &CAutomobile_::ProcessEntityCollision_, PATCH_JUMP);
+ InjectHook(0x53B660, &CAutomobile_::ProcessControlInputs_, PATCH_JUMP);
InjectHook(0x52E5F0, &CAutomobile_::GetComponentWorldPosition_, PATCH_JUMP);
InjectHook(0x52E660, &CAutomobile_::IsComponentPresent_, PATCH_JUMP);
InjectHook(0x52E680, &CAutomobile_::SetComponentRotation_, PATCH_JUMP);
diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp
index d8ed1a15..b21c859a 100644
--- a/src/vehicles/Vehicle.cpp
+++ b/src/vehicles/Vehicle.cpp
@@ -58,7 +58,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_nBombTimer = 0;
m_pWhoSetMeOnFire = nil;
field_1FB = 0;
- m_veh_flagB10 = false;
+ bComedyControls = false;
m_veh_flagB40 = false;
m_veh_flagB80 = false;
m_veh_flagC1 = false;
@@ -93,7 +93,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_pCurGroundEntity = nil;
field_22A = 0;
field_22B = 0;
- field_22F = 0;
+ m_comedyControlState = 0;
m_aCollPolys[0].valid = false;
m_aCollPolys[1].valid = false;
m_autoPilot.m_nCarMission = MISSION_NONE;
diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h
index c293b8a6..55805e9d 100644
--- a/src/vehicles/Vehicle.h
+++ b/src/vehicles/Vehicle.h
@@ -144,7 +144,7 @@ public:
CFire *m_pCarFire;
float m_fSteerAngle;
float m_fGasPedal;
- float m_fBreakPedal;
+ float m_fBrakePedal;
uint8 VehicleCreatedBy;
// cf. https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CVehicle.h from R*
@@ -161,7 +161,7 @@ public:
uint8 bIsBus: 1; // Is this vehicle a bus
uint8 bIsBig: 1; // Is this vehicle a bus
uint8 bLowVehicle: 1; // Need this for sporty type cars to use low getting-in/out anims
- uint8 m_veh_flagB10 : 1;
+ uint8 bComedyControls : 1; // Will make the car hard to control (hopefully in a funny way)
uint8 m_veh_flagB20 : 1;
uint8 m_veh_flagB40 : 1;
uint8 m_veh_flagB80 : 1;
@@ -207,7 +207,7 @@ public:
uint8 m_nCarHornTimer;
int8 field_22D;
bool m_bSirenOrAlarm;
- int8 field_22F;
+ int8 m_comedyControlState;
CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car
float m_fSteerRatio;
eVehicleType m_vehType;