myomer damage reaches the wheels, legs gimp at half structure, reverse refuses -- and an ODR trap unmasked (#75/#78)
The speed-demand site (MechControlsMapper::InterpretControls) now applies the
drive scale the mover's feed roster applied in 1995: speedDemand multiplies by
the myomers' live speedEffect (gear ratio, thermal curve, 1 - zone damage, via
the BTMyomersDriveOf bridge) and, while GIMPED, by 0.5 [T3: VGL Lynx's
"roughly 50%", BT_GIMP_SPEED overrides]. The gimp states were already being
raised -- mechdmg sets graphicAlarm 3 (left) / 4 (right) when a LegDamageZone-
flagged zone crosses half structure -- but nothing downstream ever saw them.
While gimped, reverse input is refused ("reverse disabled"), matching the
old-timers' account; the pod's audio cue rides the alarm's watchers.
Bench, one trajectory, arithmetically exact: a deterministic right-leg ramp
(the new BT_SELF_DAMAGE_ZONE harness) crosses 0.5 and the demand goes
44.837 -> 6.726 = 44.837 x 0.5 (gimp) x 0.3 (a crit-chewed myomers from the
same ramp -- the #80 crits composing with #75's scale, unprompted).
The reason "nothing downstream ever saw them" is the real find of the night,
now gotcha #23: AlarmIndicator is typedef'd to DIFFERENT TYPES per header
family -- mech.hpp says ReconAlarm (4 bytes), heat.hpp says GaugeAlarm (0x54)
-- so Mech::graphicAlarm and EVERY member after it sit at different offsets
depending on a TU's include order. mechdmg wrote level 4 and read it back;
mechmppr read 0 from the same object, same expression. No compiler error can
catch it: each TU only ever sees one definition. Until the split is audited,
cross-TU reads of the gimp level go through BTMechGimpLevel (compiled in
mechdmg's TU) -- and the same split-brain explains why the port carries the
binary's ONE movementMode cell as two live members (engine simulationState vs
graphicAlarm level) that never meet.
Also landed en route: the Myomers un-powered self-repair observed healing in
the field logs at exactly 0.011 x the authored Explosive scale per tick --
the 2026-07-29 reversal confirmed live; and Mech message 0x15 "RealMaxSpeed"
raw-decoded (@0x49f604: sets mech+0x7a0 from the message unless the +0x7a4
latch holds -- a console-tunable top speed).
Open on #78, documented in locomotion.md: the Gimp animation clips (authored
keys in the binary's model-record parser; mech2's state enum vs mech3's
reverse-fix disagree about slots 0x12-0x17 -- reconcile before wiring) and
the audio-cue binding.
Diags: BT_SELF_DAMAGE_ZONE, BT_DRIVE_LOG, BT_GIMP_SPEED.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
8a99972f22
commit
520f6eecd3
@@ -469,6 +469,13 @@ void
|
||||
}
|
||||
else if (mech->IsDisabled() == 0) // FUN_0049fb54 (NOT disabled)
|
||||
{
|
||||
if (getenv("BT_DMG_LOG") && (leftLeg || rightLeg))
|
||||
DEBUG_STREAM << "[gimp-eval] zone=" << damageZoneIndex
|
||||
<< " L=" << (int)leftLeg << " R=" << (int)rightLeg
|
||||
<< " lvl=" << damageLevel
|
||||
<< " half=" << (int)(damageLevel >= LegHalfStructure)
|
||||
<< " alarmBefore=" << (int)mech->graphicAlarm.GetLevel()
|
||||
<< "\n" << std::flush;
|
||||
// A live (non-disabled) mech: a half-destroyed leg zone trips the
|
||||
// partial-failure graphic (right -> 4, left -> 3). The oracle
|
||||
// compares against _DAT_0049c9a0 (0.5), NOT StructureMax. task #60:
|
||||
@@ -586,6 +593,22 @@ void
|
||||
// incomplete Mech; this TU already writes graphicAlarm level 9 for the
|
||||
// leg-destruction path, so the vital path reuses the same complete-type site.
|
||||
//
|
||||
//
|
||||
// #78 bridge: the gimp level, read in THIS TU. The mapper's direct
|
||||
// `mech->graphicAlarm.GetLevel()` read 0 while this TU's read of the same
|
||||
// object returned 4 -- AlarmIndicator is typedef'd to DIFFERENT TYPES per
|
||||
// header family (mech.hpp: ReconAlarm, 4 bytes; heat.hpp: GaugeAlarm, 0x54),
|
||||
// so Mech's layout past graphicAlarm diverges between TU families. Until
|
||||
// that typedef split is audited and unified, every cross-TU read of the
|
||||
// alarm goes through here.
|
||||
//
|
||||
int BTMechGimpLevel(void *mech_v)
|
||||
{
|
||||
if (mech_v == 0)
|
||||
return 0;
|
||||
return (int)((Mech *)mech_v)->graphicAlarm.GetLevel();
|
||||
}
|
||||
|
||||
void BTMechVitalSubsystemKill(void *owner_mech)
|
||||
{
|
||||
if (owner_mech != 0)
|
||||
|
||||
Reference in New Issue
Block a user