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
@@ -3791,6 +3791,10 @@ void
|
||||
// the authentic MaxAcceleration reads directly since the task #4
|
||||
// record-layout fix (madcat: 30 u/s^2); the old floor-25 block
|
||||
// and its one-shot log are retired.
|
||||
// (#78 note: the gimp states live on graphicAlarm, NOT this
|
||||
// engine simulationState cell -- the port carries the
|
||||
// binary's one mech+0x40 as two members; see the split-brain
|
||||
// note in combat-damage.md. This write never touches them.)
|
||||
if (!IsMechDestroyed()) // a dead mech keeps its death movementMode
|
||||
SetMovementMode(1); // ground, non-death, non-airborne
|
||||
// reverseSpeedMax2@0x7a0 is the run-cycle bodyCycleSpeed CLAMP (AdvanceBody
|
||||
@@ -5614,10 +5618,21 @@ void
|
||||
dmg.damageAmount = (want > 0.0f) ? want : 20.0f;
|
||||
dmg.burstCount = 1;
|
||||
dmg.impactPoint = localOrigin.linearPosition;
|
||||
// BT_SELF_DAMAGE_ZONE=<n>: aim the harness at an explicit zone
|
||||
// (#78 bench: ramp a LEG zone deterministically past the
|
||||
// LegHalfStructure threshold). Unset = -1 = the lottery.
|
||||
int sdZone = -1;
|
||||
{
|
||||
const char *ze = getenv("BT_SELF_DAMAGE_ZONE");
|
||||
if (ze != 0 && *ze != '\0')
|
||||
sdZone = atoi(ze);
|
||||
if (sdZone < -1 || sdZone >= damageZoneCount)
|
||||
sdZone = -1;
|
||||
}
|
||||
Entity::TakeDamageMessage td(
|
||||
Entity::TakeDamageMessageID,
|
||||
sizeof(Entity::TakeDamageMessage),
|
||||
GetEntityID(), -1 /*unaimed -> cylinder table resolves the zone*/, dmg);
|
||||
GetEntityID(), sdZone /*-1 -> cylinder lottery*/, dmg);
|
||||
DEBUG_STREAM << "[selfdmg] " << dmg.damageAmount
|
||||
<< " to own mech (unaimed)" << std::endl << std::flush;
|
||||
Dispatch(&td);
|
||||
|
||||
Reference in New Issue
Block a user