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
@@ -843,6 +843,36 @@ static void
|
||||
}
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// MechDeathHandler effect-spawn bridge (mechdmg.cpp calls this)
|
||||
//
|
||||
// Spawns a damage-state descriptor's explosion at the mech. The authentic path
|
||||
// (FUN_0043663c -> FUN_004364e4) broadcasts a class-5 message to the effect
|
||||
// manager app+0x38 (the 0xBD3 SubsystemMessageManager, unreconstructed); we use
|
||||
// the same established Explosion::Make port the weapon path uses. The binary
|
||||
// derives the position from the subsystem (mech+0x184); we use the mech origin.
|
||||
//###########################################################################
|
||||
void
|
||||
BTSpawnDamageEffect(Mech *mech, int effect_resource)
|
||||
{
|
||||
if (mech == 0)
|
||||
return;
|
||||
ResourceDescription::ResourceID res = (ResourceDescription::ResourceID)effect_resource;
|
||||
if (res <= 0)
|
||||
res = gExplodeRes; // fall back to the resolved generic explosion
|
||||
if (res <= 0)
|
||||
return; // nothing to spawn yet
|
||||
Origin o = mech->localOrigin; // at the mech (binary: per-subsystem)
|
||||
Explosion::MakeMessage m(
|
||||
Explosion::MakeMessageID, sizeof(Explosion::MakeMessage),
|
||||
(Entity::ClassID)RegisteredClass::ExplosionClassID, EntityID::Null,
|
||||
res, Explosion::DefaultFlags, o,
|
||||
mech->GetEntityID(), mech->GetEntityID());
|
||||
Explosion *e = Explosion::Make(&m);
|
||||
if (e)
|
||||
Register_Object(e);
|
||||
}
|
||||
|
||||
//###########################################################################
|
||||
// Death sequence -- the un-exported master-perf death branch (region
|
||||
// 0x4a9770-0x4ab188), reconstructed from its EXPORTED consumers + the RP
|
||||
@@ -920,6 +950,13 @@ void
|
||||
// dead mech keeps its death state instead of reverting to a live gait.
|
||||
UpdateDeathState();
|
||||
|
||||
// MechDeathHandler (@0042aa2c): per-frame destroyed-skin + explosion effects as
|
||||
// this mech's zones cross damage thresholds. The binary ticks it off the mech's
|
||||
// Performance list (mech+0xbc), which the bring-up drive override bypasses, so
|
||||
// it is driven here. Runs for EVERY mech (so the enemy visibly falls apart too).
|
||||
if (deathHandler != 0)
|
||||
((MechDeathHandler *)deathHandler)->Tick();
|
||||
|
||||
// WAVE 7 Phase B: advance/render/impact the flying projectiles once per frame (viewpoint).
|
||||
if (isPlayerMech && dt > 0.0001f)
|
||||
BTUpdateProjectiles(dt);
|
||||
|
||||
Reference in New Issue
Block a user