Skip to content

Commit

Permalink
Add spawnFlyingComponent & breakGlass arguments for setVehiclePanelSt…
Browse files Browse the repository at this point in the history
…ate (PR multitheftauto#3920, Fixes multitheftauto#2122)

Previous attempt in 5b69d70
  • Loading branch information
FileEX authored Jan 3, 2025
1 parent 0f9e18d commit c0b47ea
Show file tree
Hide file tree
Showing 21 changed files with 255 additions and 101 deletions.
5 changes: 5 additions & 0 deletions Client/game_sa/CAEVehicleAudioEntitySA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions Client/game_sa/CAutomobileSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<eCarNodes>(nodeId);

RwFrame* frame = m_aCarNodes[nodeId];
if (!frame)
return;

CVehicleModelInfoSAInterface* vehicleInfo = nullptr;
if (auto* mi = pGame->GetModelInfo(m_nModelIndex))
vehicleInfo = static_cast<CVehicleModelInfoSAInterface*>(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;
}
}
}
12 changes: 12 additions & 0 deletions Client/game_sa/CAutomobileSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<std::size_t>(eCarNodes::NUM_NODES)];
Expand Down
78 changes: 38 additions & 40 deletions Client/game_sa/CDamageManagerSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "StdInc.h"
#include "CDamageManagerSA.h"
#include "CAutomobileSA.h"

BYTE CDamageManagerSA::GetEngineStatus()
{
Expand Down Expand Up @@ -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)
Expand All @@ -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<CAutomobileSAInterface*>(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<eDoors>(uiIndex), static_cast<unsigned char>(ulStatus));
SetPanelStatus(static_cast<eDoors>(uiIndex), static_cast<unsigned char>(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()
Expand Down Expand Up @@ -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;
}
16 changes: 13 additions & 3 deletions Client/game_sa/CDamageManagerSA.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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);
Expand All @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions Client/game_sa/CModelInfoSA.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2157,3 +2157,8 @@ bool CModelInfoSA::ForceUnload()

return true;
}

bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const
{
return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex);
}
Loading

0 comments on commit c0b47ea

Please sign in to comment.