summaryrefslogtreecommitdiffstats
path: root/src/control
diff options
context:
space:
mode:
authorNikolay Korolev <nickvnuk@gmail.com>2019-08-11 19:11:54 +0200
committerNikolay Korolev <nickvnuk@gmail.com>2019-08-11 19:11:54 +0200
commit14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0 (patch)
tree671d1b9f6f0a3b67449f8d41b28724fe890619b4 /src/control
parentMerge remote-tracking branch 'upstream/master' (diff)
downloadre3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar.gz
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar.bz2
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar.lz
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar.xz
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.tar.zst
re3-14b945ba08bfa18d8ac61bb7f5c08b299ce8a2b0.zip
Diffstat (limited to '')
-rw-r--r--src/control/AutoPilot.cpp5
-rw-r--r--src/control/AutoPilot.h24
-rw-r--r--src/control/CarAI.cpp13
-rw-r--r--src/control/CarAI.h1
-rw-r--r--src/control/CarCtrl.cpp336
-rw-r--r--src/control/CarCtrl.h37
-rw-r--r--src/control/Cranes.cpp5
-rw-r--r--src/control/Cranes.h10
-rw-r--r--src/control/Gangs.cpp2
-rw-r--r--src/control/Gangs.h3
-rw-r--r--src/control/Garages.cpp1
-rw-r--r--src/control/Garages.h1
-rw-r--r--src/control/PathFind.h2
-rw-r--r--src/control/RoadBlocks.cpp5
-rw-r--r--src/control/RoadBlocks.h10
-rw-r--r--src/control/Script.cpp6
-rw-r--r--src/control/TrafficLights.cpp3
-rw-r--r--src/control/TrafficLights.h3
18 files changed, 424 insertions, 43 deletions
diff --git a/src/control/AutoPilot.cpp b/src/control/AutoPilot.cpp
new file mode 100644
index 00000000..54b51454
--- /dev/null
+++ b/src/control/AutoPilot.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "AutoPilot.h"
+
+WRAPPER void CAutoPilot::ModifySpeed(float) { EAXJMP(0x4137B0); }
diff --git a/src/control/AutoPilot.h b/src/control/AutoPilot.h
index 3ace0a51..e0adc23a 100644
--- a/src/control/AutoPilot.h
+++ b/src/control/AutoPilot.h
@@ -64,25 +64,25 @@ public:
uint32 m_nNextRouteNode;
uint32 m_nPrevRouteNode;
uint32 m_nTimeEnteredCurve;
- uint32 m_nCurveSpeedScale;
+ uint32 m_nTimeToSpendOnCurrentCurve;
uint32 m_nCurrentPathNodeInfo;
uint32 m_nNextPathNodeInfo;
uint32 m_nPreviousPathNodeInfo;
uint32 m_nTimeToStartMission;
- uint32 m_nTimeSwitchedToRealPhysics;
+ uint32 m_nAntiReverseTimer;
int8 m_nPreviousDirection;
int8 m_nCurrentDirection;
int8 m_nNextDirection;
- int8 m_nPreviousLane;
int8 m_nCurrentLane;
+ int8 m_nNextLane;
eCarDrivingStyle m_nDrivingStyle;
eCarMission m_nCarMission;
- eCarTempAction m_nAnimationId;
- uint8 m_nAnimationTime;
+ eCarTempAction m_nTempAction;
+ uint32 m_nTimeTempAction;
float m_fMaxTrafficSpeed;
uint8 m_nCruiseSpeed;
uint8 m_flag1 : 1;
- uint8 m_flag2 : 1;
+ uint8 m_bSlowedDownBecauseOfPeds : 1;
uint8 m_flag4 : 1;
uint8 m_flag8 : 1;
uint8 m_flag10 : 1;
@@ -96,25 +96,27 @@ public:
m_nNextRouteNode = m_nPrevRouteNode;
m_nCurrentRouteNode = m_nNextRouteNode;
m_nTimeEnteredCurve = 0;
- m_nCurveSpeedScale = 1000;
+ m_nTimeToSpendOnCurrentCurve = 1000;
m_nPreviousPathNodeInfo = 0;
m_nNextPathNodeInfo = m_nPreviousPathNodeInfo;
m_nCurrentPathNodeInfo = m_nNextPathNodeInfo;
m_nNextDirection = 1;
m_nCurrentDirection = m_nNextDirection;
- m_nPreviousLane = m_nCurrentLane = 0;
+ m_nCurrentLane = m_nNextLane = 0;
m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
m_nCarMission = MISSION_NONE;
- m_nAnimationId = TEMPACT_NONE;
+ m_nTempAction = TEMPACT_NONE;
m_nCruiseSpeed = 10;
m_fMaxTrafficSpeed = 10.0f;
- m_flag2 = false;
+ m_bSlowedDownBecauseOfPeds = false;
m_flag1 = false;
m_nPathFindNodesCount = 0;
m_pTargetCar = 0;
m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
- m_nTimeSwitchedToRealPhysics = m_nTimeToStartMission;
+ m_nAntiReverseTimer = m_nTimeToStartMission;
m_flag8 = false;
}
+
+ void ModifySpeed(float);
};
static_assert(sizeof(CAutoPilot) == 0x70, "CAutoPilot: error");
diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp
index 5129f112..470c3d24 100644
--- a/src/control/CarAI.cpp
+++ b/src/control/CarAI.cpp
@@ -2,8 +2,21 @@
#include "patcher.h"
#include "CarAI.h"
+#include "AutoPilot.h"
+#include "Timer.h"
+#include "Vehicle.h"
+
WRAPPER void CCarAI::UpdateCarAI(CVehicle*) { EAXJMP(0x413E50); }
WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
+
+void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)
+{
+ pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
+}
+
+STARTPATCHES
+InjectHook(0x415B00, &CCarAI::CarHasReasonToStop, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/control/CarAI.h b/src/control/CarAI.h
index 865cb467..0b0a939b 100644
--- a/src/control/CarAI.h
+++ b/src/control/CarAI.h
@@ -12,4 +12,5 @@ public:
static int32 FindPoliceCarSpeedForWantedLevel(CVehicle*);
static eCarMission FindPoliceCarMissionForWantedLevel();
static void AddPoliceOccupants(CVehicle*);
+ static void CarHasReasonToStop(CVehicle*);
};
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index b83b8fec..b2468a76 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -6,8 +6,11 @@
#include "Camera.h"
#include "CarAI.h"
#include "CarGen.h"
+#include "Cranes.h"
#include "Curves.h"
#include "CutsceneMgr.h"
+#include "Gangs.h"
+#include "Garages.h"
#include "General.h"
#include "IniFile.h"
#include "ModelIndices.h"
@@ -15,7 +18,11 @@
#include "Ped.h"
#include "PlayerInfo.h"
#include "PlayerPed.h"
+#include "Pools.h"
+#include "Renderer.h"
+#include "RoadBlocks.h"
#include "Timer.h"
+#include "TrafficLights.h"
#include "Streaming.h"
#include "VisibilityPlugins.h"
#include "Vehicle.h"
@@ -23,7 +30,8 @@
#include "World.h"
#include "Zones.h"
-#define LANE_WIDTH 5.0f
+#define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS 51.0f
+#define DISTANCE_TO_SCAN_FOR_DANGER 11.0f
#define INFINITE_Z 1000000000.0f
int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
@@ -40,19 +48,19 @@ uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
int32 (&CCarCtrl::TotalNumOfCarsOfRating)[7] = *(int32(*)[7])*(uintptr*)0x8F1A60;
int32 (&CCarCtrl::NextCarOfRating)[7] = *(int32(*)[7])*(uintptr*)0x9412AC;
int32 (&CCarCtrl::CarArrays)[7][256] = *(int32(*)[7][256])*(uintptr*)0x6EB860;
+CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])0x70D830;
WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); }
-WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); }
WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); }
WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); }
WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
-WRAPPER void CCarCtrl::UpdateCarOnRails(CVehicle*) { EAXJMP(0x418880); }
-WRAPPER void CCarCtrl::ScanForPedDanger(CVehicle *veh) { EAXJMP(0x418F40); }
WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); }
-WRAPPER int32 CCarCtrl::ChoosePoliceCarModel(void) { EAXJMP(0x4181F0); }
-WRAPPER int32 CCarCtrl::ChooseGangCarModel(int32 gang) { EAXJMP(0x4182C0); }
+WRAPPER void CCarCtrl::PickNextNodeAccordingStrategy(CVehicle*) { EAXJMP(0x41BA50); }
+WRAPPER void CCarCtrl::DragCarToPoint(CVehicle*, CVector*) { EAXJMP(0x41D450); }
+WRAPPER void CCarCtrl::SlowCarDownForCarsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float) { EAXJMP(0x419B40); }
+WRAPPER void CCarCtrl::SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float) { EAXJMP(0x419300); }
void
CCarCtrl::GenerateRandomCars()
@@ -292,12 +300,12 @@ CCarCtrl::GenerateOneRandomCar()
}
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed;
pCar->AutoPilot.m_nCarMission = MISSION_CRUISE;
- pCar->AutoPilot.m_nAnimationId = TEMPACT_NONE;
+ pCar->AutoPilot.m_nTempAction = TEMPACT_NONE;
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
break;
}
case COPS:
- pCar->AutoPilot.m_nAnimationId = TEMPACT_NONE;
+ pCar->AutoPilot.m_nTempAction = TEMPACT_NONE;
if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){
pCar->AutoPilot.m_nCruiseSpeed = CCarAI::FindPoliceCarSpeedForWantedLevel(pCar);
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed / 2;
@@ -320,7 +328,7 @@ CCarCtrl::GenerateOneRandomCar()
if (pCar && pCar->GetModelIndex() == MI_MRWHOOP)
pCar->m_bSirenOrAlarm = true;
pCar->AutoPilot.m_nNextPathNodeInfo = connectionId;
- pCar->AutoPilot.m_nCurrentLane = pCar->AutoPilot.m_nPreviousLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad;
+ pCar->AutoPilot.m_nNextLane = pCar->AutoPilot.m_nCurrentLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad;
CColBox* boundingBox = &CModelInfo::GetModelInfo(pCar->GetModelIndex())->GetColModel()->boundingBox;
float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2;
float distanceBetweenNodes = (pCurNode->pos - pNextNode->pos).Magnitude2D();
@@ -366,27 +374,21 @@ CCarCtrl::GenerateOneRandomCar()
float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].dirY;
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
- float currentLaneCoefficient = (pCurrentLink->numLeftLanes == 0) ? (0.5f - 0.5f * pCurrentLink->numRightLanes) :
- ((pCurrentLink->numRightLanes == 0) ? (0.5f - 0.5f * pCurrentLink->numLeftLanes) : 0.5f);
- float roadShiftAlongCurrentNode = (pCar->AutoPilot.m_nPreviousLane + currentLaneCoefficient) * LANE_WIDTH;
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
- float nextLaneCoefficient = (pNextLink->numLeftLanes == 0) ? (0.5f - 0.5f * pNextLink->numRightLanes) :
- ((pNextLink->numRightLanes == 0) ? (0.5f - 0.5f * pNextLink->numLeftLanes) : 0.5f);
- float roadShiftAlongNextNode = (pCar->AutoPilot.m_nCurrentLane + nextLaneCoefficient) * LANE_WIDTH;
CVector positionOnCurrentLinkIncludingLane(
- pCurrentLink->posX + roadShiftAlongCurrentNode * currentPathLinkForwardY,
- pCurrentLink->posY - roadShiftAlongCurrentNode * currentPathLinkForwardX,
+ pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY,
+ pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX,
0.0f);
CVector positionOnNextLinkIncludingLane(
- pNextLink->posX + roadShiftAlongNextNode * nextPathLinkForwardY,
- pNextLink->posY - roadShiftAlongNextNode * nextPathLinkForwardX,
+ pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
+ pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
0.0f);
float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection;
float directionNextLinkX = pNextLink->dirX * pCar->AutoPilot.m_nNextDirection;
float directionNextLinkY = pNextLink->dirY * pCar->AutoPilot.m_nNextDirection;
/* We want to make a path between two links that may not have the same forward directions a curve. */
- pCar->AutoPilot.m_nCurveSpeedScale = CCurves::CalcSpeedScaleFactor(
+ pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane,
&positionOnNextLinkIncludingLane,
directionCurrentLinkX, directionCurrentLinkY,
@@ -396,13 +398,11 @@ CCarCtrl::GenerateOneRandomCar()
/* Casting timer to float is very unwanted. In this case it's not awful */
/* but in CAutoPilot::ModifySpeed it can even cause crashes (see SilentPatch). */
pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
- (uint32)((0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nCurveSpeedScale);
+ (uint32)((0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve);
#else
pCar->AutoPilot.m_nTotalSpeedScaleFactor = CTimer::GetTimeInMilliseconds() -
(0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nSpeedScaleFactor;
#endif
- uint32 timeAlreadyInCurve = CTimer::GetTimeInMilliseconds() - pCar->AutoPilot.m_nTimeEnteredCurve;
- float positionAlongCurve = (float)timeAlreadyInCurve / pCar->AutoPilot.m_nCurveSpeedScale;
CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f);
CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f);
CVector positionIncludingCurve;
@@ -412,8 +412,8 @@ CCarCtrl::GenerateOneRandomCar()
&positionOnNextLinkIncludingLane,
&directionCurrentLink,
&directionNextLink,
- positionAlongCurve,
- pCar->AutoPilot.m_nCurveSpeedScale,
+ GetPositionAlongCurrentCurve(pCar),
+ pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve,
&positionIncludingCurve,
&directionIncludingCurve
);
@@ -587,6 +587,289 @@ CCarCtrl::ChooseCarModel(int32 vehclass)
return model;
}
+int32
+CCarCtrl::ChoosePoliceCarModel(void)
+{
+ if (FindPlayerPed()->m_pWanted->AreSwatRequired() &&
+ CStreaming::HasModelLoaded(MI_ENFORCER) &&
+ CStreaming::HasModelLoaded(MI_POLICE))
+ return ((CGeneral::GetRandomNumber() & 0xF) == 0) ? MI_ENFORCER : MI_POLICE;
+ if (FindPlayerPed()->m_pWanted->AreFbiRequired() &&
+ CStreaming::HasModelLoaded(MI_FBICAR) &&
+ CStreaming::HasModelLoaded(MI_FBI))
+ return MI_FBICAR;
+ if (FindPlayerPed()->m_pWanted->AreArmyRequired() &&
+ CStreaming::HasModelLoaded(MI_RHINO) &&
+ CStreaming::HasModelLoaded(MI_BARRACKS) &&
+ CStreaming::HasModelLoaded(MI_RHINO))
+ return CGeneral::GetRandomTrueFalse() ? MI_BARRACKS : MI_RHINO;
+ return MI_POLICE;
+}
+
+int32
+CCarCtrl::ChooseGangCarModel(int32 gang)
+{
+ if (CStreaming::HasModelLoaded(MI_GANG01 + 2 * gang) &&
+ CStreaming::HasModelLoaded(MI_GANG02 + 2 * gang))
+ return CGangs::GetGangVehicleModel(gang);
+ return -1;
+}
+
+void
+CCarCtrl::AddToCarArray(int32 id, int32 vehclass)
+{
+ CarArrays[vehclass][TotalNumOfCarsOfRating[vehclass]++] = id;
+}
+
+void
+CCarCtrl::RemoveDistantCars()
+{
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (--i){
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ PossiblyRemoveVehicle(pVehicle);
+ if (pVehicle->bCreateRoadBlockPeds){
+ if ((pVehicle->GetPosition() - FindPlayerCentreOfWorld(CWorld::PlayerInFocus)).Magnitude2D() < DISTANCE_TO_SPAWN_ROADBLOCK_PEDS) {
+ CRoadBlocks::GenerateRoadBlockCopsForCar(pVehicle, pVehicle->m_nRoadblockType, pVehicle->m_nRoadblockNode);
+ pVehicle->bCreateRoadBlockPeds = false;
+ }
+ }
+ }
+}
+
+void
+CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle)
+{
+ CVector vecPlayerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus);
+ /* BUG: this variable is initialized only in if-block below but can be used outside of it. */
+ if (!IsThisVehicleInteresting(pVehicle) && !pVehicle->bIsLocked &&
+ pVehicle->CanBeDeleted() && !CCranes::IsThisCarBeingTargettedByAnyCrane(pVehicle)){
+ if (pVehicle->bFadeOut && CVisibilityPlugins::GetClumpAlpha(pVehicle->GetClump()) == 0){
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ return;
+ }
+ float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D();
+ float threshold = 50.0f;
+ if (pVehicle->GetIsOnScreen() ||
+ TheCamera.Cams[TheCamera.ActiveCam].LookingLeft ||
+ TheCamera.Cams[TheCamera.ActiveCam].LookingRight ||
+ TheCamera.Cams[TheCamera.ActiveCam].LookingBehind ||
+ TheCamera.GetLookDirection() == 0 ||
+ pVehicle->VehicleCreatedBy == PARKED_VEHICLE ||
+ pVehicle->GetModelIndex() == MI_AMBULAN ||
+ pVehicle->GetModelIndex() == MI_FIRETRUCK ||
+ pVehicle->bIsLawEnforcer ||
+ pVehicle->bIsCarParkVehicle
+ ){
+ threshold = 130.0f * TheCamera.GenerationDistMultiplier;
+ }
+ if (pVehicle->bExtendedRange)
+ threshold *= 1.5f;
+ if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){
+ if (pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)){
+ pVehicle->bFadeOut = true;
+ }else{
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ }
+ return;
+ }
+ }
+ if ((pVehicle->m_status == STATUS_SIMPLE || pVehicle->m_status == STATUS_PHYSICS && pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS) &&
+ CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeToStartMission > 5000 &&
+ !pVehicle->GetIsOnScreen() &&
+ (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f &&
+ !IsThisVehicleInteresting(pVehicle) &&
+ !pVehicle->bIsLocked &&
+ !CTrafficLights::ShouldCarStopForLight(pVehicle, true) &&
+ !CTrafficLights::ShouldCarStopForBridge(pVehicle) &&
+ !CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ return;
+ }
+ if (pVehicle->m_status != STATUS_WRECKED || pVehicle->m_nTimeOfDeath == 0)
+ return;
+ if (CTimer::GetTimeInMilliseconds() > pVehicle->m_nTimeOfDeath + 60000 &&
+ (!pVehicle->GetIsOnScreen() || CRenderer::IsEntityCullZoneVisible(pVehicle))){
+ if ((pVehicle->GetPosition() - vecPlayerPos).MagnitudeSqr() > SQR(7.5f)){
+ if (!CGarages::IsPointWithinHideOutGarage(&pVehicle->GetPosition())){
+ CWorld::Remove(pVehicle);
+ delete pVehicle;
+ }
+ }
+ }
+}
+
+int32
+CCarCtrl::CountCarsOfType(int32 mi)
+{
+ int32 total = 0;
+ uint32 i = CPools::GetVehiclePool()->GetSize();
+ while (i--){
+ CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
+ if (!pVehicle)
+ continue;
+ if (pVehicle->GetModelIndex() == mi)
+ total++;
+ }
+ return total;
+}
+
+bool
+CCarCtrl::IsThisVehicleInteresting(CVehicle* pVehicle)
+{
+ for (int i = 0; i < MAX_CARS_TO_KEEP; i++) {
+ if (apCarsToKeep[i] == pVehicle)
+ return true;
+ }
+ return false;
+}
+
+void
+CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
+{
+ if (pVehicle->AutoPilot.m_nTempAction == TEMPACT_WAIT){
+ pVehicle->SetMoveSpeed(0.0f, 0.0f, 0.0f);
+ pVehicle->AutoPilot.ModifySpeed(0.0f);
+ if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTempAction){
+ pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
+ pVehicle->AutoPilot.m_nAntiReverseTimer = 0;
+ pVehicle->AutoPilot.m_nTimeToStartMission = 0;
+ }
+ return;
+ }
+ SlowCarOnRailsDownForTrafficAndLights(pVehicle);
+ if (pVehicle->AutoPilot.m_nTimeEnteredCurve + pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve <= CTimer::GetTimeInMilliseconds())
+ PickNextNodeAccordingStrategy(pVehicle);
+ if (pVehicle->m_status == STATUS_PHYSICS)
+ return;
+ CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
+ CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
+ float currentPathLinkForwardX = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
+ float currentPathLinkForwardY = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
+ float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
+ float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
+ CVector positionOnCurrentLinkIncludingLane(
+ pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY,
+ pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX,
+ 0.0f);
+ CVector positionOnNextLinkIncludingLane(
+ pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY,
+ pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX,
+ 0.0f);
+ CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f);
+ CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f);
+ CVector positionIncludingCurve;
+ CVector directionIncludingCurve;
+ CCurves::CalcCurvePoint(
+ &positionOnCurrentLinkIncludingLane,
+ &positionOnNextLinkIncludingLane,
+ &directionCurrentLink,
+ &directionNextLink,
+ GetPositionAlongCurrentCurve(pVehicle),
+ pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve,
+ &positionIncludingCurve,
+ &directionIncludingCurve
+ );
+ positionIncludingCurve.z = 15.0f;
+ DragCarToPoint(pVehicle, &positionIncludingCurve);
+ pVehicle->SetMoveSpeed(directionIncludingCurve / 60.0f);
+}
+
+float
+CCarCtrl::FindMaximumSpeedForThisCarInTraffic(CVehicle* pVehicle)
+{
+ if (pVehicle->AutoPilot.m_nDrivingStyle == MISSION_RAMPLAYER_FARAWAY ||
+ pVehicle->AutoPilot.m_nDrivingStyle == MISSION_RAMPLAYER_CLOSE)
+ return pVehicle->AutoPilot.m_nCruiseSpeed;
+ float left = pVehicle->GetPosition().x - DISTANCE_TO_SCAN_FOR_DANGER;
+ float right = pVehicle->GetPosition().x + DISTANCE_TO_SCAN_FOR_DANGER;
+ float top = pVehicle->GetPosition().y - DISTANCE_TO_SCAN_FOR_DANGER;
+ float bottom = pVehicle->GetPosition().y + DISTANCE_TO_SCAN_FOR_DANGER;
+ int xstart = max(0, CWorld::GetSectorIndexX(left));
+ int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(right));
+ int ystart = max(0, CWorld::GetSectorIndexY(top));
+ int yend = min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(bottom));
+ assert(xstart <= xend);
+ assert(ystart <= yend);
+
+ float maxSpeed = pVehicle->AutoPilot.m_nCruiseSpeed;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for (int y = ystart; y <= yend; y++){
+ for (int x = xstart; x <= xend; x++){
+ CSector* s = CWorld::GetSector(x, y);
+ SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ }
+ }
+ pVehicle->bWarnedPeds = true;
+ if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS)
+ return maxSpeed;
+ return (maxSpeed + pVehicle->AutoPilot.m_nDrivingStyle) / 2;
+}
+
+void
+CCarCtrl::ScanForPedDanger(CVehicle* pVehicle)
+{
+ bool storedSlowDownFlag = pVehicle->AutoPilot.m_bSlowedDownBecauseOfPeds;
+ float left = pVehicle->GetPosition().x - DISTANCE_TO_SCAN_FOR_DANGER;
+ float right = pVehicle->GetPosition().x + DISTANCE_TO_SCAN_FOR_DANGER;
+ float top = pVehicle->GetPosition().y - DISTANCE_TO_SCAN_FOR_DANGER;
+ float bottom = pVehicle->GetPosition().y + DISTANCE_TO_SCAN_FOR_DANGER;
+ int xstart = max(0, CWorld::GetSectorIndexX(left));
+ int xend = min(NUMSECTORS_X - 1, CWorld::GetSectorIndexX(right));
+ int ystart = max(0, CWorld::GetSectorIndexY(top));
+ int yend = min(NUMSECTORS_Y - 1, CWorld::GetSectorIndexY(bottom));
+ assert(xstart <= xend);
+ assert(ystart <= yend);
+
+ float maxSpeed = pVehicle->AutoPilot.m_nCruiseSpeed;
+
+ CWorld::AdvanceCurrentScanCode();
+
+ for (int y = ystart; y <= yend; y++) {
+ for (int x = xstart; x <= xend; x++) {
+ CSector* s = CWorld::GetSector(x, y);
+ SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed);
+ }
+ }
+ pVehicle->bWarnedPeds = true;
+ pVehicle->AutoPilot.m_bSlowedDownBecauseOfPeds = storedSlowDownFlag;
+}
+
+void
+CCarCtrl::SlowCarOnRailsDownForTrafficAndLights(CVehicle* pVehicle)
+{
+ float maxSpeed;
+ if (CTrafficLights::ShouldCarStopForLight(pVehicle, false) || CTrafficLights::ShouldCarStopForBridge(pVehicle)){
+ CCarAI::CarHasReasonToStop(pVehicle);
+ maxSpeed = 0.0f;
+ }else{
+ maxSpeed = FindMaximumSpeedForThisCarInTraffic(pVehicle);
+ }
+ float curSpeed = pVehicle->AutoPilot.m_fMaxTrafficSpeed;
+ if (maxSpeed >= curSpeed){
+ if (maxSpeed > curSpeed)
+ pVehicle->AutoPilot.ModifySpeed(min(maxSpeed, curSpeed + 0.05f * CTimer::GetTimeStep()));
+ }else{
+ if (curSpeed == 0.0f)
+ return;
+ if (curSpeed >= 0.1f)
+ pVehicle->AutoPilot.ModifySpeed(max(maxSpeed, curSpeed - 0.5f * CTimer::GetTimeStep()));
+ else if (curSpeed != 0.0f) /* no need to check */
+ pVehicle->AutoPilot.ModifySpeed(0.0f);
+ }
+}
+
bool
CCarCtrl::MapCouldMoveInThisArea(float x, float y)
{
@@ -598,4 +881,7 @@ CCarCtrl::MapCouldMoveInThisArea(float x, float y)
STARTPATCHES
InjectHook(0x416580, &CCarCtrl::GenerateRandomCars, PATCH_JUMP);
InjectHook(0x417EC0, &CCarCtrl::ChooseModel, PATCH_JUMP);
+InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP);
+InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
+InjectHook(0x418C10, &CCarCtrl::FindMaximumSpeedForThisCarInTraffic, PATCH_JUMP);
ENDPATCHES \ No newline at end of file
diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h
index 049ae449..735dc89c 100644
--- a/src/control/CarCtrl.h
+++ b/src/control/CarCtrl.h
@@ -1,8 +1,16 @@
#pragma once
+#include "PathFind.h"
+#include "Vehicle.h"
-class CVehicle;
class CZoneInfo;
+enum{
+ MAX_CARS_TO_KEEP = 2,
+ MAX_CAR_MODELS_IN_ARRAY = 256,
+};
+
+#define LANE_WIDTH 5.0f
+
class CCarCtrl
{
enum eCarClass {
@@ -43,6 +51,29 @@ public:
static int32 ChooseModel(CZoneInfo*, CVector*, int*);
static int32 ChoosePoliceCarModel(void);
static int32 ChooseGangCarModel(int32 gang);
+ static void RemoveDistantCars(void);
+ static void PossiblyRemoveVehicle(CVehicle*);
+ static bool IsThisVehicleInteresting(CVehicle*);
+ static int32 CountCarsOfType(int32 mi);
+ static void SlowCarOnRailsDownForTrafficAndLights(CVehicle*);
+ static void PickNextNodeAccordingStrategy(CVehicle*);
+ static void DragCarToPoint(CVehicle*, CVector*);
+ static float FindMaximumSpeedForThisCarInTraffic(CVehicle*);
+ static void SlowCarDownForCarsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
+ static void SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
+
+
+ static float GetOffsetOfLaneFromCenterOfRoad(int8 lane, CCarPathLink* pLink)
+ {
+ return (lane + ((pLink->numLeftLanes == 0) ? (0.5f - 0.5f * pLink->numRightLanes) :
+ ((pLink->numRightLanes == 0) ? (0.5f - 0.5f * pLink->numLeftLanes) : 0.5f))) * LANE_WIDTH;
+ }
+
+ static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
+ {
+ uint32 timeInCurve = CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeEnteredCurve;
+ return (float)timeInCurve / pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve;
+ }
static int32 &NumLawEnforcerCars;
static int32 &NumAmbulancesOnDuty;
@@ -57,5 +88,7 @@ public:
static uint32 &LastTimeLawEnforcerCreated;
static int32 (&TotalNumOfCarsOfRating)[7];
static int32 (&NextCarOfRating)[7];
- static int32 (&CarArrays)[7][256];
+ static int32 (&CarArrays)[7][MAX_CAR_MODELS_IN_ARRAY];
};
+
+extern CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP]; \ No newline at end of file
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp
new file mode 100644
index 00000000..f641bc75
--- /dev/null
+++ b/src/control/Cranes.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "Cranes.h"
+
+WRAPPER bool CCranes::IsThisCarBeingTargettedByAnyCrane(CVehicle*) { EAXJMP(0x5451E0); }
diff --git a/src/control/Cranes.h b/src/control/Cranes.h
new file mode 100644
index 00000000..e262d0c3
--- /dev/null
+++ b/src/control/Cranes.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "common.h"
+
+class CVehicle;
+
+class CCranes
+{
+public:
+ static bool IsThisCarBeingTargettedByAnyCrane(CVehicle*);
+};
diff --git a/src/control/Gangs.cpp b/src/control/Gangs.cpp
index fc77ad72..9ff40ef3 100644
--- a/src/control/Gangs.cpp
+++ b/src/control/Gangs.cpp
@@ -25,7 +25,7 @@ void CGangs::Initialize(void)
Gang[GANG_8].m_nVehicleMI = -1;
}
-void CGangs::SetGangVehicleModel(int16 gang, int model)
+void CGangs::SetGangVehicleModel(int16 gang, int32 model)
{
GetGangInfo(gang)->m_nVehicleMI = model;
}
diff --git a/src/control/Gangs.h b/src/control/Gangs.h
index 2366614b..dd24ddcb 100644
--- a/src/control/Gangs.h
+++ b/src/control/Gangs.h
@@ -33,7 +33,8 @@ class CGangs
{
public:
static void Initialize(void);
- static void SetGangVehicleModel(int16, int);
+ static void SetGangVehicleModel(int16, int32);
+ static int32 GetGangVehicleModel(int16 gang) { return Gang[gang].m_nVehicleMI; }
static void SetGangWeapons(int16, eWeaponType, eWeaponType);
static void SetGangPedModelOverride(int16, int8);
static int8 GetGangPedModelOverride(int16);
diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp
index 0629ac0c..3c5c142c 100644
--- a/src/control/Garages.cpp
+++ b/src/control/Garages.cpp
@@ -69,6 +69,7 @@ bool CGarages::HasCarBeenCrushed(int32 handle)
}
WRAPPER void CGarages::TriggerMessage(char *text, int16, uint16 time, int16) { EAXJMP(0x426B20); }
+WRAPPER bool CGarages::IsPointWithinHideOutGarage(CVector*) { EAXJMP(0x428260); }
#if 0
WRAPPER void CGarages::PrintMessages(void) { EAXJMP(0x426310); }
diff --git a/src/control/Garages.h b/src/control/Garages.h
index 45a9345d..d338c71b 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -25,4 +25,5 @@ public:
static void TriggerMessage(char *text, int16, uint16 time, int16);
static void PrintMessages(void);
static bool HasCarBeenCrushed(int32);
+ static bool IsPointWithinHideOutGarage(CVector*);
};
diff --git a/src/control/PathFind.h b/src/control/PathFind.h
index d23ea823..d3f89154 100644
--- a/src/control/PathFind.h
+++ b/src/control/PathFind.h
@@ -2,6 +2,8 @@
#include "Treadable.h"
+class CVehicle;
+
enum
{
PATH_CAR = 0,
diff --git a/src/control/RoadBlocks.cpp b/src/control/RoadBlocks.cpp
new file mode 100644
index 00000000..3683ff28
--- /dev/null
+++ b/src/control/RoadBlocks.cpp
@@ -0,0 +1,5 @@
+#include "common.h"
+#include "patcher.h"
+#include "RoadBlocks.h"
+
+WRAPPER void CRoadBlocks::GenerateRoadBlockCopsForCar(CVehicle*, int32, int16) { EAXJMP(0x4376A0); }
diff --git a/src/control/RoadBlocks.h b/src/control/RoadBlocks.h
new file mode 100644
index 00000000..0d965e48
--- /dev/null
+++ b/src/control/RoadBlocks.h
@@ -0,0 +1,10 @@
+#pragma once
+#include "common.h"
+
+class CVehicle;
+
+class CRoadBlocks
+{
+public:
+ static void GenerateRoadBlockCopsForCar(CVehicle*, int32, int16);
+};
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 408771d1..c3c3a154 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -1924,7 +1924,7 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
boat->m_status = STATUS_ABANDONED;
boat->bIsLocked = true;
boat->AutoPilot.m_nCarMission = MISSION_NONE;
- boat->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */
+ boat->AutoPilot.m_nTempAction = TEMPACT_NONE; /* Animation ID? */
boat->AutoPilot.m_nCruiseSpeed = boat->AutoPilot.m_fMaxTrafficSpeed = 20.0f;
CWorld::Add(boat);
handle = CPools::GetVehiclePool()->GetIndex(boat);
@@ -1943,10 +1943,10 @@ int8 CRunningScript::ProcessCommandsFrom100To199(int32 command)
car->bIsLocked = true;
CCarCtrl::JoinCarWithRoadSystem(car);
car->AutoPilot.m_nCarMission = MISSION_NONE;
- car->AutoPilot.m_nAnimationId = TEMPACT_NONE; /* Animation ID? */
+ car->AutoPilot.m_nTempAction = TEMPACT_NONE; /* Animation ID? */
car->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
car->AutoPilot.m_nCruiseSpeed = car->AutoPilot.m_fMaxTrafficSpeed = 9.0f;
- car->AutoPilot.m_nPreviousLane = car->AutoPilot.m_nCurrentLane = 0;
+ car->AutoPilot.m_nCurrentLane = car->AutoPilot.m_nNextLane = 0;
car->bEngineOn = false;
car->m_level = CTheZones::GetLevelFromPosition(pos);
car->bHasBeenOwnedByPlayer = true;
diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp
index f1532ab5..61c941b8 100644
--- a/src/control/TrafficLights.cpp
+++ b/src/control/TrafficLights.cpp
@@ -2,8 +2,11 @@
#include "patcher.h"
#include "TrafficLights.h"
#include "Timer.h"
+#include "Vehicle.h"
WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); }
+WRAPPER bool CTrafficLights::ShouldCarStopForLight(CVehicle*, bool) { EAXJMP(0x455350); }
+WRAPPER bool CTrafficLights::ShouldCarStopForBridge(CVehicle*) { EAXJMP(0x456460); }
uint8
CTrafficLights::LightForPeds(void)
diff --git a/src/control/TrafficLights.h b/src/control/TrafficLights.h
index db240111..f0d0248d 100644
--- a/src/control/TrafficLights.h
+++ b/src/control/TrafficLights.h
@@ -1,6 +1,7 @@
#pragma once
class CEntity;
+class CVehicle;
enum {
PED_LIGHTS_WALK,
@@ -13,4 +14,6 @@ class CTrafficLights
public:
static void DisplayActualLight(CEntity *ent);
static uint8 LightForPeds(void);
+ static bool ShouldCarStopForLight(CVehicle*, bool);
+ static bool ShouldCarStopForBridge(CVehicle*);
};