Death is a FREEZE, not a collapse -- fall-latch vestige proven; band-effect impact frames

Task #32 (death collapse animation) resolved by decomp evidence -- BT 4.11 has
NO collapse animation; the movementMode 5-8 fall latch (clips 0x1c-0x1f) is an
engine-lineage vestige:
  (1) the clip-table loader FUN_004a80d4 fills slots 0x00-0x1b + 0x20 (bmp
      knockdown) and returns -- slots 0x1c-0x1f are never written;
  (2) mech+0x63c..0x648 appear in NO exported function;
  (3) no fall clip exists in the shipped 27-clip set;
  (4) firing the latch would bind resource id 0 -- a StaticAudioStream -- as
      keyframes.
Authentic death modes are the FREEZE modes (IsDestroyed == mode 2||9), so
UpdateDeathState now settles straight to 9 (was a [T3] mode-5 guess that would
trip the garbage latch in the binary).  The death READ = freeze + dnboom +
ddthsmk smoke plume + destroyed skins + shutdown; the wreck stands.

Also: damage-band effects orient toward the ATTACKER (impact frame) via
lastInflictingID -- which was declared but never written (recon gap); now
maintained by Mech::TakeDamageMessageHandler, unblocking the DamageZone LOD
same-attacker redirect too.

KB corrected + proofs recorded (combat-damage "Death SEQUENCE", open-questions).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 14:50:12 -05:00
co-authored by Claude Fable 5
parent a3d67cc639
commit d9254736ab
4 changed files with 61 additions and 42 deletions
+17 -12
View File
@@ -186,18 +186,23 @@ chain TWICE (the dtor-epilogue rule, [[reconstruction-gotchas]] §7) → a doubl
## Death SEQUENCE reconstruction — the map (2026-07-08)
Full decomp map of the death path. Two tiers:
**EXPORTED (reconstructable) [T1 read]:**
- `Mech::AdvanceLegAnimation` (`FUN_004a5028`) / `AdvanceBodyAnimation` (`FUN_004a5678`) — the **collapse-anim
latch**: `movementMode` (mech+0x40) **5/6/7/8** = the four fall directions → clips **0x1c-0x1f** (via
`SetLegAnimation`/`SetBodyAnimation` = `FUN_004a7fc4`/`FUN_004a800c`), one-shot via `deathAnimationLatched`
(mech+0x650). Already reconstructed (mech2.cpp:550-557/817-822). The active drive path DOES call
`AdvanceBodyAnimation` (mech4.cpp:317) → reachable.
**CONFLICT with the shipped clip inventory (2026-07-08) [T4 until re-read]:** BTL4.RES holds exactly
**27 named clip codes per mech** (`swr wwl wwr wsl wsr wrl wrr rrl rrr rwl rwr bmp bbl bbr bsl bsr sbl
sbr ggl ggr gsl gsr wgl wgr sqd squ trn`, + `*i` inside-skeleton variants) — NO explicit death/fall clip
name, and indexes 0x1c-0x1f (28-31) exceed a 27-entry table unless the table interleaves the i-variants
or carries non-resource entries. The "clips 0x1c-0x1f" claim needs the FUN_004a5028 latch region re-read
against the real StandingAnimation table before the collapse is built (task #32). Candidate authentic
visuals: the `bmp` (knockdown) family or `sqd` (squat/crumple).
- `Mech::AdvanceLegAnimation` (`FUN_004a5028`) / `AdvanceBodyAnimation` (`FUN_004a5678`) — the **fall-anim
latch**: `movementMode` (mech+0x40) **5/6/7/8** = the four fall directions → animation-TABLE slots
**0x1c-0x1f** (`table[i]` at `mech+0x5cc+i*4`; `SetLegAnimation`/`SetBodyAnimation` =
`FUN_004a7fc4`/`FUN_004a800c` @part_012.c:13557/13570), one-shot via `deathAnimationLatched` (mech+0x650).
Already reconstructed (mech2.cpp:550-557/817-822).
**RESOLVED (2026-07-08, task #32): the fall latch is a VESTIGE — BT 4.11 has NO collapse animation.**
[T1] Four convergent proofs: (1) the clip-table loader `FUN_004a80d4` (@part_012.c:13604) fills slots
0x00-0x1b + 0x20 (the `bmp` knockdown) by name and RETURNS — slots 0x1c-0x1f are never written; (2) the
offsets `mech+0x63c..0x648` appear in NO exported function at all; (3) BTL4.RES ships **27 clip codes
per mech** (`swr wwl wwr wsl wsr wrl wrr rrl rrr rwl rwr bmp bbl bbr bsl bsr sbl sbr ggl ggr gsl gsr
wgl wgr sqd squ trn` + `*i` variants) — no death/fall clip; (4) firing the latch would bind the
zero-initialised slot = **resource id 0 = a StaticAudioStream** as keyframes (garbage) — dead code in a
shipped arcade build. The authentic BT death modes are the FREEZE modes: `IsDestroyed()` ==
(`movementMode` 2 || 9), locomotion zeroed by `FUN_004ab1c8`. **The death READ = instant freeze + the
dnboom explosion (psfx 7) + the ddthsmk smoke plume (psfx 1) + destroyed skins + subsystem shutdown —
the wreck stands.** `UpdateDeathState` (mech4.cpp) settles straight to 9 (never 5-8, which would trip
the garbage latch). If period pod footage ever shows a mech falling, that's NEW evidence — reopen then.
- `Mech::IsDestroyed()` (`FUN_0049fb54`) = `movementMode==2||9` (reconstructed as `IsDisabled`, btstubs.cpp);
`FUN_004ab1c8` freezes locomotion (zeros mech+0x298) when destroyed.
- **`MechDeathHandler`** (ctor `FUN_0042a984` + Performance `FUN_0042aa2c`, cached mech+0x850 / `mech[0x214]`) —
+5 -3
View File
@@ -107,9 +107,11 @@ authentic path scoped.
Full map + citations in [[combat-damage]] "Death SEQUENCE". ✅ (b) `MechDeathHandler` DONE (mechdmg.cpp) +
✅ the render-side **RemakeEntity** destroyed-mesh swap DONE 2026-07-08 (btl4vid.cpp
`RemakeEntityRenderables` + `BTRemakeMechModel` bridge; in-place `SetDrawObj` swap — the tree dtor does
NOT cascade so never rebuild). **Remaining**: (a) the visible **collapse ANIMATION** latch
through the active path (+ spawned mechs don't advance body anim); (c) the whole-mech **DeathSplash**
radius damage. Do NOT issue DestroyEntityMessage on death.
NOT cascade so never rebuild). ✅ (a) **RESOLVED — no collapse animation exists in BT 4.11** [T1]: the
fall latch (modes 5-8 → table slots 0x1c-0x1f) is a vestige — no loader fills the slots, no fall clip
ships, and firing it would bind resource 0 (an AUDIO stream) as keyframes. Authentic death = FREEZE
(mode 9) + dnboom + ddthsmk plume + destroyed skins ([[combat-damage]] "Death SEQUENCE" for the proofs).
**Remaining**: (c) the whole-mech **DeathSplash** radius damage. Do NOT issue DestroyEntityMessage on death.
- **Critical-subsystem plugs UNBOUND (43 skips/mech) [T3].** `MechCriticalSubsystem::subsystemPlug`
never gets WIRED to its live subsystem (the ctor's Resolve() at mechdmg.cpp:276 only READS; the
binding write is elsewhere/unreconstructed), so `SendSubsystemDamage` skips every entry via the
+17 -17
View File
@@ -950,11 +950,20 @@ void
if (movementMode == 9) // already settled (disabled/frozen)
return;
if (movementMode < 5 || movementMode > 8) // FIRST destroyed frame
{
// Collapse: a fall movementMode fires the one-shot death clip via
// AdvanceBodyAnimation's latch (fall DIRECTION 5-8 is un-exported -> 5).
movementMode = 5; // [T3] direction not determinable from the export
//
// DEATH = FREEZE, not collapse (decomp-verified 2026-07-08, task #32).
// The fall modes 5-8 latch leg/body clips from animation-table slots
// 0x1c-0x1f (FUN_004a5028) -- but NO loader anywhere in the binary fills
// those slots (mech+0x63c..0x648 appear in no exported function; the table
// loader FUN_004a80d4 stops at the knockdown slot 0x20), NO fall clip
// exists in the shipped 27-clip set, and firing the latch would bind
// resource id 0 -- a StaticAudioStream -- as keyframes (garbage). The
// fall modes are engine-lineage vestiges; BT's death modes are the FREEZE
// modes: IsDestroyed() == (movementMode 2 || 9), and FUN_004ab1c8 zeroes
// locomotion for them. So: shut the subsystems down and settle straight
// to 9 (disabled/frozen wreck) -- never 5-8. The death READ comes from
// the effect layer (dnboom + the ddthsmk plume) + the destroyed skins.
//
// RP VTV::DeathShutdown analog: shut every subsystem down. The base
// Subsystem::DeathShutdown is an empty virtual (SUBSYSTM.h); overrides
// act. This is a SHUTDOWN, not teardown -- it frees nothing and never
@@ -965,20 +974,11 @@ void
if (s != 0)
s->DeathShutdown(1);
}
movementMode = 9; // disabled: IsDisabled() true, locomotion frozen
if (getenv("BT_DEATH_LOG"))
DEBUG_STREAM << "[death] mech " << GetEntityID()
<< " destroyed -> collapse + subsystem shutdown (wreck stays)\n" << std::flush;
}
else // SECOND frame (movementMode 5-8): settle to disabled
{
// The collapse clip (latched frame 1 if the anim path ran) plays out via
// the controller after this; movementMode 9 => IsDisabled => locomotion
// frozen regardless of whether the clip latched.
movementMode = 9;
if (getenv("BT_DEATH_LOG"))
DEBUG_STREAM << "[death] mech " << GetEntityID()
<< " settled -> disabled (IsDisabled=" << (int)IsDisabled() << ", frozen wreck)\n" << std::flush;
}
<< " destroyed -> subsystem shutdown + frozen wreck (IsDisabled="
<< (int)IsDisabled() << ")\n" << std::flush;
}
void
+12
View File
@@ -0,0 +1,12 @@
import struct
data = open(r'C:\git\bt411\content\BTL4.RES', 'rb').read()
labOnly, maxID = struct.unpack_from('<ii', data, 4)
offs = struct.unpack_from('<%dI' % maxID, data, 12)
print('maxID', maxID, 'first slots:', offs[:6])
for i, o in enumerate(offs[:8]):
if o == 0:
print('slot', i, 'EMPTY')
continue
rid, rt = struct.unpack_from('<ii', data, o)
nm = data[o + 8:o + 40].split(b'\0')[0].decode('ascii', 'replace')
print('slot %d -> id=%d type=%d name=%r' % (i, rid, rt, nm))