From 090aef7de7672c2649570eeff5cc5b68a371e723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eray=20or=C3=A7unus?= Date: Tue, 18 Feb 2020 02:56:13 +0300 Subject: CPopulation 2 --- src/control/Gangs.h | 5 +- src/core/Zones.h | 5 +- src/peds/PedPlacement.cpp | 8 ++ src/peds/PedPlacement.h | 1 + src/peds/Population.cpp | 348 +++++++++++++++++++++++++++++++++++++++++++++- src/peds/Population.h | 11 +- 6 files changed, 367 insertions(+), 11 deletions(-) diff --git a/src/control/Gangs.h b/src/control/Gangs.h index dd24ddcb..93ebe663 100644 --- a/src/control/Gangs.h +++ b/src/control/Gangs.h @@ -34,12 +34,15 @@ class CGangs public: static void Initialize(void); static void SetGangVehicleModel(int16, int32); - static int32 GetGangVehicleModel(int16 gang) { return Gang[gang].m_nVehicleMI; } static void SetGangWeapons(int16, eWeaponType, eWeaponType); static void SetGangPedModelOverride(int16, int8); static int8 GetGangPedModelOverride(int16); static void SaveAllGangData(uint8 *, uint32 *); static void LoadAllGangData(uint8 *, uint32); + + static int32 GetGangVehicleModel(int16 gang) { return Gang[gang].m_nVehicleMI; } + static eWeaponType GetGangWeapon1(int16 gang) { return Gang[gang].m_Weapon1; } + static eWeaponType GetGangWeapon2(int16 gang) { return Gang[gang].m_Weapon2; } static CGangInfo* GetGangInfo(int16 gang) { return &Gang[gang]; } private: diff --git a/src/core/Zones.h b/src/core/Zones.h index bf3957de..76855e8b 100644 --- a/src/core/Zones.h +++ b/src/core/Zones.h @@ -1,6 +1,7 @@ #pragma once #include "Game.h" +#include "Gangs.h" enum eZoneType { @@ -38,12 +39,12 @@ public: int16 carDensity; int16 carThreshold[6]; int16 copThreshold; - int16 gangThreshold[9]; + int16 gangThreshold[NUM_GANGS]; // Ped data uint16 pedDensity; uint16 copDensity; - uint16 gangDensity[9]; + uint16 gangDensity[NUM_GANGS]; uint16 pedGroup; }; diff --git a/src/peds/PedPlacement.cpp b/src/peds/PedPlacement.cpp index 8a40e56f..42cabbc2 100644 --- a/src/peds/PedPlacement.cpp +++ b/src/peds/PedPlacement.cpp @@ -41,6 +41,14 @@ CPedPlacement::IsPositionClearOfCars(CVector* pos) return CWorld::TestSphereAgainstWorld(*pos, 0.25f, nil, true, true, false, false, false, false); } +bool +CPedPlacement::IsPositionClearForPed(CVector* pos) +{ + int16 count; + CWorld::FindObjectsKindaColliding(*pos, 0.75f, true, &count, 2, nil, false, true, true, false, false); + return count == 0; +} + STARTPATCHES InjectHook(0x4EE340, &CPedPlacement::FindZCoorForPed, PATCH_JUMP); InjectHook(0x4EE310, &CPedPlacement::IsPositionClearOfCars, PATCH_JUMP); diff --git a/src/peds/PedPlacement.h b/src/peds/PedPlacement.h index 1edb50b4..cbdf8013 100644 --- a/src/peds/PedPlacement.h +++ b/src/peds/PedPlacement.h @@ -7,4 +7,5 @@ class CPedPlacement { public: static void FindZCoorForPed(CVector* pos); static CEntity* IsPositionClearOfCars(CVector*); + static bool IsPositionClearForPed(CVector*); }; \ No newline at end of file diff --git a/src/peds/Population.cpp b/src/peds/Population.cpp index e9fbbde1..a168198b 100644 --- a/src/peds/Population.cpp +++ b/src/peds/Population.cpp @@ -8,7 +8,19 @@ #include "Gangs.h" #include "ModelIndices.h" #include "Zones.h" -#include "Ped.h" +#include "CivilianPed.h" +#include "EmergencyPed.h" +#include "Replay.h" +#include "CutsceneMgr.h" +#include "CarCtrl.h" +#include "IniFile.h" +#include "VisibilityPlugins.h" +#include "PedPlacement.h" + +#define CREATION_DIST_MULT_TO_DIST 40.0f +#define CREATION_RANGE 10.0f // Being added over the CREATION_DIST_MULT_TO_DIST. +#define OFFSCREEN_CREATION_MULT 0.5f +// Also there are some hardcoded values in GeneratePedsAtStartOfGame. // TO-DO: These are hard-coded, reverse them. // More clearly they're transition areas between zones. @@ -25,7 +37,7 @@ uint32& CPopulation::ms_nNumCivFemale = *(uint32*)0x8F5F44; uint32& CPopulation::ms_nNumCop = *(uint32*)0x885AFC; bool& CPopulation::bZoneChangeHasHappened = *(bool*)0x95CD79; uint32& CPopulation::ms_nNumEmergency = *(uint32*)0x94071C; -uint32& CPopulation::m_CountDownToPedsAtStart = *(uint32*)0x95CD4F; +int8& CPopulation::m_CountDownToPedsAtStart = *(int8*)0x95CD4F; uint32& CPopulation::ms_nNumGang1 = *(uint32*)0x8F1B1C; uint32& CPopulation::ms_nNumGang2 = *(uint32*)0x8F1B14; uint32& CPopulation::ms_nTotalPeds = *(uint32*)0x95CB50; @@ -43,9 +55,9 @@ CVector &CPopulation::RegenerationPoint_a = *(CVector*)0x8E2AA4; CVector &CPopulation::RegenerationPoint_b = *(CVector*)0x8E2A98; CVector &CPopulation::RegenerationForward = *(CVector*)0x8F1AD4; -WRAPPER void CPopulation::Update(void) { EAXJMP(0x4F39A0); } WRAPPER CPed *CPopulation::AddPedInCar(CVehicle *vehicle) { EAXJMP(0x4F5800); } -WRAPPER bool CPopulation::IsPointInSafeZone(CVector *coors) { EAXJMP(0x4F60C0); } +WRAPPER void CPopulation::ManagePopulation(void) { EAXJMP(0x4F3B90); } +WRAPPER void CPopulation::MoveCarsAndPedsOutOfAbandonedZones(void) { EAXJMP(0x4F5BE0); } void CPopulation::Initialise() @@ -97,11 +109,11 @@ CPopulation::ChooseCivilianOccupation(int32 group) return ms_pPedGroups[group].models[CGeneral::GetRandomNumberInRange(0, NUMMODELSPERPEDGROUP)]; } -int32 +eCopType CPopulation::ChoosePolicePedOccupation() { CGeneral::GetRandomNumber(); - return 0; + return COP_STREET; } void @@ -385,9 +397,333 @@ CPopulation::FindClosestZoneForCoors(CVector *coors, int *safeZoneOut, eLevelNam *safeZoneOut = closestSafeZone; } +void +CPopulation::Update() +{ + if (!CReplay::IsPlayingBack()) { + ManagePopulation(); + MoveCarsAndPedsOutOfAbandonedZones(); + if (m_CountDownToPedsAtStart != 0) { + if (--m_CountDownToPedsAtStart == 0) + GeneratePedsAtStartOfGame(); + } else { + ms_nTotalCivPeds = ms_nNumCivFemale + ms_nNumCivMale; + ms_nTotalGangPeds = ms_nNumGang9 + ms_nNumGang8 + ms_nNumGang7 + + ms_nNumGang6 + ms_nNumGang5 + ms_nNumGang4 + ms_nNumGang3 + + ms_nNumGang2 + ms_nNumGang1; + ms_nTotalPeds = ms_nNumDummy + ms_nNumEmergency + ms_nNumCop + + ms_nTotalGangPeds + ms_nNumCivFemale + ms_nNumCivMale; + if (!CCutsceneMgr::IsRunning()) { + float pcdm = PedCreationDistMultiplier(); + AddToPopulation(pcdm * (CREATION_DIST_MULT_TO_DIST * TheCamera.GenerationDistMultiplier), + pcdm * ((CREATION_DIST_MULT_TO_DIST + CREATION_RANGE) * TheCamera.GenerationDistMultiplier), + pcdm * (CREATION_DIST_MULT_TO_DIST + CREATION_RANGE) * OFFSCREEN_CREATION_MULT - CREATION_RANGE, + pcdm * (CREATION_DIST_MULT_TO_DIST + CREATION_RANGE) * OFFSCREEN_CREATION_MULT); + } + } + } +} + +void +CPopulation::GeneratePedsAtStartOfGame() +{ + for (int i = 0; i < 50; i++) { + ms_nTotalCivPeds = ms_nNumCivFemale + ms_nNumCivMale; + ms_nTotalGangPeds = ms_nNumGang9 + ms_nNumGang8 + ms_nNumGang7 + + ms_nNumGang6 + ms_nNumGang5 + ms_nNumGang4 + + ms_nNumGang3 + ms_nNumGang2 + ms_nNumGang1; + ms_nTotalPeds = ms_nNumDummy + ms_nNumEmergency + ms_nNumCop + + ms_nTotalGangPeds + ms_nNumCivFemale + ms_nNumCivMale; + + // Min dist is 10.0f only for start of the game (naturally) + AddToPopulation(10.0f, PedCreationDistMultiplier() * (CREATION_DIST_MULT_TO_DIST + CREATION_RANGE), + 10.0f, PedCreationDistMultiplier() * (CREATION_DIST_MULT_TO_DIST + CREATION_RANGE)); + } +} + +bool +CPopulation::IsPointInSafeZone(CVector *coors) +{ + for (int i = 0; i < ARRAY_SIZE(aSafeZones); i++) { + if (coors->x > aSafeZones[i].x1 && coors->x < aSafeZones[i].x2) { + if (coors->y > aSafeZones[i].y1 && coors->y < aSafeZones[i].y2) { + if (coors->z > aSafeZones[i].z1 && coors->z < aSafeZones[i].z2) + return true; + } + } + } + return false; +} + +// More speed = wider area to spawn peds +float +CPopulation::PedCreationDistMultiplier() +{ + CVehicle *veh = FindPlayerVehicle(); + if (!veh) + return 1.0f; + + float vehSpeed = veh->m_vecMoveSpeed.Magnitude2D(); + return clamp(vehSpeed - 0.1f + 1.0f, 1.0f, 1.5f); +} + +CPed* +CPopulation::AddPed(ePedType pedType, uint32 mi, CVector const &coors) +{ + switch (pedType) { + case PEDTYPE_CIVMALE: + case PEDTYPE_CIVFEMALE: + { + CCivilianPed *ped = new CCivilianPed(pedType, mi); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + if (ms_bGivePedsWeapons) { + eWeaponType weapon = (eWeaponType)CGeneral::GetRandomNumberInRange(WEAPONTYPE_UNARMED, WEAPONTYPE_DETONATOR); + if (weapon != WEAPONTYPE_UNARMED) { + ped->SetCurrentWeapon(ped->GiveWeapon(weapon, 25001)); + } + } + return ped; + } + case PEDTYPE_COP: + { + CCopPed *ped = new CCopPed((eCopType)mi); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + return ped; + } + case PEDTYPE_GANG1: + case PEDTYPE_GANG2: + case PEDTYPE_GANG3: + case PEDTYPE_GANG4: + case PEDTYPE_GANG5: + case PEDTYPE_GANG6: + case PEDTYPE_GANG7: + case PEDTYPE_GANG8: + case PEDTYPE_GANG9: + { + CCivilianPed *ped = new CCivilianPed(pedType, mi); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + + uint32 weapon; + if (CGeneral::GetRandomNumberInRange(0, 100) >= 50) + weapon = ped->GiveWeapon(CGangs::GetGangWeapon2(pedType - PEDTYPE_GANG1), 25001); + else + weapon = ped->GiveWeapon(CGangs::GetGangWeapon1(pedType - PEDTYPE_GANG1), 25001); + ped->SetCurrentWeapon(weapon); + return ped; + } + case PEDTYPE_EMERGENCY: + { + CEmergencyPed *ped = new CEmergencyPed(PEDTYPE_EMERGENCY); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + return ped; + } + case PEDTYPE_FIREMAN: + { + CEmergencyPed *ped = new CEmergencyPed(PEDTYPE_FIREMAN); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + return ped; + } + case PEDTYPE_CRIMINAL: + case PEDTYPE_PROSTITUTE: + { + CCivilianPed *ped = new CCivilianPed(pedType, mi); + ped->GetPosition() = coors; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CWorld::Add(ped); + return ped; + } + default: + Error("Unknown ped type, AddPed, Population.cpp"); + return nil; + } +} + +void +CPopulation::AddToPopulation(float minDist, float maxDist, float minDistOffScreen, float maxDistOffScreen) +{ + uint32 pedTypeToAdd; + int32 modelToAdd; + int pedAmount; + + CZoneInfo zoneInfo; + CPed *gangLeader = nil; + bool addCop = false; + CPlayerInfo *playerInfo = &CWorld::Players[CWorld::PlayerInFocus]; + CVector playerCentreOfWorld = FindPlayerCentreOfWorld(CWorld::PlayerInFocus); + CTheZones::GetZoneInfoForTimeOfDay(&playerCentreOfWorld, &zoneInfo); + CWanted *wantedInfo = playerInfo->m_pPed->m_pWanted; + if (wantedInfo->m_nWantedLevel > 2) { + if (ms_nNumCop < wantedInfo->m_MaxCops && !playerInfo->m_pPed->bInVehicle + && (CCarCtrl::NumLawEnforcerCars >= wantedInfo->m_MaximumLawEnforcerVehicles + || CCarCtrl::NumRandomCars >= playerInfo->m_nTrafficMultiplier * CCarCtrl::CarDensityMultiplier + || CCarCtrl::NumFiretrucksOnDuty + CCarCtrl::NumAmbulancesOnDuty + CCarCtrl::NumParkedCars + + CCarCtrl::NumMissionCars + CCarCtrl::NumLawEnforcerCars + CCarCtrl::NumRandomCars >= CCarCtrl::MaxNumberOfCarsInUse)) { + addCop = true; + minDist = PedCreationDistMultiplier() * CREATION_DIST_MULT_TO_DIST; + maxDist = PedCreationDistMultiplier() * (CREATION_DIST_MULT_TO_DIST + CREATION_RANGE); + } + } + // Yeah, float + float maxPossiblePedsForArea = (zoneInfo.pedDensity + zoneInfo.carDensity) * playerInfo->m_fRoadDensity * PedDensityMultiplier * CIniFile::PedNumberMultiplier; + maxPossiblePedsForArea = min(maxPossiblePedsForArea, MaxNumberOfPedsInUse); + + if (ms_nTotalPeds < maxPossiblePedsForArea || addCop) { + int decisionThreshold = CGeneral::GetRandomNumberInRange(0, 1000); + if (decisionThreshold < zoneInfo.copDensity || addCop) { + pedTypeToAdd = PEDTYPE_COP; + modelToAdd = ChoosePolicePedOccupation(); + } else { + int16 density = zoneInfo.copDensity; + for (int i = 0; i < NUM_GANGS; i++) { + density += zoneInfo.gangDensity[i]; + if (decisionThreshold < density) { + pedTypeToAdd = PEDTYPE_GANG1 + i; + break; + } + + if (i == NUM_GANGS - 1) { + modelToAdd = ChooseCivilianOccupation(zoneInfo.pedGroup); + if (modelToAdd == -1) + return; + pedTypeToAdd = ((CPedModelInfo*)CModelInfo::GetModelInfo(modelToAdd))->m_pedType; + } + + } + } + if (!addCop && m_AllRandomPedsThisType > PEDTYPE_PLAYER1) + pedTypeToAdd = m_AllRandomPedsThisType; + + if (pedTypeToAdd >= PEDTYPE_GANG1 && pedTypeToAdd <= PEDTYPE_GANG9) { + int randVal = CGeneral::GetRandomNumber() % 100; + if (randVal < 50) + return; + + if (randVal < 57) { + pedAmount = 1; + } else if (randVal >= 74) { + if (randVal >= 85) + pedAmount = 4; + else + pedAmount = 3; + } else { + pedAmount = 2; + } + } else + pedAmount = 1; + + CVector generatedCoors; + int node1, node2; + float randomPos; + bool foundCoors = !!ThePaths.GeneratePedCreationCoors(playerCentreOfWorld.x, playerCentreOfWorld.y, minDist, maxDist, minDistOffScreen, maxDistOffScreen, + &generatedCoors, &node1, &node2, &randomPos, nil); + + if (!foundCoors) + return; + + for (int i = 0; i < pedAmount; ++i) { + if (pedTypeToAdd >= PEDTYPE_GANG1 && pedTypeToAdd <= PEDTYPE_GANG9) + modelToAdd = ChooseGangOccupation(pedTypeToAdd - PEDTYPE_GANG1); + + if (pedTypeToAdd == PEDTYPE_COP) { + // Unused code, ChoosePolicePedOccupation returns COP_STREET. Spawning FBI/SWAT/Army done in somewhere else. + if (modelToAdd != COP_STREET) { + if (modelToAdd == COP_FBI) { + if (!CModelInfo::GetModelInfo(MI_FBI)->GetRwObject()) + return; + + } else if (modelToAdd == COP_SWAT) { + if (!CModelInfo::GetModelInfo(MI_SWAT)->GetRwObject()) + return; + + } else if (modelToAdd == COP_ARMY && !CModelInfo::GetModelInfo(MI_ARMY)->GetRwObject()) { + return; + } + } else if (!CModelInfo::GetModelInfo(MI_COP)->GetRwObject()) { + return; + } + } else if (!CModelInfo::GetModelInfo(modelToAdd)->GetRwObject()) { + return; + } + generatedCoors.z += 0.7f; + + // What? How can this not be met? + if (i < pedAmount) { + //rand() + if (gangLeader) { + // Align gang members in formation. (btw i can't be 0 in here) + float offsetMin = i * 0.75f; + float offsetMax = (i + 1.0f) * 0.75f - offsetMin; + float xOffset = CGeneral::GetRandomNumberInRange(offsetMin, offsetMin + offsetMax); + float yOffset = CGeneral::GetRandomNumberInRange(offsetMin, offsetMin + offsetMax); + if (CGeneral::GetRandomNumber() & 1) + xOffset = -xOffset; + if (CGeneral::GetRandomNumber() & 1) + yOffset = -yOffset; + generatedCoors.x = xOffset + gangLeader->GetPosition().x; + generatedCoors.y = yOffset + gangLeader->GetPosition().y; + } + } + if (!CPedPlacement::IsPositionClearForPed(&generatedCoors)) + break; + + // Why no love for last gang member?! + if (i + 1 < pedAmount) { + bool foundGround; + float groundZ = CWorld::FindGroundZFor3DCoord(generatedCoors.x, generatedCoors.y, 2.0f + generatedCoors.z, &foundGround) + 0.7f; + if (!foundGround) + return; + + generatedCoors.z = max(generatedCoors.z, groundZ); + } + bool farEnoughToAdd = true; + CMatrix mat(TheCamera.GetCameraMatrix()); + if (TheCamera.IsSphereVisible(generatedCoors, 2.0f, &mat)) { + if (PedCreationDistMultiplier() * CREATION_DIST_MULT_TO_DIST > (generatedCoors - playerCentreOfWorld).Magnitude2D()) + farEnoughToAdd = false; + } + if (!farEnoughToAdd) + break; + CPed *newPed = AddPed((ePedType)pedTypeToAdd, modelToAdd, generatedCoors); + newPed->SetWanderPath(CGeneral::GetRandomNumberInRange(0, 8)); + + if (i != 0) { + // Gang member + newPed->SetLeader(gangLeader); + newPed->m_nPedState = PED_UNKNOWN; + gangLeader->m_nPedState = PED_UNKNOWN; + newPed->m_fRotationCur = CGeneral::GetRadianAngleBetweenPoints( + gangLeader->GetPosition().x, gangLeader->GetPosition().y, + newPed->GetPosition().x, newPed->GetPosition().y); + newPed->m_fRotationDest = newPed->m_fRotationCur; + } else { + gangLeader = newPed; + } + CVisibilityPlugins::SetClumpAlpha(newPed->GetClump(), 0); + /* + // Pointless, this is already a for loop + if (i + 1 > pedAmount) + break; + if (pedAmount <= 1) + break; */ + } + } +} + STARTPATCHES InjectHook(0x4F3770, &CPopulation::Initialise, PATCH_JUMP); InjectHook(0x4F5780, &CPopulation::ChooseGangOccupation, PATCH_JUMP); InjectHook(0x4F6200, &CPopulation::DealWithZoneChange, PATCH_JUMP); InjectHook(0x4F6010, &CPopulation::FindCollisionZoneForCoors, PATCH_JUMP); + InjectHook(0x4F6410, &CPopulation::PedCreationDistMultiplier, PATCH_JUMP); + InjectHook(0x4F5280, &CPopulation::AddPed, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/peds/Population.h b/src/peds/Population.h index c8f6f985..d39fb209 100644 --- a/src/peds/Population.h +++ b/src/peds/Population.h @@ -2,6 +2,7 @@ #include "Game.h" #include "PedType.h" +#include "CopPed.h" class CPed; class CVehicle; @@ -42,7 +43,7 @@ public: static uint32 &ms_nNumCop; static bool &bZoneChangeHasHappened; static uint32 &ms_nNumEmergency; - static uint32& m_CountDownToPedsAtStart; + static int8& m_CountDownToPedsAtStart; static uint32& ms_nNumGang1; static uint32& ms_nNumGang2; static uint32& ms_nTotalPeds; @@ -69,8 +70,14 @@ public: static bool IsPointInSafeZone(CVector *coors); static void RemovePed(CPed *ent); static int32 ChooseCivilianOccupation(int32); - static int32 ChoosePolicePedOccupation(); + static eCopType ChoosePolicePedOccupation(); static int32 ChooseGangOccupation(int); static void FindCollisionZoneForCoors(CVector*, int*, eLevelName*); static void FindClosestZoneForCoors(CVector*, int*, eLevelName, eLevelName); + static void GeneratePedsAtStartOfGame(); + static float PedCreationDistMultiplier(); + static CPed *AddPed(ePedType pedType, uint32 mi, CVector const &coors); + static void AddToPopulation(float, float, float, float); + static void ManagePopulation(void); + static void MoveCarsAndPedsOutOfAbandonedZones(void); }; -- cgit v1.2.3