Merge branch 'master' into master

This commit is contained in:
Fire_Head
2019-07-11 03:48:36 +03:00
committed by GitHub
141 changed files with 6878 additions and 917 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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");

View File

@ -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

View File

@ -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");

View File

@ -1,6 +1,7 @@
#include "common.h"
#include "patcher.h"
#include "General.h"
#include "Vehicle.h"
#include "DamageManager.h"

View File

@ -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
View 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
View 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);
};

View File

@ -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; //

View File

@ -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

View File

@ -10,7 +10,6 @@ public:
CHeli(int, uint8);
CHeli* ctor(int, uint8);
void dtor(void) { this->CHeli::~CHeli(); }
static void SpecialHeliPreRender(void);
};

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -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;
}
}