Skip to content
12 changes: 7 additions & 5 deletions Client/game_sa/CDamageManagerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -142,11 +142,13 @@ void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus)
// Call CAutomobile::SetPanelDamage to update the vehicle
dwFunction = 0x6B1480;
dwThis = (DWORD)internalEntityInterface;
bool bUnknown = false;
bool windscreenShatter = bPanel == ePanels::WINDSCREEN_PANEL && breakGlass;
bool quiet = !spawnFlyingComponent;
_asm
{
mov ecx, dwThis
push bUnknown
push quiet
push windscreenShatter
push dwPanel
call dwFunction
}
Expand All @@ -155,13 +157,13 @@ void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus)
}
}

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<eDoors>(uiIndex), static_cast<unsigned char>(ulStatus));
SetPanelStatus(static_cast<eDoors>(uiIndex), static_cast<unsigned char>(ulStatus), spawnFlyingComponent, breakGlass);
ulStatus >>= 4;
}
}
Expand Down
4 changes: 2 additions & 2 deletions Client/game_sa/CDamageManagerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions Client/mods/deathmatch/logic/CClientVehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1525,12 +1525,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<ePanels>(ucPanel), ucStatus);
m_pVehicle->GetDamageManager()->SetPanelStatus(static_cast<ePanels>(ucPanel), ucStatus, spawnFlyingComponent, breakGlass);

m_ucPanelStates[ucPanel] = ucStatus;
}
Expand Down
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/CClientVehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "");

Expand Down
6 changes: 3 additions & 3 deletions Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3194,17 +3194,17 @@ 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))
{
CClientVehicle& Vehicle = static_cast<CClientVehicle&>(Entity);

if (ucPanel < 7)
{
Vehicle.SetPanelStatus(ucPanel, ucState);
Vehicle.SetPanelStatus(ucPanel, ucState, spawnFlyingComponent, breakGlass);
return true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,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);
Expand Down
5 changes: 4 additions & 1 deletion Client/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1941,14 +1941,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;
Expand Down
10 changes: 9 additions & 1 deletion Client/mods/deathmatch/logic/rpc/CVehicleRPCs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,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:
Expand Down
28 changes: 28 additions & 0 deletions Client/multiplayer_sa/CMultiplayerSA_Vehicles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -118,4 +145,5 @@ void CMultiplayerSA::InitHooks_Vehicles()
{
EZHookInstall(CDamageManager__ProgressDoorDamage);
EZHookInstall(CAEVehicleAudioEntity__Initialise);
EZHookInstall(CAutomobile_SetPanelDamage);
}
4 changes: 2 additions & 2 deletions Client/sdk/game/CDamageManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,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;
Expand Down
6 changes: 4 additions & 2 deletions Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6722,10 +6722,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))
{
Expand All @@ -6742,6 +6742,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;
}
Expand Down
2 changes: 1 addition & 1 deletion Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,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);
Expand Down
6 changes: 5 additions & 1 deletion Server/mods/deathmatch/logic/luadefs/CLuaVehicleDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2122,15 +2122,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;
Expand Down
4 changes: 4 additions & 0 deletions Shared/sdk/net/bitstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,10 @@ enum class eBitStreamVersion : unsigned short
// 2024-09-04
RespawnObject_Serverside,

// Add "spawnFlyingComponent" to setVehiclePanelState
// 2024-07-15
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,
Expand Down