mirror of
https://github.com/halpz/re3.git
synced 2025-07-22 05:29:45 +00:00
first commit
This commit is contained in:
7
src/entities/Building.cpp
Normal file
7
src/entities/Building.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "common.h"
|
||||
#include "rpworld.h"
|
||||
#include "Building.h"
|
||||
#include "Pools.h"
|
||||
|
||||
void *CBuilding::operator new(size_t sz) { return CPools::GetBuildingPool()->New(); }
|
||||
void CBuilding::operator delete(void *p, size_t sz) { CPools::GetBuildingPool()->Delete((CBuilding*)p); }
|
15
src/entities/Building.h
Normal file
15
src/entities/Building.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Entity.h"
|
||||
|
||||
class CBuilding : public CEntity
|
||||
{
|
||||
public:
|
||||
// TODO: ReplaceWithNewModel
|
||||
// TODO: ctor
|
||||
static void *operator new(size_t);
|
||||
static void operator delete(void*, size_t);
|
||||
|
||||
virtual bool GetIsATreadable(void) { return false; }
|
||||
};
|
||||
static_assert(sizeof(CBuilding) == 0x64, "CBuilding: error");
|
2
src/entities/CutsceneHead.cpp
Normal file
2
src/entities/CutsceneHead.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "common.h"
|
||||
#include "CutsceneHead.h"
|
10
src/entities/CutsceneHead.h
Normal file
10
src/entities/CutsceneHead.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "CutsceneObject.h"
|
||||
|
||||
class CCutsceneHead : public CCutsceneObject
|
||||
{
|
||||
public:
|
||||
RwFrame *m_pHeadNode;
|
||||
};
|
||||
static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error");
|
2
src/entities/CutsceneObject.cpp
Normal file
2
src/entities/CutsceneObject.cpp
Normal file
@ -0,0 +1,2 @@
|
||||
#include "common.h"
|
||||
#include "CutsceneObject.h"
|
9
src/entities/CutsceneObject.h
Normal file
9
src/entities/CutsceneObject.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Object.h"
|
||||
|
||||
class CCutsceneObject : public CObject
|
||||
{
|
||||
public:
|
||||
};
|
||||
static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error");
|
391
src/entities/Entity.cpp
Normal file
391
src/entities/Entity.cpp
Normal file
@ -0,0 +1,391 @@
|
||||
#include "common.h"
|
||||
#include "rpworld.h"
|
||||
#include "Placeable.h"
|
||||
#include "Entity.h"
|
||||
#include "Lights.h"
|
||||
#include "World.h"
|
||||
#include "Camera.h"
|
||||
#include "References.h"
|
||||
#include "TxdStore.h"
|
||||
#include "Zones.h"
|
||||
#include "patcher.h"
|
||||
|
||||
int gBuildings;
|
||||
|
||||
void
|
||||
CEntity::GetBoundCentre(CVector &out)
|
||||
{
|
||||
out = m_matrix * CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.center;
|
||||
};
|
||||
|
||||
bool
|
||||
CEntity::GetIsTouching(CVector const ¢er, float radius)
|
||||
{
|
||||
return sq(GetBoundRadius()+radius) > (GetBoundCentre()-center).MagnitudeSqr();
|
||||
}
|
||||
|
||||
bool
|
||||
CEntity::GetIsOnScreen(void)
|
||||
{
|
||||
return TheCamera.IsSphereVisible(GetBoundCentre(), GetBoundRadius(),
|
||||
&TheCamera.GetCameraMatrix());
|
||||
}
|
||||
|
||||
bool
|
||||
CEntity::GetIsOnScreenComplex(void)
|
||||
{
|
||||
RwV3d boundBox[8];
|
||||
|
||||
if(TheCamera.IsPointVisible(GetBoundCentre(), &TheCamera.GetCameraMatrix()))
|
||||
return true;
|
||||
|
||||
CRect rect = GetBoundRect();
|
||||
CColModel *colmodel = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
|
||||
float z = GetPosition().z;
|
||||
float minz = z + colmodel->boundingBox.min.z;
|
||||
float maxz = z + colmodel->boundingBox.max.z;
|
||||
boundBox[0].x = rect.left;
|
||||
boundBox[0].y = rect.top;
|
||||
boundBox[0].z = minz;
|
||||
boundBox[1].x = rect.left;
|
||||
boundBox[1].y = rect.bottom;
|
||||
boundBox[1].z = minz;
|
||||
boundBox[2].x = rect.right;
|
||||
boundBox[2].y = rect.top;
|
||||
boundBox[2].z = minz;
|
||||
boundBox[3].x = rect.right;
|
||||
boundBox[3].y = rect.bottom;
|
||||
boundBox[3].z = minz;
|
||||
boundBox[4].x = rect.left;
|
||||
boundBox[4].y = rect.top;
|
||||
boundBox[4].z = maxz;
|
||||
boundBox[5].x = rect.left;
|
||||
boundBox[5].y = rect.bottom;
|
||||
boundBox[5].z = maxz;
|
||||
boundBox[6].x = rect.right;
|
||||
boundBox[6].y = rect.top;
|
||||
boundBox[6].z = maxz;
|
||||
boundBox[7].x = rect.right;
|
||||
boundBox[7].y = rect.bottom;
|
||||
boundBox[7].z = maxz;
|
||||
|
||||
return TheCamera.IsBoxVisible(boundBox, &TheCamera.GetCameraMatrix());
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::Add(void)
|
||||
{
|
||||
int x, xstart, xmid, xend;
|
||||
int y, ystart, ymid, yend;
|
||||
CSector *s;
|
||||
CPtrList *list;
|
||||
|
||||
CRect bounds = GetBoundRect();
|
||||
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||
assert(xstart >= 0);
|
||||
assert(xend < NUMSECTORS_X);
|
||||
assert(ystart >= 0);
|
||||
assert(yend < NUMSECTORS_Y);
|
||||
|
||||
for(y = ystart; y <= yend; y++)
|
||||
for(x = xstart; x <= xend; x++){
|
||||
s = CWorld::GetSector(x, y);
|
||||
if(x == xmid && y == ymid) switch(m_type){
|
||||
case ENTITY_TYPE_BUILDING:
|
||||
list = &s->m_lists[ENTITYLIST_BUILDINGS];
|
||||
break;
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||
break;
|
||||
case ENTITY_TYPE_DUMMY:
|
||||
list = &s->m_lists[ENTITYLIST_DUMMIES];
|
||||
break;
|
||||
}else switch(m_type){
|
||||
case ENTITY_TYPE_BUILDING:
|
||||
list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_DUMMY:
|
||||
list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
|
||||
break;
|
||||
}
|
||||
list->InsertItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::Remove(void)
|
||||
{
|
||||
int x, xstart, xmid, xend;
|
||||
int y, ystart, ymid, yend;
|
||||
CSector *s;
|
||||
CPtrList *list;
|
||||
|
||||
CRect bounds = GetBoundRect();
|
||||
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||
assert(xstart >= 0);
|
||||
assert(xend < NUMSECTORS_X);
|
||||
assert(ystart >= 0);
|
||||
assert(yend < NUMSECTORS_Y);
|
||||
|
||||
for(y = ystart; y <= yend; y++)
|
||||
for(x = xstart; x <= xend; x++){
|
||||
s = CWorld::GetSector(x, y);
|
||||
if(x == xmid && y == ymid) switch(m_type){
|
||||
case ENTITY_TYPE_BUILDING:
|
||||
list = &s->m_lists[ENTITYLIST_BUILDINGS];
|
||||
break;
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||
break;
|
||||
case ENTITY_TYPE_DUMMY:
|
||||
list = &s->m_lists[ENTITYLIST_DUMMIES];
|
||||
break;
|
||||
}else switch(m_type){
|
||||
case ENTITY_TYPE_BUILDING:
|
||||
list = &s->m_lists[ENTITYLIST_BUILDINGS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_DUMMY:
|
||||
list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP];
|
||||
break;
|
||||
}
|
||||
list->RemoveItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::CreateRwObject(void)
|
||||
{
|
||||
CBaseModelInfo *mi;
|
||||
|
||||
mi = CModelInfo::GetModelInfo(m_modelIndex);
|
||||
m_rwObject = mi->CreateInstance();
|
||||
if(m_rwObject){
|
||||
if(IsBuilding())
|
||||
gBuildings++;
|
||||
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||
m_matrix.AttachRW(RwFrameGetMatrix(RpAtomicGetFrame(m_rwObject)), false);
|
||||
else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||
m_matrix.AttachRW(RwFrameGetMatrix(RpClumpGetFrame(m_rwObject)), false);
|
||||
mi->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::DeleteRwObject(void)
|
||||
{
|
||||
RwFrame *f;
|
||||
|
||||
m_matrix.Detach();
|
||||
if(m_rwObject){
|
||||
if(RwObjectGetType(m_rwObject) == rpATOMIC){
|
||||
f = RpAtomicGetFrame(m_rwObject);
|
||||
RpAtomicDestroy((RpAtomic*)m_rwObject);
|
||||
RwFrameDestroy(f);
|
||||
}else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||
RpClumpDestroy((RpClump*)m_rwObject);
|
||||
m_rwObject = nil;
|
||||
CModelInfo::GetModelInfo(m_modelIndex)->RemoveRef();
|
||||
if(IsBuilding())
|
||||
gBuildings--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::UpdateRwFrame(void)
|
||||
{
|
||||
if(m_rwObject){
|
||||
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||
RwFrameUpdateObjects(RpAtomicGetFrame(m_rwObject));
|
||||
else if(RwObjectGetType(m_rwObject) == rpCLUMP)
|
||||
RwFrameUpdateObjects(RpClumpGetFrame(m_rwObject));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::SetupBigBuilding(void)
|
||||
{
|
||||
CSimpleModelInfo *mi;
|
||||
|
||||
mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(m_modelIndex);
|
||||
bIsBIGBuilding = true;
|
||||
m_flagC20 = true;
|
||||
bUsesCollision = false;
|
||||
m_level = CTheZones::GetLevelFromPosition(GetPosition());
|
||||
if(m_level == LEVEL_NONE){
|
||||
if(mi->GetTxdSlot() != CTxdStore::FindTxdSlot("generic")){
|
||||
mi->SetTexDictionary("generic");
|
||||
printf("%d:%s txd has been set to generic\n", m_modelIndex, mi->GetName());
|
||||
}
|
||||
}
|
||||
if(mi->m_lodDistances[0] > 2000.0f)
|
||||
m_level = LEVEL_NONE;
|
||||
}
|
||||
|
||||
CRect
|
||||
CEntity::GetBoundRect(void)
|
||||
{
|
||||
CRect rect;
|
||||
CVector v;
|
||||
CColModel *col = CModelInfo::GetModelInfo(m_modelIndex)->GetColModel();
|
||||
|
||||
rect.ContainPoint(m_matrix * col->boundingBox.min);
|
||||
rect.ContainPoint(m_matrix * col->boundingBox.max);
|
||||
|
||||
v = col->boundingBox.min;
|
||||
v.x = col->boundingBox.max.x;
|
||||
rect.ContainPoint(m_matrix * v);
|
||||
|
||||
v = col->boundingBox.max;
|
||||
v.x = col->boundingBox.min.x;
|
||||
rect.ContainPoint(m_matrix * v);
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::PreRender(void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::Render(void)
|
||||
{
|
||||
if(m_rwObject){
|
||||
bImBeingRendered = true;
|
||||
if(RwObjectGetType(m_rwObject) == rpATOMIC)
|
||||
RpAtomicRender((RpAtomic*)m_rwObject);
|
||||
else
|
||||
RpClumpRender((RpClump*)m_rwObject);
|
||||
bImBeingRendered = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CEntity::SetupLighting(void)
|
||||
{
|
||||
DeActivateDirectional();
|
||||
SetAmbientColours();
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CEntity::RegisterReference(CEntity **pent)
|
||||
{
|
||||
if(IsBuilding())
|
||||
return;
|
||||
CReference *ref;
|
||||
// check if already registered
|
||||
for(ref = m_pFirstReference; ref; ref = ref->next)
|
||||
if(ref->pentity == pent)
|
||||
return;
|
||||
// have to allocate new reference
|
||||
ref = CReferences::pEmptyList;
|
||||
if(ref){
|
||||
CReferences::pEmptyList = ref->next;
|
||||
|
||||
ref->pentity = pent;
|
||||
ref->next = m_pFirstReference;
|
||||
m_pFirstReference = ref;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear all references to this entity
|
||||
void
|
||||
CEntity::ResolveReferences(void)
|
||||
{
|
||||
CReference *ref;
|
||||
// clear pointers to this entity
|
||||
for(ref = m_pFirstReference; ref; ref = ref->next)
|
||||
if(*ref->pentity == this)
|
||||
*ref->pentity = nil;
|
||||
// free list
|
||||
if(m_pFirstReference){
|
||||
for(ref = m_pFirstReference; ref->next; ref = ref->next)
|
||||
;
|
||||
ref->next = CReferences::pEmptyList;
|
||||
CReferences::pEmptyList = ref;
|
||||
m_pFirstReference = nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Free all references that no longer point to this entity
|
||||
void
|
||||
CEntity::PruneReferences(void)
|
||||
{
|
||||
CReference *ref, *next, **lastnextp;
|
||||
lastnextp = &m_pFirstReference;
|
||||
for(ref = m_pFirstReference; ref; ref = next){
|
||||
next = ref->next;
|
||||
if(*ref->pentity == this)
|
||||
lastnextp = &ref->next;
|
||||
else{
|
||||
*lastnextp = ref->next;
|
||||
ref->next = CReferences::pEmptyList;
|
||||
CReferences::pEmptyList = ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x4742C0, (void (CEntity::*)(CVector&))&CEntity::GetBoundCentre, PATCH_JUMP);
|
||||
InjectHook(0x474310, &CEntity::GetBoundRadius, PATCH_JUMP);
|
||||
InjectHook(0x474C10, &CEntity::GetIsTouching, PATCH_JUMP);
|
||||
InjectHook(0x474CC0, &CEntity::GetIsOnScreen, PATCH_JUMP);
|
||||
InjectHook(0x474D20, &CEntity::GetIsOnScreenComplex, PATCH_JUMP);
|
||||
InjectHook(0x474CA0, &CEntity::IsVisible, PATCH_JUMP);
|
||||
InjectHook(0x474330, &CEntity::UpdateRwFrame, PATCH_JUMP);
|
||||
InjectHook(0x4755E0, &CEntity::SetupBigBuilding, PATCH_JUMP);
|
||||
InjectHook(0x4A7480, &CEntity::RegisterReference, PATCH_JUMP);
|
||||
InjectHook(0x4A74E0, &CEntity::ResolveReferences, PATCH_JUMP);
|
||||
InjectHook(0x4A7530, &CEntity::PruneReferences, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP);
|
||||
InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP);
|
||||
InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP);
|
||||
InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP);
|
||||
InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP);
|
||||
InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP);
|
||||
InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP);
|
||||
ENDPATCHES
|
146
src/entities/Entity.h
Normal file
146
src/entities/Entity.h
Normal file
@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "ModelInfo.h"
|
||||
#include "Placeable.h"
|
||||
|
||||
struct CReference;
|
||||
|
||||
enum eEntityType
|
||||
{
|
||||
ENTITY_TYPE_NOTHING = 0,
|
||||
ENTITY_TYPE_BUILDING,
|
||||
ENTITY_TYPE_VEHICLE,
|
||||
ENTITY_TYPE_PED,
|
||||
ENTITY_TYPE_OBJECT,
|
||||
ENTITY_TYPE_DUMMY,
|
||||
ENTITY_TYPE_6,
|
||||
ENTITY_TYPE_7,
|
||||
};
|
||||
|
||||
enum eEntityStatus
|
||||
{
|
||||
// from SA MTA! let's hope they didn't change from III
|
||||
STATUS_PLAYER = 0,
|
||||
STATUS_PLAYER_PLAYBACKFROMBUFFER,
|
||||
STATUS_SIMPLE,
|
||||
STATUS_PHYSICS,
|
||||
STATUS_ABANDONED,
|
||||
STATUS_WRECKED,
|
||||
STATUS_TRAIN_MOVING,
|
||||
STATUS_TRAIN_NOT_MOVING,
|
||||
STATUS_HELI,
|
||||
STATUS_PLANE,
|
||||
STATUS_PLAYER_REMOTE,
|
||||
STATUS_PLAYER_DISABLED,
|
||||
//STATUS_TRAILER,
|
||||
//STATUS_SIMPLE_TRAILER
|
||||
};
|
||||
|
||||
class CEntity : public CPlaceable
|
||||
{
|
||||
public:
|
||||
RwObject *m_rwObject;
|
||||
uint32 m_type : 3;
|
||||
uint32 m_status : 5;
|
||||
|
||||
// flagsA
|
||||
uint32 bUsesCollision : 1;
|
||||
uint32 bCollisionProcessed : 1;
|
||||
uint32 bIsStatic : 1;
|
||||
uint32 bHasContacted : 1;
|
||||
uint32 bPedPhysics : 1;
|
||||
uint32 bIsStuck : 1;
|
||||
uint32 bIsInSafePosition : 1;
|
||||
uint32 bUseCollisionRecords : 1;
|
||||
|
||||
// flagsB
|
||||
uint32 bWasPostponed : 1;
|
||||
uint32 m_flagB2 : 1; // explosion proof?
|
||||
uint32 bIsVisible : 1;
|
||||
uint32 bHasCollided : 1; //
|
||||
uint32 bRenderScorched : 1;
|
||||
uint32 m_flagB20 : 1; // bFlashing?
|
||||
uint32 bIsBIGBuilding : 1;
|
||||
// VC inserts one more flag here: if drawdist <= 2000
|
||||
uint32 bRenderDamaged : 1;
|
||||
|
||||
// flagsC
|
||||
uint32 m_flagC1 : 1; // bullet proof?
|
||||
uint32 m_flagC2 : 1; // fire proof?
|
||||
uint32 m_flagC4 : 1; // collision proof?
|
||||
uint32 m_flagC8 : 1; // melee proof?
|
||||
uint32 m_flagC10 : 1; // bOnlyDamagedByPlayer?
|
||||
uint32 m_flagC20 : 1;
|
||||
uint32 m_bZoneCulled : 1;
|
||||
uint32 m_bZoneCulled2 : 1; // only treadables+10m
|
||||
|
||||
// flagsD
|
||||
uint32 bRemoveFromWorld : 1;
|
||||
uint32 bHasHitWall : 1;
|
||||
uint32 bImBeingRendered : 1;
|
||||
uint32 m_flagD8 : 1;
|
||||
uint32 m_flagD10 : 1;
|
||||
uint32 bDrawLast : 1;
|
||||
uint32 m_flagD40 : 1;
|
||||
uint32 m_flagD80 : 1;
|
||||
|
||||
// flagsE
|
||||
uint32 bDistanceFade : 1;
|
||||
uint32 m_flagE2 : 1;
|
||||
|
||||
uint16 m_scanCode;
|
||||
int16 m_randomSeed;
|
||||
int16 m_modelIndex;
|
||||
uint16 m_level; // int16
|
||||
CReference *m_pFirstReference;
|
||||
|
||||
virtual void Add(void);
|
||||
virtual void Remove(void);
|
||||
virtual void SetModelIndex(uint32 i) { m_modelIndex = i; CreateRwObject(); }
|
||||
virtual void SetModelIndexNoCreate(uint32 i) { m_modelIndex = i; }
|
||||
virtual void CreateRwObject(void);
|
||||
virtual void DeleteRwObject(void);
|
||||
virtual CRect GetBoundRect(void);
|
||||
virtual void ProcessControl(void) {}
|
||||
virtual void ProcessCollision(void) {}
|
||||
virtual void ProcessShift(void) {}
|
||||
virtual void Teleport(CVector v) {}
|
||||
virtual void PreRender(void);
|
||||
virtual void Render(void);
|
||||
virtual bool SetupLighting(void);
|
||||
virtual void RemoveLighting(bool) {}
|
||||
virtual void FlagToDestroyWhenNextProcessed(void) {}
|
||||
|
||||
bool IsBuilding(void) { return m_type == ENTITY_TYPE_BUILDING; }
|
||||
bool IsVehicle(void) { return m_type == ENTITY_TYPE_VEHICLE; }
|
||||
bool IsPed(void) { return m_type == ENTITY_TYPE_PED; }
|
||||
bool IsObject(void) { return m_type == ENTITY_TYPE_OBJECT; }
|
||||
bool IsDummy(void) { return m_type == ENTITY_TYPE_DUMMY; }
|
||||
|
||||
void GetBoundCentre(CVector &out);
|
||||
CVector GetBoundCentre(void) { CVector v; GetBoundCentre(v); return v; }
|
||||
float GetBoundRadius(void) { return CModelInfo::GetModelInfo(m_modelIndex)->GetColModel()->boundingSphere.radius; }
|
||||
bool GetIsTouching(CVector const ¢er, float r);
|
||||
bool GetIsOnScreen(void);
|
||||
bool GetIsOnScreenComplex(void);
|
||||
bool IsVisible(void) { return m_rwObject && bIsVisible && GetIsOnScreen(); }
|
||||
bool IsVisibleComplex(void) { return m_rwObject && bIsVisible && GetIsOnScreenComplex(); }
|
||||
int GetModelIndex(void) { return m_modelIndex; }
|
||||
void UpdateRwFrame(void);
|
||||
void SetupBigBuilding(void);
|
||||
|
||||
void RegisterReference(CEntity **pent);
|
||||
void ResolveReferences(void);
|
||||
void PruneReferences(void);
|
||||
|
||||
|
||||
// to make patching virtual functions possible
|
||||
void Add_(void) { CEntity::Add(); }
|
||||
void Remove_(void) { CEntity::Remove(); }
|
||||
void CreateRwObject_(void) { CEntity::CreateRwObject(); }
|
||||
void DeleteRwObject_(void) { CEntity::DeleteRwObject(); }
|
||||
CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); }
|
||||
void Render_(void) { CEntity::Render(); }
|
||||
bool SetupLighting_(void) { return CEntity::SetupLighting(); }
|
||||
};
|
||||
static_assert(sizeof(CEntity) == 0x64, "CEntity: error");
|
9
src/entities/Object.cpp
Normal file
9
src/entities/Object.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "Object.h"
|
||||
#include "Pools.h"
|
||||
|
||||
void *CObject::operator new(size_t sz) { return CPools::GetObjectPool()->New(); }
|
||||
void CObject::operator delete(void *p, size_t sz) { CPools::GetObjectPool()->Delete((CObject*)p); }
|
||||
|
||||
WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
|
50
src/entities/Object.h
Normal file
50
src/entities/Object.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include "Physical.h"
|
||||
|
||||
enum {
|
||||
GAME_OBJECT = 1,
|
||||
MISSION_OBJECT = 2,
|
||||
TEMP_OBJECT = 3,
|
||||
};
|
||||
|
||||
class CObject : public CPhysical
|
||||
{
|
||||
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;
|
||||
int8 m_obj_flag8 : 1;
|
||||
int8 m_obj_flag10 : 1;
|
||||
int8 bHasBeenDamaged : 1;
|
||||
int8 m_obj_flag40 : 1;
|
||||
int8 m_obj_flag80 : 1;
|
||||
int8 field_172;
|
||||
int8 field_173;
|
||||
float m_fCollisionDamageMultiplier;
|
||||
int8 m_nCollisionDamageEffect;
|
||||
int8 m_bSpecialCollisionResponseCases;
|
||||
int8 m_bCameraToAvoidThisObject;
|
||||
int8 field_17B;
|
||||
int8 field_17C;
|
||||
int8 field_17D;
|
||||
int8 field_17E;
|
||||
int8 field_17F;
|
||||
int32 m_nEndOfLifeTime;
|
||||
int16 m_nRefModelIndex;
|
||||
int8 field_186;
|
||||
int8 field_187;
|
||||
CEntity *m_pCurSurface;
|
||||
CEntity *field_18C;
|
||||
int8 m_colour1, m_colour2;
|
||||
|
||||
static void *operator new(size_t);
|
||||
static void operator delete(void*, size_t);
|
||||
|
||||
void ObjectDamage(float amount);
|
||||
};
|
||||
static_assert(sizeof(CObject) == 0x198, "CObject: error");
|
35
src/entities/Ped.h
Normal file
35
src/entities/Ped.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "Physical.h"
|
||||
|
||||
enum PedAction
|
||||
{
|
||||
PED_PASSENGER = 44,
|
||||
};
|
||||
|
||||
class CVehicle;
|
||||
|
||||
class CPed : public CPhysical
|
||||
{
|
||||
public:
|
||||
// 0x128
|
||||
uint8 stuff1[252];
|
||||
int32 m_nPedState;
|
||||
uint8 stuff2[196];
|
||||
CEntity *m_pCurrentPhysSurface;
|
||||
CVector m_vecOffsetFromPhysSurface;
|
||||
CEntity *m_pCurSurface;
|
||||
uint8 stuff3[16];
|
||||
CVehicle *m_pMyVehicle;
|
||||
bool bInVehicle;
|
||||
uint8 stuff4[23];
|
||||
int32 m_nPedType;
|
||||
uint8 stuff5[528];
|
||||
|
||||
bool IsPlayer(void) { return m_nPedType == 0 || m_nPedType== 1 || m_nPedType == 2 || m_nPedType == 3; }
|
||||
};
|
||||
static_assert(offsetof(CPed, m_nPedState) == 0x224, "CPed: error");
|
||||
static_assert(offsetof(CPed, m_pCurSurface) == 0x2FC, "CPed: error");
|
||||
static_assert(offsetof(CPed, m_pMyVehicle) == 0x310, "CPed: error");
|
||||
static_assert(offsetof(CPed, m_nPedType) == 0x32C, "CPed: error");
|
||||
static_assert(sizeof(CPed) == 0x540, "CPed: error");
|
916
src/entities/Physical.cpp
Normal file
916
src/entities/Physical.cpp
Normal file
@ -0,0 +1,916 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "World.h"
|
||||
#include "Timer.h"
|
||||
#include "ModelIndices.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Ped.h"
|
||||
#include "Object.h"
|
||||
#include "Glass.h"
|
||||
#include "ParticleObject.h"
|
||||
#include "Particle.h"
|
||||
#include "SurfaceTable.h"
|
||||
#include "Physical.h"
|
||||
|
||||
void
|
||||
CPhysical::Add(void)
|
||||
{
|
||||
int x, xstart, xmid, xend;
|
||||
int y, ystart, ymid, yend;
|
||||
CSector *s;
|
||||
CPtrList *list;
|
||||
|
||||
CRect bounds = GetBoundRect();
|
||||
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||
assert(xstart >= 0);
|
||||
assert(xend < NUMSECTORS_X);
|
||||
assert(ystart >= 0);
|
||||
assert(yend < NUMSECTORS_Y);
|
||||
|
||||
for(y = ystart; y <= yend; y++)
|
||||
for(x = xstart; x <= xend; x++){
|
||||
s = CWorld::GetSector(x, y);
|
||||
if(x == xmid && y == ymid) switch(m_type){
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}else switch(m_type){
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
CPtrNode *node = list->InsertItem(this);
|
||||
assert(node);
|
||||
m_entryInfoList.InsertItem(list, node, s);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::Remove(void)
|
||||
{
|
||||
CEntryInfoNode *node, *next;
|
||||
for(node = m_entryInfoList.first; node; node = next){
|
||||
next = node->next;
|
||||
node->list->DeleteNode(node->listnode);
|
||||
m_entryInfoList.DeleteNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::RemoveAndAdd(void)
|
||||
{
|
||||
int x, xstart, xmid, xend;
|
||||
int y, ystart, ymid, yend;
|
||||
CSector *s;
|
||||
CPtrList *list;
|
||||
|
||||
CRect bounds = GetBoundRect();
|
||||
xstart = CWorld::GetSectorIndexX(bounds.left);
|
||||
xend = CWorld::GetSectorIndexX(bounds.right);
|
||||
xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f);
|
||||
ystart = CWorld::GetSectorIndexY(bounds.bottom);
|
||||
yend = CWorld::GetSectorIndexY(bounds.top);
|
||||
ymid = CWorld::GetSectorIndexY((bounds.bottom + bounds.top)/2.0f);
|
||||
assert(xstart >= 0);
|
||||
assert(xend < NUMSECTORS_X);
|
||||
assert(ystart >= 0);
|
||||
assert(yend < NUMSECTORS_Y);
|
||||
|
||||
// we'll try to recycle nodes from here
|
||||
CEntryInfoNode *next = m_entryInfoList.first;
|
||||
|
||||
for(y = ystart; y <= yend; y++)
|
||||
for(x = xstart; x <= xend; x++){
|
||||
s = CWorld::GetSector(x, y);
|
||||
if(x == xmid && y == ymid) switch(m_type){
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS];
|
||||
break;
|
||||
}else switch(m_type){
|
||||
case ENTITY_TYPE_VEHICLE:
|
||||
list = &s->m_lists[ENTITYLIST_VEHICLES_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_PED:
|
||||
list = &s->m_lists[ENTITYLIST_PEDS_OVERLAP];
|
||||
break;
|
||||
case ENTITY_TYPE_OBJECT:
|
||||
list = &s->m_lists[ENTITYLIST_OBJECTS_OVERLAP];
|
||||
break;
|
||||
}
|
||||
if(next){
|
||||
// If we still have old nodes, use them
|
||||
next->list->RemoveNode(next->listnode);
|
||||
list->InsertNode(next->listnode);
|
||||
next->list = list;
|
||||
next->sector = s;
|
||||
next = next->next;
|
||||
}else{
|
||||
CPtrNode *node = list->InsertItem(this);
|
||||
m_entryInfoList.InsertItem(list, node, s);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove old nodes we no longer need
|
||||
CEntryInfoNode *node;
|
||||
for(node = next; node; node = next){
|
||||
next = node->next;
|
||||
node->list->DeleteNode(node->listnode);
|
||||
m_entryInfoList.DeleteNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
CRect
|
||||
CPhysical::GetBoundRect(void)
|
||||
{
|
||||
CVector center;
|
||||
float radius;
|
||||
GetBoundCentre(center);
|
||||
radius = GetBoundRadius();
|
||||
return CRect(center.x-radius, center.y-radius, center.x+radius, center.y+radius);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::AddToMovingList(void)
|
||||
{
|
||||
m_movingListNode = CWorld::GetMovingEntityList().InsertItem(this);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::RemoveFromMovingList(void)
|
||||
{
|
||||
if(m_movingListNode){
|
||||
CWorld::GetMovingEntityList().DeleteNode(m_movingListNode);
|
||||
m_movingListNode = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Some quantities (german in parens):
|
||||
*
|
||||
* acceleration: distance/time^2: a
|
||||
* velocity: distance/time: v (GTA: speed)
|
||||
* momentum (impuls): velocity*mass: p
|
||||
* impulse (kraftstoss): delta momentum, force*time: J
|
||||
*
|
||||
* angular equivalents:
|
||||
* velocity -> angular velocity (GTA: turn speed)
|
||||
* momentum -> angular momentum (drehimpuls): L = r cross p
|
||||
* force -> torque (drehmoment): tau = r cross F
|
||||
* mass -> moment of inertia, angular mass (drehmoment, drehmasse): I = L/omega (GTA: turn mass)
|
||||
*/
|
||||
|
||||
CVector
|
||||
CPhysical::GetSpeed(const CVector &r)
|
||||
{
|
||||
return m_vecMoveSpeed + m_vecMoveFriction + CrossProduct(m_vecTurnFriction + m_vecTurnSpeed, r);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyMoveSpeed(void)
|
||||
{
|
||||
GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep();
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyTurnSpeed(void)
|
||||
{
|
||||
// Move the coordinate axes by their speed
|
||||
// Note that this denormalizes the matrix
|
||||
CVector turnvec = m_vecTurnSpeed*CTimer::GetTimeStep();
|
||||
GetRight() += CrossProduct(turnvec, GetRight());
|
||||
GetForward() += CrossProduct(turnvec, GetForward());
|
||||
GetUp() += CrossProduct(turnvec, GetUp());
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyMoveForce(float jx, float jy, float jz)
|
||||
{
|
||||
m_vecMoveSpeed += CVector(jx, jy, jz)*(1.0f/m_fMass);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyTurnForce(float jx, float jy, float jz, float px, float py, float pz)
|
||||
{
|
||||
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||
CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz));
|
||||
m_vecTurnSpeed += turnimpulse*(1.0f/m_fTurnMass);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyFrictionMoveForce(float jx, float jy, float jz)
|
||||
{
|
||||
m_vecMoveFriction += CVector(jx, jy, jz)*(1.0f/m_fMass);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyFrictionTurnForce(float jx, float jy, float jz, float px, float py, float pz)
|
||||
{
|
||||
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||
CVector turnimpulse = CrossProduct(CVector(px, py, pz)-com, CVector(jx, jy, jz));
|
||||
m_vecTurnFriction += turnimpulse*(1.0f/m_fTurnMass);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3)
|
||||
{
|
||||
if(1.0f - f2 <= 0.0f)
|
||||
return;
|
||||
float step = min(CTimer::GetTimeStep(), 3.0f);
|
||||
float strength = -0.008f*m_fMass*2.0f*step * f1 * (1.0f-f2) * f3;
|
||||
ApplyMoveForce(v.x*strength, v.y*strength, v.z*strength);
|
||||
ApplyTurnForce(v.x*strength, v.y*strength, v.z*strength, p.x, p.y, p.z);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyGravity(void)
|
||||
{
|
||||
if(bAffectedByGravity)
|
||||
m_vecMoveSpeed.z -= 0.008f * CTimer::GetTimeStep();
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyFriction(void)
|
||||
{
|
||||
m_vecMoveSpeed += m_vecMoveFriction;
|
||||
m_vecTurnSpeed += m_vecTurnFriction;
|
||||
m_vecMoveFriction = CVector(0.0f, 0.0f, 0.0f);
|
||||
m_vecTurnFriction = CVector(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ApplyAirResistance(void)
|
||||
{
|
||||
if(m_fAirResistance > 0.1f){
|
||||
float f = powf(m_fAirResistance, CTimer::GetTimeStep());
|
||||
m_vecMoveSpeed *= f;
|
||||
m_vecTurnSpeed *= f;
|
||||
}else{
|
||||
float f = powf(1.0f/(m_fAirResistance*0.5f*m_vecMoveSpeed.MagnitudeSqr() + 1.0f), CTimer::GetTimeStep());
|
||||
m_vecMoveSpeed *= f;
|
||||
m_vecTurnSpeed *= 0.99f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CPhysical::ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB)
|
||||
{
|
||||
float eA, eB;
|
||||
CPhysical *A = this;
|
||||
CObject *Bobj = (CObject*)B;
|
||||
|
||||
bool ispedcontactA = false;
|
||||
bool ispedcontactB = false;
|
||||
|
||||
float timestepA;
|
||||
if(B->bPedPhysics){
|
||||
timestepA = 10.0f;
|
||||
if(B->IsPed() && ((CPed*)B)->m_pCurrentPhysSurface == A)
|
||||
ispedcontactA = true;
|
||||
}else
|
||||
timestepA = A->m_phy_flagA1 ? 2.0f : 1.0f;
|
||||
|
||||
float timestepB;
|
||||
if(A->bPedPhysics){
|
||||
if(A->IsPed() && ((CPed*)A)->IsPlayer() && B->IsVehicle() &&
|
||||
(B->m_status == STATUS_ABANDONED || B->m_status == STATUS_WRECKED || A->bHasHitWall))
|
||||
timestepB = 2200.0f / B->m_fMass;
|
||||
else
|
||||
timestepB = 10.0f;
|
||||
|
||||
if(A->IsPed() && ((CPed*)A)->m_pCurrentPhysSurface == B)
|
||||
ispedcontactB = true;
|
||||
}else
|
||||
timestepB = B->m_phy_flagA1 ? 2.0f : 1.0f;
|
||||
|
||||
float speedA, speedB;
|
||||
if(B->bIsStatic){
|
||||
if(A->bPedPhysics){
|
||||
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||
if(speedA < 0.0f){
|
||||
if(B->IsObject()){
|
||||
impulseA = -speedA * A->m_fMass;
|
||||
impulseB = impulseA;
|
||||
if(impulseA > Bobj->m_fUprootLimit){
|
||||
if(IsGlass(B->GetModelIndex()))
|
||||
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
|
||||
else if(!B->bInfiniteMass)
|
||||
B->bIsStatic = false;
|
||||
}else{
|
||||
if(IsGlass(B->GetModelIndex()))
|
||||
CGlass::WindowRespondsToSoftCollision(B, impulseA);
|
||||
if(!A->bInfiniteMass)
|
||||
A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA);
|
||||
return true;
|
||||
}
|
||||
}else if(!B->bInfiniteMass)
|
||||
B->bIsStatic = false;
|
||||
|
||||
if(B->bInfiniteMass){
|
||||
impulseA = -speedA * A->m_fMass;
|
||||
impulseB = 0.0f;
|
||||
if(!A->bInfiniteMass)
|
||||
A->ApplyMoveForce(colpoint.normal*(1.0f + A->m_fElasticity)*impulseA);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
CVector pointposA = colpoint.point - A->GetPosition();
|
||||
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||
if(speedA < 0.0f){
|
||||
if(B->IsObject()){
|
||||
if(A->bHasHitWall)
|
||||
eA = -1.0f;
|
||||
else
|
||||
eA = -(1.0f + A->m_fElasticity);
|
||||
impulseA = eA * speedA * A->GetMass(pointposA, colpoint.normal);
|
||||
impulseB = impulseA;
|
||||
|
||||
if(Bobj->m_nCollisionDamageEffect && impulseA > 20.0f){
|
||||
Bobj->ObjectDamage(impulseA);
|
||||
if(!B->bUsesCollision){
|
||||
if(!A->bInfiniteMass){
|
||||
A->ApplyMoveForce(colpoint.normal*0.2f*impulseA);
|
||||
A->ApplyTurnForce(colpoint.normal*0.2f*impulseA, pointposA);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if((impulseA > Bobj->m_fUprootLimit || A->bIsStuck) &&
|
||||
!B->bInfiniteMass){
|
||||
if(IsGlass(B->GetModelIndex()))
|
||||
CGlass::WindowRespondsToCollision(B, impulseA, A->m_vecMoveSpeed, colpoint.point, false);
|
||||
else
|
||||
B->bIsStatic = false;
|
||||
int16 model = B->GetModelIndex();
|
||||
if(model == MI_FIRE_HYDRANT && !Bobj->bHasBeenDamaged){
|
||||
CParticleObject::AddObject(POBJECT_FIRE_HYDRANT, B->GetPosition() - CVector(0.0f, 0.0f, 0.5f), true);
|
||||
Bobj->bHasBeenDamaged = true;
|
||||
}else if(B->IsObject() && model != MI_EXPLODINGBARREL && model != MI_PETROLPUMP)
|
||||
Bobj->bHasBeenDamaged = true;
|
||||
}else{
|
||||
if(IsGlass(B->GetModelIndex()))
|
||||
CGlass::WindowRespondsToSoftCollision(B, impulseA);
|
||||
CVector f = colpoint.normal * impulseA;
|
||||
if(A->IsVehicle() && colpoint.normal.z < 0.7f)
|
||||
f.z *= 0.3f;
|
||||
if(!A->bInfiniteMass){
|
||||
A->ApplyMoveForce(f);
|
||||
if(!A->IsVehicle() || !CWorld::bNoMoreCollisionTorque)
|
||||
A->ApplyTurnForce(f, pointposA);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}else if(!B->bInfiniteMass)
|
||||
B->bIsStatic = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(B->bIsStatic)
|
||||
return false;
|
||||
if(!B->bInfiniteMass)
|
||||
B->AddToMovingList();
|
||||
}
|
||||
|
||||
// B is not static
|
||||
|
||||
if(A->bPedPhysics && B->bPedPhysics){
|
||||
// negative if A is moving towards B
|
||||
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||
// positive if B is moving towards A
|
||||
// not interested in how much B moves into A apparently?
|
||||
// only interested in cases where A collided into B
|
||||
speedB = max(0.0f, DotProduct(B->m_vecMoveSpeed, colpoint.normal));
|
||||
// A has moved into B
|
||||
if(speedA < speedB){
|
||||
if(!A->bHasHitWall)
|
||||
speedB -= (speedA - speedB) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
impulseA = (speedB-speedA) * A->m_fMass * timestepA;
|
||||
if(!A->bInfiniteMass)
|
||||
A->ApplyMoveForce(colpoint.normal*(impulseA/timestepA));
|
||||
return true;
|
||||
}
|
||||
}else if(A->bPedPhysics){
|
||||
CVector pointposB = colpoint.point - B->GetPosition();
|
||||
speedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
|
||||
|
||||
float a = A->m_fMass*timestepA;
|
||||
float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
|
||||
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||
if(speedA < speedSum){
|
||||
if(A->bHasHitWall)
|
||||
eA = speedSum;
|
||||
else
|
||||
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
if(B->bHasHitWall)
|
||||
eB = speedSum;
|
||||
else
|
||||
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
impulseA = (eA - speedA) * a;
|
||||
impulseB = -(eB - speedB) * b;
|
||||
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||
if(!A->bInfiniteMass){
|
||||
if(fA.z < 0.0f) fA.z = 0.0f;
|
||||
if(ispedcontactB){
|
||||
fA.x *= 2.0f;
|
||||
fA.y *= 2.0f;
|
||||
}
|
||||
A->ApplyMoveForce(fA);
|
||||
}
|
||||
if(!B->bInfiniteMass && !ispedcontactB){
|
||||
B->ApplyMoveForce(fB);
|
||||
B->ApplyTurnForce(fB, pointposB);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}else if(B->bPedPhysics){
|
||||
CVector pointposA = colpoint.point - A->GetPosition();
|
||||
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||
speedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||
|
||||
float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
|
||||
float b = B->m_fMass*timestepB;
|
||||
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||
if(speedA < speedSum){
|
||||
if(A->bHasHitWall)
|
||||
eA = speedSum;
|
||||
else
|
||||
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
if(B->bHasHitWall)
|
||||
eB = speedSum;
|
||||
else
|
||||
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
impulseA = (eA - speedA) * a;
|
||||
impulseB = -(eB - speedB) * b;
|
||||
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||
if(!A->bInfiniteMass && !ispedcontactA){
|
||||
if(fA.z < 0.0f) fA.z = 0.0f;
|
||||
A->ApplyMoveForce(fA);
|
||||
A->ApplyTurnForce(fA, pointposA);
|
||||
}
|
||||
if(!B->bInfiniteMass){
|
||||
if(fB.z < 0.0f){
|
||||
fB.z = 0.0f;
|
||||
if(fabs(speedA) < 0.01f)
|
||||
fB *= 0.5f;
|
||||
}
|
||||
if(ispedcontactA){
|
||||
fB.x *= 2.0f;
|
||||
fB.y *= 2.0f;
|
||||
}
|
||||
B->ApplyMoveForce(fB);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
CVector pointposA = colpoint.point - A->GetPosition();
|
||||
CVector pointposB = colpoint.point - B->GetPosition();
|
||||
speedA = DotProduct(A->GetSpeed(pointposA), colpoint.normal);
|
||||
speedB = DotProduct(B->GetSpeed(pointposB), colpoint.normal);
|
||||
float a = A->GetMassTime(pointposA, colpoint.normal, timestepA);
|
||||
float b = B->GetMassTime(pointposB, colpoint.normal, timestepB);
|
||||
float speedSum = (b*speedB + a*speedA)/(a + b);
|
||||
if(speedA < speedSum){
|
||||
if(A->bHasHitWall)
|
||||
eA = speedSum;
|
||||
else
|
||||
eA = speedSum - (speedA - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
if(B->bHasHitWall)
|
||||
eB = speedSum;
|
||||
else
|
||||
eB = speedSum - (speedB - speedSum) * (A->m_fElasticity+B->m_fElasticity)/2.0f;
|
||||
impulseA = (eA - speedA) * a;
|
||||
impulseB = -(eB - speedB) * b;
|
||||
CVector fA = colpoint.normal*(impulseA/timestepA);
|
||||
CVector fB = colpoint.normal*(-impulseB/timestepB);
|
||||
if(A->IsVehicle() && !A->bHasHitWall){
|
||||
fA.x *= 1.4f;
|
||||
fA.y *= 1.4f;
|
||||
if(colpoint.normal.z < 0.7f)
|
||||
fA.z *= 0.3f;
|
||||
if(A->m_status == STATUS_PLAYER)
|
||||
pointposA *= 0.8f;
|
||||
if(CWorld::bNoMoreCollisionTorque){
|
||||
A->ApplyFrictionMoveForce(fA*-0.3f);
|
||||
A->ApplyFrictionTurnForce(fA*-0.3f, pointposA);
|
||||
}
|
||||
}
|
||||
if(B->IsVehicle() && !B->bHasHitWall){
|
||||
fB.x *= 1.4f;
|
||||
fB.y *= 1.4f;
|
||||
if(colpoint.normal.z < 0.7f)
|
||||
fB.z *= 0.3f;
|
||||
if(B->m_status == STATUS_PLAYER)
|
||||
pointposB *= 0.8f;
|
||||
if(CWorld::bNoMoreCollisionTorque){
|
||||
// BUG: the game actually uses A here, but this can't be right
|
||||
B->ApplyFrictionMoveForce(fB*-0.3f);
|
||||
B->ApplyFrictionTurnForce(fB*-0.3f, pointposB);
|
||||
}
|
||||
}
|
||||
if(!A->bInfiniteMass){
|
||||
A->ApplyMoveForce(fA);
|
||||
A->ApplyTurnForce(fA, pointposA);
|
||||
}
|
||||
if(!B->bInfiniteMass){
|
||||
if(B->bIsInSafePosition)
|
||||
B->UnsetIsInSafePosition();
|
||||
B->ApplyMoveForce(fB);
|
||||
B->ApplyTurnForce(fB, pointposB);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CPhysical::ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed)
|
||||
{
|
||||
float normalSpeed;
|
||||
float e;
|
||||
CVector speed;
|
||||
CVector vImpulse;
|
||||
|
||||
if(bPedPhysics){
|
||||
normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal);
|
||||
if(normalSpeed < 0.0f){
|
||||
impulse = -normalSpeed * m_fMass;
|
||||
ApplyMoveForce(colpoint.normal * impulse);
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
CVector pointpos = colpoint.point - GetPosition();
|
||||
speed = GetSpeed(pointpos);
|
||||
normalSpeed = DotProduct(speed, colpoint.normal);
|
||||
if(normalSpeed < 0.0f){
|
||||
float minspeed = 0.0104f * CTimer::GetTimeStep();
|
||||
if((IsObject() || IsVehicle() && GetUp().z < -0.3f) &&
|
||||
!bHasContacted &&
|
||||
fabs(m_vecMoveSpeed.x) < minspeed &&
|
||||
fabs(m_vecMoveSpeed.y) < minspeed &&
|
||||
fabs(m_vecMoveSpeed.z) < minspeed*2.0f)
|
||||
e = -1.0f;
|
||||
else
|
||||
e = -(m_fElasticity + 1.0f);
|
||||
impulse = normalSpeed * e * GetMass(pointpos, colpoint.normal);
|
||||
|
||||
// ApplyMoveForce
|
||||
vImpulse = colpoint.normal*impulse;
|
||||
if(IsVehicle() &&
|
||||
(!bHasHitWall ||
|
||||
!(m_vecMoveSpeed.MagnitudeSqr() > 0.1 || !(B->IsBuilding() || ((CPhysical*)B)->bInfiniteMass))))
|
||||
moveSpeed += vImpulse * 1.2f * (1.0f/m_fMass);
|
||||
else
|
||||
moveSpeed += vImpulse * (1.0f/m_fMass);
|
||||
|
||||
// ApplyTurnForce
|
||||
CVector com = Multiply3x3(m_matrix, m_vecCentreOfMass);
|
||||
CVector turnimpulse = CrossProduct(pointpos-com, vImpulse);
|
||||
turnSpeed += turnimpulse*(1.0f/m_fTurnMass);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CPhysical::ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint)
|
||||
{
|
||||
CVector speedA, speedB;
|
||||
float normalSpeedA, normalSpeedB;
|
||||
CVector vOtherSpeedA, vOtherSpeedB;
|
||||
float fOtherSpeedA, fOtherSpeedB;
|
||||
float speedSum;
|
||||
CVector frictionDir;
|
||||
float impulseA, impulseB;
|
||||
float impulseLimit;
|
||||
CPhysical *A = this;
|
||||
|
||||
if(A->bPedPhysics && B->bPedPhysics){
|
||||
normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||
normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||
vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA;
|
||||
vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB;
|
||||
|
||||
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||
|
||||
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||
speedSum = (B->m_fMass*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(B->m_fMass + A->m_fMass);
|
||||
if(fOtherSpeedA > speedSum){
|
||||
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
|
||||
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||
if(impulseB > impulseLimit) impulseB = impulseLimit; // BUG: game has A's clamp again here, but this can't be right
|
||||
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||
return true;
|
||||
}
|
||||
}else if(A->bPedPhysics){
|
||||
if(B->IsVehicle())
|
||||
return false;
|
||||
CVector pointposB = colpoint.point - B->GetPosition();
|
||||
speedB = B->GetSpeed(pointposB);
|
||||
|
||||
normalSpeedA = DotProduct(A->m_vecMoveSpeed, colpoint.normal);
|
||||
normalSpeedB = DotProduct(speedB, colpoint.normal);
|
||||
vOtherSpeedA = A->m_vecMoveSpeed - colpoint.normal*normalSpeedA;
|
||||
vOtherSpeedB = speedB - colpoint.normal*normalSpeedB;
|
||||
|
||||
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||
|
||||
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||
float massB = B->GetMass(pointposB, frictionDir);
|
||||
speedSum = (massB*fOtherSpeedB + A->m_fMass*fOtherSpeedA)/(massB + A->m_fMass);
|
||||
if(fOtherSpeedA > speedSum){
|
||||
impulseA = (speedSum - fOtherSpeedA) * A->m_fMass;
|
||||
impulseB = (speedSum - fOtherSpeedB) * massB;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||
B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB);
|
||||
return true;
|
||||
}
|
||||
}else if(B->bPedPhysics){
|
||||
if(A->IsVehicle())
|
||||
return false;
|
||||
CVector pointposA = colpoint.point - A->GetPosition();
|
||||
speedA = A->GetSpeed(pointposA);
|
||||
|
||||
normalSpeedA = DotProduct(speedA, colpoint.normal);
|
||||
normalSpeedB = DotProduct(B->m_vecMoveSpeed, colpoint.normal);
|
||||
vOtherSpeedA = speedA - colpoint.normal*normalSpeedA;
|
||||
vOtherSpeedB = B->m_vecMoveSpeed - colpoint.normal*normalSpeedB;
|
||||
|
||||
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||
|
||||
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||
float massA = A->GetMass(pointposA, frictionDir);
|
||||
speedSum = (B->m_fMass*fOtherSpeedB + massA*fOtherSpeedA)/(B->m_fMass + massA);
|
||||
if(fOtherSpeedA > speedSum){
|
||||
impulseA = (speedSum - fOtherSpeedA) * massA;
|
||||
impulseB = (speedSum - fOtherSpeedB) * B->m_fMass;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||
A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA);
|
||||
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
CVector pointposA = colpoint.point - A->GetPosition();
|
||||
CVector pointposB = colpoint.point - B->GetPosition();
|
||||
speedA = A->GetSpeed(pointposA);
|
||||
speedB = B->GetSpeed(pointposB);
|
||||
|
||||
normalSpeedA = DotProduct(speedA, colpoint.normal);
|
||||
normalSpeedB = DotProduct(speedB, colpoint.normal);
|
||||
vOtherSpeedA = speedA - colpoint.normal*normalSpeedA;
|
||||
vOtherSpeedB = speedB - colpoint.normal*normalSpeedB;
|
||||
|
||||
fOtherSpeedA = vOtherSpeedA.Magnitude();
|
||||
fOtherSpeedB = vOtherSpeedB.Magnitude();
|
||||
|
||||
frictionDir = vOtherSpeedA * (1.0f/fOtherSpeedA);
|
||||
float massA = A->GetMass(pointposA, frictionDir);
|
||||
float massB = B->GetMass(pointposB, frictionDir);
|
||||
speedSum = (massB*fOtherSpeedB + massA*fOtherSpeedA)/(massB + massA);
|
||||
if(fOtherSpeedA > speedSum){
|
||||
impulseA = (speedSum - fOtherSpeedA) * massA;
|
||||
impulseB = (speedSum - fOtherSpeedB) * massB;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep();
|
||||
if(impulseA < -impulseLimit) impulseA = -impulseLimit;
|
||||
if(impulseB > impulseLimit) impulseB = impulseLimit;
|
||||
A->ApplyFrictionMoveForce(frictionDir*impulseA);
|
||||
A->ApplyFrictionTurnForce(frictionDir*impulseA, pointposA);
|
||||
B->ApplyFrictionMoveForce(frictionDir*impulseB);
|
||||
B->ApplyFrictionTurnForce(frictionDir*impulseB, pointposB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CPhysical::ApplyFriction(float adhesiveLimit, CColPoint &colpoint)
|
||||
{
|
||||
CVector speed;
|
||||
float normalSpeed;
|
||||
CVector vOtherSpeed;
|
||||
float fOtherSpeed;
|
||||
CVector frictionDir;
|
||||
float fImpulse;
|
||||
float impulseLimit;
|
||||
|
||||
if(bPedPhysics){
|
||||
normalSpeed = DotProduct(m_vecMoveSpeed, colpoint.normal);
|
||||
vOtherSpeed = m_vecMoveSpeed - colpoint.normal*normalSpeed;
|
||||
|
||||
fOtherSpeed = vOtherSpeed.Magnitude();
|
||||
if(fOtherSpeed > 0.0f){
|
||||
frictionDir = vOtherSpeed * (1.0f/fOtherSpeed);
|
||||
// not really impulse but speed
|
||||
// maybe use ApplyFrictionMoveForce instead?
|
||||
fImpulse = -fOtherSpeed;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() / m_fMass;
|
||||
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
|
||||
CVector vImpulse = frictionDir*fImpulse;
|
||||
m_vecMoveFriction += CVector(vImpulse.x, vImpulse.y, 0.0f);
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
CVector pointpos = colpoint.point - GetPosition();
|
||||
speed = GetSpeed(pointpos);
|
||||
normalSpeed = DotProduct(speed, colpoint.normal);
|
||||
vOtherSpeed = speed - colpoint.normal*normalSpeed;
|
||||
|
||||
fOtherSpeed = vOtherSpeed.Magnitude();
|
||||
if(fOtherSpeed > 0.0f){
|
||||
frictionDir = vOtherSpeed * (1.0f/fOtherSpeed);
|
||||
fImpulse = -fOtherSpeed * m_fMass;
|
||||
impulseLimit = adhesiveLimit*CTimer::GetTimeStep() * 1.5f;
|
||||
if(fImpulse < -impulseLimit) fImpulse = -impulseLimit;
|
||||
ApplyFrictionMoveForce(frictionDir*fImpulse);
|
||||
ApplyFrictionTurnForce(frictionDir*fImpulse, pointpos);
|
||||
|
||||
if(fOtherSpeed > 0.1f &&
|
||||
colpoint.surfaceB != SURFACE_2 && colpoint.surfaceB != SURFACE_4 &&
|
||||
CSurfaceTable::GetAdhesionGroup(colpoint.surfaceA) == ADHESIVE_HARD){
|
||||
CVector v = frictionDir * fOtherSpeed * 0.25f;
|
||||
for(int i = 0; i < 4; i++)
|
||||
CParticle::AddParticle(PARTICLE_SPARK_SMALL, colpoint.point, v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CPhysical::AddCollisionRecord(CEntity *ent)
|
||||
{
|
||||
AddCollisionRecord_Treadable(ent);
|
||||
this->bHasCollided = true;
|
||||
ent->bHasCollided = true;
|
||||
if(IsVehicle() && ent->IsVehicle()){
|
||||
if(((CVehicle*)this)->m_nAlarmState == -1)
|
||||
((CVehicle*)this)->m_nAlarmState = 15000;
|
||||
if(((CVehicle*)ent)->m_nAlarmState == -1)
|
||||
((CVehicle*)ent)->m_nAlarmState = 15000;
|
||||
}
|
||||
if(bUseCollisionRecords){
|
||||
int i;
|
||||
for(i = 0; i < m_nCollisionRecords; i++)
|
||||
if(m_aCollisionRecords[i] == ent)
|
||||
return;
|
||||
if(m_nCollisionRecords < PHYSICAL_MAX_COLLISIONRECORDS)
|
||||
m_aCollisionRecords[m_nCollisionRecords++] = ent;
|
||||
m_nLastTimeCollided = CTimer::GetTimeInMilliseconds();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::AddCollisionRecord_Treadable(CEntity *ent)
|
||||
{
|
||||
if(ent->IsBuilding() && ((CBuilding*)ent)->GetIsATreadable()){
|
||||
CTreadable *t = (CTreadable*)ent;
|
||||
if(t->m_nodeIndicesPeds[0] >= 0 ||
|
||||
t->m_nodeIndicesPeds[1] >= 0 ||
|
||||
t->m_nodeIndicesPeds[2] >= 0 ||
|
||||
t->m_nodeIndicesPeds[3] >= 0)
|
||||
m_pedTreadable = t;
|
||||
if(t->m_nodeIndicesCars[0] >= 0 ||
|
||||
t->m_nodeIndicesCars[1] >= 0 ||
|
||||
t->m_nodeIndicesCars[2] >= 0 ||
|
||||
t->m_nodeIndicesCars[3] >= 0)
|
||||
m_carTreadable = t;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CPhysical::GetHasCollidedWith(CEntity *ent)
|
||||
{
|
||||
int i;
|
||||
if(bUseCollisionRecords)
|
||||
for(i = 0; i < m_nCollisionRecords; i++)
|
||||
if(m_aCollisionRecords[i] == ent)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CPhysical::ProcessControl(void)
|
||||
{
|
||||
if(!IsPed())
|
||||
m_phy_flagA8 = false;
|
||||
bHasContacted = false;
|
||||
bIsInSafePosition = false;
|
||||
bWasPostponed = false;
|
||||
bHasHitWall = false;
|
||||
|
||||
if(m_status == STATUS_SIMPLE)
|
||||
return;
|
||||
|
||||
m_nCollisionRecords = 0;
|
||||
bHasCollided = false;
|
||||
m_nCollisionPieceType = 0;
|
||||
m_fCollisionImpulse = 0.0f;
|
||||
m_pCollidingEntity = nil;
|
||||
|
||||
if(!bIsStuck){
|
||||
if(IsObject() ||
|
||||
IsPed() && !bPedPhysics){
|
||||
m_vecMoveSpeedAvg = (m_vecMoveSpeedAvg + m_vecMoveSpeed)/2.0f;
|
||||
m_vecTurnSpeedAvg = (m_vecTurnSpeedAvg + m_vecTurnSpeed)/2.0f;
|
||||
float step = CTimer::GetTimeStep() * 0.003;
|
||||
if(m_vecMoveSpeedAvg.MagnitudeSqr() < step*step &&
|
||||
m_vecTurnSpeedAvg.MagnitudeSqr() < step*step){
|
||||
m_nStaticFrames++;
|
||||
if(m_nStaticFrames > 10){
|
||||
m_nStaticFrames = 10;
|
||||
bIsStatic = true;
|
||||
m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||
m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
|
||||
m_vecMoveFriction = m_vecMoveSpeed;
|
||||
m_vecTurnFriction = m_vecTurnSpeed;
|
||||
return;
|
||||
}
|
||||
}else
|
||||
m_nStaticFrames = 0;
|
||||
}
|
||||
}
|
||||
ApplyGravity();
|
||||
ApplyFriction();
|
||||
ApplyAirResistance();
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x4951F0, &CPhysical::Add_, PATCH_JUMP);
|
||||
InjectHook(0x4954B0, &CPhysical::Remove_, PATCH_JUMP);
|
||||
InjectHook(0x495540, &CPhysical::RemoveAndAdd, PATCH_JUMP);
|
||||
InjectHook(0x495F10, &CPhysical::ProcessControl_, PATCH_JUMP);
|
||||
InjectHook(0x4958F0, &CPhysical::AddToMovingList, PATCH_JUMP);
|
||||
InjectHook(0x495940, &CPhysical::RemoveFromMovingList, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x497180, &CPhysical::AddCollisionRecord, PATCH_JUMP);
|
||||
InjectHook(0x4970C0, &CPhysical::AddCollisionRecord_Treadable, PATCH_JUMP);
|
||||
InjectHook(0x497240, &CPhysical::GetHasCollidedWith, PATCH_JUMP);
|
||||
|
||||
#define F3 float, float, float
|
||||
InjectHook(0x495B10, &CPhysical::ApplyMoveSpeed, PATCH_JUMP);
|
||||
InjectHook(0x497280, &CPhysical::ApplyTurnSpeed, PATCH_JUMP);
|
||||
InjectHook(0x4959A0, (void (CPhysical::*)(F3))&CPhysical::ApplyMoveForce, PATCH_JUMP);
|
||||
InjectHook(0x495A10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyTurnForce, PATCH_JUMP);
|
||||
InjectHook(0x495D90, (void (CPhysical::*)(F3))&CPhysical::ApplyFrictionMoveForce, PATCH_JUMP);
|
||||
InjectHook(0x495E10, (void (CPhysical::*)(F3, F3))&CPhysical::ApplyFrictionTurnForce, PATCH_JUMP);
|
||||
InjectHook(0x499890, &CPhysical::ApplySpringCollision, PATCH_JUMP);
|
||||
InjectHook(0x495B50, &CPhysical::ApplyGravity, PATCH_JUMP);
|
||||
InjectHook(0x495B80, (void (CPhysical::*)(void))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||
InjectHook(0x495C20, &CPhysical::ApplyAirResistance, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x4973A0, &CPhysical::ApplyCollision, PATCH_JUMP);
|
||||
InjectHook(0x4992A0, &CPhysical::ApplyCollisionAlt, PATCH_JUMP);
|
||||
InjectHook(0x499BE0, (bool (CPhysical::*)(float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||
InjectHook(0x49A180, (bool (CPhysical::*)(CPhysical*, float, CColPoint&))&CPhysical::ApplyFriction, PATCH_JUMP);
|
||||
ENDPATCHES
|
137
src/entities/Physical.h
Normal file
137
src/entities/Physical.h
Normal file
@ -0,0 +1,137 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lists.h"
|
||||
#include "Entity.h"
|
||||
#include "Treadable.h"
|
||||
|
||||
enum {
|
||||
PHYSICAL_MAX_COLLISIONRECORDS = 6
|
||||
};
|
||||
|
||||
class CPhysical : public CEntity
|
||||
{
|
||||
public:
|
||||
// The not properly indented fields haven't been checked properly yet
|
||||
|
||||
int uAudioEntityId;
|
||||
float unk1;
|
||||
CTreadable *m_carTreadable;
|
||||
CTreadable *m_pedTreadable;
|
||||
uint32 m_nLastTimeCollided;
|
||||
CVector m_vecMoveSpeed; // velocity
|
||||
CVector m_vecTurnSpeed; // angular velocity
|
||||
CVector m_vecMoveFriction;
|
||||
CVector m_vecTurnFriction;
|
||||
CVector m_vecMoveSpeedAvg;
|
||||
CVector m_vecTurnSpeedAvg;
|
||||
float m_fMass;
|
||||
float m_fTurnMass; // moment of inertia
|
||||
float fForceMultiplier;
|
||||
float m_fAirResistance;
|
||||
float m_fElasticity;
|
||||
float fPercentSubmerged;
|
||||
CVector m_vecCentreOfMass;
|
||||
CEntryInfoList m_entryInfoList;
|
||||
CPtrNode *m_movingListNode;
|
||||
|
||||
char field_EC;
|
||||
uint8 m_nStaticFrames;
|
||||
uint8 m_nCollisionRecords;
|
||||
char field_EF;
|
||||
CEntity *m_aCollisionRecords[PHYSICAL_MAX_COLLISIONRECORDS];
|
||||
|
||||
float m_fDistanceTravelled;
|
||||
|
||||
// damaged piece
|
||||
float m_fCollisionImpulse;
|
||||
CEntity *m_pCollidingEntity;
|
||||
CVector m_vecCollisionDirection;
|
||||
int16 m_nCollisionPieceType;
|
||||
|
||||
uint8 m_phy_flagA1 : 1;
|
||||
uint8 bAffectedByGravity : 1;
|
||||
uint8 bInfiniteMass : 1;
|
||||
uint8 m_phy_flagA8 : 1;
|
||||
uint8 m_phy_flagA10 : 1;
|
||||
uint8 m_phy_flagA20 : 1;
|
||||
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;
|
||||
|
||||
|
||||
// from CEntity
|
||||
void Add(void);
|
||||
void Remove(void);
|
||||
CRect GetBoundRect(void);
|
||||
void ProcessControl(void);
|
||||
|
||||
void RemoveAndAdd(void);
|
||||
void AddToMovingList(void);
|
||||
void RemoveFromMovingList(void);
|
||||
|
||||
// get speed of point p relative to entity center
|
||||
CVector GetSpeed(const CVector &r);
|
||||
CVector GetSpeed(void) { return GetSpeed(CVector(0.0f, 0.0f, 0.0f)); }
|
||||
float GetMass(const CVector &pos, const CVector &dir) {
|
||||
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/m_fTurnMass +
|
||||
1.0f/m_fMass);
|
||||
}
|
||||
float GetMassTime(const CVector &pos, const CVector &dir, float t) {
|
||||
return 1.0f / (CrossProduct(pos, dir).MagnitudeSqr()/(m_fTurnMass*t) +
|
||||
1.0f/(m_fMass*t));
|
||||
}
|
||||
void UnsetIsInSafePosition(void) {
|
||||
m_vecMoveSpeed *= -1.0f;
|
||||
m_vecTurnSpeed *= -1.0f;
|
||||
ApplyTurnSpeed();
|
||||
ApplyMoveSpeed();
|
||||
m_vecMoveSpeed *= -1.0f;
|
||||
m_vecTurnSpeed *= -1.0f;
|
||||
bIsInSafePosition = false;
|
||||
}
|
||||
|
||||
void ApplyMoveSpeed(void);
|
||||
void ApplyTurnSpeed(void);
|
||||
// Force actually means Impulse here
|
||||
void ApplyMoveForce(float jx, float jy, float jz);
|
||||
void ApplyMoveForce(const CVector &j) { ApplyMoveForce(j.x, j.y, j.z); }
|
||||
// v(x,y,z) is direction of force, p(x,y,z) is point relative to model center where force is applied
|
||||
void ApplyTurnForce(float jx, float jy, float jz, float rx, float ry, float rz);
|
||||
// v is direction of force, p is point relative to model center where force is applied
|
||||
void ApplyTurnForce(const CVector &j, const CVector &p) { ApplyTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
|
||||
void ApplyFrictionMoveForce(float jx, float jy, float jz);
|
||||
void ApplyFrictionMoveForce(const CVector &j) { ApplyFrictionMoveForce(j.x, j.y, j.z); }
|
||||
void ApplyFrictionTurnForce(float jx, float jy, float jz, float rx, float ry, float rz);
|
||||
void ApplyFrictionTurnForce(const CVector &j, const CVector &p) { ApplyFrictionTurnForce(j.x, j.y, j.z, p.x, p.y, p.z); }
|
||||
void ApplySpringCollision(float f1, CVector &v, CVector &p, float f2, float f3);
|
||||
void ApplyGravity(void);
|
||||
void ApplyFriction(void);
|
||||
void ApplyAirResistance(void);
|
||||
bool ApplyCollision(CPhysical *B, CColPoint &colpoint, float &impulseA, float &impulseB);
|
||||
bool ApplyCollisionAlt(CEntity *B, CColPoint &colpoint, float &impulse, CVector &moveSpeed, CVector &turnSpeed);
|
||||
bool ApplyFriction(CPhysical *B, float adhesiveLimit, CColPoint &colpoint);
|
||||
bool ApplyFriction(float adhesiveLimit, CColPoint &colpoint);
|
||||
|
||||
void AddCollisionRecord(CEntity *ent);
|
||||
void AddCollisionRecord_Treadable(CEntity *ent);
|
||||
bool GetHasCollidedWith(CEntity *ent);
|
||||
|
||||
// to make patching virtual functions possible
|
||||
void Add_(void) { CPhysical::Add(); }
|
||||
void Remove_(void) { CPhysical::Remove(); }
|
||||
CRect GetBoundRect_(void) { return CPhysical::GetBoundRect(); }
|
||||
void ProcessControl_(void) { CPhysical::ProcessControl(); }
|
||||
};
|
||||
static_assert(sizeof(CPhysical) == 0x128, "CPhysical: error");
|
7
src/entities/Treadable.cpp
Normal file
7
src/entities/Treadable.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "common.h"
|
||||
#include "rpworld.h"
|
||||
#include "Treadable.h"
|
||||
#include "Pools.h"
|
||||
|
||||
void *CTreadable::operator new(size_t sz) { return CPools::GetTreadablePool()->New(); }
|
||||
void CTreadable::operator delete(void *p, size_t sz) { CPools::GetTreadablePool()->Delete((CTreadable*)p); }
|
16
src/entities/Treadable.h
Normal file
16
src/entities/Treadable.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "Building.h"
|
||||
|
||||
class CTreadable : public CBuilding
|
||||
{
|
||||
public:
|
||||
static void *operator new(size_t);
|
||||
static void operator delete(void*, size_t);
|
||||
|
||||
int16 m_nodeIndicesCars[12];
|
||||
int16 m_nodeIndicesPeds[12];
|
||||
|
||||
virtual bool GetIsATreadable(void) { return true; }
|
||||
};
|
||||
static_assert(sizeof(CTreadable) == 0x94, "CTreadable: error");
|
21
src/entities/Vehicle.h
Normal file
21
src/entities/Vehicle.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "Physical.h"
|
||||
|
||||
class CPed;
|
||||
|
||||
class CVehicle : public CPhysical
|
||||
{
|
||||
public:
|
||||
// 0x128
|
||||
uint8 stuff1[120];
|
||||
int16 m_nAlarmState;
|
||||
CPed *pDriver;
|
||||
CPed *pPassengers[8];
|
||||
uint8 stuff2[24];
|
||||
CEntity *m_pCurSurface;
|
||||
uint8 stuff3[160];
|
||||
int32 m_vehType;
|
||||
};
|
||||
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error");
|
Reference in New Issue
Block a user