diff options
Diffstat (limited to 'src/control/CarCtrl.cpp')
-rw-r--r-- | src/control/CarCtrl.cpp | 674 |
1 files changed, 457 insertions, 217 deletions
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 71236580..cf8e63f4 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -11,6 +11,7 @@ #include "Curves.h" #include "CutsceneMgr.h" #include "Gangs.h" +#include "Game.h" #include "Garages.h" #include "General.h" #include "IniFile.h" @@ -19,6 +20,7 @@ #include "Ped.h" #include "PlayerInfo.h" #include "PlayerPed.h" +#include "Population.h" #include "Wanted.h" #include "Pools.h" #include "Renderer.h" @@ -29,6 +31,7 @@ #include "VisibilityPlugins.h" #include "Vehicle.h" #include "Fire.h" +#include "WaterLevel.h" #include "World.h" #include "Zones.h" @@ -67,6 +70,12 @@ #define MIN_ANGLE_TO_APPLY_HANDBRAKE 0.7f #define MIN_SPEED_TO_APPLY_HANDBRAKE 0.3f +#define PROBABILITY_OF_DEAD_PED_ACCIDENT 0.005f +#define DISTANCE_BETWEEN_CAR_AND_DEAD_PED 6.0f +#define PROBABILITY_OF_PASSENGER_IN_VEHICLE 0.125f + +#define FARAWAY_DISTANCE_REMOVAL 120.0f + int CCarCtrl::NumLawEnforcerCars; int CCarCtrl::NumAmbulancesOnDuty; int CCarCtrl::NumFiretrucksOnDuty; @@ -81,23 +90,29 @@ int32 CCarCtrl::MaxNumberOfCarsInUse = 12; uint32 CCarCtrl::LastTimeLawEnforcerCreated; uint32 CCarCtrl::LastTimeFireTruckCreated; uint32 CCarCtrl::LastTimeAmbulanceCreated; +int32 CCarCtrl::MiamiViceCycle; +uint32 CCarCtrl::LastTimeMiamiViceGenerated; 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::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]; uint32 aCarsToKeepTime[MAX_CARS_TO_KEEP]; void CCarCtrl::GenerateRandomCars() { - if (CCutsceneMgr::IsRunning()) + if (CCutsceneMgr::IsRunning()) { + CountDownToCarsAtStart = 2; return; + } if (NumRandomCars < 30){ - if (CountDownToCarsAtStart == 0){ + if (CountDownToCarsAtStart == 0) GenerateOneRandomCar(); - } else if (--CountDownToCarsAtStart == 0) { - for (int i = 0; i < 50; i++) + for (int i = 0; i < 100; i++) GenerateOneRandomCar(); CTheCarGenerators::GenerateEvenIfPlayerIsCloseCounter = 20; } @@ -111,6 +126,7 @@ void CCarCtrl::GenerateOneRandomCar() { static int32 unk = 0; + bool bTopDownCamera = false; CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; CVector vecTargetPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); CVector2D vecPlayerSpeed = FindPlayerSpeed(); @@ -125,7 +141,7 @@ CCarCtrl::GenerateOneRandomCar() int carClass; int carModel; 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 > 2 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 5000 || pWanted->m_nWantedLevel > 1 && CTimer::GetTimeInMilliseconds() > LastTimeLawEnforcerCreated + 8000)) { @@ -135,7 +151,7 @@ CCarCtrl::GenerateOneRandomCar() carModel = ChoosePoliceCarModel(); }else{ 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. */ /* In particular it means that cop cars never spawn if player has wanted level of 1. */ return; @@ -159,8 +175,9 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn essentially anywhere. */ frontX = frontY = 0.707f; /* 45 degrees */ angleLimit = -1.0f; + bTopDownCamera = true; invertAngleLimitTest = true; - preferredDistance = 40.0f; + preferredDistance = 55.0f; /* BUG: testForCollision not initialized in original game. */ testForCollision = false; }else if (!pPlayerVehicle){ @@ -174,7 +191,7 @@ CCarCtrl::GenerateOneRandomCar() /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle close to player to his side. */ @@ -196,14 +213,14 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn a vehicle in a very narrow gap in front of a player */ angleLimit = 0.85f; /* approx 30 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * 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 = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier; break; case 3: /* Spawn a vehicle close to player to his side. */ @@ -224,14 +241,14 @@ CCarCtrl::GenerateOneRandomCar() /* Spawn a vehicle in a very narrow gap in front of a player */ angleLimit = 0.85f; /* approx 30 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * 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 = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier; break; case 2: case 3: @@ -254,7 +271,7 @@ CCarCtrl::GenerateOneRandomCar() /* Forward to his current direction (camera direction). */ angleLimit = 0.707f; /* 45 degrees */ invertAngleLimitTest = true; - preferredDistance = 120.0f * TheCamera.GenerationDistMultiplier; + preferredDistance = 110.0f * TheCamera.GenerationDistMultiplier; break; case 1: /* Spawn a vehicle close to player to his side. */ @@ -269,17 +286,45 @@ CCarCtrl::GenerateOneRandomCar() preferredDistance, angleLimit, invertAngleLimitTest, &spawnPosition, &curNodeId, &nextNodeId, &positionBetweenNodes, carClass == COPS && pWanted->m_nWantedLevel >= 1)) 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 { + int i; + carModel = -1; + for (i = 10; i > 0 && (carModel == -1 || !CStreaming::HasModelLoaded(carModel)); i--) { + carModel = ChooseBoatModel(ChooseBoatRating(&zone)); + } + if (i == 0) + return; + } + if (pCurNode->bOnlySmallBoats || pNextNode->bOnlySmallBoats) { + if (BoatWithTallMast(carModel)) + return; + } + } 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 something is already present in spawn position, do not create vehicle*/ 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. */ return; int16 idInNode = 0; - CPathNode* pCurNode = &ThePaths.m_pathNodes[curNodeId]; - CPathNode* pNextNode = &ThePaths.m_pathNodes[nextNodeId]; + while (idInNode < pCurNode->numLinks && ThePaths.ConnectedNode(idInNode + pCurNode->firstLink) != nextNodeId) idInNode++; @@ -287,48 +332,20 @@ CCarCtrl::GenerateOneRandomCar() CCarPathLink* pPathLink = &ThePaths.m_carPathLinks[connectionId]; int16 lanesOnCurrentRoad = pPathLink->pathNodeIndex == nextNodeId ? pPathLink->numLeftLanes : pPathLink->numRightLanes; 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. */ - /* Also not spawning bikes but they don't exist in final game. */ return; - CAutomobile* pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); + CVehicle* pVehicle; + if (CModelInfo::IsBoatModel(carModel)) + pVehicle = new CBoat(carModel, RANDOM_VEHICLE); + else if (CModelInfo::IsBikeModel(carModel)) + return; // TODO(MIAMI): spawn bikes + else + pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); pVehicle->AutoPilot.m_nPrevRouteNode = 0; pVehicle->AutoPilot.m_nCurrentRouteNode = curNodeId; pVehicle->AutoPilot.m_nNextRouteNode = nextNodeId; switch (carClass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - case MAFIA: - case TRIAD: - case DIABLO: - case YAKUZA: - case YARDIE: - case COLOMB: - case NINES: - case GANG8: - case GANG9: - { - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(9, 14); - if (carClass == EXEC) - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(12, 18); - else if (carClass == POOR || carClass == SPECIAL) - pVehicle->AutoPilot.m_nCruiseSpeed = CGeneral::GetRandomNumberInRange(7, 10); - CVehicleModelInfo* pVehicleInfo = pVehicle->GetModelInfo(); - if (pVehicleInfo->GetColModel()->boundingBox.max.y - pVehicle->GetModelInfo()->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; - } case COPS: pVehicle->AutoPilot.m_nTempAction = TEMPACT_NONE; if (CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pWanted->m_nWantedLevel != 0){ @@ -345,16 +362,37 @@ CCarCtrl::GenerateOneRandomCar() if (carModel == MI_FBICAR){ pVehicle->m_currentColour1 = 0; pVehicle->m_currentColour2 = 0; - /* FBI cars are gray in carcols, but we want them black if they going after player. */ } + pVehicle->bCreatedAsPoliceVehicle = true; + break; + 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(); + pVehicle->bCreatedAsPoliceVehicle = true; + break; 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; } if (pVehicle && pVehicle->GetModelIndex() == MI_MRWHOOP) pVehicle->m_bSirenOrAlarm = true; pVehicle->AutoPilot.m_nNextPathNodeInfo = connectionId; pVehicle->AutoPilot.m_nNextLane = pVehicle->AutoPilot.m_nCurrentLane = CGeneral::GetRandomNumber() % lanesOnCurrentRoad; - CColBox* boundingBox = &CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel()->boundingBox; + CBox* boundingBox = &CModelInfo::GetModelInfo(pVehicle->GetModelIndex())->GetColModel()->boundingBox; float carLength = 1.0f + (boundingBox->max.y - boundingBox->min.y) / 2; 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. */ @@ -393,11 +431,6 @@ CCarCtrl::GenerateOneRandomCar() pVehicle->GetRight() = CVector(forwardY, -forwardX, 0.0f); pVehicle->GetUp() = CVector(0.0f, 0.0f, 1.0f); - float currentPathLinkForwardX = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirX(); - float currentPathLinkForwardY = pVehicle->AutoPilot.m_nCurrentDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nCurrentPathNodeInfo].GetDirY(); - float nextPathLinkForwardX = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirX(); - float nextPathLinkForwardY = pVehicle->AutoPilot.m_nNextDirection * ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo].GetDirY(); - #ifdef FIX_BUGS CCarPathLink* pCurrentLink; CCarPathLink* pNextLink; @@ -494,6 +527,7 @@ CCarCtrl::GenerateOneRandomCar() pVehicle->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - (0.5f + positionBetweenNodes) * pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve; #endif + CVector directionCurrentLink(directionCurrentLinkX, directionCurrentLinkY, 0.0f); CVector directionNextLink(directionNextLinkX, directionNextLinkY, 0.0f); CVector positionIncludingCurve; @@ -515,62 +549,68 @@ CCarCtrl::GenerateOneRandomCar() float groundZ = INFINITE_Z; CColPoint colPoint; CEntity* pEntity; - if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) - 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)) + if (bBoatGenerated) { + if (!CWaterLevel::GetWaterLevel(finalPosition, &groundZ, true)) { + delete pVehicle; + return; + } + } + else { + if (CWorld::ProcessVerticalLine(finalPosition, 1000.0f, colPoint, pEntity, true, false, false, false, true, false, nil)) 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) { /* Failed to find ground or too far from expected position. */ delete pVehicle; return; } - finalPosition.z = groundZ + pVehicle->GetHeightAboveRoad(); + if (CModelInfo::IsBoatModel(carModel)) { + finalPosition.z = groundZ; + pVehicle->bExtendedRange = true; + } + 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; switch (carClass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - case MAFIA: - case TRIAD: - case DIABLO: - case YAKUZA: - case YARDIE: - case COLOMB: - case NINES: - case GANG8: - case GANG9: - pVehicle->SetStatus(STATUS_SIMPLE); - break; case COPS: pVehicle->SetStatus((pVehicle->AutoPilot.m_nCarMission == MISSION_CRUISE) ? STATUS_SIMPLE : STATUS_PHYSICS); pVehicle->ChangeLawEnforcerState(1); break; + case COPS_BOAT: + pVehicle->ChangeLawEnforcerState(1); + pVehicle->SetStatus(STATUS_PHYSICS); default: + pVehicle->SetStatus(STATUS_SIMPLE); break; } CVisibilityPlugins::SetClumpAlpha(pVehicle->GetClump(), 0); if (!pVehicle->GetIsOnScreen()){ - if ((vecTargetPos - pVehicle->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. */ delete pVehicle; return; } - }else if((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * 130.0f || - (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 110.0f){ - delete pVehicle; - return; - }else if((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 90.0f * TheCamera.GenerationDistMultiplier){ - delete pVehicle; - return; + }else{ + if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? 1.5f : 1.0f) * FARAWAY_DISTANCE_REMOVAL || + (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 100.0f) { + delete pVehicle; + return; + } + if ((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 82.5f * TheCamera.GenerationDistMultiplier || bTopDownCamera) { + delete pVehicle; + return; + } + if (pVehicle->GetModelIndex() == MI_MARQUIS) { // so marquis can only spawn if player doesn't see it? + delete pVehicle; + return; + } } CVehicleModelInfo* pVehicleModel = pVehicle->GetModelInfo(); float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius; @@ -593,58 +633,152 @@ CCarCtrl::GenerateOneRandomCar() } pVehicleModel->AvoidSameVehicleColour(&pVehicle->m_currentColour1, &pVehicle->m_currentColour2); CWorld::Add(pVehicle); - if (carClass == COPS) + if (carClass == COPS || carClass == COPS_BOAT) CCarAI::AddPoliceCarOccupants(pVehicle); - else + else { pVehicle->SetUpDriver(); - if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */ + 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_BIKE: + nMadDrivers = 30; + break; + case VEHICLE_BOAT: + nMadDrivers = 40; + break; + default: + nMadDrivers = 6; + break; + } + if ((CGeneral::GetRandomNumber() & 0x7F) < nMadDrivers /* TODO(MIAMI): || mad drivers cheat */) { pVehicle->SetStatus(STATUS_PHYSICS); pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; pVehicle->AutoPilot.m_nCruiseSpeed += 10; } if (carClass == COPS) LastTimeLawEnforcerCreated = CTimer::GetTimeInMilliseconds(); + if (pVehicle->GetModelIndex() == MI_CADDY) { + pVehicle->SetStatus(STATUS_PHYSICS); + pVehicle->AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + } + if (carClass == COPS && pVehicle->GetModelIndex() == MI_VICECHEE) { + CVehicleModelInfo* pVehicleModel = (CVehicleModelInfo*)CModelInfo::GetModelInfo(MI_VICECHEE); + switch (MiamiViceCycle) { + case 0: + pVehicleModel->SetVehicleColour(53, 77); + break; + case 1: + pVehicleModel->SetVehicleColour(15, 77); + break; + case 2: + pVehicleModel->SetVehicleColour(41, 77); + break; + case 3: + pVehicleModel->SetVehicleColour(61, 77); + break; + default: + break; + } + } + if (CGeneral::GetRandomNumberInRange(0.0f, 1.0f) >= (1 - PROBABILITY_OF_DEAD_PED_ACCIDENT)) { + if (CModelInfo::IsCarModel(pVehicle->GetModelIndex()) && !pVehicle->bIsLawEnforcer) { + if (CPopulation::AddDeadPedInFrontOfCar(pVehicle->GetPosition() + pVehicle->GetForward() * DISTANCE_BETWEEN_CAR_AND_DEAD_PED, pVehicle)) { + pVehicle->AutoPilot.m_nCruiseSpeed = 0; + pVehicle->SetMoveSpeed(0.0f, 0.0f, 0.0f); + for (int i = 0; i < pVehicle->m_nNumPassengers; i++) { + if (pVehicle->pPassengers[i]) { + pVehicle->pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); + pVehicle->pPassengers[i]->m_nLastPedState = PED_WANDER_PATH; + pVehicle->pPassengers[i]->m_vehicleInAccident = pVehicle; + pVehicle->pPassengers[i]->bDeadPedInFrontOfCar = true; + pVehicle->RegisterReference((CEntity**)&pVehicle->pPassengers[i]->m_vehicleInAccident); + } + } + if (pVehicle->pDriver) { + pVehicle->pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, pVehicle); + pVehicle->pDriver->m_nLastPedState = PED_WANDER_PATH; + pVehicle->pDriver->m_vehicleInAccident = pVehicle; + pVehicle->pDriver->bDeadPedInFrontOfCar = true; + pVehicle->RegisterReference((CEntity**)&pVehicle->pDriver->m_vehicleInAccident); + } + } + } + } +} + +bool +CCarCtrl::BoatWithTallMast(int32 mi) +{ + return mi == MI_RIO || mi == MI_TROPIC || mi == MI_MARQUIS; +} + +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 CCarCtrl::ChooseModel(CZoneInfo* pZone, CVector* pPos, int* pClass) { 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); - if (rnd < pZone->carThreshold[0]) - model = CCarCtrl::ChooseCarModel((*pClass = POOR)); - else if (rnd < pZone->carThreshold[1]) - model = CCarCtrl::ChooseCarModel((*pClass = RICH)); - else if (rnd < pZone->carThreshold[2]) - model = CCarCtrl::ChooseCarModel((*pClass = EXEC)); - else if (rnd < pZone->carThreshold[3]) - model = CCarCtrl::ChooseCarModel((*pClass = WORKER)); - else if (rnd < pZone->carThreshold[4]) - model = CCarCtrl::ChooseCarModel((*pClass = SPECIAL)); - else if (rnd < pZone->carThreshold[5]) - model = CCarCtrl::ChooseCarModel((*pClass = BIG)); - else if (rnd < pZone->copThreshold) - *pClass = COPS, model = CCarCtrl::ChoosePoliceCarModel(); - else if (rnd < pZone->gangThreshold[0]) - model = CCarCtrl::ChooseGangCarModel((*pClass = MAFIA) - MAFIA); - 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)); + + if (rnd < pZone->copThreshold) { + *pClass = COPS; + model = ChoosePoliceCarModel(); + continue; + } + + int j; + for (j = 0; j < NUM_GANG_CAR_CLASSES; j++) { + if (rnd < pZone->gangThreshold[i]) { + *pClass = j + FIRST_GANG_CAR_RATING; + model = ChooseGangCarModel(j); + break; + } + } + + if (j != NUM_GANG_CAR_CLASSES) + continue; + + *pClass = ChooseCarRating(pZone); + model = ChooseCarModel(*pClass); } return model; } @@ -653,34 +787,83 @@ int32 CCarCtrl::ChooseCarModel(int32 vehclass) { int32 model = -1; - switch (vehclass) { - case POOR: - case RICH: - case EXEC: - case WORKER: - case SPECIAL: - case BIG: - case TAXI: - { - if (TotalNumOfCarsOfRating[vehclass] == 0) - debug("ChooseCarModel : No cars of type %d have been declared\n", vehclass); - model = CarArrays[vehclass][NextCarOfRating[vehclass]]; - int32 total = TotalNumOfCarsOfRating[vehclass]; - NextCarOfRating[vehclass] += CGeneral::GetRandomNumberInRange(1, total); - while (NextCarOfRating[vehclass] >= total) - NextCarOfRating[vehclass] -= total; - //NextCarOfRating[vehclass] %= total; - TotalNumOfCarsOfRating[vehclass] = total; /* why... */ - } - default: - break; - } - return model; + ++NumRequestsOfCarRating[vehclass]; + if (NumOfLoadedCarsOfRating[vehclass] == 0) + return -1; + int32 rnd = CGeneral::GetRandomNumberInRange(0, CarFreqArrays[vehclass][NumOfLoadedCarsOfRating[vehclass] - 1]); + int32 index = 0; + while (rnd > CarFreqArrays[vehclass][index]) + index++; + assert(LoadedCarsArray[vehclass][index]); + return LoadedCarsArray[vehclass][index]; +} + +void +CCarCtrl::AddToLoadedVehicleArray(int32 mi, int32 rating, int32 freq) +{ + LoadedCarsArray[rating][NumOfLoadedCarsOfRating[rating]] = mi; + assert(mi >= 130); + CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] = freq; + if (NumOfLoadedCarsOfRating[rating]) + CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating]] += CarFreqArrays[rating][NumOfLoadedCarsOfRating[rating] - 1]; + NumOfLoadedCarsOfRating[rating]++; +} + +void +CCarCtrl::RemoveFromLoadedVehicleArray(int mi, int32 rating) +{ + int index = 0; + while (LoadedCarsArray[rating][index] != -1) { + if (LoadedCarsArray[rating][index] == mi) + break; + index++; + } + assert(LoadedCarsArray[rating][index] == mi); + int32 freq = CarFreqArrays[rating][index]; + 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; + index++; + } + --NumOfLoadedCarsOfRating[rating]; +} + +int32 +CCarCtrl::ChooseCarModelToLoad(int rating) +{ + return CarArrays[rating][CGeneral::GetRandomNumberInRange(0, TotalNumOfCarsOfRating[rating])]; } int32 CCarCtrl::ChoosePoliceCarModel(void) { + if (FindPlayerPed()->m_pWanted->AreMiamiViceRequired() && + CTimer::GetTimeInMilliseconds() > LastTimeMiamiViceGenerated + 120000 && + CStreaming::HasModelLoaded(MI_VICECHEE)) { + // TODO(MIAMI): setup correct models! + switch (MiamiViceCycle) { + case 0: + if (CStreaming::HasModelLoaded(MI_COP) && CStreaming::HasModelLoaded(MI_COP)) + return MI_VICECHEE; + break; + case 1: + if (CStreaming::HasModelLoaded(MI_COP) && CStreaming::HasModelLoaded(MI_COP)) + return MI_VICECHEE; + break; + case 2: + if (CStreaming::HasModelLoaded(MI_COP) && CStreaming::HasModelLoaded(MI_COP)) + return MI_VICECHEE; + break; + case 3: + if (CStreaming::HasModelLoaded(MI_COP) && CStreaming::HasModelLoaded(MI_COP)) + return MI_VICECHEE; + break; + default: + break; + } + } if (FindPlayerPed()->m_pWanted->AreSwatRequired() && CStreaming::HasModelLoaded(MI_ENFORCER) && CStreaming::HasModelLoaded(MI_POLICE)) @@ -701,7 +884,7 @@ int32 CCarCtrl::ChooseGangCarModel(int32 gang) { if (CStreaming::HasModelLoaded(MI_GANG01 + 2 * gang) && - CStreaming::HasModelLoaded(MI_GANG02 + 2 * gang)) + CStreaming::HasModelLoaded(MI_GANG01+1 + 2 * gang)) return CGangs::GetGangVehicleModel(gang); return -1; } @@ -709,6 +892,7 @@ CCarCtrl::ChooseGangCarModel(int32 gang) void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { + assert(TotalNumOfCarsOfRating[vehclass] < MAX_CAR_MODELS_IN_ARRAY); CarArrays[vehclass][TotalNumOfCarsOfRating[vehclass]++] = id; } @@ -730,6 +914,36 @@ CCarCtrl::RemoveDistantCars() } void +CCarCtrl::RemoveCarsIfThePoolGetsFull(void) +{ + if ((CTimer::GetFrameCounter() & 7) != 3) + return; + if (CPools::GetVehiclePool()->GetNoOfFreeSpaces() >= 8) + return; + int i = CPools::GetVehiclePool()->GetSize(); + float md = 999999.9f; + CVehicle* pClosestVehicle = nil; + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle) + continue; + if (IsThisVehicleInteresting(pVehicle) || pVehicle->bIsLocked) + continue; + if (!pVehicle->CanBeDeleted() || CCranes::IsThisCarBeingTargettedByAnyCrane(pVehicle)) + continue; + float distance = (TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude(); + if (distance < md) { + md = distance; + pClosestVehicle = pVehicle; + } + } + if (pClosestVehicle) { + CWorld::Remove(pClosestVehicle); + delete pClosestVehicle; + } +} + +void CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) { CVector vecPlayerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); @@ -742,7 +956,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) return; } float distanceToPlayer = (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D(); - float threshold = 50.0f; + float threshold = 40.0f; if (pVehicle->GetIsOnScreen() || TheCamera.Cams[TheCamera.ActiveCam].LookingLeft || TheCamera.Cams[TheCamera.ActiveCam].LookingRight || @@ -754,12 +968,14 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) pVehicle->bIsLawEnforcer || pVehicle->bIsCarParkVehicle ){ - threshold = 130.0f * TheCamera.GenerationDistMultiplier; + threshold = FARAWAY_DISTANCE_REMOVAL * TheCamera.GenerationDistMultiplier; } + if (TheCamera.GetForward().z < -0.9f) + threshold = 70.0f; if (pVehicle->bExtendedRange) threshold *= 1.5f; if (distanceToPlayer > threshold && !CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ - if (pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)) { + if (pVehicle->GetIsOnScreen()){ pVehicle->bFadeOut = true; }else{ CWorld::Remove(pVehicle); @@ -768,7 +984,8 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) 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 && !pVehicle->GetIsOnScreen() && (pVehicle->GetPosition() - vecPlayerPos).Magnitude2D() > 25.0f && @@ -785,7 +1002,7 @@ CCarCtrl::PossiblyRemoveVehicle(CVehicle* pVehicle) if (pVehicle->GetStatus() != STATUS_WRECKED || pVehicle->m_nTimeOfDeath == 0) return; if (CTimer::GetTimeInMilliseconds() > pVehicle->m_nTimeOfDeath + 60000 && - !(pVehicle->GetIsOnScreen() && CRenderer::IsEntityCullZoneVisible(pVehicle)) ){ + !pVehicle->GetIsOnScreen()){ if ((pVehicle->GetPosition() - vecPlayerPos).MagnitudeSqr() > SQR(7.5f)){ if (!CGarages::IsPointWithinHideOutGarage(pVehicle->GetPosition())){ CWorld::Remove(pVehicle); @@ -809,6 +1026,16 @@ CCarCtrl::CountCarsOfType(int32 mi) return total; } +static CVector GetRandomOffsetForVehicle(CVehicle* pVehicle, bool bNext) +{ + CVector offset; + int32 seed = ((bNext ? pVehicle->AutoPilot.m_nNextPathNodeInfo : pVehicle->AutoPilot.m_nCurrentPathNodeInfo) + pVehicle->m_randomSeed) & 7; + offset.x = (seed - 3) * 0.009f; + offset.y = ((seed >> 3) - 3) * 0.009f; + offset.z = 0.0f; + return offset; +} + void CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle) { @@ -841,8 +1068,12 @@ CCarCtrl::UpdateCarOnRails(CVehicle* pVehicle) pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, 0.0f); - CVector directionCurrentLink(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f); - CVector directionNextLink(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f); + CVector directionCurrentLink = GetRandomOffsetForVehicle(pVehicle, false); + directionCurrentLink += CVector(currentPathLinkForwardX, currentPathLinkForwardY, 0.0f); + directionCurrentLink.Normalise(); + CVector directionNextLink = GetRandomOffsetForVehicle(pVehicle, true); + directionNextLink += CVector(nextPathLinkForwardX, nextPathLinkForwardY, 0.0f); + directionNextLink.Normalise(); CVector positionIncludingCurve; CVector directionIncludingCurve; CCurves::CalcCurvePoint( @@ -865,7 +1096,7 @@ CCarCtrl::FindMaximumSpeedForThisCarInTraffic(CVehicle* pVehicle) { if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_AVOID_CARS || pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_PLOUGH_THROUGH) - return pVehicle->AutoPilot.m_nCruiseSpeed; + return pVehicle->AutoPilot.GetCruiseSpeed(); float left = pVehicle->GetPosition().x - DISTANCE_TO_SCAN_FOR_DANGER; float right = pVehicle->GetPosition().x + DISTANCE_TO_SCAN_FOR_DANGER; float top = pVehicle->GetPosition().y - DISTANCE_TO_SCAN_FOR_DANGER; @@ -877,23 +1108,23 @@ CCarCtrl::FindMaximumSpeedForThisCarInTraffic(CVehicle* pVehicle) assert(xstart <= xend); assert(ystart <= yend); - float maxSpeed = pVehicle->AutoPilot.m_nCruiseSpeed; + float maxSpeed = pVehicle->AutoPilot.GetCruiseSpeed(); CWorld::AdvanceCurrentScanCode(); for (int y = ystart; y <= yend; y++){ for (int x = xstart; x <= xend; x++){ CSector* s = CWorld::GetSector(x, y); - SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); - SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.m_nCruiseSpeed); + SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForCarsSectorList(s->m_lists[ENTITYLIST_VEHICLES_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); + SlowCarDownForPedsSectorList(s->m_lists[ENTITYLIST_PEDS_OVERLAP], pVehicle, left, top, right, bottom, &maxSpeed, pVehicle->AutoPilot.GetCruiseSpeed()); } } pVehicle->bWarnedPeds = true; if (pVehicle->AutoPilot.m_nDrivingStyle == DRIVINGSTYLE_STOP_FOR_CARS) return maxSpeed; - return (maxSpeed + pVehicle->AutoPilot.m_nCruiseSpeed) / 2; + return (maxSpeed + pVehicle->AutoPilot.GetCruiseSpeed()) / 2; } void @@ -1095,8 +1326,8 @@ void CCarCtrl::SlowCarDownForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float proximityA = TestCollisionBetween2MovingRects(pOtherVehicle, pVehicle, projectionX, projectionY, &forwardA, &forwardB, 0); float proximityB = TestCollisionBetween2MovingRects(pVehicle, pOtherVehicle, -projectionX, -projectionY, &forwardB, &forwardA, 1); float minProximity = Min(proximityA, proximityB); - if (minProximity >= 0.0f && minProximity < 1.0f){ - minProximity = Max(0.0f, (minProximity - 0.2f) * 1.25f); + if (minProximity >= 0.0f && minProximity < 1.5f){ + minProximity = Max(0.0f, (minProximity - 0.2f) / 1.3f); pVehicle->AutoPilot.m_bSlowedDownBecauseOfCars = true; *pSpeed = Min(*pSpeed, minProximity * curSpeed); } @@ -1322,6 +1553,7 @@ void CCarCtrl::WeaveThroughCarsSectorList(CPtrList& lst, CVehicle* pVehicle, CPh void CCarCtrl::WeaveForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float* pAngleToWeaveLeft, float* pAngleToWeaveRight) { + // TODO(MIAMI): if (pVehicle->AutoPilot.m_nCarMission == MISSION_RAMPLAYER_CLOSE && pOtherEntity == FindPlayerVehicle()) return; if (pVehicle->AutoPilot.m_nCarMission == MISSION_RAMCAR_CLOSE && pOtherEntity == pVehicle->AutoPilot.m_pTargetCar) @@ -1333,8 +1565,8 @@ void CCarCtrl::WeaveForOtherCar(CEntity* pOtherEntity, CVehicle* pVehicle, float if (distance < 1.0f) return; if (DotProduct2D(pVehicle->GetMoveSpeed() - pOtherCar->GetMoveSpeed(), vecDiff) * 110.0f - - pOtherCar->GetModelInfo()->GetColModel()->boundingSphere.radius - - pVehicle->GetModelInfo()->GetColModel()->boundingSphere.radius < distance) + pOtherCar->GetColModel()->boundingSphere.radius - + pVehicle->GetColModel()->boundingSphere.radius < distance) return; CVector2D forward = pVehicle->GetForward(); forward.Normalise(); @@ -1508,23 +1740,30 @@ bool CCarCtrl::PickNextNodeAccordingStrategy(CVehicle* pVehicle) return false; default: PickNextNodeRandomly(pVehicle); + if (ThePaths.GetNode(pVehicle->AutoPilot.m_nNextRouteNode)->bOnlySmallBoats && BoatWithTallMast(pVehicle->GetModelIndex())) + pVehicle->AutoPilot.m_nCruiseSpeed = 0; return false; } } void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) { + if (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; CCarPathLink* pCurLink = &ThePaths.m_carPathLinks[pVehicle->AutoPilot.m_nNextPathNodeInfo]; -#ifdef FIX_BUGS - uint8 lanesOnCurrentPath = pCurLink->pathNodeIndex == curNode ? - pCurLink->numLeftLanes : pCurLink->numRightLanes; -#else - uint8 lanesOnCurrentPath = pCurLink->pathNodeIndex == curNode ? - pCurLink->numRightLanes : pCurLink->numLeftLanes; -#endif + uint8 lanesOnCurrentPath; + bool isOnOneWayRoad; + if (pCurLink->pathNodeIndex == curNode) { + lanesOnCurrentPath = pCurLink->numLeftLanes; + isOnOneWayRoad = pCurLink->numRightLanes == 0; + } + else { + lanesOnCurrentPath = pCurLink->numRightLanes; + isOnOneWayRoad = pCurLink->numLeftLanes == 0; + } uint8 allowedDirections = PATH_DIRECTION_NONE; uint8 nextLane = pVehicle->AutoPilot.m_nNextLane; if (nextLane == 0) @@ -1546,6 +1785,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) CCarPathLink* pNextLink; CPathNode* pNextPathNode; bool goingAgainstOneWayRoad; + bool nextNodeIsOneWayRoad; uint8 direction; for(attempt = 0; attempt < ATTEMPTS_TO_FIND_NEXT_NODE; attempt++){ if (attempt != 0){ @@ -1555,7 +1795,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) if ((!pNextPathNode->bDeadEnd || pPrevPathNode->bDeadEnd) && (!pNextPathNode->bDisabled || pPrevPathNode->bDisabled) && (!pNextPathNode->bBetweenLevels || pPrevPathNode->bBetweenLevels || !pVehicle->AutoPilot.m_bStayInCurrentLevel) && - !goingAgainstOneWayRoad) + !goingAgainstOneWayRoad && (!isOnOneWayRoad || !nextNodeIsOneWayRoad)) break; } } @@ -1565,9 +1805,10 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) direction = FindPathDirection(prevNode, curNode, pVehicle->AutoPilot.m_nNextRouteNode); pNextLink = &ThePaths.m_carPathLinks[ThePaths.m_carPathConnections[nextLink + pCurPathNode->firstLink]]; goingAgainstOneWayRoad = pNextLink->pathNodeIndex == curNode ? pNextLink->numRightLanes == 0 : pNextLink->numLeftLanes == 0; + nextNodeIsOneWayRoad = pNextLink->pathNodeIndex == curNode ? pNextLink->numLeftLanes == 0 : pNextLink->numRightLanes == 0; } if (attempt >= ATTEMPTS_TO_FIND_NEXT_NODE) { - /* If we failed 15 times, then remove dead end and current lane limitations */ + /* If we failed 15 times, then remove dead end, one way road and current lane limitations */ for (attempt = 0; attempt < ATTEMPTS_TO_FIND_NEXT_NODE; attempt++) { if (attempt != 0) { if (pVehicle->AutoPilot.m_nNextRouteNode != prevNode) { @@ -1648,6 +1889,7 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) } if (pVehicle->AutoPilot.m_bStayInFastLane) pVehicle->AutoPilot.m_nNextLane = 0; +#ifdef FIX_BUGS CVector positionOnCurrentLinkIncludingLane( pCurLink->GetX() + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardY, pCurLink->GetY() - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX, @@ -1656,6 +1898,16 @@ void CCarCtrl::PickNextNodeRandomly(CVehicle* pVehicle) pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, 0.0f); +#else + CVector positionOnCurrentLinkIncludingLane( + pCurLink->GetX() + ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH), + pCurLink->GetY() - ((pVehicle->AutoPilot.m_nCurrentLane + pCurLink->OneWayLaneOffset()) * LANE_WIDTH) * currentPathLinkForwardX, + 0.0f); + CVector positionOnNextLinkIncludingLane( + pNextLink->GetX() + ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardY, + pNextLink->GetY() - ((pVehicle->AutoPilot.m_nNextLane + pNextLink->OneWayLaneOffset()) * LANE_WIDTH) * nextPathLinkForwardX, + 0.0f); +#endif float directionCurrentLinkX = pCurLink->GetDirX() * pVehicle->AutoPilot.m_nCurrentDirection; float directionCurrentLinkY = pCurLink->GetDirY() * pVehicle->AutoPilot.m_nCurrentDirection; float directionNextLinkX = pNextLink->GetDirX() * pVehicle->AutoPilot.m_nNextDirection; @@ -1713,41 +1965,13 @@ void CCarCtrl::PickNextNodeToChaseCar(CVehicle* pVehicle, float targetX, float t CPathNode* pTargetNode; int16 numNodes; float distanceToTargetNode; - if (pTarget && pTarget->m_pCurGroundEntity && - pTarget->m_pCurGroundEntity->IsBuilding() && - ((CBuilding*)pTarget->m_pCurGroundEntity)->GetIsATreadable() && - ((CTreadable*)pTarget->m_pCurGroundEntity)->m_nodeIndices[0][0] >= 0){ - CTreadable* pCurrentMapObject = (CTreadable*)pTarget->m_pCurGroundEntity; - int closestNode = -1; - float minDist = 100000.0f; - for (int i = 0; i < 12; i++){ - int node = pCurrentMapObject->m_nodeIndices[0][i]; - if (node < 0) - break; - float dist = (ThePaths.m_pathNodes[node].GetPosition() - pTarget->GetPosition()).Magnitude(); - if (dist < minDist){ - minDist = dist; - closestNode = node; - } - } - ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, + ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, #ifdef FIX_PATHFIND_BUG - CVector(targetX, targetY, targetZ), + CVector(targetX, targetY, targetZ), #else - CVector(targetX, targetY, 0.0f), + CVector(targetX, targetY, 0.0f), #endif - &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, closestNode); - }else - { - - ThePaths.DoPathSearch(0, pCurNode->GetPosition(), curNode, -#ifdef FIX_PATHFIND_BUG - CVector(targetX, targetY, targetZ), -#else - CVector(targetX, targetY, 0.0f), -#endif - &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, -1); - } + &pTargetNode, &numNodes, 1, pVehicle, &distanceToTargetNode, 999999.9f, -1); int newNextNode; int nextLink; @@ -1951,9 +2175,11 @@ void CCarCtrl::Init(void) 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; + for (int j = 0; j < MAX_CAR_MODELS_IN_ARRAY; j++) { + LoadedCarsArray[i][j] = -1; + } + NumOfLoadedCarsOfRating[i] = 0; + NumRequestsOfCarRating[i] = 0; TotalNumOfCarsOfRating[i] = 0; } } @@ -1977,7 +2203,7 @@ void CCarCtrl::ReInit(void) 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; + NumRequestsOfCarRating[i] = 0; } void CCarCtrl::DragCarToPoint(CVehicle* pVehicle, CVector* pPoint) @@ -2813,7 +3039,21 @@ bool CCarCtrl::ThisRoadObjectCouldMove(int16 mi) bool CCarCtrl::MapCouldMoveInThisArea(float x, float y) { +#ifdef GTA_BRIDGE // actually they forgot that in VC... // bridge moves up and down return x > -342.0f && x < -219.0f && y > -677.0f && y < -580.0f; +#else + return false; +#endif +} + +float CCarCtrl::FindSpeedMultiplierWithSpeedFromNodes(int8 type) +{ + switch (type) + { + case 1: return 1.5f; + case 2: return 2.0f; + } + return 1.0f; } |