Gauges: the CLOSEOUT wave -- radar pips, Myomers dedup, attribute parity, ledger sweep (tasks #14-#17)

TASK #17 -- AUTHENTIC RADAR SYMBOLOGY (the cross-blip stand-in retired).
The recon proved the 'missing pip raster set' never existed as BT game code:
pips are the ENGINE's L4GaugeImage vector-stroke system (T0 source in tree,
L4GAUIMA.cpp == FUN_0046f0c0 line-for-line), the 'pip table' is L4Warehouse::
gaugeImageBin keyed by Entity::resourceID, and BTL4.RES ships 110 type-0x12
shapes (every mech/vehicle/building/tree).  The six btl4rdr stubs are wired
to the real facilities: contacts draw their authentic model silhouettes with
LOD selection, the target gets the binary's 4px-inflated box highlight, and
player-name labels resolve via Mission::GetSmallNameBitmap (the prebuilt
64x16 egg rasters keyed by the player's bitmapindex).  DECODED: the invented
'VideoObject' was Entity::owningPlayer all along (+0x190; nameID =
playerBitmapIndex@0x1E0, target = BTPlayer::objectiveMech@0x284 -- new
bridge BTPlayerObjectiveMechOf); the 'LabelledEntity' class is Landmark
(cultural.h; label path dormant -- no landmark content ships, no runtime
landmarkID writer).  The L4GREND BT_DEV_GAUGES warehouse guard is removed
(its AV had a different culprit, below); resource type 18 corrected to
GaugeImageStream in decomp-reference (was mislabeled 'ModelList').

TASK #14 -- the Myomers ODR duplicate ELIMINATED: the powersub.cpp/hpp
'Myomers' (classID 0xBC3 -- actually Sensor) is retired whole; it duplicated
?DefaultData@Myomers@@ against the real class (dumpbin-verified) and /FORCE
picked the winner by link order.  The real Myomers (0xBC6) now chains
PoweredSubsystem's handler set (ids 4-8) and publishes its SEVEN binary
attributes (@00511588: SpeedEffect/Current/Recommended/Min/MaxSeekVoltage-
Index/SeekVoltage/OutputVoltage) -- the old empty unchained index starved
the Myomer engineering panel of every resolve.

TASK #16 -- attribute parity: MechWeapon publishes the FULL binary table
@0x511890 (11 entries; ids renumbered to binary truth -- the port aliases
had squatted the binary's DistanceToTarget/TargetWithinRange ids; the
streamed TriggerState 0x13 binding unchanged).  Binary names resolved two
TODO members: pipState -> estimatedReadyTime (attr 0x1A), and the EXT-model
flag is the binary's RearFiring (0x1B).  ThermalSight LightState published.
HUD (offset conflicts) + missile-side tables (id encoding suspect)
documented for a re-dump instead of publishing blind.
  THE CRASH THIS EXPOSED [T2, cdb-verified]: gotcha #11's dense-table gap
is a LATENT AV, not a guaranteed one -- the old table's 0x0D..0x12 gap
(task #5) survived on heap luck; the renumber reshuffled allocations and
Find() AV'd on a garbage entryName in WeaponCluster's PercentDone resolve.
Fixed with five named PAD entries (the mech.cpp attrPad idiom) + a
static_assert locking the pad base to PoweredSubsystem::NextAttributeID.
Gotcha #11 amended with the proof.

TASK #15 -- stale-ledger sweep: GAUGE_COMPOSITE ('composite not yet built',
Reservoir shadow, PlayerStatus/vehicleSubSystems 'remaining', valve-dormant-
until-0xBD3, sensor guard, the superseded 'Heat MFD near-static' reframe --
all banner-corrected), gauges-hud frontmatter, L4VB16 + powersub comments.

Verified live: 50/50 config attribute bindings resolve, 0 NULLs, 0 parse
skips, mech spawns and simulates 31/31 subsystems, no cross-blip fallbacks,
the pip cache fills through entity registration without the old guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-12 00:57:45 -05:00
co-authored by Claude Fable 5
parent 80cadc98c7
commit dd27238ceb
16 changed files with 309 additions and 384 deletions
+14 -163
View File
@@ -849,171 +849,19 @@ int
//###########################################################################
//###########################################################################
// Myomers
// (Myomers mislabel -- RETIRED, task #14)
//###########################################################################
//###########################################################################
//#############################################################################
// Shared Data Support
//
Myomers::SharedData
Myomers::DefaultData(
Myomers::GetClassDerivations(),
Myomers::GetMessageHandlers(),
Myomers::GetAttributeIndex(),
Myomers::StateCount
);
Derivation*
Myomers::GetClassDerivations()
{
static Derivation classDerivations(PoweredSubsystem::GetClassDerivations(), "Myomers");
return &classDerivations;
}
// The "Myomers" block that lived here (ctor @4b1d18, classID 0xBC3,
// outputVoltage/powered/voltageAvailable) was a MISLABEL of Sensor (real
// reconstruction: sensor.cpp). Its Myomers::DefaultData / ctor / dtor /
// TestInstance / MyomersSimulation / ResetToInitialState / HandleMessage /
// CreateStreamedSubsystem definitions ODR-DUPLICATED the REAL Myomers
// (myomers.cpp, classID 0xBC6) -- /FORCE picked the winner by link order,
// so which SharedData live Myomers instances got was link-order-dependent
// (the same archetype as the fixed Condenser stub dedup). Retired whole.
//
// @004b1d18 -- master myomer bundle registers a separate Performance and a
// status-flag bit (0x8); copies skip the live simulation.
//
Myomers::Myomers(
Mech *owner,
int subsystem_ID,
SubsystemResource *subsystem_resource,
SharedData &shared_data
):
PoweredSubsystem(owner, subsystem_ID, subsystem_resource, /*shared_data=*/DefaultData) // FUN_004b0f74(..,&DAT_0050fa1c,0,0)
{
outputVoltage = 1.0f; // this[0xc7]
powered = 0; // this[0xc8]
voltageAvailable = 0; // this[0xc9]
simulationFlags |= 0x8; // this[0xa] |= 8
if ((subsystem_resource->subsystemFlags & SegmentCopyMask) != 4) // (flags & 0xC) != 4
{
SetPerformance((Performance)&Myomers::MyomersSimulation); // PTR @0050fa94
}
}
//
// @004b1d90
//
Myomers::~Myomers()
{
Check(this);
BT_ClearMyomers((Mech *)owner); // *(this[0x34]+0x374) = 0
Check_Fpu();
}
Logical Myomers::TestClass(Mech &) { return True; }
Logical Myomers::TestInstance() const // @004b1e18
{
return IsDerivedFrom(*GetClassDerivations()); // FUN_0041a1a4(..,0x50fa2c)
}
//
// @004b1c4c -- compute the actuator drive voltage available to the locomotion
// model from the powering generator, throttled by heat damage and gated by
// the electrical state.
//
void
Myomers::MyomersSimulation(Scalar time_slice)
{
PoweredSubsystem::PoweredSubsystemSimulation(time_slice); // FUN_004b0bd0
Generator *source = (Generator *)voltageSource.Resolve(); // this[0x38] linked source
outputVoltage = RatedVoltageRef - source->MeasuredVoltage(); // 1.0 - *(source+0x158)
if (simulationState == 1) // this[0x10] @0x40
{
outputVoltage = 0.0f;
powered = 0;
}
else
{
powered = 1;
}
if (electricalStateAlarm.GetLevel() == Ready) // this[0x9e] == 4
{
voltageAvailable = 0;
}
else
{
voltageAvailable = 1;
outputVoltage = 0.0f;
}
//
// Heat damage (HeatSink heat-state @0x184) throttles the drive.
//
switch (heatAlarm.GetLevel()) // this+0x184 (heat-state inside heatAlarm@0x170+0x14)
{
case HeatSink::NormalHeat: // 0
powered = 1;
break;
case HeatSink::DegradationHeat: // 1
outputVoltage *= DegradedDriveScale; // *= 0.5
powered = 1;
break;
case HeatSink::FailureHeat: // 2
outputVoltage = 0.0f;
powered = 0;
break;
}
}
//
// @004b1c18 -- reset clears the myomer output state, then chains to the base.
//
void
Myomers::ResetToInitialState(Logical powered_flag)
{
if (powered_flag)
{
outputVoltage = 1.0f; // this[0xc7]
powered = 0; // this[0xc8]
voltageAvailable = 0; // this[0xc9]
}
PoweredSubsystem::ResetToInitialState(powered_flag); // FUN_004b0e6c
}
//
// @004b1bfc -- straight delegation to the base.
//
Logical
Myomers::HandleMessage(int message)
{
return PoweredSubsystem::HandleMessage(message); // FUN_004b0efc
}
//
// @004b1dcc -- no extra resource fields; just tags the record as Myomers.
//
int
Myomers::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
const ResourceDirectories *directories,
int passes
)
{
if (
!PoweredSubsystem::CreateStreamedSubsystem( // FUN_004b13ac
model_file, model_name, subsystem_name,
subsystem_resource, subsystem_file, directories, passes
)
)
{
return False;
}
subsystem_resource->subsystemModelSize = 0x190;
subsystem_resource->classID = RegisteredClass::MyomersClassID; // 0x0bc3, resource+0x20
return True;
}
//###########################################################################
//###########################################################################
@@ -1509,8 +1357,11 @@ Subsystem *CreatePoweredSubsystem(Mech *owner, int id, void *seg)
// Bridge for the vehicleSubSystems gauge factory (btl4gau2.cpp). The engineering-
// screen assignment lives on PoweredSubsystem (auxScreenNumber / auxScreenPlacement
// / auxScreenLabel, resource +0x104/+0x108/+0x10C). Reading it from btl4gau2.cpp
// via a raw offset (sub+0x1dc) is wrong because the reconstructed heat-leaf branch
// is not byte-exact -- so the gauge factory calls this bridge, which casts through
// via a raw offset (sub+0x1dc) is wrong because raw offsets on our compiled
// objects are the databinding trap (2026-07-12: the "heat-leaf not byte-exact"
// wording is stale -- the leaf IS byte-exact since the sensor re-base,
// sensor.cpp:407-413 -- but the bridge stays: named members are the rule)
// -- so the gauge factory calls this bridge, which casts through
// the real PoweredSubsystem type and returns the NAMED fields. Returns False for
// non-PoweredSubsystem-derived subsystems (== the FUN_0041a1a4 / 0x50f4bc type
// filter the vehicleSubSystems Make applies before dispatch).