diff --git a/src/control/CarAI.cpp b/src/control/CarAI.cpp index 0330d80d..c233178f 100644 --- a/src/control/CarAI.cpp +++ b/src/control/CarAI.cpp @@ -13,6 +13,7 @@ #include "DMAudio.h" #include "Fire.h" #include "Pools.h" +#include "Population.h" #include "Timer.h" #include "TrafficLights.h" #include "Vehicle.h" @@ -560,18 +561,15 @@ void CCarAI::AddPoliceCarOccupants(CVehicle* pVehicle) case MI_PREDATOR: pVehicle->SetUpDriver(); return; -//TODO(MIAMI) uncomment this when we have MI_VICECHEE -/* case MI_VICECHEE: { - pVehicle->SetUpDriver()->bIsMiamiViceCop = true; - pVehicle->SetUpPassenger(0)->bIsMiamiViceCop = true; + pVehicle->SetUpDriver()->bMiamiViceCop = true; + pVehicle->SetupPassenger(0)->bMiamiViceCop = true; CPopulation::NumMiamiViceCops += 2; CCarCtrl::MiamiViceCycle = (CCarCtrl::MiamiViceCycle + 1) % 4; CCarCtrl::LastTimeMiamiViceGenerated = CTimer::GetTimeInMilliseconds(); return; } -*/ default: return; } diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 66e29b6c..8be39a86 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -20,6 +20,7 @@ #include "Ped.h" #include "PlayerInfo.h" #include "PlayerPed.h" +#include "Population.h" #include "Wanted.h" #include "Pools.h" #include "Renderer.h" @@ -69,6 +70,10 @@ #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 + int CCarCtrl::NumLawEnforcerCars; int CCarCtrl::NumAmbulancesOnDuty; int CCarCtrl::NumFiretrucksOnDuty; @@ -83,6 +88,8 @@ 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::CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; int32 CCarCtrl::NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES]; @@ -291,10 +298,19 @@ CCarCtrl::GenerateOneRandomCar() CStreaming::RequestModel(MI_PREDATOR, STREAMFLAGS_DEPENDENCY); return; } - else { - return; - // TODO: normal boats + } + 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; @@ -320,8 +336,8 @@ 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 if (CModelInfo::IsBikeModel(carModel)) + return; // TODO(MIAMI): spawn bikes else pVehicle = new CAutomobile(carModel, RANDOM_VEHICLE); pVehicle->AutoPilot.m_nPrevRouteNode = 0; @@ -344,15 +360,15 @@ 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. */ } - // TODO(MIAMI): check the flag + 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); @@ -445,6 +461,8 @@ CCarCtrl::GenerateOneRandomCar() /* 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 seems like design decisions in VC were made based on this 0.5f addition. Can't remove it anymore. */ pVehicle->AutoPilot.m_nTimeEnteredCurve = CTimer::GetTimeInMilliseconds() - (uint32)((0.5f + positionBetweenNodes) * pVehicle->AutoPilot.m_nTimeToSpendOnCurrentCurve); #else @@ -520,15 +538,21 @@ CCarCtrl::GenerateOneRandomCar() delete pVehicle; return; } - }else if((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? 1.5f : 1.0f) * 120.0f || - (vecTargetPos - pVehicle->GetPosition()).Magnitude2D() < TheCamera.GenerationDistMultiplier * 100.0f){ - delete pVehicle; - return; - }else if((TheCamera.GetPosition() - pVehicle->GetPosition()).Magnitude2D() < 82.5f * TheCamera.GenerationDistMultiplier || bTopDownCamera ){ - delete pVehicle; - return; + }else{ + if ((vecTargetPos - pVehicle->GetPosition()).Magnitude2D() > TheCamera.GenerationDistMultiplier * (pVehicle->bExtendedRange ? 1.5f : 1.0f) * 120.0f || + (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; + } } - // TODO(MIAMI): if MARQUIS then delete CVehicleModelInfo* pVehicleModel = pVehicle->GetModelInfo(); float radiusToTest = pVehicleModel->GetColModel()->boundingSphere.radius; if (testForCollision){ @@ -552,17 +576,93 @@ CCarCtrl::GenerateOneRandomCar() CWorld::Add(pVehicle); if (carClass == COPS || carClass == COPS_BOAT) CCarAI::AddPoliceCarOccupants(pVehicle); - else - pVehicle->SetUpDriver(); //TODO(MIAMI): FIX! - if ((CGeneral::GetRandomNumber() & 0x3F) == 0){ /* 1/64 probability */ /* TODO(MIAMI): FIX!*/ + 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; + } + } + } + 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(); - /* TODO(MIAMI): CADDY, VICECHEE, dead ped code*/ - return; + 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 @@ -680,6 +780,31 @@ CCarCtrl::ChooseCarModelToLoad(int 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)) diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h index ce25c206..f66b9232 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -124,7 +124,8 @@ public: 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 int32 ChooseCarModelToLoad(int32 rating); + static bool BoatWithTallMast(int32 mi); static float GetPositionAlongCurrentCurve(CVehicle* pVehicle) { @@ -158,6 +159,8 @@ public: static int32 TotalNumOfCarsOfRating[TOTAL_CUSTOM_CLASSES]; static int32 CarArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; + static int32 MiamiViceCycle; + static uint32 LastTimeMiamiViceGenerated; static int32 NumRequestsOfCarRating[TOTAL_CUSTOM_CLASSES]; static int32 NumOfLoadedCarsOfRating[TOTAL_CUSTOM_CLASSES]; static int32 CarFreqArrays[TOTAL_CUSTOM_CLASSES][MAX_CAR_MODELS_IN_ARRAY]; diff --git a/src/control/PathFind.cpp b/src/control/PathFind.cpp index 20c4aa69..4a948032 100644 --- a/src/control/PathFind.cpp +++ b/src/control/PathFind.cpp @@ -322,7 +322,7 @@ CPathFind::StoreNodeInfoPed(int16 id, int16 node, int8 type, int8 next, int16 x, InfoForTilePeds[i].roadBlock = false; InfoForTilePeds[i].disabled = false; InfoForTilePeds[i].waterPath = false; - InfoForTilePeds[i].flag02 = false; + InfoForTilePeds[i].onlySmallBoats = false; InfoForTilePeds[i].betweenLevels = false; InfoForTilePeds[i].spawnRate = Min(spawnRate, 15); @@ -351,7 +351,7 @@ CPathFind::StoreNodeInfoCar(int16 id, int16 node, int8 type, int8 next, int16 x, InfoForTilePeds[i].roadBlock = false; InfoForTilePeds[i].disabled = false; InfoForTilePeds[i].waterPath = false; - InfoForTilePeds[i].flag02 = false; + InfoForTilePeds[i].onlySmallBoats = false; InfoForTilePeds[i].betweenLevels = false; InfoForTilePeds[i].spawnRate = Min(spawnRate, 15); @@ -383,7 +383,7 @@ CPathFind::StoreDetachedNodeInfoPed(int32 node, int8 type, int32 next, float x, DetachedInfoForTilePeds[i].roadBlock = false; DetachedInfoForTilePeds[i].disabled = disabled; DetachedInfoForTilePeds[i].waterPath = false; - DetachedInfoForTilePeds[i].flag02 = false; + DetachedInfoForTilePeds[i].onlySmallBoats = false; DetachedInfoForTilePeds[i].betweenLevels = betweenLevels; DetachedInfoForTilePeds[i].spawnRate = Min(spawnRate, 15); @@ -396,7 +396,7 @@ CPathFind::StoreDetachedNodeInfoPed(int32 node, int8 type, int32 next, float x, //--MIAMI: done void CPathFind::StoreDetachedNodeInfoCar(int32 node, int8 type, int32 next, float x, float y, float z, float width, int8 numLeft, int8 numRight, - bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate, bool unk) + bool disabled, bool betweenLevels, uint8 speedLimit, bool roadBlock, bool waterPath, uint8 spawnRate, bool onlySmallBoats) { int i; @@ -417,7 +417,7 @@ CPathFind::StoreDetachedNodeInfoCar(int32 node, int8 type, int32 next, float x, DetachedInfoForTileCars[i].roadBlock = roadBlock; DetachedInfoForTileCars[i].disabled = disabled; DetachedInfoForTileCars[i].waterPath = waterPath; - DetachedInfoForTileCars[i].flag02 = unk; + DetachedInfoForTileCars[i].onlySmallBoats = onlySmallBoats; DetachedInfoForTileCars[i].betweenLevels = betweenLevels; DetachedInfoForTileCars[i].spawnRate = Min(spawnRate, 15); @@ -655,7 +655,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_pathNodes[m_numPathNodes].bUseInRoadBlock = objectpathinfo[start + j].roadBlock; m_pathNodes[m_numPathNodes].bDisabled = objectpathinfo[start + j].disabled; m_pathNodes[m_numPathNodes].bWaterPath = objectpathinfo[start + j].waterPath; - m_pathNodes[m_numPathNodes].flagB2 = objectpathinfo[start + j].flag02; + m_pathNodes[m_numPathNodes].bOnlySmallBoats = objectpathinfo[start + j].onlySmallBoats; m_pathNodes[m_numPathNodes].bBetweenLevels = objectpathinfo[start + j].betweenLevels; m_numPathNodes++; } @@ -696,7 +696,7 @@ CPathFind::PreparePathDataForType(uint8 type, CTempNode *tempnodes, CPathInfoFor m_pathNodes[m_numPathNodes].bUseInRoadBlock = detachednodes[start + j].roadBlock; m_pathNodes[m_numPathNodes].bDisabled = detachednodes[start + j].disabled; m_pathNodes[m_numPathNodes].bWaterPath = detachednodes[start + j].waterPath; - m_pathNodes[m_numPathNodes].flagB2 = detachednodes[start + j].flag02; + m_pathNodes[m_numPathNodes].bOnlySmallBoats = detachednodes[start + j].onlySmallBoats; m_pathNodes[m_numPathNodes].bBetweenLevels = detachednodes[start + j].betweenLevels; m_numPathNodes++; }else if(detachednodes[start + j].type == NodeTypeExtern){ diff --git a/src/control/PathFind.h b/src/control/PathFind.h index 51bdbd7f..5f5de3e1 100644 --- a/src/control/PathFind.h +++ b/src/control/PathFind.h @@ -69,7 +69,7 @@ struct CPathNode uint8 bUseInRoadBlock : 1; uint8 bWaterPath : 1; - uint8 flagB2 : 1; // flag 2 in node info, always zero + uint8 bOnlySmallBoats : 1; uint8 flagB4 : 1; // where is this set? uint8 speedLimit : 2; //uint8 flagB20 : 1; @@ -145,7 +145,7 @@ struct CPathInfoForObject int8 width; uint8 crossing : 1; - uint8 flag02 : 1; // always zero + uint8 onlySmallBoats : 1; uint8 roadBlock : 1; uint8 disabled : 1; uint8 waterPath : 1; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index dabb0571..b6729486 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -3089,7 +3089,7 @@ int8 CRunningScript::ProcessCommands300To399(int32 command) case COMMAND_SET_ZONE_CAR_INFO: { char label[12]; - int16 gangDensities[NUM_GANGS]; + int16 gangDensities[NUM_GANGS] = { 0 }; int i; CTheScripts::ReadTextLabelFromScript(&m_nIp, label); @@ -9849,8 +9849,8 @@ int8 CRunningScript::ProcessCommands1200To1299(int32 command) case COMMAND_SET_ZONE_CIVILIAN_CAR_INFO: { char label[12]; - int16 carDensities[CCarCtrl::NUM_CAR_CLASSES]; - int16 boatDensities[CCarCtrl::NUM_BOAT_CLASSES]; + int16 carDensities[CCarCtrl::NUM_CAR_CLASSES] = { 0 }; + int16 boatDensities[CCarCtrl::NUM_BOAT_CLASSES] = { 0 }; int i; CTheScripts::ReadTextLabelFromScript(&m_nIp, label); diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index b1a73607..eb7fc8f5 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -1396,6 +1396,15 @@ CStreaming::StreamVehiclesAndPeds(void) else SetModelIsDeletable(MI_CHOPPER); + if (FindPlayerPed()->m_pWanted->AreMiamiViceRequired()) { + //TODO(MIAMI): miami vice peds + RequestModel(MI_VICECHEE, STREAMFLAGS_DONT_REMOVE); + } + else { + SetModelIsDeletable(MI_VICECHEE); + //TODO(MIAMI): miami vice peds + } + if(timeBeforeNextLoad >= 0) timeBeforeNextLoad--; else if(ms_numVehiclesLoaded <= desiredNumVehiclesLoaded){ diff --git a/src/core/Wanted.cpp b/src/core/Wanted.cpp index 7508c9f4..ff82edad 100644 --- a/src/core/Wanted.cpp +++ b/src/core/Wanted.cpp @@ -39,6 +39,12 @@ CWanted::Initialise() ClearQdCrimes(); } +bool +CWanted::AreMiamiViceRequired() +{ + return m_nWantedLevel >= 3; +} + bool CWanted::AreSwatRequired() { diff --git a/src/core/Wanted.h b/src/core/Wanted.h index e3e407b0..0e0e70c3 100644 --- a/src/core/Wanted.h +++ b/src/core/Wanted.h @@ -31,6 +31,7 @@ public: public: void Initialise(); + bool AreMiamiViceRequired(); bool AreSwatRequired(); bool AreFbiRequired(); bool AreArmyRequired(); diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index 79353b1b..29466777 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -199,6 +199,13 @@ CModelInfo::IsBikeModel(int32 id) ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE; } +bool +CModelInfo::IsCarModel(int32 id) +{ + return GetModelInfo(id)->GetModelType() == MITYPE_VEHICLE && + ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_CAR; +} + void CModelInfo::ReInit2dEffects() { diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index 46f8c117..fd545e3d 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -39,5 +39,6 @@ public: static bool IsBoatModel(int32 id); static bool IsBikeModel(int32 id); + static bool IsCarModel(int32 id); static void ReInit2dEffects(); }; diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 0e740768..7a7316ae 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -402,6 +402,10 @@ CPed::~CPed(void) } if (m_pFire) m_pFire->Extinguish(); + if (bCarPassenger) + CPopulation::ms_nTotalCarPassengerPeds--; + if (bMiamiViceCop) + CPopulation::NumMiamiViceCops--; CPopulation::UpdatePedCount((ePedType)m_nPedType, true); DMAudio.DestroyEntity(m_audioEntityId); } @@ -605,6 +609,10 @@ CPed::CPed(uint32 pedType) : m_pedIK(this) bSomeVCflag1 = false; #endif + bCarPassenger = false; + bMiamiViceCop = false; + bDeadPedInFrontOfCar = false; + if ((CGeneral::GetRandomNumber() & 3) == 0) bHasACamera = true; diff --git a/src/peds/Ped.h b/src/peds/Ped.h index 9f105e7a..209aeb40 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -389,6 +389,10 @@ public: uint32 m_ped_flagI40 : 1; // bMakePedsRunToPhonesToReportCrimes makes use of this as runover by car indicator uint32 m_ped_flagI80 : 1; // KANGAROO_CHEAT define makes use of this as cheat toggle + uint32 bCarPassenger : 1; + uint32 bMiamiViceCop : 1; // + uint32 bDeadPedInFrontOfCar : 1; + uint8 CharCreatedBy; eObjective m_objective; eObjective m_prevObjective; @@ -452,6 +456,9 @@ public: CVehicle *m_pMyVehicle; bool bInVehicle; float m_distanceToCountSeekDone; + + CVehicle* m_vehicleInAccident; + bool bRunningToPhone; int16 m_phoneId; eCrimeType m_crimeToReportOnPhone; diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp index 2d4a92fa..6011ce44 100644 --- a/src/peds/PedPlacement.cpp +++ b/src/peds/PedPlacement.cpp @@ -43,9 +43,13 @@ CPedPlacement::IsPositionClearOfCars(Const CVector *pos) } bool -CPedPlacement::IsPositionClearForPed(CVector* pos) +CPedPlacement::IsPositionClearForPed(const CVector& pos, float radius, int total, CEntity** entities) { int16 count; - CWorld::FindObjectsKindaColliding(*pos, 0.75f, true, &count, 2, nil, false, true, true, false, false); + if (radius == -1.0f) + radius = 0.75f; + if (total == -1) + total = 2; + CWorld::FindObjectsKindaColliding(pos, radius, true, &count, total, entities, false, true, true, false, false); return count == 0; } diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h index b51e2aad..5b8354d4 100644 --- a/src/peds/PedPlacement.h +++ b/src/peds/PedPlacement.h @@ -4,5 +4,5 @@ class CPedPlacement { public: static void FindZCoorForPed(CVector* pos); static CEntity* IsPositionClearOfCars(Const CVector*); - static bool IsPositionClearForPed(CVector*); + static bool IsPositionClearForPed(const CVector& pos, float radius = -1.0f, int total = -1, CEntity** entities = nil); }; \ No newline at end of file diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index ba8e1a74..1d8c7f5d 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -83,6 +83,9 @@ CVector CPopulation::RegenerationPoint_a; CVector CPopulation::RegenerationPoint_b; CVector CPopulation::RegenerationForward; +uint32 CPopulation::ms_nTotalCarPassengerPeds; +uint32 CPopulation::NumMiamiViceCops; + void CPopulation::Initialise() { @@ -103,6 +106,8 @@ CPopulation::Initialise() ms_nNumGang9 = 0; ms_nNumDummy = 0; + ms_nTotalCarPassengerPeds = 0; + m_AllRandomPedsThisType = -1; PedDensityMultiplier = 1.0f; bZoneChangeHasHappened = false; @@ -398,6 +403,7 @@ CPopulation::Update() + ms_nNumGang2 + ms_nNumGang1; ms_nTotalPeds = ms_nNumDummy + ms_nNumEmergency + ms_nNumCop + ms_nTotalGangPeds + ms_nNumCivFemale + ms_nNumCivMale; + ms_nTotalPeds -= ms_nTotalCarPassengerPeds; if (!CCutsceneMgr::IsRunning()) { float pcdm = PedCreationDistMultiplier(); AddToPopulation(pcdm * (MIN_CREATION_DIST * TheCamera.GenerationDistMultiplier), @@ -419,6 +425,7 @@ CPopulation::GeneratePedsAtStartOfGame() + ms_nNumGang3 + ms_nNumGang2 + ms_nNumGang1; ms_nTotalPeds = ms_nNumDummy + ms_nNumEmergency + ms_nNumCop + ms_nTotalGangPeds + ms_nNumCivFemale + ms_nNumCivMale; + ms_nTotalPeds -= ms_nTotalCarPassengerPeds; // Min dist is 10.0f only for start of the game (naturally) AddToPopulation(10.0f, PedCreationDistMultiplier() * (MIN_CREATION_DIST + CREATION_RANGE), @@ -656,7 +663,7 @@ CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScree generatedCoors.y = yOffset + gangLeader->GetPosition().y; } } - if (!CPedPlacement::IsPositionClearForPed(&generatedCoors)) + if (!CPedPlacement::IsPositionClearForPed(generatedCoors)) break; // Why no love for last gang member?! @@ -733,6 +740,7 @@ CPopulation::AddPedInCar(CVehicle* car) break; case MI_POLICE: case MI_PREDATOR: + case MI_VICECHEE: // TODO(MIAMI): proper model preferredModel = COP_STREET; pedType = PEDTYPE_COP; break; @@ -1016,6 +1024,10 @@ CPopulation::ManagePopulation(void) } float dist = (ped->GetPosition() - playerPos).Magnitude2D(); + + if (ped->IsGangMember() || (ped->bDeadPedInFrontOfCar && ped->m_vehicleInAccident)) + dist -= 30.0f; + bool pedIsFarAway = false; if (PedCreationDistMultiplier() * (PED_REMOVE_DIST_SPECIAL * TheCamera.GenerationDistMultiplier) < dist || (!ped->bCullExtraFarAway && PedCreationDistMultiplier() * PED_REMOVE_DIST * TheCamera.GenerationDistMultiplier < dist) @@ -1062,3 +1074,49 @@ CPopulation::ManagePopulation(void) } } } + +CPed* +CPopulation::AddDeadPedInFrontOfCar(const CVector& pos, CVehicle* pCulprit) +{ + if (TheCamera.IsSphereVisible(pos, 2.0f)) { + float fDistanceToPlayer = (pos - FindPlayerPed()->GetPosition()).Magnitude2D(); + float fDistanceMultiplier; + if (FindPlayerVehicle()) + fDistanceMultiplier = clamp(FindPlayerVehicle()->GetMoveSpeed().Magnitude2D() - 0.1f + 1.0f, 1.0f, 1.5f); + else + fDistanceMultiplier = 1.0f; + if (40.0f * fDistanceMultiplier > fDistanceToPlayer) + return nil; + } + bool found; + float z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &found) + 1.0f; + if (!found) + return nil; + z = Max(z, pos.z); + if (!CModelInfo::GetModelInfo(MI_MALE01)->GetRwObject()) // strange way to check it + return nil; + CPed* pPed = CPopulation::AddPed(PEDTYPE_CIVMALE, MI_MALE01, pos); // TODO(MIAMI): 4th parameter + pPed->SetDie(ANIM_KO_SHOT_FRONT1, 4.0f, 0.0f); + //TODO(MIAMI): set money == 0 + pPed->bDeadPedInFrontOfCar = true; + pPed->m_vehicleInAccident = pCulprit; + pCulprit->RegisterReference((CEntity**)&pPed->m_vehicleInAccident); + CEntity* pEntities[3] = { 0 }; + if (!CPedPlacement::IsPositionClearForPed(pos, 2.0f, 3, pEntities)) { + for (int i = 0; i < 3; i++) { + if (pEntities[i] && pEntities[i] != pCulprit && pEntities[i] != pPed) { + CWorld::Remove(pPed); + delete pPed; + return nil; + } + } + } + CColPoint colpts[32]; + if (CCollision::ProcessColModels(pCulprit->GetMatrix(), *pCulprit->GetColModel(), pPed->GetMatrix(), *pPed->GetColModel(), colpts, nil, nil)) { + CWorld::Remove(pPed); + delete pPed; + return nil; + } + CVisibilityPlugins::SetClumpAlpha(pPed->GetClump(), 0); + return pPed; +} diff --git a/src/peds/Population.h b/src/peds/Population.h index aa8129c0..181c5809 100644 --- a/src/peds/Population.h +++ b/src/peds/Population.h @@ -62,6 +62,9 @@ public: static CVector RegenerationPoint_b; static CVector RegenerationForward; + static uint32 ms_nTotalCarPassengerPeds; + static uint32 NumMiamiViceCops; + static void Initialise(); static void Update(void); static void LoadPedGroups(); @@ -86,4 +89,6 @@ public: static void ConvertAllObjectsToDummyObjects(void); static bool TestRoomForDummyObject(CObject*); static bool TestSafeForRealObject(CDummyObject*); + + static CPed* AddDeadPedInFrontOfCar(const CVector& pos, CVehicle* pCulprit); }; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 5fdbde06..1cf41435 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -99,6 +99,7 @@ CVehicle::CVehicle(uint8 CreatedBy) m_bSirenOrAlarm = 0; m_nCarHornTimer = 0; m_nCarHornPattern = 0; + bCreatedAsPoliceVehicle = false; bParking = false; m_nAlarmState = 0; m_nDoorLock = CARLOCK_UNLOCKED; diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 66dfebb1..7711e445 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -182,6 +182,7 @@ public: uint8 bIsCarParkVehicle : 1; // Car has been created using the special CAR_PARK script command uint8 bHasAlreadyBeenRecorded : 1; // Used for replays + uint8 bCreatedAsPoliceVehicle : 1;// True if this guy was created as a police vehicle (enforcer, policecar, miamivice car etc) uint8 bParking : 1; int8 m_numPedsUseItAsCover;