subsystems: un-stub Wave 4 readouts + Wave 6 Myomers (10->15 factory cases)

WAVE 4 (standalone readouts) -- Sensor(0xBC3)/Searchlight(0xBD8)/
ThermalSight(0xBDE)/AmmoBin(0xBCB) un-stubbed via Create<Class>Subsystem
bridges + Torso-style de-shim (drop cross-family shadow fields, redirect
accessors to the real inherited base, static_assert layout locks).
- FIX: Searchlight/ThermalSight ctors gated their Performance on the shadow
  segmentFlags(=0) so it NEVER installed; switched to owner->simulationFlags.
- AmmoBin: retype ammoAlarm HeatAlarm->WatcherGaugeAlarm(0x54) + drop the
  statusState@0x40 shadow -> exact 0x22C layout.
- Guard HeatWatcher::WatchSimulation against the unresolved watchedLink
  (null-deref exposed once these sims run; faithful fix = resolve the link).
- Heat-leaf branch (Sensor) is not byte-exact -> overflow-lock only.

WAVE 6 (Myomers 0xBC6, mover-coupled) -- structural un-stub, gated
BT_MYOMERS (default on; =0 -> Actuator stub). Wired INERT: MyomersSimulation
early-returns (advanced-damage gate stubbed) + no-op mover feed, so the live
JointedMover is untouched and the gait cannot regress. De-shim drops the
owner*/segmentFlags shims to fit the exact-0x358 alloc. Authentic mover/heat
coupling deferred (needs messmgr 0xBD3 + reconciling the mover feed with the
gait cutover).

Verified: BLH tick 20->27, Mad Cat 24, combat DESTROYED un-regressed,
locomotion un-regressed, 0 crashes, 0 heap detections under BT_HEAPCHECK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-05 23:01:31 -05:00
co-authored by Claude Opus 4.8
parent 5aa791b245
commit 8b36440d05
14 changed files with 421 additions and 141 deletions
+36 -6
View File
@@ -136,12 +136,8 @@ Sensor::Sensor(
Check(owner);
Check_Pointer(subsystem_resource);
segmentFlags = 0;
hasActivePerformance = False;
heatStateLevel = NormalHeat;
heatModelOff = False;
electricalState = Ready;
// (WAVE 4 de-shim) the 5 cross-family shim fields are gone; the accessors
// now read the inherited base state directly. Only the 3 own fields init here.
radarPercent = RadarBaseline; // @0x31C = 1.0f
selfTest = False; // @0x320 = 0
badVoltage = False; // @0x324 = 0
@@ -363,3 +359,37 @@ int
Check_Fpu();
return True;
}
//===========================================================================//
// WAVE 4 -- compile-time OVERFLOW lock (the property that matters for the
// placement-new into the 0x328 factory alloc).
// NOTE: the reconstructed HEAT-LEAF base chain (PoweredSubsystem : HeatSink :
// HeatableSubsystem) is NOT byte-exact to the binary (unlike the re-based
// WATCHER branch Torso sits on), so radarPercent does NOT land at the binary's
// 0x31C. That is fine here: SensorSimulation reads every field through NAMED
// members (compiled-consistent), and NOTHING reads Sensor at a raw binary
// offset yet. The one raw-offset consumer is the attribute table
// (RadarPercent -> 0x31C), used only by the (un-drawn) cockpit gauge -- so the
// exact-offset re-base of the heat-leaf branch is a Phase-4 HUD follow-up.
// Until then, no-overflow (sizeof <= alloc) is the correct, sufficient lock.
//===========================================================================//
struct SensorLayoutCheck
{
static_assert(sizeof(Sensor) <= 0x328, "sizeof(Sensor) must fit the factory Memory::Allocate(0x328)");
};
//===========================================================================//
// WAVE 4 factory bridge -- Sensor (factory case 0xBC3, "Myomers" mislabel).
// The real class at 0xBC3 (ctor @004b1d18) is Sensor (string pool @0050fae0 +
// surviving SENSOR.HPP); MyomersClassID is a factory-enum mislabel (the real
// Myomers is 0xBC6/@4b8fec). Object is 0x328 == the factory alloc (zero
// headroom; locked by SensorLayoutCheck above). Sensor's ctor is 3-arg
// (DefaultData applied internally) -- no shared_data argument.
//===========================================================================//
Subsystem *CreateSensorSubsystem(Mech *owner, int id, void *seg)
{
return (Subsystem *) new (Memory::Allocate(0x328))
Sensor(owner, id, (Sensor::SubsystemResource *)seg);
}