Files
GTASource/game/Vehicles/Automobile.h
T
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

526 lines
18 KiB
C++

// Title : Automobile.h
// Author : Richard Jobling/William Henderson
// Started : 25/08/99
//
// 27/03/01 - Andrzej: AddWheelDirt() added;
//
//
//
#ifndef _AUTOMOBILE_H_
#define _AUTOMOBILE_H_
// Rage Headers
#include "phCore/segment.h"
#include "physics/constrainthandle.h"
#include "physics/intersection.h"
// Game Headers
#include "renderer/hierarchyIds.h"
#include "vehicles/handlingMgr.h"
#include "vehicles/vehicle.h"
#include "network/objects/entities/netObjAutomobile.h"
class phInstGta;
struct ConfigVehiclePositionLightSettings;
struct ConfigVehicleWhiteLightSettings;
namespace rage { class CNodeAddress; }
#define HORN_TIME 34 // how many frames the horn should be played (audio will create patterns)
#define MAX_ASYNC_PLACE_ON_ROAD_ENTRIES (16)
#define INVALID_ASYNC_ENTRY ((u32)-1)
//
//
//
class CAutomobile : public CVehicle
{
public:
struct CAutomobileFlags
{
u8 bTaxiLight : 1; // Is the wee light on the taxi switched on
u8 bWaterTight : 1; // If TRUE then non-player characters inside won't take damage if the car ends up in water
u8 bIsBoggedDownInSand : 1; // car is bogged down (sorta stuck but can move slowly) in sand
u8 bFireNetworkCannon : 1; // if this is a networked fire truck this indicates the fire truck is firing it's cannon
u8 bBurnoutModeEnabled : 1; // car is in script burnout mode
u8 bInBurnout : 1; // car is in a player driven burnout
u8 bReduceGripModeEnabled : 1; // car is in reduce grip mode
u8 bPlayerIsRevvingEngineThisFrame : 1;
u8 bLastSpaceAvaliableToChangeBounds : 1;
u8 bDropsMoneyWhenBlownUp : 1; // Used for security vans, etc. Will generate a bunch of money pickups when blown up
u8 bHydraulicsBounceRaising : 1;
u8 bHydraulicsBounceLanding : 1;
u8 bHydraulicsJump : 1;
u8 bForceUpdateGroundClearance : 1;
u8 bWheelieModeEnabled : 1;
u8 bInWheelieMode : 1;
u8 bInWheelieModeWheelsUp : 1;
};
struct PlaceOnRoadAsyncData
{
Matrix34* matrix;
u32 modelInfo;
typedef WorldProbe::CShapeTestResults RoughHeightResults;
typedef WorldProbe::CShapeTestResults WheelResults;
RoughHeightResults* roughHeightResults;
WheelResults* wheelResults;
Vector3 aWheelPos[4];
float frontHeightAboveGround;
float rearHeightAboveGround;
u32 id;
RegdAutomobile automobile;
};
protected:
// This is PROTECTED as only CVEHICLEFACTORY is allowed to call this - make sure you use CVehicleFactory!
// DONT make this public!
CAutomobile(const eEntityOwnedBy ownedBy, u32 popType, VehicleType vehType);
friend class CVehicleFactory;
public:
~CAutomobile();
virtual void SetModelId(fwModelId modelId);
// virtual wheel stuff
virtual void InitWheels();
virtual void SetupWheels(const void* basePtr);
virtual bool IsInAir(bool bCheckForZeroVelocity = true) const;
// virtual door stuff
virtual void InitDoors();
// so derived versions of InitDoors can set the car door pointer in vehicle.h
CCarDoor* GetCarDoorPointer() {return m_aCarDoors;}
// process functions
virtual void DoProcessControl(bool fullUpdate, float fFullUpdateTimeStep);
virtual void ProcessDriverInputOptions();
virtual void ProcessFlightHandling(float fTimeStep);
void ProcessSubmarineHandling(float fTimeStep);
virtual void ProcessDriverInputsForStability(float fTimeStep);
// physics
virtual ePhysicsResult ProcessPhysics(float fTimeStep, bool bCanPostpone, int nTimeSlice);
void StartWheelIntegratorTask(phCollider* pCollider, float fTimeStep);
virtual ePhysicsResult ProcessPhysics2(float fTimeStep, int nTimeSlice);
virtual ePhysicsResult ProcessPhysics3(float fTimeStep, int nTimeSlice);
#if GTA_REPLAY
void ProcessReplayPhysics(float fTimeStep, int nTimeSlice);
#endif
void ProcessPossiblyTouchesWater(float fTimeStep, int nTimeSlice, const CVehicleModelInfo* pModelInfo);
virtual void ProcessProbes(const Matrix34& testMat);
void ProcessProbeResults(const Matrix34& testMat);
void UpdateAirResistance();
virtual int InitPhys();
virtual void InitCompositeBound();
virtual void InitDummyInst();
virtual void RemoveDummyInst();
virtual bool UsesDummyPhysics(const eVehicleDummyMode vdm) const;
virtual void ChangeDummyConstraints(const eVehicleDummyMode dummyMode, bool bIsStatic);
virtual void UpdateDummyConstraints(const Vec3V * pDistanceConstraintPos=NULL, const float * pDistanceConstraintMaxLength=NULL);
virtual bool HasDummyConstraint() const {return m_dummyStayOnRoadConstraintHandle.IsValid();}
#if __BANK
void ValidateDummyConstraints(Vec3V_In vVehPos, Vec3V_In vConstraintPos, float fConstraintLength);
#endif
bool RemoveConstraints();
bool UpdateDesiredGroundGroundClearance(float fGroundClearance, bool brokenWheels = false, bool force = false); // Make sure the bounds of the vehicle is always higher than the ground clearance, set force to true to bypass the check that this has already been done
float GetGroundClearance(){return m_fGroundClearance;}
void SetMinHydraulicsGroundClearance();
bool IsCarFloating(); // Car is floating in water but hasn't started to sink yet
// render
virtual ePrerenderStatus PreRender(const bool bIsVisibleInMainViewport = true);
virtual void PreRender2(const bool bIsVisibleInMainViewport = true);
void ProcessSuspensionTransforms();
void ProcessSuspensionTransformsForMiniTank();
void ProcessFakeBodyMovement(bool bIsGamePaused);
void PreRenderSuspensionMod(const float fFakeSuspensionLowerAmount);
void SetFakeSuspensionLoweringAmount(float fSuspensionLowering){m_fFakeSuspensionLowerAmount = fSuspensionLowering;}
float GetFakeSuspensionLoweringAmount() const { return m_fFakeSuspensionLowerAmount; }
float GetFakeSuspensionLoweringAmountApplied() const { return m_fFakeSuspensionLowerAmountApplied; }
void SetHydraulicsBounds(float fUpperBound, float lowerBound){m_fHydraulicsUpperBound = fUpperBound; m_fHydraulicsLowerBound = lowerBound;}
void SetHydraulicsRate(float fRate){m_fHydraulicsRate = fRate;}
void GetHydraulicsBounds(float &fUpperBound, float &lowerBound){fUpperBound = m_fHydraulicsUpperBound; lowerBound = m_fHydraulicsLowerBound;}
float GetHydraulicsRate(){ return m_fHydraulicsRate; }
bool HasHydraulicSuspension() const {return m_fHydraulicsUpperBound != 0.0f || m_fHydraulicsLowerBound != 0.0f;}
void SetTimeHyrdaulicsModified(u32 uTimeModified) { m_iTimeHydraulicsModified = uTimeModified; }
u32 GetTimeHydraulicsModified() const { return m_iTimeHydraulicsModified; }
// damage
virtual void Fix(bool resetFrag = true, bool allowNetwork = false);
virtual void BlowUpCar( CEntity *pCulprit, bool bInACutscene = false, bool bAddExplosion = true, bool bNetCall = false, u32 weaponHash = WEAPONTYPE_EXPLOSION, bool bDelayedExplosion = false);
virtual const eHierarchyId* GetExtraBonesToDeform(int& extraBoneCount);
virtual void NotifyWheelPopped(CWheel *pWheel);
virtual void ApplyDeformationToBones(const void* basePtr);
void ApplySteeringBias(float bias, float lifetime);
// script
virtual void CleanupMissionState();
// misc AI
void ScanForCrimes();
static const u32 DEFAULT_DOOR_TIME_TO_OPEN = 500;
static const u32 DEFAULT_DOOR_TIME_TO_CLOSE = DEFAULT_DOOR_TIME_TO_OPEN;
enum eStatus
{
OPEN_THEN_CLOSE,
CLOSE_ONLY
};
void SetAutoDoorTimer(u32 nTime, eStatus status, u32 uDoorTimeToOpen = DEFAULT_DOOR_TIME_TO_OPEN, u32 uDoorTimeToClose = DEFAULT_DOOR_TIME_TO_CLOSE);
void ProcessAutoBusDoors();
void ProcessAutoTurretDoors();
virtual void PlayCarHorn(bool bOneShot = false, u32 hornTypeHash = 0);
void SetTaxiLight(bool bOn) { m_nAutomobileFlags.bTaxiLight = bOn; }
// misc
static void GetVehicleMovementStickInput(const CControl& rControl, float& fStickX, float& fStickY);
static bool PlaceOnRoadProperly(CAutomobile* pAutomobile, Matrix34 *pMat, CInteriorInst*& pDestInteriorInst, s32& destRoomIdx, bool& setWaitForAllCollisionsBeforeProbe, u32 MI, phInst* pTestException, bool useVirtualRoad, CNodeAddress* aNodes, s16 * aLinks, s32 numNodes, float HeightSampleRangeUp = PLACEONROAD_DEFAULTHEIGHTUP, float HeightSampleRangeDown = PLACEONROAD_DEFAULTHEIGHTDOWN);
static u32 PlaceOnRoadProperlyAsync(CAutomobile* pAutomobile, Matrix34 *pMat, u32 MI, float HeightSampleRangeUp = PLACEONROAD_DEFAULTHEIGHTUP, float HeightSampleRangeDown = PLACEONROAD_DEFAULTHEIGHTDOWN);
static bool HasPlaceOnRoadProperlyFinished(u32 id, CInteriorInst*& pDestInteriorInst, s32& destRoomIdx, u32& failed, RegdEnt* hitEntities = NULL, float* hitPos = NULL);
float GetHeightAboveRoad() const { return m_fHeightAboveRoad; }
void EnableBurnoutMode(bool bEnableBurnout);
virtual bool GetBurnoutMode() const { return m_nAutomobileFlags.bBurnoutModeEnabled; } //script burnout mode
bool IsInBurnout() { return m_nAutomobileFlags.bInBurnout; } //player driven burnout
void SetInBurnout(bool inBurnout) { m_nAutomobileFlags.bInBurnout = inBurnout; }
void EnableReduceGripMode(bool bEnableReduceGrip) { m_nAutomobileFlags.bReduceGripModeEnabled = bEnableReduceGrip; }
bool GetReduceGripMode(){ return m_nAutomobileFlags.bReduceGripModeEnabled; }
void SetReduceGripLevel( int reducedGripLevel );
bool GetReducedSuspensionForce();
void SetReducedSuspensionForce( bool bReduceSuspensionForce );
// Handbrake
// For automobiles we fade the handbrake over time
// So use this function to get the strength
float GetHandBrakeForce() const;
float GetHandBrakeGripMult() const; // Lower traction on wheels after pulling the handbrake.. to try and make it easier to drift
void SetSteeringBiasScalar(float fScalar) {m_fSteeringBiasScalar = fScalar;}
#if __BANK
virtual void RenderDebug() const;
void DrawGForce() const;
void DrawAngularAcceleration() const;
static u32 GetAsyncQueueCount();
#endif
float GetFakeRotationY() {return m_fFakeRotationY;}
void ResetHydraulics();
void UpdateHydraulicsFlags( CAutomobile* pAutomobile );
protected:
virtual bool PlaceOnRoadAdjustInternal(float HeightSampleRangeUp, float HeightSampleRangeDown, bool bJustSetCompression);
// lights
void DoWhiteLightEffects(s32 boneIdx, const ConfigVehicleWhiteLightSettings &lightParam, bool frontLight, float distFade);
void DoPosLightEffects(s32 boneIdx, const ConfigVehiclePositionLightSettings &lightParam, bool isRight, bool isAnnihilator, float distFade);
bool ShouldUpdateVehicleDamageEveryFrame() const;
void ModifyControlsIfDucked(const CPed* pDriver, float fTimeStep);
void FixHydraulicSuspensionClipping();
static s32 CleanUpPlacementArray(bool getFirstFree);
// Why are these member variables public?
// Todo: make protected
public:
WheelIntegrationState m_WheelIntegrator;
static float CAR_INAIR_ROT_X;
static float CAR_INAIR_ROT_Y;
static float CAR_INAIR_ROT_Z;
static float CAR_STUCK_ROT_X;
static float CAR_STUCK_ROT_Y;
static float CAR_STUCK_ROT_Y_SELF_RIGHT; // Torque only allowed in self righting direction
static float CAR_INAIR_ROTLIM;
static float CAR_INAIR_REDUCED_ROTLIM;
static float CAR_BURNOUT_SPEED;
static float CAR_BURNOUT_ROT_Z;
static float CAR_BURNOUT_ROTLIM;
static float CAR_BURNOUT_WHEELS_OFFGROUND_MULT;
static float QUADBIKE_BURNOUT_ROT_Z;
static float QUADBIKE_BURNOUT_ROTLIM;
static float QUADBIKE_BURNOUT_WHEEL_SPEED_MULT;
static float OFFROAD_VEH_BURNOUT_ROT_Z;
static float OFFROAD_VEH_BURNOUT_ROTLIM;
static float OFFROAD_VEH_BURNOUT_WHEEL_SPEED_MULT;
static float BIG_CAR_BURNOUT_ROT_Z;
static float BIG_CAR_BURNOUT_ROTLIM;
static float BIG_CAR_BURNOUT_WHEEL_SPEED_MULT;
static float BURNOUT_WHEEL_SPEED_MULT;
static float BURNOUT_TORQUE_MULT;
static float POSSIBLY_STUCK_SPEED;
static float COMPLETELY_STUCK_SPEED;
static bool ms_bUseAsyncWheelProbes;
static float ms_fBumpSeverityMulti;
BANK_ONLY(static bool ms_bDrawWheelProbeResults;)
phConstraintHandle m_dummyStayOnRoadConstraintHandle;
phConstraintHandle m_dummyRotationalConstraint;
CAutomobileFlags m_nAutomobileFlags;
virtual void ProcessTimeStartedFailingRealConversion();
void SetStartedFailingRealConversion();
u32 GetTimeStartedFailingRealConversion() const {return m_TimeStartedFailingRealConversion;}
float GetMaxLengthForDummyConstraintsAfterFailedConversion(bool& bMaxShrinkage) const;
virtual bool HasShrunkDummyConstraintsAsMuchAsPossible() const
{
bool bMaxShrinkage = false;
GetMaxLengthForDummyConstraintsAfterFailedConversion(bMaxShrinkage);
return bMaxShrinkage;
}
virtual void ResetRealConversionFailedData()
{
m_TimeStartedFailingRealConversion = 0;
m_fConstraintDistanceWhenRealConversionFailed = -1.0f;
}
float m_fConstraintDistanceWhenRealConversionFailed;
u32 m_TimeStartedFailingRealConversion;
u32 m_nAutoDoorTimer;
u32 m_nAutoDoorStart;
float m_fHeightAboveRoad;
float m_fGroundClearance;
float m_fLastGroundClearance;
float m_fLastGroundClearanceHeightAboveGround;
u32 m_uLastGroundClearanceCheck;
float m_bIgnoreWorldHeightMapForWheelProbes;
float m_fTimeInWater; // How long we have been sinking in the water (i.e. car is dead in water) Only resets when we leave water... so can accumulate over time
float m_fOrigBuoyancyForceMult; // Keep track of original float multiplier so we can reset it
bool CanDeployParachute() { return m_bCanDeployParachute; }
// Request start car parachuting sequence
void StartParachuting();
// Finish parachuting sequence
// This attempts to finish parachuting once and is not guaranteed to finish parachuting (if the parachute is being created at the time of calling for example)
void FinishParachuting();
// Put in a request to finish parachuting
// This repeatedly attempts to destroy the parachute until it is successful
void RequestFinishParachuting() { m_bFinishParachutingRequested = true; }
// Set/Get for whether the player can cancel parachuting
void SetCanPlayerDetachParachute(bool bNewValue) { m_bCanPlayerDetachParachute = bNewValue; }
bool GetCanPlayerDetachParachute() { return m_bCanPlayerDetachParachute; }
bool IsFinishParachutingRequested() { return m_bFinishParachutingRequested; }
void SetCloneParachuting(bool parachuting)
{
if(GetNetworkObject() && GetNetworkObject()->IsClone())
{
parachuting ? m_carParachuteState = CLONE_CAR_PARACHUTING : m_carParachuteState = CAR_NOT_PARACHUTING;
}
}
// Accessor to check if a car is in parachute mode
bool IsParachuting() const { return m_carParachuteState != CAR_NOT_PARACHUTING; }
bool IsDeployingParachute() const { return m_carParachuteState == CAR_DEPLOYING_PARACHUTE; }
const CObject* GetParachuteObject() const { return m_pParachuteObject.Get(); }
void SetParachuteTintIndex(u8 idx) { m_nParachuteTintIndex=idx; }
u8 GetParachuteTintIndex() const { return m_nParachuteTintIndex; };
void GetCloneParachuteStickValues(float &xVal, float &yVal) { xVal = m_fCloneParachuteStickX; yVal = m_fCloneParachuteStickY; }
void SetCloneParachuteStickValues(float xVal, float yVal) { m_fCloneParachuteStickX = xVal; m_fCloneParachuteStickY = yVal; }
private:
// arrays of wheels and doors
CCarDoor m_aCarDoors[NUM_VEH_DOORS_MAX];
// The array needs to be aligned so that it can be sent to the SPU
// The SPU task needs to know the address of the PPU wheels so that it can send them back
CWheel* m_pCarWheels[NUM_VEH_CWHEELS_MAX] ; // Store array of pointers so they don't have to be consecutive
NETWORK_OBJECT_TYPE_DECL( CNetObjAutomobile, NET_OBJ_TYPE_AUTOMOBILE );
static atFixedArray<CAutomobile::PlaceOnRoadAsyncData, MAX_ASYNC_PLACE_ON_ROAD_ENTRIES> ms_placeOnRoadArray;
WorldProbe::CShapeTestSingleResult* m_pWheelProbeResults;
WorldProbe::CShapeTestHitPoint* m_pWheelProbePreviousResults;
float m_fFakeRotationY;
float m_fHighSpeedRotationY;
float m_fHighSpeedDirectionY;
float m_fHighSpeedYTime;
float m_fBumpSeverityY;
float m_fBumpRateY;
float m_fBumpSeverityYDecay;
float m_fFakeSuspensionLowerAmount;
float m_fFakeSuspensionLowerAmountApplied; // How much suspension lowering we have done in prerender 2
float m_fHydraulicsUpperBound;
float m_fHydraulicsLowerBound;
float m_fHydraulicsRate;
u32 m_iTimeHydraulicsModified;
float m_fBurnoutRotationTime;
float m_fSteeringBias;
float m_fSteeringBiasLife;
float m_fSteeringBiasScalar;
// PURPOSE: Used by ProcessPhysics() to hold the last return value from
// CTransmission::Process(), so we can apply it if we skip this call
// on the second simulation step.
float m_fLastDriveForce;
Vector3 m_vSuspensionDeformationLF;
Vector3 m_vSuspensionDeformationRF;
static float m_sfPassengerMassMult;
// Car parachute /////////////////////////////////
RegdObj m_pParachuteObject;
strRequest m_ModelRequestHelper;
u32 m_iParachuteModelIndex;
bool m_wasCloneParachuting;
float m_fParachuteStickX;
float m_fParachuteStickY;
float m_fCloneParachuteStickX;
float m_fCloneParachuteStickY;
float m_fParachuteHatchOffset;
u8 m_nParachuteTintIndex;
bool m_bCanDeployParachute;
bool m_bFinishParachutingRequested;
bool m_bCanPlayerDetachParachute;
bool m_bHasBeenParachuting;
public:
enum ECarParachuteState
{
CAR_NOT_PARACHUTING,
CAR_STABILISING,
CAR_CREATING_PARACHUTE,
CAR_DEPLOYING_PARACHUTE,
CAR_PARACHUTING,
CLONE_CAR_PARACHUTING
};
private:
ECarParachuteState m_carParachuteState;
void ProcessParachutePhysics();
void ProcessCarParachute();
void ProcessCarParachuteTint();
void StreamInParachute();
bool IsParachuteStreamedIn() { return m_ModelRequestHelper.HasLoaded(); }
void CreateParachute();
void AttachParachuteToVehicle();
void DetachParachuteFromVehicle();
void DestroyParachute();
public:
bool IsParachuteDeployed() const;
void SetParachuteState(ECarParachuteState parachuteState) { m_carParachuteState = parachuteState; } // this was added for replay
ECarParachuteState GetParachuteState() { return m_carParachuteState; } // this was added for replay
// End Car parachute
private:
void SlipperyBoxInitialise();
float m_fSlipperyBoxLimitX;
float m_fSlipperyBoxLimitY;
void ApplyDifferentials();
public:
void SlipperyBoxUpdateLimits( float limitModifier );
void SlipperyBoxBreakOff();
};
//
//
//
class CQuadBike : public CAutomobile
{
protected:
// This is PROTECTED as only CVEHICLEFACTORY is allowed to call this - make sure you use CVehicleFactory!
// DONT make this public!
CQuadBike(const eEntityOwnedBy ownedBy, u32 popType);
friend class CVehicleFactory;
public:
~CQuadBike();
// physics
virtual ePhysicsResult ProcessPhysics(float fTimeStep, bool bCanPostpone, int nTimeSlice);
virtual void ProcessPostPhysics();
virtual void ProcessDriverInputsForStability( float fTimeStep );
virtual ePrerenderStatus PreRender( const bool bIsVisibleInMainViewport );
#if __BANK
static void InitWidgets(bkBank& pBank);
#endif // __BANk
static bank_float ms_fQuadBikeSelfRightingTorqueScale;
static bank_float ms_fQuadBikeAntiRollOverTorqueScale;
};
#endif//_AUTOMOBILE_H_