Skip to content

Commit c0b47ea

Browse files
authored
Add spawnFlyingComponent & breakGlass arguments for setVehiclePanelState (PR #3920, Fixes #2122)
Previous attempt in 5b69d70
1 parent 0f9e18d commit c0b47ea

21 files changed

+255
-101
lines changed

Client/game_sa/CAEVehicleAudioEntitySA.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ static_assert(sizeof(CAETwinLoopSoundEntity) == 0xA8, "Invalid size for CAETwinL
7373
class CAEVehicleAudioEntitySAInterface : public CAEAudioEntity
7474
{
7575
public:
76+
void AddAudioEvent(int eventId, float volume)
77+
{
78+
((void(__thiscall*)(CAEVehicleAudioEntitySAInterface*, int, float))0x4F6420)(this, eventId, volume);
79+
}
80+
7681
short unk1; // +124
7782
char unk2[2]; // +126
7883
tVehicleAudioSettings m_nSettings; // +128

Client/game_sa/CAutomobileSA.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,79 @@
1111

1212
#include "StdInc.h"
1313
#include "CAutomobileSA.h"
14+
#include "CGameSA.h"
15+
16+
extern CGameSA* pGame;
1417

1518
CAutomobileSA::CAutomobileSA(CAutomobileSAInterface* pInterface)
1619
{
1720
SetInterface(pInterface);
1821
Init();
1922
}
23+
24+
void CAutomobileSAInterface::SetPanelDamage(std::uint8_t panelId, bool breakGlass, bool spawnFlyingComponent)
25+
{
26+
int nodeId = CDamageManagerSA::GetCarNodeIndexFromPanel(panelId);
27+
if (nodeId < 0)
28+
return;
29+
30+
eCarNodes node = static_cast<eCarNodes>(nodeId);
31+
32+
RwFrame* frame = m_aCarNodes[nodeId];
33+
if (!frame)
34+
return;
35+
36+
CVehicleModelInfoSAInterface* vehicleInfo = nullptr;
37+
if (auto* mi = pGame->GetModelInfo(m_nModelIndex))
38+
vehicleInfo = static_cast<CVehicleModelInfoSAInterface*>(mi->GetInterface());
39+
40+
if (!vehicleInfo || !vehicleInfo->IsComponentDamageable(nodeId))
41+
return;
42+
43+
switch (m_damageManager.GetPanelStatus(panelId))
44+
{
45+
case DT_PANEL_DAMAGED:
46+
{
47+
if ((pHandlingData->uiModelFlags & 0x10000000) != 0) // check bouncePanels flag
48+
return;
49+
50+
if (node != eCarNodes::WINDSCREEN && node != eCarNodes::WING_LF && node != eCarNodes::WING_RF)
51+
{
52+
// Get free bouncing panel
53+
for (auto& panel : m_panels)
54+
{
55+
if (panel.m_nFrameId == (std::uint16_t)0xFFFF)
56+
{
57+
panel.SetPanel(nodeId, 1, GetRandomNumberInRange(-0.2f, -0.5f));
58+
break;
59+
}
60+
}
61+
}
62+
63+
SetComponentVisibility(frame, 2); // ATOMIC_IS_DAM_STATE
64+
break;
65+
}
66+
case DT_PANEL_OPENED:
67+
{
68+
if (panelId == WINDSCREEN_PANEL)
69+
m_VehicleAudioEntity.AddAudioEvent(91, 0.0f);
70+
71+
SetComponentVisibility(frame, 2); // ATOMIC_IS_DAM_STATE
72+
break;
73+
}
74+
case DT_PANEL_OPENED_DAMAGED:
75+
{
76+
if (panelId == WINDSCREEN_PANEL)
77+
{
78+
if (breakGlass)
79+
((void(__cdecl*)(CAutomobileSAInterface*, bool))0x71C2B0)(this, false); // Call CGlass::CarWindscreenShatters
80+
}
81+
82+
if (spawnFlyingComponent && (panelId != WINDSCREEN_PANEL || (panelId == WINDSCREEN_PANEL && !breakGlass)))
83+
SpawnFlyingComponent(node, eCarComponentCollisionTypes::COL_NODE_PANEL);
84+
85+
SetComponentVisibility(frame, 0); // ATOMIC_IS_NOT_PRESENT
86+
break;
87+
}
88+
}
89+
}

Client/game_sa/CAutomobileSA.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
class CBouncingPanelSAInterface
2525
{
2626
public:
27+
void SetPanel(std::int16_t frameId, std::int16_t axis, float angleLimit)
28+
{
29+
((void(__thiscall*)(CBouncingPanelSAInterface*, std::int16_t, std::int16_t, float))0x6F4920)(this, frameId, axis, angleLimit);
30+
}
31+
2732
unsigned short m_nFrameId;
2833
unsigned short m_nAxis;
2934
float m_fAngleLimit;
@@ -35,6 +40,13 @@ static_assert(sizeof(CBouncingPanelSAInterface) == 0x20, "Invalid size for CBoun
3540
class CAutomobileSAInterface : public CVehicleSAInterface
3641
{
3742
public:
43+
void SetPanelDamage(std::uint8_t panelId, bool breakGlass, bool spawnFlyingComponent = true);
44+
45+
CObjectSAInterface* SpawnFlyingComponent(const eCarNodes& nodeId, const eCarComponentCollisionTypes& collType)
46+
{
47+
return ((CObjectSAInterface*(__thiscall*)(CAutomobileSAInterface*, eCarNodes, eCarComponentCollisionTypes))0x6a8580)(this, nodeId, collType);
48+
}
49+
3850
CDamageManagerSAInterface m_damageManager;
3951
CDoorSAInterface m_doors[MAX_DOORS];
4052
RwFrame* m_aCarNodes[static_cast<std::size_t>(eCarNodes::NUM_NODES)];

Client/game_sa/CDamageManagerSA.cpp

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include "StdInc.h"
1313
#include "CDamageManagerSA.h"
14+
#include "CAutomobileSA.h"
1415

1516
BYTE CDamageManagerSA::GetEngineStatus()
1617
{
@@ -98,7 +99,7 @@ void CDamageManagerSA::SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus)
9899
}
99100
}
100101

101-
void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus)
102+
void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool spawnFlyingComponent, bool breakGlass)
102103
{
103104
// Valid index?
104105
if (bPanel < MAX_PANELS && bPanelStatus <= 3)
@@ -122,70 +123,41 @@ void CDamageManagerSA::SetPanelStatus(BYTE bPanel, BYTE bPanelStatus)
122123
// Intact?
123124
if (bPanelStatus == DT_PANEL_INTACT)
124125
{
125-
// Grab the car node index for the given panel
126-
static int s_iCarNodeIndexes[7] = {0x0F, 0x0E, 0x00 /*?*/, 0x00 /*?*/, 0x12, 0x0C, 0x0D};
127-
128126
// Call CAutomobile::FixPanel to update the vehicle
129127
dwFunction = 0x6A3670;
130128
dwThis = (DWORD)internalEntityInterface;
131-
int iCarNodeIndex = s_iCarNodeIndexes[bPanel];
129+
int carNodeIndex = GetCarNodeIndexFromPanel(bPanel);
130+
if (carNodeIndex < 0)
131+
return;
132+
132133
_asm
133134
{
134135
mov ecx, dwThis
135136
push dwPanel
136-
push iCarNodeIndex
137+
push carNodeIndex
137138
call dwFunction
138139
}
139140
}
140141
else
141-
{
142-
// Call CAutomobile::SetPanelDamage to update the vehicle
143-
dwFunction = 0x6B1480;
144-
dwThis = (DWORD)internalEntityInterface;
145-
bool bUnknown = false;
146-
_asm
147-
{
148-
mov ecx, dwThis
149-
push bUnknown
150-
push dwPanel
151-
call dwFunction
152-
}
153-
}
142+
reinterpret_cast<CAutomobileSAInterface*>(internalEntityInterface)->SetPanelDamage(dwPanel, breakGlass, spawnFlyingComponent);
154143
}
155144
}
156145
}
157146

158-
void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus)
147+
void CDamageManagerSA::SetPanelStatus(unsigned long ulStatus, bool spawnFlyingComponent, bool breakGlass)
159148
{
160149
unsigned int uiIndex;
161150

162151
for (uiIndex = 0; uiIndex < MAX_PANELS; uiIndex++)
163152
{
164-
SetPanelStatus(static_cast<eDoors>(uiIndex), static_cast<unsigned char>(ulStatus));
153+
SetPanelStatus(static_cast<eDoors>(uiIndex), static_cast<unsigned char>(ulStatus), spawnFlyingComponent, breakGlass);
165154
ulStatus >>= 4;
166155
}
167156
}
168157

169-
BYTE CDamageManagerSA::GetPanelStatus(BYTE bPanel)
158+
BYTE CDamageManagerSA::GetPanelStatus(BYTE bPanel) const
170159
{
171-
if (bPanel < MAX_PANELS)
172-
{
173-
DWORD dwFunction = FUNC_GetPanelStatus;
174-
DWORD dwPointer = (DWORD)internalInterface;
175-
BYTE bReturn = 0;
176-
DWORD dwPanel = bPanel;
177-
_asm
178-
{
179-
mov ecx, dwPointer
180-
push dwPanel
181-
call dwFunction
182-
mov bReturn, al
183-
}
184-
185-
return bReturn;
186-
}
187-
188-
return 0;
160+
return internalInterface->GetPanelStatus(bPanel);
189161
}
190162

191163
unsigned long CDamageManagerSA::GetPanelStatus()
@@ -275,3 +247,29 @@ void CDamageManagerSA::FuckCarCompletely(bool bKeepWheels)
275247
call dwFunc
276248
}
277249
}
250+
251+
int CDamageManagerSA::GetCarNodeIndexFromPanel(std::uint8_t panelId) noexcept
252+
{
253+
int index = -1;
254+
255+
switch (panelId)
256+
{
257+
case 0:
258+
index = 15; // PANEL_WING_LF
259+
break;
260+
case 1:
261+
index = 14; // PANEL_WING_RF
262+
break;
263+
case 4:
264+
index = 18; // PANEL_WINDSCREEN
265+
break;
266+
case 5:
267+
index = 12; // BUMP_FRONT
268+
break;
269+
case 6:
270+
index = 13; // BUMP_REAR
271+
break;
272+
}
273+
274+
return index;
275+
}

Client/game_sa/CDamageManagerSA.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
class CDamageManagerSAInterface // 28 bytes due to the way its packed (24 containing actual data)
2828
{
2929
public:
30+
std::uint8_t GetPanelStatus(std::uint8_t panelId)
31+
{
32+
if (panelId >= MAX_PANELS)
33+
return 0;
34+
35+
return ((std::uint8_t(__thiscall*)(CDamageManagerSAInterface*, std::uint8_t))FUNC_GetPanelStatus)(this, panelId);
36+
}
37+
3038
float fWheelDamageEffect;
3139
BYTE bEngineStatus; // old - wont be used
3240
BYTE Wheel[MAX_WHEELS];
@@ -49,10 +57,10 @@ class CDamageManagerSA : public CDamageManager
4957
void SetDoorStatus(eDoors bDoor, BYTE bDoorStatus, bool spawnFlyingComponent);
5058
BYTE GetWheelStatus(eWheelPosition bWheel);
5159
void SetWheelStatus(eWheelPosition bWheel, BYTE bTireStatus);
52-
BYTE GetPanelStatus(BYTE bPanel);
60+
BYTE GetPanelStatus(BYTE bPanel) const;
5361
unsigned long GetPanelStatus();
54-
void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus);
55-
void SetPanelStatus(unsigned long ulStatus);
62+
void SetPanelStatus(BYTE bPanel, BYTE bPanelStatus, bool spawnFlyingComponent = true, bool breakGlass = false);
63+
void SetPanelStatus(unsigned long ulStatus, bool spawnFlyingComponent = true, bool breakGlass = false);
5664
BYTE GetLightStatus(BYTE bLight);
5765
unsigned char GetLightStatus();
5866
void SetLightStatus(BYTE bLight, BYTE bLightStatus);
@@ -62,6 +70,8 @@ class CDamageManagerSA : public CDamageManager
6270

6371
void FuckCarCompletely(bool bKeepWheels);
6472

73+
static int GetCarNodeIndexFromPanel(std::uint8_t panelId) noexcept;
74+
6575
CDamageManagerSA(class CEntitySAInterface* intEntityInterface, CDamageManagerSAInterface* intInterface)
6676
{
6777
internalEntityInterface = intEntityInterface;

Client/game_sa/CModelInfoSA.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,3 +2157,8 @@ bool CModelInfoSA::ForceUnload()
21572157

21582158
return true;
21592159
}
2160+
2161+
bool CVehicleModelInfoSAInterface::IsComponentDamageable(int componentIndex) const
2162+
{
2163+
return pVisualInfo->m_maskComponentDamagable & (1 << componentIndex);
2164+
}

0 commit comments

Comments
 (0)