#47 follow-up: restore the DAMAGE TIER to the heat branch -- HeatableSubsystem::GetStatusFlags was a stub returning 0

Found while auditing today's vtable change before release.  The binary's
HeatSink::GetStatusFlags @004add30 OPENS with `call 0x4ac144` --
MechSubsystem::GetStatusFlags, the damage tier (damageLevel >= 1.0 -> bit 0
Destroyed; > 0 -> bit 1 Damaged).  There is no zero-returning
HeatableSubsystem override anywhere in the image.

Our port routed that call through `HeatableSubsystem::GetStatusFlags()
{ return 0; }` -- a "neutral default" that silently dropped bits 0 and 1 for
the ENTIRE heat branch (every weapon, sensor, emitter, PPC, generator,
powered subsystem).  Two live consequences:

  * Destroyed / Damaged could never reach MechTech's annunciator scan --
    gutting half the shipped mechalrm table (Destroyed -> gotoEngineering +
    engCooling + engBusMode) hours after #47 shipped the flash;
  * PoweredSubsystem's AutoConnect gate (`GetStatusFlags() == 0`,
    powersub.cpp:358) read a DAMAGED subsystem as pristine.

One-line fix: chain the real tier, reproducing @004add30 exactly.  The call
site's own comment already said `// FUN_004ac144` -- the implementation had
simply never matched it.

Also corrected a stale comment on MechSubsystem::GetStatusFlags that read the
field as a STRUCTURE level ("1.0 = intact, 0 = dead") -- backwards.  The
engine member is damageLevel and ACCUMULATES to 1.0 = destroyed (mechdmg's
crit cascade tests `level >= StructureMax` for exactly that), which is what
makes bits 0/1 line up with TechStatusType Destroyed/Damaged.  Behaviour was
always right; the comment was a leftover of the same structureLevel misreading
#46 retired.

VERIFIED (3-pod combat sim, BT_LAMP_LOG): the annunciator is genuinely live --
Jammed x7, AmmoBurning x5, BadPower x20, Overheating x207 (Overheating
correctly maps to NO lamp: the shipped table has no entry for it).  The lamp
resolution is per-subsystem as designed -- different weapons flash their own
panel buttons (lamps 0xf/0x5/0xb/0x3 under distinct mode masks), 32 flash
writes across a whole battle, no thrash.  Zero crashes, zero plane/OOB
tripwire hits across all three pods.

FILED, deliberately NOT fixed tonight (open-questions.md): vtable slot +0x40
is misattributed.  The binary calls it `(this, 0)` in AutoConnect's outer gate
and `(this, candidateGenerator)` in the roster walk -- a one-arg voltage query
(HasVoltage(source)), not GetStatusFlags().  Modelling both as the no-arg
GetStatusFlags makes the outer gate demand "no flags" and the inner "some
flag" with nothing between them, so AutoConnect's loop body can never execute.
Pre-existing before and after this change; it is a live power-bus behaviour
change and deserves its own playtest cycle, not a release-eve patch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-25 17:58:20 -05:00
co-authored by Claude Fable 5
parent 1d31af61d7
commit f3179ef020
3 changed files with 33 additions and 3 deletions
+13
View File
@@ -254,6 +254,19 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR
(the databinding trap). DORMANT in-game (the review context no longer survives the viewpoint
swap -- the #48 teardown fix) but LIVE the moment the mission-review screen actually runs at
round end. Bridge all three through btplayer.cpp accessors before enabling the review screen.
- **`PoweredSubsystem` AutoConnect is DEAD, and vtable slot +0x40 is misattributed
(2026-07-25, found while auditing #47's GetStatusFlags change) [T1 decomp].** The binary
(@004b0bd0 tail) calls slot +0x40 with TWO shapes: `(this, 0)` in the outer gate (require
`== 0`) and `(this, candidateGenerator)` inside the roster walk (require `!= 0`). That is a
ONE-ARG voltage query -- "am I unpowered?" / "would THIS source power me?" -- i.e. the
`HasVoltage(source)` family, **not** `GetStatusFlags()`. powersub.cpp:358/372 model both as
the no-arg `GetStatusFlags()`, so the outer gate demands "no flags at all" while the inner
demands "some flag", and nothing between them can change the value -> **the loop body can
never execute and AutoConnect never attaches anything.** Pre-existing (both before and after
the #47 damage-tier fix); deliberately NOT fixed on release eve because it is a live
power-bus behaviour change that deserves its own playtest cycle. Fix = give slot +0x40 its
real signature (`Logical HasVoltage(Subsystem *source = 0)`), restore the two call shapes,
and verify a mode-Auto subsystem re-attaches after its generator drops.
- **Factory capability-roster loops 2-4 are STILL DEAD (task #57 discovery).** mech.cpp's
post-roster loops add to `heatableSubsystems`(0x51155c)/`weaponRoster`(0x511830)/
`damageableSubsystems`(0x50e4fc) through the local `SubProxy` stub whose `IsDerivedFrom`