Files
GTASource/game/Vehicles/vehicleDamage.h

1096 lines
40 KiB
C
Raw Permalink Normal View History

2025-02-23 17:40:52 +08:00
//
// filename: vehicleDamage.h
// description:
//
#ifndef INC_VEHICLEDAMAGE_H_
#define INC_VEHICLEDAMAGE_H_
// --- Include Files ------------------------------------------------------------
// C headers
// Rage headers
#include "grmodel/shaderGroupVar.h"
#include "phcore/materialMgr.h"
#include "phbound/surfacegrid.h"
#include "vector/vector3.h"
#include "vector/Vector4.h"
#include "vectormath/vectormath.h"
#include "math/simplemath.h"
#include "fwsys/glue.h"
#include "pedsafezone/pedsafezone.h"
#include "grcore/device.h"
#include "renderer/ApplyDamage.h"
// Game headers
#include "scene/RegdRefTypes.h"
#include "vehicles/door.h"
#include "control/replay/ReplaySettings.h"
#include "weapons/WeaponEnums.h"
#include "math/intrinsics.h"
class CEntity;
class CVehicle;
namespace rage
{
class grcRenderTarget;
class grcTexture;
}
// --- Defines ------------------------------------------------------------------
#include "shader_source/vehicles/vehicle_common_values.h"
#define VEHICLE_DEFORMATION_NOISE_SMOOTHING_OCTAVES (2)
#define VEHICLE_DEFORMATION_COLOR_VAR_MULT_MIN (ScalarVConstant<FLOAT_TO_INT(0.70f)>())
#define VEHICLE_DEFORMATION_COLOR_VAR_MULT_MAX (ScalarVConstant<FLOAT_TO_INT(1.15f)>())
#define VEHICLE_DEFORMATION_COLOR_VAR_ADD_MIN (ScalarVConstant<FLOAT_TO_INT(-0.05f)>())
#define VEHICLE_DEFORMATION_COLOR_VAR_ADD_MAX (ScalarVConstant<FLOAT_TO_INT(0.05f)>())
#if GPU_DAMAGE_WRITE_ENABLED
#define VEHICLE_DEFORMATION_TEXTURE_ARRAY_SIZE (2 * MAX_GPUS)
#define VEHICLE_DEFORMATION_TEXTURE_CACHE_SIZE_INIT (MAX_DAMAGED_VEHICLES) // first init value, initialized for real in VehicleDeformation::TexCacheInit()
#define VEHICLE_DEFORMATION_IMPACT_STORE_SIZE (MAX_IMPACTS_PER_VEHICLE_PER_FRAME)
// In DX11, blending over SNORM target is prohibited for some reason. The debug runtime issues an ERROR but everything seems to work correctly.
// Enable this for running with debug runtime if you want to work around this error.
#define VEHICLE_DEFORMATION_USE_HALF_FLOATS (0 && RSG_PC)
# if VEHICLE_DEFORMATION_USE_HALF_FLOATS
#include "half.h"
typedef uint16_t half;
struct TexelValue_A16B16G16R16F
{
half red;
half green;
half blue;
half alpha;
};
# else
struct TexelValue_R8G8B8A8_SNORM
{
s8 red;
s8 green;
s8 blue;
s8 alpha;
};
#endif //VEHICLE_DEFORMATION_USE_HALF_FLOATS
#else
#define VEHICLE_DEFORMATION_TEXTURE_CACHE_SIZE_INIT (16) // first init value, initialized for real in VehicleDeformation::TexCacheInit()
#define VEHICLE_DEFORMATION_IMPACT_STORE_SIZE (4)
#endif
#define TEXTUREOFFSET(base_,x_,y_) (base_ + (x_ + y_ * GTA_VEHICLE_DAMAGE_TEXTURE_WIDTH))
#define VEHICLE_DEFORMATION_TIMING (0)
#define TAXI_IDX (21)
#if VEHICLE_DEFORMATION_TIMING
extern void VD_DisplayTiming();
#endif
#define VEHICLE_LIGHT_COUNT (VEH_LASTBREAKABLELIGHT - VEH_HEADLIGHT_L + 1 + 1) // +1 for taxi light, +1 for array size.
#define VEHICLE_LIGHT_TAXI (VEHICLE_LIGHT_COUNT-1)
#define VEHICLE_SIREN_COUNT (VEH_SIREN_MAX - VEH_SIREN_1 + 1) // + 1 for array size
#define VEHICLEDAMAGE_USE_LINEAR_TEXTURE (1)
#if VEHICLEDAMAGE_USE_LINEAR_TEXTURE
#else // VEHICLEDAMAGE_USE_LINEAR_TEXTURE
#define DBG 0
#include "xgraphics.h"
// modified version of XGAddress2DTiledOffset
inline UINT Fast_XGAddress2DTiledOffset(const UINT x,const UINT y,const UINT Width/*,TexelPitch*/)
{
const UINT fixedLog = 2;
Assert(x < Width);
Assert(Width == (Width + 31) & ~31);
Assert(XGLog2LE16(TexelPitch) == fixedLog);
const UINT Macro = ((x >> 5) + (y >> 5) * (Width >> 5)) << (fixedLog + 7);
const UINT Micro = (((x & 7) + ((y & 6) << 2)) << fixedLog);
const UINT Offset = Macro + ((Micro & ~15) << 1) + (Micro & 15) + ((y & 8) << (3 + fixedLog)) + ((y & 1) << 4);
const UINT result = (((Offset & ~511) << 3) + ((Offset & 448) << 2) + (Offset & 63) +
((y & 16) << 7) + (((((y & 8) >> 2) + (x >> 3)) & 3) << 6)) >> fixedLog;
return result;
}
#define TEXTUREOFFSET(base_,x_,y_) (base_ + Fast_XGAddress2DTiledOffset(x,y,GTA_VEHICLE_DAMAGE_TEXTURE_SIZE/*,4*/))
//#define TEXTUREOFFSET(base_,x_,y_) (base_ + XGAddress2DTiledOffset(x,y,GTA_VEHICLE_DAMAGE_TEXTURE_SIZE,4))
#endif // VEHICLEDAMAGE_USE_LINEAR_TEXTURE
// --- Constants ----------------------------------------------------------------
// --- Structure/Class Definitions ----------------------------------------------
struct VehTexCacheEntry
{
CVehicleDeformation *m_pOwner;
s32 m_nPriority;
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
#if VEHICLE_ROLLING_TEXTURE_ARRAY
fwTexturePayload m_DamageTextures[VEHICLE_DEFORMATION_TEXTURE_ARRAY_SIZE];
fwTexturePayload m_DamageRenderTarget;
int m_ActiveCPUIndex;
int m_ActiveGPUIndex;
int m_FrameToDownloadOn[VEHICLE_DEFORMATION_TEXTURE_ARRAY_SIZE];
rage::sysIpcMutex m_DamageMutex;
bool m_HasDamageDrawn;
void IncrementQueuedDownload();
grcTexture *GetDownloadQueuedTexture();
bool IsDamageQueued();
bool DamageQueuedIsReady();
grcTexture *GetDamageDownloadTexture();
void AdvanceActiveTexture();
void ClearDamageDownloads();
#else
fwTexturePayload m_Payloads[2];
#endif
#else
fwTexturePayload m_Payload;
#endif
};
typedef struct VehTexCacheEntry VehTexCacheEntry;
class CVehicleDeformation
{
#if GTA_REPLAY
friend class CReplayMgr;
#endif
public:
// damageMap packing constants:
enum { YPACK = (1<<8) };
enum { ZPACK = (1<<16) };
static const unsigned NUM_NETWORK_DAMAGE_DIRECTIONS = 6;
static const unsigned FRONT_LEFT_DAMAGE = 0;
static const unsigned FRONT_RIGHT_DAMAGE = 1;
static const unsigned MIDDLE_LEFT_DAMAGE = 2;
static const unsigned MIDDLE_RIGHT_DAMAGE = 3;
static const unsigned REAR_LEFT_DAMAGE = 4;
static const unsigned REAR_RIGHT_DAMAGE = 5;
public:
CVehicleDeformation();
~CVehicleDeformation() { /*NoOp*/ };
void Init(CVehicle* pVehicle);
void Shutdown();
// convert from a normalised offset into a texture coordinate (in pixels or UV)
static Vec::Vector_4V_Out GetDamageTexCoordFromOffset(Vec::Vector_4V_In vecLocalNormalisedOffset, bool inPixels = true);
// convert from a texture coordinate into a normalised offset
static Vector3 GetDamageOffsetFromTexCoord(const Vector3& vecTexSampleCoords, bool bCoordsInPixels=true);
#if ADD_PED_SAFE_ZONE_TO_VEHICLES
ScalarV_Out GetPedSafeAreaMultiplier(Vec3V_In vecOffset) const;
void GetPedSafeAreaMinMax(Vector3& safeMin, Vector3& safeMax, Vector3& unSafeMin, Vector3& unSafeMax) const;
#endif
//////////////
// read and write to damage texture
#if !__DEBUG
__forceinline
#endif
static Vec3V_Out ReadFromPixel(const void *basePtr, int x, int y)
{
Assert(basePtr && x >= 0 && x<GTA_VEHICLE_DAMAGE_TEXTURE_SIZE && y>=0 && y<GTA_VEHICLE_DAMAGE_TEXTURE_SIZE);
#if GPU_DAMAGE_WRITE_ENABLED
# if VEHICLE_DEFORMATION_USE_HALF_FLOATS
const TexelValue_A16B16G16R16F* pTexel = TEXTUREOFFSET((const TexelValue_A16B16G16R16F *)basePtr,x,y);
Vector3 val(Float16Compressor::decompress(pTexel->red), Float16Compressor::decompress(pTexel->green), Float16Compressor::decompress(pTexel->blue));
# else
const TexelValue_R8G8B8A8_SNORM* pTexel = TEXTUREOFFSET((const TexelValue_R8G8B8A8_SNORM *)basePtr,x,y);
Vector3 val = Vector3((f32)pTexel->red, (f32)pTexel->green, (f32)pTexel->blue);
val /= 128.0f;
# endif //VEHICLE_DEFORMATION_USE_HALF_FLOATS
Vec3V vecBase = VECTOR3_TO_VEC3V(val);
#else
const float *pFloatEntry = TEXTUREOFFSET((const float *)basePtr,x,y);
// unpack what's there already
const ScalarV packedVecBase = ScalarVFromF32(*pFloatEntry);
Vec3V vecBase = Unpack(packedVecBase);
// scale into -1.0 to 1.0 range
const Vec3V oneTwentyEight = Vec3V(ScalarVConstant<FLOAT_TO_INT(128.0f)>());
vecBase -= oneTwentyEight;
vecBase /= oneTwentyEight;
#endif //GPU_DAMAGE_WRITE_ENABLED
return vecBase;
}
// read from specific pixel
static Vec3V_Out ReadFromTexPosition(const void *base, Vec2V_In xy, bool bInterpolate); // round down or interpolate
Vec3V_Out ReadFromVectorOffset(const void *base, Vec3V_In vecOffset, bool interpolate = true) const;
static void WriteToPixel(void *base, const Vector3& vecDamage, int x, int y); // overwrite pixel
static void AddToPixel(void *base, const Vector3& vecDamage, int x, int y); // accumulate into pixel
static void AddToPixel(void *base, Vec3V_In vecDamage, int x, int y); // accumulate into pixel
static inline float Pack(int x, int y, int z);
static inline ScalarV_Out Pack(Vec3V_In xyz);
static inline void Unpack(Vector3& vecResult);
static __forceinline Vec3V_Out Unpack(ScalarV_In vecResult);
/////////////
// write into areas of the damage texture
static ScalarV_Out GetTexRange(const Vector3& vecOffset, const float fRadius, bool inPixels);
void ApplyDamageToCircularArea(void *base,const Vector3& vecDamage, const Vector3& vecOffset, const float fRadius);
void ResetDamage();
void ApplyDamageToWindows(const Vector3& vecPos, const float fRadius);
// called when an impact occurs
bool ApplyCollisionImpact(const Vector3& vecImpulseWorldSpace, const Vector3& vecPosWorldSpace, CEntity* pOtherEntity, bool bFullScaleDeformation = false, bool bShouldApplyDamageToGlass = true);
inline float GetNetworkDamage(int idx) { return m_networkDamages[idx]; }
inline u32 GetNetworkDamageLevel(int idx)
{
if(m_networkDamages[idx] <= networkDamageModifiers[idx][0])
return 0;
else if(m_networkDamages[idx] <= networkDamageModifiers[idx][1])
return 1;
else if(m_networkDamages[idx] <= networkDamageModifiers[idx][2])
return 2;
else
return 3;
}
void ApplyDeformationsFromNetwork(u32 damageLevel[NUM_NETWORK_DAMAGE_DIRECTIONS]);
#if __BANK
void ApplyDamageWithOffset(const Vector4 &damage, const Vector4 &offset);
static void RenderBank();
#endif
// called from PreRender to copy damage texture across to render target
void ApplyDeformations(bool bBoundsNeedUpdating = false, bool bNetworkDamageOnly = false);
void ApplyDamageToBound(const void* basePtr, const fragInst::ComponentBits* pOnlySubBoundGroups = NULL, const Vector3 *pSubBoundGroupsOffset = NULL) const;
s32 GetImpactStoreCount() const { return m_nImpactStoreIdx; }
void ClearStoredImpacts() { m_nImpactStoreIdx = 0; }
void SetNewImpactToStore(const Vector4& rDamage, const Vector4& rOffset);
const Vector4& GetImpactDamage(u32 impactIdx) const { FastAssert(impactIdx < VEHICLE_DEFORMATION_IMPACT_STORE_SIZE); return m_ImpactStore[impactIdx].damage; }
const Vector4& GetImpactOffset(u32 impactIdx) const { FastAssert(impactIdx < VEHICLE_DEFORMATION_IMPACT_STORE_SIZE); return m_ImpactStore[impactIdx].offset; }
float GetDamageMultiplier(float* sizeMult = NULL) const;
float GetDamageMultiplierInv() const { return m_fDamageMultByVehicleSizeInv; }
void CalculateDamageMultiplier();
void HandleDamageAdded(void *basePtr, bool bEnableDamageShader, bool bUpdateBounds, bool bUpdateWheels, bool bUpdateAudio, bool bUpdateBones, bool bUpdateGlass);
void UpdateShaderDamageVars(bool bEnableDamage) { UpdateShaderDamageVars(bEnableDamage, GetBoundRadiusScaled(), GetDamageMultiplier()); }
void UpdateShaderDamageVars(bool bEnableDamage, float radius, float multiplier);
inline bool HasDamageTexture() const { return(m_nTextureCacheIdx != -1); }
void DamageTextureAllocate(bool bResetDamage = true);
void* LockDamageTexture(u32 LockFlags)
{
if ((m_nTextureCacheIdx < 0) || (m_nTextureCacheIdx >= GetTextureCacheSize()))
{
return NULL;
}
void* ptr = NULL;
VehTexCacheEntry* entry = &(ms_TextureCache[m_nTextureCacheIdx]);
DLCPushTimebar("LockDamageTexture");
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
#if VEHICLE_ROLLING_TEXTURE_ARRAY
rage::sysIpcLockMutex(entry->m_DamageMutex);
ptr = entry->m_DamageTextures[entry->m_ActiveCPUIndex].AcquireBasePtr(LockFlags);
if (!ptr) rage::sysIpcUnlockMutex(entry->m_DamageMutex);
#else
ptr = entry->m_Payloads[0].AcquireBasePtr(LockFlags);
#endif
#else
ptr = entry->m_Payload.AcquireBasePtr(LockFlags);
#endif
DLCPopTimebar();
return ptr;
}
void UnLockDamageTexture()
{
if ((m_nTextureCacheIdx < 0) || (m_nTextureCacheIdx >= GetTextureCacheSize()))
{
return;
}
VehTexCacheEntry *entry = &(ms_TextureCache[m_nTextureCacheIdx]);
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
#if VEHICLE_ROLLING_TEXTURE_ARRAY
entry->m_DamageTextures[entry->m_ActiveCPUIndex].ReleaseBasePtr();
rage::sysIpcUnlockMutex(entry->m_DamageMutex);
#else
entry->m_Payloads[0].ReleaseBasePtr();
#endif
#else
entry->m_Payload.ReleaseBasePtr();
#endif
}
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
grcRenderTarget* GetDamageRenderTarget() const { return static_cast<grcRenderTarget*>(GetDamageTexture(true)); }
grcTexture* GetDamageTexture(bool bGetRenderTarget = false) const
#else
grcRenderTarget* GetDamageRenderTarget() const { return static_cast<grcRenderTarget*>(GetDamageTexture()); }
grcTexture* GetDamageTexture() const
#endif
{
grcTexture *texture = NULL;
if(HasDamageTexture())
{
VehTexCacheEntry *entry = &(ms_TextureCache[m_nTextureCacheIdx]);
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
#if VEHICLE_ROLLING_TEXTURE_ARRAY
if (bGetRenderTarget)
{
texture = entry->m_DamageRenderTarget.GetTexture();
}
else
{
texture = entry->m_DamageTextures[entry->m_ActiveCPUIndex].GetTexture();
}
#else
texture = entry->m_Payloads[bGetRenderTarget].GetTexture();
#endif
#else
texture = entry->m_Payload.GetTexture();
#endif
}
return texture;
}
inline fwTexturePayload *GetDamagePayload() const
{
fwTexturePayload *payload = NULL;
if(HasDamageTexture())
{
#if GPU_DAMAGE_WRITE_ENABLED && __D3D11
#if VEHICLE_ROLLING_TEXTURE_ARRAY
VehTexCacheEntry &entry = (ms_TextureCache[m_nTextureCacheIdx]);
payload = &(entry.m_DamageTextures[entry.m_ActiveCPUIndex]);
#else
payload = &(ms_TextureCache[m_nTextureCacheIdx].m_Payloads[0]);
#endif
#else
payload = &(ms_TextureCache[m_nTextureCacheIdx].m_Payload);
#endif
}
return payload;
}
inline float GetBoundRadiusScaledInv() const
{
return m_fBoundRadiusScaledInv;
}
inline float GetBoundRadiusScaled() const
{
return (1.0f / m_fBoundRadiusScaledInv);
}
inline ScalarV_Out GetBoundRadiusScaledInvV() const
{
return ScalarV(m_fBoundRadiusScaledInv);
}
inline ScalarV_Out GetDamageMultiplierScalar() const
{
float multiplier = GetDamageMultiplier();
return ScalarV(multiplier);
}
#if ADD_PED_SAFE_ZONE_TO_VEHICLES
CPedSafeZone& GetPedSafeZone() { return m_PedSafeZone; }
const CPedSafeZone& GetPedSafeZone() const { return m_PedSafeZone; }
#endif
bool HasValidParentVehicle() { return m_pParentVehicle != NULL; }
private:
float m_fDamageMultByVehicleSize;
float m_fDamageMultByVehicleSizeInv;
float m_fSizeMultiplier;
#if ADD_PED_SAFE_ZONE_TO_VEHICLES
CPedSafeZone m_PedSafeZone;
#endif
void UpdateNetworkDamageLevels();
// --- Structures ------------------------
struct ImpactRecord
{
Vector4 damage; // + fRadius
Vector4 offset; // + fLength
};
typedef struct ImpactRecord ImpactRecord;
const ImpactRecord& GetImpactStoreIndex(u32 impactIdx) const { FastAssert(impactIdx < VEHICLE_DEFORMATION_IMPACT_STORE_SIZE); return m_ImpactStore[impactIdx]; }
#if VEHICLE_ROLLING_TEXTURE_ARRAY
public:
VehTexCacheEntry* GetTexCache() {return &ms_TextureCache[m_nTextureCacheIdx];}
private:
#endif
// --- Data ------------------------------
ImpactRecord m_ImpactStore[VEHICLE_DEFORMATION_IMPACT_STORE_SIZE];
CVehicle *m_pParentVehicle;
s32 m_nTextureCacheIdx;
s32 m_nImpactStoreIdx;
float m_fBoundRadiusScaledInv;
// total of impact magnitudes on the vehicles, used for network sync.
float m_networkDamages[NUM_NETWORK_DAMAGE_DIRECTIONS];
// --- Impact record ---------------------
#if VEHICLE_DEFORMATION_TIMING
s32 m_nImpactFound;
#endif // VEHICLE_DEFORMATION_TIMING
// --- Texture Cache ---------------------
static atArray<VehTexCacheEntry> ms_TextureCache;
static inline u32 GetTextureCacheSize() { return ms_TextureCache.GetCount(); }
void DamageTextureFree();
int GetTexCachePriority();
static void FreeEntry(VehTexCacheEntry &entry);
public:
static const unsigned MAX_NET_DAMAGE_MODIFIERS = 4;
static float networkDamageModifiers[NUM_NETWORK_DAMAGE_DIRECTIONS][MAX_NET_DAMAGE_MODIFIERS];
static grcTexture* CreateDamageTexture(int width, int height);
static grcRenderTarget* CreateDamageRenderTarget(grcTexture* texture, int width, int height, int index, bool lockable);
static void TexCacheInit(unsigned initMode);
static void TexCacheBuild(bool forMp);
static void TexCacheUpdate();
static void TexCacheShutdown(unsigned shutdownMode);
#if __BANK
static void DisplayTexCacheStats();
static void ClearTexCache();
static bool ms_bDisplayTexCacheStats;
static bool ms_bShowTextureAndRenderTarget;
static float ms_fDisplayTextureScale;
static bool ms_bDisplayDamageMap;
static bool ms_bDisplayDamageMult;
static bool ms_bForceDamageMapScale;
static bool ms_bFullDamage;
static float ms_fForcedDamageMapScale;
static float ms_fWeaponImpactDamageScale;
static bank_float m_ImpactPositionLocal_X;
static bank_float m_ImpactPositionLocal_Y;
static bank_float m_ImpactPositionLocal_Z;
static bank_float m_Impulse_X;
static bank_float m_Impulse_Y;
static bank_float m_Impulse_Z;
static bank_float m_OffsetDamageToMods_X;
static bank_float m_OffsetDamageToMods_Y;
static bank_float m_OffsetDamageToMods_Z;
static bank_float m_DamageTextureOffset_X;
static bank_float m_DamageTextureOffset_Y;
static bank_float m_DamageTextureOffset_Z;
static bank_float ms_fDamageAmount;
static bank_float ms_fDamagePercent;
static bank_float ms_fContainerDropHeight;
static ScalarV ms_fVehDefColVarMultMin;
static ScalarV ms_fVehDefColVarMultMax;
static ScalarV ms_fVehDefColVarAddMin;
static ScalarV ms_fVehDefColVarAddMax;
static bool ms_bAutoFix;
static bool ms_bAutoSaveDamageTexture;
static bool ms_bUpdateBoundsEnabled;
static bool ms_bUpdateBonesEnabled;
static bool ms_bHidePropellers;
static float ms_fForcedPropellerSpeed;
static void SaveDamageTexture(CVehicle* vehicle, bool skipSaveIfSameAsLast);
static void LoadDamageTexture(CVehicle* vehicle);
#endif // __BANK
static float ms_SmoothedPerlinNoise[VEHICLE_DEFORMATION_NOISE_HEIGHT][VEHICLE_DEFORMATION_NOISE_WIDTH_EXPANDED] ;
static bank_float ms_fVehDefRoofColMultZNeg;
static bank_float ms_fDeformationCarRoofMinZ;
static bank_float ms_fDeformationSuperCarRoofMinZ;
static bank_float ms_fDeformationPlaneHeadMaxZ;
static bank_float ms_fRollcageMinZ;
static bank_bool ms_bEnableRoofZDeformationClamping;
static bank_float ms_fVehDefColMultX;
static bank_float ms_fVehDefColMultY;
static bank_float ms_fVehDefColMultYNeg;
static bank_float ms_fVehDefColMultZ;
static bank_float ms_fVehDefColMultZNeg;
static bank_float ms_fCarModBoneDeformMult;
static int ms_iExtraExplosionDeformations;
static bank_float ms_fExtraExplosionsDamage;
static bool ms_bUpdateDamageFromPhysicsThread;
static bank_float m_sfVehDefColMax1;
static bank_float m_sfVehDefColMax2;
static bank_float m_sfVehDefColMult2;
static bank_float ms_fLargeVehicleRadiusMultiplier;
static bank_bool ms_bEnableExtraBoneDeformations;
#if VEHICLE_DEFORMATION_PROPORTIONAL
static bank_float ms_fDamageMagnitudeMult;
#endif
static void InitSmoothedPerlinNoise();
__forceinline static float GetSmoothedPerlinNoiseFloat(int x, int y)
{
return ms_SmoothedPerlinNoise[y % VEHICLE_DEFORMATION_NOISE_HEIGHT][x % VEHICLE_DEFORMATION_NOISE_WIDTH];
}
__forceinline static Vec4V_Out GetSmoothedPerlinNoise(int x, int y)
{
// http://devmag.org.za/2009/04/25/perlin-noise/
// Wavelength 32 looks appropriate for metal warping damage fluctuations
const int width = VEHICLE_DEFORMATION_NOISE_WIDTH;
const int height = VEHICLE_DEFORMATION_NOISE_HEIGHT;
CompileTimeAssert(VEHICLE_DEFORMATION_NOISE_WIDTH && !(VEHICLE_DEFORMATION_NOISE_WIDTH & (VEHICLE_DEFORMATION_NOISE_WIDTH - 1)));
x = x&(width - 1);
y = rage::Abs(y) % height;
Vec4V result = Vec4V(Vec::V4LoadUnaligned(&(ms_SmoothedPerlinNoise[y][x])));
return result;
}
};
inline float CVehicleDeformation::Pack(int x, int y, int z)
{
return (float(x) + float(y * YPACK) + float(z * ZPACK));
}
inline ScalarV_Out CVehicleDeformation::Pack(Vec3V_In xyz)
{
const Vec3V packTerms = Vec3V(1.0f, float(YPACK), float(ZPACK));
return Dot(xyz, packTerms);
}
inline void CVehicleDeformation::Unpack(Vector3& vecResult)
{
// unpack z component
rage::Modf(vecResult.x / float(ZPACK), &vecResult.z);
vecResult.x -= vecResult.z*float(ZPACK);
// unpack y component
rage::Modf(vecResult.x / float(YPACK), &vecResult.y);
vecResult.x -= vecResult.y*float(YPACK);
}
__forceinline Vec3V_Out CVehicleDeformation::Unpack(ScalarV_In packedValue)
{
Vec3V unpackedVecResults = Vec3V(packedValue);
const Vec3V packXYZParams = Vec3V(1.0f, float(YPACK), float(ZPACK));
const Vec3V unpackXYZParams = Vec3V(1.0f, 1.0f/float(YPACK), 1.0f/float(ZPACK));
//unpack z component first
unpackedVecResults.SetZ(RoundToNearestIntZero(unpackedVecResults.GetX() * unpackXYZParams.GetZ()));
unpackedVecResults.SetX(unpackedVecResults.GetX() - unpackedVecResults.GetZ() * packXYZParams.GetZ());
//unpack y component
unpackedVecResults.SetY(RoundToNearestIntZero(unpackedVecResults.GetX() * unpackXYZParams.GetY()));
unpackedVecResults.SetX(unpackedVecResults.GetX() - unpackedVecResults.GetY() * packXYZParams.GetY());
return unpackedVecResults;
}
// this enum exists in commands_vehicle.sch as well, so please keep in synch
enum eVehStuckTypes
{
VEH_STUCK_ON_ROOF = 0,
VEH_STUCK_ON_SIDE,
VEH_STUCK_HUNG_UP,
VEH_STUCK_JAMMED,
VEH_STUCK_RESET_ALL
};
enum eVehBrokenBouncingState
{
VEH_BB_NONE = 0,
VEH_BB_BOUNCING = 1,
VEH_BB_BROKEN = 2
};
#define MAX_BOUNCING_PANELS (3)
#define VEH_DAMAGE_HEALTH_STD (1000.0f)
#define VEH_DAMAGE_PETROL_LEVEL_STD (65.0f)
#define VEH_DAMAGE_OIL_LEVEL_STD (5.0f)
#define VEH_DAMAGE_HEALTH_PTANK_LEAKING (700.0f)
#define VEH_DAMAGE_HEALTH_PTANK_ONFIRE (0.0f)
#define VEH_DAMAGE_HEALTH_PTANK_FINISHED (-1000.0f)
#define VEH_DAMAGE_PTANK_LEVEL_BEFOREMISFIRE (0.1f)
#define VEH_DAMAGE_PTANK_LEAK_RATE (2.5f)
// force vehicle damage to behave in the same way as before
// (cars go on fire and explode when health goes to zero)
// #define VEHICLE_DAMAGE_FORCE_EXPLOSIONS (1)
class CVehicleDamage
{
public:
struct Tunables : public CTuning
{
Tunables();
float m_AngleVectorsPointSameDir;
float m_MinFaultVelocityThreshold;
// C&C Endurance Damage
float m_MinImpulseForEnduranceDamage;
float m_MaxImpulseForEnduranceDamage;
float m_MinEnduranceDamage;
float m_MaxEnduranceDamage;
float m_InstigatorDamageMultiplier;
// C&C Wanted Status
float m_MinImpulseForWantedStatus;
PAR_PARSABLE;
};
static Tunables sm_Tunables;
CVehicleDamage();
~CVehicleDamage();
void Init(CVehicle* pParentVehicle);
void SetParent(CVehicle* pParent) { m_pParent = pParent; }
CVehicle* GetParent() {return m_pParent;}
CVehicleDeformation* GetDeformation() {return &m_Deformation;}
const CVehicleDeformation* GetDeformation() const {return &m_Deformation;}
void Process(float fTimeStep, bool bBoundsNeedUpdating = false);
void PreRender();
void PreRender2();
float ApplyDamage(CEntity* pInflictor, eDamageType nDamageType, u32 nWeaponHash, float fDamage, const Vector3& vecPos, const Vector3& vecNorm, const Vector3& vecDirn, int nComponent, phMaterialMgr::Id nMaterialId=0, int nPieceIndex=-1, const bool bFireDriveby=false, const bool bIsAccurate = true, const float fDamageRadius = 0.0f, const bool bAvoidExplosions = false, const bool bChainExplosion = false, const bool bMeleeDamage = false, const bool isFlameThrowerFire = false, const bool forceMinDamage = false );
bool HasBoneCollidedWithComponent(eHierarchyId boneId, int iComponent);
bool CanVehicleBeDamaged(CEntity* pInflictor, u32 nWeaponHash, bool bDoNetworkCloneCheck = true);
bool CanVehicleBeDamagedBasedOnDriverInvincibility();
void FixVehicleDamage(bool resetFrag, bool allowNetwork = false);
void FixVehicleDeformation();
float GetOverallHealth() const;// {return m_pParent->GetHealth();}
float GetBodyHealth() const { return m_fBodyHealth; }
void RefillOilAndPetrolTanks();
float GetVehicleHealthPercentage(const CVehicle* pVehicle, float maxEngineHealth = 1000.0f, float maxPetrolTankHealth = 1000.0f, float maxHealth = 1000.0f, float maxMainRotorHealth = 1000.0f, float maxRearRotorHealth = 1000.0f, float maxTailBoomHealth = 1000.0f ) const;
float GetPetrolTankHealth() const {return m_fPetrolTankHealth;}
bool GetPetrolTankOnFire() const {return (m_fPetrolTankHealth > VEH_DAMAGE_HEALTH_PTANK_FINISHED && m_fPetrolTankHealth < VEH_DAMAGE_HEALTH_PTANK_ONFIRE);}
void ResetPetrolTankHealth() {m_fPetrolTankHealth = VEH_DAMAGE_HEALTH_STD;}
void ResetPetrolTankHealthIfItsOverTheMaximum() {if (m_fPetrolTankHealth > VEH_DAMAGE_HEALTH_STD) m_fPetrolTankHealth = VEH_DAMAGE_HEALTH_STD;}
void ProcessPetrolTankDamage(float fTimeStep);
void ProcessFuelConsumption(float fTimeStep);
void SetPetrolTankHealth(float fHealth) {Assert(fHealth >= VEH_DAMAGE_HEALTH_PTANK_FINISHED); m_fPetrolTankHealth = fHealth;}
float GetPetrolTankLevel() const {return m_fPetrolTankLevel;}
void SetPetrolTankLevel(float fPetrolLevel);
bool IsPetrolTankBurning() const;
float CalculatePetrolTankFireBurnRate() const;
float CalculateTimeUntilPetrolTankExplosion() const;
float GetEngineHealth() const;// {return m_pParent->m_Transmission->GetEngineHealth();}
bool GetEngineOnFire() const;
void ResetEngineHealth();
void SetEngineHealth(float fHealth);
void SetBodyHealth(float fHealth);
void ProcessOilLeak(float fTimeStep);
float GetOilLevel() const {return m_fOilLevel;}
float GetSuspensionHealth(int i) const;
float GetTyreHealth(int i) const;
int GetAnyWheelsBurst() const;
//Finds the closest petrol tank or cap bone in world coords from the local hit position
void FindClosestPetrolTankPos(const Vector3& vecPosLocal, Vector3* vecPetrolTankTestPos);
bool GetPetrolTankPosWld(Vector3* pPetrolTankWldPosL, Vector3* pPetrolTankWldPosR=NULL, Vector3* pPetrolTankWldPosCap=NULL);
bool GetPetrolTankPosLcl(Vector3* pPetrolTankWldPosL, Vector3* pPetrolTankWldPosR=NULL, Vector3* pPetrolTankWldPosCap=NULL);
const Vector3& GetPetrolSprayPosLocal() { return m_vPetrolSprayPosLocal; }
const Vector3& GetPetrolSprayNrmLocal() { return m_vPetrolSprayNrmLocal; }
inline static float GetBodyHealthMax() {return VEH_DAMAGE_HEALTH_STD;}
float GetDefaultBodyHealthMax(const CVehicle *pParentVehicle) const;// Get the max body health that is stored in the vehicle model info, if availiable.
CBouncingPanel* GetBouncingPanel(u32 index) { return index < MAX_BOUNCING_PANELS ? &m_BouncingPanels[index] : NULL; }
const CBouncingPanel* GetBouncingPanel(u32 index) const { return index < MAX_BOUNCING_PANELS ? &m_BouncingPanels[index] : NULL; }
// Warning : this take a BONE ID !!! (as in CAR_HEADLIGHT_L)
inline bool GetLightState(const s32 boneId) const
{
Assert((boneId - VEH_HEADLIGHT_L) >= 0);
Assert((boneId - VEH_HEADLIGHT_L) < VEHICLE_LIGHT_COUNT);
return m_LightState.IsSet(boneId - VEH_HEADLIGHT_L);
}
// Warning : this take a BONE ID !!! (as in CAR_HEADLIGHT_L)
inline void SetLightState(const s32 boneId, const bool value)
{
Assert((boneId - VEH_HEADLIGHT_L) >= 0);
Assert((boneId - VEH_HEADLIGHT_L) < VEHICLE_LIGHT_COUNT);
m_LightState.Set(boneId - VEH_HEADLIGHT_L,value);
}
// Warning : this take a 0 to n index
inline bool GetLightStateImmediate(const s32 idx) const
{
Assert(idx>=0);
Assert(idx<VEHICLE_LIGHT_COUNT);
return m_LightState.IsSet(idx);
}
inline void SetLightStateImmediate(const s32 idx, const bool value)
{
Assert(idx>=0);
Assert(idx<VEHICLE_LIGHT_COUNT);
m_LightState.Set(idx,value);
}
inline bool GetUpdateLightBones(void) const { return m_UpdateLightBones;}
inline void SetUpdateLightBones(const bool value) {m_UpdateLightBones = value;}
// Warning : this take a BONE ID !!! (as in CAR_HEADLIGHT_L)
inline bool GetSirenState(const s32 boneId) const
{
Assert((boneId - VEH_SIREN_1) >= 0);
Assert((boneId - VEH_SIREN_1) < VEHICLE_SIREN_COUNT);
return m_SirenState.IsSet(boneId - VEH_SIREN_1);
}
// Warning : this take a BONE ID !!! (as in CAR_HEADLIGHT_L)
inline void SetSirenState(const s32 boneId, const bool value)
{
Assert((boneId - VEH_SIREN_1) >= 0);
Assert((boneId - VEH_SIREN_1) < VEHICLE_SIREN_COUNT);
m_SirenState.Set(boneId - VEH_SIREN_1,value);
}
// Warning : this take a 0 to n index
inline bool GetSirenStateImmediate(const s32 idx) const
{
Assert(idx>=0);
Assert(idx<VEHICLE_SIREN_COUNT);
return m_SirenState.IsSet(idx);
}
inline void SetSirenStateImmediate(const s32 idx, const bool value)
{
Assert(idx>=0);
Assert(idx<VEHICLE_SIREN_COUNT);
m_SirenState.Set(idx,value);
}
inline bool GetUpdateSirenBones(void) const { return m_UpdateSirenBones;}
inline void SetUpdateSirenBones(const bool value) {m_UpdateSirenBones = value;}
inline int GetSirenHealth(void) const
{
s32 c0unt0 = 0;
for(int i=0;i<VEHICLE_SIREN_COUNT;i++)
{
c0unt0 += (GetSirenStateImmediate(i) == true) ? 1 : 0;
}
return c0unt0;
}
void SetPetrolTankOnFire(CEntity* pEntityResponsible);
const CEntity* GetEntityThatSetUsOnFire() { return m_pEntityThatSetUsOnFire; }
void ClearPetrolTankFireCulprit() { m_pEntityThatSetUsOnFire = NULL; }
void ProcessStuckCheck(float fTimeStep);
void ResetStuckCheck();
bool GetIsStuck(int nStuckType, u16 nRequiredTime) const;
float GetStuckTimer(int nStuckType) const;
void ResetStuckTimer(int nStuckType);
bool GetIsDriveable(bool bCheckForPlayerPed = false, bool bIgnoreHealthCheck = false, bool bIgnorePetrolCheck = false) const;
void ResetBrokenPartCountdown();
int GetNumOfBrokenOffParts() const;
int GetNumOfBrokenLoosenParts() const;
// Car only
void BreakOffWheel(int wheelIndex, float ptfxProbability = 1.0f, float deleteProbability = 0.0f, float burstTyreProbability = 0.0f, bool dueToExplosion=false, bool bNetworkCheck = true);
void BlowUpCarParts(CEntity *pInflictor, int eBreakingState = Break_Off_Car_Parts_Immediately);
void BreakOffPart(eHierarchyId hierarchyId, int fragChild, fragInst *pFragInst, const CVehicleExplosionInfo* vehicleExplosionInfo, bool bDeleteParts, float fDeleteProb, float fxProb, bool bApplyAdditionalVelocityToPart = true );
void ApplyAdditionalVelocityToVehiclePart(phInst& oldInst, phInst& newInst, const CVehicleExplosionInfo& vehicleExplosionInfo);
// Used for bikes, and car and anything else...
void BlowUpVehicleParts(CEntity* pInflictor);
void PopOutWindScreen();
void PopOffRoof(const Vector3 &vRoofImpulse);
void ApplyDamageToEngine(CEntity* pInflictor, eDamageType nDamageType, float fDamage, const Vector3& vecPosLocal, const Vector3& vecNormLocal, const Vector3& vecDirnLocal, const bool bFireDriveby, const bool bIsAccurate, const float fDamageRadius, const bool bAvoidExplosions = false, u32 nWeaponHash = 0, const bool bChainExplosion = false);
void UpdateLightsOnBreakOff(int nComponentID);
void BreakOffMiscComponents(float fDeleteMiscChance, float fBreakMiscChance, const Vector3& vecPosLocal);
u8 GetPartDamage(eHierarchyId ePart);
void SetPartDamage(eHierarchyId ePart, u8 state);
static void Copy(CVehicle *dstVehicle, CVehicle* srcVehicle);
Vector3 RecomputeImpulseFromTrain(CTrain *pTrain, const Vector3& vImpulse) const;
#if __DEV
// smash test needs to know about these ..
static const eHierarchyId* GetGlassBoneHierarchyIds();
static int GetGlassBoneHierarchyIdCount();
#endif // __DEV
#if __BANK
static void SetupVehicleDoorDamageBank(bkBank& bank);
static bool ms_bDisplayDamageVectors;
#endif
static float ms_fArmorModMagnitude;
#if GPU_DAMAGE_WRITE_ENABLED
static bool ms_bEnableGPUDamage;
enum eBlowUpCarPartsStates
{
Break_Off_Car_Parts_Immediately,
Break_Off_Car_Parts_Pending_Bound_Update,
Num_Blow_Up_Car_Parts_States
};
u8 m_uBlowUpCarPartsPending;
bool IsBlowUpCarPartsPending() const {return m_uBlowUpCarPartsPending == Break_Off_Car_Parts_Pending_Bound_Update;}
#endif
#if __BANK
#if GPU_DAMAGE_WRITE_ENABLED
static int ms_iForcedDamageEveryFrame;
#endif
static CVehicle *ms_SourceVehicle;
static CVehicle *ms_DestinationVehicle;
static u32 g_DamageDebug[CVehicleDeformation::NUM_NETWORK_DAMAGE_DIRECTIONS];
static float g_DamageValue[CVehicleDeformation::NUM_NETWORK_DAMAGE_DIRECTIONS];
static void SetSourceVehicleCB();
static void SetDestinationVehicleCB();
static void DisplayDamageImpulse(const Vector3& impulseDirection, const Vector3& impulsePosition, CVehicle* vehicle, float damageRadius, bool inLocalCoordinates, int framesToLive);
static void DamageCurrentCar();
static void DamageCurrentCar(const Vector3& impulseLocal, const Vector3& damagePosLocal, float damage, bool autoFix);
static void DamageCurrentCarByPercentage();
static void DamageDriverSideRoof();
static void HeadOnCollision();
static void RearEndCollision();
static void LeftSideCollision();
static void RightSideCollision();
static void TailRotorCollision();
static void ImplodeSubmarine();
static void RandomSmash();
static void NetworkSmashDebug();
static void NetworkSmashDebugRandom();
static void UpdateNetworkDamageDebug();
static void RemoveWheel();
static void RemoveHelicopterTail();
static void RemoveHelicopterPropellers();
static void DropFiveTonContainer();
static void DuplicateDamageCB();
static void SaveDamageTexture();
static void LoadDamageTexture();
static void FixDamageForTests();
static void BreakOffWheelsCB();
#if VEHICLE_DEFORMATION_PROPORTIONAL
static void UpdateDamageMultiplier();
#endif
#endif // __BANK
static void HeadOnCollision(CVehicle* pVehicle, float damage, bool randomize);
static void RearEndCollision(CVehicle* pVehicle, float damage, bool randomize);
// PURPOSE:
// If this returns true we should try to avoid the results of a vehicle blowing up (explosions, fires, damage, ...) start another
// explosion. Since there are so many things that can blow up a vehicle it's not expected that this function is always respected.
static bool AvoidVehicleExplosionChainReactions();
static float GetVehicleExplosionBreakChanceMultiplier();
static void InitTunables();
#if __BANK
static bool ms_bNeverAvoidVehicleExplosionChainReactions;
static bool ms_bAlwaysAvoidVehicleExplosionChainReactions;
static bool ms_bUseVehicleExplosionBreakChanceMultiplierOverride;
static float ms_fVehicleExplosionBreakChanceMultiplierOverride;
#endif // BANK
static bool ms_bDisableVehiclePartCollisionOnBreak;
static bool ms_bDisableVehicleExplosionBreakOffParts;
static float ms_fLooseLatchedDoorOpenAngle;
static float ms_fLooseLatchedBonnetOpenAngle;
static bank_float sfVehDamPetrolTankApplyGunDamageMult;
static bank_float sfVehDamPetrolTankApplyGunDamageMultAI;
static bank_float ms_fChanceToBreak;
// B*2031517: Value from 0 to 1 that controls how many restrictions are placed on parts breaking of vehicles due to damage.
// Zero indicates no additional restrictions. One indicates that no parts will break off and VFX will not occur.
// Values in between places restrictions on various areas of the vehicles breaking starting with the most superfluous with doors and wheels being the last to be restricted.
// Restrictions involve increasingly limiting the number of parts breaking off per-vehicle before totally disabling breaking.
static float ms_fBreakingPartsReduction;
private:
void ApplyDamageToWheels(CEntity* pInflictor, eDamageType nDamageType, float fDamage, const Vector3& vecPosLocal, const Vector3& vecNormLocal, const Vector3& vecDirnLocal, int nComponent, phMaterialMgr::Id nMaterialId, int nPieceIndex);
void ApplyDamageToGlass(float fDamage, const Vector3& vecPosLocal, const Vector3& vecNormLocal, const Vector3& vecDirnLocal);
void ApplyDamageToOverallHealth(CEntity* pInflictor, eDamageType nDamageType, u32 nWeaponHash, float fDamage, const Vector3& vecPosLocal, const Vector3& vecDirnLocal, int nComponent, const bool bChainExplosion);
void ApplyDamageToBody(CEntity* pInflictor, eDamageType nDamageType, u32 nWeaponHash, float fDamage, const Vector3& vecPosLocal, const Vector3& vecNormLocal, int nComponent, bool isFlameThrowerFire );
void ApplyPadShake(const CEntity* pInflictor, float fDamage);
void ApplyPadShakeInternal();
void SpewEntityThatSetUsOnFire(const char* DEV_ONLY(text));
public:
//This updates all vehicle damage trackers, usually it would be private and called withim ApplyDamage() but because of BlowUpCar() I
// made this public to fix double network events in some cases.
void UpdateDamageTrackers(CEntity* pInflictor, u32 nWeaponHash, const eDamageType nDamageType, const float totalDamage, const bool isAlreadyWrecked, const bool isMeleeDamage = false, phMaterialMgr::Id nMaterialId = 0);
static void DamageVehicleByDriver(const Vector3& impulseLocal, const Vector3& damagePosLocal, float damageAmount, eDamageType nDamageType, CVehicle* vehicle, bool fullDamage);
static void DamageVehicle(CEntity* pInflictor, const Vector3& impulseLocal, const Vector3& damagePosLocal, float damageAmount, eDamageType nDamageType, CVehicle* vehicle, bool fullDamage);
static void AddVehicleExplosionDeformations(CVehicle* vehicle, CEntity* pCulprit, eDamageType nDamageType, int numberOfImpulses, float explosionDamageAmount);
static void DisableVehicleExplosionBreakOffParts() {ms_bDisableVehicleExplosionBreakOffParts = true;}
static void ResetVehicleExplosionBreakOffPartsFlag() {ms_bDisableVehicleExplosionBreakOffParts = false;}
float &GetDynamicSpoilerDamage() { return m_fDynamicSpoilerDamage; }
void SetScriptDamageScale( float damageScale ) { m_fScriptDamageScale = damageScale; }
float GetScriptDamageScale() const { return m_fScriptDamageScale; }
void SetScriptWeaponDamageScale( float damageScale ) { m_fScriptWeaponDamageScale = damageScale; }
float GetScriptWeaponDamageScale() const { return m_fScriptWeaponDamageScale; }
void SetDisableDamageWithPickedUpEntity( bool disableDamage ) { m_bDisableDamageWithPickedUpEntity = disableDamage; }
void SetDamageScales( float bodyDamageScale, float petrolTankDamageScale, float engineDamageScale );
void SetHeliDamageScales( float mainRotorDamageScale, float rearRotorDamageScale, float tailBoomDamageScale );
float GetBodyDamageScale() const { return m_fBodyDamageScale; }
void SetBodyDamageScale( float damageScale ) { m_fBodyDamageScale = damageScale; }
float GetPetrolTankDamageScale() const { return m_fPetrolTankDamageScale; }
void SetPetrolTankDamageScale( float damageScale ) { m_fPetrolTankDamageScale = damageScale; }
float GetCollisionWithMapDamageScale() const { return m_fCollisionWithMapDamageScale; }
void SetCollisionWithMapDamageScale( float damageScale ) { m_fCollisionWithMapDamageScale = damageScale; }
private:
//Updates network stuff related to damage tracking like triggering the network events. Its called by UpdateDamageTrackers().
void UpdateNetworkDamageTracker(CEntity* pInflictor, const float fDamage, const u32 uWeaponHash, const bool vehicleIsDestroyed, const bool isMeleeDamage = false, phMaterialMgr::Id nMaterialId = 0) const;
void ResetFragCacheEntry();
void ApplyDamageToBreakablePanels( eDamageType nDamageType, float fDamage, const Vector3& vecPosLocal, int nComponent );
private:
CVehicleDeformation m_Deformation;
// array of bouncing panels - stores
CBouncingPanel m_BouncingPanels[MAX_BOUNCING_PANELS];
Vector3 m_vPetrolSprayPosLocal;
Vector3 m_vPetrolSprayNrmLocal;
static float ms_fPetrolTankFireBurnRateMin;
static float ms_fPetrolTankFireBurnRateMax;
Vector3 m_vecOldMoveSpeed;
Vector3 m_vecOldTurnSpeed;
Vector3 m_vecLastStuckPos;
Vector3 m_vecLastStuckJammedPos;
u16 m_nStuckCounterOnRoof;
u16 m_nStuckCounterOnSide;
u16 m_nStuckCounterHungUp;
u16 m_nStuckCounterJammed;
CVehicle* m_pParent;
float m_fBodyHealth;
float m_fPetrolTankHealth;
float m_fBodyDamageScale;
float m_fPetrolTankDamageScale;
float m_fCollisionWithMapDamageScale;
float m_fPetrolTankLevel;
float m_fOilLevel;
RegdEnt m_pEntityThatSetUsOnFire;
f32 m_fCountDownToTimeAnotherPartCanBreakOff;
static u32 sm_TimeOfLastShotAtHeliMegaphone;
atFixedBitSet<VEHICLE_LIGHT_COUNT> m_LightState;
atFixedBitSet<VEHICLE_SIREN_COUNT> m_SirenState;
bool m_UpdateLightBones;
bool m_UpdateSirenBones;
bool m_bHasHandBrake;
bool m_bDisableDamageWithPickedUpEntity;
float m_fPadShakeIntensity;
u8 m_uPadShakeDuration;
float m_fDynamicSpoilerDamage;
float m_fScriptDamageScale;
float m_fScriptWeaponDamageScale;
// Cloud tunables
static bool sbPlaneDamageCapLargePlanesOnly;
static float sfPlaneExplosionDamageCapInMP;
static float sfSpecialAmmoFMJDamageMultiplierAgainstVehicles;
static float sfSpecialAmmoFMJDamageMultiplierAgainstVehicleGasTank;
};
#endif // !INC_VEHICLEDAMAGE_H_