Merge branch 'carctrl_dev'

This commit is contained in:
Nikolay Korolev 2019-09-14 20:54:56 +03:00
commit 84186e7b0f
11 changed files with 669 additions and 57 deletions

View File

@ -11,6 +11,7 @@ WRAPPER void CCarAI::MakeWayForCarWithSiren(CVehicle *veh) { EAXJMP(0x416280); }
WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); } WRAPPER eCarMission CCarAI::FindPoliceCarMissionForWantedLevel() { EAXJMP(0x415E30); }
WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); } WRAPPER int32 CCarAI::FindPoliceCarSpeedForWantedLevel(CVehicle*) { EAXJMP(0x415EB0); }
WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); } WRAPPER void CCarAI::AddPoliceOccupants(CVehicle*) { EAXJMP(0x415C60); }
WRAPPER void CCarAI::TellOccupantsToLeaveCar(CVehicle*) { EAXJMP(0x415D20); }
void CCarAI::CarHasReasonToStop(CVehicle* pVehicle) void CCarAI::CarHasReasonToStop(CVehicle* pVehicle)
{ {

View File

@ -13,4 +13,5 @@ public:
static eCarMission FindPoliceCarMissionForWantedLevel(); static eCarMission FindPoliceCarMissionForWantedLevel();
static void AddPoliceOccupants(CVehicle*); static void AddPoliceOccupants(CVehicle*);
static void CarHasReasonToStop(CVehicle*); static void CarHasReasonToStop(CVehicle*);
static void TellOccupantsToLeaveCar(CVehicle*);
}; };

View File

@ -52,6 +52,23 @@
#define ATTEMPTS_TO_FIND_NEXT_NODE 15 #define ATTEMPTS_TO_FIND_NEXT_NODE 15
#define TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING 2500
#define DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP 5.0f
#define DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK 10.0f
#define MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING 0.13f
#define DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN 40.0f
#define MAX_ANGLE_TO_STEER_AT_HIGH_SPEED 0.2f
#define MIN_SPEED_TO_START_LIMITING_STEER 0.45f
#define DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW 5.0f
#define DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW 8.0f
#define DEFAULT_MAX_STEER_ANGLE 0.5f
#define MIN_LOWERING_SPEED_COEFFICIENT 0.4f
#define MAX_ANGLE_FOR_SPEED_LIMITING 1.2f
#define MIN_ANGLE_FOR_SPEED_LIMITING 0.4f
#define MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES 0.1f
#define MIN_ANGLE_TO_APPLY_HANDBRAKE 0.7f
#define MIN_SPEED_TO_APPLY_HANDBRAKE 0.3f
int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38; int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38;
int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0; int &CCarCtrl::NumAmbulancesOnDuty = *(int*)0x885BB0;
int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0; int &CCarCtrl::NumFiretrucksOnDuty = *(int*)0x9411F0;
@ -60,12 +77,15 @@ float& CCarCtrl::CarDensityMultiplier = *(float*)0x5EC8B4;
int32 &CCarCtrl::NumMissionCars = *(int32*)0x8F1B54; int32 &CCarCtrl::NumMissionCars = *(int32*)0x8F1B54;
int32 &CCarCtrl::NumRandomCars = *(int32*)0x943118; int32 &CCarCtrl::NumRandomCars = *(int32*)0x943118;
int32 &CCarCtrl::NumParkedCars = *(int32*)0x8F29E0; int32 &CCarCtrl::NumParkedCars = *(int32*)0x8F29E0;
int32 &CCarCtrl::NumPermanentCars = *(int32*)0x8F29F0;
int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63; int8 &CCarCtrl::CountDownToCarsAtStart = *(int8*)0x95CD63;
int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8; int32 &CCarCtrl::MaxNumberOfCarsInUse = *(int32*)0x5EC8B8;
uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0; uint32 &CCarCtrl::LastTimeLawEnforcerCreated = *(uint32*)0x8F5FF0;
int32 (&CCarCtrl::TotalNumOfCarsOfRating)[7] = *(int32(*)[7])*(uintptr*)0x8F1A60; uint32 &CCarCtrl::LastTimeFireTruckCreated = *(uint32*)0x941450;
int32 (&CCarCtrl::NextCarOfRating)[7] = *(int32(*)[7])*(uintptr*)0x9412AC; uint32 &CCarCtrl::LastTimeAmbulanceCreated = *(uint32*)0x880F5C;
int32 (&CCarCtrl::CarArrays)[7][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[7][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860; int32 (&CCarCtrl::TotalNumOfCarsOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x8F1A60;
int32 (&CCarCtrl::NextCarOfRating)[TOTAL_CUSTOM_CLASSES] = *(int32(*)[TOTAL_CUSTOM_CLASSES])*(uintptr*)0x9412AC;
int32 (&CCarCtrl::CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY] = *(int32(*)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY])*(uintptr*)0x6EB860;
CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x70D830; CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP] = *(CVehicle*(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x70D830;
uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x87F9A8; uint32 (&aCarsToKeepTime)[MAX_CARS_TO_KEEP] = *(uint32(*)[MAX_CARS_TO_KEEP])*(uintptr*)0x87F9A8;
@ -73,11 +93,8 @@ WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0);
WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); } WRAPPER void CCarCtrl::UpdateCarCount(CVehicle*, bool) { EAXJMP(0x4202E0); }
WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); } WRAPPER bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool) { EAXJMP(0x41FA00); }
WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); } WRAPPER void CCarCtrl::JoinCarWithRoadSystem(CVehicle*) { EAXJMP(0x41F820); }
WRAPPER void CCarCtrl::SteerAICarWithPhysics(CVehicle*) { EAXJMP(0x41DA60); }
WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); } WRAPPER void CCarCtrl::RemoveFromInterestingVehicleList(CVehicle* v) { EAXJMP(0x41F7A0); }
WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); } WRAPPER void CCarCtrl::GenerateEmergencyServicesCar(void) { EAXJMP(0x41FC50); }
WRAPPER void CCarCtrl::DragCarToPoint(CVehicle*, CVector*) { EAXJMP(0x41D450); }
WRAPPER void CCarCtrl::Init(void) { EAXJMP(0x41D280); }
void void
CCarCtrl::GenerateRandomCars() CCarCtrl::GenerateRandomCars()
@ -393,12 +410,12 @@ CCarCtrl::GenerateOneRandomCar()
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo]; CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo]; CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo];
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY, pCurrentLink->posX + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX, pCurrentLink->posY - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY, pNextLink->posX + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pCar->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX, pNextLink->posY - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection; float directionCurrentLinkX = pCurrentLink->dirX * pCar->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurrentLink->dirY * pCar->AutoPilot.m_nCurrentDirection;
@ -534,7 +551,7 @@ CCarCtrl::GenerateOneRandomCar()
int32 int32
CCarCtrl::ChooseModel(CZoneInfo* pZone, CVector* pPos, int* pClass) { CCarCtrl::ChooseModel(CZoneInfo* pZone, CVector* pPos, int* pClass) {
int32 model = -1;; int32 model = -1;
while (model == -1 || !CStreaming::HasModelLoaded(model)){ while (model == -1 || !CStreaming::HasModelLoaded(model)){
int rnd = CGeneral::GetRandomNumberInRange(0, 1000); int rnd = CGeneral::GetRandomNumberInRange(0, 1000);
if (rnd < pZone->carThreshold[0]) if (rnd < pZone->carThreshold[0])
@ -799,12 +816,12 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle)
float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection; float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection; float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurrentLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardY, pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
pCurrentLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurrentLink) * currentPathLinkForwardX, pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY, pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX, pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f); CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f);
CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f); CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f);
@ -1614,12 +1631,12 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle)
if (pVehicle->AutoPilot.m_bStayInFastLane) if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0; pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink), /* ...what about Y? */ pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), /* ...what about Y? */
pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX, pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink), pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH),
pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX, pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@ -1794,12 +1811,12 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t
if (pVehicle->AutoPilot.m_bStayInFastLane) if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0; pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardY, pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX, pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY, pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX, pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@ -1819,9 +1836,6 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
{ {
int curNode = pVehicle->AutoPilot.m_nNextRouteNode; int curNode = pVehicle->AutoPilot.m_nNextRouteNode;
CPathNode* pCurNode = &ThePaths.m_pathNodes[curNode]; CPathNode* pCurNode = &ThePaths.m_pathNodes[curNode];
CPathNode* pTargetNode;
int16 numNodes;
float distanceToTargetNode;
if (pVehicle->AutoPilot.m_nPathFindNodesCount == 0){ if (pVehicle->AutoPilot.m_nPathFindNodesCount == 0){
ThePaths.DoPathSearch(0, pVehicle->GetPosition(), curNode, ThePaths.DoPathSearch(0, pVehicle->GetPosition(), curNode,
pVehicle->AutoPilot.m_vecDestinationCoors, pVehicle->AutoPilot.m_aPathFindNodesInfo, pVehicle->AutoPilot.m_vecDestinationCoors, pVehicle->AutoPilot.m_aPathFindNodesInfo,
@ -1877,12 +1891,12 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
if (pVehicle->AutoPilot.m_bStayInFastLane) if (pVehicle->AutoPilot.m_bStayInFastLane)
pVehicle->AutoPilot.m_nNextLane = 0; pVehicle->AutoPilot.m_nNextLane = 0;
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardY, pCurLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
pCurLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nCurrentLane, pCurLink) * currentPathLinkForwardX, pCurLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->posX + GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardY, pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->posY - GetOffsetOfLaneFromCenterOfRoad(pVehicle->AutoPilot.m_nNextLane, pNextLink) * nextPathLinkForwardX, pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkX = pCurLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
@ -1899,8 +1913,586 @@ bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle)
return false; return false;
} }
bool void CCarCtrl::Init(void)
CCarCtrl::MapCouldMoveInThisArea(float x, float y) {
NumRandomCars = 0;
NumLawEnforcerCars = 0;
NumMissionCars = 0;
NumParkedCars = 0;
NumPermanentCars = 0;
NumAmbulancesOnDuty = 0;
NumFiretrucksOnDuty = 0;
LastTimeFireTruckCreated = 0;
LastTimeAmbulanceCreated = 0;
bCarsGeneratedAroundCamera = false;
CountDownToCarsAtStart = 2;
CarDensityMultiplier = 1.0f;
for (int i = 0; i < MAX_CARS_TO_KEEP; i++)
apCarsToKeep[i] = nil;
for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++){
for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++)
CarArrays[i][j] = 0;
NextCarOfRating[i] = 0;
TotalNumOfCarsOfRating[i] = 0;
}
}
void CCarCtrl::ReInit(void)
{
NumRandomCars = 0;
NumLawEnforcerCars = 0;
NumMissionCars = 0;
NumParkedCars = 0;
NumPermanentCars = 0;
NumAmbulancesOnDuty = 0;
NumFiretrucksOnDuty = 0;
CountDownToCarsAtStart = 2;
CarDensityMultiplier = 1.0f;
for (int i = 0; i < MAX_CARS_TO_KEEP; i++)
apCarsToKeep[i] = nil;
for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++)
NextCarOfRating[i] = 0;
}
void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint)
{
CVector2D posBehind = (CVector2D)pVehicle->GetPosition() - 3 * pVehicle->GetForward() / 2;
CVector2D posTarget = *pPoint;
CVector2D direction = posBehind - posTarget;
CVector2D midPos = posTarget + direction * 3 / direction.Magnitude();
float actualAheadZ;
float actualBehindZ;
CColPoint point;
CEntity* pRoadObject;
if (CCollision::IsStoredPoluStillValidVerticalLine(CVector(posTarget.x, posTarget.y, pVehicle->GetPosition().z - 3.0f),
pVehicle->GetPosition().z - 3.0f, point, &pVehicle->m_aCollPolys[0])){
actualAheadZ = point.point.z;
}else if (CWorld::ProcessVerticalLine(CVector(posTarget.x, posTarget.y, pVehicle->GetPosition().z + 1.5f),
pVehicle->GetPosition().z - 2.0f, point,
pRoadObject, true, false, false, false, false, false, &pVehicle->m_aCollPolys[0])){
actualAheadZ = point.point.z;
pVehicle->m_pCurGroundEntity = pRoadObject;
if (ThisRoadObjectCouldMove(pRoadObject->GetModelIndex()))
pVehicle->m_aCollPolys[0].valid = false;
}else if (CWorld::ProcessVerticalLine(CVector(posTarget.x, posTarget.y, pVehicle->GetPosition().z + 3.0f),
pVehicle->GetPosition().z - 3.0f, point,
pRoadObject, true, false, false, false, false, false, &pVehicle->m_aCollPolys[0])) {
actualAheadZ = point.point.z;
pVehicle->m_pCurGroundEntity = pRoadObject;
if (ThisRoadObjectCouldMove(pRoadObject->GetModelIndex()))
pVehicle->m_aCollPolys[0].valid = false;
}else{
actualAheadZ = pVehicle->m_fMapObjectHeightAhead;
}
pVehicle->m_fMapObjectHeightAhead = actualAheadZ;
if (CCollision::IsStoredPoluStillValidVerticalLine(CVector(midPos.x, midPos.y, pVehicle->GetPosition().z - 3.0f),
pVehicle->GetPosition().z - 3.0f, point, &pVehicle->m_aCollPolys[1])){
actualBehindZ = point.point.z;
}else if (CWorld::ProcessVerticalLine(CVector(midPos.x, midPos.y, pVehicle->GetPosition().z + 1.5f),
pVehicle->GetPosition().z - 2.0f, point,
pRoadObject, true, false, false, false, false, false, &pVehicle->m_aCollPolys[1])){
actualBehindZ = point.point.z;
pVehicle->m_pCurGroundEntity = pRoadObject;
if (ThisRoadObjectCouldMove(pRoadObject->GetModelIndex()))
pVehicle->m_aCollPolys[1].valid = false;
}else if (CWorld::ProcessVerticalLine(CVector(midPos.x, midPos.y, pVehicle->GetPosition().z + 3.0f),
pVehicle->GetPosition().z - 3.0f, point,
pRoadObject, true, false, false, false, false, false, &pVehicle->m_aCollPolys[1])){
actualBehindZ = point.point.z;
pVehicle->m_pCurGroundEntity = pRoadObject;
if (ThisRoadObjectCouldMove(pRoadObject->GetModelIndex()))
pVehicle->m_aCollPolys[1].valid = false;
}else{
actualBehindZ = pVehicle->m_fMapObjectHeightBehind;
}
pVehicle->m_fMapObjectHeightBehind = actualBehindZ;
float angleZ = Atan2((actualAheadZ - actualBehindZ) / 3, 1.0f);
float cosZ = Cos(angleZ);
float sinZ = Sin(angleZ);
pVehicle->GetRight() = CVector(posTarget.y - midPos.y, -(posTarget.x - midPos.x), 0.0f) / 3;
pVehicle->GetForward() = CVector(-cosZ * pVehicle->GetRight().y, cosZ * pVehicle->GetRight().x, sinZ);
pVehicle->GetUp() = CrossProduct(pVehicle->GetRight(), pVehicle->GetForward());
pVehicle->GetPosition() = (CVector(midPos.x, midPos.y, actualBehindZ)
+ CVector(posTarget.x, posTarget.y, actualAheadZ)) / 2;
pVehicle->GetPosition().z += pVehicle->GetHeightAboveRoad();
}
float CCarCtrl::FindSpeedMultiplier(float angleChange, float minAngle, float maxAngle, float coef)
{
float actual = ((float(*)(float, float, float, float))(0x41D980))(angleChange, minAngle, maxAngle, coef);
float angle = Abs(LimitRadianAngle(angleChange));
float n = angle - minAngle;
n = max(0.0f, n);
float d = maxAngle - minAngle;
float mult = 1.0f - n / d * (1.0f - coef);
if (n > d)
return coef == actual ? coef : ASSERT(0), coef;
if (ABS(mult - actual) > 0.01f)
ASSERT(0);
return mult;
}
void CCarCtrl::SteerAICarWithPhysics(CVehicle* pVehicle)
{
float swerve;
float accel;
float brake;
bool handbrake;
switch (pVehicle->AutoPilot.m_nTempAction){
case TEMPACT_WAIT:
swerve = 0.0f;
accel = 0.0f;
brake = 0.2f;
handbrake = false;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction){
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
pVehicle->AutoPilot.m_nAntiReverseTimer = CTimer::GetTimeInMilliseconds();
pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds();
}
break;
case TEMPACT_REVERSE:
SteerAICarWithPhysics_OnlyMission(pVehicle, &swerve, &accel, &brake, &handbrake);
handbrake = false;
swerve = -swerve;
if (DotProduct(pVehicle->GetMoveSpeed(), pVehicle->GetForward()) > 0.04f){
accel = 0.0f;
brake = 0.5f;
}else{
accel = -0.5f;
brake = 0.0f;
}
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_HANDBRAKETURNLEFT:
swerve = -1.0f; // It seems like this should be swerve = 1.0f (fixed in VC)
accel = 0.0f;
brake = 0.0f;
handbrake = true;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_HANDBRAKETURNRIGHT:
swerve = 1.0f; // It seems like this should be swerve = -1.0f (fixed in VC)
accel = 0.0f;
brake = 0.0f;
handbrake = true;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_HANDBRAKESTRAIGHT:
swerve = 0.0f;
accel = 0.0f;
brake = 0.0f;
handbrake = true;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_TURNLEFT:
swerve = 1.0f;
accel = 1.0f;
brake = 0.0f;
handbrake = false;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_TURNRIGHT:
swerve = -1.0f;
accel = 1.0f;
brake = 0.0f;
handbrake = false;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_GOFORWARD:
swerve = 0.0f;
accel = 0.5f;
brake = 0.0f;
handbrake = false;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
case TEMPACT_SWERVELEFT:
case TEMPACT_SWERVERIGHT:
swerve = (pVehicle->AutoPilot.m_nTempAction == TEMPACT_SWERVERIGHT) ? 0.15f : -0.15f;
accel = 0.0f;
brake = 0.001f;
handbrake = false;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction - 1000)
swerve = -swerve;
if (CTimer::GetTimeInMilliseconds() > pVehicle->AutoPilot.m_nTimeTempAction)
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
break;
default:
SteerAICarWithPhysics_OnlyMission(pVehicle, &swerve, &accel, &brake, &handbrake);
break;
}
pVehicle->m_fSteerAngle = swerve;
pVehicle->bIsHandbrakeOn = handbrake;
pVehicle->m_fGasPedal = accel;
pVehicle->m_fBrakePedal = brake;
}
void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
{
switch (pVehicle->AutoPilot.m_nCarMission) {
case MISSION_NONE:
*pSwerve = 0.0f;
*pAccel = 0.0f;
*pBrake = 0.5f;
*pHandbrake = true;
return;
case MISSION_CRUISE:
case MISSION_RAMPLAYER_FARAWAY:
case MISSION_BLOCKPLAYER_FARAWAY:
case MISSION_GOTOCOORDS:
case MISSION_GOTOCOORDS_ACCURATE:
case MISSION_RAMCAR_FARAWAY:
case MISSION_BLOCKCAR_FARAWAY:
{
SteerAICarWithPhysicsFollowPath(pVehicle, pSwerve, pAccel, pBrake, pHandbrake);
return;
}
case MISSION_RAMPLAYER_CLOSE:
{
CVector2D targetPos = FindPlayerCoors();
if (FindPlayerVehicle()){
if (pVehicle->m_randomSeed & 1 && DotProduct(FindPlayerVehicle()->GetForward(), pVehicle->GetForward()) > 0.5f){
float targetWidth = FindPlayerVehicle()->GetColModel()->boundingBox.max.x;
float ownWidth = pVehicle->GetColModel()->boundingBox.max.x;
if (pVehicle->m_randomSeed & 2){
targetPos += (targetWidth + ownWidth - 0.2f) * FindPlayerVehicle()->GetRight();
}else{
targetPos -= (targetWidth + ownWidth - 0.2f) * FindPlayerVehicle()->GetRight();
}
float targetSpeed = FindPlayerVehicle()->GetMoveSpeed().Magnitude();
float distanceToTarget = ((CVector2D)pVehicle->GetPosition() - targetPos).Magnitude();
if (12.0f * targetSpeed + 2.0f > distanceToTarget && pVehicle->AutoPilot.m_nTempAction == TEMPACT_NONE){
pVehicle->AutoPilot.m_nTempAction = (pVehicle->m_randomSeed & 2) ? TEMPACT_TURNLEFT : TEMPACT_TURNRIGHT;
pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 250;
}
}else{
targetPos += FindPlayerVehicle()->GetRight() / 160 * ((pVehicle->m_randomSeed & 0xFF) - 128);
}
}
SteerAICarWithPhysicsHeadingForTarget(pVehicle, FindPlayerVehicle(), targetPos.x, targetPos.y, pSwerve, pAccel, pBrake, pHandbrake);
return;
}
case MISSION_BLOCKPLAYER_CLOSE:
SteerAICarWithPhysicsTryingToBlockTarget(pVehicle, FindPlayerCoors().x, FindPlayerCoors().y,
FindPlayerSpeed().x, FindPlayerSpeed().y, pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_BLOCKPLAYER_HANDBRAKESTOP:
SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle, FindPlayerCoors().x, FindPlayerCoors().y,
FindPlayerSpeed().x, FindPlayerSpeed().y, pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_GOTOCOORDS_STRAIGHT:
case MISSION_GOTO_COORDS_STRAIGHT_ACCURATE:
SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil,
pVehicle->AutoPilot.m_vecDestinationCoors.x, pVehicle->AutoPilot.m_vecDestinationCoors.y,
pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_EMERGENCYVEHICLE_STOP:
case MISSION_STOP_FOREVER:
*pSwerve = 0.0f;
*pAccel = 0.0f;
*pHandbrake = true;
*pBrake = 0.5f;
return;
case MISSION_RAMCAR_CLOSE:
SteerAICarWithPhysicsHeadingForTarget(pVehicle, pVehicle->AutoPilot.m_pTargetCar,
pVehicle->AutoPilot.m_pTargetCar->GetPosition().x, pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_BLOCKCAR_CLOSE:
SteerAICarWithPhysicsTryingToBlockTarget(pVehicle,
pVehicle->AutoPilot.m_pTargetCar->GetPosition().x,
pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().x,
pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().y,
pSwerve, pAccel, pBrake, pHandbrake);
return;
case MISSION_BLOCKCAR_HANDBRAKESTOP:
SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle,
pVehicle->AutoPilot.m_pTargetCar->GetPosition().x,
pVehicle->AutoPilot.m_pTargetCar->GetPosition().y,
pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().x,
pVehicle->AutoPilot.m_pTargetCar->GetMoveSpeed().y,
pSwerve, pAccel, pBrake, pHandbrake);
return;
default:
return;
}
}
void CCarCtrl::SteerAIBoatWithPhysics(CBoat* pBoat)
{
if (pBoat->AutoPilot.m_nCarMission == MISSION_GOTOCOORDS_ASTHECROWSWIMS){
SteerAIBoatWithPhysicsHeadingForTarget(pBoat,
pBoat->AutoPilot.m_vecDestinationCoors.x, pBoat->AutoPilot.m_vecDestinationCoors.y,
&pBoat->m_fSteeringLeftRight, &pBoat->m_fAccelerate, &pBoat->m_fBrake);
}else if (pBoat->AutoPilot.m_nCarMission == MISSION_NONE){
pBoat->m_fSteeringLeftRight = 0.0f;
pBoat->m_fAccelerate = 0.0f;
pBoat->m_fBrake = 0.0f;
}
pBoat->m_fSteerAngle = pBoat->m_fSteeringLeftRight;
pBoat->m_fGasPedal = pBoat->m_fAccelerate;
pBoat->m_fBrakePedal = pBoat->m_fBrake;
pBoat->bIsHandbrakeOn = false;
}
float CCarCtrl::FindMaxSteerAngle(CVehicle* pVehicle)
{
return pVehicle->GetModelIndex() == MI_ENFORCER ? 0.7f : DEFAULT_MAX_STEER_ANGLE;
}
void CCarCtrl::SteerAICarWithPhysicsFollowPath(CVehicle* pVehicle, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
{
CVector2D forward = pVehicle->GetForward();
forward.Normalise();
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
CVector2D currentPathLinkForward(pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection,
pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection);
float nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
float nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
CVector2D positionOnCurrentLinkIncludingLane(
pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
CVector2D positionOnNextLinkIncludingLane(
pNextLink->posX + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->posY - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX);
CVector2D distanceToNextNode = (CVector2D)pVehicle->GetPosition() - positionOnCurrentLinkIncludingLane;
float scalarDistanceToNextNode = distanceToNextNode.Magnitude();
CVector2D distanceBetweenNodes = positionOnNextLinkIncludingLane - positionOnCurrentLinkIncludingLane;
float dp = DotProduct2D(distanceBetweenNodes, distanceToNextNode);
if (scalarDistanceToNextNode < DISTANCE_TO_NEXT_NODE_TO_SELECT_NEW ||
dp > 0.0f && scalarDistanceToNextNode < DISTANCE_TO_FACING_NEXT_NODE_TO_SELECT_NEW ||
dp / (scalarDistanceToNextNode * distanceBetweenNodes.Magnitude()) > 0.7f ||
pVehicle->AutoPilot.m_nNextPathNodeInfo == pVehicle->AutoPilot.m_nCurrentPathNodeInfo){
if (PickNextNodeAccordingStrategy(pVehicle)) {
switch (pVehicle->AutoPilot.m_nCarMission){
case MISSION_GOTOCOORDS:
pVehicle->AutoPilot.m_nCarMission = MISSION_GOTOCOORDS_STRAIGHT;
*pSwerve = 0.0f;
*pAccel = 0.0f;
*pBrake = 0.0f;
*pHandbrake = false;
return;
case MISSION_GOTOCOORDS_ACCURATE:
pVehicle->AutoPilot.m_nCarMission = MISSION_GOTO_COORDS_STRAIGHT_ACCURATE;
*pSwerve = 0.0f;
*pAccel = 0.0f;
*pBrake = 0.0f;
*pHandbrake = false;
return;
}
}
pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
scalarDistanceToNextNode = CVector2D(
pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y - pVehicle->GetPosition().x,
pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x - pVehicle->GetPosition().y).Magnitude();
pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
currentPathLinkForward.x = pCurrentLink->dirX * pVehicle->AutoPilot.m_nCurrentDirection;
currentPathLinkForward.y = pCurrentLink->dirY * pVehicle->AutoPilot.m_nCurrentDirection;
nextPathLinkForwardX = pNextLink->dirX * pVehicle->AutoPilot.m_nNextDirection;
nextPathLinkForwardY = pNextLink->dirY * pVehicle->AutoPilot.m_nNextDirection;
}
positionOnCurrentLinkIncludingLane.x = pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y;
positionOnCurrentLinkIncludingLane.y = pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x;
CVector2D projectedPosition = positionOnCurrentLinkIncludingLane - currentPathLinkForward * scalarDistanceToNextNode * 0.4f;
if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN){
projectedPosition.x = positionOnCurrentLinkIncludingLane.x;
projectedPosition.y = positionOnCurrentLinkIncludingLane.y;
}
CVector2D distanceToProjectedPosition = projectedPosition - pVehicle->GetPosition();
float angleCurrentLink = CGeneral::GetATanOfXY(distanceToProjectedPosition.x, distanceToProjectedPosition.y);
float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS)
angleCurrentLink = FindAngleToWeaveThroughTraffic(pVehicle, nil, angleCurrentLink, angleForward);
float steerAngle = LimitRadianAngle(angleCurrentLink - angleForward);
float maxAngle = FindMaxSteerAngle(pVehicle);
steerAngle = min(maxAngle, max(-maxAngle, steerAngle));
if (pVehicle->GetMoveSpeed().Magnitude() > MIN_SPEED_TO_START_LIMITING_STEER)
steerAngle = min(MAX_ANGLE_TO_STEER_AT_HIGH_SPEED, max(-MAX_ANGLE_TO_STEER_AT_HIGH_SPEED, steerAngle));
float currentForwardSpeed = DotProduct(pVehicle->GetMoveSpeed(), pVehicle->GetForward()) * GAME_SPEED_TO_CARAI_SPEED;
float speedStyleMultiplier;
switch (pVehicle->AutoPilot.m_nDrivingStyle) {
case DRIVINGSTYLE_STOP_FOR_CARS:
case DRIVINGSTYLE_SLOW_DOWN_FOR_CARS:
speedStyleMultiplier = FindMaximumSpeedForThisCarInTraffic(pVehicle) / pVehicle->AutoPilot.m_nCruiseSpeed;
break;
default:
speedStyleMultiplier = 1.0f;
break;
}
switch (pVehicle->AutoPilot.m_nDrivingStyle) {
case DRIVINGSTYLE_STOP_FOR_CARS:
case DRIVINGSTYLE_SLOW_DOWN_FOR_CARS:
if (CTrafficLights::ShouldCarStopForLight(pVehicle, false)){
CCarAI::CarHasReasonToStop(pVehicle);
speedStyleMultiplier = 0.0f;
}
break;
default:
break;
}
if (CTrafficLights::ShouldCarStopForBridge(pVehicle)){
CCarAI::CarHasReasonToStop(pVehicle);
speedStyleMultiplier = 0.0f;
}
CVector2D trajectory(pCurrentLink->posX + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.y,
pCurrentLink->posY - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForward.x);
trajectory -= pVehicle->GetPosition();
float speedAngleMultiplier = FindSpeedMultiplier(
CGeneral::GetATanOfXY(trajectory.x, trajectory.y) - angleForward,
MIN_ANGLE_FOR_SPEED_LIMITING, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
float tmpWideMultiplier = FindSpeedMultiplier(
CGeneral::GetATanOfXY(currentPathLinkForward.x, currentPathLinkForward.y) -
CGeneral::GetATanOfXY(nextPathLinkForwardX, nextPathLinkForwardY),
MIN_ANGLE_FOR_SPEED_LIMITING_BETWEEN_NODES, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
float speedNodesMultiplier;
if (scalarDistanceToNextNode > DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN || pVehicle->AutoPilot.m_nCruiseSpeed < 12)
speedNodesMultiplier = 1.0f;
else
speedNodesMultiplier = 1.0f -
(1.0f - scalarDistanceToNextNode / DISTANCE_TO_NEXT_NODE_TO_CONSIDER_SLOWING_DOWN) *
(1.0f - tmpWideMultiplier);
float speedMultiplier = min(speedStyleMultiplier, min(speedAngleMultiplier, speedNodesMultiplier));
float speed = pVehicle->AutoPilot.m_nCruiseSpeed * speedMultiplier;
float speedDifference = speed - currentForwardSpeed;
if (speed < 0.05f && speedDifference < 0.03f){
*pBrake = 1.0f;
*pAccel = 0.0f;
}else if (speedDifference <= 0.0f){
*pBrake = min(0.5f, -speedDifference * 0.05f);
*pAccel = 0.0f;
}else if (currentForwardSpeed < 2.0f){
*pBrake = 0.0f;
*pAccel = min(1.0f, speedDifference * 0.25f);
}else{
*pBrake = 0.0f;
*pAccel = min(1.0f, speedDifference * 0.125f);
}
*pSwerve = steerAngle;
*pHandbrake = false;
}
void CCarCtrl::SteerAICarWithPhysicsHeadingForTarget(CVehicle* pVehicle, CPhysical* pTarget, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
{
*pHandbrake = false;
CVector2D forward = pVehicle->GetForward();
forward.Normalise();
float angleToTarget = CGeneral::GetATanOfXY(targetX - pVehicle->GetPosition().x, targetY - pVehicle->GetPosition().y);
float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS)
angleToTarget = FindAngleToWeaveThroughTraffic(pVehicle, pTarget, angleToTarget, angleForward);
float steerAngle = LimitRadianAngle(angleToTarget - angleForward);
if (pVehicle->GetMoveSpeed().Magnitude() > MIN_SPEED_TO_APPLY_HANDBRAKE)
if (ABS(steerAngle) > MIN_ANGLE_TO_APPLY_HANDBRAKE)
*pHandbrake = true;
float maxAngle = FindMaxSteerAngle(pVehicle);
steerAngle = min(maxAngle, max(-maxAngle, steerAngle));
float speedMultiplier = FindSpeedMultiplier(angleToTarget - angleForward,
MIN_ANGLE_FOR_SPEED_LIMITING, MAX_ANGLE_FOR_SPEED_LIMITING, MIN_LOWERING_SPEED_COEFFICIENT);
float speedTarget = pVehicle->AutoPilot.m_nCruiseSpeed * speedMultiplier;
float currentSpeed = pVehicle->GetMoveSpeed().Magnitude() * GAME_SPEED_TO_CARAI_SPEED;
float speedDiff = speedTarget - currentSpeed;
if (speedDiff <= 0.0f){
*pAccel = 0.0f;
*pBrake = min(0.5f, -speedDiff * 0.05f);
}else if (currentSpeed < 25.0f){
*pAccel = min(1.0f, speedDiff * 0.1f);
*pBrake = 0.0f;
}else{
*pAccel = 1.0f;
*pBrake = 0.0f;
}
*pSwerve = steerAngle;
}
void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget(CVehicle* pVehicle, float targetX, float targetY, float targetSpeedX, float targetSpeedY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
{
CVector2D targetPos(targetX, targetY);
CVector2D offset(targetSpeedX, targetSpeedY);
float trajectoryLen = offset.Magnitude();
if (trajectoryLen > MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING)
offset *= MAX_SPEED_TO_ACCOUNT_IN_INTERCEPTING / trajectoryLen;
targetPos += offset * GAME_SPEED_TO_CARAI_SPEED;
pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
SteerAICarWithPhysicsHeadingForTarget(pVehicle, nil, targetPos.x, targetPos.y, pSwerve, pAccel, pBrake, pHandbrake);
if ((targetPos - pVehicle->GetPosition()).MagnitudeSqr() < SQR(DISTANCE_TO_SWITCH_FROM_BLOCK_TO_STOP))
pVehicle->AutoPilot.m_nCarMission = (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_CLOSE) ?
MISSION_BLOCKCAR_HANDBRAKESTOP : MISSION_BLOCKPLAYER_HANDBRAKESTOP;
}
void CCarCtrl::SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle* pVehicle, float targetX, float targetY, float targetSpeedX, float targetSpeedY, float* pSwerve, float* pAccel, float* pBrake, bool* pHandbrake)
{
*pSwerve = 0.0f;
*pAccel = 0.0f;
*pBrake = 1.0f;
*pHandbrake = true;
float distanceToTargetSqr = (CVector2D(targetX, targetY) - pVehicle->GetPosition()).MagnitudeSqr();
if (distanceToTargetSqr > SQR(DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK)){
pVehicle->AutoPilot.m_nCarMission = (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_HANDBRAKESTOP) ?
MISSION_BLOCKCAR_CLOSE : MISSION_BLOCKPLAYER_CLOSE;
return;
}
if (pVehicle->AutoPilot.m_nCarMission == MISSION_BLOCKCAR_HANDBRAKESTOP){
if (((CVector2D)pVehicle->GetMoveSpeed()).MagnitudeSqr() < SQR(0.01f) &&
CVector2D(targetSpeedX, targetSpeedY).MagnitudeSqr() < SQR(0.02f) &&
pVehicle->bIsLawEnforcer){
CCarAI::TellOccupantsToLeaveCar(pVehicle);
pVehicle->AutoPilot.m_nCruiseSpeed = 0;
pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
}
}else{
if (FindPlayerVehicle() && FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f)
#ifdef FIX_BUGS
pVehicle->m_nTimeBlocked += CTimer::GetTimeStepInMilliseconds();
#else
pVehicle->m_nTimeBlocked += 16.66f * CTimer::GetTimeStep(); // very doubtful constant
#endif
else
pVehicle->m_nTimeBlocked = 0;
if ((FindPlayerVehicle() == nil || FindPlayerVehicle()->IsUpsideDown() ||
FindPlayerVehicle()->GetMoveSpeed().Magnitude() < 0.05f) &&
pVehicle->m_nTimeBlocked > TIME_COPS_WAIT_TO_EXIT_AFTER_STOPPING){
if (pVehicle->bIsLawEnforcer && distanceToTargetSqr < SQR(DISTANCE_TO_SWITCH_FROM_STOP_TO_BLOCK)){
CCarAI::TellOccupantsToLeaveCar(pVehicle);
pVehicle->AutoPilot.m_nCruiseSpeed = 0;
pVehicle->AutoPilot.m_nCarMission = MISSION_NONE;
}
}
}
}
void CCarCtrl::SteerAIBoatWithPhysicsHeadingForTarget(CBoat* pBoat, float targetX, float targetY, float* pSwerve, float* pAccel, float* pBrake)
{
CVector2D forward(pBoat->GetForward());
forward.Normalise();
CVector2D distanceToTarget = CVector2D(targetX, targetY) - pBoat->GetPosition();
float angleToTarget = CGeneral::GetATanOfXY(distanceToTarget.x, distanceToTarget.y);
float angleForward = CGeneral::GetATanOfXY(forward.x, forward.y);
float angleDiff = LimitRadianAngle(angleToTarget - angleForward);
angleDiff = min(DEFAULT_MAX_STEER_ANGLE, max(-DEFAULT_MAX_STEER_ANGLE, angleDiff));
float currentSpeed = pBoat->GetMoveSpeed().Magnitude(); // +0.0f for some reason
float speedDiff = pBoat->AutoPilot.m_nCruiseSpeed - currentSpeed;
if (speedDiff > 0.0f){
float accRemaining = speedDiff / pBoat->AutoPilot.m_nCruiseSpeed;
*pAccel = (accRemaining > 0.25f) ? 1.0f : 1.0f - (0.25f - accRemaining) * 4.0f;
}else
*pAccel = (speedDiff < -5.0f) ? -0.2f : -0.1f;
*pBrake = 0.0f;
*pSwerve = angleDiff;
}
bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi)
{
return mi == MI_BRIDGELIFT || mi == MI_BRIDGEROADSEGMENT;
}
bool CCarCtrl::MapCouldMoveInThisArea(float x, float y)
{ {
// bridge moves up and down // bridge moves up and down
return x > -342.0f && x < -219.0f && return x > -342.0f && x < -219.0f &&
@ -1912,7 +2504,6 @@ InjectHook(0x416580, &CCarCtrl::GenerateRandomCars, PATCH_JUMP);
InjectHook(0x417EC0, &CCarCtrl::ChooseModel, PATCH_JUMP); InjectHook(0x417EC0, &CCarCtrl::ChooseModel, PATCH_JUMP);
InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP); InjectHook(0x418320, &CCarCtrl::RemoveDistantCars, PATCH_JUMP);
InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP); InjectHook(0x418430, &CCarCtrl::PossiblyRemoveVehicle, PATCH_JUMP);
InjectHook(0x418C10, &CCarCtrl::FindMaximumSpeedForThisCarInTraffic, PATCH_JUMP); InjectHook(0x41D280, &CCarCtrl::Init, PATCH_JUMP);
InjectHook(0x41A590, &CCarCtrl::FindAngleToWeaveThroughTraffic, PATCH_JUMP); InjectHook(0x41D3B0, &CCarCtrl::ReInit, PATCH_JUMP);
InjectHook(0x41BA50, &CCarCtrl::PickNextNodeAccordingStrategy, PATCH_JUMP);
ENDPATCHES ENDPATCHES

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "PathFind.h" #include "PathFind.h"
#include "Boat.h"
#include "Vehicle.h" #include "Vehicle.h"
class CZoneInfo; class CZoneInfo;
@ -25,7 +26,7 @@ class CCarCtrl
SPECIAL, SPECIAL,
BIG, BIG,
TAXI, TAXI,
CLASS7, TOTAL_CUSTOM_CLASSES,
MAFIA, MAFIA,
TRIAD, TRIAD,
DIABLO, DIABLO,
@ -44,7 +45,6 @@ public:
static int32 ChooseCarModel(int32 vehclass); static int32 ChooseCarModel(int32 vehclass);
static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool); static bool JoinCarWithRoadSystemGotoCoors(CVehicle*, CVector, bool);
static void JoinCarWithRoadSystem(CVehicle*); static void JoinCarWithRoadSystem(CVehicle*);
static void SteerAICarWithPhysics(CVehicle*);
static void UpdateCarOnRails(CVehicle*); static void UpdateCarOnRails(CVehicle*);
static bool MapCouldMoveInThisArea(float x, float y); static bool MapCouldMoveInThisArea(float x, float y);
static void ScanForPedDanger(CVehicle *veh); static void ScanForPedDanger(CVehicle *veh);
@ -66,7 +66,6 @@ public:
static float FindMaximumSpeedForThisCarInTraffic(CVehicle*); static float FindMaximumSpeedForThisCarInTraffic(CVehicle*);
static void SlowCarDownForCarsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float); static void SlowCarDownForCarsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
static void SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float); static void SlowCarDownForPedsSectorList(CPtrList&, CVehicle*, float, float, float, float, float*, float);
static void Init(void);
static void SlowCarDownForOtherCar(CEntity*, CVehicle*, float*, float); static void SlowCarDownForOtherCar(CEntity*, CVehicle*, float*, float);
static float TestCollisionBetween2MovingRects(CVehicle*, CVehicle*, float, float, CVector*, CVector*, uint8); static float TestCollisionBetween2MovingRects(CVehicle*, CVehicle*, float, float, CVector*, CVector*, uint8);
static float FindAngleToWeaveThroughTraffic(CVehicle*, CPhysical*, float, float); static float FindAngleToWeaveThroughTraffic(CVehicle*, CPhysical*, float, float);
@ -84,12 +83,19 @@ public:
static bool PickNextNodeToFollowPath(CVehicle*); static bool PickNextNodeToFollowPath(CVehicle*);
static void PickNextNodeRandomly(CVehicle*); static void PickNextNodeRandomly(CVehicle*);
static uint8 FindPathDirection(int32, int32, int32); static uint8 FindPathDirection(int32, int32, int32);
static void Init(void);
static float GetOffsetOfLaneFromCenterOfRoad(int8 lane, CCarPathLink* pLink) static void ReInit(void);
{ static float FindSpeedMultiplier(float, float, float, float);
return (lane + ((pLink->numLeftLanes == 0) ? (0.5f - 0.5f * pLink->numRightLanes) : static void SteerAICarWithPhysics(CVehicle*);
((pLink->numRightLanes == 0) ? (0.5f - 0.5f * pLink->numLeftLanes) : 0.5f))) * LANE_WIDTH; static void SteerAICarWithPhysics_OnlyMission(CVehicle*, float*, float*, float*, bool*);
} static void SteerAIBoatWithPhysics(CBoat*);
static float FindMaxSteerAngle(CVehicle*);
static void SteerAICarWithPhysicsFollowPath(CVehicle*, float*, float*, float*, bool*);
static void SteerAICarWithPhysicsHeadingForTarget(CVehicle*, CPhysical*, float, float, float*, float*, float*, bool*);
static void SteerAICarWithPhysicsTryingToBlockTarget(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
static void SteerAICarWithPhysicsTryingToBlockTarget_Stop(CVehicle*, float, float, float, float, float*, float*, float*, bool*);
static void SteerAIBoatWithPhysicsHeadingForTarget(CBoat*, float, float, float*, float*, float*);
static bool ThisRoadObjectCouldMove(int16);
static float GetPositionAlongCurrentCurve(CVehicle* pVehicle) static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
{ {
@ -112,14 +118,17 @@ public:
static int32 &NumRandomCars; static int32 &NumRandomCars;
static int32 &NumMissionCars; static int32 &NumMissionCars;
static int32 &NumParkedCars; static int32 &NumParkedCars;
static int32 &NumPermanentCars;
static bool &bCarsGeneratedAroundCamera; static bool &bCarsGeneratedAroundCamera;
static float &CarDensityMultiplier; static float &CarDensityMultiplier;
static int8 &CountDownToCarsAtStart; static int8 &CountDownToCarsAtStart;
static int32 &MaxNumberOfCarsInUse; static int32 &MaxNumberOfCarsInUse;
static uint32 &LastTimeLawEnforcerCreated; static uint32 &LastTimeLawEnforcerCreated;
static int32 (&TotalNumOfCarsOfRating)[7]; static uint32 &LastTimeFireTruckCreated;
static int32 (&NextCarOfRating)[7]; static uint32 &LastTimeAmbulanceCreated;
static int32 (&CarArrays)[7][MAX_CAR_MODELS_IN_ARRAY]; static int32 (&TotalNumOfCarsOfRating)[TOTAL_CUSTOM_CLASSES];
static int32 (&NextCarOfRating)[TOTAL_CUSTOM_CLASSES];
static int32 (&CarArrays)[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
}; };
extern CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP]; extern CVehicle* (&apCarsToKeep)[MAX_CARS_TO_KEEP];

View File

@ -75,6 +75,15 @@ struct CCarPathLink
uint8 bBridgeLights : 1; uint8 bBridgeLights : 1;
// more? // more?
float OneWayLaneOffset()
{
if (numLeftLanes == 0)
return 0.5f - 0.5f * numRightLanes;
if (numRightLanes == 0)
return 0.5f - 0.5f * numLeftLanes;
return 0.5f;
}
}; };
struct CPathInfoForObject struct CPathInfoForObject

View File

@ -960,6 +960,7 @@ void CReplay::EmptyReplayBuffer(void)
{ {
if (Mode == MODE_PLAYBACK) if (Mode == MODE_PLAYBACK)
return; return;
Record.m_nOffset = 0;
for (int i = 0; i < 8; i++){ for (int i = 0; i < 8; i++){
BufferStatus[i] = REPLAYBUFFER_UNUSED; BufferStatus[i] = REPLAYBUFFER_UNUSED;
} }

View File

@ -34,6 +34,8 @@ enum Direction
eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250; eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250;
CLinkList<CColModel*> &CCollision::ms_colModelCache = *(CLinkList<CColModel*>*)0x95CB58; CLinkList<CColModel*> &CCollision::ms_colModelCache = *(CLinkList<CColModel*>*)0x95CB58;
WRAPPER bool CCollision::IsStoredPoluStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly) { EAXJMP(0x4105A0); }
void void
CCollision::Init(void) CCollision::Init(void)
{ {

View File

@ -148,9 +148,8 @@ public:
static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough); static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough);
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly); static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly);
static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists); static int32 ProcessColModels(const CMatrix &matrixA, CColModel &modelA, const CMatrix &matrixB, CColModel &modelB, CColPoint *spherepoints, CColPoint *linepoints, float *linedists);
// TODO: // TODO:
// CCollision::IsStoredPolyStillValidVerticalLine static bool IsStoredPoluStillValidVerticalLine(const CVector &pos, float z, CColPoint &point, CStoredCollPoly *poly);
static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point); static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point);
static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest); static float DistToLine(const CVector *l0, const CVector *l1, const CVector *point, CVector &closest);

View File

@ -3074,7 +3074,7 @@ CAutomobile::PlaceOnRoadProperly(void)
frontZ = point.point.z; frontZ = point.point.z;
m_pCurGroundEntity = entity; m_pCurGroundEntity = entity;
}else{ }else{
frontZ = field_21C; frontZ = m_fMapObjectHeightAhead;
} }
CVector rear(GetPosition().x - GetForward().x*lenBack, CVector rear(GetPosition().x - GetForward().x*lenBack,
@ -3085,7 +3085,7 @@ CAutomobile::PlaceOnRoadProperly(void)
rearZ = point.point.z; rearZ = point.point.z;
m_pCurGroundEntity = entity; m_pCurGroundEntity = entity;
}else{ }else{
rearZ = field_220; rearZ = m_fMapObjectHeightBehind;
} }
float len = lenFwd + lenBack; float len = lenFwd + lenBack;

View File

@ -78,7 +78,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_veh_flagD1 = false; m_veh_flagD1 = false;
m_veh_flagD2 = false; m_veh_flagD2 = false;
m_nGunFiringTime = 0; m_nGunFiringTime = 0;
field_214 = 0; m_nTimeBlocked = 0;
bLightsOn = false; bLightsOn = false;
bVehicleColProcessed = false; bVehicleColProcessed = false;
m_numPedsUseItAsCover = 0; m_numPedsUseItAsCover = 0;
@ -90,8 +90,7 @@ CVehicle::CVehicle(uint8 CreatedBy)
m_nAlarmState = 0; m_nAlarmState = 0;
m_nDoorLock = CARLOCK_UNLOCKED; m_nDoorLock = CARLOCK_UNLOCKED;
m_nLastWeaponDamage = -1; m_nLastWeaponDamage = -1;
field_220 = 0.0; m_fMapObjectHeightAhead = m_fMapObjectHeightBehind = 0.0f;
field_21C = field_220;
m_audioEntityId = DMAudio.CreateEntity(AUDIOTYPE_PHYSICAL, this); m_audioEntityId = DMAudio.CreateEntity(AUDIOTYPE_PHYSICAL, this);
if(m_audioEntityId) if(m_audioEntityId)
DMAudio.SetEntityStatus(m_audioEntityId, true); DMAudio.SetEntityStatus(m_audioEntityId, true);

View File

@ -183,11 +183,11 @@ public:
float m_fChangeGearTime; float m_fChangeGearTime;
uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats) uint32 m_nGunFiringTime; // last time when gun on vehicle was fired (used on boats)
uint32 m_nTimeOfDeath; uint32 m_nTimeOfDeath;
int16 field_214; uint16 m_nTimeBlocked;
int16 m_nBombTimer; // goes down with each frame int16 m_nBombTimer; // goes down with each frame
CEntity *m_pBlowUpEntity; CEntity *m_pBlowUpEntity;
float field_21C; // front Z? float m_fMapObjectHeightAhead; // front Z?
float field_220; // rear Z? float m_fMapObjectHeightBehind; // rear Z?
eCarLock m_nDoorLock; eCarLock m_nDoorLock;
int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage int8 m_nLastWeaponDamage; // see eWeaponType, -1 if no damage
int8 m_nRadioStation; int8 m_nRadioStation;