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

1231 lines
44 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
// Title : PopZones.cpp
// Author : Graeme, Adam Croston
// Started : 19.06.00
// Purpose : To keep track of population areas on the map.
/////////////////////////////////////////////////////////////////////////////////
#include "peds/popzones.h"
// C headers
#include <stdio.h>
#include <string.h>
// Framework includes
#include "fwscene/world/WorldLimits.h"
// Rage includes
#include "bank/bank.h"
#include "bank/bkmgr.h"
// Game headers
#include "ai/stats.h"
#include "camera/CamInterface.h"
#include "camera/debug/DebugDirector.h"
#include "camera/helpers/Frame.h"
#include "debug/vectormap.h"
#include "game/clock.h"
#include "game/dispatch/DispatchData.h"
#include "peds/popcycle.h"
#include "peds/playerinfo.h"
#include "peds/ped.h"
#include "scene/world/gameWorld.h"
#include "script/script.h"
#include "system/filemgr.h"
#include "vfx/metadata/VfxRegionInfo.h"
#include "vehicles/vehiclepopulation.h"
#include "text/textconversion.h"
using namespace AIStats;
AI_OPTIMISATIONS()
PARAM(check_pop_zones, "[PopZones] check popzones for overlap");
/////////////////////////////////////////////////////////////////////////////////
// Name : CPopZone
// Purpose : TODO
/////////////////////////////////////////////////////////////////////////////////
atArray<CPopZone> CPopZones::sm_popZones;
// Cache for FindSmallestForPosition
CPopZones::SmallestPopZoneCacheEntry CPopZones::sm_smallestPopZoneCache[CACHED_SMALLEST_POP_ZONE_RESULTS];
u8 CPopZones::sm_smallestPopZoneCacheIndex = 0;
#if __BANK
bool CPopZones::bPrintZoneInfo = false;
bool CPopZones::bDisplayZonesOnVMap = false;
bool CPopZones::bDisplayZonesInWorld = false;
bool CPopZones::bDisplayOnlySlowLawResponseZones = false;
bool CPopZones::bDisplayNonSlowLawResponseZones = false;
#endif // __BANK
CPopZone::CPopZone()
{
m_id.Clear();
m_associatedTextId.Clear();
m_uberZoneCentreX = m_uberZoneCentreY = 0;
m_bNoCops = false;
m_MPGangTerritoryIndex = -1;
m_bBigZoneForScanner = false;
m_vehDirtMin = -1.f;
m_vehDirtMax = -1.f;
m_pedDirtMin = -1.f;
m_pedDirtMax = -1.f;
m_dirtGrowScale = 1.0f;
m_dirtCol.Set(0);
m_vfxRegionHashName = VFXREGIONINFO_DEFAULT_HASHNAME;
m_plantsMgrTxdIdx = 0x07;
m_scumminess = SCUMMINESS_ABOVE_AVERAGE;
m_lawResponseDelayType = LAW_RESPONSE_DELAY_MEDIUM;
m_vehicleResponseType = VEHICLE_RESPONSE_DEFAULT;
m_fPopBaseRangeScale = 1.0f;
m_fPopHeightScaleMultiplier = 1.0f;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : CPopZoneSearchInfo
// Purpose : TODO
/////////////////////////////////////////////////////////////////////////////////
atArray<CPopZoneSearchInfo> CPopZones::sm_popZoneSearchInfos;
CPopZoneSearchInfo::CPopZoneSearchInfo()
{
m_ZoneCategory = (ZONECAT_NAVIGATION);
m_bEnabled = true; // enabled by default
m_popScheduleIndexForSP = 0;
m_popScheduleIndexForMP = 0;
m_x1 = 0;
m_y1 = 0;
m_z1 = 0;
m_x2 = 0;
m_y2 = 0;
m_z2 = 0;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetTranslatedName
// Purpose : Returns the text to be displayed when entering this Zone
// Only Navigation and Local Navigation Zones should have associated text
// Parameters : none
// Returns : Pointer to the text to display
/////////////////////////////////////////////////////////////////////////////////
char *CPopZone::GetTranslatedName() const
{
return TheText.Get(m_associatedTextId.TryGetCStr());
}
/////////////////////////////////////////////////////////////////////////////////
// Name : InitLevelWithMapUnloaded
// Purpose : TODO
// Parameters : None
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::Init(unsigned initMode)
{
if (initMode == INIT_BEFORE_MAP_LOADED)
{
ResetPopZones();
// Make the first Name Zone and the first Info Zone a default zone which covers the entire level
CPopZone popZone;
{
popZone.m_id.SetFromString("DEFAULT");
popZone.m_associatedTextId.SetFromString("SanAnd");
popZone.m_bNoCops = false;
popZone.m_MPGangTerritoryIndex = -1;
popZone.m_lawResponseDelayType = LAW_RESPONSE_DELAY_MEDIUM;
popZone.m_vehicleResponseType = VEHICLE_RESPONSE_DEFAULT;
popZone.m_specialAttributeType = SPECIAL_NONE;
#if RSG_PC || RSG_DURANGO || RSG_ORBIS
popZone.m_plantsMgrTxdIdx = 0x07;
#else
popZone.m_plantsMgrTxdIdx = 0x02; // force txd=2 (underwater) for DEFAULT
#endif
}
sm_popZones.PushAndGrow(popZone);
CPopZoneSearchInfo popZoneSearchInfo;
{
popZoneSearchInfo.m_x1 = (s16)WORLDLIMITS_XMIN;
popZoneSearchInfo.m_y1 = (s16)WORLDLIMITS_YMIN;
popZoneSearchInfo.m_z1 = (s16)WORLDLIMITS_ZMIN;
popZoneSearchInfo.m_x2 = (s16)WORLDLIMITS_XMAX;
popZoneSearchInfo.m_y2 = (s16)WORLDLIMITS_YMAX;
popZoneSearchInfo.m_z2 = (s16)WORLDLIMITS_ZMAX;
popZoneSearchInfo.m_ZoneCategory = ZONECAT_NAVIGATION;
popZoneSearchInfo.m_popScheduleIndexForSP = 0;
popZoneSearchInfo.m_popScheduleIndexForMP = 0;
}
sm_popZoneSearchInfos.PushAndGrow(popZoneSearchInfo);
// init cache values
sm_smallestPopZoneCacheIndex = 0;
sysMemSet(sm_smallestPopZoneCache, 0, sizeof(CPopZones::SmallestPopZoneCacheEntry)*CACHED_SMALLEST_POP_ZONE_RESULTS);
}
else if (initMode == INIT_AFTER_MAP_LOADED)
{
PostCreation();
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : Update
// Purpose : TODO
// Parameters : None
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::Update(void)
{
#if __BANK
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
CPopZone * pDebugZone = FindSmallestForPosition(&vOrigin, ZONECAT_ANY, NetworkInterface::IsGameInProgress() ? ZONETYPE_MP : ZONETYPE_SP);
if(bPrintZoneInfo || bDisplayZonesOnVMap || bDisplayZonesInWorld)
{
if(pDebugZone)
{
Vector2 vPixelSize( 1.0f / ((float)grcDevice::GetWidth()), 1.0f / ((float)grcDevice::GetHeight()) );
Vector2 vTextPos( vPixelSize.x * 56.0f, 1.0f );
vTextPos.y -= (vPixelSize.y * ((float)grcDebugDraw::GetScreenSpaceTextHeight())) * 13.0f;
char debugText[256];
formatf(debugText, "ZONE : \"%s\"", pDebugZone->GetTranslatedName());
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "ID : %s, TextID : %s", pDebugZone->m_id.TryGetCStr(), pDebugZone->m_associatedTextId.TryGetCStr());
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
const char * pZoneCat;
switch(GetPopZoneZoneCategory(pDebugZone))
{
case ZONECAT_NAVIGATION : pZoneCat = "ZONECAT_NAVIGATION"; break;
case ZONECAT_LOCAL_NAVIGATION : pZoneCat = "ZONECAT_LOCAL_NAVIGATION"; break;
case ZONECAT_INFORMATION : pZoneCat = "ZONECAT_INFORMATION"; break;
case ZONECAT_MAP : pZoneCat = "ZONECAT_MAP"; break;
case ZONECAT_ANY: default: pZoneCat = "ZONECAT_ANY"; break;
}
formatf(debugText, "Category : %s", pZoneCat);
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "Pop Scaling (StartZ: %.1f, EndZ: %.1f, Multiplier: %.1f)", (float)pDebugZone->m_iPopHeightScaleLowZ, (float)pDebugZone->m_iPopHeightScaleHighZ, pDebugZone->m_fPopHeightScaleMultiplier);
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "Pop Schedule (SP: %i, MP: %i) Gang Territory: %i", GetPopZonePopScheduleIndexForSP(pDebugZone), GetPopZonePopScheduleIndexForMP(pDebugZone), pDebugZone->m_MPGangTerritoryIndex);
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "Response Speed (Law: %i, Vehicle: %i)", pDebugZone->m_lawResponseDelayType, pDebugZone->m_vehicleResponseType);
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "BigZone: %s NoCops: %s Enabled: %s Special: %s",
pDebugZone->m_bBigZoneForScanner ? "true" : "false",
pDebugZone->m_bNoCops ? "true" : "false",
GetPopZoneEnabled(pDebugZone) ? "true" : "false",
pDebugZone->m_specialAttributeType ? "true" : "false");
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "AllowScenarioWeatherExits: %s", pDebugZone->m_bAllowScenarioWeatherExits ? "true" : "false");
grcDebugDraw::Text( vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
formatf(debugText, "Let hurry away leave pavements %s", pDebugZone->m_bLetHurryAwayLeavePavements ? "true" : "false");
grcDebugDraw::Text(vTextPos, Color_NavyBlue, debugText, true);
vTextPos.y += vPixelSize.y * grcDebugDraw::GetScreenSpaceTextHeight();
}
}
if(bDisplayZonesOnVMap)
{
CPopZone* pZone = FindSmallestForPosition(&vOrigin, ZONECAT_ANY, NetworkInterface::IsGameInProgress() ? ZONETYPE_MP : ZONETYPE_SP);
const int popZoneCount = sm_popZones.GetCount();
for(int popZoneIndex = 0; popZoneIndex < popZoneCount; ++popZoneIndex)
{
Vector3 vMin( static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_x1),
static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_y1),
static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_z1));
Vector3 vMax( static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_x2),
static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_y2),
static_cast<float>(sm_popZoneSearchInfos[popZoneIndex].m_z2));
if(&sm_popZones[popZoneIndex] == pZone)
{
static bool flash = true;
flash = !flash;
if(flash)
{
CVectorMap::DrawRectAxisAligned(vMin, vMax, Color32(0,0,0,128), true);
}
}
else
{
CVectorMap::DrawRectAxisAligned(vMin, vMax, Color32(32,32,32,64), true);
}
}
}
if(bDisplayZonesInWorld)
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vec3V vOrigin = VECTOR3_TO_VEC3V(debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos);
int iHeight = grcDebugDraw::GetScreenSpaceTextHeight();
char txt[256];
const Vector3 vFwd = debugDirector.GetFreeCamFrame().GetFront();
const float fPlaneD = - DotProduct(vFwd, VEC3V_TO_VECTOR3(vOrigin));
const float fMaxDist = 1024.0f;
for(int z=0; z<sm_popZones.GetCount(); z++)
{
CPopZone * pZone = &sm_popZones[z];
if(pZone->m_id.GetHash() != 0 && (!bDisplayOnlySlowLawResponseZones || pZone->m_lawResponseDelayType == LAW_RESPONSE_DELAY_SLOW) &&
(!bDisplayNonSlowLawResponseZones || pZone->m_lawResponseDelayType != LAW_RESPONSE_DELAY_SLOW))
{
Vec3V vZoneMin((float)GetPopZoneX1(pZone), (float)GetPopZoneY1(pZone), (float)GetPopZoneZ1(pZone));
Vec3V vZoneMax((float)GetPopZoneX2(pZone), (float)GetPopZoneY2(pZone), (float)GetPopZoneZ2(pZone));
Color32 iCol;
u32 iRandVal = static_cast<u32>(reinterpret_cast<size_t>(pZone));
iRandVal ^= pZone->m_id.GetHash() * pZone->m_id.GetHash();
iCol.Set(iRandVal);
Vec3V vCol(iCol.GetRedf(), iCol.GetGreenf(), iCol.GetBluef());
vCol = Normalize(vCol);
iCol = Color32(vCol.GetXf(), vCol.GetYf(), vCol.GetZf(), 1.0f);
//**************************
// Draw the zone's min/max
Vec3V vZoneMid = (vZoneMin+vZoneMax)*ScalarV(V_HALF);
const float fDist = Mag(vOrigin - vZoneMid).Getf();
const float fAlpha = 1.0f - Clamp(fDist / fMaxDist, 0.0f, 1.0f);
iCol.SetAlpha((int)(fAlpha*255.0f));
grcDebugDraw::BoxAxisAligned(vZoneMin, vZoneMax, iCol, false);
if(fDist < fMaxDist && DotProduct(vFwd, VEC3V_TO_VECTOR3(vZoneMid))+fPlaneD > 0.0f )
{
//float fAlpha = 1.0f - (fDist / fMaxTextDist);
//iCol.SetAlpha((int)(fAlpha*255.0f));
int iY = 0;
// Zone Name
formatf(txt, "Name : %s", pZone->m_associatedTextId.TryGetCStr());
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// Zone ID
formatf(txt, "ID : %s", pZone->m_id.TryGetCStr());
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// Pop Schedule Index
formatf(txt, "PopScheduleForSP : %i", GetPopZonePopScheduleIndexForSP(pZone));
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// Pop Schedule Index
formatf(txt, "PopScheduleForMP : %i", GetPopZonePopScheduleIndexForMP(pZone));
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// bNoCops
formatf(txt, "bNoCops : %s", pZone->m_bNoCops ? "true" : "false");
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// MP Gang Territory Index
formatf(txt, "MP Gang Territory : %d", pZone->m_MPGangTerritoryIndex);
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// law response speed
formatf(txt, "Law response speed : %d", pZone->m_lawResponseDelayType);
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// vehicle response type
formatf(txt, "Vehicle response type : %d", pZone->m_vehicleResponseType);
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// m_bBigZoneForScanner
formatf(txt, "bBigZone : %s", pZone->m_bBigZoneForScanner ? "true" : "false");
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// m_bAirport
formatf(txt, "Special attribute type : %d", pZone->m_specialAttributeType);
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// m_bAllowScenarioWeatherExits
formatf(txt, "Allow Scenario Weather Exits: %s", pZone->m_bAllowScenarioWeatherExits ? "true" : "false");
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
// m_bLetHurryAwayLeavePavements
formatf(txt, "Care about pavement for shocking events: %s", pZone->m_bLetHurryAwayLeavePavements ? "true" : "false");
grcDebugDraw::Text(vZoneMid, iCol, 0, iY, txt);
iY += iHeight;
}
}
}
// Flash the debug zone on/off every few frames
if(pDebugZone && (fwTimer::GetFrameCount() & 4))
{
Vec3V vZoneMin((float)GetPopZoneX1(pDebugZone), (float)GetPopZoneY1(pDebugZone), (float)GetPopZoneZ1(pDebugZone));
Vec3V vZoneMax((float)GetPopZoneX2(pDebugZone), (float)GetPopZoneY2(pDebugZone), (float)GetPopZoneZ2(pDebugZone));
// Vec3V vZoneMid = (vZoneMin+vZoneMax)*ScalarV(V_HALF);
grcDebugDraw::BoxAxisAligned(vZoneMin, vZoneMax, Color_red, false);
}
}
#endif // __BANK
}
/////////////////////////////////////////////////////////////////////////////////
// Name : CreatePopZone
// Purpose : Sets up the name, position and type of a new zone.
// This function will be called when loading the .ipl file
// Default ratios/densities are set up for appropriate zones.
// These can be changed in the scripts later.
// Parameters : TODO
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::CreatePopZone( const char* pZoneIdName,
const Vector3 &boxMin_, const Vector3 &boxMax_,
const char* pAssociatedTextIdName,
eZoneCategory ZoneCategory)
{
// Make sure the min and max values for the box is in the right order.
float temp_float;
Vector3 boxMin = boxMin_, boxMax = boxMax_;
if(boxMin.x > boxMax.x)
{
temp_float = boxMin.x;
boxMin.x = boxMax.x;
boxMax.x = temp_float;
}
if(boxMin.y > boxMax.y)
{
temp_float = boxMin.y;
boxMin.y = boxMax.y;
boxMax.y = temp_float;
}
if(boxMin.z > boxMax.z)
{
temp_float = boxMin.z;
boxMin.z = boxMax.z;
boxMax.z = temp_float;
}
char idBuff[8];
strncpy(idBuff, pZoneIdName, 7);
idBuff[7] = 0;
int len = istrlen(idBuff);
for(int i = len; i< 7; ++i){idBuff[i] = 0;}
CTextConversion::MakeUpperCaseAsciiOnly(idBuff);
char associatedTextIdBuff[8];
strncpy(associatedTextIdBuff, pAssociatedTextIdName, 7);
associatedTextIdBuff[7] = 0;
len = istrlen(associatedTextIdBuff);
for(int i = len; i< 7; ++i){associatedTextIdBuff[i] = 0;}
CTextConversion::MakeUpperCaseAsciiOnly(associatedTextIdBuff);
CPopZone popZone;
{
popZone.m_id.SetFromString(idBuff);
popZone.m_associatedTextId.SetFromString(associatedTextIdBuff);
popZone.m_bNoCops = false;
popZone.m_MPGangTerritoryIndex = -1;
popZone.m_vehDirtMin = -1.f;
popZone.m_vehDirtMax = -1.f;
popZone.m_pedDirtMin = -1.f;
popZone.m_pedDirtMax = -1.f;
popZone.m_dirtGrowScale = 1.0f;
popZone.m_dirtCol.Set(0);
popZone.m_vfxRegionHashName = VFXREGIONINFO_DEFAULT_HASHNAME;
popZone.m_plantsMgrTxdIdx = 0x07;
}
sm_popZones.PushAndGrow(popZone);
CPopZoneSearchInfo popZoneSearchInfo;
{
popZoneSearchInfo.m_x1 = (s16)boxMin.x;
popZoneSearchInfo.m_y1 = (s16)boxMin.y;
popZoneSearchInfo.m_z1 = (s16)boxMin.z;
popZoneSearchInfo.m_x2 = (s16)boxMax.x;
popZoneSearchInfo.m_y2 = (s16)boxMax.y;
popZoneSearchInfo.m_z2 = (s16)boxMax.z;
popZoneSearchInfo.m_ZoneCategory = ZoneCategory;
popZoneSearchInfo.m_popScheduleIndexForSP = 0;
popZoneSearchInfo.m_popScheduleIndexForMP = 0;
}
sm_popZoneSearchInfos.PushAndGrow(popZoneSearchInfo);
}
#if __ASSERT
/////////////////////////////////////////////////////////////////////////////////
// Name : CheckForOverlap
// Purpose : TODO
// Parameters : None
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::CheckForOverlap(void)
{
const int popZoneCount = sm_popZones.GetCount();
for(int i = 1; i < popZoneCount; ++i)
{ // Check that each navigation zone is entirely contained within the first navigation zone
Assertf(IsEntirelyInsideAnother(&sm_popZones[i], &sm_popZones[0]), "Zone %s is outside the world zone\n", sm_popZones[i].m_id.TryGetCStr());
for(int j = (i+1); j < popZoneCount; ++j)
{ // Check that each zone is entirely inside or entirely outside every other zone
if ( (IsEntirelyInsideAnother(&sm_popZones[i], &sm_popZones[j]))
|| (IsEntirelyInsideAnother(&sm_popZones[j], &sm_popZones[i])) )
{
}
else
{
if (Overlaps(&sm_popZones[i], &sm_popZones[j]))
{
Assertf(0, "CPopZones::CheckForOverlap - pop zone %s with Min <<%d,%d,%d>> and Max <<%d,%d,%d>> overlaps with pop zone %s with Min <<%d,%d,%d>> and Max <<%d,%d,%d>>",
sm_popZones[i].m_id.TryGetCStr(),
sm_popZoneSearchInfos[i].m_x1, sm_popZoneSearchInfos[i].m_y1, sm_popZoneSearchInfos[i].m_z1,
sm_popZoneSearchInfos[i].m_x2, sm_popZoneSearchInfos[i].m_y2, sm_popZoneSearchInfos[i].m_z2,
sm_popZones[j].m_id.TryGetCStr(),
sm_popZoneSearchInfos[j].m_x1, sm_popZoneSearchInfos[j].m_y1, sm_popZoneSearchInfos[j].m_z1,
sm_popZoneSearchInfos[j].m_x2, sm_popZoneSearchInfos[j].m_y2, sm_popZoneSearchInfos[j].m_z2);
}
}
}
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : IsPopZoneEntirelyInsideAnother
// Purpose : checks whether one Zone completely contains another
// Parameters : pointers to two Zones(the one which is expected to be smaller is first)
// Returns : TRUE if the first Zone is inside the second Zone
/////////////////////////////////////////////////////////////////////////////////
bool CPopZones::IsEntirelyInsideAnother(const CPopZone* pSmallZone, const CPopZone* pBigZone)
{
const CPopZoneSearchInfo* pSmallZoneInfo = GetSearchInfoFromPopZone(pSmallZone);
const CPopZoneSearchInfo* pBigZoneInfo = GetSearchInfoFromPopZone(pBigZone);
if( (pSmallZoneInfo->m_x1 >= pBigZoneInfo->m_x1) && (pSmallZoneInfo->m_x2 <= pBigZoneInfo->m_x2) &&
(pSmallZoneInfo->m_y1 >= pBigZoneInfo->m_y1) && (pSmallZoneInfo->m_y2 <= pBigZoneInfo->m_y2) &&
(pSmallZoneInfo->m_z1 >= pBigZoneInfo->m_z1) && (pSmallZoneInfo->m_z2 <= pBigZoneInfo->m_z2))
{
return TRUE;
}
else
{
//Vector3 TempPoint;
//TempPoint = Vector3(pSmallZone->m_x1, pSmallZone->m_y1, pSmallZone->m_z1);
//Assertf((TempPoint.x > pBigZone->m_x1) && (TempPoint.x < pBigZone->m_x2) &&
// (TempPoint.y > pBigZone->m_y1) && (TempPoint.y < pBigZone->m_y2) &&
// (TempPoint.z > pBigZone->m_z1) && (TempPoint.z < pBigZone->m_z2), "Overlapping zones %s and %s\n",(char*)&(pSmallZone->m_id),(char*)&(pBigZone->m_id));
//TempPoint = Vector3(pSmallZone->m_x2, pSmallZone->m_y2, pSmallZone->m_z2);
//Assertf((TempPoint.x > pBigZone->m_x1) && (TempPoint.x < pBigZone->m_x2) &&
// (TempPoint.y > pBigZone->m_y1) && (TempPoint.y < pBigZone->m_y2) &&
// (TempPoint.z > pBigZone->m_z1) && (TempPoint.z < pBigZone->m_z2), "Overlapping zones %s and %s\n",(char*)&(pSmallZone->m_id),(char*)&(pBigZone->m_id));
return FALSE;
}
}
bool CPopZones::DoesOverlapInOneDimension(s32 FirstMin, s32 FirstMax, s32 SecondMin, s32 SecondMax)
{
s32 LeftValue = Max(FirstMin, SecondMin);
s32 RightValue = Min(FirstMax, SecondMax);
s32 Difference = RightValue - LeftValue;
if (Difference > 0)
{
return true;
}
return false;
}
bool CPopZones::Overlaps(const CPopZone* pFirstZone, const CPopZone* pSecondZone)
{
const CPopZoneSearchInfo* pFirstZoneInfo = GetSearchInfoFromPopZone(pFirstZone);
const CPopZoneSearchInfo* pSecondZoneInfo = GetSearchInfoFromPopZone(pSecondZone);
// Assume that we've already dealt with the case of one zone being entirely inside the other
if (DoesOverlapInOneDimension(pFirstZoneInfo->m_x1, pFirstZoneInfo->m_x2, pSecondZoneInfo->m_x1, pSecondZoneInfo->m_x2))
{ // Overlap in X
if (DoesOverlapInOneDimension(pFirstZoneInfo->m_y1, pFirstZoneInfo->m_y2, pSecondZoneInfo->m_y1, pSecondZoneInfo->m_y2))
{ // Overlap in Y
if (DoesOverlapInOneDimension(pFirstZoneInfo->m_z1, pFirstZoneInfo->m_z2, pSecondZoneInfo->m_z1, pSecondZoneInfo->m_z2))
{ // Overlap in Z
return true;
}
}
}
return false;
}
#endif // __ASSERT
/////////////////////////////////////////////////////////////////////////////////
// Name : ClearPopZones
// Purpose : To clean the sm_popZones array out.
// Parameters : None
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::ResetPopZones(void)
{
sm_popZones.Reset();
sm_popZoneSearchInfos.Reset();
// reset cache values
sm_smallestPopZoneCacheIndex = 0;
sysMemSet(sm_smallestPopZoneCache, 0, sizeof(CPopZones::SmallestPopZoneCacheEntry)*CACHED_SMALLEST_POP_ZONE_RESULTS);
}
/////////////////////////////////////////////////////////////////////////////////
// Name : PostCreation
// Purpose : This function only affects navigation(and local navigation) zones
// This function should be called after all the zones
// have been loaded from the .ipl file and Created.
// The navigation zones are arranged so that it is easy to find which zones
// are inside which others.(This rearrangement assumes that no zone
// overlaps another.)
// Parameters : None
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::PostCreation(void)
{
#if __ASSERT
if (PARAM_check_pop_zones.Get())
{
CheckForOverlap();
}
#endif // __ASSERT
// compute mid points for any zones with the same name for use with the police scanner
const int popZoneCount = sm_popZones.GetCount();
for(int i = 0; i < popZoneCount; ++i)
{
u32 textHash = sm_popZones[i].m_associatedTextId.GetHash();
s64 sumX = 0, sumY=0;
u32 numZones = 0;
u32 zoneSize = 0;
for(int j = 0; j < popZoneCount; ++j)
{
if(sm_popZones[j].m_associatedTextId.GetHash() == textHash)
{
sumX +=(sm_popZoneSearchInfos[j].m_x1 + sm_popZoneSearchInfos[j].m_x2) / 2;
sumY +=(sm_popZoneSearchInfos[j].m_y1 + sm_popZoneSearchInfos[j].m_y2) / 2;
zoneSize +=(u32)(Vector3((f32)sm_popZoneSearchInfos[j].m_x1,(f32)sm_popZoneSearchInfos[j].m_y1,(f32)sm_popZoneSearchInfos[i].m_z1) - Vector3((f32)sm_popZoneSearchInfos[j].m_x2,(f32)sm_popZoneSearchInfos[j].m_y2,(f32)sm_popZoneSearchInfos[i].m_z2)).Mag();
numZones++;
}
}
sm_popZones[i].m_uberZoneCentreX = static_cast<s16>(sumX / numZones);
sm_popZones[i].m_uberZoneCentreY = static_cast<s16>(sumY / numZones);
sm_popZones[i].m_bBigZoneForScanner =(zoneSize > 200);
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : DoesPointLiesWithinPopZone
// Purpose : checks whether a given point is inside a given Zone
// Parameters : pointer to the point, pointer to the Zone
// Returns : TRUE if the point is inside the Zone
/////////////////////////////////////////////////////////////////////////////////
bool CPopZones::DoesPointLiesWithinPopZone(const Vector3* pPoint, const CPopZone* pZone)
{
const CPopZoneSearchInfo* pZoneInfo = GetSearchInfoFromPopZone(pZone);
if( (pPoint->x >= pZoneInfo->m_x1) && (pPoint->x <= pZoneInfo->m_x2) &&
(pPoint->y >= pZoneInfo->m_y1) && (pPoint->y <= pZoneInfo->m_y2) &&
(pPoint->z >= pZoneInfo->m_z1) && (pPoint->z <= pZoneInfo->m_z2))
{
return TRUE;
}
else
{
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : DoesPointLiesWithinPopZoneFast
// Purpose : checks whether a given point is inside a given Zone
// Parameters : X/Y/Z coordinates of the point as integers, pointer to the Zone
// Returns : TRUE if the point is inside the Zone
/////////////////////////////////////////////////////////////////////////////////
bool CPopZones::DoesPointLieWithinPopZoneFast(int pPoint_X, int pPoint_Y, int pPoint_Z, const CPopZoneSearchInfo* pZone)
{
if( (pPoint_X >= pZone->m_x1) && (pPoint_X <= pZone->m_x2) &&
(pPoint_Y >= pZone->m_y1) && (pPoint_Y <= pZone->m_y2) &&
(pPoint_Z >= pZone->m_z1) && (pPoint_Z <= pZone->m_z2))
{
return TRUE;
}
else
{
return FALSE;
}
}
int CPopZones::SmallestDistanceToPopZoneEdge(int pPoint_X, int pPoint_Y, int pPoint_Z, const CPopZoneSearchInfo* pZone)
{
int dif = pPoint_X - pZone->m_x1;
dif = MIN(dif, pPoint_Y - pZone->m_y1);
dif = MIN(dif, pPoint_Z - pZone->m_z1);
dif = MIN(dif, pZone->m_x2 - pPoint_X);
dif = MIN(dif, pZone->m_y2 - pPoint_Y);
dif = MIN(dif, pZone->m_z2 - pPoint_Z);
return dif;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : IsPointInPopZonesWithText
// Purpose : TODO
// Parameters : TODO
// Returns : TODO
/////////////////////////////////////////////////////////////////////////////////
bool CPopZones::IsPointInPopZonesWithText(const Vector3* pPoint, const char* pZoneLabel)
{
atHashString zoneHash(pZoneLabel);
const int popZoneCount = sm_popZones.GetCount();
for(int popZoneIndex = 0; popZoneIndex < popZoneCount; ++popZoneIndex)
{
if(sm_popZoneSearchInfos[popZoneIndex].m_bEnabled)
{
if(sm_popZones[popZoneIndex].m_associatedTextId.GetHash() == zoneHash.GetHash())
{
if(DoesPointLiesWithinPopZone(pPoint, &sm_popZones[popZoneIndex]))
{
return true;
}
}
}
}
return false;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetZone
// Purpose : Finds the first Zone(of the given type) with the given id.
// Parameters : zoneIdName to search for, Type of zone to search for
// Returns : TODO
/////////////////////////////////////////////////////////////////////////////////
CPopZone* CPopZones::GetPopZone(const char* pZoneIdName)
{
Assert(pZoneIdName);
atHashString pz(pZoneIdName);
const int popZoneCount = sm_popZones.GetCount();
for(int popZoneIndex = 0; popZoneIndex < popZoneCount; ++popZoneIndex)
{
if(sm_popZones[popZoneIndex].m_id.GetHash() == pz.GetHash())
{
return &sm_popZones[popZoneIndex];
}
}
return NULL;
}
int CPopZones::GetPopZoneId(const CPopZone* pPopZone)
{
if(pPopZone)
return ptrdiff_t_to_int(pPopZone - &sm_popZones[0]);
return INVALID_ZONEID;
}
CPopZone* CPopZones::GetPopZone(int zoneId)
{
if(zoneId != INVALID_ZONEID)
return &sm_popZones[zoneId];
return NULL;
}
bool CPopZones::IsValidForSearchType(const CPopZoneSearchInfo *zoneInfo, eZoneCategory zoneCategory, eZoneType zoneType)
{
bool isValid = false;
if(zoneInfo && zoneInfo->m_bEnabled)
{
if((zoneCategory == zoneInfo->m_ZoneCategory) || (zoneCategory == ZONECAT_ANY))
{
if((zoneType == ZONETYPE_ANY) ||
(zoneType == ZONETYPE_SP && zoneInfo->m_popScheduleIndexForSP != -1) ||
(zoneType == ZONETYPE_MP && zoneInfo->m_popScheduleIndexForMP != -1))
{
isValid = true;
}
}
}
return isValid;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetSearchInfoFromPopZone
// Purpose : Return a CPopZoneSearchInfo for the given Pop Zone
// Parameters : a pointer to the pop zone - it better not be Null
// Returns : The matching CPopZoneSearchInfo
/////////////////////////////////////////////////////////////////////////////////
const CPopZoneSearchInfo* CPopZones::GetSearchInfoFromPopZone(const CPopZone* pPopZone)
{
FastAssert(pPopZone);
int index = ptrdiff_t_to_int(pPopZone - sm_popZones.GetElements());
Assert(index >= 0 && index < sm_popZones.GetCount());
return &sm_popZoneSearchInfos[index];
}
/////////////////////////////////////////////////////////////////////////////////
// Name : InitWidgets
// Purpose : TODO
// Parameters : TODO
// Returns : TODO
/////////////////////////////////////////////////////////////////////////////////
#if __BANK
void GetNameOfZoneAtDebugCam()
{
Vector3 vOrigin = camInterface::GetDebugDirector().IsFreeCamActive() ? camInterface::GetDebugDirector().GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
CPopZone* pZone = CPopZones::FindSmallestForPosition(&vOrigin, ZONECAT_ANY, NetworkInterface::IsGameInProgress() ? ZONETYPE_MP : ZONETYPE_SP);
if(pZone)
{
Displayf("ZONE IS \"%s\"", pZone->m_associatedTextId.TryGetCStr());
}
else
{
Displayf("ZONE IS \"\"");
}
}
void CPopZones::InitWidgets(bkBank& BANK_ONLY(bank))
{
#if __BANK
bank.PushGroup("Pop Zones", false);
bank.AddToggle("Print zone info", &bPrintZoneInfo);
bank.AddToggle("Display pop zones (on VM)", &bDisplayZonesOnVMap);
bank.AddToggle("Display pop zones (in World)", &bDisplayZonesInWorld);
bank.AddToggle("Only display SLOW law response zones (in World)", &bDisplayOnlySlowLawResponseZones);
bank.AddToggle("Only display non-SLOW law response zones (in World)", &bDisplayNonSlowLawResponseZones);
bank.AddButton("GET_NAME_OF_ZONE at debug cam", GetNameOfZoneAtDebugCam);
bank.PopGroup();
#endif // __DEV
}
#endif // __BANK
/////////////////////////////////////////////////////////////////////////////////
// Name : FindSmallestForPosition
// Purpose : TODO
// Parameters : TODO
// Returns : TODO
/////////////////////////////////////////////////////////////////////////////////
CPopZone* CPopZones::FindSmallestForPosition(const Vector3* pPoint, eZoneCategory zoneCategory, eZoneType zoneType)
{
PF_FUNC(FindSmallestForPosition);
// #if __DEV
// char * pZoneName = NULL;
// #endif
// casting down to int here - precision loss is worth it for the performance gain
int pPoint_X = (int)pPoint->GetX();
int pPoint_Y = (int)pPoint->GetY();
int pPoint_Z = (int)pPoint->GetZ();
// Try to use cached results
#define CACHED_RESULT_DISTANCE_MAX_TOLERANCE (10.0f)
CPopZone* cachedResult = NULL;
for(int i = 0; i < CACHED_SMALLEST_POP_ZONE_RESULTS; i++)
{
if(sm_smallestPopZoneCache[i].m_Result && sm_smallestPopZoneCache[i].m_ZoneCategory == zoneCategory && sm_smallestPopZoneCache[i].m_ZoneType == zoneType)
{
// adjust the tolerance for how close the cached point was to the edge of it's pop zone
if(sm_smallestPopZoneCache[i].m_Point.IsClose(*pPoint, MIN(CACHED_RESULT_DISTANCE_MAX_TOLERANCE, sm_smallestPopZoneCache[i].m_smallestDistanceToEdge)) && sm_smallestPopZoneCache[i].m_Result)
{
// test to make sure the point lies in the cached zone
if(DoesPointLieWithinPopZoneFast(pPoint_X, pPoint_Y, pPoint_Z, GetSearchInfoFromPopZone(sm_smallestPopZoneCache[i].m_Result))
&& SmallestDistanceToPopZoneEdge(pPoint_X, pPoint_Y, pPoint_Z,GetSearchInfoFromPopZone(sm_smallestPopZoneCache[i].m_Result))>0) // don't use cached results that are right on the edge of the zone
{
cachedResult = sm_smallestPopZoneCache[i].m_Result;
return cachedResult;
}
}
}
}
// Cached value not found. Do full test
CPopZone *pSmallestZone = 0;
u32 smallestZoneIndex = 0;
//int SmallestZoneSize = INT_MAX;
u64 SmallestZoneSize = 0xffffffffffffffff;
FastAssert( sm_popZoneSearchInfos.GetCount() == sm_popZones.GetCount());
int popZoneIndex = 0;
const int popZoneCount = sm_popZoneSearchInfos.GetCount();
while(popZoneIndex < popZoneCount)
{
const CPopZoneSearchInfo *currentZoneInfo = &sm_popZoneSearchInfos[popZoneIndex];
if(currentZoneInfo && IsValidForSearchType(currentZoneInfo, zoneCategory, zoneType))
{
if(DoesPointLieWithinPopZoneFast(pPoint_X, pPoint_Y, pPoint_Z, currentZoneInfo))
{
const u64 dx = (currentZoneInfo->m_x2 - currentZoneInfo->m_x1);
const u64 dy = (currentZoneInfo->m_y2 - currentZoneInfo->m_y1);
const u64 dz = (currentZoneInfo->m_z2 - currentZoneInfo->m_z1);
const u64 SizeOfCurrentZone = dx * dy * dz;
if(SizeOfCurrentZone < SmallestZoneSize)
{
pSmallestZone = &sm_popZones[popZoneIndex];;
SmallestZoneSize = SizeOfCurrentZone;
smallestZoneIndex = popZoneIndex;
}
}
}
++popZoneIndex;
}
// cache result
sm_smallestPopZoneCache[sm_smallestPopZoneCacheIndex].m_Result = pSmallestZone;
sm_smallestPopZoneCache[sm_smallestPopZoneCacheIndex].m_Point = *pPoint;
sm_smallestPopZoneCache[sm_smallestPopZoneCacheIndex].m_ZoneCategory = zoneCategory;
sm_smallestPopZoneCache[sm_smallestPopZoneCacheIndex].m_ZoneType = zoneType;
// store off the smallest difference between the point and it's zone, to try and reduce errors
sm_smallestPopZoneCache[sm_smallestPopZoneCacheIndex].m_smallestDistanceToEdge = SmallestDistanceToPopZoneEdge(pPoint_X, pPoint_Y, pPoint_Z, &sm_popZoneSearchInfos[smallestZoneIndex])*.75f;
sm_smallestPopZoneCacheIndex++;
if(sm_smallestPopZoneCacheIndex >= CACHED_SMALLEST_POP_ZONE_RESULTS)
{
sm_smallestPopZoneCacheIndex = 0; // wrap
}
return pSmallestZone;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetDirtRangeInternal
// Purpose : Sets the vehicle dirt range for the zone specified
// Parameters : minimum dirt value, maximum dirt value
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetVehDirtRange(int zone, float dirtMin, float dirtMax)
{
sm_popZones[zone].m_vehDirtMin = dirtMin;
sm_popZones[zone].m_vehDirtMax = dirtMax;
}
void CPopZones::SetPedDirtRange(int zone, float dirtMin, float dirtMax)
{
sm_popZones[zone].m_pedDirtMin = dirtMin;
sm_popZones[zone].m_pedDirtMax = dirtMax;
}
void CPopZones::SetDirtGrowScale(int zone, float dirtScale)
{
sm_popZones[zone].m_dirtGrowScale = dirtScale;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetDirtColorInternal
// Purpose : Sets the vehicle dirt color for the zone specified
// Parameters : dirt color
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetDirtColor(int zone, const Color32& dirtCol)
{
sm_popZones[zone].m_dirtCol = dirtCol;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetVfxRegionHashName
// Purpose : Sets the vfx region hash value from the specified zone
// Parameters : vfx region hash value
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetVfxRegionHashName(int zone, atHashWithStringNotFinal hashName)
{
sm_popZones[zone].m_vfxRegionHashName = hashName;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetPlantsMgrTxdIdx
// Purpose : Sets PlantsMgr txd index for specified zone
// Parameters : txd index
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetPlantsMgrTxdIdx(int zone, u8 txdIdx)
{
Assert(txdIdx < 8); // must fit into 3 bits
sm_popZones[zone].m_plantsMgrTxdIdx = txdIdx;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetLawResponseDelayType
// Purpose : Sets the delay type of our law response (generally slow, medium, fast)
// Parameters : enum/int representing the type of delay
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetLawResponseDelayType(int zone, int iLawResponseDelayType)
{
sm_popZones[zone].m_lawResponseDelayType = static_cast<u8>(iLawResponseDelayType);
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetVehicleResponseType
// Purpose : Sets the zone type of our vehicle response (default, countryside, city, etc) that determines vehicle types
// Parameters : enum/int representing the type of zone
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetVehicleResponseType(int zone, int iVehicleResponseType)
{
sm_popZones[zone].m_vehicleResponseType = static_cast<u8>(iVehicleResponseType);
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetSpecialAttribute
// Purpose : Sets the special type of the zone (none, airport)
// Parameters : enum/int representing the type of zone
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetSpecialAttribute(int zone, int iSpecialAttributeType)
{
sm_popZones[zone].m_specialAttributeType = static_cast<u8>(iSpecialAttributeType);
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetScumminess
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetScumminess (int zone, int iScumminess)
{
if (Verifyf( (zone >= 0) && (zone < sm_popZones.GetCount()), "CPopZones::SetScumminess - zone index %d is out of range 0 to %d", zone, sm_popZones.GetCount()))
{
sm_popZones[zone].m_scumminess = iScumminess;
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetScumminess
/////////////////////////////////////////////////////////////////////////////////
int CPopZones::GetScumminess (int zone)
{
if (Verifyf( (zone >= 0) && (zone < sm_popZones.GetCount()), "CPopZones::GetScumminess - zone index %d is out of range 0 to %d", zone, sm_popZones.GetCount()))
{
return sm_popZones[zone].m_scumminess;
}
return SCUMMINESS_ABOVE_AVERAGE;
}
void CPopZones::SetPopulationRangeScaleParameters(int zone, float fBaseRangeScale, float fLowZ, float fHightZ, float fMaxMultiplier)
{
Assert(fHightZ >= fLowZ);
Assert(fMaxMultiplier >= 1.0f && fMaxMultiplier <= 4.0f);
sm_popZones[zone].m_fPopBaseRangeScale = Min(fBaseRangeScale, CVehiclePopulation::ms_fGatherLinksUseKeyHoleShapeRangeThreshold);
sm_popZones[zone].m_iPopHeightScaleLowZ = (s16) fLowZ;
sm_popZones[zone].m_iPopHeightScaleHighZ = (s16) fHightZ;
sm_popZones[zone].m_fPopHeightScaleMultiplier = Min(fMaxMultiplier, CVehiclePopulation::ms_fGatherLinksUseKeyHoleShapeRangeThreshold);
}
void CPopZones::SetAllowScenarioWeatherExits(int zone, int iAllowScenarioWeatherExits)
{
if (Verifyf( (zone >= 0) && (zone < sm_popZones.GetCount()), "CPopZones::SetAllowScenarioWeatherExits - zone index %d is out of range 0 to %d", zone, sm_popZones.GetCount()))
{
sm_popZones[zone].m_bAllowScenarioWeatherExits = (iAllowScenarioWeatherExits != 0);
}
}
void CPopZones::SetAllowHurryAwayToLeavePavement(int zone, int iAllow)
{
if (Verifyf( (zone >= 0) && (zone < sm_popZones.GetCount()), "CPopZones::SetAllowHurryAwayToLeavePavement - zone index %d is out of range 0 to %d", zone, sm_popZones.GetCount()))
{
sm_popZones[zone].m_bLetHurryAwayLeavePavements = (iAllow != 0);
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetZoneScumminessFromString
// Purpose : Gets the zone scumminess level from a string value
// Parameters : String value of the zone scumminess
/////////////////////////////////////////////////////////////////////////////////
int CPopZones::GetZoneScumminessFromString(char* pString)
{
if (pString)
{
if (stricmp(pString, "SL_POSH") == 0)
{
return SCUMMINESS_POSH;
}
else if (stricmp(pString, "SL_NICE") == 0)
{
return SCUMMINESS_NICE;
}
else if (stricmp(pString, "SL_ABOVE_AV") == 0)
{
return SCUMMINESS_ABOVE_AVERAGE;
}
else if (stricmp(pString, "SL_BELOW_AV") == 0)
{
return SCUMMINESS_BELOW_AVERAGE;
}
else if (stricmp(pString, "SL_CRAP") == 0)
{
return SCUMMINESS_CRAP;
}
else if (stricmp(pString, "SL_SCUM") == 0)
{
return SCUMMINESS_SCUM;
}
else
{
Assertf(0, "Invalid zone scumminess type (%s)", pString);
}
}
return SCUMMINESS_ABOVE_AVERAGE;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetSpecialZoneAttributeFromString
// Purpose : Gets the special type from a string value
// Parameters : String value of the special type
/////////////////////////////////////////////////////////////////////////////////
int CPopZones::GetSpecialZoneAttributeFromString(char* pString)
{
if (stricmp(pString, "SPECIAL_NONE") == 0)
{
return SPECIAL_NONE;
}
else if (stricmp(pString, "SPECIAL_AIRPORT") == 0)
{
return SPECIAL_AIRPORT;
}
else
{
Assertf(0, "Invalid special attribute type (%s)", pString);
}
return SPECIAL_NONE;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetPopScheduleIndicesInternal
// Purpose : TODO
// Parameters : TODO
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetPopScheduleIndices(int zone, s32 popScheduleIndexForSP, s32 popScheduleIndexForMP)
{
// casting down to s8 here
// will assert if we need more space - update PopZones.h if needed
Assertf(popScheduleIndexForSP <= 127 && popScheduleIndexForMP <= 127, "Casting s32 down to s8, losing data");
sm_popZoneSearchInfos[zone].m_popScheduleIndexForSP = static_cast<s8>(popScheduleIndexForSP);
sm_popZoneSearchInfos[zone].m_popScheduleIndexForMP = static_cast<s8>(popScheduleIndexForMP);
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetAllowCops
// Purpose : TODO
// Parameters : TODO
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetAllowCops(int zone, bool allowCops)
{
sm_popZones[zone].m_bNoCops = !allowCops;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetMPGangTerritoryIndex
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetMPGangTerritoryIndex(s32 zone, s32 territoryIndex)
{
if (Verifyf( (zone >= 0) && (zone < sm_popZones.GetCount()), "CPopZones::SetMPGangTerritoryIndex - zone index %d is out of range 0 to %d", zone, sm_popZones.GetCount()))
{
sm_popZones[zone].m_MPGangTerritoryIndex = (s16) territoryIndex;
}
}
/////////////////////////////////////////////////////////////////////////////////
// Name : SetEnabled
// Purpose : Turn on/off a zone
// Parameters :
// Returns : Nothing
/////////////////////////////////////////////////////////////////////////////////
void CPopZones::SetEnabled(int zone, bool bEnabled)
{
sm_popZoneSearchInfos[zone].m_bEnabled = bEnabled;
}
/////////////////////////////////////////////////////////////////////////////////
// Name : GetEnabled
// Purpose : See if a zone is enabled
// Parameters :
// Returns : true/false
/////////////////////////////////////////////////////////////////////////////////
bool CPopZones::GetEnabled(int zone)
{
return sm_popZoneSearchInfos[zone].m_bEnabled;
}