diff options
Diffstat (limited to 'src/control/CarCtrl.cpp')
-rw-r--r-- | src/control/CarCtrl.cpp | 567 |
1 files changed, 409 insertions, 158 deletions
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 6742ccfe..3d82fc1a 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -11,11 +11,13 @@ #include "Cranes.h" #include "Curves.h" #include "CutsceneMgr.h" +#include "Frontend.h" #include "Gangs.h" #include "Game.h" #include "Garages.h" #include "General.h" #include "IniFile.h" +#include "Lines.h" #include "ModelIndices.h" #include "PathFind.h" #include "Ped.h" @@ -37,7 +39,9 @@ #include "Zones.h" #include "Pickups.h" -#define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS (51.0f) +//--LCS: file done except TODO + +#define DISTANCE_TO_SPAWN_ROADBLOCK_PEDS (51.0f) // apparently POPULATION_CULL_RANGE? TODO: unite with CPopulation #define DISTANCE_TO_SCAN_FOR_DANGER (14.0f) #define DISTANCE_TO_SCAN_FOR_PED_DANGER (11.0f) #define SAFE_DISTANCE_TO_PED (3.0f) @@ -77,12 +81,30 @@ #define DISTANCE_BETWEEN_CAR_AND_DEAD_PED (6.0f) #define PROBABILITY_OF_PASSENGER_IN_VEHICLE (0.125f) -#define ONSCREEN_DESPAWN_RANGE (120.0f) +#ifdef GTA_PSP +#define ONSCREEN_DESPAWN_RANGE (160.0f) #define MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN (100.0f) -#define REQUEST_ONSCREEN_DISTANCE ((ONSCREEN_DESPAWN_RANGE + MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN) / 2) -#define OFFSCREEN_DESPAWN_RANGE (40.0f) +#define MAX_DISTANCE_FROM_CAMERA_TO_SPAWN_ONSCREEN (82.5f) +#else +#define ONSCREEN_DESPAWN_RANGE (190.0f) +#define MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN (130.0f) +#define MAX_DISTANCE_FROM_CAMERA_TO_SPAWN_ONSCREEN (105.0f) +#endif + +#define REQUEST_ONSCREEN_DISTANCE (140.0f) +#define OFFSCREEN_DESPAWN_RANGE (60.0f) +#define MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN (40.0f) #define EXTENDED_RANGE_DESPAWN_MULTIPLIER (1.5f) +#ifdef GTA_NETWORK +const int32 CCarCtrl::MultiplayerCarBanks[TOTAL_MULTIPLAYER_CAR_BANKS][CARS_IN_MULTIPLAYER_BANK] = +{ + MI_SANCHEZ, MI_KURUMA, MI_ESPRIT, MI_MULE, MI_DIABLOS, MI_KURUMA, MI_PEREN, MI_STINGER, + MI_PCJ600, MI_BOBCAT, MI_BLISTA, MI_LANDSTAL,MI_SENTINEL,MI_MOONBEAM,MI_MANANA, MI_PEREN, + MI_SANCHEZ2,MI_PCJ600, MI_STALLION,MI_MANANA, MI_LINERUN, MI_RCBANDIT,MI_MRWONGS, MI_STINGER +}; +#endif + bool CCarCtrl::bMadDriversCheat; int CCarCtrl::NumLawEnforcerCars; int CCarCtrl::NumAmbulancesOnDuty; @@ -108,6 +130,15 @@ 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]; uint32 aCarsToKeepTime[MAX_CARS_TO_KEEP]; +uint32 CCarCtrl::maxRandomMpCars = 20; +bool CCarCtrl::scriptControlsMpCarLimit = false; + +bool gbEmergencyVehiclesEnabled = true; + +#ifdef GTA_NETWORK // TMP +extern bool gIsMultiplayerGame; +extern int8 nAmbientCarBank; // actually gMultiGame.nAmbientCarBank (TODO) +#endif void CCarCtrl::GenerateRandomCars() @@ -141,31 +172,60 @@ CCarCtrl::GenerateOneRandomCar() CZoneInfo zone; CTheZones::GetZoneInfoForTimeOfDay(&vecTargetPos, &zone); pPlayer->m_nTrafficMultiplier = pPlayer->m_fRoadDensity * zone.carDensity; - if (NumRandomCars >= pPlayer->m_nTrafficMultiplier * CarDensityMultiplier * CIniFile::CarNumberMultiplier) - return; - if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars >= MaxNumberOfCarsInUse) - return; +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + // TODO (count number of players within 250 meters from spawn position + int numPlayersClose = 1; + if (NumRandomCars >= pPlayer->m_nTrafficMultiplier * CarDensityMultiplier * CIniFile::CarNumberMultiplier * numPlayersClose) + return; + if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars >= MaxNumberOfCarsInUse) + return; + } + else +#endif + { + if (NumRandomCars >= pPlayer->m_nTrafficMultiplier * CarDensityMultiplier * CIniFile::CarNumberMultiplier) + return; + if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars >= MaxNumberOfCarsInUse) + return; + } CWanted* pWanted = pPlayer->m_pPed->m_pWanted; int carClass; int carModel; - if (pWanted->GetWantedLevel() > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && - pWanted->m_CurrentCops < pWanted->m_MaxCops && !CGame::IsInInterior() && ( - pWanted->GetWantedLevel() > 3 || - pWanted->GetWantedLevel() > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || - pWanted->GetWantedLevel() > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { - /* Last pWanted->GetWantedLevel() > 1 is unnecessary but I added it for better readability. */ - /* Wouldn't be surprised it was there originally but was optimized out. */ - carClass = COPS; - carModel = ChoosePoliceCarModel(); - }else{ +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { carModel = ChooseModel(&zone, &carClass); - if (carModel == -1 || (carClass == COPS && pWanted->GetWantedLevel() >= 1)) - /* 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. */ + if (carModel == -1) return; } + else +#endif + { + if (pWanted->GetWantedLevel() > 1 && NumLawEnforcerCars < pWanted->m_MaximumLawEnforcerVehicles && + pWanted->m_CurrentCops < pWanted->m_MaxCops && !CGame::IsInInterior() && ( + pWanted->GetWantedLevel() > 3 || + pWanted->GetWantedLevel() > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || + pWanted->GetWantedLevel() > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { + /* Last pWanted->GetWantedLevel() > 1 is unnecessary but I added it for better readability. */ + /* Wouldn't be surprised it was there originally but was optimized out. */ + carClass = COPS; + carModel = ChoosePoliceCarModel(); + } + else { + for (int i = 0; i < 5; i++) { + carModel = ChooseModel(&zone, &carClass); + if (carModel == -1) + return; + if (!(carClass == COPS && pWanted->GetWantedLevel() >= 1)) + /* 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. */ + break; + } + } + } float frontX, frontY; float preferredDistance, angleLimit; + float requestMultiplier = 1.0f; bool invertAngleLimitTest; CVector spawnPosition; int32 curNodeId, nextNodeId; @@ -185,11 +245,14 @@ CCarCtrl::GenerateOneRandomCar() angleLimit = -1.0f; bTopDownCamera = true; invertAngleLimitTest = true; - preferredDistance = OFFSCREEN_DESPAWN_RANGE + 15.0f; + preferredDistance = MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN + 15.0f; /* BUG: testForCollision not initialized in original game. */ testForCollision = false; }else if (!pPlayerVehicle){ /* Player is not in vehicle. */ + requestMultiplier = 13.0f / 20.0f; + if (FrontEndMenuManager.m_PrefsUseWideScreen) // TODO(LCS): static + requestMultiplier *= 4.0f / 3.0f; testForCollision = true; frontX = TheCamera.CamFrontXNorm; frontY = TheCamera.CamFrontYNorm; @@ -199,95 +262,105 @@ CCarCtrl::GenerateOneRandomCar() /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle close to player to his side. */ /* Kinda not within camera angle. */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = false; - preferredDistance = OFFSCREEN_DESPAWN_RANGE; + preferredDistance = MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN; break; } - }else if (fPlayerVehicleSpeed > 0.4f){ /* 72 km/h */ + } + else { + requestMultiplier = 13.0f / 20.0f; + if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON && !FrontEndMenuManager.m_PrefsUseWideScreen) + requestMultiplier *= 0.9f; + if (FrontEndMenuManager.m_PrefsUseWideScreen) // TODO(LCS): static + requestMultiplier *= 4.0f / 3.0f; + if (fPlayerVehicleSpeed > 0.4f) { /* 72 km/h */ /* Player is moving fast in vehicle */ /* Prefer spawning vehicles very far away from him. */ - frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed; - frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed; - testForCollision = false; - switch (CTimer::GetFrameCounter() & 3) { - case 0: - case 1: - /* Spawn a vehicle in a very narrow gap in front of a player */ - angleLimit = 0.85f; /* approx 30 degrees */ - invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; - break; - case 2: - /* Spawn a vehicle relatively far away from player. */ - /* Forward to his current direction (camera direction). */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; - break; - case 3: - /* Spawn a vehicle close to player to his side. */ - /* Kinda not within camera angle. */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = false; - preferredDistance = OFFSCREEN_DESPAWN_RANGE; - break; + frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed; + frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed; + testForCollision = false; + switch (CTimer::GetFrameCounter() & 3) { + case 0: + case 1: + /* Spawn a vehicle in a very narrow gap in front of a player */ + angleLimit = 0.85f; /* approx 30 degrees */ + invertAngleLimitTest = true; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; + break; + case 2: + /* Spawn a vehicle relatively far away from player. */ + /* Forward to his current direction (camera direction). */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = true; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; + break; + case 3: + /* Spawn a vehicle close to player to his side. */ + /* Kinda not within camera angle. */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = false; + preferredDistance = MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN; + break; + } } - }else if (fPlayerVehicleSpeed > 0.1f){ /* 18 km/h */ - /* Player is moving moderately fast in vehicle */ - /* Spawn more vehicles to player's side. */ - frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed; - frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed; - testForCollision = false; - switch (CTimer::GetFrameCounter() & 3) { - case 0: - /* Spawn a vehicle in a very narrow gap in front of a player */ - angleLimit = 0.85f; /* approx 30 degrees */ - invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; - break; - case 1: - /* Spawn a vehicle relatively far away from player. */ - /* Forward to his current direction (camera direction). */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; - break; - case 2: - case 3: - /* Spawn a vehicle close to player to his side. */ - /* Kinda not within camera angle. */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = false; - preferredDistance = OFFSCREEN_DESPAWN_RANGE; - break; + else if (fPlayerVehicleSpeed > 0.1f) { /* 18 km/h */ + /* Player is moving moderately fast in vehicle */ + /* Spawn more vehicles to player's side. */ + frontX = vecPlayerVehicleSpeed.x / fPlayerVehicleSpeed; + frontY = vecPlayerVehicleSpeed.y / fPlayerVehicleSpeed; + testForCollision = false; + switch (CTimer::GetFrameCounter() & 3) { + case 0: + /* Spawn a vehicle in a very narrow gap in front of a player */ + angleLimit = 0.85f; /* approx 30 degrees */ + invertAngleLimitTest = true; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; + break; + case 1: + /* Spawn a vehicle relatively far away from player. */ + /* Forward to his current direction (camera direction). */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = true; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; + break; + case 2: + case 3: + /* Spawn a vehicle close to player to his side. */ + /* Kinda not within camera angle. */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = false; + preferredDistance = MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN; + break; + } } - }else{ - /* Player is in vehicle but moving very slow. */ - /* Then use camera direction instead of vehicle direction. */ - testForCollision = true; - frontX = TheCamera.CamFrontXNorm; - frontY = TheCamera.CamFrontYNorm; - switch (CTimer::GetFrameCounter() & 1) { - case 0: - /* Spawn a vehicle relatively far away from player. */ - /* Forward to his current direction (camera direction). */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = true; - preferredDistance = REQUEST_ONSCREEN_DISTANCE * TheCamera.GenerationDistMultiplier; - break; - case 1: - /* Spawn a vehicle close to player to his side. */ - /* Kinda not within camera angle. */ - angleLimit = 0.707f; /* 45 degrees */ - invertAngleLimitTest = false; - preferredDistance = OFFSCREEN_DESPAWN_RANGE; - break; + else { + /* Player is in vehicle but moving very slow. */ + /* Then use camera direction instead of vehicle direction. */ + testForCollision = true; + frontX = TheCamera.CamFrontXNorm; + frontY = TheCamera.CamFrontYNorm; + switch (CTimer::GetFrameCounter() & 1) { + case 0: + /* Spawn a vehicle relatively far away from player. */ + /* Forward to his current direction (camera direction). */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = true; + preferredDistance = REQUEST_ONSCREEN_DISTANCE * requestMultiplier * TheCamera.GenerationDistMultiplier; + break; + case 1: + /* Spawn a vehicle close to player to his side. */ + /* Kinda not within camera angle. */ + angleLimit = 0.707f; /* 45 degrees */ + invertAngleLimitTest = false; + preferredDistance = MINIMAL_DISTANCE_TO_SPAWN_OFFSCREEN; + break; + } } } if (!ThePaths.GenerateCarCreationCoors(vecTargetPos.x, vecTargetPos.y, frontX, frontY, @@ -297,6 +370,8 @@ CCarCtrl::GenerateOneRandomCar() CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId]; CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId]; bool bBoatGenerated = false; + if (!OkToCreateVehicleAtThisPosition(spawnPosition)) + return; if ((CGeneral::GetRandomNumber() & 0xF) > Min(pCurNode->spawnRate, pNextNode->spawnRate)) return; if (pCurNode->bWaterPath) { @@ -346,10 +421,16 @@ CCarCtrl::GenerateOneRandomCar() CVehicle* pVehicle; if (CModelInfo::IsBoatModel(carModel)) pVehicle = new CBoat(carModel, RANDOM_VEHICLE); - else if (CModelInfo::IsBikeModel(carModel)) - pVehicle = new CBike(carModel, RANDOM_VEHICLE); else - pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); + { + if (CModelInfo::IsBikeModel(carModel)) + pVehicle = new CBike(carModel, RANDOM_VEHICLE); + else + pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); +#ifdef GTA_NETWORK + // TODO +#endif + } pVehicle->AutoPilot.m_nPrevRouteNode = 0; pVehicle->AutoPilot.m_nCurrentRouteNode = curNodeId; pVehicle->AutoPilot.m_nNextRouteNode = nextNodeId; @@ -367,7 +448,7 @@ CCarCtrl::GenerateOneRandomCar() pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_STOP_FOR_CARS; pVehicle->AutoPilot.m_nCarMission = MISSION_CRUISE; } - if (carModel == MI_FBIRANCH){ + if (carModel == MI_FBICAR){ pVehicle->m_currentColour1 = 0; pVehicle->m_currentColour2 = 0; } @@ -589,6 +670,9 @@ CCarCtrl::GenerateOneRandomCar() break; } CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0); +#ifdef GTA_MOBILE + //CVisibilityPlugins::SetObjectDistanceAlpha(pVehicle->GetClump(), 0) // TODO(LCS) +#endif if (!pVehicle->GetIsOnScreen()){ if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > OFFSCREEN_DESPAWN_RANGE * (pVehicle->bExtendedRange ? EXTENDED_RANGE_DESPAWN_MULTIPLIER : 1.0f)) { /* Too far away cars that are not visible aren't needed. */ @@ -596,12 +680,12 @@ CCarCtrl::GenerateOneRandomCar() return; } }else{ - if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? EXTENDED_RANGE_DESPAWN_MULTIPLIER : 1.0f) * ONSCREEN_DESPAWN_RANGE || - (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN) { + if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * requestMultiplier * (pVehicle->bExtendedRange ? EXTENDED_RANGE_DESPAWN_MULTIPLIER : 1.0f) * ONSCREEN_DESPAWN_RANGE || + (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * requestMultiplier * MINIMAL_DISTANCE_TO_SPAWN_ONSCREEN) { delete pVehicle; return; } - if ((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 82.5f * TheCamera.GenerationDistMultiplier || bTopDownCamera) { + if ((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < MAX_DISTANCE_FROM_CAMERA_TO_SPAWN_ONSCREEN * requestMultiplier * TheCamera.GenerationDistMultiplier || bTopDownCamera) { delete pVehicle; return; } @@ -635,29 +719,34 @@ CCarCtrl::GenerateOneRandomCar() CCarAI::AddPoliceCarOccupants(pVehicle); else { pVehicle->SetUpDriver(); - int32 passengers = 0; - for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) - passengers += (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < PROBABILITY_OF_PASSENGER_IN_VEHICLE) ? 1 : 0; - if (CModelInfo::IsCarModel(carModel) && (CModelInfo::GetModelInfo(carModel)->GetAnimFileIndex() == CAnimManager::GetAnimationBlockIndex("van") && passengers >= 1)) - passengers = 1; - for (int i = 0; i < passengers; i++) { - CPed* pPassenger = pVehicle->SetupPassenger(i); - if (pPassenger) { - ++CPopulation::ms_nTotalCarPassengerPeds; - pPassenger->bCarPassenger = true; +#ifdef GTA_NETWORK + if (!gIsMultiplayerGame) +#endif + { + int32 passengers = 0; + for (int i = 0; i < pVehicle->m_nNumMaxPassengers; i++) + passengers += (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) < PROBABILITY_OF_PASSENGER_IN_VEHICLE) ? 1 : 0; + if (CModelInfo::IsCarModel(carModel) && (CModelInfo::GetModelInfo(carModel)->GetAnimFileIndex() == CAnimManager::GetAnimationBlockIndex("van") && passengers >= 1)) + passengers = 1; + for (int i = 0; i < passengers; i++) { + CPed* pPassenger = pVehicle->SetupPassenger(i); + if (pPassenger) { + ++CPopulation::ms_nTotalCarPassengerPeds; + pPassenger->bCarPassenger = true; + } } } } int nMadDrivers; switch (pVehicle->GetVehicleAppearance()) { case VEHICLE_APPEARANCE_BIKE: - nMadDrivers = 30; + nMadDrivers = 20; break; case VEHICLE_APPEARANCE_BOAT: nMadDrivers = 40; break; default: - nMadDrivers = 6; + nMadDrivers = 3; break; } if ((CGeneral::GetRandomNumber() & 0x7F) < nMadDrivers || bMadDriversCheat) { @@ -714,12 +803,9 @@ CCarCtrl::GenerateOneRandomCar() } } } -} - -bool -CCarCtrl::BoatWithTallMast(int32 mi) -{ - return mi == MI_RIO || mi == MI_TROPIC || mi == MI_MARQUIS; +#ifdef GTA_NETWORK + // TODO +#endif } int32 @@ -755,6 +841,22 @@ int32 CCarCtrl::ChooseModel(CZoneInfo* pZone, int* pClass) { int32 model = -1; int32 i; +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + for (i = 10; i > 0 && (model == -1 || !CStreaming::HasModelLoaded(model)); i--) { + *pClass = ChooseCarRating(pZone); + model = ChooseCarModel(*pClass); + bool found = false; + for (int j = 0; j < 8; j++) { + if (model == MultiplayerCarBanks[nAmbientCarBank][j]) + found = true; + } + if (!found) + model = -1; + } + return model; + } +#endif for (i = 10; i > 0 && (model == -1 || !CStreaming::HasModelLoaded(model)); i--) { int rnd = CGeneral::GetRandomNumberInRange(0, 1000); @@ -781,6 +883,9 @@ CCarCtrl::ChooseModel(CZoneInfo* pZone, int* pClass) { } if (i == 0) return -1; + CColModel* pColModel = CModelInfo::GetColModel(model); + if (!pColModel || pColModel->boundingSphere.radius > 20.0f) + return -1; return model; } @@ -941,6 +1046,7 @@ CCarCtrl::RemoveCarsIfThePoolGetsFull(void) } } if (pClosestVehicle) { + debug(":::::::::::\'Nearest removed\' cause pools was full -> NumRandomCars %d\n", NumRandomCars); CWorld::Remove(pClosestVehicle); delete pClosestVehicle; } @@ -963,7 +1069,12 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) return; } float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D(); - float threshold = OFFSCREEN_DESPAWN_RANGE; + float despawnMultiplier = 1.0f; +#if !defined EXTENDED_OFFSCREEN_DESPAWN_RANGE || defined GTA_PSP + if (FindPlayerVehicle() && TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_1STPERSON && !FrontEndMenuManager.m_PrefsUseWideScreen) + despawnMultiplier = 0.75f; +#endif + float threshold = OFFSCREEN_DESPAWN_RANGE * despawnMultiplier; #ifndef EXTENDED_OFFSCREEN_DESPAWN_RANGE if (pVehicle->GetIsOnScreen() || TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || @@ -979,7 +1090,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) ) #endif { - threshold = ONSCREEN_DESPAWN_RANGE * TheCamera.GenerationDistMultiplier; + threshold = ONSCREEN_DESPAWN_RANGE * despawnMultiplier * TheCamera.GenerationDistMultiplier; } #ifndef EXTENDED_OFFSCREEN_DESPAWN_RANGE if (TheCamera.GetForward().z < -0.9f) @@ -991,6 +1102,14 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) if (pVehicle->GetIsOnScreen()){ pVehicle->bFadeOut = true; }else{ +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + // TODO + if (false) + MultiPlayerRemoveVehicleAndDriver(pVehicle); + return; + } +#endif CWorld::Remove(pVehicle); delete pVehicle; } @@ -1008,10 +1127,33 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) !CTrafficLights::ShouldCarStopForLight(pVehicle, true) && !CTrafficLights::ShouldCarStopForBridge(pVehicle) && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ - CWorld::Remove(pVehicle); - delete pVehicle; +#ifdef GTA_NETWORK + if (!gIsMultiplayerGame) +#endif + { + CWorld::Remove(pVehicle); + delete pVehicle; + return; + } +#ifdef GTA_NETWORK + if (false) // TODO(LCS): figure out condition for mp + MultiPlayerRemoveVehicleAndDriver(pVehicle); +#endif + } +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + if (pVehicle->GetStatus() == STATUS_WRECKED && CTimer::GetLogicalFrameCounter() == pVehicle->m_randomSeed) { + if ((pVehicle->GetPosition() - vecPlayerPos).MagnitudeSqr() > SQR(6.5f)) { + if (pVehicle->GetMoveSpeed().MagnitudeSqr() <= SQR(0.01f)) { + printf("viciously removing dead vehicle"); + CWorld::Remove(pVehicle); + delete pVehicle; + } + } + } return; } +#endif if (pVehicle->GetStatus() == STATUS_WRECKED) { if (pVehicle->m_nTimeOfDeath != 0) { if (CTimer::GetTimeInMilliseconds() > pVehicle->m_nTimeOfDeath + 60000 && @@ -1347,6 +1489,10 @@ void CCarCtrl::SlowCarDownForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, pVehicle->AutoPilot.m_bSlowedDownBecauseOfCars = true; *pSpeed = Min(*pSpeed, minProximity * curSpeed); } +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) + return; +#endif if (minProximity >= 0.0f && minProximity < 0.5f && pOtherEntity->IsVehicle() && CTimer::GetTimeInMilliseconds() - pVehicle->AutoPilot.m_nTimeToStartMission > 15000 && CTimer::GetTimeInMilliseconds() - pOtherVehicle->AutoPilot.m_nTimeToStartMission > 15000){ @@ -1594,16 +1740,12 @@ void CCarCtrl::WeaveForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float diffToLeftAngle = ABS(diffToLeftAngle); float angleToWeave = lengthToEvade / 2; if (diffToLeftAngle < angleToWeave){ - *pAngleToWeaveLeft = angleBetweenVehicles - angleToWeave; - while (*pAngleToWeaveLeft < -PI) - *pAngleToWeaveLeft += TWOPI; + *pAngleToWeaveLeft = LimitRadianAngle(angleBetweenVehicles - angleToWeave); } float diffToRightAngle = LimitRadianAngle(angleBetweenVehicles - *pAngleToWeaveRight); diffToRightAngle = ABS(diffToRightAngle); if (diffToRightAngle < angleToWeave){ - *pAngleToWeaveRight = angleBetweenVehicles + angleToWeave; - while (*pAngleToWeaveRight > PI) - *pAngleToWeaveRight -= TWOPI; + *pAngleToWeaveRight = LimitRadianAngle(angleBetweenVehicles + angleToWeave); } } @@ -1642,16 +1784,12 @@ void CCarCtrl::WeaveForPed(CEntity* pOtherEntity, CVehicle* pVehicle, float* pAn diffToLeftAngle = ABS(diffToLeftAngle); float angleToWeave = lengthToEvade / 2; if (diffToLeftAngle < angleToWeave) { - *pAngleToWeaveLeft = angleBetweenVehicleAndPed - angleToWeave; - while (*pAngleToWeaveLeft < -PI) - *pAngleToWeaveLeft += TWOPI; + *pAngleToWeaveLeft = LimitRadianAngle(angleBetweenVehicleAndPed - angleToWeave); } float diffToRightAngle = LimitRadianAngle(angleBetweenVehicleAndPed - *pAngleToWeaveRight); diffToRightAngle = ABS(diffToRightAngle); if (diffToRightAngle < angleToWeave) { - *pAngleToWeaveRight = angleBetweenVehicleAndPed + angleToWeave; - while (*pAngleToWeaveRight > PI) - *pAngleToWeaveRight -= TWOPI; + *pAngleToWeaveRight = LimitRadianAngle(angleBetweenVehicleAndPed + angleToWeave); } } @@ -1714,16 +1852,12 @@ void CCarCtrl::WeaveForObject(CEntity* pOtherEntity, CVehicle* pVehicle, float* diffToLeftAngle = ABS(diffToLeftAngle); float angleToWeave = lengthToEvade / 2; if (diffToLeftAngle < angleToWeave) { - *pAngleToWeaveLeft = angleBetweenVehicleAndObject - angleToWeave; - while (*pAngleToWeaveLeft < -PI) - *pAngleToWeaveLeft += TWOPI; + *pAngleToWeaveLeft = LimitRadianAngle(angleBetweenVehicleAndObject - angleToWeave); } float diffToRightAngle = LimitRadianAngle(angleBetweenVehicleAndObject - *pAngleToWeaveRight); diffToRightAngle = ABS(diffToRightAngle); if (diffToRightAngle < angleToWeave) { - *pAngleToWeaveRight = angleBetweenVehicleAndObject + angleToWeave; - while (*pAngleToWeaveRight > PI) - *pAngleToWeaveRight -= TWOPI; + *pAngleToWeaveRight = LimitRadianAngle(angleBetweenVehicleAndObject + angleToWeave); } } @@ -1765,7 +1899,7 @@ bool CCarCtrl::PickNextNodeAccordingStrategy(CVehicle* pVehicle) void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) { if (pVehicle->m_nRouteSeed) - CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed++); int32 prevNode = pVehicle->AutoPilot.m_nCurrentRouteNode; int32 curNode = pVehicle->AutoPilot.m_nNextRouteNode; uint8 totalLinks = ThePaths.m_pathNodes[curNode].numLinks; @@ -1851,13 +1985,15 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) pNextPathNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nNextRouteNode]; if ((!pNextPathNode->bDisabled || pPrevPathNode->bDisabled) && (!pNextPathNode->bBetweenLevels || pPrevPathNode->bBetweenLevels || !pVehicle->AutoPilot.m_bStayInCurrentLevel)) - /* Nice way to exit loop but this will fail because this is used for indexing! */ - nextLink = 1000; + break; } } - if (nextLink < 999) + if (nextLink >= totalLinks) { /* If everything else failed, turn vehicle around */ + nextLink = 0; + debug("Couldn\'t find ANYTHING. Just go back from where we came.\n"); pVehicle->AutoPilot.m_nNextRouteNode = prevNode; + } } pNextPathNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nNextRouteNode]; pNextLink = &ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[nextLink + pCurPathNode->firstLink]]; @@ -1970,7 +2106,7 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t #endif { if (pVehicle->m_nRouteSeed) - CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed++); int prevNode = pVehicle->AutoPilot.m_nCurrentRouteNode; int curNode = pVehicle->AutoPilot.m_nNextRouteNode; CPathNode* pPrevNode = &ThePaths.m_pathNodes[prevNode]; @@ -1984,7 +2120,7 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t #else CVector(targetX, targetY, 0.0f), #endif - pTargetNode, &numNodes, 2, pVehicle, &distanceToTargetNode, 999999.9f, -1); + pTargetNode, &numNodes, 2, pVehicle, &distanceToTargetNode, 100.0f, -1); int newNextNode; int nextLink; @@ -2099,14 +2235,14 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t bool CCarCtrl::PickNextNodeToFollowPath(CVehicle* pVehicle) { if (pVehicle->m_nRouteSeed) - CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed++); int curNode = pVehicle->AutoPilot.m_nNextRouteNode; CPathNode* pCurNode = &ThePaths.m_pathNodes[curNode]; if (pVehicle->AutoPilot.m_nPathFindNodesCount == 0){ ThePaths.DoPathSearch(0, pVehicle->GetPosition(), curNode, pVehicle->AutoPilot.m_vecDestinationCoors, pVehicle->AutoPilot.m_aPathFindNodesInfo, &pVehicle->AutoPilot.m_nPathFindNodesCount, NUM_PATH_NODES_IN_AUTOPILOT, - pVehicle, nil, 999999.9f, -1); + pVehicle, nil, 100.0f, -1); if (pVehicle->AutoPilot.m_nPathFindNodesCount < 2) return true; pVehicle->AutoPilot.RemoveOnePathNode(); @@ -2418,6 +2554,16 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe *pHandbrake = true; return; case MISSION_CRUISE: + if (CTrafficLights::ShouldCarStopForBridge(pVehicle)) { + *pAccel = 0.0f; + *pBrake = 1.0f; + *pHandbrake = true; +#ifdef FIX_BUGS + *pSwerve = 0.0f; +#endif + break; + } + // fallthough case MISSION_RAMPLAYER_FARAWAY: case MISSION_BLOCKPLAYER_FARAWAY: case MISSION_GOTOCOORDS: @@ -2488,11 +2634,19 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe *pHandbrake = false; return; case MISSION_RAMCAR_CLOSE: + if (!pVehicle->AutoPilot.m_pTargetCar) { + debug("NO TARGET VEHICLE FOR MISSION_RAMCAR_CLOSE\n"); + return; + } 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: + if (!pVehicle->AutoPilot.m_pTargetCar) { + debug("NO TARGET VEHICLE FOR MISSION_BLOCKCAR_CLOSE\n"); + return; + } SteerAICarWithPhysicsTryingToBlockTarget(pVehicle, pVehicle->AutoPilot.m_pTargetCar->GetPosition().x, pVehicle->AutoPilot.m_pTargetCar->GetPosition().y, @@ -2501,6 +2655,9 @@ void CCarCtrl::SteerAICarWithPhysics_OnlyMission(CVehicle* pVehicle, float* pSwe pSwerve, pAccel, pBrake, pHandbrake); return; case MISSION_BLOCKCAR_HANDBRAKESTOP: + if (!pVehicle->AutoPilot.m_pTargetCar) { + return; + } SteerAICarWithPhysicsTryingToBlockTarget_Stop(pVehicle, pVehicle->AutoPilot.m_pTargetCar->GetPosition().x, pVehicle->AutoPilot.m_pTargetCar->GetPosition().y, @@ -3109,7 +3266,7 @@ bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle* pVehicle, CVector vecTar { pVehicle->AutoPilot.m_vecDestinationCoors = vecTarget; ThePaths.DoPathSearch(0, pVehicle->GetPosition(), -1, vecTarget, pVehicle->AutoPilot.m_aPathFindNodesInfo, - &pVehicle->AutoPilot.m_nPathFindNodesCount, NUM_PATH_NODES_IN_AUTOPILOT, pVehicle, nil, 999999.9f, -1); + &pVehicle->AutoPilot.m_nPathFindNodesCount, NUM_PATH_NODES_IN_AUTOPILOT, pVehicle, nil, 100.0f, -1); ThePaths.RemoveBadStartNode(pVehicle->GetPosition(), pVehicle->AutoPilot.m_aPathFindNodesInfo, &pVehicle->AutoPilot.m_nPathFindNodesCount); if (pVehicle->AutoPilot.m_nPathFindNodesCount < 2){ @@ -3130,7 +3287,7 @@ bool CCarCtrl::JoinCarWithRoadSystemGotoCoors(CVehicle* pVehicle, CVector vecTar void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle) { if (pVehicle->m_nRouteSeed) - CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed); + CGeneral::SetRandomSeed(pVehicle->m_nRouteSeed++); int nextLink; CPathNode* pCurNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nCurrentRouteNode]; for (nextLink = 0; nextLink < 12; nextLink++) @@ -3168,14 +3325,22 @@ void CCarCtrl::FindLinksToGoWithTheseNodes(CVehicle* pVehicle) void CCarCtrl::GenerateEmergencyServicesCar(void) { +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) + return; +#endif if (FindPlayerPed()->m_pWanted->GetWantedLevel() > 3) return; if (CGame::IsInInterior()) return; +#ifndef GTA_PSP + if (TheCamera.m_WideScreenOn) + return; +#endif if (NumFiretrucksOnDuty + NumAmbulancesOnDuty + NumParkedCars + NumMissionCars + NumLawEnforcerCars + NumRandomCars > MaxNumberOfCarsInUse) return; - if (NumAmbulancesOnDuty == 0){ + if (NumAmbulancesOnDuty == 0 && gbEmergencyVehiclesEnabled){ if (gAccidentManager.CountActiveAccidents() < 2){ if (CStreaming::HasModelLoaded(MI_AMBULAN)) CStreaming::SetModelIsDeletable(MI_MEDIC); @@ -3195,7 +3360,7 @@ void CCarCtrl::GenerateEmergencyServicesCar(void) } } } - if (NumFiretrucksOnDuty == 0){ + if (NumFiretrucksOnDuty == 0 && gbEmergencyVehiclesEnabled){ if (gFireManager.GetTotalActiveFires() < 3){ if (CStreaming::HasModelLoaded(MI_FIRETRUCK)) CStreaming::SetModelIsDeletable(MI_FIREMAN); @@ -3225,6 +3390,10 @@ void CCarCtrl::GenerateEmergencyServicesCar(void) bool CCarCtrl::GenerateOneEmergencyServicesCar(uint32 mi, CVector vecPos) { +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) + return; +#endif CVector pPlayerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); bool created = false; int attempts = 0; @@ -3290,6 +3459,11 @@ bool CCarCtrl::GenerateOneEmergencyServicesCar(uint32 mi, CVector vecPos) pVehicle->m_bSirenOrAlarm = true; CWorld::Add(pVehicle); printf("CREATED EMERGENCY VEHICLE\n"); +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + // TODO (register car for network) + } +#endif return true; } @@ -3359,6 +3533,22 @@ bool CCarCtrl::MapCouldMoveInThisArea(float x, float y) #endif } +bool +CCarCtrl::BoatWithTallMast(int32 mi) +{ + return mi == MI_RIO || mi == MI_TROPIC || mi == MI_MARQUIS; +} + +bool CCarCtrl::OkToCreateVehicleAtThisPosition(const CVector& pos) +{ +#ifdef GTA_NETWORK + if (gIsMultiplayerGame) { + // TODO + } +#endif + return true; +} + float CCarCtrl::FindSpeedMultiplierWithSpeedFromNodes(int8 type) { switch (type) @@ -3368,3 +3558,64 @@ float CCarCtrl::FindSpeedMultiplierWithSpeedFromNodes(int8 type) } return 1.0f; } + +void CCarCtrl::RenderDebugInfo(CVehicle* pVehicle) +{ + if (!pVehicle->AutoPilot.m_nNextRouteNode || !pVehicle->AutoPilot.m_nCurrentRouteNode) + return; + + CPathNode* pCurNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nCurrentRouteNode]; + CPathNode* pNextNode = &ThePaths.m_pathNodes[pVehicle->AutoPilot.m_nNextRouteNode]; + CCarPathLink* pCurLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo]; + CCarPathLink* pNextLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo]; + + CVector vCurNodePos(pCurNode->GetPosition()); + vCurNodePos.z += 1.0f; + CVector vNextNodePos(pNextNode->GetPosition()); + vNextNodePos.z += 1.0f; + CVector vCurLinkDir(pCurLink->GetDirX() * pVehicle->AutoPilot.m_nCurrentDirection, pCurLink->GetDirY() * pVehicle->AutoPilot.m_nCurrentDirection, 0.0f); + CVector vNextLinkDir(pNextLink->GetDirX() * pVehicle->AutoPilot.m_nNextDirection, pNextLink->GetDirY() * pVehicle->AutoPilot.m_nNextDirection, 0.0f); + vCurLinkDir.Normalise(); + vNextLinkDir.Normalise(); + + if (vCurLinkDir.x * vNextLinkDir.x + vCurLinkDir.y * vNextLinkDir.y < 0.5f) { + CVector vCurPos(vCurNodePos); + CVector vCurDir(0.0f, 0.0f, 1.0f); + for (int i = 0; i < 10; i++) { + CVector vPrevPos = vCurPos; + CCurves::CalcCurvePoint(&vCurNodePos, &vNextNodePos, &vCurLinkDir, &vNextLinkDir, i * 0.1f, pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve, &vCurPos, &vCurDir); + // Render3DLine(&vCurPos, &vNextPos, CVector(255.0f, 255.0f, 0.0f, 255.0f)); // <- originally this is called, let's reuse stuff we have + // TODO: not drawing :( + CLines::RenderLineWithClipping(vPrevPos.x, vPrevPos.y, vCurNodePos.z, vCurPos.x, vCurPos.y, vNextNodePos.z, 0xFFFF00FF, 0xFFFF00FF); // using NodePos for Z coord cause Curves set it to 0 + } + DefinedState(); + } +} + +void CCarCtrl::SetMultiplayerAmbientCarLimit(uint32 limit) +{ + maxRandomMpCars = limit; +} + +void CCarCtrl::ToggleScriptControlsMpCarLimit(bool toggle) +{ + scriptControlsMpCarLimit = toggle; +} + +void CCarCtrl::MultiPlayerRemoveVehicleAndDriver(CVehicle* pVehicle) +{ + CPed* pDriver = pVehicle->pDriver; + CWorld::Remove(pVehicle); + delete pVehicle; + if (pDriver) { + CWorld::Remove(pDriver); + delete pDriver; + } +} + +void CCarCtrl::Write(base::cRelocatableChunkWriter& writer) +{ + writer.AllocateRaw(CarArrays, sizeof(CarArrays), 4); + writer.AllocateRaw(TotalNumOfCarsOfRating, sizeof(TotalNumOfCarsOfRating), 4, false, true); +} + |