diff options
Diffstat (limited to '')
-rw-r--r-- | src/control/AutoPilot.cpp | 5 | ||||
-rw-r--r-- | src/control/AutoPilot.h | 24 | ||||
-rw-r--r-- | src/control/CarAI.cpp | 13 | ||||
-rw-r--r-- | src/control/CarAI.h | 1 | ||||
-rw-r--r-- | src/control/CarCtrl.cpp | 336 | ||||
-rw-r--r-- | src/control/CarCtrl.h | 37 | ||||
-rw-r--r-- | src/control/Cranes.cpp | 5 | ||||
-rw-r--r-- | src/control/Cranes.h | 10 | ||||
-rw-r--r-- | src/control/Gangs.cpp | 2 | ||||
-rw-r--r-- | src/control/Gangs.h | 3 | ||||
-rw-r--r-- | src/control/Garages.cpp | 1 | ||||
-rw-r--r-- | src/control/Garages.h | 1 | ||||
-rw-r--r-- | src/control/PathFind.h | 2 | ||||
-rw-r--r-- | src/control/RoadBlocks.cpp | 5 | ||||
-rw-r--r-- | src/control/RoadBlocks.h | 10 | ||||
-rw-r--r-- | src/control/Script.cpp | 6 | ||||
-rw-r--r-- | src/control/TrafficLights.cpp | 3 | ||||
-rw-r--r-- | src/control/TrafficLights.h | 3 | ||||
-rw-r--r-- | src/vehicles/Automobile.cpp | 4 | ||||
-rw-r--r-- | src/vehicles/Vehicle.cpp | 6 | ||||
-rw-r--r-- | src/vehicles/Vehicle.h | 7 |
21 files changed, 433 insertions, 51 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*); }; diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp index 00f53762..488dcf69 100644 --- a/src/vehicles/Automobile.cpp +++ b/src/vehicles/Automobile.cpp @@ -312,7 +312,7 @@ CAutomobile::ProcessControl(void) CVisibilityPlugins::SetClumpAlpha((RpClump*)m_rwObject, clumpAlpha); AutoPilot.m_flag1 = false; - AutoPilot.m_flag2 = false; + AutoPilot.m_bSlowedDownBecauseOfPeds = false; // Set Center of Mass to make car more stable if(strongGrip1 || bCheat3) @@ -3930,7 +3930,7 @@ CAutomobile::PlayCarHorn(void) void CAutomobile::PlayHornIfNecessary(void) { - if(AutoPilot.m_flag2 || + if(AutoPilot.m_bSlowedDownBecauseOfPeds || AutoPilot.m_flag1) if(!HasCarStoppedBecauseOfLight()) PlayCarHorn(); diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 4fc79cca..16863b7a 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -60,7 +60,7 @@ CVehicle::CVehicle(uint8 CreatedBy) pPassengers[i] = nil; m_nBombTimer = 0; m_pBlowUpEntity = nil; - field_1FB = 0; + m_nPacManPickupsCarried = 0; bComedyControls = false; bCraneMessageDone = false; bExtendedRange = false; @@ -71,7 +71,7 @@ CVehicle::CVehicle(uint8 CreatedBy) m_nTimeOfDeath = 0; m_pCarFire = nil; bHasBeenOwnedByPlayer = false; - m_veh_flagC20 = false; + bCreateRoadBlockPeds = false; bCanBeDamaged = true; bUsingSpecialColModel = false; m_veh_flagD1 = false; @@ -102,7 +102,7 @@ CVehicle::CVehicle(uint8 CreatedBy) m_aCollPolys[0].valid = false; m_aCollPolys[1].valid = false; AutoPilot.m_nCarMission = MISSION_NONE; - AutoPilot.m_nAnimationId = TEMPACT_NONE; + AutoPilot.m_nTempAction = TEMPACT_NONE; AutoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds(); AutoPilot.m_flag4 = false; AutoPilot.m_flag10 = false; diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 4681c711..386c7130 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -159,7 +159,7 @@ public: uint8 bHasBeenOwnedByPlayer : 1;// To work out whether stealing it is a crime uint8 bFadeOut : 1; // Fade vehicle out uint8 m_veh_flagC10 : 1; - uint8 m_veh_flagC20 : 1; + uint8 bCreateRoadBlockPeds : 1; // If this vehicle gets close enough we will create peds (coppers or gang members) round it uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions uint8 bUsingSpecialColModel : 1;// Is player vehicle using special collision model, stored in player strucure @@ -174,8 +174,9 @@ public: int8 m_numPedsUseItAsCover; uint8 m_nAmmoInClip; // Used to make the guns on boat do a reload (20 by default) - int8 field_1FB; - int8 field_1FC[4]; + int8 m_nPacManPickupsCarried; + uint8 m_nRoadblockType; + int16 m_nRoadblockNode; float m_fHealth; // 1000.0f = full health. 250.0f = fire. 0 -> explode uint8 m_nCurrentGear; int8 field_205[3]; |