Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add spawnFlyingComponent & breakGlass arguments for setVehiclePanelState #3920

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading