#88: coolant leaks LIVE -- the #64 damageZone shadow was the single break

in the leak chain

HeatSink::UpdateCoolant prices the damage-driven leak from the QUALIFIED
engine member (Subsystem::damageZone @0xE0): coolantDraw = zoneDamage *
heatLoad, with the coolantActive hysteresis (= the ReportLeak attribute
the 19 authored leak watchers ride).  But the MechSubsystem ctor only
ever filled its re-declared SHADOW member (gitea #64, gotcha #1), so the
engine member stayed NULL forever, zoneDamage pinned 0, and a coolant
leak was STRUCTURALLY IMPOSSIBLE no matter how much damage landed --
Oracle's night-7 report exactly.  The #80 crit fix and the #83 collision
rattle write real subsystem-zone damage, but into an object the leak
reader could never see.

Fix: alias the ENGINE base member to the same zone in both MechSubsystem
ctors.  Every shadow reader keeps working (same object); the engine base
Subsystem::TakeDamage latent null-AV (#64 consequence 2) is disarmed;
the full #64 de-shadow sweep remains the long-term cleanup.

Verified live (solo, BT_COOL_LOG/BT_CRIT_LOG): collision rattle drove a
damaged Myomers to [cool] draw = dmg*heatLoad with the level draining;
sustained weapon fire rolled real crits ([critroll]) and produced 588
leak-pricing lines.  Authored routing extracted from BTL4.RES: collision
rattle targets HeatSinkBank 0.3 / Gyro 0.35 / Torso 0.25 / Myomers 0.35
(Condenser+Reservoir authored 0 for collisions); weapon crits select via
the zone's crit-entry list.  Known-remaining fidelity item (documented):
HeatSink::DrawCoolant (slot 14, central top-up) is still a return-0 TODO.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Zh7PTkFy4KwTzVighLR9J
This commit is contained in:
Joe DiPrima
2026-07-31 08:26:40 -05:00
co-authored by Claude Fable 5
parent 1570983fde
commit a8a0042f28
3 changed files with 35 additions and 2 deletions
+11
View File
@@ -152,6 +152,16 @@ MechSubsystem::MechSubsystem(
printSimulationState = 0; // this[0x41]
configureActivePress = -1; // this[0x44] configure-session idle
damageZone = (ReconDamageZone *)new DamageZone(this, 0); // this[0x38] = FUN_0041de1c(new 0x160, this, 0)
// #64/#88: ALIAS the ENGINE base member to the same zone. The binary has
// ONE cell (subsystem word 0x38); the port's re-declared shadow left
// Subsystem::damageZone null forever, so every engine-member reader --
// HeatSink::UpdateCoolant's leak feed (`coolantDraw = zoneDamage *
// heatLoad`), the engine base TakeDamage -- saw a pristine/null zone.
// With the crit sink + collision rattle now writing real damage into the
// (same) zone, the null base was the single break in the coolant-leak
// chain. Aliasing (not moving) keeps every shadow reader intact; the
// full #64 de-shadow sweep remains the long-term cleanup.
Subsystem::damageZone = (::DamageZone *)damageZone;
}
//
@@ -190,6 +200,7 @@ MechSubsystem::MechSubsystem(
collisionCriticalHitWeight = subsystem_resource->collisionCriticalHitWeight; // res+0xdc
damageZone = (ReconDamageZone *)new DamageZone(this, 0); // this[0x38]
Subsystem::damageZone = (::DamageZone *)damageZone; // #64/#88 alias -- see the sibling ctor
BindName((char *)damageZone + 0x15c, GetName()); // FUN_00402a98(., dz+0x15c, name)
//