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:
arcattack
2026-07-19 16:28:38 -05:00
co-authored by Claude Fable 5
parent 2ae9bd43ae
commit 1d6339b226
14 changed files with 229 additions and 39 deletions
+4 -2
View File
@@ -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
+2
View File
@@ -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
+3
View File
@@ -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
View File
@@ -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 =
+4 -1
View File
@@ -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")
+21
View File
@@ -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:
+5 -2
View File
@@ -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).
+5
View File
@@ -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;
+1
View File
@@ -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;
+52 -13
View File
@@ -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)
}
//
+21 -5
View File
@@ -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
+42
View File
@@ -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
+36 -7
View File
@@ -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
+7
View File
@@ -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