1
0
Fork 0
mirror of https://github.com/halpz/re3.git synced 2024-12-22 17:35:29 +00:00

implemented bits of CWorld

This commit is contained in:
aap 2019-05-28 08:39:36 +02:00
parent 886633293d
commit cb8993f15e
15 changed files with 915 additions and 44 deletions

View file

@ -384,7 +384,7 @@ CCollision::TestSphereTriangle(const CColSphere &sphere,
}
bool
CCollision::TestLineOfSight(CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSurf78)
CCollision::TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough)
{
static CMatrix matTransform;
int i;
@ -398,18 +398,18 @@ CCollision::TestLineOfSight(CColLine &line, const CMatrix &matrix, CColModel &mo
return false;
for(i = 0; i < model.numSpheres; i++)
if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8)
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD)
if(TestLineSphere(newline, model.spheres[i]))
return true;
for(i = 0; i < model.numBoxes; i++)
if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8)
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD)
if(TestLineBox(newline, model.boxes[i]))
return true;
CalculateTrianglePlanes(&model);
for(i = 0; i < model.numTriangles; i++)
if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8)
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD)
if(TestLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i]))
return true;
@ -933,7 +933,7 @@ CCollision::ProcessSphereTriangle(const CColSphere &sphere,
bool
CCollision::ProcessLineOfSight(const CColLine &line,
const CMatrix &matrix, CColModel &model,
CColPoint &point, float &mindist, bool ignoreSurf78)
CColPoint &point, float &mindist, bool ignoreSeeThrough)
{
static CMatrix matTransform;
int i;
@ -948,16 +948,16 @@ CCollision::ProcessLineOfSight(const CColLine &line,
float coldist = mindist;
for(i = 0; i < model.numSpheres; i++)
if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8)
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD)
ProcessLineSphere(newline, model.spheres[i], point, coldist);
for(i = 0; i < model.numBoxes; i++)
if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8)
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD)
ProcessLineBox(newline, model.boxes[i], point, coldist);
CalculateTrianglePlanes(&model);
for(i = 0; i < model.numTriangles; i++)
if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8)
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD)
ProcessLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist);
if(coldist < mindist){
@ -972,7 +972,7 @@ CCollision::ProcessLineOfSight(const CColLine &line,
bool
CCollision::ProcessVerticalLine(const CColLine &line,
const CMatrix &matrix, CColModel &model,
CColPoint &point, float &mindist, bool ignoreSurf78, CStoredCollPoly *poly)
CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly)
{
static CStoredCollPoly TempStoredPoly;
int i;
@ -988,17 +988,17 @@ CCollision::ProcessVerticalLine(const CColLine &line,
float coldist = mindist;
for(i = 0; i < model.numSpheres; i++)
if(!ignoreSurf78 || model.spheres[i].surface != 7 && model.spheres[i].surface != 8)
if(!ignoreSeeThrough || model.spheres[i].surface != SURFACE_GLASS && model.spheres[i].surface != SURFACE_SCAFFOLD)
ProcessLineSphere(newline, model.spheres[i], point, coldist);
for(i = 0; i < model.numBoxes; i++)
if(!ignoreSurf78 || model.boxes[i].surface != 7 && model.boxes[i].surface != 8)
if(!ignoreSeeThrough || model.boxes[i].surface != SURFACE_GLASS && model.boxes[i].surface != SURFACE_SCAFFOLD)
ProcessLineBox(newline, model.boxes[i], point, coldist);
CalculateTrianglePlanes(&model);
TempStoredPoly.valid = false;
for(i = 0; i < model.numTriangles; i++)
if(!ignoreSurf78 || model.triangles[i].surface != 7 && model.triangles[i].surface != 8)
if(!ignoreSeeThrough || model.triangles[i].surface != SURFACE_GLASS && model.triangles[i].surface != SURFACE_SCAFFOLD)
ProcessVerticalLineTriangle(newline, model.vertices, model.triangles[i], model.trianglePlanes[i], point, coldist, &TempStoredPoly);
if(coldist < mindist){
@ -1260,6 +1260,7 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
extern int gDbgSurf;
for(i = 0; i < colModel.numTriangles; i++){
colModel.GetTrianglePoint(verts[0], colModel.triangles[i].a);
@ -1310,6 +1311,7 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
}
// TODO: make some surface types flicker?
//if(s != gDbgSurf) continue;
if(s > SURFACE_32){
r = CGeneral::GetRandomNumber();
@ -1385,6 +1387,7 @@ CCollision::DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel,
}
// TODO: make some surface types flicker?
//if(s != gDbgSurf) continue;
RenderBuffer::StartStoring(36, 8, &iptr, &vptr);
RwIm3DVertexSetRGBA(&vptr[0], r, g, b, 255);

View file

@ -132,7 +132,7 @@ public:
static bool TestLineTriangle(const CColLine &line, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineSphere(const CColLine &line, const CColSphere &sph);
static bool TestSphereTriangle(const CColSphere &sphere, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane);
static bool TestLineOfSight(CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSurf78);
static bool TestLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, bool ignoreSeeThrough);
static bool ProcessSphereSphere(const CColSphere &s1, const CColSphere &s2, CColPoint &point, float &mindistsq);
static bool ProcessSphereBox(const CColSphere &sph, const CColBox &box, CColPoint &point, float &mindistsq);
@ -141,8 +141,8 @@ public:
static bool ProcessLineTriangle(const CColLine &line , const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindist);
static bool ProcessLineSphere(const CColLine &line, const CColSphere &sphere, CColPoint &point, float &mindist);
static bool ProcessSphereTriangle(const CColSphere &sph, const CVector *verts, const CColTriangle &tri, const CColTrianglePlane &plane, CColPoint &point, float &mindistsq);
static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSurf78);
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSurf78, CStoredCollPoly *poly);
static bool ProcessLineOfSight(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough);
static bool ProcessVerticalLine(const CColLine &line, const CMatrix &matrix, CColModel &model, CColPoint &point, float &mindist, bool ignoreSeeThrough, CStoredCollPoly *poly);
static int32 ProcessColModels(const CMatrix &matrix1, CColModel &model1, const CMatrix &matrix2, CColModel &model2, CColPoint *point1, CColPoint *point2, float *linedists);
// TODO:

42
src/Garages.cpp Normal file
View file

@ -0,0 +1,42 @@
#include "common.h"
#include "patcher.h"
#include "ModelIndices.h"
#include "Garages.h"
bool
CGarages::IsModelIndexADoor(uint32 id)
{
return id == MI_GARAGEDOOR1 ||
id == MI_GARAGEDOOR2 ||
id == MI_GARAGEDOOR3 ||
id == MI_GARAGEDOOR4 ||
id == MI_GARAGEDOOR5 ||
id == MI_GARAGEDOOR6 ||
id == MI_GARAGEDOOR7 ||
id == MI_GARAGEDOOR9 ||
id == MI_GARAGEDOOR10 ||
id == MI_GARAGEDOOR11 ||
id == MI_GARAGEDOOR12 ||
id == MI_GARAGEDOOR13 ||
id == MI_GARAGEDOOR14 ||
id == MI_GARAGEDOOR15 ||
id == MI_GARAGEDOOR16 ||
id == MI_GARAGEDOOR17 ||
id == MI_GARAGEDOOR18 ||
id == MI_GARAGEDOOR19 ||
id == MI_GARAGEDOOR20 ||
id == MI_GARAGEDOOR21 ||
id == MI_GARAGEDOOR22 ||
id == MI_GARAGEDOOR23 ||
id == MI_GARAGEDOOR24 ||
id == MI_GARAGEDOOR25 ||
id == MI_GARAGEDOOR26 ||
id == MI_GARAGEDOOR27 ||
id == MI_GARAGEDOOR28 ||
id == MI_GARAGEDOOR29 ||
id == MI_GARAGEDOOR30 ||
id == MI_GARAGEDOOR31 ||
id == MI_GARAGEDOOR32 ||
id == MI_CRUSHERBODY ||
id == MI_CRUSHERLID;
}

7
src/Garages.h Normal file
View file

@ -0,0 +1,7 @@
#pragma once
class CGarages
{
public:
static bool IsModelIndexADoor(uint32 id);
};

View file

@ -44,26 +44,26 @@ enum
// TODO: check and use this
enum eSurfaceType
{
SURFACE_ROAD0,
SURFACE_ROAD1,
SURFACE_DEFAULT,
SURFACE_TARMAC,
SURFACE_GRASS,
SURFACE_DIRT,
SURFACE_MUD,
SURFACE_DIRTTRACK,
SURFACE_PAVEMENT,
SURFACE_METAL6,
SURFACE_GLASS,
SURFACE_HARD8,
SURFACE_METAL_DOOR,
SURFACE_METAL10,
SURFACE_METAL11,
SURFACE_METAL12,
SURFACE_METAL13,
SURFACE_SCAFFOLD,
SURFACE_METAL_DOOR, // garage door
SURFACE_BILLBOARD,
SURFACE_STEEL, //?
SURFACE_METAL_POLE, // ?
SURFACE_STREET_LIGHT,
SURFACE_METAL14,
SURFACE_METAL15,
SURFACE_METAL_FENCE,
SURFACE_FLESH,
SURFACE_SAND18,
SURFACE_WATER,
SURFACE_SAND,
SURFACE_PUDDLE,
SURFACE_WOOD,
SURFACE_WOOD_BOX,
SURFACE_WOOD_PLANK,

17
src/TempColModels.cpp Normal file
View file

@ -0,0 +1,17 @@
#include "common.h"
#include "patcher.h"
#include "TempColModels.h"
CColModel &CTempColModels::ms_colModelPed1 = *(CColModel*)0x726CB0;
CColModel &CTempColModels::ms_colModelPed2 = *(CColModel*)0x726D08;
CColModel &CTempColModels::ms_colModelBBox = *(CColModel*)0x727FE0;
CColModel &CTempColModels::ms_colModelBumper1 = *(CColModel*)0x86BE88;
CColModel &CTempColModels::ms_colModelWheel1 = *(CColModel*)0x878C40;
CColModel &CTempColModels::ms_colModelPanel1 = *(CColModel*)0x87BDD8;
CColModel &CTempColModels::ms_colModelBodyPart2 = *(CColModel*)0x87BE30;
CColModel &CTempColModels::ms_colModelBodyPart1 = *(CColModel*)0x87BE88;
CColModel &CTempColModels::ms_colModelCutObj = *(CColModel*)0x87C960;
CColModel &CTempColModels::ms_colModelPedGroundHit = *(CColModel*)0x880480;
CColModel &CTempColModels::ms_colModelBoot1 = *(CColModel*)0x880670;
CColModel &CTempColModels::ms_colModelDoor1 = *(CColModel*)0x880850;
CColModel &CTempColModels::ms_colModelBonnet1 = *(CColModel*)0x8808A8;

21
src/TempColModels.h Normal file
View file

@ -0,0 +1,21 @@
#pragma once
#include "Collision.h"
class CTempColModels
{
public:
static CColModel &ms_colModelPed1;
static CColModel &ms_colModelPed2;
static CColModel &ms_colModelBBox;
static CColModel &ms_colModelBumper1;
static CColModel &ms_colModelWheel1;
static CColModel &ms_colModelPanel1;
static CColModel &ms_colModelBodyPart2;
static CColModel &ms_colModelBodyPart1;
static CColModel &ms_colModelCutObj;
static CColModel &ms_colModelPedGroundHit;
static CColModel &ms_colModelBoot1;
static CColModel &ms_colModelDoor1;
static CColModel &ms_colModelBonnet1;
};

View file

@ -1,6 +1,10 @@
#include "common.h"
#include "patcher.h"
#include "Entity.h"
#include "Ped.h"
#include "Object.h"
#include "Garages.h"
#include "TempColModels.h"
#include "World.h"
CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60;
@ -10,6 +14,7 @@ uint16 &CWorld::ms_nCurrentScanCode = *(uint16*)0x95CC64;
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;
@ -35,8 +40,548 @@ CWorld::ClearScanCodes(void)
}
}
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 = GetSectorIndexX(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexX(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
colmodel = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel();
}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 CWorld::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 = GetSectorIndexX(point1.y);
xend = GetSectorIndexX(point2.x);
yend = GetSectorIndexX(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;
}
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;
}
}
STARTPATCHES
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(0x4B3A80, CWorld::FindGroundZForCoord, PATCH_JUMP);
InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP);
InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP);
ENDPATCHES
WRAPPER CVector &FindPlayerCoors(CVector &v) { EAXJMP(0x4A1030); }

View file

@ -33,6 +33,9 @@ public:
static_assert(sizeof(CSector) == 0x28, "CSector: error");
class CEntity;
struct CColPoint;
struct CColLine;
struct CStoredCollPoly;
class CWorld
{
@ -43,6 +46,7 @@ class CWorld
public:
static CEntity *&pIgnoreEntity;
static bool &bIncludeDeadPeds;
static bool &bNoMoreCollisionTorque;
static bool &bSecondShift;
static bool &bForceProcessControl;
@ -61,10 +65,28 @@ public:
}
static void ClearScanCodes(void);
static bool CameraToIgnoreThisObject(CEntity *ent);
static bool 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 = false);
static bool 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 = false);
static bool ProcessLineOfSightSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool ProcessVerticalLine(const CVector &point1, float z2, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool ProcessVerticalLineSector(CSector &sector, const CColLine &line, CColPoint &point, CEntity *&entity, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool ProcessVerticalLineSectorList(CPtrList &list, const CColLine &line, CColPoint &point, float &dist, CEntity *&entity, bool ignoreSeeThrough, CStoredCollPoly *poly);
static bool GetIsLineOfSightClear(const CVector &point1, const CVector &point2, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool GetIsLineOfSightSectorClear(CSector &sector, const CColLine &line, bool checkBuildings, bool checkVehicles, bool checkPeds, bool checkObjects, bool checkDummies, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static bool GetIsLineOfSightSectorListClear(CPtrList &list, const CColLine &line, bool ignoreSeeThrough, bool ignoreSomeObjects = false);
static float FindGroundZForCoord(float x, float y);
static float FindGroundZFor3DCoord(float x, float y, float z, bool *found);
static float FindRoofZFor3DCoord(float x, float y, float z, bool *found);
static float GetSectorX(float f) { return ((f + 2000.0f)/40.0f); }
static float GetSectorY(float f) { return ((f + 2000.0f)/40.0f); }
static int GetSectorIndexX(float f) { return (int)GetSectorX(f); }
static int GetSectorIndexY(float f) { return (int)GetSectorY(f); }
static float GetWorldX(int x) { return x*40.0f - 2000.0f; }
static float GetWorldY(int y) { return y*40.0f - 2000.0f; }
};
CVector &FindPlayerCoors(CVector &v);

View file

@ -16,7 +16,6 @@ public:
CMatrix m_objectMatrix;
float m_fUprootLimit;
int8 ObjectCreatedBy;
// int8 m_nObjectFlags;
int8 m_obj_flag1 : 1;
int8 m_obj_flag2 : 1;
int8 m_obj_flag4 : 1;

View file

@ -7,3 +7,167 @@
//void CPed::operator delete(void *p, size_t sz) { CPools::GetPedPool()->Delete((CPed*)p); }
WRAPPER void CPed::KillPedWithCar(CVehicle *veh, float impulse) { EAXJMP(0x4EC430); }
static char ObjectiveText[34][28] = {
"No Obj",
"Wait on Foot",
"Flee on Foot Till Safe",
"Guard Spot",
"Guard Area",
"Wait in Car",
"Wait in Car then Getout",
"Kill Char on Foot",
"Kill Char Any Means",
"Flee Char on Foot Till Safe",
"Flee Char on Foot Always",
"GoTo Char on Foot",
"Follow Char in Formation",
"Leave Car",
"Enter Car as Passenger",
"Enter Car as Driver",
"Follow Car in Car",
"Fire at Obj from Vehicle",
"Destroy Obj",
"Destroy Car",
"GoTo Area Any Means",
"GoTo Area on Foot",
"Run to Area",
"GoTo Area in Car",
"Follow Car on Foot Woffset",
"Guard Attack",
"Set Leader",
"Follow Route",
"Solicit",
"Take Taxi",
"Catch Train",
"Buy IceCream",
"Steal Any Car",
"Mug Char",
};
static char StateText[56][18] = {
"None", // 1
"Idle",
"Look Entity",
"Look Heading",
"Wander Range",
"Wander Path",
"Seek Pos",
"Seek Entity",
"Flee Pos",
"Flee Entity",
"Pursue",
"Follow Path",
"Sniper Mode",
"Rocket Mode",
"Dummy",
"Pause",
"Attack",
"Fight",
"Face Phone",
"Make Call",
"Chat",
"Mug",
"AimGun",
"AI Control",
"Seek Car",
"Seek InBoat",
"Follow Route",
"C.P.R.",
"Solicit",
"Buy IceCream",
"Investigate",
"Step away",
"STATES_NO_AI",
"On Fire",
"Jump",
"Fall",
"GetUp",
"Stagger",
"Dive away",
"STATES_NO_ST",
"Enter Train",
"Exit Train",
"Arrest Plyr",
"Driving",
"Passenger",
"Taxi Passngr",
"Open Door",
"Die",
"Dead",
"CarJack",
"Drag fm Car",
"Enter Car",
"Steal Car",
"Exit Car",
"Hands Up",
"Arrested",
};
static char PersonalityTypeText[32][18] = {
"Player",
"Cop",
"Medic",
"Fireman",
"Gang 1",
"Gang 2",
"Gang 3",
"Gang 4",
"Gang 5",
"Gang 6",
"Gang 7",
"Street Guy",
"Suit Guy",
"Sensible Guy",
"Geek Guy",
"Old Guy",
"Tough Guy",
"Street Girl",
"Suit Girl",
"Sensible Girl",
"Geek Girl",
"Old Girl",
"Tough Girl",
"Tramp",
"Tourist",
"Prostitute",
"Criminal",
"Busker",
"Taxi Driver",
"Psycho",
"Steward",
"Sports Fan",
};
static char WaitStateText[21][16] = {
"No Wait",
"Traffic Lights",
"Pause CrossRoad",
"Look CrossRoad",
"Look Ped",
"Look Shop",
"Look Accident",
"FaceOff Gang",
"Double Back",
"Hit Wall",
"Turn 180deg",
"Surprised",
"Ped Stuck",
"Look About",
"Play Duck",
"Play Cower",
"Play Taxi",
"Play HandsUp",
"Play HandsCower",
"Play Chat",
"Finish Flee",
};
bool
CPed::UseGroundColModel(void)
{
return m_nPedState == PED_FALL ||
m_nPedState == PED_DIVE_AWAY ||
m_nPedState == PED_DIE ||
m_nPedState == PED_DEAD;
}

View file

@ -2,9 +2,65 @@
#include "Physical.h"
enum PedAction
enum PedState
{
PED_PASSENGER = 44,
// This is a bit strange...shouldn't PED_NONE be 0?
PED_NONE = 1,
PED_IDLE,
PED_LOOK_ENTITY,
PED_LOOK_HEADING,
PED_WANDER_RANGE,
PED_WANDER_PATH,
PED_SEEK_POS,
PED_SEEK_ENTITY,
PED_FLEE_POS,
PED_FLEE_ENTITY,
PED_PURSUE,
PED_FOLLOW_PATH,
PED_SNIPER_MODE,
PED_ROCKET_ODE,
PED_DUMMY,
PED_PAUSE,
PED_ATTACK,
PED_FIGHT,
PED_FACE_PHONE,
PED_MAKE_CALL,
PED_CHAT,
PED_MUG,
PED_AIM_GUN,
PED_AI_CONTROL,
PED_SEEK_CAR,
PED_SEEK_IN_BOAT,
PED_FOLLOW_ROUTE,
PED_CPR,
PED_SOLICIT,
PED_BUY_ICECREAM,
PED_INVESTIGATE,
PED_STEP_AWAY,
PED_STATES_NO_AI,
PED_ON_FIRE,
PED_JUMP,
PED_FALL,
PED_GETUP,
PED_STAGGER,
PED_DIVE_AWAY,
PED_STATES_NO_ST,
PED_ENTER_TRAIN,
PED_EXIT_TRAIN,
PED_ARREST_PLAYER,
PED_DRIVING,
PED_PASSENGER,
PED_TAXI_PASSENGER,
PED_OPEN_DOOR,
PED_DIE,
PED_DEAD,
PED_CARJACK,
PED_DRAG_FROM_CAR,
PED_ENTER_CAR,
PED_STEAL_CAR,
PED_EXIT_CAR,
PED_HANDS_UP,
PED_ARRESTED,
};
class CVehicle;
@ -107,6 +163,7 @@ public:
// static void operator delete(void*, size_t);
bool IsPlayer(void) { return m_nPedType == 0 || m_nPedType== 1 || m_nPedType == 2 || m_nPedType == 3; }
bool UseGroundColModel(void);
void KillPedWithCar(CVehicle *veh, float impulse);
};
static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error");

View file

@ -58,18 +58,9 @@ public:
uint8 m_phy_flagA40 : 1;
uint8 m_phy_flagA80 : 1;
uint8 m_phy_flagB1 : 1;
uint8 m_phy_flagB2 : 1;
uint8 m_phy_flagB4 : 1;
uint8 m_phy_flagB8 : 1;
uint8 m_phy_flagB10 : 1;
uint8 m_phy_flagB20 : 1;
uint8 m_phy_flagB40 : 1;
uint8 m_phy_flagB80 : 1;
char byteLastCollType;
char byteZoneLevel;
int16 pad;
uint8 m_nLastCollType;
uint8 m_nZoneLevel;
uint8 pad[3];
// from CEntity

View file

@ -59,6 +59,8 @@ open_script(const char *path, const char *mode)
return open_script_orig(path, mode);
}
int gDbgSurf;
int (*RsEventHandler_orig)(int a, int b);
int
delayedPatches10(int a, int b)
@ -71,6 +73,7 @@ delayedPatches10(int a, int b)
DebugMenuAddVarBool8("Debug", "Don't render Big Buildings", (int8*)&gbDontRenderBigBuildings, nil);
DebugMenuAddVarBool8("Debug", "Don't render Peds", (int8*)&gbDontRenderPeds, nil);
DebugMenuAddVarBool8("Debug", "Don't render Objects", (int8*)&gbDontRenderObjects, nil);
DebugMenuAddVar("Debug", "Dbg Surface", &gDbgSurf, nil, 1, 0, 34, nil);
}
return RsEventHandler_orig(a, b);

View file

@ -93,7 +93,7 @@ CRenderer::RenderOneNonRoad(CEntity *e)
return;
#endif
ped = (CPed*)e;
if(ped->m_nPedState == PED_PASSENGER)
if(ped->m_nPedState == PED_DRIVING)
return;
}
#ifndef MASTER
@ -111,10 +111,10 @@ CRenderer::RenderOneNonRoad(CEntity *e)
// Render Peds in vehicle before vehicle itself
if(e->IsVehicle()){
veh = (CVehicle*)e;
if(veh->pDriver && veh->pDriver->m_nPedState == PED_PASSENGER)
if(veh->pDriver && veh->pDriver->m_nPedState == PED_DRIVING)
veh->pDriver->Render();
for(i = 0; i < 8; i++)
if(veh->pPassengers[i] && veh->pPassengers[i]->m_nPedState == PED_PASSENGER)
if(veh->pPassengers[i] && veh->pPassengers[i]->m_nPedState == PED_DRIVING)
veh->pPassengers[i]->Render();
}
e->Render();