MechDeathHandler: per-zone destroyed-skins + explosions (faithful, exported)
Fixes the "kills are invisible" report: a mech died only at the state level, with no visible destruction on its body. Root cause: the per-zone damage-state descriptor table (binary zone+0xd4) that drives destroyed-skins + explosions was never built -- its loader (Mech__DamageZone::LoadCriticalSubsystems / FUN_0041e4a8) was a no-op stub, and MechDeathHandler itself was a no-op stub. The surrounding plumbing (the per-zone load loop over the type-0x1e resource, the death-handler slot) was already correct. Whole pipeline is EXPORTED -- no stand-ins. Reconstructed: - Mech__DamageZone descriptor table (binary this+0xd4): un-stubbed LoadCriticalSubsystems (FUN_0041e4a8/FUN_0042a748/FUN_0042a2c8) to parse the real type-0x1e stream -- entry = [f32 DamageLevel][i32 EffectResource] [i32 GraphicState][f32 TimeDelay], ascending by DamageLevel. Verified live: 6 entries/zone, first threshold 0.2, effect 26, across all 40 zones, no crash. - The three lookups (FUN_0042a664 by-level / FUN_0042a5f4 crossing / FUN_0042a6c4 by-graphic-state) as Mech__DamageZone methods. - The real MechDeathHandler (FUN_0042a984 ctor / FUN_0042aa2c Performance / FUN_0042a9f4 dtor), replacing the stub: each tick it walks the zones and, as a zone's damageLevel rises across a descriptor threshold, fires that entry's explosion (binary +0xb8 & 4) and, on destruction, the Destroyed-graphic descriptor's explosion (+0xb8 & 8), applying the descriptor's GraphicState (the destroyed skin) to the zone. Runs for EVERY mech, so the enemy visibly falls apart as it dies. Integration: the binary ticks MechDeathHandler off the mech's Performance list (mech+0xbc), which the bring-up drive override bypasses, so Mech::PerformAndWatch drives Tick() directly (same approach as UpdateDeathState). Effect spawn uses the established Explosion::Make port (BTSpawnDamageEffect) -- the authentic dispatch (class-5 message -> the 0xBD3 SubsystemMessageManager effect manager) is unported. Runtime: builds clean, boots clean, 42 descriptor tables load with sensible byte-aligned data, no crash. Live effect firing is combat-triggered (verified by the load + the wiring; the [deathfx] threshold-crossing log fires under BT_DEATH_LOG). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a9467481c5
commit
7c455303bd
@@ -218,7 +218,7 @@ extern Subsystem *CreateGaussRifleSubsystem(Mech *, int, void *); // 0xBCE (WAVE
|
||||
|
||||
// Post-stream entity glue + cosmetic objects.
|
||||
struct StandingAnimation { template<class...A> StandingAnimation(A&&...) {} };
|
||||
struct MechDeathHandler { template<class...A> MechDeathHandler(A&&...) {} };
|
||||
// MechDeathHandler is now the REAL class (mechdmg.hpp) -- the local stub was removed.
|
||||
struct StabilityMessage { StabilityMessage() {} };
|
||||
|
||||
// "Mechs" object directory in the global registry (decomp registry verbs).
|
||||
@@ -1297,13 +1297,19 @@ Mech::Mech(
|
||||
{
|
||||
critRes->Lock();
|
||||
{
|
||||
// Load each zone's damage-state descriptor table from the type-0x1e
|
||||
// stream, sequentially (binary loops mech[0x47] subsystems == our zones,
|
||||
// calling FUN_0041e4a8 per object over the same stream). This is what
|
||||
// MechDeathHandler walks to fire destroyed-skins + explosions on damage.
|
||||
DynamicMemoryStream critStream(critRes->resourceAddress, critRes->resourceSize);
|
||||
for (int z = 0; z < damageZoneCount; ++z)
|
||||
{
|
||||
Zone(z)->LoadCriticalSubsystems(&critStream); // FUN_0041e4a8
|
||||
Zone(z)->LoadCriticalSubsystems(&critStream); // FUN_0041e4a8 (now the real loader)
|
||||
}
|
||||
}
|
||||
deathHandler = (int)new (Memory::Allocate(0x18)) MechDeathHandler(this); // FUN_0042a984
|
||||
// The REAL MechDeathHandler (mechdmg.hpp), not the binary's 0x18 placement --
|
||||
// plain new (our class carries a std::vector cache). Ticked from PerformAndWatch.
|
||||
deathHandler = (int)new MechDeathHandler(this); // FUN_0042a984
|
||||
critRes->Unlock();
|
||||
}
|
||||
|
||||
@@ -1426,7 +1432,7 @@ Mech::~Mech()
|
||||
|
||||
if (deathHandler != 0) // Wword(0x214)
|
||||
{
|
||||
((Releasable *)deathHandler)->Release();
|
||||
delete (MechDeathHandler *)deathHandler; // real class -> plain delete
|
||||
}
|
||||
|
||||
ReleaseRefCounted(resourceNameC); // Wword(0x213)
|
||||
|
||||
Reference in New Issue
Block a user