diff --git a/Client/game_sa/CDamageManagerSA.cpp b/Client/game_sa/CDamageManagerSA.cpp index 372dcaeaa57..6f5ae8f81ef 100644 --- a/Client/game_sa/CDamageManagerSA.cpp +++ b/Client/game_sa/CDamageManagerSA.cpp @@ -98,7 +98,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) @@ -140,28 +140,19 @@ void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus) 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 - } + ((void(__thiscall*)(CEntitySAInterface*, int, bool, bool))0x6B1480)(internalEntityInterface, dwPanel, bPanel == ePanels::WINDSCREEN_PANEL && 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; } } diff --git a/Client/game_sa/CDamageManagerSA.h b/Client/game_sa/CDamageManagerSA.h index 33f72aeccc8..00651f68b5e 100644 --- a/Client/game_sa/CDamageManagerSA.h +++ b/Client/game_sa/CDamageManagerSA.h @@ -51,8 +51,8 @@ class CDamageManagerSA : public CDamageManager void SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus); BYTE GetPanelStatus(BYTE bPanel); 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); diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index 2c5ef561ef2..ffc1fbdbc1a 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 faeb4acfec7..a316425b1df 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 87521a812a5..7098e7fdbd7 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 188e249f2d1..17d4fa7edf1 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 e9ec1ca94b7..ff92f957d54 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 50d5028caf8..78215f30aad 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/multiplayer_sa/CMultiplayerSA_Vehicles.cpp b/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp index 88b0b11eb8a..9884e8e658c 100644 --- a/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp @@ -107,6 +107,33 @@ static void _declspec(naked) HOOK_CAEVehicleAudioEntity__Initialise() } } +////////////////////////////////////////////////////////////////////////////////////////// +// CAutomobile::SetPanelDamage +// +// This hook allows determining whether flying components should be spawned +////////////////////////////////////////////////////////////////////////////////////////// +#define HOOKPOS_CAutomobile_SetPanelDamage 0x6B15BE +#define HOOKSIZE_CAutomobile_SetPanelDamage 5 +static DWORD SPAWN_FLYING_COMPONENTS = 0x6B15C3; +static DWORD SKIP_FLYING_COMPONENTS = 0x6B15DA; +static void _declspec(naked) HOOK_CAutomobile_SetPanelDamage() +{ + _asm + { + mov al, byte ptr [esp+1Ch] + test al, al + jnz skipFlyingComponents + + push 5 + push ebp + mov ecx, esi + jmp SPAWN_FLYING_COMPONENTS + + skipFlyingComponents: + jmp SKIP_FLYING_COMPONENTS + } +} + ////////////////////////////////////////////////////////////////////////////////////////// // // CMultiplayerSA::InitHooks_Vehicles @@ -118,4 +145,5 @@ void CMultiplayerSA::InitHooks_Vehicles() { EZHookInstall(CDamageManager__ProgressDoorDamage); EZHookInstall(CAEVehicleAudioEntity__Initialise); + EZHookInstall(CAutomobile_SetPanelDamage); } diff --git a/Client/sdk/game/CDamageManager.h b/Client/sdk/game/CDamageManager.h index 9c4fcc23487..7b48148f4b5 100644 --- a/Client/sdk/game/CDamageManager.h +++ b/Client/sdk/game/CDamageManager.h @@ -175,8 +175,8 @@ class CDamageManager virtual void SetWheelStatus(eWheelPosition bTire, BYTE bTireStatus) = 0; virtual BYTE GetPanelStatus(BYTE bPanel) = 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 2aaf1867bdb..c3cebfdce8a 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 ea178da19b9..52ce191c262 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 55ab0e06312..b1352f2e9eb 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/net/bitstream.h b/Shared/sdk/net/bitstream.h index 5c68ec2c2e3..7a2d3f10d75 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,