Fix the logic behind exploding cars losing wheels

Fixes #17
This commit is contained in:
Silent 2024-03-06 22:42:35 +01:00
parent c6c9fe6013
commit 9f94595ee4
No known key found for this signature in database
GPG key ID: AE53149BB0C45AF1
3 changed files with 144 additions and 2 deletions

View file

@ -5294,6 +5294,24 @@ void Patch_SA_10(HINSTANCE hInstance)
InterceptCall(0x6A8BBE, orgWorldAdd, WorldAdd_SetLightObjectFlag); InterceptCall(0x6A8BBE, orgWorldAdd, WorldAdd_SetLightObjectFlag);
} }
// Fix the logic behind exploding cars losing wheels
// Right now, they lose one wheel at random according to the damage manager, but they always lose the front left wheel visually.
// This change matches the visuals to the physics
// Also make it possible for the rear right wheel to be randomly picked
{
std::array<uint32_t, 4> spawnFlyingComponent = { 0x6B38CA, 0x6B3CCB, 0x6C6EBE, 0x6CCEF9 };
CAutomobile::HookEach_SpawnFlyingComponent(spawnFlyingComponent, InterceptCall);
Nop(0x6B38E4, 5);
Nop(0x6B3CF1, 5);
Nop(0x6C6ED8, 5);
Nop(0x6CCF17, 5);
static const float fRandomness = -4.0f;
Patch(0x6C25F5 + 2, &fRandomness);
}
#if FULL_PRECISION_D3D #if FULL_PRECISION_D3D
// Test - full precision D3D device // Test - full precision D3D device
Patch<uint8_t>( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE ); Patch<uint8_t>( 0x7F672B+1, *(uint8_t*)(0x7F672B+1) | D3DCREATE_FPU_PRESERVE );
@ -7028,6 +7046,36 @@ void Patch_SA_NewBinaries_Common(HINSTANCE hInstance)
InterceptCall(worldAdd, orgWorldAdd, WorldAdd_SetLightObjectFlag); InterceptCall(worldAdd, orgWorldAdd, WorldAdd_SetLightObjectFlag);
} }
// Fix the logic behind exploding cars losing wheels
// Right now, they lose one wheel at random according to the damage manager, but they always lose the front left wheel visually.
// This change matches the visuals to the physics
// Also make it possible for the rear right wheel to be randomly picked
{
auto automobileBlowUp = pattern("E8 ? ? ? ? 8B 8E ? ? ? ? 8D 45 08").get_one();
auto automobileBlowUpCutscene = pattern("E8 ? ? ? ? 80 7D 10 00 C7 45").get_one();
auto heliBlowUp = pattern("E8 ? ? ? ? 8B 86 ? ? ? ? 8D 55 08").get_one();
auto planeBlowUp = pattern("E8 ? ? ? ? 8B 86 ? ? ? ? 85 C0 74 24").get_one();
auto wheelDetachRandomness = get_pattern("DC 0D ? ? ? ? E8 ? ? ? ? 8B CE", 2);
std::array<void*, 4> spawnFlyingComponent = {
automobileBlowUp.get<void>(),
automobileBlowUpCutscene.get<void>(),
heliBlowUp.get<void>(),
planeBlowUp.get<void>(),
};
CAutomobile::HookEach_SpawnFlyingComponent(spawnFlyingComponent, InterceptCall);
Nop(automobileBlowUp.get<void>(0x1C), 5);
Nop(automobileBlowUpCutscene.get<void>(0x22), 5);
Nop(heliBlowUp.get<void>(0x1C), 5);
Nop(planeBlowUp.get<void>(0x20), 5);
static const double fRandomness = -4.0;
Patch(wheelDetachRandomness, &fRandomness);
}
} }

View file

@ -573,6 +573,69 @@ void CAutomobile::AfterPreRender()
} }
} }
void CAutomobile::HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int nodeID, unsigned int modelID)
{
auto hideWheel = [this](int nodeID)
{
bool bHasWheel = false;
RwFrame* wheelNode = m_pCarNode[nodeID];
if (wheelNode != nullptr)
{
RwFrameForAllObjects(wheelNode, [&bHasWheel](RwObject* object)
{
if ((rwObjectGetFlags(object) & rpATOMICRENDER) != 0)
{
rwObjectSetFlags(object, 0);
bHasWheel = true;
}
return object;
});
}
return bHasWheel;
};
if (m_DamageManager.GetWheelStatus(0) == 2)
{
if (hideWheel(5))
{
std::invoke(spawnFlyingComponentCB, this, 5, modelID);
}
}
if (m_DamageManager.GetWheelStatus(2) == 2)
{
if (hideWheel(2))
{
std::invoke(spawnFlyingComponentCB, this, 2, modelID);
}
}
// For rear wheels, also hide and spawn the middle wheel (if it exists)
if (m_DamageManager.GetWheelStatus(1) == 2)
{
if (hideWheel(6))
{
std::invoke(spawnFlyingComponentCB, this, 6, modelID);
}
if (hideWheel(7))
{
std::invoke(spawnFlyingComponentCB, this, 7, modelID);
}
}
if (m_DamageManager.GetWheelStatus(3) == 2)
{
if (hideWheel(3))
{
std::invoke(spawnFlyingComponentCB, this, 3, modelID);
}
if (hideWheel(4))
{
std::invoke(spawnFlyingComponentCB, this, 4, modelID);
}
}
}
void CAutomobile::Fix_SilentPatch() void CAutomobile::Fix_SilentPatch()
{ {
ResetFrames(); ResetFrames();

View file

@ -135,6 +135,24 @@ public:
} }
}; };
class CDamageManager
{
private:
float WheelDamageEffect;
uint8_t EngineStatus;
uint8_t Wheel[4];
uint8_t Door[6];
uint32_t Lights;
uint32_t Panels;
public:
uint32_t GetWheelStatus(int wheelID) const
{
return Wheel[wheelID];
}
};
static_assert(sizeof(CDamageManager) == 0x18, "Wrong size: CDamageManager");
enum eRotAxis enum eRotAxis
{ {
ROT_AXIS_X = 0, ROT_AXIS_X = 0,
@ -299,7 +317,7 @@ public:
class NOVMT CAutomobile : public CVehicle class NOVMT CAutomobile : public CVehicle
{ {
public: public:
BYTE paddd[24]; CDamageManager m_DamageManager;
CDoor Door[NUM_DOORS]; CDoor Door[NUM_DOORS];
RwFrame* m_pCarNode[25]; RwFrame* m_pCarNode[25];
CBouncingPanel m_aBouncingPanel[3]; CBouncingPanel m_aBouncingPanel[3];
@ -327,7 +345,20 @@ public:
AfterPreRender(); AfterPreRender();
} }
HOOK_EACH_FUNC_CTR(PreRender, 1, orgAutomobilePreRender, &PreRender_SilentPatch); HOOK_EACH_FUNC(PreRender, orgAutomobilePreRender, &PreRender_SilentPatch);
void HideDestroyedWheels_SilentPatch(void (CAutomobile::*spawnFlyingComponentCB)(int, unsigned int), int nodeID, unsigned int modelID);
template<std::size_t Index>
static void (CAutomobile::*orgSpawnFlyingComponent)(int, unsigned int);
template<std::size_t Index>
void SpawnFlyingComponent_HideWheels(int nodeID, unsigned int modelID)
{
HideDestroyedWheels_SilentPatch(orgSpawnFlyingComponent<Index>, nodeID, modelID);
}
HOOK_EACH_FUNC(SpawnFlyingComponent, orgSpawnFlyingComponent, &SpawnFlyingComponent_HideWheels);
void Fix_SilentPatch(); void Fix_SilentPatch();
RwFrame* GetTowBarFrame() const; RwFrame* GetTowBarFrame() const;