From c0b47ea386cba67dd8537665675c7ddf84b4ff7c Mon Sep 17 00:00:00 2001 From: FileEX Date: Fri, 3 Jan 2025 02:28:00 +0100 Subject: [PATCH] Add spawnFlyingComponent & breakGlass arguments for setVehiclePanelState (PR #3920, Fixes #2122) Previous attempt in 5b69d700c848e36b2f427bbc6ba5b2c905592783 --- Client/game_sa/CAEVehicleAudioEntitySA.h | 5 + Client/game_sa/CAutomobileSA.cpp | 70 ++++++++++++++ Client/game_sa/CAutomobileSA.h | 12 +++ Client/game_sa/CDamageManagerSA.cpp | 78 ++++++++-------- Client/game_sa/CDamageManagerSA.h | 16 +++- Client/game_sa/CModelInfoSA.cpp | 5 + Client/game_sa/CModelInfoSA.h | 91 +++++++++++-------- Client/game_sa/CVehicleSA.cpp | 2 +- Client/game_sa/CVehicleSA.h | 5 + .../mods/deathmatch/logic/CClientVehicle.cpp | 4 +- Client/mods/deathmatch/logic/CClientVehicle.h | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 6 +- .../logic/CStaticFunctionDefinitions.h | 2 +- .../logic/luadefs/CLuaVehicleDefs.cpp | 5 +- .../deathmatch/logic/rpc/CVehicleRPCs.cpp | 10 +- Client/sdk/game/CDamageManager.h | 14 +-- .../logic/CStaticFunctionDefinitions.cpp | 6 +- .../logic/CStaticFunctionDefinitions.h | 2 +- .../logic/luadefs/CLuaVehicleDefs.cpp | 6 +- Shared/sdk/SharedUtil.Math.h | 9 ++ Shared/sdk/net/bitstream.h | 6 +- 21 files changed, 255 insertions(+), 101 deletions(-) diff --git a/Client/game_sa/CAEVehicleAudioEntitySA.h b/Client/game_sa/CAEVehicleAudioEntitySA.h index cb4ff8699d..45f169299c 100644 --- a/Client/game_sa/CAEVehicleAudioEntitySA.h +++ b/Client/game_sa/CAEVehicleAudioEntitySA.h @@ -73,6 +73,11 @@ static_assert(sizeof(CAETwinLoopSoundEntity) == 0xA8, "Invalid size for CAETwinL class CAEVehicleAudioEntitySAInterface : public CAEAudioEntity { public: + void AddAudioEvent(int eventId, float volume) + { + ((void(__thiscall*)(CAEVehicleAudioEntitySAInterface*, int, float))0x4F6420)(this, eventId, volume); + } + short unk1; // +124 char unk2[2]; // +126 tVehicleAudioSettings m_nSettings; // +128 diff --git a/Client/game_sa/CAutomobileSA.cpp b/Client/game_sa/CAutomobileSA.cpp index 59205e86e1..0dc82e6b1b 100644 --- a/Client/game_sa/CAutomobileSA.cpp +++ b/Client/game_sa/CAutomobileSA.cpp @@ -11,9 +11,79 @@ #include "StdInc.h" #include "CAutomobileSA.h" +#include "CGameSA.h" + +extern CGameSA* pGame; CAutomobileSA::CAutomobileSA(CAutomobileSAInterface* pInterface) { SetInterface(pInterface); Init(); } + +void CAutomobileSAInterface::SetPanelDamage(std::uint8_t panelId, bool breakGlass, bool spawnFlyingComponent) +{ + int nodeId = CDamageManagerSA::GetCarNodeIndexFromPanel(panelId); + if (nodeId < 0) + return; + + eCarNodes node = static_cast(nodeId); + + RwFrame* frame = m_aCarNodes[nodeId]; + if (!frame) + return; + + CVehicleModelInfoSAInterface* vehicleInfo = nullptr; + if (auto* mi = pGame->GetModelInfo(m_nModelIndex)) + vehicleInfo = static_cast(mi->GetInterface()); + + if (!vehicleInfo || !vehicleInfo->IsComponentDamageable(nodeId)) + return; + + switch (m_damageManager.GetPanelStatus(panelId)) + { + case DT_PANEL_DAMAGED: + { + if ((pHandlingData->uiModelFlags & 0x10000000) != 0) // check bouncePanels flag + return; + + if (node != eCarNodes::WINDSCREEN && node != eCarNodes::WING_LF && node != eCarNodes::WING_RF) + { + // Get free bouncing panel + for (auto& panel : m_panels) + { + if (panel.m_nFrameId == (std::uint16_t)0xFFFF) + { + panel.SetPanel(nodeId, 1, GetRandomNumberInRange(-0.2f, -0.5f)); + break; + } + } + } + + SetComponentVisibility(frame, 2); // ATOMIC_IS_DAM_STATE + break; + } + case DT_PANEL_OPENED: + { + if (panelId == WINDSCREEN_PANEL) + m_VehicleAudioEntity.AddAudioEvent(91, 0.0f); + + SetComponentVisibility(frame, 2); // ATOMIC_IS_DAM_STATE + break; + } + case DT_PANEL_OPENED_DAMAGED: + { + if (panelId == WINDSCREEN_PANEL) + { + if (breakGlass) + ((void(__cdecl*)(CAutomobileSAInterface*, bool))0x71C2B0)(this, false); // Call CGlass::CarWindscreenShatters + } + + if (spawnFlyingComponent && (panelId != WINDSCREEN_PANEL || (panelId == WINDSCREEN_PANEL && !breakGlass))) + SpawnFlyingComponent(node, eCarComponentCollisionTypes::COL_NODE_PANEL); + + SetComponentVisibility(frame, 0); // ATOMIC_IS_NOT_PRESENT + break; + } + } +} diff --git a/Client/game_sa/CAutomobileSA.h b/Client/game_sa/CAutomobileSA.h index 921c6638b3..b2fc09417c 100644 --- a/Client/game_sa/CAutomobileSA.h +++ b/Client/game_sa/CAutomobileSA.h @@ -24,6 +24,11 @@ class CBouncingPanelSAInterface { public: + void SetPanel(std::int16_t frameId, std::int16_t axis, float angleLimit) + { + ((void(__thiscall*)(CBouncingPanelSAInterface*, std::int16_t, std::int16_t, float))0x6F4920)(this, frameId, axis, angleLimit); + } + unsigned short m_nFrameId; unsigned short m_nAxis; float m_fAngleLimit; @@ -35,6 +40,13 @@ static_assert(sizeof(CBouncingPanelSAInterface) == 0x20, "Invalid size for CBoun class CAutomobileSAInterface : public CVehicleSAInterface { public: + void SetPanelDamage(std::uint8_t panelId, bool breakGlass, bool spawnFlyingComponent = true); + + CObjectSAInterface* SpawnFlyingComponent(const eCarNodes& nodeId, const eCarComponentCollisionTypes& collType) + { + return ((CObjectSAInterface*(__thiscall*)(CAutomobileSAInterface*, eCarNodes, eCarComponentCollisionTypes))0x6a8580)(this, nodeId, collType); + } + CDamageManagerSAInterface m_damageManager; CDoorSAInterface m_doors[MAX_DOORS]; RwFrame* m_aCarNodes[static_cast(eCarNodes::NUM_NODES)]; diff --git a/Client/game_sa/CDamageManagerSA.cpp b/Client/game_sa/CDamageManagerSA.cpp index 372dcaeaa5..d659330afc 100644 --- a/Client/game_sa/CDamageManagerSA.cpp +++ b/Client/game_sa/CDamageManagerSA.cpp @@ -11,6 +11,7 @@ #include "StdInc.h" #include "CDamageManagerSA.h" +#include "CAutomobileSA.h" BYTE CDamageManagerSA::GetEngineStatus() { @@ -98,7 +99,7 @@ void CDamageManagerSA::SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus) } } -void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) +void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool spawnFlyingComponent, bool breakGlass) { // Valid index? if (bPanel < MAX_PANELS && bPanelStatus <= 3) @@ -122,70 +123,41 @@ void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) // Intact? if (bPanelStatus == DT_PANEL_INTACT) { - // Grab the car node index for the given panel - static int s_iCarNodeIndexes[7] = {0x0F, 0x0E, 0x00 /*?*/, 0x00 /*?*/, 0x12, 0x0C, 0x0D}; - // Call CAutomobile::FixPanel to update the vehicle dwFunction = 0x6A3670; dwThis = (DWORD)internalEntityInterface; - int iCarNodeIndex = s_iCarNodeIndexes[bPanel]; + int carNodeIndex = GetCarNodeIndexFromPanel(bPanel); + if (carNodeIndex < 0) + return; + _asm { mov ecx, dwThis push dwPanel - push iCarNodeIndex + push carNodeIndex call dwFunction } } else - { - // Call CAutomobile::SetPanelDamage to update the vehicle - dwFunction = 0x6B1480; - dwThis = (DWORD)internalEntityInterface; - bool bUnknown = false; - _asm - { - mov ecx, dwThis - push bUnknown - push dwPanel - call dwFunction - } - } + reinterpret_cast(internalEntityInterface)->SetPanelDamage(dwPanel, breakGlass, spawnFlyingComponent); } } } -void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus) +void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus, bool spawnFlyingComponent, bool breakGlass) { unsigned int uiIndex; for (uiIndex = 0; uiIndex < MAX_PANELS; uiIndex++) { - SetPanelStatus(static_cast(uiIndex), static_cast(ulStatus)); + SetPanelStatus(static_cast(uiIndex), static_cast(ulStatus), spawnFlyingComponent, breakGlass); ulStatus >>= 4; } } -BYTE CDamageManagerSA::GetPanelStatus(BYTE bPanel) +BYTE CDamageManagerSA::GetPanelStatus(BYTE bPanel) const { - if (bPanel < MAX_PANELS) - { - DWORD dwFunction = FUNC_GetPanelStatus; - DWORD dwPointer = (DWORD)internalInterface; - BYTE bReturn = 0; - DWORD dwPanel = bPanel; - _asm - { - mov ecx, dwPointer - push dwPanel - call dwFunction - mov bReturn, al - } - - return bReturn; - } - - return 0; + return internalInterface->GetPanelStatus(bPanel); } unsigned long CDamageManagerSA::GetPanelStatus() @@ -275,3 +247,29 @@ void CDamageManagerSA::FuckCarCompletely(bool bKeepWheels) call dwFunc } } + +int CDamageManagerSA::GetCarNodeIndexFromPanel(std::uint8_t panelId) noexcept +{ + int index = -1; + + switch (panelId) + { + case 0: + index = 15; // PANEL_WING_LF + break; + case 1: + index = 14; // PANEL_WING_RF + break; + case 4: + index = 18; // PANEL_WINDSCREEN + break; + case 5: + index = 12; // BUMP_FRONT + break; + case 6: + index = 13; // BUMP_REAR + break; + } + + return index; +} diff --git a/Client/game_sa/CDamageManagerSA.h b/Client/game_sa/CDamageManagerSA.h index 33f72aeccc..b3fbb72900 100644 --- a/Client/game_sa/CDamageManagerSA.h +++ b/Client/game_sa/CDamageManagerSA.h @@ -27,6 +27,14 @@ class CDamageManagerSAInterface // 28 bytes due to the way its packed (24 containing actual data) { public: + std::uint8_t GetPanelStatus(std::uint8_t panelId) + { + if (panelId >= MAX_PANELS) + return 0; + + return ((std::uint8_t(__thiscall*)(CDamageManagerSAInterface*, std::uint8_t))FUNC_GetPanelStatus)(this, panelId); + } + float fWheelDamageEffect; BYTE bEngineStatus; // old - wont be used BYTE Wheel[MAX_WHEELS]; @@ -49,10 +57,10 @@ class CDamageManagerSA : public CDamageManager void SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool spawnFlyingComponent); BYTE GetWheelStatus(eWheelPosition bWheel); void SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus); - BYTE GetPanelStatus(BYTE bPanel); + BYTE GetPanelStatus(BYTE bPanel) const; unsigned long GetPanelStatus(); - void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus); - void SetPanelStatus(unsigned long ulStatus); + void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool spawnFlyingComponent = true, bool breakGlass = false); + void SetPanelStatus(unsigned long ulStatus, bool spawnFlyingComponent = true, bool breakGlass = false); BYTE GetLightStatus(BYTE bLight); unsigned char GetLightStatus(); void SetLightStatus(BYTE bLight, BYTE bLightStatus); @@ -62,6 +70,8 @@ class CDamageManagerSA : public CDamageManager void FuckCarCompletely(bool bKeepWheels); + static int GetCarNodeIndexFromPanel(std::uint8_t panelId) noexcept; + CDamageManagerSA(class CEntitySAInterface* intEntityInterface, CDamageManagerSAInterface* intInterface) { internalEntityInterface = intEntityInterface; diff --git a/Client/game_sa/CModelInfoSA.cpp b/Client/game_sa/CModelInfoSA.cpp index 9982bcf5bd..1c9e4ed4bf 100644 --- a/Client/game_sa/CModelInfoSA.cpp +++ b/Client/game_sa/CModelInfoSA.cpp @@ -2157,3 +2157,8 @@ bool CModelInfoSA::ForceUnload() return true; } + +bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const +{ + return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex); +} diff --git a/Client/game_sa/CModelInfoSA.h b/Client/game_sa/CModelInfoSA.h index ac55d61f48..6d0e00c758 100644 --- a/Client/game_sa/CModelInfoSA.h +++ b/Client/game_sa/CModelInfoSA.h @@ -14,6 +14,7 @@ #include #include #include "CRenderWareSA.h" +#include "game/RenderWare.h" class CPedModelInfoSA; class CPedModelInfoSAInterface; @@ -259,6 +260,14 @@ class CTimeModelInfoSAInterface : public CBaseModelInfoSAInterface CTimeInfoSAInterface timeInfo; }; +class CVehicleModelUpgradePosnDesc +{ + CVector m_vPosition; + RtQuat m_vRotation; + int m_iParentId; +}; +static_assert(sizeof(CVehicleModelUpgradePosnDesc) == 0x20, "Invalid size of CVehicleModelUpgradePosnDesc class"); + class CDamageableModelInfoSAInterface : public CBaseModelInfoSAInterface { public: @@ -268,51 +277,61 @@ class CDamageableModelInfoSAInterface : public CBaseModelInfoSAInterface class CVehicleModelVisualInfoSAInterface // Not sure about this name. If somebody knows more, please change { public: - CVector vecDummies[15]; - char m_sUpgrade[18]; + CVector vecDummies[15]; + CVehicleModelUpgradePosnDesc m_sUpgrade[18]; + RpAtomic* m_pExtra[6]; + std::uint8_t m_numExtras; + std::uint8_t _pad[3]; + int m_maskComponentDamagable; }; +static_assert(sizeof(CVehicleModelVisualInfoSAInterface) == 0x314, "Invalid size of CVehicleModelVisualInfoSAInterface class"); -class CVehicleModelInfoSAInterface : public CBaseModelInfoSAInterface +class CVehicleModelInfoSAInterface : public CClumpModelInfoSAInterface { public: - uint32 pad1; // +32 - RpMaterial* pPlateMaterial; // +36 + bool IsComponentDamageable(int componentIndex) const; + + RpMaterial* pPlateMaterial; char plateText[8]; - char pad[2]; + std::uint8_t field_30; + std::uint8_t plateType; char gameName[8]; - char pad2[2]; - unsigned int uiVehicleType; + std::uint8_t field_3A[2]; + std::uint32_t vehicleType; float fWheelSizeFront; float fWheelSizeRear; - short sWheelModel; - short sHandlingID; - byte ucNumDoors; - byte ucVehicleList; - byte ucVehicleFlags; - byte ucWheelUpgradeClass; - byte ucTimesUsed; - short sVehFrequency; - unsigned int uiComponentRules; - float fSteeringAngle; - CVehicleModelVisualInfoSAInterface* pVisualInfo; // +92 - char pad3[464]; - char pDirtMaterial[64]; // *RwMaterial - char pad4[64]; - char primColors[8]; - char secondColors[8]; - char treeColors[8]; - char fourColors[8]; - unsigned char ucNumOfColorVariations; - unsigned char ucLastColorVariation; - unsigned char ucPrimColor; - unsigned char ucSecColor; - unsigned char ucTertColor; - unsigned char ucQuatColor; - char upgrades[36]; - char anRemapTXDs[8]; - char pad5[2]; - char pAnimBlock[4]; + std::int16_t wheelModelID; + std::int16_t handlingID; + std::uint8_t numDoors; + std::uint8_t vehicleClass; + std::uint8_t vehicleFlags; + std::uint8_t wheelUpgradeClass; + std::uint8_t timesUsed; + std::uint8_t field_51; + std::int16_t vehFrequency; + std::uint32_t componentRules; + float bikeSteeringAngle; + CVehicleModelVisualInfoSAInterface* pVisualInfo; // vehicleStruct + std::uint8_t field_60[464]; + RpMaterial** m_dirtMaterials; + std::size_t m_numDirtMaterials; + RpMaterial* m_staticDirtMaterials[30]; + std::uint8_t primColors[8]; + std::uint8_t secondColors[8]; + std::uint8_t treeColors[8]; + std::uint8_t fourColors[8]; + std::uint8_t numOfColorVariations; + std::uint8_t lastColorVariation; + std::uint8_t primColor; + std::uint8_t secColor; + std::uint8_t tertColor; + std::uint8_t quatColor; + std::uint8_t upgrades[36]; + std::uint8_t anRemapTXDs[8]; + std::uint8_t field_302[2]; + void* pAnimBlock; // CAnimBlock* }; +static_assert(sizeof(CVehicleModelInfoSAInterface) == 0x308, "Invalid size of CVehicleModelInfoSAInterface class"); class CModelInfoSA : public CModelInfo { diff --git a/Client/game_sa/CVehicleSA.cpp b/Client/game_sa/CVehicleSA.cpp index afb1bf0c42..898add2961 100644 --- a/Client/game_sa/CVehicleSA.cpp +++ b/Client/game_sa/CVehicleSA.cpp @@ -1666,7 +1666,7 @@ bool CVehicleSA::SpawnFlyingComponent(const eCarNodes& nodeIndex, const eCarComp MemPut(0x6A85B3, nodesOffset); MemPut(0x6A8631, nodesOffset); - auto* componentObject = ((CObjectSAInterface * (__thiscall*)(CVehicleSAInterface*, int, int)) FUNC_CAutomobile__SpawnFlyingComponent)(GetVehicleInterface(), static_cast(nodeIndex), static_cast(collisionType)); + auto* componentObject = reinterpret_cast(GetInterface())->SpawnFlyingComponent(nodeIndex, collisionType); // Restore default nodes array in CAutomobile::SpawnFlyingComponent // CAutomobile::m_aCarNodes offset diff --git a/Client/game_sa/CVehicleSA.h b/Client/game_sa/CVehicleSA.h index ca4f496c9b..5c4b332b7c 100644 --- a/Client/game_sa/CVehicleSA.h +++ b/Client/game_sa/CVehicleSA.h @@ -274,6 +274,11 @@ class CAutoPilot class CVehicleSAInterface : public CPhysicalSAInterface { public: + void SetComponentVisibility(RwFrame* component, std::uint32_t state) + { + ((void(__thiscall*)(CVehicleSAInterface*, RwFrame*, std::uint32_t))0x6D2700)(this, component, state); + } + CAEVehicleAudioEntitySAInterface m_VehicleAudioEntity; // 312 tHandlingDataSA* pHandlingData; // +900 diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index 2c5ef561ef..ffc1fbdbc1 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -1521,12 +1521,12 @@ bool CClientVehicle::GetWheelMissing(unsigned char ucWheel, const SString& strWh return false; } -void CClientVehicle::SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus) +void CClientVehicle::SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus, bool spawnFlyingComponent, bool breakGlass) { if (ucPanel < MAX_PANELS) { if (m_pVehicle && HasDamageModel()) - m_pVehicle->GetDamageManager()->SetPanelStatus(static_cast(ucPanel), ucStatus); + m_pVehicle->GetDamageManager()->SetPanelStatus(static_cast(ucPanel), ucStatus, spawnFlyingComponent, breakGlass); m_ucPanelStates[ucPanel] = ucStatus; } diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index faeb4acfec..a316425b1d 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -292,7 +292,7 @@ class CClientVehicle : public CClientStreamElement void SetDoorStatus(unsigned char ucDoor, unsigned char ucStatus, bool spawnFlyingComponent); void SetWheelStatus(unsigned char ucWheel, unsigned char ucStatus, bool bSilent = true); - void SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus); + void SetPanelStatus(unsigned char ucPanel, unsigned char ucStatus, bool spawnFlyingComponent = true, bool breakGlass = false); void SetLightStatus(unsigned char ucLight, unsigned char ucStatus); bool GetWheelMissing(unsigned char ucWheel, const SString& strWheelName = ""); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 87521a812a..7098e7fdbd 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -3197,9 +3197,9 @@ bool CStaticFunctionDefinitions::SetVehicleLightState(CClientEntity& Entity, uns return false; } -bool CStaticFunctionDefinitions::SetVehiclePanelState(CClientEntity& Entity, unsigned char ucPanel, unsigned char ucState) +bool CStaticFunctionDefinitions::SetVehiclePanelState(CClientEntity& Entity, unsigned char ucPanel, unsigned char ucState, bool spawnFlyingComponent, bool breakGlass) { - RUN_CHILDREN(SetVehiclePanelState(**iter, ucPanel, ucState)) + RUN_CHILDREN(SetVehiclePanelState(**iter, ucPanel, ucState, spawnFlyingComponent, breakGlass)) if (IS_VEHICLE(&Entity)) { @@ -3207,7 +3207,7 @@ bool CStaticFunctionDefinitions::SetVehiclePanelState(CClientEntity& Entity, uns if (ucPanel < 7) { - Vehicle.SetPanelStatus(ucPanel, ucState); + Vehicle.SetPanelStatus(ucPanel, ucState, spawnFlyingComponent, breakGlass); return true; } } diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index 188e249f2d..17d4fa7edf 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -243,7 +243,7 @@ class CStaticFunctionDefinitions static bool SetVehicleDoorState(CClientEntity& Entity, unsigned char ucDoor, unsigned char ucState, bool spawnFlyingComponent); static bool SetVehicleWheelStates(CClientEntity& Entity, int iFrontLeft, int iRearLeft = -1, int iFrontRight = -1, int iRearRight = -1); static bool SetVehicleLightState(CClientEntity& Entity, unsigned char ucLight, unsigned char ucState); - static bool SetVehiclePanelState(CClientEntity& Entity, unsigned char ucPanel, unsigned char ucState); + static bool SetVehiclePanelState(CClientEntity& Entity, unsigned char ucPanel, unsigned char ucState, bool spawnFlyingComponent = true, bool breakGlass = false); static bool SetVehicleOverrideLights(CClientEntity& Entity, unsigned char ucLights); static bool AttachTrailerToVehicle(CClientVehicle& Vehicle, CClientVehicle& Trailer, const CVector& vecRotationOffsetDegrees); static bool DetachTrailerFromVehicle(CClientVehicle& Vehicle, CClientVehicle* pTrailer = NULL); diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp b/Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp index e9ec1ca94b..ff92f957d5 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp +++ b/Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp @@ -1956,14 +1956,17 @@ int CLuaVehicleDefs::SetVehiclePanelState(lua_State* luaVM) { CClientEntity* pEntity = NULL; unsigned char ucPanel = 0, ucState = 0; + bool spawnFlyingComponent, breakGlass; CScriptArgReader argStream(luaVM); argStream.ReadUserData(pEntity); argStream.ReadNumber(ucPanel); argStream.ReadNumber(ucState); + argStream.ReadBool(spawnFlyingComponent, true); + argStream.ReadBool(breakGlass, false); if (!argStream.HasErrors()) { - if (CStaticFunctionDefinitions::SetVehiclePanelState(*pEntity, ucPanel, ucState)) + if (CStaticFunctionDefinitions::SetVehiclePanelState(*pEntity, ucPanel, ucState, spawnFlyingComponent, breakGlass)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Client/mods/deathmatch/logic/rpc/CVehicleRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CVehicleRPCs.cpp index 50d5028caf..78215f30aa 100644 --- a/Client/mods/deathmatch/logic/rpc/CVehicleRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CVehicleRPCs.cpp @@ -352,7 +352,15 @@ void CVehicleRPCs::SetVehicleDamageState(CClientEntity* pSource, NetBitStreamInt unsigned char ucPanel, ucState; if (bitStream.Read(ucPanel) && bitStream.Read(ucState)) { - pVehicle->SetPanelStatus(ucPanel, ucState); + bool spawnFlyingComponent = true; + bool breakGlass = false; + if (bitStream.Can(eBitStreamVersion::SetVehiclePanelState_SpawnFlyingComponent)) + { + bitStream.ReadBit(spawnFlyingComponent); + bitStream.ReadBit(breakGlass); + } + + pVehicle->SetPanelStatus(ucPanel, ucState, spawnFlyingComponent, breakGlass); } } default: diff --git a/Client/sdk/game/CDamageManager.h b/Client/sdk/game/CDamageManager.h index 9c4fcc2348..a764467a5a 100644 --- a/Client/sdk/game/CDamageManager.h +++ b/Client/sdk/game/CDamageManager.h @@ -55,12 +55,12 @@ enum ePlaneComponentStatus DT_PLANE_MISSING }; -enum eComponentStatus +enum eComponentStatus : std::uint8_t { DT_PANEL_INTACT = 0, - // DT_PANEL_SHIFTED, - DT_PANEL_BASHED, - DT_PANEL_BASHED2, + DT_PANEL_OPENED, + DT_PANEL_DAMAGED, + DT_PANEL_OPENED_DAMAGED, DT_PANEL_MISSING }; @@ -173,10 +173,10 @@ class CDamageManager virtual void SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool spawnFlyingComponent) = 0; virtual BYTE GetWheelStatus(eWheelPosition bTire) = 0; virtual void SetWheelStatus(eWheelPosition bTire, BYTE bTireStatus) = 0; - virtual BYTE GetPanelStatus(BYTE bPanel) = 0; + virtual BYTE GetPanelStatus(BYTE bPanel) const = 0; virtual unsigned long GetPanelStatus() = 0; - virtual void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) = 0; - virtual void SetPanelStatus(unsigned long ulStatus) = 0; + virtual void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool spawnFlyingComponent = true, bool breakGlass = false) = 0; + virtual void SetPanelStatus(unsigned long ulStatus, bool spawnFlyingComponent = true, bool breakGlass = false) = 0; virtual BYTE GetLightStatus(BYTE bLight) = 0; virtual unsigned char GetLightStatus() = 0; virtual void SetLightStatus(BYTE bLight, BYTE bLightStatus) = 0; diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 2aaf1867bd..c3cebfdce8 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -6719,10 +6719,10 @@ bool CStaticFunctionDefinitions::SetVehicleLightState(CElement* pElement, unsign return false; } -bool CStaticFunctionDefinitions::SetVehiclePanelState(CElement* pElement, unsigned char ucPanel, unsigned char ucState) +bool CStaticFunctionDefinitions::SetVehiclePanelState(CElement* pElement, unsigned char ucPanel, unsigned char ucState, bool spawnFlyingComponent, bool breakGlass) { assert(pElement); - RUN_CHILDREN(SetVehiclePanelState(*iter, ucPanel, ucState)) + RUN_CHILDREN(SetVehiclePanelState(*iter, ucPanel, ucState, spawnFlyingComponent, breakGlass)) if (IS_VEHICLE(pElement)) { @@ -6739,6 +6739,8 @@ bool CStaticFunctionDefinitions::SetVehiclePanelState(CElement* pElement, unsign BitStream.pBitStream->Write(ucObject); BitStream.pBitStream->Write(ucPanel); BitStream.pBitStream->Write(ucState); + BitStream.pBitStream->WriteBit(spawnFlyingComponent); + BitStream.pBitStream->WriteBit(breakGlass); m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pVehicle, SET_VEHICLE_DAMAGE_STATE, *BitStream.pBitStream)); return true; } diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h index ea178da19b..52ce191c26 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -314,7 +314,7 @@ class CStaticFunctionDefinitions static bool SetVehicleDoorState(CElement* pElement, unsigned char ucDoor, unsigned char ucState, bool spawnFlyingComponent); static bool SetVehicleWheelStates(CElement* pElement, int iFrontLeft, int iRearLeft = -1, int iFrontRight = -1, int iRearRight = -1); static bool SetVehicleLightState(CElement* pElement, unsigned char ucLight, unsigned char ucState); - static bool SetVehiclePanelState(CElement* pElement, unsigned char ucPanel, unsigned char ucState); + static bool SetVehiclePanelState(CElement* pElement, unsigned char ucPanel, unsigned char ucState, bool spawnFlyingComponent = true, bool breakGlass = false); static bool SetVehicleIdleRespawnDelay(CElement* pElement, unsigned long ulTime); static bool SetVehicleRespawnDelay(CElement* pElement, unsigned long ulTime); static bool GetVehicleRespawnPosition(CElement* pElement, CVector& vecPosition); diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp index 55ab0e0631..b1352f2e9e 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp @@ -2125,15 +2125,19 @@ int CLuaVehicleDefs::SetVehiclePanelState(lua_State* luaVM) CElement* pElement; unsigned char ucPanel; unsigned char ucState; + bool spawnFlyingComponent; + bool breakGlass; CScriptArgReader argStream(luaVM); argStream.ReadUserData(pElement); argStream.ReadNumber(ucPanel); argStream.ReadNumber(ucState); + argStream.ReadBool(spawnFlyingComponent, true); + argStream.ReadBool(breakGlass, false); if (!argStream.HasErrors()) { - if (CStaticFunctionDefinitions::SetVehiclePanelState(pElement, ucPanel, ucState)) + if (CStaticFunctionDefinitions::SetVehiclePanelState(pElement, ucPanel, ucState, spawnFlyingComponent, breakGlass)) { lua_pushboolean(luaVM, true); return 1; diff --git a/Shared/sdk/SharedUtil.Math.h b/Shared/sdk/SharedUtil.Math.h index 32677d4e0c..73c7c532df 100644 --- a/Shared/sdk/SharedUtil.Math.h +++ b/Shared/sdk/SharedUtil.Math.h @@ -12,6 +12,7 @@ #include #include "SharedUtil.Misc.h" +#include namespace SharedUtil { @@ -104,4 +105,12 @@ namespace SharedUtil } inline float DegreesToRadians(float fValue) { return fValue * 0.017453292f; } + + static std::random_device randomDevice; + static std::mt19937 randomEngine(randomDevice()); + + inline float GetRandomNumberInRange(float minRange, float maxRange) + { + return std::uniform_real_distribution{minRange, maxRange}(randomEngine); + } } // namespace SharedUtil diff --git a/Shared/sdk/net/bitstream.h b/Shared/sdk/net/bitstream.h index 5c68ec2c2e..7a2d3f10d7 100644 --- a/Shared/sdk/net/bitstream.h +++ b/Shared/sdk/net/bitstream.h @@ -589,9 +589,13 @@ enum class eBitStreamVersion : unsigned short WorldSpecialPropertyEvent, // Add setElementOnFire function - // 2024-30-12 + // 2024-12-30 SetElementOnFire, + // Add "spawnFlyingComponent" to setVehiclePanelState + // 2024-12-31 + SetVehiclePanelState_SpawnFlyingComponent, + // This allows us to automatically increment the BitStreamVersion when things are added to this enum. // Make sure you only add things above this comment. Next,