summaryrefslogtreecommitdiffstats
path: root/src/objects
diff options
context:
space:
mode:
Diffstat (limited to 'src/objects')
-rw-r--r--src/objects/CutsceneHead.cpp118
-rw-r--r--src/objects/CutsceneHead.h24
-rw-r--r--src/objects/CutsceneObject.cpp100
-rw-r--r--src/objects/CutsceneObject.h25
-rw-r--r--src/objects/DummyObject.cpp17
-rw-r--r--src/objects/DummyObject.h14
-rw-r--r--src/objects/Object.cpp93
-rw-r--r--src/objects/Object.h81
-rw-r--r--src/objects/ObjectData.cpp103
-rw-r--r--src/objects/ObjectData.h27
-rw-r--r--src/objects/ParticleObject.cpp23
-rw-r--r--src/objects/ParticleObject.h39
-rw-r--r--src/objects/Projectile.cpp7
-rw-r--r--src/objects/Projectile.h11
14 files changed, 682 insertions, 0 deletions
diff --git a/src/objects/CutsceneHead.cpp b/src/objects/CutsceneHead.cpp
new file mode 100644
index 00000000..a9c47777
--- /dev/null
+++ b/src/objects/CutsceneHead.cpp
@@ -0,0 +1,118 @@
+#include "common.h"
+#include <rpskin.h>
+#include "patcher.h"
+#include "main.h"
+#include "RwHelper.h"
+#include "RpAnimBlend.h"
+#include "AnimBlendClumpData.h"
+#include "Directory.h"
+#include "CutsceneMgr.h"
+#include "Streaming.h"
+#include "CutsceneHead.h"
+
+
+CCutsceneHead::CCutsceneHead(CObject *obj)
+{
+ RpAtomic *atm;
+
+ assert(RwObjectGetType(obj->m_rwObject) == rpCLUMP);
+ m_pHeadNode = RpAnimBlendClumpFindFrame((RpClump*)obj->m_rwObject, "Shead")->frame;
+ atm = (RpAtomic*)GetFirstObject(m_pHeadNode);
+ if(atm){
+ assert(RwObjectGetType(atm) == rpATOMIC);
+ RpAtomicSetFlags(atm, RpAtomicGetFlags(atm) & ~rpATOMICRENDER);
+ }
+}
+
+void
+CCutsceneHead::CreateRwObject(void)
+{
+ RpAtomic *atm;
+
+ CEntity::CreateRwObject();
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ atm = GetFirstAtomic((RpClump*)m_rwObject);
+ RpSkinAtomicSetHAnimHierarchy(atm, RpHAnimFrameGetHierarchy(GetFirstChild(RpClumpGetFrame((RpClump*)m_rwObject))));
+}
+
+void
+CCutsceneHead::DeleteRwObject(void)
+{
+ CEntity::DeleteRwObject();
+}
+
+void
+CCutsceneHead::ProcessControl(void)
+{
+ RpAtomic *atm;
+ RpHAnimHierarchy *hier;
+
+ CPhysical::ProcessControl();
+
+ m_matrix.SetRotateY(PI/2);
+ m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix;
+ UpdateRwFrame();
+
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ atm = GetFirstAtomic((RpClump*)m_rwObject);
+ hier = RpSkinAtomicGetHAnimHierarchy(atm);
+ RpHAnimHierarchyAddAnimTime(hier, CTimer::GetTimeStepNonClipped()/50.0f);
+}
+
+void
+CCutsceneHead::Render(void)
+{
+ RpAtomic *atm;
+
+ m_matrix.SetRotateY(PI/2);
+ m_matrix = CMatrix(RwFrameGetLTM(m_pHeadNode)) * m_matrix;
+ UpdateRwFrame();
+
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ atm = GetFirstAtomic((RpClump*)m_rwObject);
+ RpHAnimHierarchyUpdateMatrices(RpSkinAtomicGetHAnimHierarchy(atm));
+
+ CObject::Render();
+}
+
+void
+CCutsceneHead::PlayAnimation(const char *animName)
+{
+ RpAtomic *atm;
+ RpHAnimHierarchy *hier;
+ RpHAnimAnimation *anim;
+ uint32 offset, size;
+ RwStream *stream;
+
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ atm = GetFirstAtomic((RpClump*)m_rwObject);
+ hier = RpSkinAtomicGetHAnimHierarchy(atm);
+
+ sprintf(gString, "%s.anm", animName);
+
+ if(CCutsceneMgr::ms_pCutsceneDir->FindItem(gString, offset, size)){
+ stream = RwStreamOpen(rwSTREAMFILENAME, rwSTREAMREAD, "ANIM\\CUTS.IMG");
+ assert(stream);
+
+ CStreaming::MakeSpaceFor(size*2048);
+ CStreaming::ImGonnaUseStreamingMemory();
+
+ RwStreamSkip(stream, offset*2048);
+ if(RwStreamFindChunk(stream, rwID_HANIMANIMATION, nil, nil)){
+ anim = RpHAnimAnimationStreamRead(stream);
+ RpHAnimHierarchySetCurrentAnim(hier, anim);
+ }
+
+ CStreaming::IHaveUsedStreamingMemory();
+
+ RwStreamClose(stream, nil);
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x4BA650, &CCutsceneHead::CreateRwObject_, PATCH_JUMP);
+ InjectHook(0x4BA690, &CCutsceneHead::DeleteRwObject_, PATCH_JUMP);
+ InjectHook(0x4BA760, &CCutsceneHead::ProcessControl_, PATCH_JUMP);
+ InjectHook(0x4BA800, &CCutsceneHead::Render_, PATCH_JUMP);
+ InjectHook(0x4BA6A0, &CCutsceneHead::PlayAnimation, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/objects/CutsceneHead.h b/src/objects/CutsceneHead.h
new file mode 100644
index 00000000..de4f011f
--- /dev/null
+++ b/src/objects/CutsceneHead.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "CutsceneObject.h"
+
+class CCutsceneHead : public CCutsceneObject
+{
+public:
+ RwFrame *m_pHeadNode;
+
+ CCutsceneHead(CObject *obj);
+
+ void CreateRwObject(void);
+ void DeleteRwObject(void);
+ void ProcessControl(void);
+ void Render(void);
+
+ void PlayAnimation(const char *animName);
+
+ void CreateRwObject_(void) { CCutsceneHead::CreateRwObject(); }
+ void DeleteRwObject_(void) { CCutsceneHead::DeleteRwObject(); }
+ void ProcessControl_(void) { CCutsceneHead::ProcessControl(); }
+ void Render_(void) { CCutsceneHead::Render(); }
+};
+static_assert(sizeof(CCutsceneHead) == 0x19C, "CCutsceneHead: error");
diff --git a/src/objects/CutsceneObject.cpp b/src/objects/CutsceneObject.cpp
new file mode 100644
index 00000000..ede5be5b
--- /dev/null
+++ b/src/objects/CutsceneObject.cpp
@@ -0,0 +1,100 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "Lights.h"
+#include "PointLights.h"
+#include "RpAnimBlend.h"
+#include "AnimBlendClumpData.h"
+#include "Renderer.h"
+#include "ModelIndices.h"
+#include "Shadows.h"
+#include "Timecycle.h"
+#include "CutsceneObject.h"
+
+CCutsceneObject::CCutsceneObject(void)
+{
+ m_status = STATUS_SIMPLE;
+ bUsesCollision = false;
+ bStreamingDontDelete = true;
+ ObjectCreatedBy = CUTSCENE_OBJECT;
+ m_fMass = 1.0f;
+ m_fTurnMass = 1.0f;
+}
+
+void
+CCutsceneObject::SetModelIndex(uint32 id)
+{
+ CEntity::SetModelIndex(id);
+ assert(RwObjectGetType(m_rwObject) == rpCLUMP);
+ RpAnimBlendClumpInit((RpClump*)m_rwObject);
+ (*RPANIMBLENDCLUMPDATA(m_rwObject))->velocity = &m_vecMoveSpeed;
+ (*RPANIMBLENDCLUMPDATA(m_rwObject))->frames[0].flag |= AnimBlendFrameData::VELOCITY_EXTRACTION_3D;
+}
+
+void
+CCutsceneObject::ProcessControl(void)
+{
+ CPhysical::ProcessControl();
+
+ if(CTimer::GetTimeStep() < 1/100.0f)
+ m_vecMoveSpeed *= 100.0f;
+ else
+ m_vecMoveSpeed *= 1.0f/CTimer::GetTimeStep();
+
+ ApplyMoveSpeed();
+}
+
+void
+CCutsceneObject::PreRender(void)
+{
+ if(IsPedModel(GetModelIndex()))
+ CShadows::StoreShadowForPedObject(this,
+ CTimeCycle::m_fShadowDisplacementX[CTimeCycle::m_CurrentStoredValue],
+ CTimeCycle::m_fShadowDisplacementY[CTimeCycle::m_CurrentStoredValue],
+ CTimeCycle::m_fShadowFrontX[CTimeCycle::m_CurrentStoredValue],
+ CTimeCycle::m_fShadowFrontY[CTimeCycle::m_CurrentStoredValue],
+ CTimeCycle::m_fShadowSideX[CTimeCycle::m_CurrentStoredValue],
+ CTimeCycle::m_fShadowSideY[CTimeCycle::m_CurrentStoredValue]);
+}
+
+void
+CCutsceneObject::Render(void)
+{
+ CObject::Render();
+}
+
+bool
+CCutsceneObject::SetupLighting(void)
+{
+ ActivateDirectional();
+ SetAmbientColoursForPedsCarsAndObjects();
+
+ if(bRenderScorched){
+ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+ }else{
+ CVector coors = GetPosition();
+ float lighting = CPointLights::GenerateLightsAffectingObject(&coors);
+ if(!bHasBlip && lighting != 1.0f){
+ SetAmbientAndDirectionalColours(lighting);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+CCutsceneObject::RemoveLighting(bool reset)
+{
+ CRenderer::RemoveVehiclePedLights(this, reset);
+}
+
+STARTPATCHES
+ InjectHook(0x4BA960, &CCutsceneObject::dtor, PATCH_JUMP);
+ InjectHook(0x4BA980, &CCutsceneObject::SetModelIndex_, PATCH_JUMP);
+ InjectHook(0x4BA9C0, &CCutsceneObject::ProcessControl_, PATCH_JUMP);
+ InjectHook(0x4BAA40, &CCutsceneObject::PreRender_, PATCH_JUMP);
+ InjectHook(0x4BAAA0, &CCutsceneObject::Render_, PATCH_JUMP);
+ InjectHook(0x4A7E70, &CCutsceneObject::SetupLighting_, PATCH_JUMP);
+ InjectHook(0x4A7F00, &CCutsceneObject::RemoveLighting_, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/objects/CutsceneObject.h b/src/objects/CutsceneObject.h
new file mode 100644
index 00000000..9360651e
--- /dev/null
+++ b/src/objects/CutsceneObject.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "Object.h"
+
+class CCutsceneObject : public CObject
+{
+public:
+ CCutsceneObject(void);
+
+ virtual void SetModelIndex(uint32 id);
+ virtual void ProcessControl(void);
+ virtual void PreRender(void);
+ virtual void Render(void);
+ virtual bool SetupLighting(void);
+ virtual void RemoveLighting(bool reset);
+
+ void dtor(void) { this->CCutsceneObject::~CCutsceneObject(); }
+ void SetModelIndex_(uint32 id) { CCutsceneObject::SetModelIndex(id); }
+ void ProcessControl_(void) { CCutsceneObject::ProcessControl(); }
+ void PreRender_(void) { CCutsceneObject::PreRender(); }
+ void Render_(void) { CCutsceneObject::Render(); }
+ bool SetupLighting_(void) { return CCutsceneObject::SetupLighting(); }
+ void RemoveLighting_(bool reset) { CCutsceneObject::RemoveLighting(reset); }
+};
+static_assert(sizeof(CCutsceneObject) == 0x198, "CCutsceneObject: error");
diff --git a/src/objects/DummyObject.cpp b/src/objects/DummyObject.cpp
new file mode 100644
index 00000000..1e4b2ae0
--- /dev/null
+++ b/src/objects/DummyObject.cpp
@@ -0,0 +1,17 @@
+#include "common.h"
+#include "patcher.h"
+#include "DummyObject.h"
+#include "Pools.h"
+
+CDummyObject::CDummyObject(CObject *obj)
+{
+ SetModelIndexNoCreate(obj->GetModelIndex());
+ if(obj->m_rwObject)
+ AttachToRwObject(obj->m_rwObject);
+ obj->DetachFromRwObject();
+ m_level = obj->m_level;
+}
+
+STARTPATCHES
+ InjectHook(0x4BAB70, &CDummyObject::dtor, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/objects/DummyObject.h b/src/objects/DummyObject.h
new file mode 100644
index 00000000..10554bdd
--- /dev/null
+++ b/src/objects/DummyObject.h
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "Dummy.h"
+
+class CObject;
+
+class CDummyObject : public CDummy
+{
+public:
+ CDummyObject(void) {}
+ CDummyObject(CObject *obj);
+ void dtor(void) { this->CDummyObject::~CDummyObject(); }
+};
+static_assert(sizeof(CDummyObject) == 0x68, "CDummyObject: error");
diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp
new file mode 100644
index 00000000..6712d77b
--- /dev/null
+++ b/src/objects/Object.cpp
@@ -0,0 +1,93 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "Lights.h"
+#include "Pools.h"
+#include "Radar.h"
+#include "Object.h"
+
+WRAPPER void CObject::ObjectDamage(float amount) { EAXJMP(0x4BB240); }
+
+int16 &CObject::nNoTempObjects = *(int16*)0x95CCA2;
+
+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); }
+
+CObject::CObject(void)
+{
+ m_type = ENTITY_TYPE_OBJECT;
+ m_fUprootLimit = 0.0f;
+ m_nCollisionDamageEffect = 0;
+ m_nSpecialCollisionResponseCases = COLLRESPONSE_NONE;
+ m_bCameraToAvoidThisObject = false;
+ ObjectCreatedBy = 0;
+ m_nEndOfLifeTime = 0;
+// m_nRefModelIndex = -1; // duplicate
+// bUseVehicleColours = false; // duplicate
+ m_colour2 = 0;
+ m_colour1 = m_colour2;
+ field_172 = 0;
+ bIsPickup = false;
+ m_obj_flag2 = false;
+ m_obj_flag4 = false;
+ m_obj_flag8 = false;
+ m_obj_flag10 = false;
+ bHasBeenDamaged = false;
+ m_nRefModelIndex = -1;
+ bUseVehicleColours = false;
+ m_pCurSurface = nil;
+ m_pCollidingEntity = nil;
+}
+
+CObject::~CObject(void)
+{
+ CRadar::ClearBlipForEntity(BLIP_OBJECT, CPools::GetObjectPool()->GetIndex(this));
+
+ if(m_nRefModelIndex != -1)
+ CModelInfo::GetModelInfo(m_nRefModelIndex)->RemoveRef();
+
+ if(ObjectCreatedBy == TEMP_OBJECT && nNoTempObjects != 0)
+ nNoTempObjects--;
+}
+
+void
+CObject::Render(void)
+{
+ if(m_flagD80)
+ return;
+
+ if(m_nRefModelIndex != -1 && ObjectCreatedBy == TEMP_OBJECT && bUseVehicleColours){
+ CVehicleModelInfo *mi = (CVehicleModelInfo*)CModelInfo::GetModelInfo(m_nRefModelIndex);
+ assert(mi->m_type == MITYPE_VEHICLE);
+ mi->SetVehicleColour(m_colour1, m_colour2);
+ }
+
+ CEntity::Render();
+}
+
+bool
+CObject::SetupLighting(void)
+{
+ DeActivateDirectional();
+ SetAmbientColours();
+
+ if(bRenderScorched){
+ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f);
+ return true;
+ }
+ return false;
+}
+
+void
+CObject::RemoveLighting(bool reset)
+{
+ if(reset)
+ WorldReplaceScorchedLightsWithNormal(Scene.world);
+}
+
+WRAPPER void CObject::DeleteAllTempObjectInArea(CVector, float) { EAXJMP(0x4BBED0); }
+
+STARTPATCHES
+ InjectHook(0x4BAE00, &CObject::dtor, PATCH_JUMP);
+ InjectHook(0x4BB1E0, &CObject::Render_, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/objects/Object.h b/src/objects/Object.h
new file mode 100644
index 00000000..de4c8e05
--- /dev/null
+++ b/src/objects/Object.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include "Physical.h"
+
+enum {
+ GAME_OBJECT = 1,
+ MISSION_OBJECT = 2,
+ TEMP_OBJECT = 3,
+ CUTSCENE_OBJECT = 4,
+};
+
+enum {
+ COLLRESPONSE_NONE,
+ COLLRESPONSE_CHANGE_MODEL,
+ COLLRESPONSE_SPLIT_MODEL,
+ COLLRESPONSE_SMASH_COMPLETELY,
+ COLLRESPONSE_CHANGE_THEN_SMASH,
+ COLLRESPONSE_UNKNOWN5,
+
+ COLLRESPONSE_SMASH_CARDBOARD_COMPLETELY = 50,
+ COLLRESPONSE_SMASH_WOODENBOX_COMPLETELY = 60,
+ COLLRESPONSE_SMASH_TRAFFICCONE_COMPLETELY = 70,
+ COLLRESPONSE_SMASH_BARPOST_COMPLETELY = 80,
+
+};
+
+class CVehicle;
+
+class CObject : public CPhysical
+{
+public:
+ CMatrix m_objectMatrix;
+ float m_fUprootLimit;
+ int8 ObjectCreatedBy;
+ int8 bIsPickup : 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 bUseVehicleColours : 1;
+ int8 m_obj_flag80 : 1;
+ int8 field_172;
+ int8 field_173;
+ float m_fCollisionDamageMultiplier;
+ uint8 m_nCollisionDamageEffect;
+ uint8 m_nSpecialCollisionResponseCases;
+ bool 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 *m_pCollidingEntity;
+ int8 m_colour1, m_colour2;
+
+ static int16 &nNoTempObjects;
+
+ static void *operator new(size_t);
+ static void operator delete(void*, size_t);
+
+ CObject(void);
+ ~CObject(void);
+
+ void Render(void);
+ bool SetupLighting(void);
+ void RemoveLighting(bool reset);
+
+ void ObjectDamage(float amount);
+
+ static void DeleteAllTempObjectInArea(CVector, float);
+
+ void dtor(void) { this->CObject::~CObject(); }
+ void Render_(void) { CObject::Render(); }
+};
+static_assert(sizeof(CObject) == 0x198, "CObject: error");
diff --git a/src/objects/ObjectData.cpp b/src/objects/ObjectData.cpp
new file mode 100644
index 00000000..ef5bcc5e
--- /dev/null
+++ b/src/objects/ObjectData.cpp
@@ -0,0 +1,103 @@
+#include "common.h"
+#include "patcher.h"
+#include "main.h"
+#include "ModelInfo.h"
+#include "Object.h"
+#include "FileMgr.h"
+#include "ObjectData.h"
+
+CObjectInfo CObjectData::ms_aObjectInfo[NUMOBJECTINFO];
+
+// Another ugly file reader
+void
+CObjectData::Initialise(const char *filename)
+{
+ char *p, *lp;
+ char line[1024], name[256];
+ int id;
+ float percentSubmerged;
+ int damageEffect, responseCase, camAvoid;
+ CBaseModelInfo *mi;
+
+ CFileMgr::SetDir("");
+ CFileMgr::LoadFile(filename, work_buff, sizeof(work_buff), "r");
+
+ id = 0;
+ p = (char*)work_buff;
+ while(*p != '*'){
+ // skip over white space and comments
+ while(*p == ' ' || *p == '\n' || *p == '\r' || *p == ';')
+ if(*p == ';')
+ while(*p != '\n' && *p != '*')
+ p++;
+ else
+ p++;
+
+ if(*p == '*')
+ break;
+
+ // read one line
+ lp = line;
+ while(*p != '\n' && *p != '*'){
+ *lp++ = *p == ',' ? ' ' : *p;
+ p++;
+ }
+ if(*p == '\n')
+ p++;
+ *lp = '\0'; // FIX: game wrote '\n' here
+
+ assert(id < NUMOBJECTINFO);
+ sscanf(line, "%s %f %f %f %f %f %f %f %d %d %d", name,
+ &ms_aObjectInfo[id].m_fMass,
+ &ms_aObjectInfo[id].m_fTurnMass,
+ &ms_aObjectInfo[id].m_fAirResistance,
+ &ms_aObjectInfo[id].m_fElasticity,
+ &percentSubmerged,
+ &ms_aObjectInfo[id].m_fUprootLimit,
+ &ms_aObjectInfo[id].m_fCollisionDamageMultiplier,
+ &damageEffect, &responseCase, &camAvoid);
+
+ ms_aObjectInfo[id].m_fBuoyancy = 100.0f/percentSubmerged * 0.008*ms_aObjectInfo[id].m_fMass;
+ ms_aObjectInfo[id].m_nCollisionDamageEffect = damageEffect;
+ ms_aObjectInfo[id].m_nSpecialCollisionResponseCases = responseCase;
+ ms_aObjectInfo[id].m_bCameraToAvoidThisObject = camAvoid;
+
+ mi = CModelInfo::GetModelInfo(name, nil);
+ if(mi)
+ mi->SetObjectID(id++);
+ else
+ debug("CObjectData: Cannot find object %s\n", name);
+ }
+}
+
+void
+CObjectData::SetObjectData(int32 modelId, CObject &object)
+{
+ CObjectInfo *objinfo;
+
+ if(CModelInfo::GetModelInfo(modelId)->GetObjectID() == -1)
+ return;
+
+ objinfo = &ms_aObjectInfo[CModelInfo::GetModelInfo(modelId)->GetObjectID()];
+
+ object.m_fMass = objinfo->m_fMass;
+ object.m_fTurnMass = objinfo->m_fTurnMass;
+ object.m_fAirResistance = objinfo->m_fAirResistance;
+ object.m_fElasticity = objinfo->m_fElasticity;
+ object.m_fBuoyancy = objinfo->m_fBuoyancy;
+ object.m_fUprootLimit = objinfo->m_fUprootLimit;
+ object.m_fCollisionDamageMultiplier = objinfo->m_fCollisionDamageMultiplier;
+ object.m_nCollisionDamageEffect = objinfo->m_nCollisionDamageEffect;
+ object.m_nSpecialCollisionResponseCases = objinfo->m_nSpecialCollisionResponseCases;
+ object.m_bCameraToAvoidThisObject = objinfo->m_bCameraToAvoidThisObject;
+ if(object.m_fMass >= 99998.0){
+ object.bInfiniteMass = true;
+ object.bAffectedByGravity = false;
+ object.m_flagB2 = true;
+ }
+}
+
+STARTPATCHES
+ InjectHook(0x4BC0E0, CObjectData::Initialise, PATCH_JUMP);
+ InjectHook(0x4BC270, CObjectData::SetObjectData, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/objects/ObjectData.h b/src/objects/ObjectData.h
new file mode 100644
index 00000000..e3a5c1bd
--- /dev/null
+++ b/src/objects/ObjectData.h
@@ -0,0 +1,27 @@
+#pragma once
+
+class CObject;
+
+class CObjectInfo
+{
+public:
+ float m_fMass;
+ float m_fTurnMass;
+ float m_fAirResistance;
+ float m_fElasticity;
+ float m_fBuoyancy;
+ float m_fUprootLimit;
+ float m_fCollisionDamageMultiplier;
+ uint8 m_nCollisionDamageEffect;
+ uint8 m_nSpecialCollisionResponseCases;
+ bool m_bCameraToAvoidThisObject;
+};
+static_assert(sizeof(CObjectInfo) == 0x20, "CObjectInfo: error");
+
+class CObjectData
+{
+ static CObjectInfo ms_aObjectInfo[NUMOBJECTINFO];
+public:
+ static void Initialise(const char *filename);
+ static void SetObjectData(int32 modelId, CObject &object);
+};
diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp
new file mode 100644
index 00000000..cf6e84bf
--- /dev/null
+++ b/src/objects/ParticleObject.cpp
@@ -0,0 +1,23 @@
+#include "common.h"
+#include "patcher.h"
+#include "ParticleObject.h"
+
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, float size, bool remove) { EAXJMP(0x4BC520); }
+WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove) { EAXJMP(0x4BC570); }
+
+// Converted from static void __cdecl CParticleObject::Initialise() 0x42C760
+void CParticleObject::Initialise()
+{
+ ((void (__cdecl *)())0x4BC440)();
+}
+
+// Converted from static void __cdecl CParticleObject::UpdateAll() 0x4BCA30
+void CParticleObject::UpdateAll()
+{
+ ((void (__cdecl *)())0x4BCA30)();
+}
+
+STARTPATCHES
+ InjectHook(0x4BC420, &CParticleObject::dtor, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/objects/ParticleObject.h b/src/objects/ParticleObject.h
new file mode 100644
index 00000000..def7b7de
--- /dev/null
+++ b/src/objects/ParticleObject.h
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "Placeable.h"
+
+enum eParticleObjectType
+{
+ POBJECT_PAVEMENT_STEAM,
+ POBJECT_PAVEMENT_STEAM_SLOWMOTION,
+ POBJECT_WALL_STEAM,
+ POBJECT_WALL_STEAM_SLOWMOTION,
+ POBJECT_DARK_SMOKE,
+ POBJECT_FIRE_HYDRANT,
+ POBJECT_CAR_WATER_SPLASH,
+ POBJECT_PED_WATER_SPLASH,
+ POBJECT_SPLASHES_AROUND,
+ POBJECT_SMALL_FIRE,
+ POBJECT_BIG_FIRE,
+ POBJECT_DRY_ICE,
+ POBJECT_DRY_ICE_SLOWMOTION,
+ POBJECT_FIRE_TRAIL,
+ POBJECT_SMOKE_TRAIL,
+ POBJECT_FIREBALL_AND_SMOKE,
+ POBJECT_ROCKET_TRAIL,
+ POBJECT_EXPLOSION_ONCE,
+ POBJECT_CATALINAS_GUNFLASH,
+ POBJECT_CATALINAS_SHOTGUNFLASH,
+};
+
+class CParticleObject : CPlaceable
+{
+public:
+ static void AddObject(uint16 type, const CVector &pos, bool remove);
+ static void AddObject(uint16 type, const CVector &pos, float size, bool remove);
+ static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove);
+ static void Initialise();
+ static void UpdateAll();
+
+ void dtor() { this->CParticleObject::~CParticleObject(); }
+};
diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp
new file mode 100644
index 00000000..e21323de
--- /dev/null
+++ b/src/objects/Projectile.cpp
@@ -0,0 +1,7 @@
+#include "common.h"
+#include "patcher.h"
+#include "Projectile.h"
+
+STARTPATCHES
+ InjectHook(0x4BFED0, &CProjectile::dtor, PATCH_JUMP);
+ENDPATCHES \ No newline at end of file
diff --git a/src/objects/Projectile.h b/src/objects/Projectile.h
new file mode 100644
index 00000000..a8e826b6
--- /dev/null
+++ b/src/objects/Projectile.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#pragma once
+
+#include "Object.h"
+
+class CProjectile : public CObject
+{
+public:
+ void dtor(void) { this->CProjectile::~CProjectile(); }
+};