re3/src/core/World.cpp

2088 lines
77 KiB
C++

#include "common.h"
#include "patcher.h"
#include "Entity.h"
#include "Ped.h"
#include "PlayerPed.h"
#include "Vehicle.h"
#include "Object.h"
#include "Camera.h"
#include "DMAudio.h"
#include "CarCtrl.h"
#include "Garages.h"
#include "TempColModels.h"
#include "World.h"
#include "ModelIndices.h"
#include "References.h"
#include "CutsceneMgr.h"
#include "Record.h"
#include "RpAnimBlend.h"
#include "Messages.h"
#include "Replay.h"
#include "Population.h"
#include "Fire.h"
#include "ProjectileInfo.h"
#include "WaterLevel.h"
#include "CopPed.h"
#include "Object.h"
#include "Shadows.h"
#include "Explosion.h"
#define OBJECT_REPOSITION_OFFSET_Z 0.2f
CColPoint *gaTempSphereColPoints = (CColPoint*)0x6E64C0; // [32]
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C;
CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608;
uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
CPlayerInfo (&CWorld::Players)[NUMPLAYERS] = *(CPlayerInfo (*)[NUMPLAYERS])*(uintptr*)0x9412F0;
bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC;
CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494;
bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F;
bool &CWorld::bSecondShift = *(bool*)0x95CD54;
bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C;
bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
bool &CWorld::bDoingCarCollisions = *(bool*)0x95CD8C;
bool &CWorld::bIncludeCarTyres = *(bool*)0x95CDAA;
//WRAPPER void CWorld::ClearForRestart(void) { EAXJMP(0x4AE850); }
//WRAPPER void CWorld::AddParticles(void) { EAXJMP(0x4B4010); }
//WRAPPER void CWorld::ShutDown(void) { EAXJMP(0x4AE450); }
//WRAPPER void CWorld::RepositionCertainDynamicObjects() { EAXJMP(0x4B42B0); }
//WRAPPER void CWorld::RemoveStaticObjects() { EAXJMP(0x4B4D50); }
//WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); }
//WRAPPER void CWorld::FindObjectsKindaColliding(const CVector &, float, bool, int16*, int16, CEntity **, bool, bool, bool, bool, bool){ EAXJMP(0x4B2A30); }
//WRAPPER void CWorld::ClearExcitingStuffFromArea(const CVector &pos, float radius, uint8 unused) { EAXJMP(0x4B4E70) };
//WRAPPER void CWorld::FindObjectsIntersectingCube(const CVector &, const CVector &, int16*, int16, CEntity **, bool, bool, bool, bool, bool) { EAXJMP(0x4B2E70); }
//WRAPPER void CWorld::FindObjectsIntersectingAngledCollisionBox(const CColBox &, const CMatrix &, const CVector &, float, float, float, float, int16*, int16, CEntity **, bool, bool, bool, bool, bool) { EAXJMP(0x4B3280); }
//WRAPPER void CWorld::FindObjectsOfTypeInRange(uint32, CVector&, float, bool, short*, short, CEntity**, bool, bool, bool, bool, bool) { EAXJMP(0x4B2600); }
//WRAPPER void CWorld::FindObjectsOfTypeInRangeSectorList(uint32, CPtrList&, CVector&, float, bool, short*, short, CEntity**) { EAXJMP(0x4B2960); }
//WRAPPER void CWorld::FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool) { EAXJMP(0x4B3680); }
//WRAPPER void CWorld::ClearCarsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B50E0); }
//WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B52B0); }
//WRAPPER void CWorld::CallOffChaseForArea(float, float, float, float) { EAXJMP(0x4B5530); }
WRAPPER void CWorld::TriggerExplosion(const CVector& position, float fRadius, float fPower, CEntity *pCreator, bool bProcessVehicleBombTimer) { EAXJMP(0x4B1140); }
//WRAPPER void CWorld::SetPedsOnFire(float, float, float, float, CEntity*) { EAXJMP(0x4B3D30); }
void
CWorld::Initialise()
{
pIgnoreEntity = nil;
bDoingCarCollisions = false;
bSecondShift = false;
bNoMoreCollisionTorque = false;
bProcessCutsceneOnly = false;
bIncludeDeadPeds = false;
bForceProcessControl = false;
bIncludeCarTyres = false;
}
void
CWorld::Add(CEntity *ent)
{
if(ent->IsVehicle() || ent->IsPed())
DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, true);
if(ent->bIsBIGBuilding)
ms_bigBuildingsList[ent->m_level].InsertItem(ent);
else
ent->Add();
if(ent->IsBuilding() || ent->IsDummy())
return;
if(!ent->bIsStatic)
((CPhysical*)ent)->AddToMovingList();
}
void
CWorld::Remove(CEntity *ent)
{
if(ent->IsVehicle() || ent->IsPed())
DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, false);
if(ent->bIsBIGBuilding)
ms_bigBuildingsList[ent->m_level].RemoveItem(ent);
else
ent->Remove();
if(ent->IsBuilding() || ent->IsDummy())
return;
if(!ent->bIsStatic)
((CPhysical*)ent)->RemoveFromMovingList();
}
void
CWorld::ClearScanCodes(void)
{
CPtrNode *node;
for(int i = 0; i < NUMSECTORS_Y; i++)
for(int j = 0; j < NUMSECTORS_X; j++){
CSector *s = &ms_aSectors[i][j];
for(node = s->m_lists[ENTITYLIST_BUILDINGS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_VEHICLES].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_PEDS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_OBJECTS].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
for(node = s->m_lists[ENTITYLIST_DUMMIES].first; node; node = node->next)
((CEntity*)node->item)->m_scanCode = 0;
}
}
void
CWorld::ClearExcitingStuffFromArea(const CVector& pos, float radius, bool bRemoveProjectilesAndTidyUpShadows)
{
CPedPool* pedPool = CPools::GetPedPool();
for (int32 i = 0; i < pedPool->GetSize(); i++) {
CPed* pPed = pedPool->GetSlot(i);
if (pPed && !pPed->IsPlayer() && pPed->CanBeDeleted() &&
CVector2D(pPed->GetPosition() - pos).MagnitudeSqr() < radius) {
CPopulation::RemovePed(pPed);
}
}
CVehiclePool* VehiclePool = CPools::GetVehiclePool();
for (int32 i = 0; i < VehiclePool->GetSize(); i++) {
CVehicle* pVehicle = VehiclePool->GetSlot(i);
if (pVehicle && CVector2D(pVehicle->GetPosition() - pos).MagnitudeSqr() < radius &&
!pVehicle->bIsLocked && pVehicle->CanBeDeleted()) {
if (pVehicle->pDriver) {
CPopulation::RemovePed(pVehicle->pDriver);
pVehicle->pDriver = nil;
}
for (int32 j = 0; j < pVehicle->m_nNumMaxPassengers; ++j) {
if (pVehicle->pPassengers[j]) {
CPopulation::RemovePed(pVehicle->pPassengers[j]);
pVehicle->pPassengers[j] = nil;
--pVehicle->m_nNumPassengers;
}
}
CCarCtrl::RemoveFromInterestingVehicleList(pVehicle);
CWorld::Remove(pVehicle);
delete pVehicle;
}
}
CObject::DeleteAllTempObjectsInArea(pos, radius);
gFireManager.ExtinguishPoint(pos, radius);
CWorld::ExtinguishAllCarFiresInArea(pos, radius);
CExplosion::RemoveAllExplosionsInArea(pos, radius);
if (bRemoveProjectilesAndTidyUpShadows) {
CProjectileInfo::RemoveAllProjectiles();
CShadows::TidyUpShadows();
}
}
bool
CWorld::CameraToIgnoreThisObject(CEntity *ent)
{
if(CGarages::IsModelIndexADoor(ent->GetModelIndex()))
return false;
return ((CObject*)ent)->m_bCameraToAvoidThisObject != 1;
}
bool
CWorld::ProcessLineOfSight(const CVector &point1, const CVector &point2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
int x, xstart, xend;
int y, ystart, yend;
int y1, y2;
float dist;
AdvanceCurrentScanCode();
entity = nil;
dist = 1.0f;
xstart = GetSectorIndexX(point1.x);
ystart = GetSectorIndexY(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexY(point2.y);
#define LOSARGS CColLine(point1, point2), point, dist, entity, checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects
if(xstart == xend && ystart == yend){
// Only one sector
return ProcessLineOfSightSector(*GetSector(xstart, ystart), LOSARGS);
}else if(xstart == xend){
// Only step in y
if(ystart < yend)
for(y = ystart; y <= yend; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = ystart; y >= yend; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
return dist < 1.0f;
}else if(ystart == yend){
// Only step in x
if(xstart < xend)
for(x = xstart; x <= xend; x++)
ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS);
else
for(x = xstart; x >= xend; x--)
ProcessLineOfSightSector(*GetSector(x, ystart), LOSARGS);
return dist < 1.0f;
}else{
if(point1.x < point2.x){
// Step from left to right
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
for(x = xstart+1; x < xend; x++){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
}
y1 = y2;
y2 = yend;
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
}else{
// Step from right to left
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xstart, y), LOSARGS);
for(x = xstart-1; x > xend; x--){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y);
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(x, y), LOSARGS);
}
y1 = y2;
y2 = yend;
if(y1 < y2)
for(y = y1; y <= y2; y++)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
else
for(y = y1; y >= y2; y--)
ProcessLineOfSightSector(*GetSector(xend, y), LOSARGS);
}
return dist < 1.0f;
}
#undef LOSARGS
}
bool
CWorld::ProcessLineOfSightSector(CSector &sector, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
float mindist = dist;
bool deadPeds = !!bIncludeDeadPeds;
bIncludeDeadPeds = false;
if(checkBuildings){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
if(checkVehicles){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
if(checkPeds){
if(deadPeds)
bIncludeDeadPeds = true;
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
bIncludeDeadPeds = false;
}
if(checkObjects){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, ignoreSomeObjects);
}
if(checkDummies){
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough);
ProcessLineOfSightSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough);
}
bIncludeDeadPeds = deadPeds;
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
bool deadPeds = false;
float mindist = dist;
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
if(list.first && bIncludeDeadPeds && ((CEntity*)list.first->item)->IsPed())
deadPeds = true;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e != pIgnoreEntity &&
(e->bUsesCollision || deadPeds) &&
!(ignoreSomeObjects && CameraToIgnoreThisObject(e))){
colmodel = nil;
e->m_scanCode = GetCurrentScanCode();
if(e->IsPed()){
if(e->bUsesCollision ||
deadPeds && ((CPed*)e)->m_nPedState == PED_DEAD){
if (((CPed*)e)->UseGroundColModel())
colmodel = &CTempColModels::ms_colModelPedGroundHit;
else
#ifdef ANIMATE_PED_COL_MODEL
colmodel = CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(), RpClumpGetFrame(e->GetClump()));
#else
colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel();
#endif
}else
colmodel = nil;
}else if(e->bUsesCollision)
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(colmodel &&
CCollision::ProcessLineOfSight(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough))
entity = e;
}
}
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
AdvanceCurrentScanCode();
CVector point2(point1.x, point1.y, z2);
return ProcessVerticalLineSector(*GetSector(GetSectorIndexX(point1.x), GetSectorIndexX(point1.y)),
CColLine(point1, point2), point, entity,
checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, poly);
}
bool
CWorld::ProcessVerticalLineSector(CSector &sector, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
float mindist = 1.0f;
if(checkBuildings){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkVehicles){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkPeds){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkObjects){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
if(checkDummies){
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES], line, point, mindist, entity, ignoreSeeThrough, poly);
ProcessVerticalLineSectorList(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, point, mindist, entity, ignoreSeeThrough, poly);
}
return mindist < 1.0f;
}
bool
CWorld::ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
float mindist = dist;
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e->bUsesCollision){
e->m_scanCode = GetCurrentScanCode();
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(CCollision::ProcessVerticalLine(line, e->GetMatrix(), *colmodel, point, dist, ignoreSeeThrough, poly))
entity = e;
}
}
if(mindist < dist){
dist = mindist;
return true;
}else
return false;
}
bool
CWorld::GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
int x, xstart, xend;
int y, ystart, yend;
int y1, y2;
AdvanceCurrentScanCode();
xstart = GetSectorIndexX(point1.x);
ystart = GetSectorIndexY(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexY(point2.y);
#define LOSARGS CColLine(point1, point2), checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, ignoreSomeObjects
if(xstart == xend && ystart == yend){
// Only one sector
return GetIsLineOfSightSectorClear(*GetSector(xstart, ystart), LOSARGS);
}else if(xstart == xend){
// Only step in y
if(ystart < yend){
for(y = ystart; y <= yend; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = ystart; y >= yend; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
}else if(ystart == yend){
// Only step in x
if(xstart < xend){
for(x = xstart; x <= xend; x++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS))
return false;
}else{
for(x = xstart; x >= xend; x--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, ystart), LOSARGS))
return false;
}
}else{
if(point1.x < point2.x){
// Step from left to right
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart+1) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
for(x = xstart+1; x < xend; x++){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x+1) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}
}
y1 = y2;
y2 = yend;
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}
}else{
// Step from right to left
float m = (point2.y - point1.y) / (point2.x - point1.x);
y1 = ystart;
y2 = GetSectorIndexY((GetWorldX(xstart) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xstart, y), LOSARGS))
return false;
}
for(x = xstart-1; x > xend; x--){
y1 = y2;
y2 = GetSectorIndexY((GetWorldX(x) - point1.x)*m + point1.y);
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(x, y), LOSARGS))
return false;
}
}
y1 = y2;
y2 = yend;
if(y1 < y2){
for(y = y1; y <= y2; y++)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}else{
for(y = y1; y >= y2; y--)
if(!GetIsLineOfSightSectorClear(*GetSector(xend, y), LOSARGS))
return false;
}
}
}
return true;
#undef LOSARGS
}
bool
CWorld::GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
if(checkBuildings){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_BUILDINGS_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkVehicles){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_VEHICLES_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkPeds){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_PEDS_OVERLAP], line, ignoreSeeThrough))
return false;
}
if(checkObjects){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS], line, ignoreSeeThrough, ignoreSomeObjects))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_OBJECTS_OVERLAP], line, ignoreSeeThrough, ignoreSomeObjects))
return false;
}
if(checkDummies){
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES], line, ignoreSeeThrough))
return false;
if(!GetIsLineOfSightSectorListClear(sector.m_lists[ENTITYLIST_DUMMIES_OVERLAP], line, ignoreSeeThrough))
return false;
}
return true;
}
bool
CWorld::GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects)
{
CPtrNode *node;
CEntity *e;
CColModel *colmodel;
for(node = list.first; node; node = node->next){
e = (CEntity*)node->item;
if(e->m_scanCode != GetCurrentScanCode() &&
e->bUsesCollision){
e->m_scanCode = GetCurrentScanCode();
if(e != pIgnoreEntity &&
!(ignoreSomeObjects && CameraToIgnoreThisObject(e))){
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
if(CCollision::TestLineOfSight(line, e->GetMatrix(), *colmodel, ignoreSeeThrough))
return false;
}
}
}
return true;
}
void
CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
{
float radiusSqr = radius * radius;
float objDistSqr;
for (CPtrNode *node = list.first; node; node = node->next) {
CEntity *object = (CEntity*)node->item;
if (object->m_scanCode != GetCurrentScanCode()) {
object->m_scanCode = GetCurrentScanCode();
CVector diff = centre - object->GetPosition();
if (ignoreZ)
objDistSqr = diff.MagnitudeSqr2D();
else
objDistSqr = diff.MagnitudeSqr();
if (objDistSqr < radiusSqr && *nextObject < lastObject) {
if (objects) {
objects[*nextObject] = object;
}
(*nextObject)++;
}
}
}
}
void
CWorld::FindObjectsInRange(CVector &centre, float radius, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
{
int minX = GetSectorIndexX(centre.x - radius);
if (minX <= 0) minX = 0;
int minY = GetSectorIndexY(centre.y - radius);
if (minY <= 0) minY = 0;
int maxX = GetSectorIndexX(centre.x + radius);
#ifdef FIX_BUGS
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
#else
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
#endif
int maxY = GetSectorIndexY(centre.y + radius);
#ifdef FIX_BUGS
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
#else
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y;
#endif
AdvanceCurrentScanCode();
*nextObject = 0;
for(int curY = minY; curY <= maxY; curY++) {
for(int curX = minX; curX <= maxX; curX++) {
CSector *sector = GetSector(curX, curY);
if (checkBuildings) {
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, ignoreZ, nextObject, lastObject, objects);
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkVehicles) {
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, ignoreZ, nextObject, lastObject, objects);
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkPeds) {
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, ignoreZ, nextObject, lastObject, objects);
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkObjects) {
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, ignoreZ, nextObject, lastObject, objects);
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
if (checkDummies) {
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, ignoreZ, nextObject, lastObject, objects);
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, ignoreZ, nextObject, lastObject, objects);
}
}
}
}
void
CWorld::FindObjectsOfTypeInRangeSectorList(uint32 modelId, CPtrList& list, const CVector& position, float radius, bool bCheck2DOnly, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities)
{
CPtrNode* pNode = list.first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity->m_scanCode != ms_nCurrentScanCode) {
pEntity->m_scanCode = ms_nCurrentScanCode;
float fMagnitude = 0.0f;
if (bCheck2DOnly)
fMagnitude = CVector2D(position - pEntity->GetPosition()).Magnitude();
else
fMagnitude = CVector(position - pEntity->GetPosition()).Magnitude();
if (fMagnitude < radius * radius && *nEntitiesFound < maxEntitiesToFind) {
if (aEntities)
aEntities[*nEntitiesFound] = pEntity;
++*nEntitiesFound;
}
}
pNode = pNode->next;
}
}
void
CWorld::FindObjectsOfTypeInRange(uint32 modelId, const CVector& position, float radius, bool bCheck2DOnly, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies)
{
CWorld::AdvanceCurrentScanCode();
*nEntitiesFound = 0;
const CVector2D vecSectorStartPos(position.x - radius, position.y - radius);
const CVector2D vecSectorEndPos(position.x + radius, position.y + radius);
const int32 nStartX = max(CWorld::GetSectorIndexX(vecSectorStartPos.x), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(vecSectorStartPos.y), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
if (bBuildings) {
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_BUILDINGS], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bVehicles) {
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_VEHICLES], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bPeds) {
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_PEDS], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bObjects) {
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_OBJECTS], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bDummies) {
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_DUMMIES], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsOfTypeInRangeSectorList(modelId, pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], position, radius, bCheck2DOnly, nEntitiesFound, maxEntitiesToFind, aEntities);
}
}
}
}
CEntity*
CWorld::TestSphereAgainstWorld(CVector centre, float radius, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
{
CEntity* foundE = nil;
int minX = GetSectorIndexX(centre.x - radius);
if (minX <= 0) minX = 0;
int minY = GetSectorIndexY(centre.y - radius);
if (minY <= 0) minY = 0;
int maxX = GetSectorIndexX(centre.x + radius);
#ifdef FIX_BUGS
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
#else
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
#endif
int maxY = GetSectorIndexY(centre.y + radius);
#ifdef FIX_BUGS
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
#else
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y;
#endif
AdvanceCurrentScanCode();
for (int curY = minY; curY <= maxY; curY++) {
for (int curX = minX; curX <= maxX; curX++) {
CSector* sector = GetSector(curX, curY);
if (checkBuildings) {
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkVehicles) {
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkPeds) {
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
if (checkObjects) {
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, radius, entityToIgnore, ignoreSomeObjects);
if (foundE)
return foundE;
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, radius, entityToIgnore, ignoreSomeObjects);
if (foundE)
return foundE;
}
if (checkDummies) {
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, radius, entityToIgnore, false);
if (foundE)
return foundE;
}
}
}
return foundE;
}
CEntity*
CWorld::TestSphereAgainstSectorList(CPtrList &list, CVector spherePos, float radius, CEntity *entityToIgnore, bool ignoreSomeObjects)
{
static CColModel sphereCol;
sphereCol.boundingSphere.center.x = 0.0f;
sphereCol.boundingSphere.center.y = 0.0f;
sphereCol.boundingSphere.center.z = 0.0f;
sphereCol.boundingSphere.radius = radius;
sphereCol.boundingBox.min.x = -radius;
sphereCol.boundingBox.min.y = -radius;
sphereCol.boundingBox.min.z = -radius;
sphereCol.boundingBox.max.x = radius;
sphereCol.boundingBox.max.y = radius;
sphereCol.boundingBox.max.z = radius;
sphereCol.numSpheres = 1;
sphereCol.spheres = &sphereCol.boundingSphere;
sphereCol.numLines = 0;
sphereCol.numBoxes = 0;
sphereCol.numTriangles = 0;
sphereCol.ownsCollisionVolumes = false;
CMatrix sphereMat;
sphereMat.SetTranslate(spherePos);
for(CPtrNode *node=list.first; node; node = node->next) {
CEntity *e = (CEntity*)node->item;
if (e->m_scanCode != GetCurrentScanCode()) {
e->m_scanCode = GetCurrentScanCode();
if (e != entityToIgnore && e->bUsesCollision && !(ignoreSomeObjects && CameraToIgnoreThisObject(e))) {
CVector diff = spherePos - e->GetPosition();
float distance = diff.Magnitude();
if (e->GetBoundRadius() + radius > distance) {
CColModel *eCol = CModelInfo::GetModelInfo(e->m_modelIndex)->GetColModel();
int collidedSpheres = CCollision::ProcessColModels(sphereMat, sphereCol, e->GetMatrix(),
*eCol, gaTempSphereColPoints, nil, nil);
if (collidedSpheres != 0 ||
(e->IsVehicle() && ((CVehicle*)e)->m_vehType == VEHICLE_TYPE_CAR &&
e->m_modelIndex != MI_DODO && radius + eCol->boundingBox.max.x > distance)) {
return e;
}
}
}
}
}
return nil;
}
float
CWorld::FindGroundZForCoord(float x, float y)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, 1000.0f), -1000.0f, point, ent, true, false, false, false, true, false, nil))
return point.point.z;
else
return 20.0f;
}
float
CWorld::FindGroundZFor3DCoord(float x, float y, float z, bool *found)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, z), -1000.0f, point, ent, true, false, false, false, false, false, nil)){
if(found)
*found = true;
return point.point.z;
}else{
if(found)
*found = false;
return 0.0f;
}
}
float
CWorld::FindRoofZFor3DCoord(float x, float y, float z, bool *found)
{
CColPoint point;
CEntity *ent;
if(ProcessVerticalLine(CVector(x, y, z), 1000.0f, point, ent, true, false, false, false, true, false, nil)){
if(found)
*found = true;
return point.point.z;
}else{
if(found == nil)
printf("THERE IS NO MAP BELOW THE FOLLOWING COORS:%f %f %f. (FindGroundZFor3DCoord)\n", x, y, z);
if(found)
*found = false;
return 20.0f;
}
}
void
CWorld::RemoveReferencesToDeletedObject(CEntity* pDeletedObject)
{
int32 i = CPools::GetPedPool()->GetSize();
while (--i >= 0) {
CPed* pPed = CPools::GetPedPool()->GetSlot(i);
if (pPed && pPed != pDeletedObject) {
pPed->RemoveRefsToEntity(pDeletedObject);
if (pPed->m_pCurrentPhysSurface == pDeletedObject)
pPed->m_pCurrentPhysSurface = nil;
}
}
i = CPools::GetVehiclePool()->GetSize();
while (--i >= 0) {
CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
if (pVehicle && pVehicle != pDeletedObject) {
pVehicle->RemoveRefsToEntity(pDeletedObject);
pVehicle->RemoveRefsToVehicle(pDeletedObject);
}
}
i = CPools::GetObjectPool()->GetSize();
while (--i >= 0) {
CObject* pObject = CPools::GetObjectPool()->GetSlot(i);
if (pObject && pObject != pDeletedObject) {
pObject->RemoveRefsToEntity(pDeletedObject);
}
}
}
void
CWorld::FindObjectsKindaColliding(const CVector& position, float radius, bool bCheck2DOnly, int16* nCollidingEntities, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies)
{
CWorld::AdvanceCurrentScanCode();
*nCollidingEntities = 0;
const CVector2D vecSectorStartPos(position.x - radius, position.y - radius);
const CVector2D vecSectorEndPos(position.x + radius, position.y + radius);
const int32 nStartX = max(CWorld::GetSectorIndexX(vecSectorStartPos.x), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(vecSectorStartPos.y), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(vecSectorEndPos.x), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(vecSectorEndPos.y), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
if (bBuildings) {
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
}
if (bVehicles) {
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
}
if (bPeds) {
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_PEDS], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
}
if (bObjects) {
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
}
if (bDummies) {
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_DUMMIES], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
CWorld::FindObjectsKindaCollidingSectorList(pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], position, radius, bCheck2DOnly, nCollidingEntities, maxEntitiesToFind, aEntities);
}
}
}
}
void
CWorld::FindObjectsKindaCollidingSectorList(CPtrList& list, const CVector& position, float radius, bool bCheck2DOnly, int16* nCollidingEntities, int16 maxEntitiesToFind, CEntity** aEntities)
{
CPtrNode* pNode = list.first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity->m_scanCode != ms_nCurrentScanCode) {
pEntity->m_scanCode = ms_nCurrentScanCode;
float fMagnitude = 0.0f;
if (bCheck2DOnly)
fMagnitude = CVector2D(position - pEntity->GetPosition()).Magnitude();
else
fMagnitude = CVector(position - pEntity->GetPosition()).Magnitude();
if (pEntity->GetBoundRadius() + radius > fMagnitude && *nCollidingEntities < maxEntitiesToFind) {
if (aEntities)
aEntities[*nCollidingEntities] = pEntity;
++*nCollidingEntities;
}
}
pNode = pNode->next;
}
}
void
CWorld::FindObjectsIntersectingCube(const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies)
{
CWorld::AdvanceCurrentScanCode();
*nIntersecting = 0;
const int32 nStartX = max(CWorld::GetSectorIndexX(vecStartPos.x), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(vecStartPos.y), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
if (bBuildings) {
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
}
if (bVehicles) {
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
}
if (bPeds) {
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_PEDS], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
}
if (bObjects) {
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
}
if (bDummies) {
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_DUMMIES], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities);
}
}
}
}
void
CWorld::FindObjectsIntersectingCubeSectorList(CPtrList& list, const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities)
{
CPtrNode* pNode = list.first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity->m_scanCode != CWorld::ms_nCurrentScanCode) {
pEntity->m_scanCode = CWorld::ms_nCurrentScanCode;
float fRadius = pEntity->GetBoundRadius();
const CVector& entityPos = pEntity->GetPosition();
if (fRadius + entityPos.x >= vecStartPos.x && entityPos.x - fRadius <= vecEndPos.x &&
fRadius + entityPos.y >= vecStartPos.y && entityPos.y - fRadius <= vecEndPos.y &&
fRadius + entityPos.z >= vecStartPos.z && entityPos.z - fRadius <= vecEndPos.z &&
*nIntersecting < maxEntitiesToFind) {
if (aEntities)
aEntities[*nIntersecting] = pEntity;
++*nIntersecting;
}
}
pNode = pNode->next;
}
}
void
CWorld::FindObjectsIntersectingAngledCollisionBox(const CColBox& boundingBox, const CMatrix& matrix, const CVector& position, float fStartX, float fStartY, float fEndX, float fEndY, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities, bool bBuildings, bool bVehicles, bool bPeds, bool bObjects, bool bDummies)
{
CWorld::AdvanceCurrentScanCode();
*nEntitiesFound = 0;
const int32 nStartX = max(CWorld::GetSectorIndexX(fStartX), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(fStartY), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
if (bBuildings) {
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bVehicles) {
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bPeds) {
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_PEDS], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bObjects) {
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
}
if (bDummies) {
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_DUMMIES], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], boundingBox, matrix, position, nEntitiesFound, maxEntitiesToFind, aEntities);
}
}
}
}
void
CWorld::FindObjectsIntersectingAngledCollisionBoxSectorList(CPtrList& list, const CColBox& boundingBox, const CMatrix& matrix, const CVector& position, int16* nEntitiesFound, int16 maxEntitiesToFind, CEntity** aEntities)
{
CPtrNode* pNode = list.first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity->m_scanCode != CWorld::ms_nCurrentScanCode) {
pEntity->m_scanCode = CWorld::ms_nCurrentScanCode;
CColSphere sphere;
CVector vecDistance = pEntity->m_matrix.GetPosition() - position;
sphere.radius = pEntity->GetBoundRadius();
sphere.center = Multiply3x3(vecDistance, matrix);
if (CCollision::TestSphereBox(sphere, boundingBox) && *nEntitiesFound < maxEntitiesToFind) {
if (aEntities)
aEntities[*nEntitiesFound] = pEntity;
++*nEntitiesFound;
}
}
pNode = pNode->next;
}
}
void
CWorld::FindMissionEntitiesIntersectingCube(const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bVehicles, bool bPeds, bool bObjects)
{
CWorld::AdvanceCurrentScanCode();
*nIntersecting = 0;
const int32 nStartX = max(CWorld::GetSectorIndexX(vecStartPos.x), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(vecStartPos.y), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
if (bVehicles) {
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, true, false);
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, true, false);
}
if (bPeds) {
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_PEDS], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, false, true);
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, false, true);
}
if (bObjects) {
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, false, false);
CWorld::FindMissionEntitiesIntersectingCubeSectorList(pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], vecStartPos, vecEndPos, nIntersecting, maxEntitiesToFind, aEntities, false, false);
}
}
}
}
void
CWorld::FindMissionEntitiesIntersectingCubeSectorList(CPtrList& list, const CVector& vecStartPos, const CVector& vecEndPos, int16* nIntersecting, int16 maxEntitiesToFind, CEntity** aEntities, bool bIsVehicleList, bool bIsPedList)
{
CPtrNode* pNode = list.first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity->m_scanCode != CWorld::ms_nCurrentScanCode) {
pEntity->m_scanCode = CWorld::ms_nCurrentScanCode;
bool bIsMissionEntity = false;
if (bIsVehicleList)
bIsMissionEntity = ((CVehicle*)pEntity)->VehicleCreatedBy == MISSION_VEHICLE;
else if (bIsPedList)
bIsMissionEntity = ((CPed*)pEntity)->CharCreatedBy == MISSION_CHAR;
else
bIsMissionEntity = ((CObject*)pEntity)->ObjectCreatedBy == MISSION_OBJECT;
float fRadius = pEntity->GetBoundRadius();
const CVector& entityPos = pEntity->GetPosition();
if (bIsMissionEntity &&
fRadius + entityPos.x >= vecStartPos.x && entityPos.x - fRadius <= vecEndPos.x &&
fRadius + entityPos.y >= vecStartPos.y && entityPos.y - fRadius <= vecEndPos.y &&
fRadius + entityPos.z >= vecStartPos.z && entityPos.z - fRadius <= vecEndPos.z &&
*nIntersecting < maxEntitiesToFind) {
if (aEntities)
aEntities[*nIntersecting] = (CEntity*)pEntity;
++*nIntersecting;
}
}
pNode = pNode->next;
}
}
CPlayerPed*
FindPlayerPed(void)
{
return CWorld::Players[CWorld::PlayerInFocus].m_pPed;
}
CVehicle*
FindPlayerVehicle(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped && ped->InVehicle())
return ped->m_pMyVehicle;
return nil;
}
CVehicle*
FindPlayerTrain(void)
{
if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain())
return FindPlayerVehicle();
else
return nil;
}
CEntity*
FindPlayerEntity(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle;
else
return ped;
}
CVector
FindPlayerCoors(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle->GetPosition();
else
return ped->GetPosition();
}
CVector&
FindPlayerSpeed(void)
{
CPlayerPed *ped = FindPlayerPed();
if(ped->InVehicle())
return ped->m_pMyVehicle->m_vecMoveSpeed;
else
return ped->m_vecMoveSpeed;
}
CVector&
FindPlayerCentreOfWorld(int32 player)
{
if(CCarCtrl::bCarsGeneratedAroundCamera)
return TheCamera.GetPosition();
if(CWorld::Players[player].m_pRemoteVehicle)
return CWorld::Players[player].m_pRemoteVehicle->GetPosition();
if(FindPlayerVehicle())
return FindPlayerVehicle()->GetPosition();
return CWorld::Players[player].m_pPed->GetPosition();
}
CVector&
FindPlayerCentreOfWorld_NoSniperShift(void)
{
if(CCarCtrl::bCarsGeneratedAroundCamera)
return TheCamera.GetPosition();
if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition();
if(FindPlayerVehicle())
return FindPlayerVehicle()->GetPosition();
return FindPlayerPed()->GetPosition();
}
float
FindPlayerHeading(void)
{
if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle)
return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading();
if(FindPlayerVehicle())
return FindPlayerVehicle()->GetForward().Heading();
return FindPlayerPed()->GetForward().Heading();
}
void CWorld::ClearCarsFromArea(float x1, float y1, float z1, float x2, float y2, float z2)
{
CVehiclePool *pVehiclePool = CPools::GetVehiclePool();
for (int32 i = 0; i < pVehiclePool->GetSize(); i++) {
CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i);
if (pVehicle) {
const CVector& position = pVehicle->GetPosition();
if (position.x >= x1 && position.x <= x2 &&
position.y >= y1 && position.y <= y2 &&
position.z >= z1 && position.z <= z2 &&
!pVehicle->bIsLocked && pVehicle->CanBeDeleted()) {
if (pVehicle->pDriver) {
CPopulation::RemovePed(pVehicle->pDriver);
pVehicle->pDriver = nil;
}
for (int32 j = 0; j < pVehicle->m_nNumMaxPassengers; ++j) {
if (pVehicle->pPassengers[j]) {
CPopulation::RemovePed(pVehicle->pPassengers[j]);
pVehicle->pPassengers[j] = nil;
--pVehicle->m_nNumPassengers;
}
}
CCarCtrl::RemoveFromInterestingVehicleList(pVehicle);
CWorld::Remove(pVehicle);
delete pVehicle;
}
}
}
}
void
CWorld::ClearPedsFromArea(float x1, float y1, float z1, float x2, float y2, float z2)
{
CPedPool* pPedPool = CPools::GetPedPool();
for (int32 i = 0; i < pPedPool->GetSize(); i++) {
CPed* pPed = CPools::GetPedPool()->GetSlot(i);
if (pPed) {
const CVector& position = pPed->GetPosition();
if (!pPed->IsPlayer() && pPed->CanBeDeleted() &&
position.x >= x1 && position.x <= x2 &&
position.y >= y1 && position.y <= y2 &&
position.z >= z1 && position.z <= z2) {
CPopulation::RemovePed(pPed);
}
}
}
}
void
CWorld::CallOffChaseForArea(float x1, float y1, float x2, float y2)
{
CWorld::AdvanceCurrentScanCode();
float fStartX = x1 - 10.0f;
float fStartY = y1 - 10.0f;
float fEndX = x2 + 10.0f;
float fEndY = y2 + 10.0f;
const int32 nStartX = max(CWorld::GetSectorIndexX(fStartX), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(fStartY), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(fEndX), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(fEndY), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
CWorld::CallOffChaseForAreaSectorListVehicles(pSector->m_lists[ENTITYLIST_VEHICLES], x1, y1, x2, y2, fStartX, fStartY, fEndX, fEndY);
CWorld::CallOffChaseForAreaSectorListVehicles(pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], x1, y1, x2, y2, fStartX, fStartY, fEndX, fEndY);
CWorld::CallOffChaseForAreaSectorListPeds(pSector->m_lists[ENTITYLIST_PEDS], x1, y1, x2, y2);
CWorld::CallOffChaseForAreaSectorListPeds(pSector->m_lists[ENTITYLIST_PEDS_OVERLAP], x1, y1, x2, y2);
}
}
}
void
CWorld::CallOffChaseForAreaSectorListVehicles(CPtrList& list, float x1, float y1, float x2, float y2, float fStartX, float fStartY, float fEndX, float fEndY)
{
CPtrNode* pNode = list.first;
while (pNode) {
CVehicle *pVehicle = (CVehicle*)pNode->item;
if (pVehicle->m_scanCode != CWorld::ms_nCurrentScanCode) {
pVehicle->m_scanCode = CWorld::ms_nCurrentScanCode;
const CVector& vehiclePos = pVehicle->m_matrix.GetPosition();
eCarMission carMission = pVehicle->AutoPilot.m_nCarMission;
if (pVehicle != FindPlayerVehicle() &&
vehiclePos.x > fStartX && vehiclePos.x < fEndX &&
vehiclePos.y > fStartY && vehiclePos.y < fEndY &&
pVehicle->bIsLawEnforcer &&
(carMission == MISSION_RAMPLAYER_FARAWAY || carMission == MISSION_RAMPLAYER_CLOSE ||
carMission == MISSION_BLOCKPLAYER_FARAWAY || carMission == MISSION_BLOCKPLAYER_CLOSE)
) {
pVehicle->AutoPilot.m_nTimeTempAction = CTimer::GetTimeInMilliseconds() + 2000;
CColModel* pColModel = pVehicle->GetColModel();
bool bInsideSphere = false;
for (int32 i = 0; i < pColModel->numSpheres; i++) {
CVector pos = pVehicle->m_matrix * pColModel->spheres[i].center;
float fRadius = pColModel->spheres[i].radius;
if (pos.x + fRadius > x1 && pos.x - fRadius < x2 && pos.y + fRadius > y1 && pos.y - fRadius < y2)
bInsideSphere = true;
// Maybe break the loop when bInsideSphere is set to true?
}
if (bInsideSphere) {
if (pVehicle->m_matrix.GetPosition().x <= (x1 + x2) * 0.5f)
pVehicle->m_vecMoveSpeed.x = min(pVehicle->m_vecMoveSpeed.x, 0.0f);
else
pVehicle->m_vecMoveSpeed.x = max(pVehicle->m_vecMoveSpeed.x, 0.0f);
if (pVehicle->m_matrix.GetPosition().y <= (y1 + y2) * 0.5f)
pVehicle->m_vecMoveSpeed.y = min(pVehicle->m_vecMoveSpeed.y, 0.0f);
else
pVehicle->m_vecMoveSpeed.y = max(pVehicle->m_vecMoveSpeed.y, 0.0f);
}
}
}
pNode = pNode->next;
}
}
void
CWorld::CallOffChaseForAreaSectorListPeds(CPtrList& list, float x1, float y1, float x2, float y2)
{
CPtrNode* pNode = list.first;
while (pNode) {
CPed* pPed = (CPed*)pNode->item;
const CVector& pedPos = pPed->GetPosition();
if (pPed->m_scanCode != CWorld::ms_nCurrentScanCode)
{
pPed->m_scanCode = CWorld::ms_nCurrentScanCode;
if (pPed != FindPlayerPed() && pPed->m_leader != FindPlayerPed() &&
pedPos.x > x1 && pedPos.x < x2 &&
pedPos.y > y1 && pedPos.y < y2 &&
(pPed->m_pedInObjective == FindPlayerPed() || pPed->m_carInObjective && pPed->m_carInObjective == FindPlayerVehicle()) &&
pPed->m_nPedState != PED_DEAD && pPed->m_nPedState != PED_DIE &&
(pPed->m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT ||
pPed->m_objective == OBJECTIVE_ENTER_CAR_AS_DRIVER ||
pPed->m_objective == OBJECTIVE_KILL_CHAR_ANY_MEANS)) {
if (pPed->IsPedInControl()) {
if (pPed->m_nPedType == PEDTYPE_COP)
((CCopPed*)pPed)->ClearPursuit();
else
pPed->SetIdle();
pPed->SetObjective(OBJECTIVE_NONE);
}
else {
pPed->m_prevObjective = OBJECTIVE_NONE;
pPed->m_nLastPedState = PED_IDLE;
}
}
}
}
}
void
CWorld::RemoveEntityInsteadOfProcessingIt(CEntity* ent)
{
if (ent->IsPed()) {
if (FindPlayerPed() == ent)
Remove(ent);
else
CPopulation::RemovePed((CPed*)ent);
} else {
Remove(ent);
delete ent;
}
}
void
CWorld::RemoveFallenPeds(void)
{
int poolSize = CPools::GetPedPool()->GetSize();
for(int poolIndex = poolSize-1; poolIndex >= 0; poolIndex--) {
CPed *ped = CPools::GetPedPool()->GetSlot(poolIndex);
if (ped) {
if (ped->GetPosition().z < MAP_Z_LOW_LIMIT) {
if (ped->CharCreatedBy != RANDOM_CHAR || ped->IsPlayer()) {
int closestNode = ThePaths.FindNodeClosestToCoors(ped->GetPosition(), PATH_PED, 999999.9f, false, false);
CVector newPos = ThePaths.m_pathNodes[closestNode].pos;
newPos.z += 2.0f;
ped->Teleport(newPos);
ped->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
} else {
CPopulation::RemovePed(ped);
}
}
}
}
}
void
CWorld::RemoveFallenCars(void)
{
int poolSize = CPools::GetVehiclePool()->GetSize();
for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) {
CVehicle* veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
if (veh) {
if (veh->GetPosition().z < MAP_Z_LOW_LIMIT) {
if (veh->VehicleCreatedBy == MISSION_VEHICLE || veh == FindPlayerVehicle() || (veh->pDriver && veh->pDriver->IsPlayer())) {
int closestNode = ThePaths.FindNodeClosestToCoors(veh->GetPosition(), PATH_CAR, 999999.9f, false, false);
CVector newPos = ThePaths.m_pathNodes[closestNode].pos;
newPos.z += 3.0f;
veh->Teleport(newPos);
veh->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
} else if (veh->VehicleCreatedBy == RANDOM_VEHICLE || veh->VehicleCreatedBy == PARKED_VEHICLE) {
Remove(veh);
delete veh;
}
}
}
}
}
void
CWorld::StopAllLawEnforcersInTheirTracks(void)
{
int poolSize = CPools::GetVehiclePool()->GetSize();
for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) {
CVehicle* veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
if (veh) {
if (veh->bIsLawEnforcer)
veh->SetMoveSpeed(0.0f, 0.0f, 0.0f);
}
}
}
void
CWorld::SetAllCarsCanBeDamaged(bool toggle)
{
int poolSize = CPools::GetVehiclePool()->GetSize();
for (int poolIndex = 0; poolIndex < poolSize; poolIndex++) {
CVehicle *veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
if (veh)
veh->bCanBeDamaged = toggle;
}
}
void
CWorld::ExtinguishAllCarFiresInArea(CVector point, float range)
{
int poolSize = CPools::GetVehiclePool()->GetSize();
for (int poolIndex = 0; poolIndex < poolSize; poolIndex++) {
CVehicle* veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
if (veh) {
if ((point - veh->GetPosition()).MagnitudeSqr() < sq(range))
veh->ExtinguishCarFire();
}
}
}
void
CWorld::AddParticles(void)
{
for (int32 y = 0; y < NUMSECTORS_Y; y++) {
for (int32 x = 0; x < NUMSECTORS_X; x++) {
CSector* pSector = GetSector(x, y);
CEntity::AddSteamsFromGround1(pSector->m_lists[ENTITYLIST_BUILDINGS]);
CEntity::AddSteamsFromGround1(pSector->m_lists[ENTITYLIST_DUMMIES]);
}
}
}
void
CWorld::ShutDown(void)
{
for (int32 y = 0; y < NUMSECTORS_Y; y++) {
for (int32 x = 0; x < NUMSECTORS_X; x++) {
CSector *pSector = GetSector(x, y);
CPtrNode *pNode = pSector->m_lists[ENTITYLIST_BUILDINGS].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_VEHICLES].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_PEDS].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_OBJECTS].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_DUMMIES].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush();
}
}
for (int32 i = 0; i < 4; i ++) {
CPtrNode* pNode = GetBigBuildingList((eLevelName)i).first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
// Maybe remove from world here?
delete pEntity;
}
pNode = pNode->next;
}
GetBigBuildingList((eLevelName)i).Flush();
}
for (int32 y = 0; y < NUMSECTORS_Y; y++) {
for (int32 x = 0; x < NUMSECTORS_X; x++) {
CSector* pSector = GetSector(x, y);
if (pSector->m_lists[ENTITYLIST_BUILDINGS].first) {
sprintf(gString, "Building list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
}
if (pSector->m_lists[ENTITYLIST_DUMMIES].first) {
sprintf(gString, "Dummy list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_DUMMIES].Flush();
}
if (pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].first) {
sprintf(gString, "Building overlap list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush();
}
if (pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP].first) {
sprintf(gString, "Vehicle overlap list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_VEHICLES_OVERLAP].Flush();
}
if (pSector->m_lists[ENTITYLIST_PEDS_OVERLAP].first) {
sprintf(gString, "Ped overlap list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_PEDS_OVERLAP].Flush();
}
if (pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP].first) {
sprintf(gString, "Object overlap list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_OBJECTS_OVERLAP].Flush();
}
if (pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].first) {
sprintf(gString, "Dummy overlap list %d,%d not empty\n", x, y);
pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush();
}
}
}
ms_listMovingEntityPtrs.Flush();
}
void
CWorld::ClearForRestart(void)
{
if (CCutsceneMgr::HasLoaded())
CCutsceneMgr::DeleteCutsceneData();
CProjectileInfo::RemoveAllProjectiles();
CObject::DeleteAllTempObjects();
CObject::DeleteAllMissionObjects();
CPopulation::ConvertAllObjectsToDummyObjects();
for (int32 y = 0; y < NUMSECTORS_Y; y++) {
for (int32 x = 0; x < NUMSECTORS_X; x++) {
CSector *pSector = GetSector(x, y);
CPtrNode *pNode = pSector->m_lists[ENTITYLIST_PEDS].first;
while (pNode) {
CEntity *pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = GetBigBuildingList(LEVEL_NONE).first;
while (pNode) {
CVehicle *pVehicle = (CVehicle*)pNode->item;
if (pVehicle && pVehicle->IsVehicle() && pVehicle->IsPlane()) {
CWorld::Remove(pVehicle);
delete pVehicle;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_VEHICLES].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
}
}
CPools::CheckPoolsEmpty();
}
void
CWorld::RepositionCertainDynamicObjects()
{
int32 i = CPools::GetDummyPool()->GetSize();
while (--i >= 0) {
CDummy* dummy = CPools::GetDummyPool()->GetSlot(i);
if (dummy) {
RepositionOneObject(dummy);
}
}
}
void
CWorld::RepositionOneObject(CEntity* pEntity)
{
int16 modeId = pEntity->m_modelIndex;
if (MI_SINGLESTREETLIGHTS1 == modeId || MI_SINGLESTREETLIGHTS2 == modeId || MI_SINGLESTREETLIGHTS3 == modeId
|| MI_DOUBLESTREETLIGHTS == modeId || MI_TREE1 == modeId || MI_TREE2 == modeId || MI_TREE3 == modeId
|| MI_TREE4 == modeId || MI_TREE5 == modeId || MI_TREE6 == modeId || MI_TREE7 == modeId
|| MI_TREE8 == modeId || MI_TREE9 == modeId || MI_TREE10 == modeId || MI_TREE11 == modeId
|| MI_TREE12 == modeId || MI_TREE13 == modeId || MI_TREE14 == modeId || MI_TRAFFICLIGHTS == modeId
|| MI_PARKINGMETER == modeId || MI_PHONEBOOTH1 == modeId || MI_WASTEBIN == modeId || MI_BIN == modeId
|| MI_POSTBOX1 == modeId || MI_NEWSSTAND == modeId || MI_TRAFFICCONE == modeId || MI_DUMP1 == modeId
|| MI_ROADWORKBARRIER1 == modeId || MI_BUSSIGN1 == modeId || MI_NOPARKINGSIGN1 == modeId
|| MI_PHONESIGN == modeId || MI_TAXISIGN == modeId || MI_FISHSTALL01 == modeId || MI_FISHSTALL02 == modeId
|| MI_FISHSTALL03 == modeId || MI_FISHSTALL04 == modeId || MI_BAGELSTAND2 == modeId || MI_FIRE_HYDRANT == modeId
|| MI_BOLLARDLIGHT == modeId || MI_PARKTABLE == modeId) {
CVector& position = pEntity->m_matrix.GetPosition();
float fBoundingBoxMinZ = pEntity->GetColModel()->boundingBox.min.z;
position.z = CWorld::FindGroundZFor3DCoord(position.x, position.y, position.z + OBJECT_REPOSITION_OFFSET_Z, nil) - fBoundingBoxMinZ;
pEntity->m_matrix.UpdateRW();
pEntity->UpdateRwFrame();
} else if (MI_BUOY == modeId) {
float fWaterLevel = 0.0f;
bool found = true;
const CVector& position = pEntity->m_matrix.GetPosition();
float fGroundZ = CWorld::FindGroundZFor3DCoord(position.x, position.y, position.z + OBJECT_REPOSITION_OFFSET_Z, &found);
if (CWaterLevel::GetWaterLevelNoWaves(position.x, position.y, position.z + OBJECT_REPOSITION_OFFSET_Z, &fWaterLevel)) {
if (!found || fWaterLevel > fGroundZ) {
CColModel* pColModel = pEntity->GetColModel();
float fHeight = pColModel->boundingBox.max.z - pColModel->boundingBox.min.z;
pEntity->m_matrix.GetPosition().z = 0.2f * fHeight + fWaterLevel - 0.5f * fHeight;
}
}
}
}
void
CWorld::SetCarsOnFire(float x, float y, float z, float radius, CEntity *reason)
{
int poolSize = CPools::GetVehiclePool()->GetSize();
for (int poolIndex = poolSize - 1; poolIndex >= 0; poolIndex--) {
CVehicle *veh = CPools::GetVehiclePool()->GetSlot(poolIndex);
if (veh && veh->m_status != STATUS_WRECKED && !veh->m_pCarFire && !veh->bFireProof) {
if (Abs(veh->GetPosition().z - z) < 5.0f && Abs(veh->GetPosition().x - x) < radius && Abs(veh->GetPosition().y - y) < radius)
gFireManager.StartFire(veh, reason, 0.8f, true);
}
}
}
void
CWorld::SetPedsOnFire(float x, float y, float z, float radius, CEntity* reason)
{
int32 poolSize = CPools::GetPedPool()->GetSize();
for (int32 i = poolSize - 1; i >= 0; i--) {
CPed* pPed = CPools::GetPedPool()->GetSlot(i);
if (pPed && pPed->m_nPedState != PED_DEAD && !pPed->bInVehicle && !pPed->m_pFire && !pPed->bFireProof) {
if (Abs(pPed->GetPosition().z - z) < 5.0f && Abs(pPed->GetPosition().x - x) < radius && Abs(pPed->GetPosition().y - y) < radius)
gFireManager.StartFire(pPed, reason, 0.8f, true);
}
}
}
void
CWorld::RemoveStaticObjects()
{
for (int32 y = 0; y < NUMSECTORS_Y; y++) {
for (int32 x = 0; x < NUMSECTORS_X; x++) {
CSector* pSector = GetSector(x, y);
CPtrNode* pNode = pSector->m_lists[ENTITYLIST_BUILDINGS].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_OBJECTS].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pNode = pSector->m_lists[ENTITYLIST_DUMMIES].first;
while (pNode) {
CEntity* pEntity = (CEntity*)pNode->item;
if (pEntity) {
CWorld::Remove(pEntity);
delete pEntity;
}
pNode = pNode->next;
}
pSector->m_lists[ENTITYLIST_BUILDINGS].Flush();
pSector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES].Flush();
pSector->m_lists[ENTITYLIST_DUMMIES_OVERLAP].Flush();
}
}
}
void
CWorld::Process(void)
{
if (!(CTimer::GetFrameCounter() & 63))
CReferences::PruneAllReferencesInWorld();
if (bProcessCutsceneOnly) {
for (int i = 0; i < NUMCUTSCENEOBJECTS; i++) {
CCutsceneObject *csObj = CCutsceneMgr::GetCutsceneObject(i);
if (csObj && csObj->m_entryInfoList.first) {
if (csObj->m_rwObject && RwObjectGetType(csObj->m_rwObject) == rpCLUMP
&& RpAnimBlendClumpGetFirstAssociation(csObj->GetClump())) {
RpAnimBlendClumpUpdateAnimations(csObj->GetClump(), 0.02f * (csObj->m_type == ENTITY_TYPE_OBJECT ? CTimer::GetTimeStepNonClipped() : CTimer::GetTimeStep()));
}
csObj->ProcessControl();
csObj->ProcessCollision();
csObj->GetMatrix().UpdateRW();
csObj->UpdateRwFrame();
}
}
CRecordDataForChase::ProcessControlCars();
CRecordDataForChase::SaveOrRetrieveCarPositions();
} else {
for (CPtrNode *node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity *movingEnt = (CEntity*)node->item;
if (movingEnt->m_rwObject && RwObjectGetType(movingEnt->m_rwObject) == rpCLUMP
&& RpAnimBlendClumpGetFirstAssociation(movingEnt->GetClump())) {
RpAnimBlendClumpUpdateAnimations(movingEnt->GetClump(), 0.02f * (movingEnt->m_type == ENTITY_TYPE_OBJECT ? CTimer::GetTimeStepNonClipped() : CTimer::GetTimeStep()));
}
}
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CPhysical* movingEnt = (CPhysical*)node->item;
if (movingEnt->bRemoveFromWorld) {
RemoveEntityInsteadOfProcessingIt(movingEnt);
} else {
movingEnt->ProcessControl();
if (movingEnt->bIsStatic) {
movingEnt->RemoveFromMovingList();
}
}
}
bForceProcessControl = true;
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CPhysical* movingEnt = (CPhysical*)node->item;
if (movingEnt->bWasPostponed) {
if (movingEnt->bRemoveFromWorld) {
RemoveEntityInsteadOfProcessingIt(movingEnt);
} else {
movingEnt->ProcessControl();
if (movingEnt->bIsStatic) {
movingEnt->RemoveFromMovingList();
}
}
}
}
bForceProcessControl = false;
if (CReplay::IsPlayingBack()) {
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity* movingEnt = (CEntity*)node->item;
movingEnt->bIsInSafePosition = true;
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
}
} else {
bNoMoreCollisionTorque = false;
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity* movingEnt = (CEntity*)node->item;
if (!movingEnt->bIsInSafePosition) {
movingEnt->ProcessCollision();
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
}
}
bNoMoreCollisionTorque = true;
for (int i = 0; i < 4; i++) {
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity* movingEnt = (CEntity*)node->item;
if (!movingEnt->bIsInSafePosition) {
movingEnt->ProcessCollision();
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
}
}
}
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity* movingEnt = (CEntity*)node->item;
if (!movingEnt->bIsInSafePosition) {
movingEnt->bIsStuck = true;
movingEnt->ProcessCollision();
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
if (!movingEnt->bIsInSafePosition) {
movingEnt->bIsStuck = true;
}
}
}
bSecondShift = false;
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CEntity* movingEnt = (CEntity*)node->item;
if (!movingEnt->bIsInSafePosition) {
movingEnt->ProcessShift();
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
if (!movingEnt->bIsInSafePosition) {
movingEnt->bIsStuck = true;
}
}
}
bSecondShift = true;
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CPhysical* movingEnt = (CPhysical*)node->item;
if (!movingEnt->bIsInSafePosition) {
movingEnt->ProcessShift();
movingEnt->GetMatrix().UpdateRW();
movingEnt->UpdateRwFrame();
if (!movingEnt->bIsInSafePosition) {
movingEnt->bIsStuck = true;
if (movingEnt->m_status == STATUS_PLAYER) {
printf("STUCK: Final Step: Player Entity %d Is Stuck\n", movingEnt->m_modelIndex);
movingEnt->m_vecMoveSpeed *= 0.3f;
movingEnt->ApplyMoveSpeed();
movingEnt->ApplyTurnSpeed();
}
}
}
}
}
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
CPed* movingPed = (CPed*)node->item;
if (movingPed->IsPed()) {
if (movingPed->bInVehicle && movingPed->m_nPedState != PED_EXIT_TRAIN || movingPed->EnteringCar()) {
CVehicle *movingCar = movingPed->m_pMyVehicle;
if (movingCar) {
if (movingCar->IsTrain()) {
movingPed->SetPedPositionInTrain();
} else {
switch (movingPed->m_nPedState) {
case PED_ENTER_CAR:
case PED_CARJACK:
movingPed->EnterCar();
break;
case PED_DRAG_FROM_CAR:
movingPed->BeingDraggedFromCar();
break;
case PED_EXIT_CAR:
movingPed->ExitCar();
break;
case PED_ARRESTED:
if (movingPed->m_nLastPedState == PED_DRAG_FROM_CAR) {
movingPed->BeingDraggedFromCar();
break;
}
// fall through
default:
movingPed->SetPedPositionInCar();
break;
}
}
movingPed->GetMatrix().UpdateRW();
movingPed->UpdateRwFrame();
} else {
movingPed->bInVehicle = false;
movingPed->QuitEnteringCar();
}
}
}
}
CMessages::Process();
Players[PlayerInFocus].Process();
CRecordDataForChase::SaveOrRetrieveCarPositions();
if ((CTimer::GetFrameCounter() & 7) == 1) {
RemoveFallenPeds();
} else if ((CTimer::GetFrameCounter() & 7) == 5) {
RemoveFallenCars();
}
}
}
/*
void
CWorld::TriggerExplosion(const CVector& position, float fRadius, float fPower, CEntity* pCreator, bool bProcessVehicleBombTimer)
{
CVector2D vecStartPos(position.x - fRadius, position.y - fRadius);
CVector2D vecEndPos(position.x + fRadius, position.y + fRadius);
const int32 nStartX = max(CWorld::GetSectorIndexX(vecStartPos.x), 0);
const int32 nStartY = max(CWorld::GetSectorIndexY(vecStartPos.y), 0);
const int32 nEndX = min(CWorld::GetSectorIndexX(vecEndPos.x), NUMSECTORS_X - 1);
const int32 nEndY = min(CWorld::GetSectorIndexY(vecEndPos.y), NUMSECTORS_Y - 1);
for (int32 y = nStartY; y <= nEndY; y++) {
for (int32 x = nStartX; x <= nEndX; x++) {
CSector* pSector = CWorld::GetSector(x, y);
CWorld::TriggerExplosionSectorList(pSector->m_lists[ENTITYLIST_VEHICLES], position, fRadius, fPower, pCreator, bDrecementBombTimer);
CWorld::TriggerExplosionSectorList(pSector->m_lists[ENTITYLIST_PEDS], position, fRadius, fPower, pCreator, bDrecementBombTimer);
CWorld::TriggerExplosionSectorList(pSector->m_lists[ENTITYLIST_OBJECTS], position, fRadius, fPower, pCreator, bDrecementBombTimer);
}
}
}
*/
STARTPATCHES
InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP);
InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP);
InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP);
InjectHook(0x4AF970, CWorld::ProcessLineOfSight, PATCH_JUMP);
InjectHook(0x4B0A80, CWorld::ProcessLineOfSightSector, PATCH_JUMP);
InjectHook(0x4B0C70, CWorld::ProcessLineOfSightSectorList, PATCH_JUMP);
InjectHook(0x4B0DE0, CWorld::ProcessVerticalLine, PATCH_JUMP);
InjectHook(0x4B0EF0, CWorld::ProcessVerticalLineSector, PATCH_JUMP);
InjectHook(0x4B1090, CWorld::ProcessVerticalLineSectorList, PATCH_JUMP);
InjectHook(0x4AEAA0, CWorld::GetIsLineOfSightClear, PATCH_JUMP);
InjectHook(0x4B2000, CWorld::GetIsLineOfSightSectorClear, PATCH_JUMP);
InjectHook(0x4B2160, CWorld::GetIsLineOfSightSectorListClear, PATCH_JUMP);
InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP);
InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, PATCH_JUMP);
InjectHook(0x4B4AC0, CWorld::TestSphereAgainstSectorList, PATCH_JUMP);
InjectHook(0x4B4710, CWorld::TestSphereAgainstWorld, PATCH_JUMP);
InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP);
InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP);
InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP);
InjectHook(0x4B5BC0, CWorld::StopAllLawEnforcersInTheirTracks, PATCH_JUMP);
InjectHook(0x4B53F0, CWorld::SetAllCarsCanBeDamaged, PATCH_JUMP);
InjectHook(0x4B5460, CWorld::ExtinguishAllCarFiresInArea, PATCH_JUMP);
InjectHook(0x4B1A60, CWorld::Process, PATCH_JUMP);
ENDPATCHES