From 2b6b0276fd9162e658aad7f8d27537b0fb0967f7 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Sun, 9 Aug 2026 17:26:27 -0500 Subject: [PATCH] #152: the real hole -- glass/RIO rigs had NO torso-centre control; wire pod button 0x42 The reported "torso no longer recentres on its own" decomposed into two parts: the auto-recentre in Mid/Adv was never authentic (it was the stuck-centerCommand bug acting as a phantom feature since ~674 -- analysis on the ticket, awaiting Oracle's 1995-memory verdict), but underneath it sat a REAL defect: with the phantom gone, a glass/RIO player had no way to recentre the torso at all. WHY. The only centerCommand writer lived inside the desktop key-bridge block, which is OFF whenever a RIO/PadRIO is present -- glass and the pod both. The pod's dedicated CENTER button (0x42, "the shipped .RES name", UP arrow via bindings.txt) reached nothing: benched two scripted 0x42 holds on the RIO path, ctrCmd=0 throughout, twist parked forever. (Keyboard X/NumPad5 recentred only as a side effect of ALL-STOP -- you could not recentre without stopping.) FIX, two pieces, both existing patterns: * L4PADRIO::EmitButton -- the documented single chokepoint every button source funnels through -- publishes the 0x42 HOLD state (gBTTorsoCenterHeld), exactly the 0x3F ReverseThrust precedent. * mechmppr gains ONE unified centerCommand writer, deliberately OUTSIDE the key-bridge gate (the same placement lesson as the mode-cycle hook): hold = torsoCenter(@0x154 databound) OR gBTTorsoCenterHeld(0x42) OR the one-frame X pulse; asserts while held, clears on release. Single writer == the sources can never stomp each other's clear. BENCHED (scratchpad/night14/center42.sh, RIO path, bridge off): before: ctrCmd=0 in all samples across two 0x42 holds; twist parked at 1.478 after: hold -> ctrCmd=1 recen=1, twist slews 2.22->0.44 at the authored 0.87 rad/s; twist input DURING the hold cancels sim-side (authentic); release clears; no button -> aim holds (authentic Std/Vet). Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC --- engine/MUNGA_L4/L4PADRIO.cpp | 12 ++++++++ game/reconstructed/mechmppr.cpp | 50 +++++++++++++++++++++++---------- scratchpad/night14/center42.sh | 26 +++++++++++++++++ 3 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 scratchpad/night14/center42.sh diff --git a/engine/MUNGA_L4/L4PADRIO.cpp b/engine/MUNGA_L4/L4PADRIO.cpp index 3acf1a2..e315942 100644 --- a/engine/MUNGA_L4/L4PADRIO.cpp +++ b/engine/MUNGA_L4/L4PADRIO.cpp @@ -36,6 +36,7 @@ int gBTPadViewToggleEdges = 0; // desktop bridge, which owns `reverseThrust` (mapper attr 6 @0x124) every frame. // int gBTReverseHeld = 0; +int gBTTorsoCenterHeld = 0; // button 0x42 hold (#152; same seam as 0x3F) // // The desktop per-MFD preset-page cycle edges (J/K/L -> Mfd1/2/3), consumed @@ -458,6 +459,17 @@ void // via SetScreenButton), so the desktop bridge can honour the button exactly // like the pod's RIO board did. // + // TORSO CENTER (pod button 0x42, 'the shipped .RES name' -- UP arrow via + // bindings.txt). Same chokepoint pattern as 0x3F below: publish the HOLD + // state so the mapper's unified recenter writer (#152) can honour it on + // every rig. Before this, no RIO/glass path reached centerCommand at all + // -- bench: two scripted 0x42 holds, ctrCmd=0 throughout. + if (address == 0x42) + { + extern int gBTTorsoCenterHeld; + gBTTorsoCenterHeld = pressed ? 1 : 0; + } + if (address == 0x3F) { gBTReverseHeld = pressed ? 1 : 0; diff --git a/game/reconstructed/mechmppr.cpp b/game/reconstructed/mechmppr.cpp index 2337b93..899d7c9 100644 --- a/game/reconstructed/mechmppr.cpp +++ b/game/reconstructed/mechmppr.cpp @@ -727,6 +727,35 @@ void CycleControlModeNow(); } } + // (#152) TORSO-CENTER -- the ONE writer of the torso's centerCommand + // (@0x208, HELD-button semantics: writer asserts while held, clears on + // release; TorsoSimulation re-arms recenterActive from it each frame). + // Sources OR'd here, deliberately OUTSIDE the key-bridge gate: + // * torsoCenter (@0x154) -- this mapper's databound "TorsoCenter" cell, + // the streamed pod-button route (button 0x42); + // * gBTTorsoRecenter -- the desktop 'X' one-frame pulse (mech4 key poll). + // The old writer lived INSIDE the key-bridge block, so on any rig with a + // RIO/PadRIO present (glass + the pod -- the bridge is off there) NO path + // could reach centerCommand: with the stuck-cell phantom auto-recentre + // fixed, those players had no way to recentre the torso in Std/Vet at all + // (Oracle's #152 report). Single-writer here also means the two sources + // can never stomp each other's clear. + { + Mech *rcMech = GetMech(); + Torso *rcTorso = (rcMech != 0) ? (Torso *)rcMech->GetTorsoSubsystem() : 0; + if (rcTorso != 0) + { + int hold = (torsoCenter != 0); + extern int gBTTorsoRecenter; + extern int gBTTorsoCenterHeld; // pod button 0x42 (L4PADRIO chokepoint) + if (gBTTorsoCenterHeld) hold = 1; + if (gBTTorsoRecenter) { gBTTorsoRecenter = 0; hold = 1; } + if (hold) + rcTorso->CommandRecenter(); + else + rcTorso->ClearRecenterCommand(); + } + } { // STAND-DOWN (glass-cockpit step 2c): BT_KEY_BRIDGE unset = AUTO -- // the bridge runs only when NO live cockpit device (serial RIO / @@ -938,21 +967,12 @@ void // centerCommand is a pod BUTTON state, so the writer clears // it while unpressed (Basic's own path re-asserts every // frame; this branch owns it in Standard/Veteran). - { - Torso *rcTorso = (Torso *)mech->GetTorsoSubsystem(); - if (rcTorso != 0) - { - if (gBTTorsoRecenter) - { - gBTTorsoRecenter = 0; - rcTorso->CommandRecenter(); - } - else - { - rcTorso->ClearRecenterCommand(); - } - } - } + // (#152) the recenter writer moved OUT of this key-bridge + // block to the unified consumer below -- inside here it was + // DEAD on every RIO/glass rig (bridge off), which left those + // players with no torso-centre control at all once the + // stuck-cell phantom auto-recentre was fixed. Bench: two + // scripted 0x42 holds on the RIO path, ctrCmd=0 throughout. } } // (stickPosition.y no longer zeroed here -- the bridge above diff --git a/scratchpad/night14/center42.sh b/scratchpad/night14/center42.sh new file mode 100644 index 0000000..3b18816 --- /dev/null +++ b/scratchpad/night14/center42.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# #152: is the AUTHENTIC torso-CENTER button (0x42) alive on the RIO/glass path +# (key bridge OFF)? Cycle to Standard, deflect/release the twist axis, and +# hold 0x42 during release windows. ctrCmd=1 while held + twist slewing to 0 +# = route works (ticket becomes player education). ctrCmd stuck 0 = the +# streamed 0x42 route is dead on glass and needs the forward implemented. +set -x +. /c/git/bt411/scratchpad/night6/bench_common.sh +cd /c/git/bt411/content || exit 1 +taskkill //F //IM btl4.exe > /dev/null 2>&1 +sleep 2 +rm -f c42_a.log +bt_expert_egg MP.EGG C42.EGG +sed -i "s/^map=.*/map=grass/; s/^time=.*/time=day/; s/^vehicle=.*/vehicle=madcat/" C42.EGG +( export BT_MODECYCLE_EVERY=400 BT_TWIST_PULSE=150 + export BT_BTNTEST=0x42,900,1150 BT_BTNTEST2=0x42,1500,1750 + export BT_TORSO_LOG=1 BT_KEY_NOFOCUS=1 BT_KEY_BRIDGE=0 + bt_launch c42_a.log C42.EGG 0x03 ) +sleep 130 +bt_kill_ours; sleep 2; taskkill //F //IM btl4.exe > /dev/null 2>&1; sleep 3 +echo "============ RESULT ============" +grep -a "\[mode\] control mode" c42_a.log | head -4 +echo "--- ctrCmd seen (want some =1 during the 0x42 holds) ---" +grep -ao "ctrCmd=[01]" c42_a.log | sort | uniq -c +echo "--- twist trajectory around the first hold ---" +grep -aE "twistpulse|ctrCmd=1" c42_a.log | head -8