torso twist died after a respawn: Myomers ran the inner integrator, never the wrapper
Gitea #70. Torso twist intermittently stops working after a death/respawn and stays stopped, with the generator at a full 10000V and the voltage link resolving fine. A stale state, not a live one. The Torso is a PowerWatcher that mirrors the electrical level of the subsystem it watches -- for the MadCat that is roster slot 15, Myomers -- and torso.cpp:570 holds effectiveTwistRate at 0 whenever that mirrored level is not Ready. So the question was never about the torso. It was: why does Myomers sit at NoVoltage forever? Because it never ran the state machine that would walk it back. The Myomers ctor @004b8fec stores [0x511620] into activePerformance, and that pointer resolves to 0x4b8b9c -- whose first instruction is `call 0x4b0bd0`, which is PoweredSubsystem::PoweredSubsystemSimulation. @004b8d18, the function this port had registered, is the INNER drive-heat integrator that wrapper goes on to run. We registered the inside of the onion. PoweredSubsystemSimulation is the only code that both enters NoVoltage (source == 0) and leaves it (NoVoltage -> Starting -> Ready), so a Myomers that lost power during the death/reset window had no way back out. Order is load-bearing: the base call precedes the heat-model gate in the binary. Gating first -- as this did -- also denied the electrical machine to every non-expert pilot, since OwnerAdvancedDamage() reads the +0x260 heat-model flag and that is off below veteran. Measured with BT_SELF_DAMAGE + BT_TORSO_LOG, before and after: pristine, before 48/48 Ready after 38/38 Ready post-respawn 95/97 Ready 89/89 Ready Two dead windows per respawn, now none, and the clean case stays clean. The wrapper has a tail this does not yet reconstruct: @004b8bb9-0x4b8c1e runs an effect when electricalStateAlarm == 1 and the myomer's damage zone is below 1.0, building a small vector (const 0xbc343958, about -0.011f) against the owner's localOrigin@0x100. Almost certainly the un-powered movement penalty. Flagged in the KB as T4 rather than guessed at. Worth generalizing, and noted as such in context/subsystems.md: when a subsystem's Performance address in a PTR_LAB_* slot does not match the function we reconstructed, suspect a wrapper that chains the base sim. The whole family does it -- Generator and PoweredSubsystem both lead with HeatSink::HeatSinkSimulation, and the Torso's own perf @004b5cf0 leads with UpdateWatch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c5537a1247
commit
b70654dd11
@@ -67,6 +67,26 @@ Making a base byte-exact GROWS every subclass — they must be re-based TOGETHER
|
||||
- **WAVE 5** — Torso (aim twist/elevation; joint-I/O reconstructed; the BLH record disables torso →
|
||||
faithfully no visible twist).
|
||||
- **WAVE 6** — Myomers (mover-coupled; structural un-stub is INERT — no live mover/heat coupling).
|
||||
⚠ **The registered Performance is the WRAPPER @004b8b9c, not the inner integrator @004b8d18**
|
||||
[T1, fixed 2026-07-28]. The ctor @004b8fec stores `[0x511620]` into activePerformance, and that
|
||||
pointer resolves to `0x4b8b9c`, whose first instruction is `call 0x4b0bd0` =
|
||||
`PoweredSubsystem::PoweredSubsystemSimulation`; @004b8d18 is the drive-heat integrator it then
|
||||
runs. The port had registered the INNER function, so Myomers never advanced its own electrical
|
||||
state machine — and since that machine is the only thing that both enters `NoVoltage`
|
||||
(`source == 0`) and walks it back (`NoVoltage → Starting → Ready`), a Myomers that lost power in
|
||||
the death/reset window stayed there **forever**. The Torso is a PowerWatcher that MIRRORS its
|
||||
watched subsystem, so `torso.cpp:570` held `effectiveTwistRate` at 0 = **Gitea #70, "torso twist
|
||||
stops working after a death/respawn."** Measured: 2 dead windows per respawn before, 0 after;
|
||||
pristine missions never showed it. **Order is load-bearing** — the base call precedes the
|
||||
heat-model gate, and gating first also denied the electrical machine to every non-expert pilot
|
||||
(`OwnerAdvancedDamage()` is the +0x260 flag, off below veteran).
|
||||
**General rule this establishes:** when a subsystem's Performance address in a `PTR_LAB_*` slot
|
||||
does not match the function you reconstructed, check whether the real target is a wrapper that
|
||||
chains the base sim — the whole family does (`Generator`/`PoweredSubsystem` lead with
|
||||
`HeatSink::HeatSinkSimulation`; the Torso's own perf @004b5cf0 leads with `UpdateWatch`).
|
||||
Still unreconstructed [T4]: @004b8bb9-0x4b8c1e, an effect when `electricalStateAlarm == 1` and the
|
||||
myomer's damage zone is < 1.0, building a small vector (const `0xbc343958` ≈ -0.011f) against the
|
||||
owner's `localOrigin@0x100` — almost certainly the un-powered movement penalty.
|
||||
- **WAVE 7** — projectile/missile weapons (byte-exact; flying projectiles are a PORT reconstruction —
|
||||
the 2007 Entity is 0x1BC vs the binary's 0x300, so raw base-offset reads fail).
|
||||
- **TASK #56 (2026-07-11)** — Gyroscope LIVE byte-exact (ctor @004b3778, sizeof 0x3D0 locked;
|
||||
|
||||
Reference in New Issue
Block a user