2019-05-15 14:52:37 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "patcher.h"
|
|
|
|
#include "Entity.h"
|
2019-05-28 06:39:36 +00:00
|
|
|
#include "Ped.h"
|
2019-06-29 09:09:33 +00:00
|
|
|
#include "PlayerPed.h"
|
|
|
|
#include "Vehicle.h"
|
2019-05-28 06:39:36 +00:00
|
|
|
#include "Object.h"
|
2019-06-29 09:09:33 +00:00
|
|
|
#include "Camera.h"
|
|
|
|
#include "DMAudio.h"
|
|
|
|
#include "CarCtrl.h"
|
2019-05-28 06:39:36 +00:00
|
|
|
#include "Garages.h"
|
|
|
|
#include "TempColModels.h"
|
2019-05-15 14:52:37 +00:00
|
|
|
#include "World.h"
|
2019-07-15 12:11:40 +00:00
|
|
|
#include "ModelIndices.h"
|
2019-09-12 00:43:18 +00:00
|
|
|
#include "References.h"
|
|
|
|
#include "CutsceneMgr.h"
|
|
|
|
#include "Record.h"
|
|
|
|
#include "RpAnimBlend.h"
|
|
|
|
#include "Messages.h"
|
|
|
|
#include "Replay.h"
|
|
|
|
#include "Population.h"
|
2019-05-15 14:52:37 +00:00
|
|
|
|
|
|
|
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;
|
2019-07-15 12:11:40 +00:00
|
|
|
CColPoint &CWorld::ms_testSpherePoint = *(CColPoint*)0x6E64C0;
|
2019-05-15 14:52:37 +00:00
|
|
|
|
2019-06-14 23:34:19 +00:00
|
|
|
uint8 &CWorld::PlayerInFocus = *(uint8 *)0x95CD61;
|
|
|
|
CPlayerInfo *CWorld::Players = (CPlayerInfo *)0x9412F0;
|
2019-05-15 14:52:37 +00:00
|
|
|
bool &CWorld::bNoMoreCollisionTorque = *(bool*)0x95CDCC;
|
2019-05-17 12:08:18 +00:00
|
|
|
CEntity *&CWorld::pIgnoreEntity = *(CEntity**)0x8F6494;
|
2019-05-28 06:39:36 +00:00
|
|
|
bool &CWorld::bIncludeDeadPeds = *(bool*)0x95CD8F;
|
2019-05-17 12:08:18 +00:00
|
|
|
bool &CWorld::bSecondShift = *(bool*)0x95CD54;
|
|
|
|
bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C;
|
|
|
|
bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B;
|
|
|
|
|
2019-08-15 14:51:39 +00:00
|
|
|
bool &CWorld::bDoingCarCollisions = *(bool*)0x95CD8C;
|
|
|
|
bool &CWorld::bIncludeCarTyres = *(bool*)0x95CDAA;
|
|
|
|
|
|
|
|
WRAPPER void CWorld::ShutDown(void) { EAXJMP(0x4AE450); }
|
2019-10-18 22:23:40 +00:00
|
|
|
WRAPPER void CWorld::RepositionCertainDynamicObjects() { EAXJMP(0x4B42B0); }
|
|
|
|
WRAPPER void CWorld::RemoveStaticObjects() { EAXJMP(0x4B4D50); }
|
2019-07-14 09:49:03 +00:00
|
|
|
WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); }
|
2019-07-27 18:28:18 +00:00
|
|
|
WRAPPER void CWorld::FindObjectsKindaColliding(const CVector &, float, bool, int16*, int16, CEntity **, bool, bool, bool, bool, bool){ EAXJMP(0x4B2A30); }
|
2019-10-07 21:29:30 +00:00
|
|
|
WRAPPER void CWorld::ClearExcitingStuffFromArea(const CVector &pos, float radius, uint8) { EAXJMP(0x4B4E70) };
|
2020-01-03 16:48:13 +00:00
|
|
|
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); }
|
2020-02-02 11:47:03 +00:00
|
|
|
WRAPPER void CWorld::FindMissionEntitiesIntersectingCube(const CVector&, const CVector&, int16*, int16, CEntity**, bool, bool, bool) { EAXJMP(0x4B3680); }
|
2020-02-15 11:53:42 +00:00
|
|
|
WRAPPER void CWorld::ClearCarsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B50E0); }
|
2020-02-16 20:08:54 +00:00
|
|
|
WRAPPER void CWorld::ClearPedsFromArea(float, float, float, float, float, float) { EAXJMP(0x4B52B0); }
|
2019-07-14 09:49:03 +00:00
|
|
|
|
2019-08-15 14:51:39 +00:00
|
|
|
void
|
|
|
|
CWorld::Initialise()
|
|
|
|
{
|
|
|
|
pIgnoreEntity = nil;
|
|
|
|
bDoingCarCollisions = false;
|
|
|
|
bSecondShift = false;
|
|
|
|
bNoMoreCollisionTorque = false;
|
|
|
|
bProcessCutsceneOnly = false;
|
|
|
|
bIncludeDeadPeds = false;
|
|
|
|
bForceProcessControl = false;
|
|
|
|
bIncludeCarTyres = false;
|
|
|
|
}
|
|
|
|
|
2019-06-29 09:09:33 +00:00
|
|
|
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();
|
|
|
|
}
|
2019-05-15 14:52:37 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:39:36 +00:00
|
|
|
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);
|
2020-03-07 19:22:43 +00:00
|
|
|
ystart = GetSectorIndexY(point1.y);
|
2019-05-28 06:39:36 +00:00
|
|
|
xend = GetSectorIndexX(point2.x);
|
2020-03-07 19:22:43 +00:00
|
|
|
yend = GetSectorIndexY(point2.y);
|
2019-05-28 06:39:36 +00:00
|
|
|
|
|
|
|
#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 §or, 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){
|
2019-08-17 19:03:57 +00:00
|
|
|
if (((CPed*)e)->UseGroundColModel())
|
2019-05-28 06:39:36 +00:00
|
|
|
colmodel = &CTempColModels::ms_colModelPedGroundHit;
|
|
|
|
else
|
2019-08-17 19:03:57 +00:00
|
|
|
#ifdef ANIMATE_PED_COL_MODEL
|
|
|
|
colmodel = CPedModelInfo::AnimatePedColModel(((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel(), RpClumpGetFrame(e->GetClump()));
|
|
|
|
#else
|
2019-06-22 23:01:21 +00:00
|
|
|
colmodel = ((CPedModelInfo*)CModelInfo::GetModelInfo(e->GetModelIndex()))->GetHitColModel();
|
2019-08-17 19:03:57 +00:00
|
|
|
#endif
|
2019-05-28 06:39:36 +00:00
|
|
|
}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);
|
2019-09-12 12:35:05 +00:00
|
|
|
return ProcessVerticalLineSector(*GetSector(GetSectorIndexX(point1.x), GetSectorIndexX(point1.y)),
|
2019-05-28 06:39:36 +00:00
|
|
|
CColLine(point1, point2), point, entity,
|
|
|
|
checkBuildings, checkVehicles, checkPeds, checkObjects, checkDummies, ignoreSeeThrough, poly);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
CWorld::ProcessVerticalLineSector(CSector §or, 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);
|
2020-03-07 19:22:43 +00:00
|
|
|
ystart = GetSectorIndexY(point1.y);
|
2019-05-28 06:39:36 +00:00
|
|
|
xend = GetSectorIndexX(point2.x);
|
2020-03-07 19:22:43 +00:00
|
|
|
yend = GetSectorIndexY(point2.y);
|
2019-05-28 06:39:36 +00:00
|
|
|
|
|
|
|
#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 §or, 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;
|
|
|
|
}
|
|
|
|
|
2019-07-10 06:06:43 +00:00
|
|
|
void
|
|
|
|
CWorld::FindObjectsInRangeSectorList(CPtrList &list, CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects)
|
|
|
|
{
|
|
|
|
float distSqr = distance * distance;
|
|
|
|
float objDistSqr;
|
|
|
|
|
|
|
|
for (CPtrNode *node = list.first; node; node = node->next) {
|
|
|
|
CEntity *object = (CEntity*)node->item;
|
2019-09-12 12:35:05 +00:00
|
|
|
if (object->m_scanCode != GetCurrentScanCode()) {
|
|
|
|
object->m_scanCode = GetCurrentScanCode();
|
2019-07-10 06:06:43 +00:00
|
|
|
|
|
|
|
CVector diff = centre - object->GetPosition();
|
|
|
|
if (ignoreZ)
|
|
|
|
objDistSqr = diff.MagnitudeSqr2D();
|
|
|
|
else
|
|
|
|
objDistSqr = diff.MagnitudeSqr();
|
|
|
|
|
|
|
|
if (objDistSqr < distSqr && *nextObject < lastObject) {
|
|
|
|
if (objects) {
|
|
|
|
objects[*nextObject] = object;
|
|
|
|
}
|
|
|
|
(*nextObject)++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CWorld::FindObjectsInRange(CVector ¢re, float distance, bool ignoreZ, short *nextObject, short lastObject, CEntity **objects, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies)
|
|
|
|
{
|
|
|
|
int minX = GetSectorIndexX(centre.x - distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
if (minX <= 0) minX = 0;
|
2019-07-10 06:06:43 +00:00
|
|
|
|
|
|
|
int minY = GetSectorIndexY(centre.y - distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
if (minY <= 0) minY = 0;
|
2019-07-10 06:06:43 +00:00
|
|
|
|
|
|
|
int maxX = GetSectorIndexX(centre.x + distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
#ifdef FIX_BUGS
|
|
|
|
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
|
|
|
|
#else
|
|
|
|
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
|
|
|
|
#endif
|
2019-07-10 06:06:43 +00:00
|
|
|
|
|
|
|
int maxY = GetSectorIndexY(centre.y + distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
#ifdef FIX_BUGS
|
|
|
|
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
|
|
|
|
#else
|
|
|
|
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y;
|
|
|
|
#endif
|
2019-07-10 06:06:43 +00:00
|
|
|
|
|
|
|
AdvanceCurrentScanCode();
|
|
|
|
|
|
|
|
*nextObject = 0;
|
|
|
|
for(int curY = minY; curY <= maxY; curY++) {
|
|
|
|
for(int curX = minX; curX <= maxX; curX++) {
|
|
|
|
CSector *sector = GetSector(curX, curY);
|
|
|
|
if (checkBuildings) {
|
2019-07-15 12:11:40 +00:00
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
2019-07-10 06:06:43 +00:00
|
|
|
}
|
|
|
|
if (checkVehicles) {
|
2019-07-15 12:11:40 +00:00
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
2019-07-10 06:06:43 +00:00
|
|
|
}
|
|
|
|
if (checkPeds) {
|
2019-07-15 12:11:40 +00:00
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
2019-07-10 06:06:43 +00:00
|
|
|
}
|
|
|
|
if (checkObjects) {
|
2019-07-15 12:11:40 +00:00
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
2019-07-10 06:06:43 +00:00
|
|
|
}
|
|
|
|
if (checkDummies) {
|
2019-07-15 12:11:40 +00:00
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
|
|
|
FindObjectsInRangeSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, ignoreZ, nextObject, lastObject, objects);
|
2019-07-10 06:06:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-15 12:11:40 +00:00
|
|
|
CEntity*
|
2019-08-03 22:31:00 +00:00
|
|
|
CWorld::TestSphereAgainstWorld(CVector centre, float distance, CEntity *entityToIgnore, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSomeObjects)
|
2019-07-15 12:11:40 +00:00
|
|
|
{
|
|
|
|
CEntity* foundE = nil;
|
|
|
|
|
|
|
|
int minX = GetSectorIndexX(centre.x - distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
if (minX <= 0) minX = 0;
|
2019-07-15 12:11:40 +00:00
|
|
|
|
|
|
|
int minY = GetSectorIndexY(centre.y - distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
if (minY <= 0) minY = 0;
|
2019-07-15 12:11:40 +00:00
|
|
|
|
|
|
|
int maxX = GetSectorIndexX(centre.x + distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
#ifdef FIX_BUGS
|
|
|
|
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X - 1;
|
|
|
|
#else
|
|
|
|
if (maxX >= NUMSECTORS_X) maxX = NUMSECTORS_X;
|
|
|
|
#endif
|
2019-07-15 12:11:40 +00:00
|
|
|
|
|
|
|
int maxY = GetSectorIndexY(centre.y + distance);
|
2020-03-07 19:22:43 +00:00
|
|
|
#ifdef FIX_BUGS
|
|
|
|
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y - 1;
|
|
|
|
#else
|
|
|
|
if (maxY >= NUMSECTORS_Y) maxY = NUMSECTORS_Y;
|
|
|
|
#endif
|
2019-07-15 12:11:40 +00:00
|
|
|
|
|
|
|
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, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_BUILDINGS_OVERLAP], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
}
|
|
|
|
if (checkVehicles) {
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_VEHICLES_OVERLAP], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
}
|
|
|
|
if (checkPeds) {
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_PEDS_OVERLAP], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
}
|
|
|
|
if (checkObjects) {
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS], centre, distance, entityToIgnore, ignoreSomeObjects);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_OBJECTS_OVERLAP], centre, distance, entityToIgnore, ignoreSomeObjects);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
}
|
|
|
|
if (checkDummies) {
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES], centre, distance, entityToIgnore, false);
|
|
|
|
if (foundE)
|
|
|
|
return foundE;
|
|
|
|
|
|
|
|
foundE = TestSphereAgainstSectorList(sector->m_lists[ENTITYLIST_DUMMIES_OVERLAP], centre, distance, 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, &ms_testSpherePoint, 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;
|
|
|
|
}
|
|
|
|
|
2019-05-28 06:39:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-29 09:09:33 +00:00
|
|
|
CPlayerPed*
|
|
|
|
FindPlayerPed(void)
|
|
|
|
{
|
|
|
|
return CWorld::Players[CWorld::PlayerInFocus].m_pPed;
|
|
|
|
}
|
|
|
|
|
|
|
|
CVehicle*
|
|
|
|
FindPlayerVehicle(void)
|
|
|
|
{
|
2019-12-02 20:02:32 +00:00
|
|
|
CPlayerPed *ped = FindPlayerPed();
|
2020-02-06 17:35:24 +00:00
|
|
|
if(ped && ped->InVehicle())
|
2019-06-29 09:09:33 +00:00
|
|
|
return ped->m_pMyVehicle;
|
2020-02-06 17:35:24 +00:00
|
|
|
return nil;
|
2019-06-29 09:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CVehicle*
|
|
|
|
FindPlayerTrain(void)
|
|
|
|
{
|
|
|
|
if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain())
|
|
|
|
return FindPlayerVehicle();
|
|
|
|
else
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
CEntity*
|
|
|
|
FindPlayerEntity(void)
|
|
|
|
{
|
2019-12-02 20:02:32 +00:00
|
|
|
CPlayerPed *ped = FindPlayerPed();
|
|
|
|
if(ped->InVehicle())
|
2019-06-29 09:09:33 +00:00
|
|
|
return ped->m_pMyVehicle;
|
|
|
|
else
|
|
|
|
return ped;
|
|
|
|
}
|
|
|
|
|
|
|
|
CVector
|
|
|
|
FindPlayerCoors(void)
|
|
|
|
{
|
2019-12-02 20:02:32 +00:00
|
|
|
CPlayerPed *ped = FindPlayerPed();
|
|
|
|
if(ped->InVehicle())
|
2019-06-29 09:09:33 +00:00
|
|
|
return ped->m_pMyVehicle->GetPosition();
|
|
|
|
else
|
|
|
|
return ped->GetPosition();
|
|
|
|
}
|
|
|
|
|
|
|
|
CVector&
|
|
|
|
FindPlayerSpeed(void)
|
|
|
|
{
|
2019-12-02 20:02:32 +00:00
|
|
|
CPlayerPed *ped = FindPlayerPed();
|
|
|
|
if(ped->InVehicle())
|
2019-06-29 09:09:33 +00:00
|
|
|
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();
|
2019-12-02 20:02:32 +00:00
|
|
|
return FindPlayerPed()->GetPosition();
|
2019-06-29 09:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2019-12-02 20:02:32 +00:00
|
|
|
return FindPlayerPed()->GetForward().Heading();
|
2019-06-29 09:09:33 +00:00
|
|
|
}
|
|
|
|
|
2019-09-12 00:43:18 +00:00
|
|
|
void
|
|
|
|
CWorld::RemoveEntityInsteadOfProcessingIt(CEntity* ent)
|
|
|
|
{
|
|
|
|
if (ent->IsPed()) {
|
|
|
|
if (FindPlayerPed() == ent)
|
2019-09-12 12:35:05 +00:00
|
|
|
Remove(ent);
|
2019-09-12 00:43:18 +00:00
|
|
|
else
|
2020-02-16 02:15:58 +00:00
|
|
|
CPopulation::RemovePed((CPed*)ent);
|
2019-09-12 00:43:18 +00:00
|
|
|
} else {
|
2019-09-12 12:35:05 +00:00
|
|
|
Remove(ent);
|
2019-09-12 00:43:18 +00:00
|
|
|
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) {
|
2020-01-03 16:48:13 +00:00
|
|
|
if (ped->GetPosition().z < MAP_Z_LOW_LIMIT) {
|
2019-09-12 00:43:18 +00:00
|
|
|
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) {
|
2020-01-03 16:48:13 +00:00
|
|
|
if (veh->GetPosition().z < MAP_Z_LOW_LIMIT) {
|
2019-09-12 00:43:18 +00:00
|
|
|
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) {
|
2019-09-12 12:35:05 +00:00
|
|
|
Remove(veh);
|
2019-09-12 00:43:18 +00:00
|
|
|
delete veh;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-21 21:39:59 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 20:02:32 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 00:43:18 +00:00
|
|
|
void
|
|
|
|
CWorld::Process(void)
|
|
|
|
{
|
|
|
|
if (!(CTimer::GetFrameCounter() & 63))
|
|
|
|
CReferences::PruneAllReferencesInWorld();
|
|
|
|
|
2019-09-12 12:35:05 +00:00
|
|
|
if (bProcessCutsceneOnly) {
|
2019-09-12 00:43:18 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:35:05 +00:00
|
|
|
bForceProcessControl = true;
|
2019-09-12 00:43:18 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:35:05 +00:00
|
|
|
bForceProcessControl = false;
|
2019-09-12 00:43:18 +00:00
|
|
|
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 {
|
2019-09-12 12:35:05 +00:00
|
|
|
bNoMoreCollisionTorque = false;
|
2019-09-12 00:43:18 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:35:05 +00:00
|
|
|
bNoMoreCollisionTorque = true;
|
2019-09-12 00:43:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:35:05 +00:00
|
|
|
bSecondShift = false;
|
2019-09-12 00:43:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-12 12:35:05 +00:00
|
|
|
bSecondShift = true;
|
2019-09-12 00:43:18 +00:00
|
|
|
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);
|
2019-09-12 16:13:32 +00:00
|
|
|
movingEnt->m_vecMoveSpeed *= 0.3f;
|
2019-09-12 00:43:18 +00:00
|
|
|
movingEnt->ApplyMoveSpeed();
|
|
|
|
movingEnt->ApplyTurnSpeed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (CPtrNode* node = ms_listMovingEntityPtrs.first; node; node = node->next) {
|
|
|
|
CPed* movingPed = (CPed*)node->item;
|
|
|
|
if (movingPed->IsPed()) {
|
2020-03-07 19:22:43 +00:00
|
|
|
if (movingPed->bInVehicle && movingPed->m_nPedState != PED_EXIT_TRAIN || movingPed->EnteringCar()) {
|
2019-09-12 00:43:18 +00:00
|
|
|
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) {
|
2019-09-12 12:35:05 +00:00
|
|
|
RemoveFallenPeds();
|
2019-09-12 00:43:18 +00:00
|
|
|
} else if ((CTimer::GetFrameCounter() & 7) == 5) {
|
2019-09-12 12:35:05 +00:00
|
|
|
RemoveFallenCars();
|
2019-09-12 00:43:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-15 14:52:37 +00:00
|
|
|
STARTPATCHES
|
2019-06-29 09:09:33 +00:00
|
|
|
InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP);
|
|
|
|
InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP);
|
2019-05-15 14:52:37 +00:00
|
|
|
InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP);
|
2019-05-28 06:39:36 +00:00
|
|
|
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);
|
|
|
|
|
2019-07-10 06:06:43 +00:00
|
|
|
InjectHook(0x4B2200, CWorld::FindObjectsInRange, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B2540, CWorld::FindObjectsInRangeSectorList, PATCH_JUMP);
|
2019-07-15 12:11:40 +00:00
|
|
|
InjectHook(0x4B4AC0, CWorld::TestSphereAgainstSectorList, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B4710, CWorld::TestSphereAgainstWorld, PATCH_JUMP);
|
2019-05-28 06:39:36 +00:00
|
|
|
InjectHook(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP);
|
2019-09-12 00:43:18 +00:00
|
|
|
|
2019-12-02 20:02:32 +00:00
|
|
|
InjectHook(0x4B5BC0, CWorld::StopAllLawEnforcersInTheirTracks, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B53F0, CWorld::SetAllCarsCanBeDamaged, PATCH_JUMP);
|
|
|
|
InjectHook(0x4B5460, CWorld::ExtinguishAllCarFiresInArea, PATCH_JUMP);
|
|
|
|
|
2019-09-12 00:43:18 +00:00
|
|
|
InjectHook(0x4B1A60, CWorld::Process, PATCH_JUMP);
|
2019-05-15 14:52:37 +00:00
|
|
|
ENDPATCHES
|