Gitea #6: secondary MFD Damage/Critical/Heat cycling -- reconstruct the
NotifyOfDisplayModeChange override (vtbl+0x4C @4d1ae4) + wire desktop 'N'
The secondary screen's schematic selector was mislabeled: @004d1ae4 (the
bits-18..20 ModeSecondary* mask swap) was reconstructed as a non-virtual
"SetControlMode" that nothing called, so the desktop stayed pinned on the
Damage view. The binary's L4 vtable @0051e440 pins the truth:
+0x48 = @004d1acc <- CycleControlModeMessageHandler (FUN_004afbe0):
forwards to the base RET no-op @004b048c. A BAS/MID/ADV
control-mode change never touches the secondary view
(empirically confirmed: BT_MODECYCLE_TEST cycles the CONTROL
MODE lamp, mask bits 18-20 unchanged, schematic stays ARMOR).
+0x4C = @004d1ae4 <- CycleDisplayModeMessageHandler (FUN_004afcac):
THE Damage/Critical/Heat selector, indexed by displayMode
(table @0051dbe4 = ModeSecondaryDamage/Critical/Heat).
Authentic pod inputs (streamed type-6 .CTL EventMappings, dumped via the
new BT_CTRLMAP_LOG EVENT records): secondary-panel button 0x15 -> msg
0x15 CycleDisplayMode (manual p13, the "'Mech status Info center" bottom
left of the secondary screen), button 0x18 -> msg 0x14 CycleControlMode
(manual p6, top right), 0x10/0x11 -> ZoomIn/Out. The DOS keyboard
fallbacks (Keypress 0x13d/0x13e = extended F3/F4) are dead under the
WinTesla VK map, hence the desktop pin.
Port wiring (the M/ModeCycle pattern): key N / pad RightThumb -> action
DisplayCycle -> gBTDisplayCycle -> CycleDisplayModeNow() -- the same body
the pod console button message drives. Both .MAP profiles + the
compiled-in default updated.
Verified live (docked gauges + BT_SHOT, BT_VIEWCYCLE_TEST): the sec
panel cycles ARMOR DAMAGE silhouette -> CRITICAL DAMAGE subsystem list
-> HEAT DAMAGE colored list, mask 0x450421 -> 0x490421 -> 0x510421; M
control-mode cycling un-regressed (BAS/MID/ADV lamp cycles, view pinned).
Diags: BT_MODE_LOG, BT_VIEWCYCLE_TEST=<frame>, BT_MODECYCLE_TEST=<frame>,
BT_CTRLMAP_LOG now dumps EVENT records. KB: gauges-hud secondary-view
section rewritten, CLASSMAP +0x48/+0x4C slots, decomp-reference env
gates, GAUGE_COMPOSITE phase-4 entry resolved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
2ae9bd43ae
commit
1d6339b226
@@ -31,8 +31,8 @@
|
||||
# LeftTrigger RightTrigger (as digital, >= 50% pressed)
|
||||
# <src> LeftStickX LeftStickY RightStickX RightStickY
|
||||
# LeftTrigger RightTrigger
|
||||
# action ViewToggle LookBehind AllStop ModeCycle Valve Flush ConfigHold
|
||||
# Generator1-4 Reconnect
|
||||
# action ViewToggle LookBehind AllStop ModeCycle DisplayCycle Valve Flush
|
||||
# ConfigHold Generator1-4 Reconnect
|
||||
# pckey sends an authentic 1995 PC-keyboard hotkey (the in-cockpit
|
||||
# dispatcher): '+'/'-' = target zoom, 'w'..'o' = pilot select,
|
||||
# 'a','b','c','d','f','g','s','v','x','z' = display presets, ...
|
||||
@@ -75,6 +75,7 @@ key G action ConfigHold # hold + fire keys = regroup the weapon
|
||||
key C action Valve # coolant valve cycle
|
||||
key H action Flush # coolant flush (HOLD -- dumps reservoir coolant)
|
||||
key M action ModeCycle # Basic -> Standard -> Veteran controls
|
||||
key N action DisplayCycle # secondary schematic: Damage -> Critical -> Heat
|
||||
key V action ViewToggle # cockpit <-> chase camera (dev)
|
||||
key B action LookBehind # HOLD = the pod's rear-view button
|
||||
key F5 action Generator1
|
||||
@@ -102,4 +103,5 @@ pad B action AllStop
|
||||
pad Y action ViewToggle
|
||||
pad X action LookBehind
|
||||
pad Start action ModeCycle
|
||||
pad RightThumb action DisplayCycle
|
||||
pad Back action Valve
|
||||
|
||||
@@ -44,6 +44,7 @@ key Right button 0x43 # Hat Right
|
||||
# ---- Systems ------------------------------------------------------------
|
||||
key G action ConfigHold
|
||||
key Enter action ModeCycle
|
||||
key N action DisplayCycle # secondary schematic: Damage -> Critical -> Heat
|
||||
key V action ViewToggle
|
||||
key B action LookBehind
|
||||
key F5 action Generator1
|
||||
@@ -99,4 +100,5 @@ pad B action AllStop
|
||||
pad Y action ViewToggle
|
||||
pad X action LookBehind
|
||||
pad Start action ModeCycle
|
||||
pad RightThumb action DisplayCycle
|
||||
pad Back action Valve
|
||||
|
||||
@@ -283,6 +283,9 @@ default-ON (`'0'` disables).
|
||||
| `BT_SELF=<[pilots] tag>` | claim a specific roster seat in relay mode; absent/`auto` = the relay assigns one (SEAT_REQUEST) |
|
||||
| `BT_RELAY_TCP_ONLY=1` | disable the relay UDP channel (all unreliable traffic rides the TCP relay conn) |
|
||||
| `BT_INPUT_LOG` | binding-engine trace: CONTROLS.MAP load, button/keypad emissions, pad connect, torso twist/elev axis ([[pod-hardware]] §Desktop input remap) |
|
||||
| `BT_MODE_LOG` | `[mode] display notify` — the ModeManager mask after each secondary-view swap (btl4mppr.cpp NotifyOfDisplayModeChange, Gitea #6) |
|
||||
| `BT_VIEWCYCLE_TEST=<frame>` / `BT_MODECYCLE_TEST=<frame>` | scripted verify (mech4.cpp): pulse a secondary-schematic cycle / a control-mode cycle at the frame and every 300 after — pixel-verifiable with `BT_DEV_GAUGES_DOCK`+`BT_SHOT` |
|
||||
| `BT_CTRLMAP_LOG` | streamed `.CTL` record audit (L4CTRL.cpp CreateStreamedMappings): Direct records with the resolved member offset + EVENT records (button→subsystem message; found the pod's secondary-panel Cycle buttons 0x15/0x18) |
|
||||
| `BT_CAM_LOG` | camera-seat/broadcast trace: streamed camera network count, director pick + Players-group census, ship follow state, PlayerLink dispatch/receive, ranking-window render ([[multiplayer]] camera seat) |
|
||||
| `BT_SPEC_LOG` | manual spec-audit dump at subsystem ctor: torso speed/limits, heat-sink count, reservoir capacity, per-subsystem coolant loop ([[pod-hardware]] §Spec cross-check) |
|
||||
|
||||
|
||||
+26
-9
@@ -8,7 +8,7 @@ key_terms: [gauge, methodDescription, attribute-pointer, GaugeRenderer, MFD, PCC
|
||||
open_questions:
|
||||
- "MessageBoard LIVE 2026-07-12 (kill ticker); remaining: only strip 0 (kill) is produced -- survey the other btsmsgs.pcx strips for authentic producers"
|
||||
- "HUD binary attr table @005110c0 offsets conflict with the port HUD layout on 3 slots (0x1D8/0x1EC/0x1F8) -- re-dump before publishing"
|
||||
- "Secondary-view cycling (Damage/Critical/Heat) unreachable from the desktop keyboard: the mapper's 0x13d/0x13e cases are dead DOS F3/F4 codes (VK_F3/F4 = 0x72/0x73 collide with 'r'/'s') -- wire a free key to CycleControlMode"
|
||||
- "Secondary-view cycling RESOLVED 2026-07-19 (Gitea #6): the selector is the DISPLAY mode (CycleDisplayMode -> vtbl+0x4C override @4d1ae4), NOT CycleControlMode; desktop 'N' / pad RightThumb wired; pixel-verified dama->crit->heat"
|
||||
- "MP DEATHS resolved 2026-07-12 (observed-death tally + display clamp); remaining: verify multi-death tallies stay in sync across a long session (GAUGE_COMPOSITE.md)"
|
||||
---
|
||||
|
||||
@@ -70,7 +70,7 @@ over one shared `SVGA16` pixelBuffer; `SVGA16::DrawDevSurface`). On the POD they
|
||||
intact). The `overlay` port (SectorDisplay lives there) shares the `sec` physical surface via a
|
||||
different bit-plane (0x00C0). [T2]
|
||||
|
||||
## The secondary screen's THREE views (Damage / Critical / Heat) — mode-gated [T0/T1]
|
||||
## The secondary screen's THREE views (Damage / Critical / Heat) — mode-gated [T0/T1/T2]
|
||||
The `sec` port stacks three mode-gated mech-schematic layers at offset (50,0) over the
|
||||
always-on radar/heading/speed/messageBoard (`Secondary1`): **Damage** (`ModeSecondaryDamage`,
|
||||
`<mech>dama.pcc` + `colorMapArmor`/`colorMapperMultiArmor` — 4 silhouettes front/left/right/back,
|
||||
@@ -80,13 +80,30 @@ pixel-plane ids 60-63, per-DAMAGE-ZONE `dz_*` tint through the adpal→adpal2 ra
|
||||
NonMapping=0x10000, Intercom=0x20000, **SecondaryDamage=0x40000, SecondaryCritical=0x80000,
|
||||
SecondaryHeat=0x100000** (bits 18-20). `ModeInitial` includes **SecondaryDamage** → the ARMOR
|
||||
view is the default-on layer (our port creates `BTL4ModeManager(ModeInitial)`, btl4app.cpp:303).
|
||||
`L4MechControlsMapper::SetControlMode` @004d1ae4 is the SELECTOR — its mask table
|
||||
{0x40000,0x80000,0x100000} clears bits 18-20 and sets one — despite the "control mode" name it
|
||||
switches the secondary VIEW. ⚠ Desktop gap: the Keypress cases `0x13d`/`0x13e`
|
||||
(CycleControlMode/CycleDisplayMode) are the DOS Tesla extended F3/F4 codes and never fire under
|
||||
the WinTesla VK map (VK_F3=0x72 collides with 'r', VK_F4=0x73 with 's' — the same collision
|
||||
class as the documented 'p'/VK_F1 drop), so the desktop is PINNED on the Damage view. The
|
||||
schematic shows the pilot's OWN mech only — there is no target-damage readout in the cockpit.
|
||||
The schematic shows the pilot's OWN mech only — there is no target-damage readout in the cockpit.
|
||||
|
||||
**The selector is the DISPLAY mode, not the control mode (Gitea #6, RESOLVED 2026-07-19) [T1→T2].**
|
||||
The L4 vtable @0051e440 pins the slots: **+0x4C = @004d1ae4** — dispatched by
|
||||
`CycleDisplayModeMessageHandler` (FUN_004afcac) with the new `displayMode` (0/1/2) — is the
|
||||
`NotifyOfDisplayModeChange` override that clears bits 18-20 and sets the mask from the table
|
||||
@0051dbe4 {0x40000,0x80000,0x100000}. (The old "SetControlMode @004d1ae4 switches the secondary
|
||||
VIEW" claim was the mislabel that kept the port's copy a never-called non-virtual.) **+0x48 =
|
||||
@004d1acc** — dispatched by `CycleControlModeMessageHandler` (FUN_004afbe0) — just forwards to
|
||||
the base RET no-op @004b048c: a BAS/MID/ADV control-mode change NEVER touches the secondary
|
||||
view (empirically confirmed: M cycles the CONTROL MODE gauge lamp, mask bits 18-20 unchanged,
|
||||
schematic stays on ARMOR DAMAGE). **Authentic pod inputs** (streamed type-6 `.CTL`
|
||||
EventMappings, dumped live via `BT_CTRLMAP_LOG`): secondary-panel button **0x15 → msg 0x15
|
||||
CycleDisplayMode** (the manual-p13 "'Mech status Info center", bottom left of the secondary
|
||||
screen: Armor/Critical/Heat Damage Schematic cycle), button **0x18 → msg 0x14 CycleControlMode**
|
||||
(the manual-p6 mode button, top right), buttons 0x10/0x11 → ZoomIn/ZoomOut 0x12/0x13 (the map
|
||||
zoom ± pair). The DOS keyboard fallbacks (Keypress `0x13d`/`0x13e` = extended F3/F4) never fire
|
||||
under the WinTesla VK map (VK_F3=0x72 collides with 'r', VK_F4=0x73 with 's' — the 'p'/VK_F1
|
||||
collision class), so the desktop was PINNED on Damage. **Port wiring (mirrors the M/ModeCycle
|
||||
pattern): 'N' / pad RightThumb → action DisplayCycle → gBTDisplayCycle → `CycleDisplayModeNow()`**
|
||||
(mechmppr.cpp; the same body the pod button message drives). Pixel-verified live (docked gauges +
|
||||
BT_SHOT): ARMOR DAMAGE silhouette → CRITICAL DAMAGE subsystem list → HEAT DAMAGE colored list,
|
||||
mask 0x450421→0x490421→0x510421. Diags: `BT_MODE_LOG`, `BT_VIEWCYCLE_TEST=<frame>`,
|
||||
`BT_MODECYCLE_TEST=<frame>`.
|
||||
|
||||
## pilotList (Comm KILLS/DEATHS) row semantics + the −1 [T1/T2]
|
||||
One ROW PER PILOT in the mission (2-player MP = 2 rows — not duplicate displays). KILLS =
|
||||
|
||||
@@ -627,7 +627,10 @@ Byte-exact re-base of the PoweredSubsystem:HeatSink LEAF (Sensor/Emitter/Myomers
|
||||
(delete the sensor.cpp:287-288 guard — ✅ LANDED: the guard is deleted and the leaf is byte-exact,
|
||||
sensor.cpp:407-413) + the raw-offset cluster reads (partially locked since — MechWeapon byte-exact);
|
||||
radar pip/name symbology + staticEntities (task #17, under reconstruction 2026-07-12);
|
||||
CycleDisplayMode→ModeManager mask (machinery reconstructed, gauge-layer toggle unverified [T3]);
|
||||
CycleDisplayMode→ModeManager mask (✅ RESOLVED 2026-07-19, Gitea #6 [T2]: @4d1ae4 relabeled the
|
||||
NotifyOfDisplayModeChange override (vtbl+0x4C) and made virtual; desktop 'N'/pad RightThumb →
|
||||
CycleDisplayModeNow; secondary schematic swap dama→crit→heat pixel-verified via
|
||||
BT_DEV_GAUGES_DOCK+BT_SHOT; pod buttons = streamed EventMappings 0x15→msg 0x15 / 0x18→msg 0x14);
|
||||
numericSpeed units (open).
|
||||
|
||||
### Authentically-static (do NOT "fix")
|
||||
|
||||
@@ -2286,6 +2286,27 @@ void
|
||||
Receiver::MessageID
|
||||
msg_id = mapping->messageID;
|
||||
|
||||
//
|
||||
// BT_CTRLMAP_LOG=1: dump the streamed EVENT records too (button ->
|
||||
// subsystem message). Gitea #6 needed this to identify which pod
|
||||
// console buttons carried the mapper's CycleControlMode (0x14) /
|
||||
// CycleDisplayMode (0x15) messages.
|
||||
//
|
||||
{
|
||||
static const int s_ctrlmapLog =
|
||||
(getenv("BT_CTRLMAP_LOG") != 0 && *getenv("BT_CTRLMAP_LOG") != '0');
|
||||
if (s_ctrlmapLog)
|
||||
{
|
||||
DEBUG_STREAM << "[ctrlmap] rec " << i
|
||||
<< " subsys " << mapping->subsystemID
|
||||
<< " group " << (int)mapping->controlsGroup
|
||||
<< " elem 0x" << std::hex << element
|
||||
<< " mask 0x" << (unsigned)mode_mask
|
||||
<< " EVENT msg 0x" << (unsigned)msg_id
|
||||
<< std::dec << "\n" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
switch (mapping->controlsGroup)
|
||||
{
|
||||
case ScalarGroup:
|
||||
|
||||
@@ -147,8 +147,11 @@ Subsystem (MUNGA base — have source: RP/MUNGA/SUBSYSTM.HPP)
|
||||
│ throttleForward@0x1ac/throttleReverse@0x1b0/leftPedal@0x1b4/rightPedal@0x1b8 (cleared by derived ctors).
|
||||
│ InterpretControls@4d196c (throttle detent snap 1.0±0.05, BuildPilotArray, review-mode bit 0x200000,
|
||||
│ target-range ramp range=250*2^exp, exp clamp[0,5]; then chains MechControlsMapper::InterpretControls @4afd10).
|
||||
│ ZoomTargetRangeIn@4d1b64 / ZoomTargetRangeOut@4d1b9c (±1.0). NotifyOfDisplayModeChange-override@4d1ae4 (vtbl+0x4C; ex-"SetControlMode", (mode bits18-20,
|
||||
│ table @0051dbe4={0x40000,0x80000,0x100000}). SetPresetMode@4d1b24 (group*5+item -> {clear,set} mask table @0051dbf0[15]).
|
||||
│ ZoomTargetRangeIn@4d1b64 / ZoomTargetRangeOut@4d1b9c (±1.0). NotifyOfControlModeChange-override@4d1acc (vtbl+0x48; forwards to base no-op @4b048c —
|
||||
│ control mode never touches the secondary view). NotifyOfDisplayModeChange-override@4d1ae4 (vtbl+0x4C; ex-"SetControlMode"; Gitea #6 reconstructed
|
||||
│ 2026-07-19 = THE secondary Damage/Critical/Heat selector, mode bits18-20, table @0051dbe4={0x40000,0x80000,0x100000}; pod input = streamed
|
||||
│ EventMapping secondary-panel button 0x15 -> msg 0x15 CycleDisplayMode; button 0x18 -> msg 0x14 CycleControlMode).
|
||||
│ SetPresetMode@4d1b24 (group*5+item -> {clear,set} mask table @0051dbf0[15]).
|
||||
│ EnterConfiguration@4d1840 (+0x38) / ExitConfiguration@4d18dc (+0x3C) (task #6 relabel (buttons 0x40..0x47, hat-skip 0x41->0x45,
|
||||
│ mode 0x8000=ConfigReady). AddOrErase evt/dir RET no-ops @4d195c/@4d1964 (+0x40/+0x44; TM can't regroup). KeypressMessageHandler@4d1bf0
|
||||
│ (shared dispatcher: zoom/preset/pilot-cycle/look keys + fake-button dev keys; default -> @4d141c).
|
||||
|
||||
@@ -70,6 +70,7 @@ enum BTActionID
|
||||
BTActLookBehind,
|
||||
BTActAllStop,
|
||||
BTActModeCycle,
|
||||
BTActDisplayCycle, // Gitea #6: secondary schematic cycle (Damage/Critical/Heat)
|
||||
BTActValve,
|
||||
BTActFlush, // Gitea #7: HELD = coolant flush (InjectCoolant)
|
||||
BTActConfigHold,
|
||||
@@ -193,6 +194,7 @@ static const BTName sActionNames[] =
|
||||
{
|
||||
{"ViewToggle", BTActViewToggle}, {"LookBehind", BTActLookBehind},
|
||||
{"AllStop", BTActAllStop}, {"ModeCycle", BTActModeCycle},
|
||||
{"DisplayCycle", BTActDisplayCycle},
|
||||
{"Valve", BTActValve}, {"Flush", BTActFlush}, {"ConfigHold", BTActConfigHold},
|
||||
{"Generator1", BTActGenerator1}, {"Generator2", BTActGenerator2},
|
||||
{"Generator3", BTActGenerator3}, {"Generator4", BTActGenerator4},
|
||||
@@ -266,6 +268,7 @@ static const char *sDefaultProfile =
|
||||
"key C action Valve\n"
|
||||
"key H action Flush\n"
|
||||
"key M action ModeCycle\n"
|
||||
"key N action DisplayCycle\n"
|
||||
"key V action ViewToggle\n"
|
||||
"key B action LookBehind\n"
|
||||
"key F5 action Generator1\n"
|
||||
@@ -289,6 +292,7 @@ static const char *sDefaultProfile =
|
||||
"pad Y action ViewToggle\n"
|
||||
"pad X action LookBehind\n"
|
||||
"pad Start action ModeCycle\n"
|
||||
"pad RightThumb action DisplayCycle\n"
|
||||
"pad Back action Valve\n";
|
||||
|
||||
//=============================================================================
|
||||
@@ -963,6 +967,7 @@ void
|
||||
case BTActLookBehind: next.lookBehind = 1; break;
|
||||
case BTActAllStop: next.allStop = 1; break;
|
||||
case BTActModeCycle: next.modeCycle = 1; break;
|
||||
case BTActDisplayCycle: next.displayCycle = 1; break;
|
||||
case BTActValve: next.valve = 1; break;
|
||||
case BTActFlush: next.flush = 1; break;
|
||||
case BTActConfigHold: next.configHold = 1; break;
|
||||
|
||||
@@ -51,6 +51,7 @@ struct BTInputState
|
||||
int lookBehind;
|
||||
int allStop;
|
||||
int modeCycle;
|
||||
int displayCycle; // Gitea #6: secondary schematic cycle (Damage/Critical/Heat)
|
||||
int valve;
|
||||
int flush; // Gitea #7: coolant flush HELD (InjectCoolant)
|
||||
int configHold;
|
||||
|
||||
@@ -30,10 +30,12 @@
|
||||
// @004d17ac ctor @004d1814 dtor
|
||||
// @004d196c InterpretControls (target-range ramp + review-mode watch)
|
||||
// @004d1b64 ZoomTargetRangeIn @004d1b9c ZoomTargetRangeOut
|
||||
// @004d1ae4 SetControlMode (mode-mask switch; calls base NotifyOfDisplayMode)
|
||||
// @004d1acc NotifyOfControlModeChange (+0x48; forwards to base no-op @004b048c)
|
||||
// @004d1ae4 NotifyOfDisplayModeChange (+0x4C; the secondary-view mask swap
|
||||
// -- Gitea #6 relabel; ex-"SetControlMode")
|
||||
// @004d1b24 SetPresetMode (group/item -> preset mode-mask)
|
||||
// @004d1840 CreateTemporaryEventMappings @004d18dc RemoveTemporaryEventMappings
|
||||
// @004d195c NotifyOfControlModeChange (no-op) @004d1964 NotifyOfConfigurationModeChange (no-op)
|
||||
// @004d1840 EnterConfiguration @004d18dc ExitConfiguration
|
||||
// @004d195c/@004d1964 AddOrErase evt/dir (+0x40/+0x44, RET no-ops)
|
||||
// @004d1bf0 KeypressMessageHandler (the shared L4 keyboard dispatcher)
|
||||
// MechThrustmasterMapper --------------------------- vtable @0051e3f0
|
||||
// @004d21d0 ctor @004d22b4 dtor @004d22e0 TestInstance
|
||||
@@ -81,7 +83,8 @@
|
||||
// _DAT_004d1ac8 = 0x437a0000 = 250.0f (target-range scale: range = 250*2^x)
|
||||
// _DAT_004d1b94 = 1.0f zoom-in step _DAT_004d1b98 = 0.0f min exponent
|
||||
// _DAT_004d1bcc = 1.0f zoom-out step _DAT_004d1bd0 = 5.0f max exponent
|
||||
// DAT_0051dbe4[3] = {0x40000,0x80000,0x100000} control-mode mode-masks
|
||||
// DAT_0051dbe4[3] = {0x40000,0x80000,0x100000} secondary-VIEW mode-masks
|
||||
// (ModeSecondaryDamage/Critical/Heat, indexed by displayMode)
|
||||
// DAT_0051dbf0[15] = {clear,set} mode-mask pairs (group*5+item), preset select
|
||||
// DAT_0051dcd0[8] = {0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30} hotbox buttons
|
||||
//
|
||||
@@ -482,25 +485,61 @@ L4MechControlsMapper::MessageHandlerSet&
|
||||
|
||||
//
|
||||
//#############################################################################
|
||||
// SetControlMode @004d1ae4
|
||||
// NotifyOfControlModeChange @004d1acc (vtbl+0x48)
|
||||
// NotifyOfDisplayModeChange @004d1ae4 (vtbl+0x4C)
|
||||
//#############################################################################
|
||||
//
|
||||
// Swap the application mode-manager's control-mode bits (18..20) for the bit
|
||||
// selected by new_mode, then notify the base of the implied display change.
|
||||
// Gitea #6 RELABEL (2026-07-19). The old reconstruction carried @004d1ae4 as
|
||||
// a non-virtual "SetControlMode" that nothing ever called, so the desktop's
|
||||
// secondary MFD stayed pinned on the Damage view. The vtable @0051e440
|
||||
// (section_dump.txt:73033) pins the truth:
|
||||
//
|
||||
// +0x48 = @004d1acc -- dispatched by CycleControlModeMessageHandler
|
||||
// (FUN_004afbe0) with the new controlMode. Capstone disasm: pushes
|
||||
// its two args and forwards to the BASE no-op @004b048c. A
|
||||
// control-mode (BAS/MID/ADV) change never touches the secondary
|
||||
// view -- in the shipped binary OR here.
|
||||
// +0x4C = @004d1ae4 -- dispatched by CycleDisplayModeMessageHandler
|
||||
// (FUN_004afcac) with the new displayMode. THE secondary-view
|
||||
// selector: clears mode bits 18..20 (& 0xffe3ffff =
|
||||
// ~ModeSecondaryAll), sets the mask picked from the table @0051dbe4
|
||||
// = {ModeSecondaryDamage 0x40000, ModeSecondaryCritical 0x80000,
|
||||
// ModeSecondaryHeat 0x100000}, then chains the base no-op
|
||||
// @004b0494. displayMode 0/1/2 = Damage/Critical/Heat -- the
|
||||
// manual-p13 "'Mech status Info center" schematic cycle (bottom
|
||||
// left of the secondary screen).
|
||||
//
|
||||
void
|
||||
L4MechControlsMapper::SetControlMode(int new_mode)
|
||||
L4MechControlsMapper::NotifyOfControlModeChange(int new_mode)
|
||||
{
|
||||
static const ModeMask control_mode_mask[] = // @0051dbe4
|
||||
{ 0x40000, 0x80000, 0x100000 };
|
||||
MechControlsMapper::NotifyOfControlModeChange(new_mode); // @004b048c (no-op)
|
||||
}
|
||||
|
||||
void
|
||||
L4MechControlsMapper::NotifyOfDisplayModeChange(int new_mode)
|
||||
{
|
||||
static const ModeMask display_mode_mask[] = // @0051dbe4
|
||||
{
|
||||
BTL4ModeManager::ModeSecondaryDamage, // 0 -> 0x040000
|
||||
BTL4ModeManager::ModeSecondaryCritical, // 1 -> 0x080000
|
||||
BTL4ModeManager::ModeSecondaryHeat // 2 -> 0x100000
|
||||
};
|
||||
|
||||
BTL4ModeManager *mode_manager =
|
||||
(BTL4ModeManager*)application->GetModeManager(); // DAT_004efc94+0x50
|
||||
|
||||
mode_manager->RemoveModeMask(0x001c0000); // clear bits 18..20 (~0xffe3ffff)
|
||||
mode_manager->AddModeMask(control_mode_mask[new_mode]);
|
||||
mode_manager->RemoveModeMask( // clear bits 18..20
|
||||
BTL4ModeManager::ModeSecondaryAll); // (& 0xffe3ffff)
|
||||
mode_manager->AddModeMask(display_mode_mask[new_mode]);
|
||||
|
||||
NotifyOfDisplayModeChange(displayMode); // FUN_004b0494
|
||||
// DIAG (BT_MODE_LOG): the resulting manager mask -- proves the
|
||||
// secondary-view bit actually flipped for the gauge layer gating.
|
||||
if (getenv("BT_MODE_LOG"))
|
||||
DEBUG_STREAM << "[mode] display notify " << new_mode
|
||||
<< " -> manager mask 0x" << std::hex
|
||||
<< mode_manager->GetModeMask() << std::dec << "\n" << std::flush;
|
||||
|
||||
MechControlsMapper::NotifyOfDisplayModeChange(new_mode); // @004b0494 (no-op)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@@ -104,11 +104,27 @@
|
||||
ZoomTargetRangeOut(); // @004d1b9c
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Control / display modes
|
||||
// Control / display modes (Gitea #6 relabel -- the vtable pins the slots).
|
||||
//
|
||||
// The binary's L4 vtable @0051e440 (section_dump): +0x48 = @004d1acc,
|
||||
// +0x4C = @004d1ae4. CycleControlModeMessageHandler (FUN_004afbe0)
|
||||
// dispatches vtbl+0x48 with the new controlMode; CycleDisplayModeMessage-
|
||||
// Handler (FUN_004afcac) dispatches vtbl+0x4C with the new displayMode.
|
||||
// So @004d1ae4 -- the {0x40000,0x80000,0x100000} secondary-view mask swap
|
||||
// the old reconstruction called "SetControlMode" (never called by anyone)
|
||||
// -- is the NotifyOfDisplayModeChange OVERRIDE: the secondary screen's
|
||||
// Damage / Critical / Heat schematic is selected by the DISPLAY mode
|
||||
// (manual p13: the "'Mech status Info center", bottom left of the
|
||||
// secondary screen), NOT by the BAS/MID/ADV control mode (manual p6: top
|
||||
// right of the secondary screen). @004d1acc (NotifyOfControlModeChange)
|
||||
// just forwards to the base no-op @004b048c -- a control-mode change
|
||||
// never touches the secondary view.
|
||||
//
|
||||
public:
|
||||
void
|
||||
SetControlMode(int new_mode); // @004d1ae4 (mode-mask switch)
|
||||
virtual void
|
||||
NotifyOfControlModeChange(int new_mode); // @004d1acc (+0x48, chains base no-op)
|
||||
virtual void
|
||||
NotifyOfDisplayModeChange(int new_mode); // @004d1ae4 (+0x4C, secondary-view mask swap)
|
||||
void
|
||||
SetPresetMode(int group, int item); // @004d1b24 (preset mode-mask)
|
||||
|
||||
@@ -119,8 +135,8 @@
|
||||
// old reconstruction mislabeled "NotifyOfControlModeChange /
|
||||
// NotifyOfConfigurationModeChange". Only MechRIOMapper overrides the
|
||||
// AddOrErase pair with real bodies -- a Thrustmaster cockpit cannot
|
||||
// regroup. (The REAL NotifyOf* L4 overrides are @004d1acc/@004d1ae4,
|
||||
// vtable +0x48/+0x4C -- out of scope here.)
|
||||
// regroup. (The REAL NotifyOf* L4 overrides @004d1acc/@004d1ae4,
|
||||
// vtable +0x48/+0x4C, are declared in the mode section above.)
|
||||
//
|
||||
public:
|
||||
virtual void
|
||||
|
||||
@@ -652,6 +652,7 @@ static int gBTPPCKey = 0;
|
||||
static int gBTMissileKey = 0;
|
||||
static int gBTPinkyKey = 0; // key '4' = the pod's 4th fire button (Pinky 0x45)
|
||||
int gBTModeCycle = 0; // 'M' edge: cycle the control mode (mapper consumes)
|
||||
int gBTDisplayCycle = 0; // 'N' edge: cycle the secondary schematic (Gitea #6, mapper consumes)
|
||||
int gBTLookBehind = 0; // 'V' held: the pod's rear-view button (task #68)
|
||||
float gBTTwistAxis = 0.0f; // Q/E torso-twist deflection (assisted-mode stick X)
|
||||
float gBTElevAxis = 0.0f; // R/F torso-elevation (pitch aim, stick Y)
|
||||
@@ -2670,6 +2671,15 @@ void
|
||||
const int mNow = gBTInput.modeCycle;
|
||||
if (mNow && !sPrevM) gBTModeCycle = 1; // edge -> one cycle
|
||||
sPrevM = mNow;
|
||||
// Gitea #6: 'N' cycles the secondary screen's schematic
|
||||
// (Damage -> Critical -> Heat) -- the pod's status-info-
|
||||
// center button (manual p13), CycleDisplayModeNow.
|
||||
{
|
||||
static int sPrevN = 0;
|
||||
const int nNow = gBTInput.displayCycle;
|
||||
if (nNow && !sPrevN) gBTDisplayCycle = 1;
|
||||
sPrevN = nNow;
|
||||
}
|
||||
// (task #68) LookBehind action HELD = the pod's rear-view
|
||||
// button (releases back to the forward view). Rear-mounted
|
||||
// weapons (blackhawk/owens back racks) fire only in it.
|
||||
@@ -5149,6 +5159,38 @@ void
|
||||
gBTValveKey = (s_vtFrame >= 600 && s_vtFrame < 610) ? 1 : 0;
|
||||
}
|
||||
|
||||
// Gitea #6 scripted verify (BT_VIEWCYCLE_TEST=<frame>): pulse one
|
||||
// secondary-schematic cycle (Damage -> Critical -> Heat -> Damage) at
|
||||
// the given frame and every 300 frames after -- with
|
||||
// BT_DEV_GAUGES_DOCK + BT_SHOT the docked sec panel's schematic layer
|
||||
// swap is pixel-verifiable. BT_MODECYCLE_TEST=<frame> does the same
|
||||
// for the M-key CONTROL-mode cycle (the empirical proof that a
|
||||
// control-mode change does NOT touch the secondary view).
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_VIEWCYCLE_TEST"))
|
||||
{
|
||||
static int s_vcFrame = 0;
|
||||
++s_vcFrame;
|
||||
int t0 = atoi(getenv("BT_VIEWCYCLE_TEST"));
|
||||
if (t0 < 1) t0 = 600;
|
||||
if (s_vcFrame >= t0 && (s_vcFrame - t0) % 300 == 0)
|
||||
{
|
||||
gBTDisplayCycle = 1;
|
||||
}
|
||||
}
|
||||
if ((Entity *)this == application->GetViewpointEntity()
|
||||
&& getenv("BT_MODECYCLE_TEST"))
|
||||
{
|
||||
static int s_mcFrame = 0;
|
||||
++s_mcFrame;
|
||||
int t0 = atoi(getenv("BT_MODECYCLE_TEST"));
|
||||
if (t0 < 1) t0 = 600;
|
||||
if (s_mcFrame >= t0 && (s_mcFrame - t0) % 300 == 0)
|
||||
{
|
||||
gBTModeCycle = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Gitea #7 scripted verify (BT_FLUSH_TEST=<frame>): hold the coolant
|
||||
// flush for ~60 sim frames starting at the given frame -- the
|
||||
// reservoir drains ([flush] log), the coolant vertBar drops, and the
|
||||
|
||||
@@ -521,7 +521,13 @@ void
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// @004afcac -- cycle the HUD display mode (0 -> 1 -> 2 -> 0).
|
||||
// @004afcac -- cycle the DISPLAY mode (0 -> 1 -> 2 -> 0). Gitea #6: this is
|
||||
// the secondary screen's Damage/Critical/Heat schematic cycle -- the L4
|
||||
// NotifyOfDisplayModeChange override (vtbl+0x4C, @004d1ae4) swaps the
|
||||
// ModeSecondary* mask bits 18..20. The pod input was the "'Mech status Info
|
||||
// center" button (manual p13, bottom left of the secondary screen); the DOS
|
||||
// keyboard fallback was extended-F4 (Keypress 0x13e), dead under the WinTesla
|
||||
// VK map.
|
||||
//
|
||||
void
|
||||
MechControlsMapper::CycleDisplayModeMessageHandler(
|
||||
@@ -533,16 +539,30 @@ void
|
||||
|
||||
if (message->dataContents > 0)
|
||||
{
|
||||
displayMode = displayMode + 1;
|
||||
if (displayMode > 2)
|
||||
{
|
||||
displayMode = 0;
|
||||
}
|
||||
NotifyOfDisplayModeChange(displayMode); // vtable+0x4c
|
||||
CycleDisplayModeNow();
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//
|
||||
// The display-cycle body, shared by the console-button message handler above
|
||||
// and the desktop 'N' key (mech4 key poll -> gBTDisplayCycle) -- the same
|
||||
// split as CycleControlModeNow.
|
||||
//
|
||||
void
|
||||
MechControlsMapper::CycleDisplayModeNow()
|
||||
{
|
||||
displayMode = displayMode + 1;
|
||||
if (displayMode > 2)
|
||||
{
|
||||
displayMode = 0;
|
||||
}
|
||||
NotifyOfDisplayModeChange(displayMode); // vtable+0x4c
|
||||
DEBUG_STREAM << "[mode] display mode -> " << displayMode
|
||||
<< " (0=Damage 1=Critical 2=Heat)" << std::endl;
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
// @004afce8 -- toggle voice assist on the Mech's pilot subsystem.
|
||||
@@ -759,6 +779,7 @@ void
|
||||
// CONTROL MODE gauge tracks).
|
||||
{
|
||||
extern int gBTModeCycle;
|
||||
extern int gBTDisplayCycle;
|
||||
extern float gBTTwistAxis;
|
||||
extern int gBTTorsoRecenter;
|
||||
if (gBTModeCycle)
|
||||
@@ -766,6 +787,14 @@ void
|
||||
gBTModeCycle = 0;
|
||||
CycleControlModeNow();
|
||||
}
|
||||
// Gitea #6: 'N' cycles the secondary screen's schematic
|
||||
// (Damage -> Critical -> Heat) -- the same body the pod's
|
||||
// status-info-center button message drives.
|
||||
if (gBTDisplayCycle)
|
||||
{
|
||||
gBTDisplayCycle = 0;
|
||||
CycleDisplayModeNow();
|
||||
}
|
||||
// TORSO ELEVATION (pitch): the pod stick's Y axis -- every
|
||||
// control mode routes stickPosition.y into
|
||||
// Torso::SetAnalogElevationAxis below, so the bridge feeds
|
||||
|
||||
@@ -113,6 +113,13 @@ class Pilot;
|
||||
CycleDisplayModeMessageHandler( // @004afcac
|
||||
ReceiverDataMessageOf<ControlsButton> *message
|
||||
);
|
||||
|
||||
// The shared display-cycle body (Gitea #6: the pod console button
|
||||
// message above + the desktop 'N' key both drive it) -- cycles the
|
||||
// secondary screen's Damage -> Critical -> Heat schematic via the
|
||||
// NotifyOfDisplayModeChange override (vtbl+0x4C, @004d1ae4).
|
||||
void
|
||||
CycleDisplayModeNow();
|
||||
void
|
||||
ToggleVoiceAssistMessageHandler( // @004afce8
|
||||
ReceiverDataMessageOf<ControlsButton> *message
|
||||
|
||||
Reference in New Issue
Block a user