Files
GTASource/game/Peds/Population.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

2488 lines
75 KiB
C++

// Title : Population.cpp
// Author : Gordon Speirs
// Started : 06/04/00
// Rage headers
#include "system/param.h"
// Game headers
#include "Population.h"
#include "Animation\animmanager.h"
#include "Camera\Camera.h"
#include "Control\Darkel.h"
#include "Control\gamelogic.h"
#include "Control\Pathfind.h"
#include "Control\replay.h"
#include "Control\roadblocks.h"
#include "Debug\Debug.h"
#include "Debug\DebugGlobals.h"
#include "Debug\timebars.h"
#include "Event\Events.h"
#include "Game\cheat.h"
#include "Game\Clock.h"
#include "Game\ModelIndices.h"
#include "Game\weather.h"
#include "Game\zones.h"
#include "Maths\Maths.h"
#include "Maths\random.h"
#include "Maths\vector.h"
#include "ModelInfo\ModelInfo.h"
#include "ModelInfo\ModelInfo.h"
#include "Objects\DummyObject.h"
#include "Objects\Object.h"
#include "PathServer\PathServer.h"
#include "PedGroup\PedGroup.h"
#include "Peds\gangs.h"
#include "peds\ped.h"
#include "Peds\PedDebugVisualiser.h"
#include "Peds\PedDecision.h"
#include "Peds\PedFactory.h"
#include "Peds\pedgen.h"
#include "Peds\PedIntelligence.h"
#include "Peds\pedplacement.h"
#include "Peds\PedType.h"
#include "Peds\PlayerPed.h"
#include "Peds\popcycle.h"
#include "Peds\pedvariationmgr.h"
#include "Physics\BoundsStore.h"
#include "Physics\GtaArchetype.h"
#include "Physics\WorldProbe.h"
#include "Renderer\Water.h"
#include "Renderer\zonecull.h"
#include "Scene\iplstore.h"
#include "scene\portals\interiorInst.h"
#include "Script\script.h"
#include "Streaming\populationstreaming.h"
#include "Streaming\streaming.h"
#include "System\FileMgr.h"
#include "System\Pad.h"
#include "Task\TaskBasic.h"
#include "Task\TaskCarUtils.h"
#include "Task\TaskGoto.h"
#include "Task\TaskKillController\TaskKillController.h"
#include "Task\TaskManager.h"
#include "Task\TaskPartner.h"
#include "Task\TaskSecondary.h"
#include "Task\TaskSeekEntity.h"
#include "fwutil\PtrList.h"
#include "Vehicles\Automobile.h"
#include "Vehicles\VehicleFactory.h"
#include "Vehicles\cargen.h"
#include "Vehicles\vehiclepopulation.h"
#include "control\persistence.h"
//network headers
#ifdef ONLINE_PLAY
#include "Network\network.h"
#endif
PARAM(nopeds, "[population] Dont create any random peds");
PARAM(doragdolls, "[physics] Do allow ragdolls to activate");
PARAM(allragdolls, "[physics] Force all peds to be allow ragdolls");
// grrr. This macro conflicts under visual studio.
#if defined (MSVC_COMPILER)
#ifdef max
#undef max
#endif //max
#endif //MSVC_COMPILER
#define FRAMESTOCOMPLETEMANAGEPOPULATION (32)
#define GANG_CREATION_DISTANCE_OFFSET (30.0f)
#define CIVILIAN_COUPLE_POPULATION (0.9f)
#define SUNBATHER_TOWEL_SPACING (3.0f)
//#define ADD_TO_POP_DEBUG
s32 CPopulation::ms_nNumCivMale;
s32 CPopulation::ms_nNumCivFemale;
s32 CPopulation::ms_nNumCop;
s32 CPopulation::ms_nNumEmergency;
s32 CPopulation::ms_nTotalCarPassengerPeds;
s32 CPopulation::ms_nTotalCivPeds;
s32 CPopulation::ms_nTotalPeds;
s32 CPopulation::ms_nTotalMissionPeds;
u32 CPopulation::m_CountDownToPedsAtStart;
bool CPopulation::m_bDontCreateRandomCops = false;
Vector3 CPopulation::RegenerationPoint_a;
Vector3 CPopulation::RegenerationPoint_b;
Vector3 CPopulation::RegenerationFront;
bool CPopulation::bZoneChangeHasHappened;
float CPopulation::PedDensityMultiplier = 1.0f;
s32 CPopulation::m_AllRandomPedsThisType = -1;
s32 CPopulation::MaxNumberOfPedsInUse = STANDARD_MAX_NUMBER_OF_PEDS_IN_USE; // This can be changed by the inifile values
bool CPopulation::bInPoliceStation = false;
s32 CPopulation::m_nNoPedSpawnTimer = 0;
#if __DEV
s32 CPopulation::OverrideNumberOfPeds = -1;
bool CPopulation::m_bCreatePedsAnywhere = false;
#endif
// Name : Init
// Purpose : Init CPopulation stuff
// Parameters : None
// Returns : Nothing
void CPopulation::Init()
{
#if __BANK
// Set up some bank stuff.
bkBank &bank = BANKMGR.CreateBank("Population and Zones");
bank.AddToggle("Print ped population debug", &CPopCycle::m_bDisplayDebugInfo);
bank.AddToggle("Print car population debug", &CPopCycle::m_bDisplayCarDebugInfo);
bank.AddSlider("Override Number of Cars", &CVehiclePopulation::OverrideNumberOfCars, -1, 1000, 1);
bank.AddSlider("Override Number of Parked Cars", &CVehiclePopulation::OverrideNumberOfParkedCars, -1, 1000, 1);
bank.AddSlider("Override Number of Peds", &CPopulation::OverrideNumberOfPeds, -1, 1000, 1);
bank.AddSlider("Max number of cars in use", &CVehiclePopulation::MaxNumberOfCarsInUse, 0, 200, 1);
bank.AddToggle("Render Zones", &CCullZones::bRenderCullzones, NullCB);
bank.AddSlider("Num Cam Zones", &CCullZones::m_numCamZones, 0, 9000000, 0);
bank.AddToggle("Render Car Generators", &CTheCarGenerators::gs_bDisplayCarGenerators, NullCB);
bank.AddToggle("Create Peds Anywhere", &CPopulation::m_bCreatePedsAnywhere);
bank.AddToggle("Generate test ambulance", &gbGenerateAmbulance);
bank.AddToggle("Generate test firetruck", &gbGenerateFiretruck);
#endif
}
// Name : Initialise
// Purpose : Init CPopulation stuff
// Parameters : None
// Returns : Nothing
void CPopulation::InitSession()
{
DEBUGLOG("Initialising CPopulation...\n");
#if __DEV
if(PARAM_nopeds.Get())
gbNoPedsGeneration = true;
if(PARAM_doragdolls.Get())
gbDoRagdolls = true;
if(PARAM_allragdolls.Get())
gbForceRagdolls = true;
#endif
ms_nNumCivMale = 0;
ms_nNumCivFemale = 0;
ms_nNumCop = 0;
ms_nNumEmergency = 0;
ms_nTotalCarPassengerPeds = 0;
ms_nTotalCivPeds = 0;
ms_nTotalPeds = 0;
ms_nTotalMissionPeds = 0;
m_CountDownToPedsAtStart = 5; // Give game time to settle down
bZoneChangeHasHappened = false;
PedDensityMultiplier = 1.0f;
m_AllRandomPedsThisType = -1;
MaxNumberOfPedsInUse = STANDARD_MAX_NUMBER_OF_PEDS_IN_USE; // This can be changed by the inifile values
bInPoliceStation = false;
m_bDontCreateRandomCops = false;
// Set up a default ped for the game to use if there aren't any appropriate peds available
gPopStreaming.SetDefaultPedMI(CModelInfo::GetModelIndex("m_y_streetblk_02"));
ASSERT(gPopStreaming.GetDefaultPedMI() >= 0);
CStreaming::RequestObject(gPopStreaming.GetDefaultPedMI(), CModelInfo::GetStreamingModuleId(), STRFLAG_FORCE_LOAD|STRFLAG_DONTDELETE);
CStreaming::LoadAllRequestedObjects();
DEBUGLOG("CPopulation ready\n");
} // end - CPopulation::Initialise
// Name : Update
// Purpose : Updates CPopulation stuff
// Parameters : None
// Returns : Nothing
void CPopulation::Update(bool bAddPeds)
{
if (CReplay::ReplayGoingOn()) return;
CPersistenceMgr::RevivePersistentPedsAndVehicles();
ManagePopulation();
RemovePedsIfThePoolGetsFull();
// Give game a couple of frames to get everything initialised. Then we generate peds around player.
if (m_CountDownToPedsAtStart)
{
m_CountDownToPedsAtStart--;
if (!m_CountDownToPedsAtStart)
{
GeneratePedsAtStartOfGame();
}
}
else
{ // Don't do this until the game has settled down (or peds get created at 0.0f, 0.0f, 0.0f)
ms_nTotalCivPeds = ms_nNumCivMale + ms_nNumCivFemale;
ms_nTotalPeds = ms_nTotalCivPeds + /*ms_nTotalGangPeds +*/ ms_nNumCop + ms_nNumEmergency;
if ( /* rage !CCutsceneMgr::IsCutsceneProcessing() &&*/ bAddPeds)
{
bool bMorePedsNeeded = AddToPopulation
(POPULATION_ADD_MIN_RADIUS * CRenderer::GetGenerationDistanceScale(),
POPULATION_ADD_MAX_RADIUS * CRenderer::GetGenerationDistanceScale(),
POPULATION_CULL_RANGE_OFF_SCREEN - 10.0f,
POPULATION_CULL_RANGE_OFF_SCREEN);
if (bMorePedsNeeded)
{
GeneratePedsAtAttractors(FindPlayerCentreOfWorld(),
POPULATION_ADD_MIN_RADIUS * CRenderer::GetGenerationDistanceScale(),
POPULATION_ADD_MAX_RADIUS * CRenderer::GetGenerationDistanceScale(),
POPULATION_CULL_RANGE_OFF_SCREEN - 10.0f,
POPULATION_CULL_RANGE_OFF_SCREEN,
-1,
1);
}
}
}
DEBUG_POPULATION
(
CDebug::DebugString("Civilian", 0, 3, 0xffffffff);
CDebug::DebugInt(ms_nTotalCivPeds, 20, 3, 2);
CDebug::DebugString("Cop", 0, 4, 0xffffffff);
CDebug::DebugInt(ms_nNumCop, 20, 4, 2);
CDebug::DebugString("Emergency", 0, 5, 0xffffffff);
CDebug::DebugInt(ms_nNumEmergency, 20, 5, 2);
CDebug::DebugString("Gang", 0, 6, 0xffffffff);
CDebug::DebugInt(ms_nTotalGangPeds, 20, 6, 2);
CDebug::DebugString("Total", 0, 9, 0xffffffff);
CDebug::DebugInt(ms_nTotalPeds, 20, 9, 2);
CDebug::DebugString("Mission Peds", 0, 10, 0xffffffff);
CDebug::DebugInt(ms_nTotalMissionPeds, 20, 10, 2);
)
if (m_nNoPedSpawnTimer > 0)
m_nNoPedSpawnTimer -= CTimer::GetMilliseconds();
} // end - CPopulation::Update
// Name : GeneratePedsAtStartOfGame
// Purpose : When a new game is started the streets seem a bit empty.
// This function should be called to fill the area around the player.
// Parameters : None
// Returns : Nothing
void CPopulation::GeneratePedsAtStartOfGame()
{
s32 Tries;
for (Tries = 0; Tries < 100; Tries++)
{
ms_nTotalCivPeds = ms_nNumCivMale + ms_nNumCivFemale;
ms_nTotalPeds = ms_nTotalCivPeds + ms_nNumCop + ms_nNumEmergency;
ms_nTotalPeds -= ms_nTotalCarPassengerPeds;
AddToPopulation(10.0f, POPULATION_ADD_MAX_RADIUS, 10.0f, POPULATION_ADD_MAX_RADIUS);
}
GeneratePedsAtAttractors(FindPlayerCentreOfWorld(), 10.0f, POPULATION_ADD_MAX_RADIUS, 10.0f, POPULATION_ADD_MAX_RADIUS, -1, 1);
}
//
// name: ManagePed
// description: Code to manage a ped
void CPopulation::ManagePed(CPed* pPed, const Vector3& vecCentre)
{
#ifdef ONLINE_PLAY
// don't manage peds controlled remotely by another machine
if (pPed->IsNetworkClone())
return;
#endif
if (!pPed->IsPlayer())
{
//Delete ped if he can be deleted and he isn't in a vehicle and he isn't attached to a vehicle.
if (pPed->CanBeDeleted() && !pPed->m_PedAiFlags.bInVehicle && (0==pPed->m_pAttachToEntity || pPed->m_pAttachToEntity->GetType()!=ENTITY_TYPE_VEHICLE))
{
s32 timeSinceDead = CTimer::GetElapsedTimeInMilliseconds() - pPed->m_nTimeOfDeath;
if(pPed->GetPedState() == PED_DEAD &&
(timeSinceDead > PED_REMOVED_AFTER_DEATH ||
(CDarkel::FrenzyOnGoing() && timeSinceDead > PED_REMOVED_AFTER_DEATH_INRAMPAGE) /* rage||
(timeSinceDead > PED_REMOVED_AFTER_DEATH_GANGWARS && CGangWars::GangWarFightingGoingOn())*/ ))
{
pPed->m_PedAiFlags.bFadeOut = true;
}
// Test whether ped should be removed because of time-out or something
if (pPed->m_PedAiFlags.bFadeOut /* rage&& CVisibilityPlugins::GetClumpAlpha((RpClump*)pPed->GetRwObject()) == 0*/)
{
RemovePed(pPed);
}
else
{
float DiffX = pPed->GetPosition().x - vecCentre.x;
float DiffY = pPed->GetPosition().y - vecCentre.y;
float Dist = rage::Sqrtf(DiffX*DiffX + DiffY*DiffY);
bool bRemovePed = false;
float fDist=Dist;
fDist *= pPed->fRemoveRangeMultiplier;
if((pPed->GetPedType()>=PEDTYPE_GANG1)&&(pPed->GetPedType()<=PEDTYPE_GANG10))
{
fDist-=GANG_CREATION_DISTANCE_OFFSET;
}
/*rage
else if((pPed->m_nPedFlags.bDeadPedInFrontOfCar) &&(pPed->m_pMyAccidentVehicle))
{
//If a ped has been made as a dead ped in front of a car and the car is still alive
//then don't delete the ped just because it is too far from the camera. Wait until
//the car has been deleted and the ped is too far from the camera.
fDist=0;
}
*/
if ( fDist > POPULATION_CULL_RANGE_FAR_AWAY * CRenderer::GetGenerationDistanceScale() )
{
bRemovePed = true;
}
else if ( (!pPed->m_PedAiFlags.bCullExtraFarAway) &&
fDist > POPULATION_CULL_RANGE * CRenderer::GetGenerationDistanceScale())
{
bRemovePed = true;
}
else if (fDist > POPULATION_CULL_RANGE_OFF_SCREEN)
{
bool bPedIsOnScreen = pPed->GetIsOnScreen();
if ( (CTimer::GetElapsedTimeInMilliseconds() > pPed->DontUseSmallerRemovalRange && (!bPedIsOnScreen))
&&gCamInterface.IsModeActive(CCamTypes::CAM_TYPE_PHOTO)
&& (!gCamInterface.IsLookingLeft()) && (!gCamInterface.IsLookingRight()) && (!gCamInterface.IsLookingBehind()))
{
bRemovePed = true;
}
if (bPedIsOnScreen)
{ // Ped is on-screen and not too far away. Don't remove for a wee while.
if (pPed->GetPedType() == PEDTYPE_COP)
{
pPed->DontUseSmallerRemovalRange = CTimer::GetElapsedTimeInMilliseconds() + 12000;
}
else
{
pPed->DontUseSmallerRemovalRange = CTimer::GetElapsedTimeInMilliseconds() + 6000;
}
}
}
else
{ // Guy is nearby. Don't remove for a wee while
if (pPed->GetPedType() == PEDTYPE_COP)
{
pPed->DontUseSmallerRemovalRange = CTimer::GetElapsedTimeInMilliseconds() + 12000;
}
else
{
pPed->DontUseSmallerRemovalRange = CTimer::GetElapsedTimeInMilliseconds() + 6000;
}
}
#ifdef ONLINE_PLAY
if (bRemovePed && pPed->GetNetworkObject())
{
bRemovePed = ((CNetObjPed*)pPed->GetNetworkObject())->TryToPassControlOutOfScope();
}
#endif
if (bRemovePed)
{
if(pPed->GetIsOnScreen())
pPed->m_PedAiFlags.bFadeOut = true;
else
RemovePed(pPed);
}
}
}
}
}
// Name : ManagePopulation
// Purpose : Scans through peds. Makes any dummy peds that are close enough
// into active peds, and makes any active peds that are far enough
// away into dummy peds.
// Parameters : None
// Returns : Nothing
void CPopulation::ManagePopulation(void)
{
Vector3 vecCentre;
Vector3 vecTargetObject, vecResetDist;
Vector3 vecTargetPed;
CPed::Pool *pPedPool = CPed::GetPool();
// CDummyObject::Pool *pDummyPool = CDummyObject::GetPool();
// CObject::Pool *pObjPool = CObject::GetPool();
CPed *pPed;
// CDummyObject *pDummy;
// CObject *pObj;
s32 CurrSlot;
s32 Batch;
// s32 PoolSize;
Batch = (CTimer::GetFrameCount() & (FRAMESTOCOMPLETEMANAGEPOPULATION - 1));
vecCentre = FindPlayerCentreOfWorld(); // Might need to change this for multiplayer
// so that an equal number of peds are created
// around each player
// Put this stuff back in when Dummies and Objects are working
/*
PoolSize = pObjPool->GetSize();
for (CurrSlot = ((Batch * PoolSize) / FRAMESTOCOMPLETEMANAGEPOPULATION); CurrSlot < (((Batch + 1) * PoolSize) / FRAMESTOCOMPLETEMANAGEPOPULATION); CurrSlot++)
{
pObj = pObjPool->GetSlot(CurrSlot);
if (pObj && pObj->GetModelIndex()>=0)
{
ManageObject(pObj, vecCentre);
}
}
// Scan through all dummy peds and convert to real peds or delete as appropriate
PoolSize = pDummyPool->GetSize();
for (CurrSlot = ((Batch * PoolSize) / FRAMESTOCOMPLETEMANAGEPOPULATION); CurrSlot < (((Batch + 1) * PoolSize) / FRAMESTOCOMPLETEMANAGEPOPULATION); CurrSlot++)
{
pDummy = pDummyPool->GetSlot(CurrSlot);
// If dummy exists,
if(pDummy)
{
ManageDummy(pDummy, vecCentre);
}
}
*/
CurrSlot = pPedPool->GetSize();
while (CurrSlot--)
{
pPed = pPedPool->GetSlot(CurrSlot);
if(pPed)
{
ManagePed(pPed, vecCentre);
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : FindNumberOfPedsWeCanPlaceOnBenches
// PURPOSE : Used to work out how many peds we have spare to create on benches and
// wait in queues, use teller machines etc.
/////////////////////////////////////////////////////////////////////////////////
s32 CPopulation::FindNumberOfPedsWeCanPlaceOnBenches()
{
s32 ReturnVal = 0;
s32 MaxNumCivilians = (s32)rage::Min((float)CPopulation::MaxNumberOfPedsInUse, CPopCycle::m_NumOther_Peds);
MaxNumCivilians = (s32)(MaxNumCivilians * CPopulation::PedDensityMultiplier * CPopulation::FindPedDensityMultiplierCullZone());
ReturnVal = MaxNumCivilians - (CPopulation::ms_nNumCivMale + CPopulation::ms_nNumCivFemale);
ReturnVal += 2; // This extra one is an attempt to favour peds on benches because they look cool. Without this fudge we wouldn't get them as much.
// if (ReturnVal > 0)
// { // Find the MI of the extra ped we would create.
// *pMI = CPopulation::ChooseCivilianOccupation(false, false, -1, -1, -1, true);
// if (*pMI < 0) return 0; // Could find a Model that was actually loaded in. Never mind then.
// }
return ReturnVal;
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : FindPedDensityMultiplierCullZone
// PURPOSE : Finds the number the ped population is reduced by here.
/////////////////////////////////////////////////////////////////////////////////
float CPopulation::FindPedDensityMultiplierCullZone()
{
if (CCullZones::FewerPeds()) return 0.6f;
return 1.0f;
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : RemovePedsIfThePoolGetsFull
// PURPOSE : If the ped pool fills up this function will remove some peds.
/////////////////////////////////////////////////////////////////////////////////
void CPopulation::RemovePedsIfThePoolGetsFull(void)
{
if ((CTimer::GetFrameCount() & 7) == 5)
{
CPed::Pool *pool = CPed::GetPool();
if (pool->GetNoOfFreeSpaces() < 8)
{ // Need to remove at least one ped
s32 i=pool->GetSize();
CPed *pPed;
float NearestDist = 9999999.9f, Dist;
CPed *pNearestPed = NULL;
while(i--)
{
pPed = pool->GetSlot(i);
if(pPed)
{
if ( pPed->CanBeDeleted() )
{
Dist = (*gCamInterface.GetPos() - pPed->GetPosition()).Mag();
if (Dist < NearestDist)
{
NearestDist = Dist;
pNearestPed = pPed;
}
}
}
}
if (pNearestPed)
{
RemovePed(pNearestPed);
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// FUNCTION : RemoveAllRandomPeds
// PURPOSE : Removes all the peds we can. Used for entering interior
/////////////////////////////////////////////////////////////////////////////////
void CPopulation::RemoveAllRandomPeds()
{
CPed::Pool *pool = CPed::GetPool();
s32 i=pool->GetSize();
CPed *pPed;
while(i--)
{
pPed = pool->GetSlot(i);
if(pPed)
{
if ( pPed->CanBeDeleted() && !pPed->IsPlayer())
{
RemovePed(pPed);
}
}
}
}
// Name : AddToPopulation
// Purpose : Adds a ped of the specified type to the current population
// Parameters : PedType - type of ped to add
// fMinRad, fMaxRad - min and max radii, ped will be added somewhere
// within these two boundaries (***try to keep at least 10 metres between
// the two otherwise it may not work very well***)
// Returns : Nothing
bool CPopulation::AddToPopulation(float fMinRad, float fMaxRad, float fMinRadClose, float fMaxRadClose)
{
ePedType NewPedType;
s32 NewPedOccupation;
s32 NewPedMaleOccupation=-1;
s32 NewPedFemaleOccupation=-1;
Vector3 PlayerPos;
Vector3 vecResult;
bool bResult;
bool bMoreCopsNeeded = false;
CNodeAddress FromNode, ToNode;
float RandomFraction, GroundZ;
s32 NumPedsInGroup, PedInGroup;
float MaxNumPeds;
CPed *pFirstPed = NULL, *pThisPed;
bool FoundGround;
u8 MaxCopsInPursuit;
CPlayerInfo *pPlayer = CWorld::GetMainPlayerInfo();
bool bMorePedsNeeded = false;
if (m_nNoPedSpawnTimer > 0)
return false;
#if __DEV
if(gbNoPedsGeneration)
return false;
#endif
PlayerPos = FindPlayerCentreOfWorld();
Vector3 vecPedSpawnOrigin, vecPedSpawnLookahead;
// check against actual number of cops on map rather than just those that are in pursuit or we might create far too many
MaxCopsInPursuit = pPlayer->pPed->GetPlayerWanted()->m_nMaxCopsInPursuit;
if(ms_nNumCop < MaxCopsInPursuit)
{
if( !pPlayer->pPed->m_PedAiFlags.bInVehicle &&
( CVehiclePopulation::NumLawEnforcerCars >= pPlayer->pPed->GetPlayerWanted()->m_nMaxCopCarsInPursuit
|| CVehiclePopulation::NumRandomCars >= pPlayer->CarDensityForCurrentZone*CVehiclePopulation::CarDensityMultiplier
|| CVehiclePopulation::NumRandomCars+CVehiclePopulation::NumLawEnforcerCars+CVehiclePopulation::NumMissionCars+CVehiclePopulation::NumParkedCars+CVehiclePopulation::NumAmbulancesOnDuty+CVehiclePopulation::NumFireTrucksOnDuty >= CVehiclePopulation::MaxNumberOfCarsInUse) )
{
bMoreCopsNeeded = true;
fMinRad = POPULATION_ADD_MIN_RADIUS;
fMaxRad = POPULATION_ADD_MAX_RADIUS;
}
}
MaxNumPeds = (float)CPopulation::MaxNumberOfPedsInUse;
float Mult = 1.0f; // rage CIniFile::PedNumberMultiplier;
if (CDarkel::FrenzyOnGoing()) Mult = 1.0f;
MaxNumPeds = MIN(MaxNumPeds, CPopCycle::m_NumCops_Peds + CPopCycle::m_NumOther_Peds );
MaxNumPeds *= PedDensityMultiplier;
#if __DEV
if (OverrideNumberOfPeds >= 0)
{
MaxNumPeds = (float)OverrideNumberOfPeds;
}
#endif
// MaxNumPeds *= CPopulation::PedDensityMultiplier * CPopulation::FindPedDensityMultiplierCullZone();
if (ms_nTotalPeds < MaxNumPeds)
{
bMorePedsNeeded = true; // Pass this back so that we can create a ped at an attractor as well.
}
if ((ms_nTotalPeds < MaxNumPeds) || bMoreCopsNeeded)
{
#ifdef ADD_TO_POP_DEBUG
static int iNoOfTries=0;
static int iNoOfSuccesses1=0;
static int iNoOfSuccesses2=0;
static int iNoOfSuccesses3=0;
static int iNoOfSuccesses4=0;
iNoOfTries++;
if(iNoOfTries==1000)
{
iNoOfTries=1;
iNoOfSuccesses1=0;
iNoOfSuccesses2=0;
iNoOfSuccesses3=0;
iNoOfSuccesses4=0;
}
const float fSuccessFrac1=(float)iNoOfSuccesses1/(float)iNoOfTries;
const float fSuccessFrac2=(float)iNoOfSuccesses2/(float)iNoOfTries;
const float fSuccessFrac3=(float)iNoOfSuccesses3/(float)iNoOfTries;
const float fSuccessFrac4=(float)iNoOfSuccesses4/(float)iNoOfTries;
char s[255];
sprintf(s,"Fracs are %f %f %f %f N is %d \n",fSuccessFrac1,fSuccessFrac2,fSuccessFrac3,fSuccessFrac4,ms_nTotalPeds);
DEBUGLOG(s);
#endif
// Generate a random number and use this in conjunction with the ped ratios
// to decide which type of ped to create
// Once the ped type has been decided, maybe need special functions
// to decide on the ped occupation
if (bMoreCopsNeeded)
{ // Create a police ped
// Obbe put the next lines back in ones we have cop models.
NewPedType = PEDTYPE_COP;
NewPedOccupation = gPopStreaming.FindPoliceOfficerMI();
if( NewPedOccupation == -1 )
{
return bMorePedsNeeded;
}
}
else
{
if (CPopCycle::FindNewPedType(&NewPedType, &NewPedOccupation, false)) // && FindPlayerWanted()->GetWantedLevel() <= WANTED_LEVEL2)) This wanted level thing doesn't workk because Christians script grabs all peds and gives them an indoor decision maker. Cops just stand there with their hands in the air.
{
if (NewPedType == PEDTYPE_CIVMALE || NewPedType == PEDTYPE_CIVFEMALE)
{
if (fwRandom::GetRandomNumberInRange(0.0f,1.0f)>CIVILIAN_COUPLE_POPULATION)
{
ChooseCivilianCoupleOccupations(NewPedMaleOccupation, NewPedFemaleOccupation);
if((-1==NewPedMaleOccupation)||(-1==NewPedFemaleOccupation))
{
return bMorePedsNeeded;
}
NewPedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedMaleOccupation))->GetDefaultPedType();
}
}
if (m_AllRandomPedsThisType > 0)
{
NewPedType = (ePedType)m_AllRandomPedsThisType;
}
}
else
{
return bMorePedsNeeded;
}
}
// If we are talking about a gang member we work out a random number that decides the
// number of peds in this group. Note we have a chance of 0 as well to keep the total
// expected peds to be created at 1 so that the ratio stuff is still valid.
if (NewPedType >= PEDTYPE_GANG1 && NewPedType <= PEDTYPE_GANG10)
{
NumPedsInGroup=CPedGroupPlacer::ComputeRandomisedGangSize();
}
else
{
NumPedsInGroup = 1;
}
//Gang peds need to be created a greater distance from the player/camera because they
//get made in clusters of large numbers of peds. This makes it much more obvious that
//they are being created.
float fMinR=fMinRad;
float fMaxR=fMaxRad;
float fMinRClose=fMinRadClose;
float fMaxRClose=fMaxRadClose;
if (NewPedType >= PEDTYPE_GANG1 && NewPedType <= PEDTYPE_GANG10)
{
fMinR+=GANG_CREATION_DISTANCE_OFFSET;
fMaxR+=GANG_CREATION_DISTANCE_OFFSET;
fMinRClose+=0.0f;
fMaxRClose+=0.0f;
}
//***********************************************************************
//
// Ped density is now a value from 0..3 inclusive.
// All surface types have a ped density associated with them.
//
// 0 = no peds ever created here (eg. roads)
// ...
// 3 = most preferred ped creation places (eg. pavements)
//
// Areas such as grass & fields might have a ped density of 1 or 2.
//
// We should avoid only looking for generation coords with a ped
// density of 3, because then peds will only ever be created if there
// is an area of pavement nearby. (unless that's the desired behaviour!)
//
//***********************************************************************
s32 iRequiredPedDensity = fwRandom::GetRandomNumberInRange(1, 4);
Assert(iRequiredPedDensity >= 1 && iRequiredPedDensity < 4);
#if __DEV
// Allow us to toggle peds being created anywhere on map (for when artists have not used surface types which make peds)
if(m_bCreatePedsAnywhere)
iRequiredPedDensity = 0;
#endif
bResult = CPathServer::GetPedGenerationCoords(
PlayerPos,
fMinR, fMaxR, fMinRClose, fMaxRClose,
iRequiredPedDensity,
&vecResult
);
if (bResult)
{
// s32 Density = MIN(ThePaths.FindNodePointer(FromNode)->Density, ThePaths.FindNodePointer(ToNode)->Density);
// if ((fwRandom::GetRandomNumber() & 15) <= Density)
{
#ifdef ADD_TO_POP_DEBUG
iNoOfSuccesses1++;
#endif
// Randomize the coordinates a bit
// ThePaths.TakeWidthIntoAccountForCoors(FromNode, ToNode, fwRandom::GetRandomNumber(), &vecResult.x, &vecResult.y);
if (NewPedType >= PEDTYPE_GANG1 && NewPedType <= PEDTYPE_GANG10)
{
PlaceGangMembers(NewPedType,NumPedsInGroup,vecResult);
}
else if((NewPedMaleOccupation>=0)&&(NewPedFemaleOccupation>=0))
{
PlaceCouple(PEDTYPE_CIVMALE,NewPedMaleOccupation,PEDTYPE_CIVFEMALE,NewPedFemaleOccupation,vecResult);
}
else
{
for (PedInGroup = 0; PedInGroup < NumPedsInGroup; PedInGroup++)
{
// don't bother making ped if model hasn't loaded
if (NewPedType == PEDTYPE_COP)
{
// can assume cop is in memory
/*
//NEEDS_MOVED_TO_NY_LAYER
if (NewPedOccupation == COPTYPE_FBI)
{
if(!CStreaming::HasObjectLoaded(MODELID_FBI_PED, CModelInfo::GetStreamingModuleId()) ||
!CStreaming::HasObjectLoaded(CWeaponInfo::GetWeaponInfo(WEAPONTYPE_MP5)->GetModelId(), CModelInfo::GetStreamingModuleId()))
return bMorePedsNeeded;
}
else if (NewPedOccupation == COPTYPE_SWAT)
{
if(!CStreaming::HasObjectLoaded(MODELID_SWAT_PED, CModelInfo::GetStreamingModuleId()) ||
!CStreaming::HasObjectLoaded(CWeaponInfo::GetWeaponInfo(WEAPONTYPE_MICRO_UZI)->GetModelId(), CModelInfo::GetStreamingModuleId()))
return bMorePedsNeeded;
}
else if (NewPedOccupation == COPTYPE_ARMY)
{
if(!CStreaming::HasObjectLoaded(MODELID_ARMY_PED, CModelInfo::GetStreamingModuleId()) ||
!CStreaming::HasObjectLoaded(CWeaponInfo::GetWeaponInfo(WEAPONTYPE_MP5)->GetModelId(), CModelInfo::GetStreamingModuleId()) ||
!CStreaming::HasObjectLoaded(CWeaponInfo::GetWeaponInfo(WEAPONTYPE_GRENADE)->GetModelId(), CModelInfo::GetStreamingModuleId()))
return bMorePedsNeeded;
}
else if(NewPedType != PEDTYPE_COP)
{
Assertf(0, "CPopulation::AddToPopulation - Unknown cop type");
}
//NEEDS_MOVED_TO_NY_LAYER
*/
}
// ~dodgy~ temp hack till collision model problem gets resolved (dropping
// peds into the world at the specified coord results in them getting stuck
// in the map and dying)
vecResult.z += 0.7f;
// If there are more peds to follow we will randomise the coordinates a bit
if (PedInGroup < NumPedsInGroup)
{
RandomFraction = (fwRandom::GetRandomNumber() & 255) / 256.0f;
if(pFirstPed)
{
float fx = fwRandom::GetRandomNumberInRange(((float)PedInGroup)*0.75f,(((float)PedInGroup)+1.0f)*0.75f);
float fy = fwRandom::GetRandomNumberInRange(((float)PedInGroup)*0.75f,(((float)PedInGroup)+1.0f)*0.75f);
if(fwRandom::GetRandomNumber() & 1)
{
fx = -fx;
}
if(fwRandom::GetRandomNumber() & 1)
{
fy = -fy;
}
vecResult.x = pFirstPed->GetPosition().x + fx;
vecResult.y = pFirstPed->GetPosition().y + fy;
}
}
bResult = CPedPlacement::IsPositionClearForPed(vecResult);
if (bResult)
{
#ifdef ADD_TO_POP_DEBUG
iNoOfSuccesses2++;
#endif
// If there are more peds to follow we will randomise the coordinates a bit
if (PedInGroup+1 < NumPedsInGroup)
{
// add a bit to stop the peds getting created halfway into the ground
GroundZ = 0.7f + CWorldProbe::FindGroundZFor3DCoord(vecResult.x, vecResult.y, vecResult.z + 2.0f, &FoundGround);
if (!FoundGround)
{
// sprintf(gString2, "No ground below ped creation coors: %f %f %f\n", vecResult.x, vecResult.y, vecResult.z);
// printf("%s", gString2);
return bMorePedsNeeded;
}
vecResult.z = MAX(vecResult.z, GroundZ);
}
bool bGoAhead = true;
if ( (gCamInterface.IsSphereVisible(vecResult, 2.0f)) && ( ((Vector3)(vecResult - PlayerPos)).XYMag() < POPULATION_ADD_MIN_RADIUS))
{
bGoAhead = false;
}
//Don't allow skaters on the beach.
if(bGoAhead && PEDSTAT_SKATER==((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->GetDefaultPedStats())
{
bGoAhead=IsSkateable(vecResult);
}
// Do a bit of a special case check. We don't want enemy gang members in the grove.
if (bGoAhead && NewPedType >= PEDTYPE_GANG1 && NewPedType <= PEDTYPE_GANG10 && NewPedType != PEDTYPE_GANG2)
{
if (vecResult.x > 2400.0f && vecResult.x < 2540.0f && vecResult.y > -1730.0f && vecResult.y < -1625.0f)
{
bGoAhead = false;
}
}
#ifdef ONLINE_PLAY
if (CNetwork::IsGameInProgress() && bGoAhead)
{
// don't add peds if they are going to appear in front of other network players
//bGoAhead = !CNetwork::GetObjectManager().IsInScopeWithAnyRemotePlayer(CNetworkObject::NETOBJTYPE_PED, vecResult);
bGoAhead = !CNetwork::GetObjectManager().IsVisibleToAnyRemotePlayer(vecResult, CModelInfo::GetModelInfo(NewPedOccupation)->GetBoundingSphereRadius());
}
#endif
// Do a final check to make sure the guy is not visible AND closeby
if (bGoAhead)
{
#ifdef ADD_TO_POP_DEBUG
iNoOfSuccesses3++;
#endif
pThisPed = AddPed(NewPedType, NewPedOccupation, vecResult, true);
// Randomise this ped with attributes and different cothes and shit
CPedVariationMgr::SetVarRandom(pThisPed);
CPedPropsMgr::SetPedPropsRandomly(pThisPed, 0.4f, 0.25f);
/* rage_materials
if(IsSunbather(NewPedOccupation) && fwRandom::GetRandomNumber()&3)
{
// Test for surfaces to sunbathe on
CGtaIntersection colPoint;
phInst* pColInst=0;
CWorldProbe::ProcessVerticalLine(vecResult+Vector3(0,0,2),vecResult.z-2,0,colPoint,pColInst,phArchetypeGta::GTA_ALL_MAP_TYPES,NULL);
if(pColInst)
{
if(g_surfaceInfos.IsBeach(colPoint.GetSurfaceTypeB()) ||
colPoint.GetSurfaceTypeB() == SURFACE_TYPE_CONCRETE_BEACH ||
colPoint.GetSurfaceTypeB() == SURFACE_TYPE_PARKGRASS ||
CCheat::IsCheatActive(CCheat::BEACHPARTY_CHEAT))
{
if(CTaskComplexSunbathe::CanSunbathe() || CCheat::IsCheatActive(CCheat::BEACHPARTY_CHEAT))
{
bIsSunbather=true;
// Search for any other ped in a range of 1 metres to avoid towel overlaps.
CEntity* hitPeds[2]={0,0};
int NumHitPeds=2;
if(CPedPlacement::IsPositionClearForPed(vecResult,SUNBATHER_TOWEL_SPACING,NumHitPeds,hitPeds))
{
bool bHit=false;
int k;
for(k=0;k<NumHitPeds;k++)
{
if((hitPeds[k])&&(hitPeds[k]!=pThisPed))
{
bIsSunbather=false;
}
}
}
if (colPoint.GetSurfaceTypeB() != SURFACE_TYPE_PARKGRASS)
bCreateBeachToys = true;
}
}
}
}*/
/*
if(bIsSunbather)
{
Vector3 pos(pThisPed->GetPosition());
CGtaIntersection TestColPoint;
phInst *TestInst;
// check slope is not too steep
if (CWorldProbe::ProcessVerticalLine(pos+Vector3(0.0f,0.0f,10.0f), -10.0f, 0, TestColPoint, TestInst, phArchetypeGta::GTA_ALL_MAP_TYPES))
{
if (DotProduct(TestColPoint.GetNormal(), Vector3(0.0f, 0.0f, 1.0f)) > 0.95f)
{
const float fHeading=TWO_PI*fwRandom::GetRandomNumberInRange(0.0f,1.0f);
pThisPed->m_fDesiredHeading=fHeading;
pThisPed->m_fCurrentHeading=fHeading;
pThisPed->SetHeading(fHeading);
//
// "Towels on beach" stuff starts here:
//
//
// make sure we have all needed models loaded:
//
CObject *pTowel = NULL;
if (bCreateBeachToys)
{
pos.z = TestColPoint.GetPosition().z+0.04f;
pTowel = CWater::CreateBeachToy(pos, BEACHTOY_BEACHTOWEL_ANY);
if(pTowel)
{
float heading = fHeading;
pTowel->SetHeading(heading);
// place towel on ground properly
pTowel->GetMatrix().c = TestColPoint.GetNormal();
pTowel->GetMatrix().a = CrossProduct(pTowel->GetMatrix().c, pTowel->GetMatrix().b);
pTowel->GetMatrix().b = CrossProduct(pTowel->GetMatrix().c, pTowel->GetMatrix().a);
// rage pTowel->UpdateRwMatrix();
// pTowel->UpdateRwFrame();
if((fwRandom::GetRandomNumber()&0x03)==0)
{
Vector3 toyPos = pos;
toyPos += pTowel->GetMatrix().a * fwRandom::GetRandomNumberInRange(-0.5f, 0.5f);
toyPos += pTowel->GetMatrix().b * fwRandom::GetRandomNumberInRange(-1.0f, 1.0f);
CWater::CreateBeachToy(toyPos, BEACHTOY_LOTION);
}
}
}
if(fwRandom::GetRandomNumber()&3)
{
// ped already lying down
pThisPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexSunbathe(pTowel, false));
}
else
{
// ped standing up about to lie down
pThisPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexSunbathe(pTowel, true));
}
}
}
}
else
*/
{
// pThisPed->GetPedIntelligence()->AddTaskDefault(CTaskComplexWander::GetWanderTaskByPedType(*pThisPed)); Obbe:This has already been done. Doing it again is slow because the wander nodes are calculated again.
CTheScripts::ScriptsForBrains.CheckIfNewEntityNeedsScript(pThisPed, CScriptsForBrains::PED_STREAMED); // , NULL);
}
if (PedInGroup) // Tell our rage_new ped he has a leader
{
//pThisPed->SetLeader(pFirstPed);
//pThisPed->SetPedState(PED_HANG_OUT);
//pFirstPed->SetPedState(PED_HANG_OUT);
}
else
{
pFirstPed = pThisPed;
}
#ifdef ADD_TO_POP_DEBUG
iNoOfSuccesses4++;
#endif
// set ped to invisible, so that they can be faded in
// rage CVisibilityPlugins::SetClumpAlpha((RpClump*)pThisPed->GetRwObject(), 0);
if (PedInGroup+1 > NumPedsInGroup || NumPedsInGroup <= 1)
return bMorePedsNeeded;
}
else
{
return bMorePedsNeeded;
}
}
else
{
return bMorePedsNeeded;
}
}
}
}
}
}
return bMorePedsNeeded;
}
// Name : AddPed
// Purpose : Adds a ped to the world
// Parameters : PedType - type of ped to add
// PedOcc - which model to display for the ped
// vecPosition - position to add the ped
// Returns : Nothing
CPed* CPopulation::AddPed(ePedType PedType, u32 PedOcc, const Vector3& vecPosition, bool bGiveDefaultTask)
{
CPed *pPed;
s32 RandomInt;
eWeaponType weaponType;
Matrix34 tempMat;
tempMat.Identity();
tempMat.d = vecPosition;
// use pedfactory to create the ped:
pPed = CPedFactory::GetFactory()->Create(PedType, PedOcc, &tempMat);
ASSERT(pPed);
// SetWanderPath() is called outside this function now. Not all peds need to find a path to
// wander down eg peds in cars
switch(PedType)
{
case PEDTYPE_CIVMALE:
case PEDTYPE_CIVFEMALE:
// pPed = new CCivilianPed(PedType, PedOcc);
// ASSERT(pPed);
if(CCheat::IsCheatActive(CCheat::WEAPONSFORALL_CHEAT) || CCheat::IsCheatActive(CCheat::MAYHEM_CHEAT))
{
switch (fwRandom::GetRandomNumber() % 5)
{
case 0:
RandomInt = WEAPONTYPE_PISTOL;
break;
case 1:
RandomInt = WEAPONTYPE_BASEBALLBAT;
break;
case 2:
RandomInt = WEAPONTYPE_SHOTGUN;
break;
// case 3:
// RandomInt = WEAPONTYPE_M4;
// break;
default:
RandomInt = WEAPONTYPE_ROCKETLAUNCHER;
break;
}
// RandomInt = fwRandom::GetRandomNumberInRange(WEAPONTYPE_UNARMED, WEAPONTYPE_TEARGAS+1);
if(RandomInt != WEAPONTYPE_UNARMED)
{
pPed->GiveDelayedWeapon((eWeaponType)RandomInt, 25001); // > 25000 == infinite ammo
pPed->SetCurrentWeapon(CWeaponInfo::GetWeaponInfo((eWeaponType)RandomInt)->m_nWeaponSlot);
}
}
break;
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:
case PEDTYPE_GANG10:
weaponType = WEAPONTYPE_UNARMED;
{
// give weapons to about 1/3 of gang members
if (fwRandom::GetRandomNumberInRange(0, 100) < 33)
{
RandomInt = fwRandom::GetRandomNumberInRange(0, 100);
if (CGangs::Gang[PedType - PEDTYPE_GANG1].ThirdWeapon != WEAPONTYPE_UNARMED)
{
if (RandomInt < 33)
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].FirstWeapon;
else if (RandomInt < 66)
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].SecondWeapon;
else
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].ThirdWeapon;
}
else if (CGangs::Gang[PedType - PEDTYPE_GANG1].SecondWeapon != WEAPONTYPE_UNARMED)
{
if (RandomInt < 50)
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].FirstWeapon;
else
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].SecondWeapon;
}
else
{
weaponType = CGangs::Gang[PedType - PEDTYPE_GANG1].FirstWeapon;
}
}
}
if (weaponType != WEAPONTYPE_UNARMED)
{
pPed->GiveDelayedWeapon(weaponType, 25001); // > 25000 == infinite ammo
pPed->SetCurrentWeapon(CWeaponInfo::GetWeaponInfo(weaponType)->m_nWeaponSlot);
}
break;
default:
break;
}
// Set ped position and add to world
pPed->SetPosition(vecPosition);
pPed->SetOrientation(DtoR * (0.0f), DtoR * (0.0f), DtoR * (0.0f));
CWorld::Add(pPed);
// give default task
if(bGiveDefaultTask)
{
pPed->GetPedIntelligence()->AddTaskDefault(pPed->GetPedData()->ComputeWanderTask(*pPed));
if(CCheat::IsCheatActive(CCheat::MAYHEM_CHEAT))
{
CPed* pClosest=NULL;
float closestDist=FLT_MAX;
// find closest ped for this one to attack
CPed::Pool *pool = CPed::GetPool();
CPed* pTestPed;
int i;
Vector3 dir;
float dist;
i=pool->GetSize();
while(i--)
{
pTestPed = pool->GetSlot(i);
if(pTestPed && pTestPed != pPed)
{
dir = pPed->GetPosition() - pTestPed->GetPosition();
dist = dir.Mag2();
if (dist < closestDist)
{
pClosest = pTestPed;
closestDist = dist;
}
}
}
if(pClosest)
{
CEventAcquaintancePedHate eventHate(pClosest);
eventHate.SetResponseTaskType(CTaskTypes::TASK_COMPLEX_KILL_PED_ON_FOOT);
pPed->GetPedIntelligence()->AddEvent(eventHate);
}
}
}
CPopulation::UpdatePedCount(pPed, ADD_TO_POPULATION);
return(pPed);
} // end - CPopulation::AddPed
// Name : RemovePed
// Purpose : Removes a ped from the world
// Parameters : pPed - ptr to the ped to remove
// Returns : Nothing
void CPopulation::RemovePed(CPed* pPed)
{
// is ped in world?
if (pPed->GetEntryInfoList().GetHeadPtr())
{
CPersistenceMgr::PopulationPedAboutToBeRemoved(pPed);
CWorld::Remove(pPed);
}
CPedFactory::GetFactory()->Destroy(pPed);
}
bool CPopulation::ArePedStatsCompatible(s32 pedStat1, s32 pedStat2)
{
// none of these ped stat types want partners
if (pedStat1==PEDSTAT_PLAYER || pedStat2==PEDSTAT_PLAYER ||
pedStat1==PEDSTAT_COP || pedStat2==PEDSTAT_COP ||
pedStat1==PEDSTAT_MEDIC || pedStat2==PEDSTAT_MEDIC ||
pedStat1==PEDSTAT_FIRE || pedStat2==PEDSTAT_FIRE ||
pedStat1==PEDSTAT_TRAMP_MALE || pedStat2==PEDSTAT_TRAMP_MALE ||
pedStat1==PEDSTAT_TRAMP_FEMALE || pedStat2==PEDSTAT_TRAMP_FEMALE ||
pedStat1==PEDSTAT_TOURIST || pedStat2==PEDSTAT_TOURIST ||
pedStat1==PEDSTAT_PROSTITUTE || pedStat2==PEDSTAT_PROSTITUTE ||
pedStat1==PEDSTAT_CRIMINAL || pedStat2==PEDSTAT_CRIMINAL ||
pedStat1==PEDSTAT_BUSKER || pedStat2==PEDSTAT_BUSKER ||
pedStat1==PEDSTAT_TAXIDRIVER || pedStat2==PEDSTAT_TAXIDRIVER ||
pedStat1==PEDSTAT_PSYCHO || pedStat2==PEDSTAT_PSYCHO ||
pedStat1==PEDSTAT_STEWARD || pedStat2==PEDSTAT_STEWARD ||
pedStat1==PEDSTAT_SPORTSFAN || pedStat2==PEDSTAT_SPORTSFAN ||
pedStat1==PEDSTAT_SHOPPER || pedStat2==PEDSTAT_SHOPPER ||
pedStat1==PEDSTAT_OLDSHOPPER || pedStat2==PEDSTAT_OLDSHOPPER ||
pedStat1==PEDSTAT_BEACH_GUY || pedStat2==PEDSTAT_BEACH_GUY ||
pedStat1==PEDSTAT_BEACH_GIRL || pedStat2==PEDSTAT_BEACH_GIRL ||
pedStat1==PEDSTAT_SKATER || pedStat2==PEDSTAT_SKATER ||
pedStat1==PEDSTAT_STD_MISSION || pedStat2==PEDSTAT_STD_MISSION ||
pedStat1==PEDSTAT_COWARD || pedStat2==PEDSTAT_COWARD)
{
return false;
}
// no gang members want partners
if ((pedStat1>=PEDSTAT_GANG1 && pedStat1<=PEDSTAT_GANG7) ||
(pedStat2>=PEDSTAT_GANG1 && pedStat2<=PEDSTAT_GANG7))
{
return false;
}
// only group old people together
if (pedStat1==PEDSTAT_OLD_GUY || pedStat1==PEDSTAT_OLD_GIRL)
{
// the other must be old
if (pedStat2==PEDSTAT_OLD_GUY || pedStat2==PEDSTAT_OLD_GIRL)
{
return true;
}
else
{
return false;
}
}
// not coped with any of the following - they can be paired with each other ok
// PEDSTAT_STREET_GUY
// PEDSTAT_SUIT_GUY
// PEDSTAT_SENSIBLE_GUY
// PEDSTAT_GEEK_GUY
// PEDSTAT_TOUGH_GUY
// PEDSTAT_STREET_GIRL
// PEDSTAT_SUIT_GIRL
// PEDSTAT_SENSIBLE_GIRL
// PEDSTAT_GEEK_GIRL
// PEDSTAT_TOUGH_GIRL
return true;
}
///////////////////////////////////////////////////////////////
// FUNCTION: PedMICanBeCreatedAtAttractor
// Works out whether a ped with this MI is suitable at an attractor
bool CPopulation::PedMICanBeCreatedAtAttractor(s32 MI)
{
switch (((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetDefaultPedType())
{
// case PEDTYPE_COP: There are some attractors specifically for cops.
case PEDTYPE_DEALER:
case PEDTYPE_MEDIC:
case PEDTYPE_FIRE:
case PEDTYPE_CRIMINAL:
case PEDTYPE_BUM:
case PEDTYPE_PROSTITUTE:
return false;
break;
default:
break;
}
return true;
}
///////////////////////////////////////////////////////////////
// FUNCTION: PedMICanBeCreatedAtThisAttractor
// Works out whether a ped with this MI is suitable at an attractor
bool CPopulation::PedMICanBeCreatedAtThisAttractor(s32 MI, char *pBrain)
{
if (pBrain == NULL) return true;
ePedType PedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetDefaultPedType();
// The special attractors for cops.
if (!stricmp(pBrain, "COPSIT") ||
!stricmp(pBrain, "COPLOOK") ||
!stricmp(pBrain, "BROWSE"))
{
if (PedType == PEDTYPE_COP)
{
return true;
}
return false;
}
// Cops don't belong on any other attractors
if (PedType == PEDTYPE_COP)
{
return false;
}
return true;
}
///////////////////////////////////////////////////////////////
// FUNCTION: PedMICanBeCreatedInInterior
// Works out whether a ped with this MI should be created in interior
bool CPopulation::PedMICanBeCreatedInInterior(s32 MI)
{
switch (((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetDefaultPedType())
{
case PEDTYPE_COP:
case PEDTYPE_DEALER:
case PEDTYPE_MEDIC:
case PEDTYPE_FIRE:
case PEDTYPE_CRIMINAL:
case PEDTYPE_BUM:
case PEDTYPE_PROSTITUTE:
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:
case PEDTYPE_GANG10:
return false;
break;
default:
break;
}
return true;
}
s32 CPopulation::ChooseCivilianOccupation(bool bMustBeMale, bool bMustBeFemale, s32 MustHaveAnimGroup, s32 AvoidThisOccupation, s32 compatibleWithThisPedStat, bool bOnlyOnFoots, bool bAtAttractor, char *pAttractorScriptName)
{
// Pick the one ped that is appropriate and has the smallest number of occurences at the moment.
s32 AppropriateMembers = gPopStreaming.GetAppropriateLoadedPeds().CountMembers();
s32 LeastFrequentAppropriatePed = -1;
s32 LeastFrequentAppropriateUsage = 10000;
for (s32 i = 0; i < AppropriateMembers; i++)
{
s32 MI = gPopStreaming.GetAppropriateLoadedPeds().GetMember(i);
ASSERT(CStreaming::HasObjectLoaded(MI, CModelInfo::GetStreamingModuleId()));
ASSERT(MI >= 0);
if (MI != AvoidThisOccupation &&
((!bOnlyOnFoots) || ((CPedModelInfo *)CModelInfo::GetModelInfo(MI))->CanPedDriveCars(ON_FOOT)) )
{
if ( (!bMustBeMale) || IsMale(MI) )
{
if ( (!bMustBeFemale) || IsFemale(MI) )
{
if (MustHaveAnimGroup < 0 || MustHaveAnimGroup == ((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetMotionAnimGroup())
{
if ( (!bAtAttractor) || (PedMICanBeCreatedAtAttractor(MI) && CPopulation::PedMICanBeCreatedAtThisAttractor(MI, pAttractorScriptName)))
{
if (compatibleWithThisPedStat <= -1 || ArePedStatsCompatible(((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetDefaultPedStats(), compatibleWithThisPedStat))
{
if (((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetNumRefs() < LeastFrequentAppropriateUsage)
{
LeastFrequentAppropriateUsage = ((CPedModelInfo*)CModelInfo::GetModelInfo(MI))->GetNumRefs();
LeastFrequentAppropriatePed = MI;
}
}
}
}
}
}
}
}
if (LeastFrequentAppropriatePed < 0)
{
return gPopStreaming.GetDefaultPedMI();
}
return LeastFrequentAppropriatePed;
}
void CPopulation::ChooseCivilianCoupleOccupations(s32& iPedMaleOccupation, s32& iPedFemaleOccupation)
{
bool bFirstIsMale = true;
bool bSecondIsMale = false;
iPedMaleOccupation=ChooseCivilianOccupation(bFirstIsMale, bSecondIsMale, -1);
if (iPedMaleOccupation >= 0)
{
iPedFemaleOccupation=ChooseCivilianOccupation(bSecondIsMale, bFirstIsMale, -1, iPedMaleOccupation, ((CPedModelInfo*)CModelInfo::GetModelInfo(iPedMaleOccupation))->GetDefaultPedStats());
}
if (iPedFemaleOccupation < 0)
{
iPedMaleOccupation = iPedFemaleOccupation = -1;
return;
}
CPedModelInfo* pMaleModelInfo=(CPedModelInfo*)CModelInfo::GetModelInfo(iPedMaleOccupation);
CPedModelInfo* pFemaleModelInfo=(CPedModelInfo*)CModelInfo::GetModelInfo(iPedFemaleOccupation);
if((pMaleModelInfo->GetDefaultPedStats()!=PEDSTAT_SKATER)&&(pFemaleModelInfo->GetDefaultPedStats()!=PEDSTAT_SKATER))
{
return;
}
if((pMaleModelInfo->GetDefaultPedStats()==PEDSTAT_SKATER)&&(pFemaleModelInfo->GetDefaultPedStats()==PEDSTAT_SKATER))
{
return;
}
iPedMaleOccupation = iPedFemaleOccupation = -1;
return;
}
s32 CPopulation::ChooseCivilianOccupationForVehicle(bool bMustBeMale, CVehicle *pVeh)
{
ASSERT(pVeh);
#define MAXUSAGE (4)
s32 Usage = 0;
// s32 MI;
CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(pVeh->GetModelIndex());
s32 VehicleList = pModelInfo->GetVehicleList();
// Use a new strategy to create them.
// Start with the ones that aren't used yet.
// Then the ones that are only used once
// Twice and then stop.
// On the first pass we check for identical peds in the same car.
// On the seconds pass we don't.
s32 AppropriateMembers = gPopStreaming.GetAppropriateLoadedPeds().CountMembers();
for (s32 Pass = 0; Pass < 2; Pass++)
{
for (Usage = 0; Usage <= MAXUSAGE; Usage++)
{
for (s32 i = 0; i < AppropriateMembers; i++)
{
s32 MI = gPopStreaming.GetAppropriateLoadedPeds().GetMember(i);
ASSERT(CStreaming::HasObjectLoaded(MI, CModelInfo::GetStreamingModuleId()));
if (MI >= 0 && (Usage == MAXUSAGE || CModelInfo::GetModelInfo(MI)->GetNumRefs() == Usage))
{
if (((CPedModelInfo *)CModelInfo::GetModelInfo(MI))->CanPedDriveCars(VehicleList))
{
if ( (!bMustBeMale) || IsMale(MI) )
{
// If this ped is already in the car we only pick it if this is the last iteration
if (Pass == 1)
{
return MI;
}
bool bIdenticalPedInCar = false;
if (pVeh->pDriver && pVeh->pDriver->GetModelIndex() == MI)
{
bIdenticalPedInCar = true;
}
for (s32 P = 0; P < 3; P++)
{
if (pVeh->pPassengers[P] && pVeh->pPassengers[P]->GetModelIndex() == MI)
{
bIdenticalPedInCar = true;
}
}
if (!bIdenticalPedInCar)
{
return MI;
}
}
}
}
}
}
}
return -1;
}
bool CPopulation::IsMale(const s32 iOccupation)
{
CPedModelInfo* pModelInfo = ((CPedModelInfo*)CModelInfo::GetModelInfo(iOccupation));
return pModelInfo->GetDefaultPedType() == PEDTYPE_CIVMALE;
}
bool CPopulation::IsFemale(const s32 iOccupation)
{
CPedModelInfo* pModelInfo = ((CPedModelInfo*)CModelInfo::GetModelInfo(iOccupation));
return pModelInfo->GetDefaultPedType() == PEDTYPE_CIVFEMALE;
}
bool CPopulation::IsSkateable(const Vector3& vPos)
{
CGtaIntersection intersection;
phInst* pColInst=0;
CWorldProbe::ProcessVerticalLine(vPos+Vector3(0,0,2),vPos.z-2,0,intersection,pColInst,phArchetypeGta::GTA_ALL_MAP_TYPES);
if(pColInst)
{
// if(!IsSkateable(colPoint.GetSurfaceTypeB()))
/* rage_materials if (!g_surfaceInfos.IsSkateable(intersection.GetSurfaceTypeB()))
{
return false;
}*/
}
else
{
return false;
}
return true;
}
/*
bool CPopulation::IsSkateable(const u8 surfaceType)
{
//if(COLPOINT_SURFACETYPE_DEFAULT==surfaceType)
//{
// return true;
//}
if(COLPOINT_SURFACETYPE_TARMAC==surfaceType)
{
return true;
}
if(COLPOINT_SURFACETYPE_PAVEMENT==surfaceType)
{
return true;
}
return false;
}
*/
s32 CPopulation::ChooseGangOccupation(s32 gang)
{
return CGangs::ChooseGangPedModel(gang);
}
CPed* CPopulation::AddPedInCar(CVehicle *pVehicle, bool bDriver, s32 CarRating, s32 seat_num, bool bMustBeMale, bool bCriminal)
{
ePedType NewPedType;
s32 NewPedOccupation;
bool assumePedIsAvailable = true;
Vector3 vecDriverPosition;
int door = -1;
Vector3 posn = FindPlayerCoors();
// Find which zone the driver is in
vecDriverPosition = pVehicle->GetPosition();
// Specific vehicles have specific drivers.
s32 DriverMI = -1; //FindSpecificDriverModelForCar_ToUse(pVehicle->GetModelIndex());
if (bDriver && (DriverMI>=0) && CStreaming::HasObjectLoaded(DriverMI, CModelInfo::GetStreamingModuleId()))
{ // Pick the driver specifically for this vehicle.
NewPedOccupation = DriverMI;
ASSERT(NewPedOccupation >= 0);
NewPedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->GetDefaultPedType();
}
else
{
if (pVehicle->GetModelIndex() == MI_CAR_AMBULANCE)
{
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_MEDIC;
NewPedOccupation = MI_PED_MEDIC; //CStreaming::GetDefaultMedicModel();
}
else if (pVehicle->GetModelIndex() == MI_CAR_FIRETRUCK)
{
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_FIRE;
NewPedOccupation = MI_PED_FIREMAN; //CStreaming::GetDefaultFiremanModel();
}
else
/*
case MODELID_CAR_COPCAR_LA:
case MODELID_CAR_COPCAR_SF:
case MODELID_CAR_COPCAR_LV:
case MODELID_CAR_COPCAR_RURAL:
case MODELID_BOAT_PREDATOR:
case MODELID_HELI_POLMAVERICK:
// Create a police ped
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_COP;
NewPedOccupation = COPTYPE_NORMAL;
break;
case MODELID_BIKE_POLICE:
// Create a swat ped
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_COP;
NewPedOccupation = COPTYPE_MOTORCYCLE;
break;
case MODELID_CAR_ENFORCER:
// Create a swat ped
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_COP;
NewPedOccupation = COPTYPE_SWAT;
break;
case MODELID_CAR_FBI:
// Create a fbi ped
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_COP;
NewPedOccupation = COPTYPE_FBI;
break;
case MODELID_CAR_BARRACKS:
case MODELID_CAR_RHINO:
// Create a army ped
//NEEDS_MOVED_TO_NY_LAYER
NewPedType = PEDTYPE_COP;
NewPedOccupation = COPTYPE_ARMY;
break;
case MODELID_CAR_STREAKCARRIAGE:
//NEEDS_MOVED_TO_NY_LAYER
NewPedOccupation = CPopulation::ChooseCivilianOccupation();
if(NewPedOccupation == -1)
NewPedOccupation = MODELID_DEFAULT_PED;
NewPedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->GetDefaultPedType();
break;
// done using FindSpecificDriverModelForCar()
case MODELID_CAR_TAXI:
case MODELID_CAR_CABBIE:
// case MODELID_CAR_BORGNINE:
// case MODELID_CAR_KAUFMAN:
//The car is a taxi. Only attempt to make a taxi driver ped if the ped will
//be the driver of the taxi. This prevents taxis having taxi drivers
//as passengers.
if(bDriver)
{
//Only get to here if the taxi has no driver. The new ped is allowed to
//be a taxi driver.
//if(CGeneral::GetRandomTrueFalse())
{
NewPedOccupation = MODELID_PED_DEFAULT_CABBIE;
NewPedType = PEDTYPE_CIVMALE;
break;
}
}
default:
*/
//JumpbackIn:
{
assumePedIsAvailable = false;
// for(i=0; i<NUM_OF_GANGS; i++)
// {
// if(pVehicle->GetModelIndex() == CPopulation::GetCarGroupCar(POPCYCLE_TYPEGROUPS+i, 0)) // CGangs::Gang[i].VehicleModelIndex)
// {
// NewPedType = (ePedType)(PEDTYPE_GANG1 + i);
// // not using GangIndexOfLoadedPedModel because its too bloody complex
// NewPedOccupation = ChooseGangOccupation(i);
// break;
// }
// }
// if(i != NUM_OF_GANGS)
// break;
if (CarRating >= GANG1_CAR && CarRating <= GANG10_CAR)
{
NewPedType = (ePedType)(PEDTYPE_GANG1 + (CarRating - GANG1_CAR));
NewPedOccupation = ChooseGangOccupation(CarRating - GANG1_CAR);
}
else
{
// Create a normal civilian.
ASSERT(pVehicle->GetModelIndex() >= 0);
// CVehicleModelInfo* pModelInfo = (CVehicleModelInfo*)CModelInfo::GetModelInfo(pVehicle->GetModelIndex());
ASSERT(CPopCycle::m_pCurrZone);
NewPedOccupation = ChooseCivilianOccupationForVehicle(bMustBeMale, pVehicle);
// NewPedOccupation = ChooseCivilianOccupation(bCriminal);
if (NewPedOccupation < 0)
{
NewPedOccupation = gPopStreaming.GetDefaultPedMI();
}
/*
s32 count = MAX_NUM_PEDS_LOADED;
while(count--)
{
if (NewPedOccupation < 0) NewPedOccupation = MODELID_DEFAULT_PED;
//Check that the model has loaded ok.
ASSERT(NewPedOccupation >= 0);
if((CModelInfo::GetModelInfo(NewPedOccupation)->GetRwObject()))
{
//Check if the model is already used for one of the car passengers or driver.
//We aim to avoid duplicates in cars.
if((!pVehicle->IsPassenger(NewPedOccupation))&&(!pVehicle->IsDriver(NewPedOccupation)))
{
ASSERT(NewPedOccupation >= 0);
if(((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->CanPedDriveCars(pModelInfo->GetVehicleList()))
{
//The ped is driving and the model can drive so accept the ped model.
break;
}
}
}
NewPedOccupation = ChooseCivilianOccupation(bCriminal);
}
// If couldn't find a ped then use the default ped
if(count == -1)
NewPedOccupation = defaultPed;
*/
ASSERT(NewPedOccupation >= 0);
NewPedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->GetDefaultPedType();
}
}
}
if (NewPedOccupation < 0) NewPedOccupation = gPopStreaming.GetDefaultPedMI();
// If ped hasn't loaded yet just generate the default ped
ASSERT(NewPedOccupation >= 0);
// rage if(assumePedIsAvailable == false &&
// rage CModelInfo::GetModelInfo(NewPedOccupation)->GetRwObject() == NULL)
// {
// NewPedOccupation = defaultPed;
// NewPedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(NewPedOccupation))->GetDefaultPedType();
// }
// Add ped
CPed *pPed = AddPed(NewPedType, NewPedOccupation, vecDriverPosition, false);
// CPed *pPed = CPedFactory::GetFactory()->Create(PEDTYPE_CIVMALE,NewPedOccupation);
// Set ped in car
if (seat_num < 0)
{
door = 0;
}
else
{
door = CCarEnterExit::ComputeTargetDoorToEnterAsPassenger(*pVehicle, seat_num);
}
CCarEnterExit::SetPedInCarDirect(pPed, pVehicle, door, bDriver);
if (bCriminal)
{
// force the ped to be a criminal and adjust the population accordingly
UpdatePedCount(pPed, SUBTRACT_FROM_POPULATION);
pPed->SetPedType(PEDTYPE_CRIMINAL);
UpdatePedCount(pPed, ADD_TO_POPULATION);
}
return(pPed);
}
CPed* CPopulation::AddExistingPedInCar(CPed *pPed, CVehicle* UNUSED_PARAM(pVehicle))
{
/*
CPed *pPed = AddPed(NewPedType, NewPedOccupation, vecDriverPosition);
pPed->SetUsesCollision(false);
pPed->m_nCurrentWeapon = 0;
CAnimManager::AddAnimation((RpClump*)pPed->m_pRwObject, ANIM_STD_PED, ANIM_STD_CAR_SIT);
*/
return(pPed);
}
void CPopulation::UpdatePedCount(CPed *pPed, u8 AddOrSub) // ePedType PedType
{
if (AddOrSub == ADD_TO_POPULATION)
{
if (!pPed->m_PedAiFlags.bHasBeenAddedToPopulation)
{
pPed->m_PedAiFlags.bHasBeenAddedToPopulation = true;
switch(pPed->GetPedType())
{
case PEDTYPE_CIVMALE:
ms_nNumCivMale++;
break;
case PEDTYPE_CIVFEMALE:
ms_nNumCivFemale++;
break;
case PEDTYPE_COP:
ms_nNumCop++;
break;
case PEDTYPE_MEDIC:
case PEDTYPE_FIRE:
ms_nNumEmergency++;
break;
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:
case PEDTYPE_GANG10:
// ms_nNumGang[pPed->GetPedType() - PEDTYPE_GANG1]++;
ms_nNumCivMale++;
break;
case PEDTYPE_DEALER:
ms_nNumCivMale++;
break;
case PEDTYPE_CRIMINAL :
ms_nNumCivMale++;
break;
case PEDTYPE_PROSTITUTE :
ms_nNumCivFemale++;
break;
case PEDTYPE_PLAYER1:
case PEDTYPE_PLAYER2:
case PEDTYPE_PLAYER_NETWORK:
case PEDTYPE_BUM :
case PEDTYPE_SPECIAL:
case PEDTYPE_MISSION :
break;
default:
#ifndef FINAL
CDebug::DebugMessage("Unknown ped type, UpdatePedCount, Population.cpp");
#endif
break;
}
}
}
else // SUBTRACT_FROM_POPULATION
{
if (pPed->m_PedAiFlags.bHasBeenAddedToPopulation)
{
pPed->m_PedAiFlags.bHasBeenAddedToPopulation = false;
switch(pPed->GetPedType())
{
case PEDTYPE_CIVMALE:
ms_nNumCivMale--;
Assertf(ms_nNumCivMale >= 0, "UpdatePedCount - ms_nNumCivMale is less than 0");
break;
case PEDTYPE_CIVFEMALE:
ms_nNumCivFemale--;
Assertf(ms_nNumCivFemale >= 0, "UpdatePedCount - ms_nNumCivFemale is less than 0");
break;
case PEDTYPE_COP:
ms_nNumCop--;
Assertf(ms_nNumCop >= 0, "UpdatePedCount - ms_nNumCop is less than 0");
break;
case PEDTYPE_MEDIC:
case PEDTYPE_FIRE:
ms_nNumEmergency--;
Assertf(ms_nNumEmergency >= 0, "UpdatePedCount - ms_nNumEmergency is less than 0");
break;
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:
case PEDTYPE_GANG10:
ms_nNumCivMale--;
Assertf(ms_nNumCivMale >= 0, "UpdatePedCount - ms_nNumCivMale is less than 0");
// ms_nNumGang[pPed->GetPedType() - PEDTYPE_GANG1]--;
// Assertf(ms_nNumGang[pPed->GetPedType() - PEDTYPE_GANG1] >= 0, "UpdatePedCount - ms_nNumGang is less than 0");
break;
case PEDTYPE_DEALER:
ms_nNumCivMale--;
Assertf(ms_nNumCivMale >= 0, "UpdatePedCount - ms_nNumCivMale is less than 0");
break;
case PEDTYPE_CRIMINAL :
ms_nNumCivMale--;
Assertf(ms_nNumCivMale >= 0, "UpdatePedCount - ms_nNumCivMale is less than 0");
break;
case PEDTYPE_PROSTITUTE :
ms_nNumCivFemale--;
Assertf(ms_nNumCivFemale >= 0, "UpdatePedCount - ms_nNumCivFemale is less than 0");
break;
case PEDTYPE_PLAYER1:
case PEDTYPE_PLAYER2:
case PEDTYPE_PLAYER_NETWORK:
case PEDTYPE_BUM :
case PEDTYPE_SPECIAL:
case PEDTYPE_MISSION :
break;
default:
#ifndef FINAL
CDebug::DebugMessage("Unknown ped type, UpdatePedCount, Population.cpp");
#endif
break;
}
}
}
}
void CPopulation::PlaceGangMembers(const ePedType eGangPedType, const int iNoOfGangMembers, const Vector3& vCentrePos)
{
//Choose whether to place the gang chatting in a circle or walking in a formation.
CPedGroupPlacer groupPlacer;
groupPlacer.PlaceGroup(eGangPedType,iNoOfGangMembers,vCentrePos,CPedGroupDefaultTaskAllocatorTypes::DEFAULT_TASK_ALLOCATOR_RANDOM);
}
void CPopulation::PlaceCouple(const ePedType malePedType, const s32 iMaleOccupation, const ePedType femalePedType, const s32 iFemaleOccupation, const Vector3& vManPos)
{
if((PEDTYPE_CIVMALE!=malePedType)||(PEDTYPE_CIVFEMALE!=femalePedType))
{
return;
}
//If the circle is visible to the camera and is near the camera
//then don't place the couple
const float fRadius=1.5f;
Vector3 copyBlooodyConsts = vManPos;
if(gCamInterface.IsSphereVisible(copyBlooodyConsts,fRadius))
{
if( ((Vector3)(vManPos-FindPlayerPed()->GetPosition())).XYMag()<
POPULATION_ADD_MIN_RADIUS)
{
return;
}
}
//Test if the circle is clear of any obstructions.
if(!CPedPlacement::IsPositionClearForPed(vManPos,CModelInfo::GetModelInfo(iMaleOccupation)->GetBoundingSphereRadius()))
{
return;
}
//Find the ground that the man will stand on.
bool bFoundGround;
const float fGroundZ=1.0f+CWorldProbe::FindGroundZFor3DCoord(vManPos.x,vManPos.y,vManPos.z+1.0f,&bFoundGround);
if(!bFoundGround)
{
return;
}
const float z= MAX(vManPos.z,fGroundZ);
// check man model has loaded
// rage if(CModelInfo::GetModelInfo(iMaleOccupation)->GetRwObject() == NULL)
// return;
CPed* pManPed = AddPed(malePedType,iMaleOccupation,Vector3(vManPos.x,vManPos.y,z), true);
if(0==pManPed)
return;
// set ped to invisible, so that the woman can be faded in.
// rage CVisibilityPlugins::SetClumpAlpha((RpClump*)pManPed->GetRwObject(), 0);
// check model has loaded
// rage if(CModelInfo::GetModelInfo(iFemaleOccupation)->GetRwObject() == NULL)
// return;
CPed* pWomanPed=AddPed(femalePedType,iFemaleOccupation,Vector3(vManPos.x,vManPos.y,z), true);
if(pWomanPed)
{
const Vector2& vOffset2D=CTaskComplexFollowLeaderInFormation::ms_offsets.GetOffSet(1,0);
// pWomanPed->GetPedIntelligence()->AddTaskPrimary(new CTaskComplexFollowLeaderAnyMeans(NULL, pManPed,Vector3(vOffset2D.x,vOffset2D.y,0)));
// JB : if speeds are too slow or too different, then don't create this couple - they will not
// be able to keep up with each other well enough..
float fWomanWalkSpeed = pWomanPed->GetWalkAnimSpeed(ANIM_MOVE_WALK);
float fManWalkSpeed = pManPed->GetWalkAnimSpeed(ANIM_MOVE_WALK);
if(fWomanWalkSpeed < 0.75f || fManWalkSpeed < 0.75f || rage::Abs(fWomanWalkSpeed - fManWalkSpeed) > 0.45f)
{
return;
}
if (fWomanWalkSpeed > fManWalkSpeed)
{
pManPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexBeInCouple(pWomanPed, false));
pWomanPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexBeInCouple(pManPed, true));
}
else
{
pWomanPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexBeInCouple(pManPed, false));
pManPed->GetPedIntelligence()->AddTaskPrimary(rage_new CTaskComplexBeInCouple(pWomanPed, true));
}
#ifndef FINAL
char maleStat[64];
char femaleStat[64];
CPedStats::GetPedStatNameFromId(pManPed->m_pPedStats->m_ePedStatType, maleStat);
CPedStats::GetPedStatNameFromId(pWomanPed->m_pPedStats->m_ePedStatType, femaleStat);
DEBUGLOG2("COUPLE INFO: Placed couple - %s with %s\n", maleStat, femaleStat);
#endif
Vector3 vWomanPos=pManPed->GetPosition()+Vector3(vOffset2D.x,vOffset2D.y,0);
bool bFoundGround;
const float fGroundZ=1.0f+CWorldProbe::FindGroundZFor3DCoord(vWomanPos.x,vWomanPos.y,vWomanPos.z+1.0f,&bFoundGround);
if(!bFoundGround)
{
RemovePed(pManPed);
RemovePed(pWomanPed);
return;
}
else
{
const float z= MAX(vWomanPos.z,fGroundZ);
pWomanPed->SetPosition(Vector3(vWomanPos.x, vWomanPos.y, z));
//Test if any hit object isn't the man ped.
CEntity* pHitObjects[3]={0,0,0};
CPedPlacement::IsPositionClearForPed(vWomanPos,CModelInfo::GetModelInfo(iFemaleOccupation)->GetBoundingSphereRadius(),3,pHitObjects);
int k;
for(k=0;k<3;k++)
{
CEntity* pHitEntity=pHitObjects[k];
if(pHitEntity)
{
if((pHitEntity)&&(pHitEntity!=pManPed)&&(pHitEntity!=pWomanPed))
{
RemovePed(pManPed);
RemovePed(pWomanPed);
return;
}
}
}
// set ped to invisible, so that the woman can be faded in.
// rage CVisibilityPlugins::SetClumpAlpha((RpClump*)pWomanPed->GetRwObject(), 0);
}
}
}
bool CPopulation::IsCorrectTimeOfDayForEffect(const C2dEffect* pEffect)
{
ASSERT(pEffect && ET_PEDQUEUE==pEffect->m_type);
if(QT_ATM==pEffect->attr.q.m_type ||
QT_SEAT==pEffect->attr.q.m_type ||
QT_BUS_STOP==pEffect->attr.q.m_type ||
QT_PARK==pEffect->attr.q.m_type)
{
//Only use these during the day.
const int iTime=CClock::GetGameClockHours();
return ((iTime>8) && (iTime<20));
}
else
{
//Use every other effect at all times of the day.
return true;
}
}
s32 CPopulation::GeneratePedsAtAttractors(const Vector3& Coors, float minRad, float maxRad, float minRadClose, float maxRadClose, s32 decisionMaker, s32 NumToCreate)
{
s32 PedsCreated = 0;
s32 Tries = 0;
// s32 numPedsCanCreate = FindNumberOfPedsWeCanPlaceOnBenches(&pedModelIndex);
if (NumToCreate == 0) return 0;
// Search for the objects in the area (include dummies since the objects may have been created as dummies this frame during entryexit)
#define MAX_NEAR_ENTITIES (512)
s32 numNearEntities = -1;
CEntity* pNearEntities[MAX_NEAR_ENTITIES];
// Vector3 playerPos = FindPlayerCentreOfWorld(CWorld::PlayerInFocus);
CWorld::FindObjectsInRange(Coors, maxRad, false, &numNearEntities, MAX_NEAR_ENTITIES, pNearEntities, true, false, false, true, false);
while (NumToCreate > 0 && Tries < 12)
{
// search for an attractor in range - preferably on screen
Tries++;
// search through these looking for ones with interiors
for (s32 i=0; i<numNearEntities; i++)
{
if (NumToCreate==0)
{
return PedsCreated;
}
/* rage
if (pNearEntities[i]->GetRwObject() == NULL)
{
// we're not interested in ones which haven't loaded in yet
continue;
}
if (CGame::currArea != pNearEntities[i]->GetAreaCode())
{
// we're not interested in ones which aren't in our area code
continue;
}
*/
C2dEffect* pEffect = pNearEntities[i]->GetRandom2dEffect(ET_PEDQUEUE, true);
if (pEffect && IsCorrectTimeOfDayForEffect(pEffect))
{
// Don't generate peds at disabled attractors
if(pEffect->attr.q.m_flags & PEDQUEUE_DISABLED)
{
if(!pNearEntities[i]->GetIsTypeObject() ||
!((CObject *)pNearEntities[i])->m_nObjectFlags.bEnableDisabledAttractors)
continue;
}
// get the distance from the player to the attractor
Vector3 effectPos = pEffect->m_posn;
effectPos = pNearEntities[i]->GetMatrix() * effectPos;
Vector3 vec = Coors - effectPos;
float dist = vec.Mag();
float minDist, maxDist;
if (gCamInterface.IsSphereVisible(effectPos, 2.0f))
{
minDist = minRad;
maxDist = maxRad;
}
else
{
minDist = minRadClose;
maxDist = maxRadClose;
}
if (dist>minDist && dist<maxDist)
{
s32 MI;
// rage if (!bInPoliceStation || fwRandom::GetRandomNumberInRange(0, 100) > 70 /*rage|| !PedMICanBeCreatedAtThisAttractor(MODELID_COP_LA_PED, pEffect->attr.q.m_scriptName)*/)
{
MI = CPopulation::ChooseCivilianOccupation(false, false, -1, -1, -1, true, true, pEffect->attr.q.m_scriptName);
}
// else
// {
// MI = MODELID_COP_LA_PED;
// decisionMaker = CDecisionMakerTypes::DECISION_MAKER_PED_COP;
// }
if (MI > 0 && MI != gPopStreaming.GetDefaultPedMI())
{
if (AddPedAtAttractor(MI, pEffect, effectPos, pNearEntities[i], decisionMaker))
{
PedsCreated++;
if (decisionMaker == - 1)
{
// these must be ambient peds being added - only add the one
return PedsCreated;
}
NumToCreate--;
Tries = 0;
// numPedsCanCreate = FindNumberOfPedsWeCanPlaceOnBenches(&pedModelIndex);
}
}
}
}
}
}
return PedsCreated;
}
bool8 CPopulation::AddPedAtAttractor(s32 pedModelIndex, C2dEffect* pEffect, const Vector3& effectPos, CEntity* pEntity, s32 decisionMaker)
{
Assertf(pEntity, "Entity ptr is null");
Assertf(!pEntity->GetIsTypeDummy(), "Entity is null or is type dummy");
//Check that area around the effect pos is clear of other peds.
//A ped could have immediately finishing using the attractor at this pos and end up stuck
//inside the next ped generated at the attractor.
//Compute the closest ped to effectPos.
CPed* pClosestPed=0;
// float fClosest2=std::numeric_limits<float>::max();
float fClosest2 = 99999.9f;
CPed::Pool *pool = CPed::GetPool();
CPed* pPed;
s32 i=pool->GetSize();
while(i--)
{
pPed = pool->GetSlot(i);
if(pPed)
{
Vector3 vDiff;
vDiff = effectPos-pPed->GetPosition();
vDiff.z=0;
const float f2=vDiff.Mag2();
if(f2<fClosest2)
{
fClosest2=f2;
pClosestPed=pPed;
}
}
}
if(fClosest2 > (PED_RADIUS*PED_RADIUS))
{
if (GetPedAttractorManager()->HasQueueTailArrivedAtSlot(pEffect, pEntity))
//(0==GetPedAttractorManager()->GetPedUsingEffect(pEffect,pEntity))
{
// add a ped at this attractor
ePedType pedType = ((CPedModelInfo*)CModelInfo::GetModelInfo(pedModelIndex))->GetDefaultPedType();
CPed* pPed = CPopulation::AddPed(pedType, pedModelIndex, effectPos, false);
if (pPed)
{
CPopulation::UpdatePedCount(pPed, ADD_TO_POPULATION);
// Randomise this ped with attributes and different cothes and shit
CPedVariationMgr::SetVarRandom(pPed);
CPedPropsMgr::SetPedPropsRandomly(pPed, 0.4f, 0.25f);
pPed->SetCharCreatedBy(RANDOM_CHAR);
if(decisionMaker == -1)
{
decisionMaker = CDecisionMakerTypes::DECISION_MAKER_PED_RANDOM1;
}
pPed->GetPedIntelligence()->SetPedDecisionMakerType(decisionMaker);
pPed->GetPedIntelligence()->AddTaskDefault(pPed->GetPedData()->ComputeWanderTask(*pPed));
CPedAttractorPedPlacer::PlacePedAtEffect(*pEffect, pEntity, pPed, 0.02f);
pPed->m_PedAiFlags.bUseAttractorInstantly = true;
CEventAttractor event(pEffect, pEntity, true);
event.SetResponseTaskType(CTaskTypes::TASK_COMPLEX_USE_EFFECT);
pPed->GetPedIntelligence()->AddEvent(event);
pPed->GetPedIntelligence()->ProcessEventHandler();
pPed->GetPedIntelligence()->Process();
//ASSERT(pPed->GetPedIntelligence()->FindTaskActiveByType(CTaskTypes::TASK_COMPLEX_USE_EFFECT));
return true;
}
}
}
return false;
}
//
// name: NetworkRegisterAllPeds
// description: Registers all peds with the network object manager when a new network
// game starts.
//
#ifdef ONLINE_PLAY
void CPopulation::NetworkRegisterAllPeds()
{
CPed::Pool *pool = CPed::GetPool();
CPed *pPed;
for (s32 i=0; i<pool->GetSize(); i++)
{
pPed = pool->GetSlot(i);
if(pPed &&
pPed->GetPedType() != PEDTYPE_PLAYER1 &&
pPed->GetPedType() != PEDTYPE_PLAYER2)
{
const PlayerId playerID = (const PlayerId)CWorld::GetMainPlayer();
CNetwork::GetObjectManager().RegisterObject(pPed, playerID);
}
}
}
#endif