mirror of
https://github.com/halpz/re3.git
synced 2025-07-03 07:20:48 +00:00
Merge branch 'master' into master
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,21 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "DamageManager.h"
|
||||
#include "Vehicle.h"
|
||||
#include "DamageManager.h"
|
||||
#include "Door.h"
|
||||
|
||||
struct CDoor
|
||||
{
|
||||
float m_fAngleWhenOpened;
|
||||
float m_fAngleWhenClosed;
|
||||
char field_8;
|
||||
char field_9;
|
||||
char field_10;
|
||||
char field_11;
|
||||
float m_fAngle;
|
||||
float m_fPreviousAngle;
|
||||
float m_fAngularVelocity;
|
||||
CVector m_vecVelocity;
|
||||
};
|
||||
class CObject;
|
||||
|
||||
class CAutomobile : public CVehicle
|
||||
{
|
||||
@ -28,20 +17,28 @@ public:
|
||||
float m_aSuspensionSpringRatio[4];
|
||||
float m_aSuspensionSpringRatioPrev[4];
|
||||
float m_aWheelSkidThing[4];
|
||||
int field_49C;
|
||||
float field_49C;
|
||||
bool m_aWheelSkidmarkMuddy[4];
|
||||
bool m_aWheelSkidmarkBloody[4];
|
||||
float m_aWheelRotation[4];
|
||||
float m_aWheelPosition[4];
|
||||
float m_aWheelSpeed[4];
|
||||
uint8 stuff3[12];
|
||||
uint8 field_4D8;
|
||||
uint8 m_auto_flagA7 : 1;
|
||||
uint8 bTaxiLight : 1;
|
||||
uint8 m_auto_flagA10 : 1;
|
||||
uint8 m_auto_flagA20 : 1;
|
||||
uint8 m_auto_flagA40 : 1;
|
||||
uint8 m_auto_flagA80 : 1;
|
||||
uint8 field_4DA[10];
|
||||
uint32 m_nBusDoorTimerEnd;
|
||||
uint32 m_nBusDoorTimerStart;
|
||||
float m_aSuspensionSpringLength[4];
|
||||
float m_aSuspensionLineLength[4];
|
||||
float m_fHeightAboveRoad;
|
||||
float m_fImprovedHandling;
|
||||
uint8 stuff6[32];
|
||||
uint8 stuff6[28];
|
||||
float field_530;
|
||||
CPhysical *m_aGroundPhysical[4]; // physicals touching wheels
|
||||
CVector m_aGroundOffset[4]; // from ground object to colpoint
|
||||
CEntity *m_pBlowUpEntity;
|
||||
@ -57,11 +54,66 @@ public:
|
||||
uint8 stuff5[5];
|
||||
int32 m_aWheelState[4];
|
||||
|
||||
static bool &m_sAllTaxiLights;
|
||||
|
||||
CAutomobile(int, uint8);
|
||||
|
||||
// from CEntity
|
||||
void SetModelIndex(uint32 id);
|
||||
void ProcessControl(void);
|
||||
void Teleport(CVector v);
|
||||
void PreRender(void);
|
||||
void Render(void);
|
||||
|
||||
// from CPhysical
|
||||
int32 ProcessEntityCollision(CEntity *ent, CColPoint *colpoints);
|
||||
|
||||
// from CVehicle
|
||||
void ProcessControlInputs(uint8);
|
||||
void GetComponentWorldPosition(int32 component, CVector &pos);
|
||||
bool IsComponentPresent(int32 component);
|
||||
void SetComponentRotation(int32 component, CVector rotation);
|
||||
void OpenDoor(int32 component, eDoors door, float openRatio);
|
||||
void ProcessOpenDoor(uint32, uint32, float);
|
||||
bool IsDoorReady(eDoors door);
|
||||
bool IsDoorFullyOpen(eDoors door);
|
||||
bool IsDoorClosed(eDoors door);
|
||||
bool IsDoorMissing(eDoors door);
|
||||
void RemoveRefsToVehicle(CEntity *ent);
|
||||
void BlowUpCar(CEntity *ent);
|
||||
bool SetUpWheelColModel(CColModel *colModel);
|
||||
void BurstTyre(uint8 tyre);
|
||||
bool IsRoomForPedToLeaveCar(uint32, CVector *);
|
||||
float GetHeightAboveRoad(void);
|
||||
void PlayCarHorn(void);
|
||||
|
||||
void PlayHornIfNecessary(void);
|
||||
void ResetSuspension(void);
|
||||
void SetupSuspensionLines(void);
|
||||
void ScanForCrimes(void);
|
||||
void BlowUpCarsInPath(void);
|
||||
bool HasCarStoppedBecauseOfLight(void);
|
||||
void SetBusDoorTimer(uint32 timer, uint8 type);
|
||||
void ProcessAutoBusDoors(void);
|
||||
void ProcessSwingingDoor(int32 component, eDoors door);
|
||||
void SetupDamageAfterLoad(void);
|
||||
CObject *SpawnFlyingComponent(int32 component, uint32 type);
|
||||
CObject *RemoveBonnetInPedCollision(void);
|
||||
void SetPanelDamage(int32 component, ePanels panel, bool noFlyingComponents = false);
|
||||
void SetBumperDamage(int32 component, ePanels panel, bool noFlyingComponents = false);
|
||||
void SetDoorDamage(int32 component, eDoors door, bool noFlyingComponents = false);
|
||||
|
||||
void Fix(void);
|
||||
void SetComponentVisibility(RwFrame *frame, uint32 flags);
|
||||
void SetupModelNodes(void);
|
||||
void SetTaxiLight(bool light);
|
||||
bool GetAllWheelsOffGround(void);
|
||||
void HideAllComps(void);
|
||||
void ShowAllComps(void);
|
||||
void ReduceHornCounter(void);
|
||||
|
||||
static void SetAllTaxiLights(bool set);
|
||||
|
||||
CAutomobile* ctor(int, uint8);
|
||||
void SetDoorDamage(int32, uint32, bool); /* TODO: eDoors */
|
||||
void SetPanelDamage(int32, uint32, bool); /* TODO: ePanels */
|
||||
void SetBumperDamage(int32, uint32, bool); /* TODO: ePanels */
|
||||
void dtor() { this->CAutomobile::~CAutomobile(); }
|
||||
};
|
||||
static_assert(sizeof(CAutomobile) == 0x5A8, "CAutomobile: error");
|
||||
|
@ -20,7 +20,6 @@ CBoat::CBoat(int mi, uint8 owner)
|
||||
|
||||
WRAPPER CBoat* CBoat::ctor(int, uint8) { EAXJMP(0x53E3E0); }
|
||||
|
||||
|
||||
bool CBoat::IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats)
|
||||
{
|
||||
uint8 numVerts = 0;
|
||||
@ -71,7 +70,12 @@ float CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat)
|
||||
|
||||
WRAPPER void CBoat::FillBoatList(void) { EAXJMP(0x542250); }
|
||||
|
||||
class CBoat_ : public CBoat
|
||||
{
|
||||
public:
|
||||
void dtor() { CBoat::~CBoat(); };
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x53E790, &CBoat::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
InjectHook(0x53E790, &CBoat_::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -49,6 +49,7 @@ public:
|
||||
static bool IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats);
|
||||
static float IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat);
|
||||
static void FillBoatList(void);
|
||||
|
||||
};
|
||||
static_assert(sizeof(CBoat) == 0x484, "CBoat: error");
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "General.h"
|
||||
#include "Vehicle.h"
|
||||
#include "DamageManager.h"
|
||||
|
||||
|
||||
|
@ -4,6 +4,28 @@
|
||||
|
||||
// TODO: move some of this into Vehicle.h
|
||||
|
||||
enum eDoorStatus
|
||||
{
|
||||
DOOR_STATUS_OK,
|
||||
DOOR_STATUS_SMASHED,
|
||||
DOOR_STATUS_SWINGING,
|
||||
DOOR_STATUS_MISSING
|
||||
};
|
||||
|
||||
enum ePanelStatus
|
||||
{
|
||||
PANEL_STATUS_OK,
|
||||
PANEL_STATUS_SMASHED1,
|
||||
PANEL_STATUS_SMASHED2,
|
||||
PANEL_STATUS_MISSING,
|
||||
};
|
||||
|
||||
enum eWheelStatus
|
||||
{
|
||||
WHEEL_STATUS_OK,
|
||||
WHEEL_STATUS_BURST
|
||||
};
|
||||
|
||||
enum tComponent
|
||||
{
|
||||
COMPONENT_DEFAULT,
|
||||
@ -37,23 +59,7 @@ enum tComponentGroup
|
||||
COMPGROUP_DEFAULT,
|
||||
};
|
||||
|
||||
enum eLights
|
||||
{
|
||||
VEHLIGHT_FRONT_LEFT,
|
||||
VEHLIGHT_FRONT_RIGHT,
|
||||
VEHLIGHT_REAR_LEFT,
|
||||
VEHLIGHT_REAR_RIGHT,
|
||||
};
|
||||
|
||||
enum {
|
||||
VEHPANEL_FRONT_LEFT,
|
||||
VEHPANEL_FRONT_RIGHT,
|
||||
VEHPANEL_REAR_LEFT,
|
||||
VEHPANEL_REAR_RIGHT,
|
||||
VEHPANEL_WINDSCREEN,
|
||||
VEHBUMPER_FRONT,
|
||||
VEHBUMPER_REAR,
|
||||
};
|
||||
enum eLights;
|
||||
|
||||
class CDamageManager
|
||||
{
|
||||
|
126
src/vehicles/Door.cpp
Normal file
126
src/vehicles/Door.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Door.h"
|
||||
|
||||
CDoor::CDoor(void)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
void
|
||||
CDoor::Open(float ratio)
|
||||
{
|
||||
float open;
|
||||
|
||||
m_fPrevAngle = m_fAngle;
|
||||
open = RetAngleWhenOpen();
|
||||
if(ratio < 1.0f){
|
||||
m_fAngle = open*ratio;
|
||||
if(m_fAngle == 0.0f)
|
||||
m_fAngVel = 0.0f;
|
||||
}else{
|
||||
m_nDoorState = DOORST_OPEN;
|
||||
m_fAngle = open;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDoor::Process(CVehicle *vehicle)
|
||||
{
|
||||
static CVector vecOffset(1.0f, 0.0f, 0.0f);
|
||||
CVector speed = vehicle->GetSpeed(vecOffset);
|
||||
CVector vecSpeedDiff = speed - m_vecSpeed;
|
||||
vecSpeedDiff = Multiply3x3(vecSpeedDiff, vehicle->GetMatrix());
|
||||
|
||||
// air resistance
|
||||
float fSpeedDiff = 0.0f; // uninitialized in game
|
||||
switch(m_nAxis){
|
||||
case 0: // x-axis
|
||||
if(m_nDirn)
|
||||
fSpeedDiff = vecSpeedDiff.y + vecSpeedDiff.z;
|
||||
else
|
||||
fSpeedDiff = -(vecSpeedDiff.y + vecSpeedDiff.z);
|
||||
break;
|
||||
|
||||
// we don't support y axis apparently?
|
||||
|
||||
case 2: // z-axis
|
||||
if(m_nDirn)
|
||||
fSpeedDiff = -(vecSpeedDiff.x + vecSpeedDiff.y);
|
||||
else
|
||||
fSpeedDiff = vecSpeedDiff.x + vecSpeedDiff.y;
|
||||
break;
|
||||
}
|
||||
fSpeedDiff = clamp(fSpeedDiff, -0.2f, 0.2f);
|
||||
if(Abs(fSpeedDiff) > 0.002f)
|
||||
m_fAngVel += fSpeedDiff;
|
||||
m_fAngVel *= 0.945f;
|
||||
m_fAngVel = clamp(m_fAngVel, -0.3f, 0.3f);
|
||||
|
||||
m_fAngle += m_fAngVel;
|
||||
m_nDoorState = DOORST_SWINGING;
|
||||
if(m_fAngle > m_fMaxAngle){
|
||||
m_fAngle = m_fMaxAngle;
|
||||
m_fAngVel *= -0.8f;
|
||||
m_nDoorState = DOORST_OPEN;
|
||||
}
|
||||
if(m_fAngle < m_fMinAngle){
|
||||
m_fAngle = m_fMinAngle;
|
||||
m_fAngVel *= -0.8f;
|
||||
m_nDoorState = DOORST_CLOSED;
|
||||
}
|
||||
m_vecSpeed = speed;
|
||||
}
|
||||
|
||||
float
|
||||
CDoor::RetAngleWhenClosed(void)
|
||||
{
|
||||
if(Abs(m_fMaxAngle) < Abs(m_fMinAngle))
|
||||
return m_fMaxAngle;
|
||||
else
|
||||
return m_fMinAngle;
|
||||
}
|
||||
|
||||
float
|
||||
CDoor::RetAngleWhenOpen(void)
|
||||
{
|
||||
if(Abs(m_fMaxAngle) < Abs(m_fMinAngle))
|
||||
return m_fMinAngle;
|
||||
else
|
||||
return m_fMaxAngle;
|
||||
}
|
||||
|
||||
float
|
||||
CDoor::GetAngleOpenRatio(void)
|
||||
{
|
||||
float open = RetAngleWhenOpen();
|
||||
if(open == 0.0f)
|
||||
return 0.0f;
|
||||
return m_fAngle/open;
|
||||
}
|
||||
|
||||
bool
|
||||
CDoor::IsFullyOpen(void)
|
||||
{
|
||||
// why -0.5? that's around 28 deg less than fully open
|
||||
if(Abs(m_fAngle) < Abs(RetAngleWhenOpen()) - 0.5f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CDoor::IsClosed(void)
|
||||
{
|
||||
return m_fAngle == RetAngleWhenClosed();
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x545EF0, &CDoor::Open, PATCH_JUMP);
|
||||
InjectHook(0x545BD0, &CDoor::Process, PATCH_JUMP);
|
||||
InjectHook(0x545FE0, &CDoor::RetAngleWhenClosed, PATCH_JUMP);
|
||||
InjectHook(0x546020, &CDoor::RetAngleWhenOpen, PATCH_JUMP);
|
||||
InjectHook(0x545F80, &CDoor::GetAngleOpenRatio, PATCH_JUMP);
|
||||
InjectHook(0x546090, &CDoor::IsFullyOpen, PATCH_JUMP);
|
||||
InjectHook(0x546060, &CDoor::IsClosed, PATCH_JUMP);
|
||||
ENDPATCHES
|
36
src/vehicles/Door.h
Normal file
36
src/vehicles/Door.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
class CVehicle;
|
||||
|
||||
enum eDoorState
|
||||
{
|
||||
DOORST_SWINGING,
|
||||
// actually wrong though,
|
||||
// OPEN is really MAX_ANGLE and CLOSED is MIN_ANGLE
|
||||
DOORST_OPEN,
|
||||
DOORST_CLOSED
|
||||
};
|
||||
|
||||
struct CDoor
|
||||
{
|
||||
float m_fMaxAngle;
|
||||
float m_fMinAngle;
|
||||
// direction of rotation for air resistance
|
||||
int8 m_nDirn;
|
||||
// axis in which this door rotates
|
||||
int8 m_nAxis;
|
||||
int8 m_nDoorState;
|
||||
float m_fAngle;
|
||||
float m_fPrevAngle;
|
||||
float m_fAngVel;
|
||||
CVector m_vecSpeed;
|
||||
|
||||
CDoor(void);
|
||||
void Open(float ratio);
|
||||
void Process(CVehicle *veh);
|
||||
float RetAngleWhenClosed(void);
|
||||
float RetAngleWhenOpen(void);
|
||||
float GetAngleOpenRatio(void);
|
||||
bool IsFullyOpen(void);
|
||||
bool IsClosed(void);
|
||||
};
|
@ -119,7 +119,9 @@ VALIDATE_SIZE(tHandlingData, 0xD8);
|
||||
class cHandlingDataMgr
|
||||
{
|
||||
float field_0; // unused it seems
|
||||
public:
|
||||
float field_4; // wheel related
|
||||
private:
|
||||
float field_8; //
|
||||
float field_C; // unused it seems
|
||||
float field_10; //
|
||||
|
@ -10,6 +10,12 @@ CHeli::CHeli(int mi, uint8 owner)
|
||||
WRAPPER CHeli* CHeli::ctor(int, uint8) { EAXJMP(0x547220); }
|
||||
WRAPPER void CHeli::SpecialHeliPreRender(void) { EAXJMP(0x54AE10); }
|
||||
|
||||
class CHeli_ : public CHeli
|
||||
{
|
||||
public:
|
||||
void dtor(void) { CHeli::~CHeli(); }
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x5474A0, &CHeli::dtor, PATCH_JUMP);
|
||||
InjectHook(0x5474A0, &CHeli_::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -10,7 +10,6 @@ public:
|
||||
|
||||
CHeli(int, uint8);
|
||||
CHeli* ctor(int, uint8);
|
||||
void dtor(void) { this->CHeli::~CHeli(); }
|
||||
|
||||
static void SpecialHeliPreRender(void);
|
||||
};
|
||||
|
@ -14,6 +14,12 @@ CPlane::~CPlane()
|
||||
DeleteRwObject();
|
||||
}
|
||||
|
||||
class CPlane_ : public CPlane
|
||||
{
|
||||
public:
|
||||
void dtor(void) { CPlane::~CPlane(); }
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x54B270, &CPlane::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
InjectHook(0x54B270, &CPlane_::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -12,7 +12,6 @@ public:
|
||||
CPlane(int, uint8);
|
||||
~CPlane(void);
|
||||
CPlane* ctor(int, uint8);
|
||||
void dtor(void) { this->CPlane::~CPlane(); }
|
||||
void FlagToDestroyWhenNextProcessed() { bRemoveFromWorld = true; }
|
||||
};
|
||||
static_assert(sizeof(CPlane) == 0x29C, "CPlane: error");
|
||||
|
@ -9,6 +9,12 @@ CTrain::CTrain(int mi, uint8 owner)
|
||||
|
||||
WRAPPER CTrain* CTrain::ctor(int, uint8) { EAXJMP(0x54E2A0); }
|
||||
|
||||
class CTrain_ : public CTrain
|
||||
{
|
||||
public:
|
||||
void dtor(void) { CTrain::~CTrain(); }
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x54E450, &CTrain::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
InjectHook(0x54E450, &CTrain_::dtor, PATCH_JUMP);
|
||||
ENDPATCHES
|
||||
|
@ -21,6 +21,5 @@ public:
|
||||
|
||||
CTrain(int, uint8);
|
||||
CTrain* ctor(int, uint8);
|
||||
void dtor(void) { this->CTrain::~CTrain(); }
|
||||
};
|
||||
static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error");
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "common.h"
|
||||
#include "main.h"
|
||||
#include "patcher.h"
|
||||
#include "General.h"
|
||||
#include "Timer.h"
|
||||
#include "Pad.h"
|
||||
#include "Vehicle.h"
|
||||
#include "Pools.h"
|
||||
#include "HandlingMgr.h"
|
||||
@ -13,6 +15,7 @@
|
||||
#include "PointLights.h"
|
||||
#include "Renderer.h"
|
||||
#include "DMAudio.h"
|
||||
#include "MusicManager.h"
|
||||
#include "Radar.h"
|
||||
|
||||
bool &CVehicle::bWheelsOnlyCheat = *(bool *)0x95CD78;
|
||||
@ -27,6 +30,79 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP
|
||||
void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
|
||||
void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); }
|
||||
|
||||
CVehicle::CVehicle(uint8 CreatedBy)
|
||||
{
|
||||
int i;
|
||||
|
||||
m_nCurrentGear = 0;
|
||||
field_208 = 0;
|
||||
m_fSteerRatio = 0.0f;
|
||||
m_type = ENTITY_TYPE_VEHICLE;
|
||||
VehicleCreatedBy = CreatedBy;
|
||||
bIsLocked = false;
|
||||
bIsLawEnforcer = false;
|
||||
bIsAmbulanceOnDuty = false;
|
||||
bIsFireTruckOnDuty = false;
|
||||
CCarCtrl::UpdateCarCount(this, false);
|
||||
m_fHealth = 1000.0f;
|
||||
bEngineOn = true;
|
||||
bFreebies = true;
|
||||
pDriver = nil;
|
||||
m_nNumPassengers = 0;
|
||||
m_nNumGettingIn = 0;
|
||||
m_nGettingInFlags = 0;
|
||||
m_nGettingOutFlags = 0;
|
||||
m_nNumMaxPassengers = 8;
|
||||
for(i = 0; i < m_nNumMaxPassengers; i++)
|
||||
pPassengers[i] = nil;
|
||||
m_nBombTimer = 0;
|
||||
m_pWhoSetMeOnFire = nil;
|
||||
field_1FB = 0;
|
||||
m_veh_flagB10 = false;
|
||||
m_veh_flagB40 = false;
|
||||
m_veh_flagB80 = false;
|
||||
m_veh_flagC1 = false;
|
||||
bIsDamaged = false;
|
||||
m_veh_flagC8 = false;
|
||||
m_veh_flagC10 = false;
|
||||
m_veh_flagC4 = false;
|
||||
m_veh_flagC20 = false;
|
||||
bCanBeDamaged = true;
|
||||
m_veh_flagC80 = false;
|
||||
m_veh_flagD1 = false;
|
||||
m_veh_flagD2 = false;
|
||||
m_nGunFiringTime = 0;
|
||||
field_214 = 0;
|
||||
bLightsOn = false;
|
||||
bVehicleColProcessed = false;
|
||||
field_1F9 = 0;
|
||||
bIsCarParkVehicle = false;
|
||||
bHasAlreadyBeenRecorded = false;
|
||||
m_bSirenOrAlarm = 0;
|
||||
m_nCarHornTimer = 0;
|
||||
field_22D = 0;
|
||||
m_nAlarmState = 0;
|
||||
m_nDoorLock = CARLOCK_UNLOCKED;
|
||||
m_nLastWeaponDamage = -1;
|
||||
field_220 = 0.0;
|
||||
field_21C = field_220;
|
||||
m_audioEntityId = DMAudio.CreateEntity(0, this);
|
||||
if(m_audioEntityId)
|
||||
DMAudio.SetEntityStatus(m_audioEntityId, true);
|
||||
m_nRadioStation = CGeneral::GetRandomNumber() % USERTRACK;
|
||||
m_pCurGroundEntity = nil;
|
||||
field_22A = 0;
|
||||
field_22B = 0;
|
||||
field_22F = 0;
|
||||
m_aCollPolys[0].valid = false;
|
||||
m_aCollPolys[1].valid = false;
|
||||
m_autoPilot.m_nCarMission = MISSION_NONE;
|
||||
m_autoPilot.m_nAnimationId = TEMPACT_NONE;
|
||||
m_autoPilot.m_nTimeToStartMission = CTimer::GetTimeInMilliseconds();
|
||||
m_autoPilot.m_flag4 = false;
|
||||
m_autoPilot.m_flag10 = false;
|
||||
}
|
||||
|
||||
CVehicle::~CVehicle()
|
||||
{
|
||||
m_nAlarmState = 0;
|
||||
@ -92,9 +168,227 @@ CVehicle::RemoveLighting(bool reset)
|
||||
float
|
||||
CVehicle::GetHeightAboveRoad(void)
|
||||
{
|
||||
return -1.0f * CModelInfo::GetModelInfo(GetModelIndex())->GetColModel()->boundingBox.min.z;
|
||||
return -1.0f * GetColModel()->boundingBox.min.z;
|
||||
}
|
||||
|
||||
void
|
||||
CVehicle::FlyingControl(eFlightModel flightModel)
|
||||
{
|
||||
switch(flightModel){
|
||||
case FLIGHT_MODEL_DODO:
|
||||
{
|
||||
// This seems pretty magic
|
||||
|
||||
// Move Left/Right
|
||||
float moveSpeed = m_vecMoveSpeed.Magnitude();
|
||||
float sideSpeed = DotProduct(m_vecMoveSpeed, GetRight());
|
||||
float sideImpulse = -1.0f * sideSpeed / moveSpeed;
|
||||
float fwdSpeed = DotProduct(m_vecMoveSpeed, GetForward());
|
||||
float magic = m_vecMoveSpeed.MagnitudeSqr() * sq(fwdSpeed);
|
||||
float turnImpulse = (sideImpulse*0.003f + m_fSteerAngle*0.001f) *
|
||||
magic*m_fTurnMass*CTimer::GetTimeStep();
|
||||
ApplyTurnForce(turnImpulse*GetRight(), -4.0f*GetForward());
|
||||
|
||||
float impulse = sideImpulse*0.2f *
|
||||
magic*m_fMass*CTimer::GetTimeStep();
|
||||
ApplyMoveForce(impulse*GetRight());
|
||||
ApplyTurnForce(impulse*GetRight(), 2.0f*GetUp());
|
||||
|
||||
|
||||
// Move Up/Down
|
||||
moveSpeed = m_vecMoveSpeed.Magnitude();
|
||||
float upSpeed = DotProduct(m_vecMoveSpeed, GetUp());
|
||||
float upImpulse = -1.0f * upSpeed / moveSpeed;
|
||||
turnImpulse = (upImpulse*0.002f + -CPad::GetPad(0)->GetSteeringUpDown()/128.0f*0.001f) *
|
||||
magic*m_fTurnMass*CTimer::GetTimeStep();
|
||||
ApplyTurnForce(turnImpulse*GetUp(), -4.0f*GetForward());
|
||||
|
||||
impulse = (upImpulse*3.5f + 0.5f)*0.05f *
|
||||
magic*m_fMass*CTimer::GetTimeStep();
|
||||
if(GRAVITY*m_fMass*CTimer::GetTimeStep() < impulse &&
|
||||
GetPosition().z > 100.0f)
|
||||
impulse = 0.9f*GRAVITY*m_fMass*CTimer::GetTimeStep();
|
||||
CVector com = Multiply3x3(GetMatrix(), m_vecCentreOfMass);
|
||||
ApplyMoveForce(impulse*GetUp());
|
||||
ApplyTurnForce(impulse*GetUp(), 2.0f*GetUp() + com);
|
||||
|
||||
|
||||
m_vecTurnSpeed.y *= Pow(0.9f, CTimer::GetTimeStep());
|
||||
moveSpeed = m_vecMoveSpeed.MagnitudeSqr();
|
||||
if(moveSpeed > 2.25f)
|
||||
m_vecMoveSpeed *= 1.5f/Sqrt(moveSpeed);
|
||||
|
||||
float turnSpeed = m_vecTurnSpeed.MagnitudeSqr();
|
||||
if(turnSpeed > 0.04f)
|
||||
m_vecTurnSpeed *= 0.2f/Sqrt(turnSpeed);
|
||||
}
|
||||
break;
|
||||
|
||||
case FLIGHT_MODEL_RCPLANE:
|
||||
case FLIGHT_MODEL_SEAPLANE:
|
||||
assert(0 && "Plane flight model not implemented");
|
||||
case FLIGHT_MODEL_HELI:
|
||||
assert(0 && "Heli flight model not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CVehicle::ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
|
||||
int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus)
|
||||
{
|
||||
// BUG: using statics here is probably a bad idea
|
||||
static bool bAlreadySkidding = false; // this is never reset
|
||||
static bool bBraking;
|
||||
static bool bDriving;
|
||||
|
||||
// how much force we want to apply in these axes
|
||||
float fwd = 0.0f;
|
||||
float right = 0.0f;
|
||||
|
||||
bBraking = brake != 0.0f;
|
||||
if(bBraking)
|
||||
thrust = 0.0f;
|
||||
bDriving = thrust != 0.0f;
|
||||
|
||||
float contactSpeedFwd = DotProduct(wheelContactSpeed, wheelFwd);
|
||||
float contactSpeedRight = DotProduct(wheelContactSpeed, wheelRight);
|
||||
|
||||
if(*wheelState != WHEEL_STATE_0)
|
||||
bAlreadySkidding = true;
|
||||
*wheelState = WHEEL_STATE_0;
|
||||
|
||||
adhesion *= CTimer::GetTimeStep();
|
||||
if(bAlreadySkidding)
|
||||
adhesion *= m_handling->fTractionLoss;
|
||||
|
||||
// moving sideways
|
||||
if(contactSpeedRight != 0.0f){
|
||||
// exert opposing force
|
||||
right = -contactSpeedRight/wheelsOnGround;
|
||||
|
||||
if(wheelStatus == WHEEL_STATUS_BURST){
|
||||
float fwdspeed = min(contactSpeedFwd, 0.3f);
|
||||
right += fwdspeed * CGeneral::GetRandomNumberInRange(-0.1f, 0.1f);
|
||||
}
|
||||
}
|
||||
|
||||
if(bDriving){
|
||||
fwd = thrust;
|
||||
|
||||
// limit sideways force (why?)
|
||||
if(right > 0.0f){
|
||||
if(right > adhesion)
|
||||
right = adhesion;
|
||||
}else{
|
||||
if(right < -adhesion)
|
||||
right = -adhesion;
|
||||
}
|
||||
}else if(contactSpeedFwd != 0.0f){
|
||||
fwd = -contactSpeedFwd/wheelsOnGround;
|
||||
|
||||
if(!bBraking){
|
||||
if(m_fGasPedal < 0.01f){
|
||||
if(GetModelIndex() == MI_RCBANDIT)
|
||||
brake = 0.2f * mod_HandlingManager.field_4 / m_fMass;
|
||||
else
|
||||
brake = mod_HandlingManager.field_4 / m_fMass;
|
||||
}
|
||||
}
|
||||
|
||||
if(brake > adhesion){
|
||||
if(Abs(contactSpeedFwd) > 0.005f)
|
||||
*wheelState = WHEEL_STATE_STATIC;
|
||||
}else {
|
||||
if(fwd > 0.0f){
|
||||
if(fwd > brake)
|
||||
fwd = brake;
|
||||
}else{
|
||||
if(fwd < -brake)
|
||||
fwd = -brake;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sq(adhesion) < sq(right) + sq(fwd)){
|
||||
if(*wheelState != WHEEL_STATE_STATIC){
|
||||
if(bDriving && contactSpeedFwd < 0.2f)
|
||||
*wheelState = WHEEL_STATE_1;
|
||||
else
|
||||
*wheelState = WHEEL_STATE_2;
|
||||
}
|
||||
|
||||
float l = Sqrt(sq(right) + sq(fwd));
|
||||
float tractionLoss = bAlreadySkidding ? 1.0f : m_handling->fTractionLoss;
|
||||
right *= adhesion * tractionLoss / l;
|
||||
fwd *= adhesion * tractionLoss / l;
|
||||
}
|
||||
|
||||
if(fwd != 0.0f || right != 0.0f){
|
||||
CVector direction = fwd*wheelFwd + right*wheelRight;
|
||||
float speed = direction.Magnitude();
|
||||
direction.Normalise();
|
||||
|
||||
float impulse = speed*m_fMass;
|
||||
float turnImpulse = speed*GetMass(wheelContactPoint, direction);
|
||||
|
||||
ApplyMoveForce(impulse * direction);
|
||||
ApplyTurnForce(turnImpulse * direction, wheelContactPoint);
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius)
|
||||
{
|
||||
float angularVelocity;
|
||||
switch(state){
|
||||
case WHEEL_STATE_1:
|
||||
angularVelocity = -1.1f; // constant speed forward
|
||||
break;
|
||||
case WHEEL_STATE_STATIC:
|
||||
angularVelocity = 0.0f; // not moving
|
||||
break;
|
||||
default:
|
||||
angularVelocity = -DotProduct(fwd, speed) / radius; // forward speed
|
||||
break;
|
||||
}
|
||||
return angularVelocity * CTimer::GetTimeStep();
|
||||
}
|
||||
|
||||
void
|
||||
CVehicle::ExtinguishCarFire(void)
|
||||
{
|
||||
m_fHealth = max(m_fHealth, 300.0f);
|
||||
if(m_pCarFire)
|
||||
m_pCarFire->Extinguish();
|
||||
if(IsCar()){
|
||||
CAutomobile *car = (CAutomobile*)this;
|
||||
if(car->Damage.GetEngineStatus() >= 225)
|
||||
car->Damage.SetEngineStatus(215);
|
||||
car->field_530 = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CVehicle::ProcessDelayedExplosion(void)
|
||||
{
|
||||
if(m_nBombTimer == 0)
|
||||
return;
|
||||
|
||||
if(m_nBombTimer == 0){
|
||||
int tick = CTimer::GetTimeStep()/60.0f*1000.0f;
|
||||
if(tick > m_nBombTimer)
|
||||
m_nBombTimer = 0;
|
||||
else
|
||||
m_nBombTimer -= tick;
|
||||
|
||||
if(IsCar() && ((CAutomobile*)this)->m_auto_flagA7 == 4 && (m_nBombTimer & 0xFE00) != 0xFE00)
|
||||
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_BOMB_TICK, 0.0f);
|
||||
|
||||
if(FindPlayerVehicle() != this && m_pWhoSetMeOnFire == FindPlayerPed())
|
||||
CWorld::Players[CWorld::PlayerInFocus].AwardMoneyForExplosion(this);
|
||||
BlowUpCar(m_pWhoSetMeOnFire);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CVehicle::IsLawEnforcementVehicle(void)
|
||||
@ -258,9 +552,9 @@ CVehicle::CanPedExitCar(void)
|
||||
if(m_vecMoveSpeed.MagnitudeSqr() > 0.005f)
|
||||
return false;
|
||||
// if car is slow enough, check turn speed
|
||||
if(fabs(m_vecTurnSpeed.x) > 0.01f ||
|
||||
fabs(m_vecTurnSpeed.y) > 0.01f ||
|
||||
fabs(m_vecTurnSpeed.z) > 0.01f)
|
||||
if(Abs(m_vecTurnSpeed.x) > 0.01f ||
|
||||
Abs(m_vecTurnSpeed.y) > 0.01f ||
|
||||
Abs(m_vecTurnSpeed.z) > 0.01f)
|
||||
return false;
|
||||
return true;
|
||||
}else{
|
||||
@ -270,9 +564,9 @@ CVehicle::CanPedExitCar(void)
|
||||
if(m_vecMoveSpeed.MagnitudeSqr() >= 0.005f)
|
||||
return false;
|
||||
// if car is slow enough, check turn speed
|
||||
if(fabs(m_vecTurnSpeed.x) >= 0.01f ||
|
||||
fabs(m_vecTurnSpeed.y) >= 0.01f ||
|
||||
fabs(m_vecTurnSpeed.z) >= 0.01f)
|
||||
if(Abs(m_vecTurnSpeed.x) >= 0.01f ||
|
||||
Abs(m_vecTurnSpeed.y) >= 0.01f ||
|
||||
Abs(m_vecTurnSpeed.z) >= 0.01f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@ -442,7 +736,7 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius)
|
||||
float x, y, z;
|
||||
// sphere relative to vehicle
|
||||
CVector sph = CVector(sx, sy, sz) - GetPosition();
|
||||
CColModel *colmodel = CModelInfo::GetModelInfo(GetModelIndex())->GetColModel();
|
||||
CColModel *colmodel = GetColModel();
|
||||
|
||||
x = DotProduct(sph, GetRight());
|
||||
if(colmodel->boundingBox.min.x - radius > x ||
|
||||
@ -460,12 +754,28 @@ CVehicle::IsSphereTouchingVehicle(float sx, float sy, float sz, float radius)
|
||||
return true;
|
||||
}
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x551170, &CVehicle::SetModelIndex_, PATCH_JUMP);
|
||||
InjectHook(0x4A7DD0, &CVehicle::SetupLighting_, PATCH_JUMP);
|
||||
InjectHook(0x4A7E60, &CVehicle::RemoveLighting_, PATCH_JUMP);
|
||||
InjectHook(0x417E60, &CVehicle::GetHeightAboveRoad_, PATCH_JUMP);
|
||||
|
||||
class CVehicle_ : public CVehicle
|
||||
{
|
||||
public:
|
||||
void dtor(void) { CVehicle::~CVehicle(); }
|
||||
void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); }
|
||||
bool SetupLighting_(void) { return CVehicle::SetupLighting(); }
|
||||
void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); }
|
||||
float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); }
|
||||
};
|
||||
|
||||
STARTPATCHES
|
||||
InjectHook(0x551170, &CVehicle_::SetModelIndex_, PATCH_JUMP);
|
||||
InjectHook(0x4A7DD0, &CVehicle_::SetupLighting_, PATCH_JUMP);
|
||||
InjectHook(0x4A7E60, &CVehicle_::RemoveLighting_, PATCH_JUMP);
|
||||
InjectHook(0x417E60, &CVehicle_::GetHeightAboveRoad_, PATCH_JUMP);
|
||||
|
||||
InjectHook(0x552BB0, &CVehicle::FlyingControl, PATCH_JUMP);
|
||||
InjectHook(0x5512E0, &CVehicle::ProcessWheel, PATCH_JUMP);
|
||||
InjectHook(0x551280, &CVehicle::ProcessWheelRotation, PATCH_JUMP);
|
||||
InjectHook(0x552AF0, &CVehicle::ExtinguishCarFire, PATCH_JUMP);
|
||||
InjectHook(0x551C90, &CVehicle::ProcessDelayedExplosion, PATCH_JUMP);
|
||||
InjectHook(0x552880, &CVehicle::IsLawEnforcementVehicle, PATCH_JUMP);
|
||||
InjectHook(0x552820, &CVehicle::ChangeLawEnforcerState, PATCH_JUMP);
|
||||
InjectHook(0x552200, &CVehicle::UsesSiren, PATCH_JUMP);
|
||||
|
@ -69,6 +69,58 @@ enum eDoors
|
||||
DOOR_REAR_RIGHT
|
||||
};
|
||||
|
||||
enum ePanels
|
||||
{
|
||||
VEHPANEL_FRONT_LEFT,
|
||||
VEHPANEL_FRONT_RIGHT,
|
||||
VEHPANEL_REAR_LEFT,
|
||||
VEHPANEL_REAR_RIGHT,
|
||||
VEHPANEL_WINDSCREEN,
|
||||
VEHBUMPER_FRONT,
|
||||
VEHBUMPER_REAR,
|
||||
};
|
||||
|
||||
enum eLights
|
||||
{
|
||||
VEHLIGHT_FRONT_LEFT,
|
||||
VEHLIGHT_FRONT_RIGHT,
|
||||
VEHLIGHT_REAR_LEFT,
|
||||
VEHLIGHT_REAR_RIGHT,
|
||||
};
|
||||
|
||||
enum eWheels
|
||||
{
|
||||
VEHWHEEL_FRONT_LEFT,
|
||||
VEHWHEEL_FRONT_RIGHT,
|
||||
VEHWHEEL_REAR_LEFT,
|
||||
VEHWHEEL_REAR_RIGHT,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CAR_PIECE_WHEEL_LF = 13,
|
||||
CAR_PIECE_WHEEL_LR,
|
||||
CAR_PIECE_WHEEL_RF,
|
||||
CAR_PIECE_WHEEL_RR,
|
||||
};
|
||||
|
||||
enum tWheelState
|
||||
{
|
||||
WHEEL_STATE_0 = 0,
|
||||
WHEEL_STATE_1 = 1, // constant velocity
|
||||
WHEEL_STATE_2 = 2, // normal
|
||||
WHEEL_STATE_STATIC = 3, // not moving
|
||||
};
|
||||
|
||||
enum eFlightModel
|
||||
{
|
||||
FLIGHT_MODEL_DODO,
|
||||
// not used in III
|
||||
FLIGHT_MODEL_RCPLANE,
|
||||
FLIGHT_MODEL_HELI,
|
||||
FLIGHT_MODEL_SEAPLANE
|
||||
};
|
||||
|
||||
class CVehicle : public CPhysical
|
||||
{
|
||||
public:
|
||||
@ -88,7 +140,7 @@ public:
|
||||
int8 m_nGettingOutFlags;
|
||||
uint8 m_nNumMaxPassengers;
|
||||
char field_1CD[19];
|
||||
CEntity *m_pCurSurface;
|
||||
CEntity *m_pCurGroundEntity;
|
||||
CFire *m_pCarFire;
|
||||
float m_fSteerAngle;
|
||||
float m_fGasPedal;
|
||||
@ -115,19 +167,19 @@ public:
|
||||
uint8 m_veh_flagB80 : 1;
|
||||
|
||||
uint8 m_veh_flagC1 : 1;
|
||||
uint8 m_veh_flagC2 : 1;
|
||||
uint8 bIsDamaged : 1; // This vehicle has been damaged and is displaying all its components
|
||||
uint8 m_veh_flagC4 : 1;
|
||||
uint8 m_veh_flagC8 : 1;
|
||||
uint8 m_veh_flagC10 : 1;
|
||||
uint8 m_veh_flagC20 : 1;
|
||||
uint8 m_veh_flagC40 : 1;
|
||||
uint8 bCanBeDamaged : 1; // Set to FALSE during cut scenes to avoid explosions
|
||||
uint8 m_veh_flagC80 : 1;
|
||||
|
||||
uint8 m_veh_flagD1 : 1;
|
||||
uint8 m_veh_flagD2 : 1;
|
||||
uint8 m_veh_flagD4 : 1;
|
||||
uint8 m_veh_flagD8 : 1;
|
||||
uint8 bRecordedForReplay : 1;
|
||||
uint8 bVehicleColProcessed : 1;// Has ProcessEntityCollision been processed for this car?
|
||||
uint8 bIsCarParkVehicle : 1; // Car has been created using the special CAR_PARK script command
|
||||
uint8 bHasAlreadyBeenRecorded : 1; // Used for replays
|
||||
uint8 m_veh_flagD20 : 1;
|
||||
uint8 m_veh_flagD40 : 1;
|
||||
uint8 m_veh_flagD80 : 1;
|
||||
@ -144,7 +196,7 @@ public:
|
||||
uint32 m_nTimeOfDeath;
|
||||
int16 field_214;
|
||||
int16 m_nBombTimer; // goes down with each frame
|
||||
CPed *m_pWhoDetonatedMe;
|
||||
CPed *m_pWhoSetMeOnFire;
|
||||
float field_21C;
|
||||
float field_220;
|
||||
eCarLock m_nDoorLock;
|
||||
@ -154,11 +206,9 @@ public:
|
||||
int8 field_22B;
|
||||
uint8 m_nCarHornTimer;
|
||||
int8 field_22D;
|
||||
uint8 m_nSirenOrAlarm;
|
||||
bool m_bSirenOrAlarm;
|
||||
int8 field_22F;
|
||||
// TODO: this is an array
|
||||
CStoredCollPoly m_frontCollPoly; // poly which is under front part of car
|
||||
CStoredCollPoly m_rearCollPoly; // poly which is under rear part of car
|
||||
CStoredCollPoly m_aCollPolys[2]; // poly which is under front/rear part of car
|
||||
float m_fSteerRatio;
|
||||
eVehicleType m_vehType;
|
||||
|
||||
@ -167,9 +217,11 @@ public:
|
||||
static void operator delete(void*, size_t);
|
||||
static void operator delete(void*, int);
|
||||
|
||||
CVehicle(void) {} // FAKE
|
||||
CVehicle(uint8 CreatedBy);
|
||||
~CVehicle(void);
|
||||
// from CEntity
|
||||
void SetModelIndex(uint32 i);
|
||||
void SetModelIndex(uint32 id);
|
||||
bool SetupLighting(void);
|
||||
void RemoveLighting(bool);
|
||||
void FlagToDestroyWhenNextProcessed(void) {}
|
||||
@ -197,6 +249,13 @@ public:
|
||||
bool IsTrain(void) { return m_vehType == VEHICLE_TYPE_TRAIN; }
|
||||
bool IsHeli(void) { return m_vehType == VEHICLE_TYPE_HELI; }
|
||||
bool IsPlane(void) { return m_vehType == VEHICLE_TYPE_PLANE; }
|
||||
|
||||
void FlyingControl(eFlightModel flightModel);
|
||||
void ProcessWheel(CVector &wheelFwd, CVector &wheelRight, CVector &wheelContactSpeed, CVector &wheelContactPoint,
|
||||
int32 wheelsOnGround, float thrust, float brake, float adhesion, int8 wheelId, float *wheelSpeed, tWheelState *wheelState, uint16 wheelStatus);
|
||||
void ExtinguishCarFire(void);
|
||||
void ProcessDelayedExplosion(void);
|
||||
float ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVector &speed, float radius);
|
||||
bool IsLawEnforcementVehicle(void);
|
||||
void ChangeLawEnforcerState(uint8 enable);
|
||||
bool UsesSiren(uint32 id);
|
||||
@ -225,16 +284,24 @@ public:
|
||||
static bool &bCheat4;
|
||||
static bool &bCheat5;
|
||||
static bool &m_bDisableMouseSteering;
|
||||
|
||||
|
||||
void dtor(void) { CVehicle::~CVehicle(); }
|
||||
void SetModelIndex_(uint32 id) { CVehicle::SetModelIndex(id); }
|
||||
bool SetupLighting_(void) { return CVehicle::SetupLighting(); }
|
||||
void RemoveLighting_(bool reset) { CVehicle::RemoveLighting(reset); }
|
||||
float GetHeightAboveRoad_(void) { return CVehicle::GetHeightAboveRoad(); }
|
||||
};
|
||||
|
||||
static_assert(sizeof(CVehicle) == 0x288, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_pCurSurface) == 0x1E0, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_pCurGroundEntity) == 0x1E0, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_nAlarmState) == 0x1A0, "CVehicle: error");
|
||||
static_assert(offsetof(CVehicle, m_nLastWeaponDamage) == 0x228, "CVehicle: error");
|
||||
|
||||
inline uint8 GetVehDoorFlag(int32 carnode) {
|
||||
switch (carnode) {
|
||||
case CAR_DOOR_LF:
|
||||
return 1;
|
||||
case CAR_DOOR_LR:
|
||||
return 2;
|
||||
case CAR_DOOR_RF:
|
||||
return 4;
|
||||
case CAR_DOOR_RR:
|
||||
return 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user