Merge pull request #521 from Nick007J/miami

miami car control init
This commit is contained in:
aap 2020-05-08 11:04:00 +02:00 committed by GitHub
commit 2171ebe2da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 336 additions and 270 deletions

View File

@ -11,6 +11,7 @@
#include "Curves.h" #include "Curves.h"
#include "CutsceneMgr.h" #include "CutsceneMgr.h"
#include "Gangs.h" #include "Gangs.h"
#include "Game.h"
#include "Garages.h" #include "Garages.h"
#include "General.h" #include "General.h"
#include "IniFile.h" #include "IniFile.h"
@ -29,6 +30,7 @@
#include "VisibilityPlugins.h" #include "VisibilityPlugins.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "Fire.h" #include "Fire.h"
#include "WaterLevel.h"
#include "World.h" #include "World.h"
#include "Zones.h" #include "Zones.h"
@ -82,8 +84,11 @@ uint32 CCarCtrl::LastTimeLawEnforcerCreated;
uint32 CCarCtrl::LastTimeFireTruckCreated; uint32 CCarCtrl::LastTimeFireTruckCreated;
uint32 CCarCtrl::LastTimeAmbulanceCreated; uint32 CCarCtrl::LastTimeAmbulanceCreated;
int32 CCarCtrl::TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES]; int32 CCarCtrl::TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES];
int32 CCarCtrl::NextCarOfRating[TOTAL_CUSTOM_CLASSES];
int32 CCarCtrl::CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; int32 CCarCtrl::CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
int32 CCarCtrl::NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES];
int32 CCarCtrl::NumOfLoadedCarsOfRating[TOTAL_CUSTOM_CLASSES];
int32 CCarCtrl::CarFreqArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
int32 CCarCtrl::LoadedCarsArray[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP]; CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP];
uint32 aCarsToKeepTime[MAX_CARS_TO_KEEP]; uint32 aCarsToKeepTime[MAX_CARS_TO_KEEP];
@ -95,9 +100,8 @@ CCarCtrl::GenerateRandomCars()
return; return;
} }
if (NumRandomCars < 30){ if (NumRandomCars < 30){
if (CountDownToCarsAtStart == 0){ if (CountDownToCarsAtStart == 0)
GenerateOneRandomCar(); GenerateOneRandomCar();
}
else if (--CountDownToCarsAtStart == 0) { else if (--CountDownToCarsAtStart == 0) {
for (int i = 0; i < 100; i++) for (int i = 0; i < 100; i++)
GenerateOneRandomCar(); GenerateOneRandomCar();
@ -113,6 +117,7 @@ void
CCarCtrl::GenerateOneRandomCar() CCarCtrl::GenerateOneRandomCar()
{ {
static int32 unk = 0; static int32 unk = 0;
bool bTopDownCamera = false;
CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus];
CVector vecTargetPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); CVector vecTargetPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus);
CVector2D vecPlayerSpeed = FindPlayerSpeed(); CVector2D vecPlayerSpeed = FindPlayerSpeed();
@ -127,7 +132,7 @@ CCarCtrl::GenerateOneRandomCar()
int carClass; int carClass;
int carModel; int carModel;
if (pWanted->m_nWantedLevel > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && if (pWanted->m_nWantedLevel > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles &&
pWanted->m_CurrentCops < pWanted->m_MaxCops && ( pWanted->m_CurrentCops < pWanted->m_MaxCops && !CGame::IsInInterior() && (
pWanted->m_nWantedLevel > 3 || pWanted->m_nWantedLevel > 3 ||
pWanted->m_nWantedLevel > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || pWanted->m_nWantedLevel > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 ||
pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) {
@ -137,7 +142,7 @@ CCarCtrl::GenerateOneRandomCar()
carModel = ChoosePoliceCarModel(); carModel = ChoosePoliceCarModel();
}else{ }else{
carModel = ChooseModel(&zone, &vecTargetPos, &carClass); carModel = ChooseModel(&zone, &vecTargetPos, &carClass);
if (carClass == COPS && pWanted->m_nWantedLevel >= 1) if (carClass == COPS && pWanted->m_nWantedLevel >= 1 || carModel < 0)
/* All cop spawns with wanted level are handled by condition above. */ /* All cop spawns with wanted level are handled by condition above. */
/* In particular it means that cop cars never spawn if player has wanted level of 1. */ /* In particular it means that cop cars never spawn if player has wanted level of 1. */
return; return;
@ -161,8 +166,9 @@ CCarCtrl::GenerateOneRandomCar()
/* Spawn essentially anywhere. */ /* Spawn essentially anywhere. */
frontX = frontY = 0.707f; /* 45 degrees */ frontX = frontY = 0.707f; /* 45 degrees */
angleLimit = -1.0f; angleLimit = -1.0f;
bTopDownCamera = true;
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 40.0f; preferredDistance = 55.0f;
/* BUG: testForCollision not initialized in original game. */ /* BUG: testForCollision not initialized in original game. */
testForCollision = false; testForCollision = false;
}else if (!pPlayerVehicle){ }else if (!pPlayerVehicle){
@ -176,7 +182,7 @@ CCarCtrl::GenerateOneRandomCar()
/* Forward to his current direction (camera direction). */ /* Forward to his current direction (camera direction). */
angleLimit = 0.707f; /* 45 degrees */ angleLimit = 0.707f; /* 45 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 1: case 1:
/* Spawn a vehicle close to player to his side. */ /* Spawn a vehicle close to player to his side. */
@ -198,14 +204,14 @@ CCarCtrl::GenerateOneRandomCar()
/* Spawn a vehicle in a very narrow gap in front of a player */ /* Spawn a vehicle in a very narrow gap in front of a player */
angleLimit = 0.85f; /* approx 30 degrees */ angleLimit = 0.85f; /* approx 30 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 2: case 2:
/* Spawn a vehicle relatively far away from player. */ /* Spawn a vehicle relatively far away from player. */
/* Forward to his current direction (camera direction). */ /* Forward to his current direction (camera direction). */
angleLimit = 0.707f; /* 45 degrees */ angleLimit = 0.707f; /* 45 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 3: case 3:
/* Spawn a vehicle close to player to his side. */ /* Spawn a vehicle close to player to his side. */
@ -226,14 +232,14 @@ CCarCtrl::GenerateOneRandomCar()
/* Spawn a vehicle in a very narrow gap in front of a player */ /* Spawn a vehicle in a very narrow gap in front of a player */
angleLimit = 0.85f; /* approx 30 degrees */ angleLimit = 0.85f; /* approx 30 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 1: case 1:
/* Spawn a vehicle relatively far away from player. */ /* Spawn a vehicle relatively far away from player. */
/* Forward to his current direction (camera direction). */ /* Forward to his current direction (camera direction). */
angleLimit = 0.707f; /* 45 degrees */ angleLimit = 0.707f; /* 45 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 2: case 2:
case 3: case 3:
@ -256,7 +262,7 @@ CCarCtrl::GenerateOneRandomCar()
/* Forward to his current direction (camera direction). */ /* Forward to his current direction (camera direction). */
angleLimit = 0.707f; /* 45 degrees */ angleLimit = 0.707f; /* 45 degrees */
invertAngleLimitTest = true; invertAngleLimitTest = true;
preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier;
break; break;
case 1: case 1:
/* Spawn a vehicle close to player to his side. */ /* Spawn a vehicle close to player to his side. */
@ -271,17 +277,36 @@ CCarCtrl::GenerateOneRandomCar()
preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId, preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId,
&positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1)) &positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1))
return; return;
CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId];
CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId];
bool bBoatGenerated = false;
if ((CGeneral::GetRandomNumber() & 0xF) > Min(pCurNode->spawnRate, pNextNode->spawnRate))
return;
if (pCurNode->bWaterPath) {
bBoatGenerated = true;
if (carClass == COPS) {
carModel = MI_PREDATOR;
carClass = COPS_BOAT;
if (!CStreaming::HasModelLoaded(MI_PREDATOR)) {
CStreaming::RequestModel(MI_PREDATOR, STREAMFLAGS_DEPENDENCY);
return;
}
else {
return;
// TODO: normal boats
}
}
}
int16 colliding; int16 colliding;
CWorld::FindObjectsKindaColliding(spawnPosition, 10.0f, true, &colliding, 2, nil, false, true, true, false, false); CWorld::FindObjectsKindaColliding(spawnPosition, bBoatGenerated ? 40.0f : 10.0f, true, &colliding, 2, nil, false, true, true, false, false);
if (colliding) if (colliding)
/* If something is already present in spawn position, do not create vehicle*/ /* If something is already present in spawn position, do not create vehicle*/
return; return;
if (!ThePaths.TestCoorsCloseness(vecTargetPos, false, spawnPosition)) if (!bBoatGenerated && !ThePaths.TestCoorsCloseness(vecTargetPos, false, spawnPosition))
/* Testing if spawn position can reach target position via valid path. */ /* Testing if spawn position can reach target position via valid path. */
return; return;
int16 idInNode = 0; int16 idInNode = 0;
CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId];
CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId];
while (idInNode < pCurNode->numLinks && while (idInNode < pCurNode->numLinks &&
ThePaths.ConnectedNode(idInNode + pCurNode->firstLink) != nextNodeId) ThePaths.ConnectedNode(idInNode + pCurNode->firstLink) != nextNodeId)
idInNode++; idInNode++;
@ -289,79 +314,66 @@ CCarCtrl::GenerateOneRandomCar()
CCarPathLink* pPathLink = &ThePaths.m_carPathLinks[connectionId]; CCarPathLink* pPathLink = &ThePaths.m_carPathLinks[connectionId];
int16 lanesOnCurrentRoad = pPathLink->pathNodeIndex == nextNodeId ? pPathLink->numLeftLanes : pPathLink->numRightLanes; int16 lanesOnCurrentRoad = pPathLink->pathNodeIndex == nextNodeId ? pPathLink->numLeftLanes : pPathLink->numRightLanes;
CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(carModel); CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(carModel);
if (lanesOnCurrentRoad == 0 || pModelInfo->m_vehicleType == VEHICLE_TYPE_BIKE) if (lanesOnCurrentRoad == 0)
/* Not spawning vehicle if road is one way and intended direction is opposide to that way. */ /* Not spawning vehicle if road is one way and intended direction is opposide to that way. */
/* Also not spawning bikes but they don't exist in final game. */
return; return;
CAutomobile* pCar = new CAutomobile(carModel, RANDOM_VEHICLE); CVehicle* pVehicle;
pCar->AutoPilot.m_nPrevRouteNode = 0; if (CModelInfo::IsBoatModel(carModel))
pCar->AutoPilot.m_nCurrentRouteNode = curNodeId; pVehicle = new CBoat(carModel, RANDOM_VEHICLE);
pCar->AutoPilot.m_nNextRouteNode = nextNodeId; //else if (CModelInfo::IsBikeModel(carModel))
// pVehicle = new CBike(carModel, RANDOM_VEHICLE);
else
pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE);
pVehicle->AutoPilot.m_nPrevRouteNode = 0;
pVehicle->AutoPilot.m_nCurrentRouteNode = curNodeId;
pVehicle->AutoPilot.m_nNextRouteNode = nextNodeId;
switch (carClass) { switch (carClass) {
case POOR:
case RICH:
case EXEC:
case WORKER:
case BIG:
case TAXI:
// TODO(MIAMI): check this
case MOPED:
case MOTORBIKE:
case LEISUREBOAT:
case WORKERBOAT:
//
case MAFIA:
case TRIAD:
case DIABLO:
case YAKUZA:
case YARDIE:
case COLOMB:
case NINES:
case GANG8:
case GANG9:
{
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14);
if (carClass == EXEC)
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18);
else if (carClass == POOR)
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10);
CVehicleModelInfo* pVehicleInfo = pCar->GetModelInfo();
if (pVehicleInfo->GetColModel()->boundingBox.max.y - pCar->GetModelInfo()->GetColModel()->boundingBox.min.y > 10.0f || carClass == BIG) {
pCar->AutoPilot.m_nCruiseSpeed *= 3;
pCar->AutoPilot.m_nCruiseSpeed /= 4;
}
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed;
pCar->AutoPilot.m_nCarMission = MISSION_CRUISE;
pCar->AutoPilot.m_nTempAction = TEMPACT_NONE;
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
break;
}
case COPS: case COPS:
pCar->AutoPilot.m_nTempAction = TEMPACT_NONE; pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){ if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){
pCar->AutoPilot.m_nCruiseSpeed = CCarAI::FindPoliceCarSpeedForWantedLevel(pCar); pVehicle->AutoPilot.m_nCruiseSpeed = CCarAI::FindPoliceCarSpeedForWantedLevel(pVehicle);
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed / 2; pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed / 2;
pCar->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel(); pVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceCarMissionForWantedLevel();
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
}else{ }else{
pCar->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 16); pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 16);
pCar->AutoPilot.m_fMaxTrafficSpeed = pCar->AutoPilot.m_nCruiseSpeed; pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed;
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
pCar->AutoPilot.m_nCarMission = MISSION_CRUISE; pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
} }
if (carModel == MI_FBICAR){ if (carModel == MI_FBICAR){
pCar->m_currentColour1 = 0; pVehicle->m_currentColour1 = 0;
pCar->m_currentColour2 = 0; pVehicle->m_currentColour2 = 0;
/* FBI cars are gray in carcols, but we want them black if they going after player. */ /* FBI cars are gray in carcols, but we want them black if they going after player. */
} }
// TODO(MIAMI): check the flag
case COPS_BOAT:
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(4.0f, 16.0f);
pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed;
pVehicle->AutoPilot.m_nCarMission = CCarAI::FindPoliceBoatMissionForWantedLevel();
break;
default: default:
pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14);
if (carClass == EXEC)
pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18);
else if (carClass == POOR)
pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10);
if (pVehicle->GetColModel()->boundingBox.max.y - pVehicle->GetColModel()->boundingBox.min.y > 10.0f || carClass == BIG) {
pVehicle->AutoPilot.m_nCruiseSpeed *= 3;
pVehicle->AutoPilot.m_nCruiseSpeed /= 4;
}
pVehicle->AutoPilot.m_fMaxTrafficSpeed = pVehicle->AutoPilot.m_nCruiseSpeed;
pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE;
pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE;
pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS;
break; break;
} }
if (pCar && pCar->GetModelIndex() == MI_MRWHOOP) if (pVehicle && pVehicle->GetModelIndex() == MI_MRWHOOP)
pCar->m_bSirenOrAlarm = true; pVehicle->m_bSirenOrAlarm = true;
pCar->AutoPilot.m_nNextPathNodeInfo = connectionId; pVehicle->AutoPilot.m_nNextPathNodeInfo = connectionId;
pCar->AutoPilot.m_nNextLane = pCar->AutoPilot.m_nCurrentLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad; pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad;
CBox* boundingBox = &CModelInfo::GetModelInfo(pCar->GetModelIndex())->GetColModel()->boundingBox; CBox* boundingBox = &CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel()->boundingBox;
float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2; float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2;
float distanceBetweenNodes = (pCurNode->GetPosition() - pNextNode->GetPosition()).Magnitude2D(); float distanceBetweenNodes = (pCurNode->GetPosition() - pNextNode->GetPosition()).Magnitude2D();
/* If car is so long that it doesn't fit between two car nodes, place it directly in the middle. */ /* If car is so long that it doesn't fit between two car nodes, place it directly in the middle. */
@ -370,20 +382,20 @@ CCarCtrl::GenerateOneRandomCar()
positionBetweenNodes = 0.5f; positionBetweenNodes = 0.5f;
else else
positionBetweenNodes = Min(1.0f - carLength / distanceBetweenNodes, Max(carLength / distanceBetweenNodes, positionBetweenNodes)); positionBetweenNodes = Min(1.0f - carLength / distanceBetweenNodes, Max(carLength / distanceBetweenNodes, positionBetweenNodes));
pCar->AutoPilot.m_nNextDirection = (curNodeId >= nextNodeId) ? 1 : -1; pVehicle->AutoPilot.m_nNextDirection = (curNodeId >= nextNodeId) ? 1 : -1;
if (pCurNode->numLinks == 1){ if (pCurNode->numLinks == 1){
/* Do not create vehicle if there is nowhere to go. */ /* Do not create vehicle if there is nowhere to go. */
delete pCar; delete pVehicle;
return; return;
} }
int16 nextConnection = pCar->AutoPilot.m_nNextPathNodeInfo; int16 nextConnection = pVehicle->AutoPilot.m_nNextPathNodeInfo;
int16 newLink; int16 newLink;
while (nextConnection == pCar->AutoPilot.m_nNextPathNodeInfo){ while (nextConnection == pVehicle->AutoPilot.m_nNextPathNodeInfo){
newLink = CGeneral::GetRandomNumber() % pCurNode->numLinks; newLink = CGeneral::GetRandomNumber() % pCurNode->numLinks;
nextConnection = ThePaths.m_carPathConnections[newLink + pCurNode->firstLink]; nextConnection = ThePaths.m_carPathConnections[newLink + pCurNode->firstLink];
} }
pCar->AutoPilot.m_nCurrentPathNodeInfo = nextConnection; pVehicle->AutoPilot.m_nCurrentPathNodeInfo = nextConnection;
pCar->AutoPilot.m_nCurrentDirection = (ThePaths.ConnectedNode(newLink + pCurNode->firstLink) >= curNodeId) ? 1 : -1; pVehicle->AutoPilot.m_nCurrentDirection = (ThePaths.ConnectedNode(newLink + pCurNode->firstLink) >= curNodeId) ? 1 : -1;
CVector2D vecBetweenNodes = pNextNode->GetPosition() - pCurNode->GetPosition(); CVector2D vecBetweenNodes = pNextNode->GetPosition() - pCurNode->GetPosition();
float forwardX, forwardY; float forwardX, forwardY;
float distBetweenNodes = vecBetweenNodes.Magnitude(); float distBetweenNodes = vecBetweenNodes.Magnitude();
@ -396,47 +408,47 @@ CCarCtrl::GenerateOneRandomCar()
} }
/* I think the following might be some form of SetRotateZOnly. */ /* I think the following might be some form of SetRotateZOnly. */
/* Setting up direction between two car nodes. */ /* Setting up direction between two car nodes. */
pCar->GetForward() = CVector(forwardX, forwardY, 0.0f); pVehicle->GetForward() = CVector(forwardX, forwardY, 0.0f);
pCar->GetRight() = CVector(forwardY, -forwardX, 0.0f); pVehicle->GetRight() = CVector(forwardY, -forwardX, 0.0f);
pCar->GetUp() = CVector(0.0f, 0.0f, 1.0f); pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f);
float currentPathLinkForwardX = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].GetDirX(); float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirX();
float currentPathLinkForwardY = pCar->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo].GetDirY(); float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirY();
float nextPathLinkForwardX = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].GetDirX(); float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirX();
float nextPathLinkForwardY = pCar->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo].GetDirY(); float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirY();
CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nCurrentPathNodeInfo]; CCarPathLink* pCurrentLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo];
CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pCar->AutoPilot.m_nNextPathNodeInfo]; CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo];
CVector positionOnCurrentLinkIncludingLane( CVector positionOnCurrentLinkIncludingLane(
pCurrentLink->GetX() + ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY, pCurrentLink->GetX() + ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY,
pCurrentLink->GetY() - ((pCar->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX, pCurrentLink->GetY() - ((pVehicle->AutoPilot.m_nCurrentLane + pCurrentLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX,
0.0f); 0.0f);
CVector positionOnNextLinkIncludingLane( CVector positionOnNextLinkIncludingLane(
pNextLink->GetX() + ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY,
pNextLink->GetY() - ((pCar->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX,
0.0f); 0.0f);
float directionCurrentLinkX = pCurrentLink->GetDirX() * pCar->AutoPilot.m_nCurrentDirection; float directionCurrentLinkX = pCurrentLink->GetDirX() * pVehicle->AutoPilot.m_nCurrentDirection;
float directionCurrentLinkY = pCurrentLink->GetDirY() * pCar->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurrentLink->GetDirY() * pVehicle->AutoPilot.m_nCurrentDirection;
float directionNextLinkX = pNextLink->GetDirX() * pCar->AutoPilot.m_nNextDirection; float directionNextLinkX = pNextLink->GetDirX() * pVehicle->AutoPilot.m_nNextDirection;
float directionNextLinkY = pNextLink->GetDirY() * pCar->AutoPilot.m_nNextDirection; float directionNextLinkY = pNextLink->GetDirY() * pVehicle->AutoPilot.m_nNextDirection;
/* We want to make a path between two links that may not have the same forward directions a curve. */ /* We want to make a path between two links that may not have the same forward directions a curve. */
pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor( pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve = CCurves::CalcSpeedScaleFactor(
&positionOnCurrentLinkIncludingLane, &positionOnCurrentLinkIncludingLane,
&positionOnNextLinkIncludingLane, &positionOnNextLinkIncludingLane,
directionCurrentLinkX, directionCurrentLinkY, directionCurrentLinkX, directionCurrentLinkY,
directionNextLinkX, directionNextLinkY directionNextLinkX, directionNextLinkY
) * (1000.0f / pCar->AutoPilot.m_fMaxTrafficSpeed); ) * (1000.0f / pVehicle->AutoPilot.m_fMaxTrafficSpeed);
#ifdef FIX_BUGS #ifdef FIX_BUGS
/* Casting timer to float is very unwanted. In this case it's not awful */ /* 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). */ /* but in CAutoPilot::ModifySpeed it can even cause crashes (see SilentPatch). */
/* Second fix: adding 0.5f is a mistake. It should be between 0 and 1. It was fixed in SA.*/ /* Second fix: adding 0.5f is a mistake. It should be between 0 and 1. It was fixed in SA.*/
/* It is also correct in CAutoPilot::ModifySpeed. */ /* It is also correct in CAutoPilot::ModifySpeed. */
pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
(uint32)(positionBetweenNodes * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve); (uint32)((0.5f + positionBetweenNodes) * pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve);
#else #else
pCar->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() -
(0.5f + positionBetweenNodes) * pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve; (0.5f + positionBetweenNodes) * pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve;
#endif #endif
CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f); CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f);
CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f); CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f);
@ -447,8 +459,8 @@ CCarCtrl::GenerateOneRandomCar()
&positionOnNextLinkIncludingLane, &positionOnNextLinkIncludingLane,
&directionCurrentLink, &directionCurrentLink,
&directionNextLink, &directionNextLink,
GetPositionAlongCurrentCurve(pCar), GetPositionAlongCurrentCurve(pVehicle),
pCar->AutoPilot.m_nTimeToSpendOnCurrentCurve, pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve,
&positionIncludingCurve, &positionIncludingCurve,
&directionIncludingCurve &directionIncludingCurve
); );
@ -459,142 +471,150 @@ CCarCtrl::GenerateOneRandomCar()
float groundZ = INFINITE_Z; float groundZ = INFINITE_Z;
CColPoint colPoint; CColPoint colPoint;
CEntity* pEntity; CEntity* pEntity;
if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) if (bBoatGenerated) {
groundZ = colPoint.point.z; if (!CWaterLevel::GetWaterLevel(finalPosition, &groundZ, true)) {
if (CWorld::ProcessVerticalLine(finalPosition, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)){ delete pVehicle;
if (ABS(colPoint.point.z - finalPosition.z) < ABS(groundZ - finalPosition.z)) return;
}
}
else {
if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil))
groundZ = colPoint.point.z; groundZ = colPoint.point.z;
if (CWorld::ProcessVerticalLine(finalPosition, -1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) {
if (ABS(colPoint.point.z - finalPosition.z) < ABS(groundZ - finalPosition.z))
groundZ = colPoint.point.z;
}
} }
if (groundZ == INFINITE_Z || ABS(groundZ - finalPosition.z) > 7.0f) { if (groundZ == INFINITE_Z || ABS(groundZ - finalPosition.z) > 7.0f) {
/* Failed to find ground or too far from expected position. */ /* Failed to find ground or too far from expected position. */
delete pCar; delete pVehicle;
return; return;
} }
finalPosition.z = groundZ + pCar->GetHeightAboveRoad(); if (CModelInfo::IsBoatModel(carModel)) {
pCar->SetPosition(finalPosition); finalPosition.z = groundZ;
pCar->SetMoveSpeed(directionIncludingCurve / GAME_SPEED_TO_CARAI_SPEED); pVehicle->bExtendedRange = true;
CVector2D speedDifferenceWithTarget = (CVector2D)pCar->GetMoveSpeed() - vecPlayerSpeed; }
else
finalPosition.z = groundZ + pVehicle->GetHeightAboveRoad();
pVehicle->SetPosition(finalPosition);
pVehicle->SetMoveSpeed(directionIncludingCurve / GAME_SPEED_TO_CARAI_SPEED);
CVector2D speedDifferenceWithTarget = (CVector2D)pVehicle->GetMoveSpeed() - vecPlayerSpeed;
CVector2D distanceToTarget = positionIncludingCurve - vecTargetPos; CVector2D distanceToTarget = positionIncludingCurve - vecTargetPos;
switch (carClass) { switch (carClass) {
case POOR:
case RICH:
case EXEC:
case WORKER:
// TODO(MIAMI): check this
case MOPED:
case MOTORBIKE:
case LEISUREBOAT:
case WORKERBOAT:
//
case BIG:
case TAXI:
case MAFIA:
case TRIAD:
case DIABLO:
case YAKUZA:
case YARDIE:
case COLOMB:
case NINES:
case GANG8:
case GANG9:
pCar->SetStatus(STATUS_SIMPLE);
break;
case COPS: case COPS:
pCar->SetStatus((pCar->AutoPilot.m_nCarMission == MISSION_CRUISE) ? STATUS_SIMPLE : STATUS_PHYSICS); pVehicle->SetStatus((pVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) ? STATUS_SIMPLE : STATUS_PHYSICS);
pCar->ChangeLawEnforcerState(1); pVehicle->ChangeLawEnforcerState(1);
break; break;
case COPS_BOAT:
pVehicle->ChangeLawEnforcerState(1);
pVehicle->SetStatus(STATUS_PHYSICS);
default: default:
pVehicle->SetStatus(STATUS_SIMPLE);
break; break;
} }
CVisibilityPlugins::SetClumpAlpha(pCar->GetClump(), 0); CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0);
if (!pCar->GetIsOnScreen()){ if (!pVehicle->GetIsOnScreen()){
if ((vecTargetPos - pCar->GetPosition()).Magnitude2D() > 50.0f) { if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > 40.0f * (pVehicle->bExtendedRange ? 1.5f : 1.0f)) {
/* Too far away cars that are not visible aren't needed. */ /* Too far away cars that are not visible aren't needed. */
delete pCar; delete pVehicle;
return; return;
} }
}else if((vecTargetPos - pCar->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * 130.0f || }else if((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? 1.5f : 1.0f) * 120.0f ||
(vecTargetPos - pCar->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 110.0f){ (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 100.0f){
delete pCar; delete pVehicle;
return; return;
}else if((TheCamera.GetPosition() - pCar->GetPosition()).Magnitude2D() < 90.0f * TheCamera.GenerationDistMultiplier){ }else if((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 82.5f * TheCamera.GenerationDistMultiplier || bTopDownCamera ){
delete pCar; delete pVehicle;
return; return;
} }
CVehicleModelInfo* pVehicleModel = pCar->GetModelInfo(); // TODO(MIAMI): if MARQUIS then delete
CVehicleModelInfo* pVehicleModel = pVehicle->GetModelInfo();
float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius; float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius;
if (testForCollision){ if (testForCollision){
CWorld::FindObjectsKindaColliding(pCar->GetPosition(), radiusToTest + 20.0f, true, &colliding, 2, nil, false, true, false, false, false); CWorld::FindObjectsKindaColliding(pVehicle->GetPosition(), radiusToTest + 20.0f, true, &colliding, 2, nil, false, true, false, false, false);
if (colliding){ if (colliding){
delete pCar; delete pVehicle;
return; return;
} }
} }
CWorld::FindObjectsKindaColliding(pCar->GetPosition(), radiusToTest, true, &colliding, 2, nil, false, true, false, false, false); CWorld::FindObjectsKindaColliding(pVehicle->GetPosition(), radiusToTest, true, &colliding, 2, nil, false, true, false, false, false);
if (colliding){ if (colliding){
delete pCar; delete pVehicle;
return; return;
} }
if (speedDifferenceWithTarget.x * distanceToTarget.x + if (speedDifferenceWithTarget.x * distanceToTarget.x +
speedDifferenceWithTarget.y * distanceToTarget.y >= 0.0f){ speedDifferenceWithTarget.y * distanceToTarget.y >= 0.0f){
delete pCar; delete pVehicle;
return; return;
} }
pVehicleModel->AvoidSameVehicleColour(&pCar->m_currentColour1, &pCar->m_currentColour2); pVehicleModel->AvoidSameVehicleColour(&pVehicle->m_currentColour1, &pVehicle->m_currentColour2);
CWorld::Add(pCar); CWorld::Add(pVehicle);
if (carClass == COPS) if (carClass == COPS || carClass == COPS_BOAT)
CCarAI::AddPoliceCarOccupants(pCar); CCarAI::AddPoliceCarOccupants(pVehicle);
else else
pCar->SetUpDriver(); pVehicle->SetUpDriver(); //TODO(MIAMI): FIX!
if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */ if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */ /* TODO(MIAMI): FIX!*/
pCar->SetStatus(STATUS_PHYSICS); pVehicle->SetStatus(STATUS_PHYSICS);
pCar->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS;
pCar->AutoPilot.m_nCruiseSpeed += 10; pVehicle->AutoPilot.m_nCruiseSpeed += 10;
} }
if (carClass == COPS) if (carClass == COPS)
LastTimeLawEnforcerCreated = CTimer::GetTimeInMilliseconds(); LastTimeLawEnforcerCreated = CTimer::GetTimeInMilliseconds();
/* TODO(MIAMI): CADDY, VICECHEE, dead ped code*/
return;
}
int32
CCarCtrl::ChooseBoatModel(int32 rating)
{
++NumRequestsOfCarRating[rating];
return ChooseCarModel(rating);
}
int32
CCarCtrl::ChooseBoatRating(CZoneInfo* pZoneInfo)
{
int rnd = CGeneral::GetRandomNumberInRange(0, 1000);
for (int i = 0; i < NUM_BOAT_CLASSES - 1; i++) {
if (rnd < pZoneInfo->boatThreshold[i])
return FIRST_BOAT_RATING + i;
}
return FIRST_BOAT_RATING + NUM_BOAT_CLASSES - 1;
}
int32
CCarCtrl::ChooseCarRating(CZoneInfo* pZoneInfo)
{
int rnd = CGeneral::GetRandomNumberInRange(0, 1000);
for (int i = 0; i < NUM_CAR_CLASSES - 1; i++) {
if (rnd < pZoneInfo->carThreshold[i])
return i;
}
return FIRST_CAR_RATING + NUM_CAR_CLASSES - 1;
} }
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)){ for (int i = 0; i < 10 && (model == -1 || !CStreaming::HasModelLoaded(model)); i++) {
int rnd = CGeneral::GetRandomNumberInRange(0, 1000); int rnd = CGeneral::GetRandomNumberInRange(0, 1000);
// TODO(MIAMI): new car classes
if (rnd < pZone->carThreshold[0]) if (rnd < pZone->copThreshold) {
model = CCarCtrl::ChooseCarModel((*pClass = NORMAL)); *pClass = COPS;
else if (rnd < pZone->carThreshold[1]) model = ChoosePoliceCarModel();
model = CCarCtrl::ChooseCarModel((*pClass = POOR)); continue;
else if (rnd < pZone->carThreshold[2]) }
model = CCarCtrl::ChooseCarModel((*pClass = RICH));
else if (rnd < pZone->carThreshold[3]) for (int i = 0; i < NUM_GANG_CAR_CLASSES; i++) {
model = CCarCtrl::ChooseCarModel((*pClass = EXEC)); if (rnd < pZone->gangThreshold[i]) {
else if (rnd < pZone->carThreshold[4]) *pClass = i + FIRST_GANG_CAR_RATING;
model = CCarCtrl::ChooseCarModel((*pClass = WORKER)); model = ChooseGangCarModel(i);
else if (rnd < pZone->carThreshold[5]) continue;
model = CCarCtrl::ChooseCarModel((*pClass = BIG)); }
else if (rnd < pZone->copThreshold) }
*pClass = COPS, model = CCarCtrl::ChoosePoliceCarModel();
else if (rnd < pZone->gangThreshold[0]) *pClass = ChooseCarRating(pZone);
model = CCarCtrl::ChooseGangCarModel((*pClass = MAFIA) - MAFIA); model = ChooseCarModel(*pClass);
else if (rnd < pZone->gangThreshold[1])
model = CCarCtrl::ChooseGangCarModel((*pClass = TRIAD) - MAFIA);
else if (rnd < pZone->gangThreshold[2])
model = CCarCtrl::ChooseGangCarModel((*pClass = DIABLO) - MAFIA);
else if (rnd < pZone->gangThreshold[3])
model = CCarCtrl::ChooseGangCarModel((*pClass = YAKUZA) - MAFIA);
else if (rnd < pZone->gangThreshold[4])
model = CCarCtrl::ChooseGangCarModel((*pClass = YARDIE) - MAFIA);
else if (rnd < pZone->gangThreshold[5])
model = CCarCtrl::ChooseGangCarModel((*pClass = COLOMB) - MAFIA);
else if (rnd < pZone->gangThreshold[6])
model = CCarCtrl::ChooseGangCarModel((*pClass = NINES) - MAFIA);
else if (rnd < pZone->gangThreshold[7])
model = CCarCtrl::ChooseGangCarModel((*pClass = GANG8) - MAFIA);
else if (rnd < pZone->gangThreshold[8])
model = CCarCtrl::ChooseGangCarModel((*pClass = GANG9) - MAFIA);
else
model = CCarCtrl::ChooseCarModel((*pClass = TAXI));
} }
return model; return model;
} }
@ -603,34 +623,50 @@ int32
CCarCtrl::ChooseCarModel(int32 vehclass) CCarCtrl::ChooseCarModel(int32 vehclass)
{ {
int32 model = -1; int32 model = -1;
switch (vehclass) { ++NumRequestsOfCarRating[vehclass];
case POOR: if (NumOfLoadedCarsOfRating[vehclass] == 0)
case RICH: return -1;
case EXEC: int32 rnd = CGeneral::GetRandomNumberInRange(0, CarFreqArrays[vehclass][NumOfLoadedCarsOfRating[vehclass] - 1]);
case WORKER: int32 index = 0;
// TODO(MIAMI): check this while (rnd > CarFreqArrays[vehclass][index])
case MOPED: index++;
case MOTORBIKE: assert(LoadedCarsArray[vehclass][index]);
case LEISUREBOAT: return LoadedCarsArray[vehclass][index];
case WORKERBOAT: }
//
case BIG: void
case TAXI: CCarCtrl::AddToLoadedVehicleArray(int32 mi, int32 rating, int32 freq)
{ {
if (TotalNumOfCarsOfRating[vehclass] == 0) LoadedCarsArray[rating][NumOfLoadedCarsOfRating[rating]] = mi;
debug("ChooseCarModel : No cars of type %d have been declared\n", vehclass); assert(mi >= 130);
model = CarArrays[vehclass][NextCarOfRating[vehclass]]; CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] = freq;
int32 total = TotalNumOfCarsOfRating[vehclass]; if (NumOfLoadedCarsOfRating[rating])
NextCarOfRating[vehclass] += CGeneral::GetRandomNumberInRange(1, total); CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] += CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating] - 1];
while (NextCarOfRating[vehclass] >= total) NumOfLoadedCarsOfRating[rating]++;
NextCarOfRating[vehclass] -= total; }
//NextCarOfRating[vehclass] %= total;
TotalNumOfCarsOfRating[vehclass] = total; /* why... */ void
CCarCtrl::RemoveFromLoadedVehicleArray(int mi, int32 rating)
{
int index = 0;
while (LoadedCarsArray[rating][index] != -1) {
if (LoadedCarsArray[rating][index] == mi)
break;
} }
default: int32 freq = CarFreqArrays[rating][index];
break; if (index > 0)
freq -= CarFreqArrays[rating][index - 1];
while (LoadedCarsArray[rating][index + 1] != -1) {
LoadedCarsArray[rating][index] = LoadedCarsArray[rating][index + 1];
CarFreqArrays[rating][index] = CarFreqArrays[rating][index + 1] - freq;
} }
return model; --NumOfLoadedCarsOfRating[rating];
}
int32
CCarCtrl::ChooseCarModelToLoad(int rating)
{
return CarArrays[rating][CGeneral::GetRandomNumberInRange(0, TotalNumOfCarsOfRating[rating])];
} }
int32 int32
@ -698,7 +734,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle)
return; return;
} }
float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D(); float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D();
float threshold = 50.0f; float threshold = 40.0f;
if (pVehicle->GetIsOnScreen() || if (pVehicle->GetIsOnScreen() ||
TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingLeft ||
TheCamera.Cams[TheCamera.ActiveCam].LookingRight || TheCamera.Cams[TheCamera.ActiveCam].LookingRight ||
@ -710,8 +746,10 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle)
pVehicle->bIsLawEnforcer || pVehicle->bIsLawEnforcer ||
pVehicle->bIsCarParkVehicle pVehicle->bIsCarParkVehicle
){ ){
threshold = 130.0f * TheCamera.GenerationDistMultiplier; threshold = 120.0f * TheCamera.GenerationDistMultiplier;
} }
if (TheCamera.GetForward().z < -0.9f)
threshold = 70.0f;
if (pVehicle->bExtendedRange) if (pVehicle->bExtendedRange)
threshold *= 1.5f; threshold *= 1.5f;
if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){
@ -724,7 +762,8 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle)
return; return;
} }
} }
if ((pVehicle->GetStatus() == STATUS_SIMPLE || pVehicle->GetStatus() == STATUS_PHYSICS && pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS) && if ((pVehicle->GetStatus() == STATUS_SIMPLE || pVehicle->GetStatus() == STATUS_PHYSICS &&
(pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS || pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS_IGNORE_LIGHTS)) &&
CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeToStartMission > 5000 && CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeToStartMission > 5000 &&
!pVehicle->GetIsOnScreen() && !pVehicle->GetIsOnScreen() &&
(pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f && (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f &&
@ -1870,9 +1909,11 @@ void CCarCtrl::Init(void)
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) for (int i = 0; i < MAX_CARS_TO_KEEP; i++)
apCarsToKeep[i] = nil; apCarsToKeep[i] = nil;
for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++){ for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++){
for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++) for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++) {
CarArrays[i][j] = 0; LoadedCarsArray[i][j] = -1;
NextCarOfRating[i] = 0; }
NumOfLoadedCarsOfRating[i] = 0;
NumRequestsOfCarRating[i] = 0;
TotalNumOfCarsOfRating[i] = 0; TotalNumOfCarsOfRating[i] = 0;
} }
} }
@ -1896,7 +1937,7 @@ void CCarCtrl::ReInit(void)
for (int i = 0; i < MAX_CARS_TO_KEEP; i++) for (int i = 0; i < MAX_CARS_TO_KEEP; i++)
apCarsToKeep[i] = nil; apCarsToKeep[i] = nil;
for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++) for (int i = 0; i < TOTAL_CUSTOM_CLASSES; i++)
NextCarOfRating[i] = 0; NumRequestsOfCarRating[i] = 0;
} }
void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint) void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint)

View File

@ -48,10 +48,13 @@ public:
NINES, NINES,
GANG8, GANG8,
GANG9, GANG9,
COPSBOAT, COPS_BOAT,
FIRST_CAR_RATING = NORMAL,
NUM_CAR_CLASSES = MOTORBIKE+1, FIRST_BOAT_RATING = LEISUREBOAT,
NUM_BOAT_CLASSES = 2, FIRST_GANG_CAR_RATING = MAFIA,
NUM_CAR_CLASSES = MOTORBIKE - FIRST_CAR_RATING + 1,
NUM_BOAT_CLASSES = WORKERBOAT - FIRST_BOAT_RATING + 1,
NUM_GANG_CAR_CLASSES = GANG9 - FIRST_GANG_CAR_RATING + 1,
TOTAL_CUSTOM_CLASSES = NUM_CAR_CLASSES + NUM_BOAT_CLASSES TOTAL_CUSTOM_CLASSES = NUM_CAR_CLASSES + NUM_BOAT_CLASSES
}; };
@ -116,6 +119,12 @@ public:
static void FindLinksToGoWithTheseNodes(CVehicle*); static void FindLinksToGoWithTheseNodes(CVehicle*);
static bool GenerateOneEmergencyServicesCar(uint32, CVector); static bool GenerateOneEmergencyServicesCar(uint32, CVector);
static float FindSpeedMultiplierWithSpeedFromNodes(int8); static float FindSpeedMultiplierWithSpeedFromNodes(int8);
static int32 ChooseBoatModel(int32);
static int32 ChooseBoatRating(CZoneInfo* pZoneInfo);
static int32 ChooseCarRating(CZoneInfo* pZoneInfo);
static void AddToLoadedVehicleArray(int32 mi, int32 rating, int32 freq);
static void RemoveFromLoadedVehicleArray(int32 mi, int32 rating);
static int32 ChooseCarModelToLoad(int rating);
static float GetPositionAlongCurrentCurve(CVehicle* pVehicle) static float GetPositionAlongCurrentCurve(CVehicle* pVehicle)
{ {
@ -147,8 +156,12 @@ public:
static uint32 LastTimeFireTruckCreated; static uint32 LastTimeFireTruckCreated;
static uint32 LastTimeAmbulanceCreated; static uint32 LastTimeAmbulanceCreated;
static int32 TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES]; static int32 TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES];
static int32 NextCarOfRating[TOTAL_CUSTOM_CLASSES];
static int32 CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; static int32 CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
static int32 NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES];
static int32 NumOfLoadedCarsOfRating[TOTAL_CUSTOM_CLASSES];
static int32 CarFreqArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
static int32 LoadedCarsArray[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY];
}; };
extern CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP]; extern CVehicle* apCarsToKeep[MAX_CARS_TO_KEEP];

View File

@ -1419,14 +1419,14 @@ CPathFind::NewGenerateCarCreationCoors(float x, float y, float dirX, float dirY,
if(m_pathNodes[node1].bDisabled && !ignoreDisabled) if(m_pathNodes[node1].bDisabled && !ignoreDisabled)
continue; continue;
dist1 = Distance2D(m_pathNodes[node1].GetPosition(), x, y); dist1 = Distance2D(m_pathNodes[node1].GetPosition(), x, y);
if(dist1 < spawnDist + 60.0f){ if(dist1 < Max(spawnDist + 70.0f, spawnDist * 1.7f)){
d1 = dist1 - spawnDist; d1 = m_pathNodes[node1].bWaterPath ? (dist1 - spawnDist * 1.5f) : (dist1 - spawnDist);
for(j = 0; j < m_pathNodes[node1].numLinks; j++){ for(j = 0; j < m_pathNodes[node1].numLinks; j++){
node2 = ConnectedNode(m_pathNodes[node1].firstLink + j); node2 = ConnectedNode(m_pathNodes[node1].firstLink + j);
if(m_pathNodes[node2].bDisabled && !ignoreDisabled) if(m_pathNodes[node2].bDisabled && !ignoreDisabled)
continue; continue;
dist2 = Distance2D(m_pathNodes[node2].GetPosition(), x, y); dist2 = Distance2D(m_pathNodes[node2].GetPosition(), x, y);
d2 = dist2 - spawnDist; d2 = m_pathNodes[node2].bWaterPath ? (dist2 - spawnDist * 1.5f) : (dist2 - spawnDist);
if(d1*d2 < 0.0f){ if(d1*d2 < 0.0f){
// nodes are on different sides of spawn distance // nodes are on different sides of spawn distance
float f2 = Abs(d1)/(Abs(d1) + Abs(d2)); float f2 = Abs(d1)/(Abs(d1) + Abs(d2));

View File

@ -926,10 +926,10 @@ CFileLoader::LoadCarPathNode(const char *line, int id, int node, bool waterPath)
if(id == -1) if(id == -1)
ThePaths.StoreDetachedNodeInfoCar(node, type, next, x, y, z, width, numLeft, numRight, ThePaths.StoreDetachedNodeInfoCar(node, type, next, x, y, z, width, numLeft, numRight,
!!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate, false); !!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate * 15, false);
else else
ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight, ThePaths.StoreNodeInfoCar(id, node, type, next, x, y, z, 0, numLeft, numRight,
!!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate); !!(flags&1), !!(flags&4), speed, !!(flags&2), waterPath, spawnRate * 15);
} }

View File

@ -59,6 +59,8 @@ public:
static void InitialiseWhenRestarting(void); static void InitialiseWhenRestarting(void);
static void Process(void); static void Process(void);
static bool IsInInterior(void) { return currArea != AREA_MAIN_MAP; }
// NB: these do something on PS2 // NB: these do something on PS2
static void TidyUpMemory(bool, bool); static void TidyUpMemory(bool, bool);
static void DrasticTidyUpMemory(bool); static void DrasticTidyUpMemory(bool);

View File

@ -1025,7 +1025,9 @@ found:
RemoveModel(ms_vehiclesLoaded[ms_lastVehicleDeleted]); RemoveModel(ms_vehiclesLoaded[ms_lastVehicleDeleted]);
ms_numVehiclesLoaded--; ms_numVehiclesLoaded--;
ms_vehiclesLoaded[ms_lastVehicleDeleted] = -1; ms_vehiclesLoaded[ms_lastVehicleDeleted] = -1;
// TODO(MIAMI): CCarCtrl::RemoveFromLoadedVehicleArray CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(id);
if (pVehicleInfo->m_vehicleClass != -1)
CCarCtrl::RemoveFromLoadedVehicleArray(id, pVehicleInfo->m_vehicleClass);
return true; return true;
} }
@ -1159,13 +1161,21 @@ found:
ms_lastVehicleDeleted = id; ms_lastVehicleDeleted = id;
// this is more that we wanted actually // this is more that we wanted actually
ms_numVehiclesLoaded++; ms_numVehiclesLoaded++;
}else }
else{
RemoveModel(id); RemoveModel(id);
CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(modelId);
if (pVehicleInfo->m_vehicleClass != -1)
CCarCtrl::RemoveFromLoadedVehicleArray(modelId, pVehicleInfo->m_vehicleClass);
}
} }
ms_vehiclesLoaded[ms_lastVehicleDeleted++] = modelId; ms_vehiclesLoaded[ms_lastVehicleDeleted++] = modelId;
if(ms_lastVehicleDeleted == MAXVEHICLESLOADED) if(ms_lastVehicleDeleted == MAXVEHICLESLOADED)
ms_lastVehicleDeleted = 0; ms_lastVehicleDeleted = 0;
CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(modelId);
if (pVehicleInfo->m_vehicleClass != -1)
CCarCtrl::AddToLoadedVehicleArray(modelId, pVehicleInfo->m_vehicleClass, pVehicleInfo->m_frequency);
return true; return true;
} }
@ -1283,25 +1293,24 @@ CStreaming::StreamVehiclesAndPeds(void)
if(timeBeforeNextLoad >= 0) if(timeBeforeNextLoad >= 0)
timeBeforeNextLoad--; timeBeforeNextLoad--;
else if(ms_numVehiclesLoaded <= desiredNumVehiclesLoaded){ else if(ms_numVehiclesLoaded <= desiredNumVehiclesLoaded){
for(i = 1; i <= 10; i++){ CZoneInfo zone;
model = CCarCtrl::ChooseCarModel(modelQualityClass); CTheZones::GetZoneInfoForTimeOfDay(&FindPlayerCoors(), &zone);
// TODO(MIAMI): check this int32 maxReq = -1;
if(model < 0) int32 mostRequestedRating = 0;
continue; for(i = 0; i < CCarCtrl::TOTAL_CUSTOM_CLASSES; i++){
modelQualityClass++; if(CCarCtrl::NumRequestsOfCarRating[i] > maxReq &&
if(modelQualityClass >= CCarCtrl::TOTAL_CUSTOM_CLASSES) (i == 0 && zone.carThreshold[0] != 0) ||
modelQualityClass = 0; (i != 0 && zone.carThreshold[i] != zone.carThreshold[i-1])) {
maxReq = CCarCtrl::NumRequestsOfCarRating[i];
// check if we want to load this model mostRequestedRating = i;
if(ms_aInfoForModel[model].m_loadState == STREAMSTATE_NOTLOADED && }
((CVehicleModelInfo*)CModelInfo::GetModelInfo(model))->m_level & (1 << (CGame::currLevel-1)))
break;
} }
model = CCarCtrl::ChooseCarModelToLoad(mostRequestedRating);
if(i <= 10){ if(!HasModelLoaded(model)){
RequestModel(model, STREAMFLAGS_DEPENDENCY); RequestModel(model, STREAMFLAGS_DEPENDENCY);
timeBeforeNextLoad = 500; timeBeforeNextLoad = 350;
} }
CCarCtrl::NumRequestsOfCarRating[mostRequestedRating] = 0;
} }
} }
@ -2435,7 +2444,14 @@ CStreaming::LoadScene(const CVector &pos)
AddModelsToRequestList(pos); AddModelsToRequestList(pos);
CRadar::StreamRadarSections(pos); CRadar::StreamRadarSections(pos);
// TODO(MIAMI): stream zone vehicles if (!CGame::IsInInterior()) {
for (int i = 0; i < 5; i++) {
CZoneInfo zone;
CTheZones::GetZoneInfoForTimeOfDay(&pos, &zone);
int32 model = CCarCtrl::ChooseCarModelToLoad(CCarCtrl::ChooseCarRating(&zone));
CStreaming::RequestModel(model, STREAMFLAGS_DEPENDENCY);
}
}
LoadAllRequestedModels(false); LoadAllRequestedModels(false);
// TODO(MIAMI): InstanceLoadedModels // TODO(MIAMI): InstanceLoadedModels

View File

@ -16,4 +16,3 @@ public:
virtual bool GetIsATreadable(void) { return false; } virtual bool GetIsATreadable(void) { return false; }
}; };
static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error");

View File

@ -15,4 +15,3 @@ public:
static void *operator new(size_t); static void *operator new(size_t);
static void operator delete(void*, size_t); static void operator delete(void*, size_t);
}; };
static_assert(sizeof(CDummy) == 0x68, "CDummy: error");

View File

@ -174,4 +174,3 @@ public:
static void AddSteamsFromGround(CPtrList& list); static void AddSteamsFromGround(CPtrList& list);
}; };
static_assert(sizeof(CEntity) == 0x64, "CEntity: error");

View File

@ -160,4 +160,3 @@ public:
bool CheckCollision(void); bool CheckCollision(void);
bool CheckCollision_SimpleCar(void); bool CheckCollision_SimpleCar(void);
}; };
static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error");

View File

@ -10,4 +10,3 @@ public:
CDummyObject(void) {} CDummyObject(void) {}
CDummyObject(CObject *obj); CDummyObject(CObject *obj);
}; };
static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error");

View File

@ -113,4 +113,3 @@ public:
static void DeleteAllTempObjects(); static void DeleteAllTempObjects();
static void DeleteAllTempObjectsInArea(CVector point, float fRadius); static void DeleteAllTempObjectsInArea(CVector point, float fRadius);
}; };
static_assert(sizeof(CObject) == 0x198, "CObject: error");

View File

@ -8,4 +8,3 @@ class CDummyPed : CDummy
int32 pedType; int32 pedType;
int32 unknown; int32 unknown;
}; };
static_assert(sizeof(CDummyPed) == 0x70, "CDummyPed: error");

View File

@ -732,6 +732,7 @@ CPopulation::AddPedInCar(CVehicle* car)
pedType = PEDTYPE_COP; pedType = PEDTYPE_COP;
break; break;
case MI_POLICE: case MI_POLICE:
case MI_PREDATOR:
preferredModel = COP_STREET; preferredModel = COP_STREET;
pedType = PEDTYPE_COP; pedType = PEDTYPE_COP;
break; break;