Picking a preset no longer blinds the mode lamps
The six PRESET switches down the map's right flank stored their lamps in modeLamp[], which holds four. Indices 4 and 5 ran off the end into presetLamp[0..1], so the whole thing stayed self-consistent by memory layout and nobody noticed - but it overwrote the four control-mode lamps made moments earlier, and BASIC/STANDARD/VETERAN/MASTER on the upper-right MFD were never lit again. presetLamp[], meanwhile, went unused. The preset pass now fills the array it was always meant to, and the lamp work moves out of the switch handler into a virtual NotifyOfPresetChange that PresetEnable announces itself. That closes the second gap in passing: keyboard 1-6 changed the mappings without touching the lamps, leaving the flank showing a preset that was no longer in force. Both routes now go through one place. The lamp arrays are also cleared in the constructor - only the mapping loops ever filled them, and NOMODES skips those. Verified by dumping the commanded RIO lamp states out of the running game (PadRIO, TEST.EGG, at rest in Basic mode). Before and after are identical except lamp 0x33, BASIC, which goes from 14 dim to 3c lit. The preset lamps are unchanged: they worked by accident, and now work by construction. docs/CONTROL-PRESETS.md is the research behind it. The presets are not a map feature at all - each is a complete factory layout for the four mappable stick buttons, one mode-mask bit apiece, with all 26 vehicles carrying their own six-preset table in RPL4.RES for both the pod RIO and the Thrustmaster. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+84
-43
@@ -725,6 +725,13 @@ void
|
||||
mode_manager->AddModeMask(previousPresetModeMask);
|
||||
}
|
||||
//-----------------------------------
|
||||
// Move the lamps with the mappings.
|
||||
// Doing it here rather than in the
|
||||
// switch handler keeps the keyboard
|
||||
// presets (1-6) in step as well.
|
||||
//-----------------------------------
|
||||
NotifyOfPresetChange(previousPresetNumber, preset_number);
|
||||
//-----------------------------------
|
||||
// Save the new preset number
|
||||
//-----------------------------------
|
||||
previousPresetNumber = preset_number;
|
||||
@@ -733,6 +740,19 @@ void
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
//
|
||||
void
|
||||
L4VTVControlsMapper::NotifyOfPresetChange(
|
||||
int /*old_preset*/,
|
||||
int /*new_preset*/
|
||||
)
|
||||
{
|
||||
Check(this);
|
||||
// The base mapper has no preset lamps to move.
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
//########################### ThrustmasterMapper ##############################
|
||||
//#############################################################################
|
||||
@@ -1400,45 +1420,13 @@ void
|
||||
if (message->dataContents > 0)
|
||||
{
|
||||
//-----------------------------------
|
||||
// Choose a new preset
|
||||
// Choose a new preset. PresetEnable
|
||||
// ignores a repeat of the lit switch
|
||||
// and moves the lamps itself.
|
||||
//-----------------------------------
|
||||
int
|
||||
current_preset_number = (message->dataContents - 1)
|
||||
- LBE4ControlsManager::ButtonSecondary7;
|
||||
|
||||
if (previousPresetNumber != current_preset_number)
|
||||
{
|
||||
//-----------------------------------
|
||||
// Set the old preset lamp to 'dim'
|
||||
//-----------------------------------
|
||||
if (previousPresetNumber >= 0)
|
||||
{
|
||||
Verify(previousPresetNumber < presetCount);
|
||||
|
||||
if (modeLamp[previousPresetNumber] != NULL)
|
||||
{
|
||||
Check(modeLamp[previousPresetNumber]);
|
||||
modeLamp[previousPresetNumber]->SetState(L4Lamp::LampStateDim);
|
||||
}
|
||||
}
|
||||
//-----------------------------------
|
||||
// Set the new preset lamp to 'on'
|
||||
//-----------------------------------
|
||||
if (current_preset_number >= 0)
|
||||
{
|
||||
Verify(current_preset_number < presetCount);
|
||||
|
||||
if (modeLamp[current_preset_number] != NULL)
|
||||
{
|
||||
Check(modeLamp[current_preset_number]);
|
||||
modeLamp[current_preset_number]->SetState(L4Lamp::LampStateOn);
|
||||
}
|
||||
}
|
||||
//-----------------------------------
|
||||
// Change presets
|
||||
//-----------------------------------
|
||||
PresetEnable(current_preset_number);
|
||||
}
|
||||
PresetEnable(
|
||||
(message->dataContents - 1) - LBE4ControlsManager::ButtonSecondary7
|
||||
);
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
@@ -1655,6 +1643,44 @@ void
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// The six amber switches down the map's right flank. Called by PresetEnable,
|
||||
// so the lamps follow the mappings no matter what asked for the change.
|
||||
//
|
||||
void
|
||||
VTVRIOMapper::NotifyOfPresetChange(int old_preset, int new_preset)
|
||||
{
|
||||
Check(this);
|
||||
|
||||
//----------------------------------
|
||||
// Set the old preset lamp to 'dim'
|
||||
//----------------------------------
|
||||
if (old_preset >= 0)
|
||||
{
|
||||
Verify(old_preset < presetCount);
|
||||
|
||||
if (presetLamp[old_preset] != NULL)
|
||||
{
|
||||
Check(presetLamp[old_preset]);
|
||||
presetLamp[old_preset]->SetState(L4Lamp::LampStateDim);
|
||||
}
|
||||
}
|
||||
//----------------------------------
|
||||
// Set the new preset lamp to 'on'
|
||||
//----------------------------------
|
||||
if (new_preset >= 0)
|
||||
{
|
||||
Verify(new_preset < presetCount);
|
||||
|
||||
if (presetLamp[new_preset] != NULL)
|
||||
{
|
||||
Check(presetLamp[new_preset]);
|
||||
presetLamp[new_preset]->SetState(L4Lamp::LampStateOn);
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
//#############################################################################
|
||||
// Construction and Destruction Support
|
||||
//
|
||||
@@ -1680,6 +1706,20 @@ VTVRIOMapper::VTVRIOMapper(
|
||||
leftPedal = 0.0f;
|
||||
rightPedal = 0.0f;
|
||||
|
||||
//------------------------------------------------
|
||||
// There are no lamps until the mapping blocks
|
||||
// below make them - and under NOMODES they never
|
||||
// do, so the notify methods must see NULLs.
|
||||
//------------------------------------------------
|
||||
{
|
||||
int
|
||||
i;
|
||||
|
||||
for(i=0; i<configLampCount; ++i) configLamp[i] = NULL;
|
||||
for(i=0; i<modeLampCount; ++i) modeLamp[i] = NULL;
|
||||
for(i=0; i<presetCount; ++i) presetLamp[i] = NULL;
|
||||
}
|
||||
|
||||
Check(application);
|
||||
LBE4ControlsManager
|
||||
*controls = Cast_Object(
|
||||
@@ -1915,13 +1955,14 @@ VTVRIOMapper::VTVRIOMapper(
|
||||
this
|
||||
);
|
||||
|
||||
// These lamps are explicitly controlled by SelectPresetMessageHandler
|
||||
modeLamp[i] = CreateControlledLamp(button_number[i]);
|
||||
// These lamps are explicitly controlled by NotifyOfPresetChange.
|
||||
// They are six, and they are NOT the four mode lamps above.
|
||||
presetLamp[i] = CreateControlledLamp(button_number[i]);
|
||||
|
||||
if (modeLamp[i] != NULL)
|
||||
if (presetLamp[i] != NULL)
|
||||
{
|
||||
Check(modeLamp[i]);
|
||||
modeLamp[i]->SetState(
|
||||
Check(presetLamp[i]);
|
||||
presetLamp[i]->SetState(
|
||||
(i==0)? L4Lamp::LampStateOn : L4Lamp::LampStateDim
|
||||
);
|
||||
}
|
||||
|
||||
@@ -104,6 +104,12 @@ ModeMask
|
||||
//
|
||||
void
|
||||
PresetEnable(int preset_number);
|
||||
|
||||
// Announced by PresetEnable for EVERY preset change, whichever way it was
|
||||
// triggered - map-flank switch or keyboard. Platforms carrying preset
|
||||
// lamps move them here; the base mapper has none.
|
||||
virtual void
|
||||
NotifyOfPresetChange(int old_preset, int new_preset);
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Protected data
|
||||
//
|
||||
@@ -250,6 +256,9 @@ public:
|
||||
void
|
||||
NotifyOfConfigurationModeChange(Logical new_state);
|
||||
|
||||
void
|
||||
NotifyOfPresetChange(int old_preset, int new_preset);
|
||||
|
||||
void
|
||||
SetPerformance(Performance performance)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
# Red Planet — the six control presets on the map screen
|
||||
|
||||
The six amber buttons down the right flank of the map display, labelled
|
||||
PRESET 1 … PRESET 6 on the glass itself. They are not a display option and
|
||||
they do not touch the map: **each one is a complete factory layout for the
|
||||
four mappable joystick buttons**, authored per vehicle and shipped in
|
||||
`RPL4.RES`. Pressing one swaps the whole stick over, live, mid-race.
|
||||
|
||||
```
|
||||
map glass, right flank (vRIO 0x18..0x1D, amber)
|
||||
┌──────────────┐
|
||||
│ PRESET 1 ● │ Secondary7 press
|
||||
│ PRESET 2 ○ │ Secondary8 │
|
||||
│ PRESET 3 ○ │ Secondary9 ▼
|
||||
│ PRESET 4 ○ │ Secondary10 VTVRIOMapper::SelectPresetMessageHandler
|
||||
│ PRESET 5 ○ │ Secondary11 │ (keyboard 1-6 joins here)
|
||||
│ PRESET 6 ○ │ Secondary12 ▼
|
||||
└──────────────┘ L4VTVControlsMapper::PresetEnable(n)
|
||||
├─ remove old ModePresetN from the
|
||||
│ mode manager, add the new one
|
||||
│ │
|
||||
│ ▼
|
||||
│ every control mapping whose modeMask
|
||||
│ carries that bit goes live; the other
|
||||
│ five presets' mappings go dead
|
||||
│
|
||||
└─ NotifyOfPresetChange(old, new)
|
||||
▼
|
||||
lamp old→dim, new→on
|
||||
```
|
||||
|
||||
## 1. What the player sees
|
||||
|
||||
The map is the pod's portrait-mounted secondary monitor. Its gauge group
|
||||
paints the button legends itself — `tags` in
|
||||
`assets/RP411/GAUGE/L4GAUGE.CFG:1611`, six 16×102 strips at x=464:
|
||||
|
||||
| legend | file | cell |
|
||||
|---|---|---|
|
||||
| PRESET 1 … PRESET 6 | `butpres1.pcc` … `butpres6.pcc` | one per legend cell down the right edge |
|
||||
| ZOOM + / ZOOM − / reticle / HORN | `butzmin`, `butzmout`, `butcross`, `buthorn` | left edge, top four cells |
|
||||
|
||||
The legend grid is not `height/6`: the first cell starts 13 rows down and
|
||||
the six cells are 102 tall on a 105 pitch (13 + 6×102 + 5×3 = 640). vRIO's
|
||||
`MFDSplitView::LayoutButtons` scales exactly that grid so each on-screen
|
||||
button lands against its own painted label
|
||||
(`MUNGA_L4/L4MFDVIEW.cpp:683`, constants at `:103`).
|
||||
|
||||
Addresses run **down** each column from the anchor — the map view is
|
||||
created with `SideColumns, 0x10, 0x18` (`MUNGA_L4/L4VB16.cpp:4450`), so the
|
||||
left column is Secondary1…6 top-to-bottom and the right column is
|
||||
Secondary7…12, i.e. **PRESET 1 is the top button, PRESET 6 the bottom**.
|
||||
That ordering is confirmed by the left column, where the code binds
|
||||
Secondary1→zoom in, 2→zoom out, 3→reticle, 4→horn
|
||||
(`RP_L4/RPL4MPPR.cpp:1857`) and the artwork paints ZOOM+/ZOOM−/cross/HORN
|
||||
in exactly that order, leaving the bottom two cells blank — the pod wires
|
||||
only 6 of each column's 8 addresses; 0x16/0x17 and 0x1E/0x1F are Tesla
|
||||
relays (`MUNGA_L4/L4CTRL.cpp:1901`).
|
||||
|
||||
Preset 1 is lit at construction, the other five dim
|
||||
(`RP_L4/RPL4MPPR.cpp:1962`). These six lamps are driven explicitly by
|
||||
`NotifyOfPresetChange`; unlike most panel lamps they are not linked to
|
||||
their button's mapping state (`SetAutomaticOperation(False)` in
|
||||
`CreateControlledLamp`, `RP_L4/RPL4MPPR.cpp:47`).
|
||||
|
||||
## 2. The mechanism — a preset is a mode-mask bit
|
||||
|
||||
The engine gates every control mapping behind a `ModeMask`. RP adds six
|
||||
bits purely for this (`RP_L4/RPL4MODE.h:30`, `nextModeBit` = 0 so the
|
||||
values are literal):
|
||||
|
||||
| mode | bit | value |
|
||||
|---|---|---|
|
||||
| ModeNonConfig / ConfigReady / ConfigOn | 0–2 | 0x001 / 0x002 / 0x004 |
|
||||
| **ModePreset1 … ModePreset6** | **3–8** | **0x008 … 0x100** |
|
||||
| ModeBasic / ModeStandard / ModeIntercom | 9–11 | 0x200 / 0x400 / 0x800 |
|
||||
|
||||
`PresetEnable` (`RP_L4/RPL4MPPR.cpp:685`) does one thing: removes the
|
||||
outgoing preset's bit from the application mode manager and adds the
|
||||
incoming one. `ControlsUpdateManager::Update` then only dispatches
|
||||
instances whose `modeMask` intersects the live mask
|
||||
(`MUNGA/CONTROLS.h:599` shows the same test in `GetMapState`), so five
|
||||
sixths of the authored stick mappings are simply invisible at any moment.
|
||||
|
||||
Consequences that fall out of that design:
|
||||
|
||||
- Presets cost nothing to switch — no rebuild, no allocation, one mask word.
|
||||
- They are exactly six because there are six switches: `presetCount = 6 //
|
||||
limited to number of switches!` (`RP_L4/RPL4MPPR.h:119`).
|
||||
- Nothing *but* control mappings is preset-scoped. No gauge, bitmap or
|
||||
strip in `L4GAUGE.CFG` references `ModePreset*` — the mode names exist
|
||||
in the lookup table (`RP_L4/RPL4MODE.cpp:23`) only so the resource
|
||||
compiler can resolve them in the control-mapping source.
|
||||
- Entering configuration state drops all six (`ModeAllNonConfig`) and
|
||||
restores the previously selected one on exit
|
||||
(`RP_L4/RPL4MPPR.cpp:483`).
|
||||
|
||||
Keyboard `1`–`6` calls `PresetEnable` directly
|
||||
(`RP_L4/RPL4MPPR.cpp:1048`), the same entry point the flank switches use.
|
||||
Both paths therefore move the lamps, because `PresetEnable` announces the
|
||||
change itself through the virtual `NotifyOfPresetChange` (`:733`) rather
|
||||
than leaving it to the switch handler — see §7.
|
||||
|
||||
## 3. What is actually in a preset
|
||||
|
||||
Only the four mappable stick buttons are ever preset-scoped —
|
||||
`FirstMappableButton`…`LastMappableButton` minus the hat
|
||||
(`MUNGA_L4/L4CTRL.h:497`):
|
||||
|
||||
| element | button |
|
||||
|---|---|
|
||||
| 0x40 | trigger |
|
||||
| 0x45 | pinky |
|
||||
| 0x46 | thumb low |
|
||||
| 0x47 | thumb high (by the hat) |
|
||||
|
||||
Everything else — throttle, pedals, stick axes, hat, the whole aux panel —
|
||||
is bound `ModeAlwaysActive` or `ModeNonConfig` and is identical in all six
|
||||
presets. The functions that can land on a stick button are the ones that
|
||||
also have a panel button and a "configure" partner: booster fire, chute,
|
||||
weapon trigger, LIFT CUT, SIDESLIP, HORN, and intercom PTT
|
||||
(`RP/VTVMPPR.cpp:144`, `RP/BOOSTER.cpp:50`, `RP/CHUTE.cpp:48`,
|
||||
`RP/WEAPSYS.cpp:103`).
|
||||
|
||||
## 4. The shipped tables
|
||||
|
||||
The mappings are streamed from the vehicle resource at mission start —
|
||||
`LBE4ControlsManager::CreateStreamedMappings`
|
||||
(`MUNGA_L4/L4CTRL.cpp:2153`), fed from the entity's ControlMappings list
|
||||
resource by name: `"L4"` for the pod RIO, `"Thrustmaster"` for the stick
|
||||
(`RP_L4/RPL4APP.cpp:761`). Each record is a `ControlsMapping`
|
||||
(`MUNGA/CONTROLS.h:783`) carrying its own mode mask, so a single button can
|
||||
appear six times with six different targets.
|
||||
|
||||
**All 26 VTVs in `assets/RP411/RPL4.RES` ship a full six-preset table, for
|
||||
both the RIO and the Thrustmaster.** Decoded, the *lepton* (two boosters,
|
||||
one chute, unarmed) reads:
|
||||
|
||||
| | trigger | pinky | thumb low | thumb high |
|
||||
|---|---|---|---|---|
|
||||
| PRESET 1 | booster 1 | **PTT** | chute | booster 2 |
|
||||
| PRESET 2 | booster 1 | **LIFT CUT** | chute | booster 2 |
|
||||
| PRESET 3 | booster 1 | PTT | **LIFT CUT** | booster 2 |
|
||||
| PRESET 4 | booster 1 | chute | LIFT CUT | booster 2 |
|
||||
| PRESET 5 | booster 1 | LIFT CUT | **HORN** | booster 2 |
|
||||
| PRESET 6 | **LIFT CUT** | chute | booster 2 | booster 1 |
|
||||
|
||||
An armed vehicle substitutes the weapon trigger for the primary booster.
|
||||
The *puck* (one booster, laser):
|
||||
|
||||
| | trigger | pinky | thumb low | thumb high |
|
||||
|---|---|---|---|---|
|
||||
| PRESET 1 | laser | — | HORN | booster |
|
||||
| PRESET 2 | laser | LIFT CUT | HORN | booster |
|
||||
| PRESET 3 | laser | — | LIFT CUT | booster |
|
||||
| PRESET 4 | laser | HORN | LIFT CUT | booster |
|
||||
| PRESET 5 | laser | LIFT CUT | HORN | booster |
|
||||
| PRESET 6 | **LIFT CUT** | laser | — | booster |
|
||||
|
||||
The authored intent is consistent across every vehicle in the file:
|
||||
|
||||
1. **Presets 1–5 keep the primary weapon (or lead booster) on the
|
||||
trigger** and shuffle the *secondary* duties — where LIFT CUT lives,
|
||||
whether the stick carries PTT or HORN, and whether the chute/third
|
||||
system stays on the stick at all.
|
||||
2. **Preset 2 always puts LIFT CUT on the pinky** and **preset 6 always
|
||||
puts LIFT CUT on the trigger** — verified true for all 26 tables.
|
||||
Preset 6 is the outlier layout: everything shifts up a finger and the
|
||||
trigger becomes a handling control rather than a fire control.
|
||||
3. Vehicles carrying fewer systems leave cells empty, and some presets then
|
||||
collapse into duplicates — on the puck, presets 2 and 5 are identical.
|
||||
4. Heavily armed vehicles spend the freed cells on second and third
|
||||
weapons instead of HORN (bttlbrg, gator, roadblk).
|
||||
|
||||
## 5. Editing the active preset in flight
|
||||
|
||||
The presets are also the storage for in-mission rebinding. With the CFG
|
||||
button on the upper-right MFD (`AuxUpperRight1/2`, registered under
|
||||
`ModeStandard` — `RP_L4/RPL4MPPR.cpp:1826`), the pod enters configuration
|
||||
state: the aux strips swap their legends from tool art to SET art
|
||||
(`strptol1/2.pcc` → `strpset1/2.pcc`, `L4GAUGE.CFG:715`), and every
|
||||
mappable button gets a temporary mapping to the chosen system's "choose"
|
||||
message (`RP_L4/RPL4MPPR.cpp:604`). Pressing a panel button arms a
|
||||
function; pressing a stick button toggles it via `AddOrErase`, which
|
||||
writes against **`previousPresetModeMask`** — the currently selected
|
||||
preset, and only that one (`RP_L4/RPL4MPPR.cpp:1538`).
|
||||
|
||||
The `configMap` gauge on that display (`RPL4GAUG.cpp:3199`, placed at
|
||||
`L4GAUGE.CFG:749`) shows the state of all four stick buttons against the
|
||||
armed function, one icon each, using the same preset mask:
|
||||
`cfgNone` / `cfgOther` / `cfgMe` / `cfgBoth` for
|
||||
`unmapped` / `mappedByOthers` / `mappedByMe` / both
|
||||
(`MUNGA/CONTROLS.h:315`).
|
||||
|
||||
Configuration is unavailable in Basic control mode — the CFG button and the
|
||||
`configMap` gauge are both `ModeStandard`, which is set by Standard,
|
||||
Veteran and Master but cleared by Basic (`RP_L4/RPL4MPPR.cpp:374`).
|
||||
|
||||
**Nothing is persisted.** Edits live in the `ControlsMappingGroup` chains
|
||||
for the mission only; no code writes mappings back to disk, and the next
|
||||
mission re-streams the authored table from `RPL4.RES`. (Porting a real
|
||||
bindings file is still open — see the roadmap's Workstream A.)
|
||||
|
||||
## 6. The preset number goes out on the wire
|
||||
|
||||
`PresetEnable` sets `mustMatch = preset_number` unconditionally, before the
|
||||
early-out, tagged `HACK - for backward watcher compatibility`
|
||||
(`RP_L4/RPL4MPPR.cpp:700`). `mustMatch` is a replicated attribute of the
|
||||
mapper (`RP/VTVMPPR.cpp:384`), so a watcher/spectator station sees which
|
||||
preset a pilot is on. It is the only preset state that leaves the machine.
|
||||
|
||||
## 7. Defects found while reading
|
||||
|
||||
**Fixed (2026-08-06):** both lamp defects below.
|
||||
|
||||
1. **The preset loop wrote past `modeLamp`.** `modeLampCount` is 4, but the
|
||||
preset pass stored six lamps into `modeLamp[i]`, i = 0…5. The members
|
||||
are declared `configLamp[2], modeLamp[4], presetLamp[6]` in that order
|
||||
(`RP_L4/RPL4MPPR.h:312`), so indices 4 and 5 landed in
|
||||
`presetLamp[0..1]` and the whole thing was self-consistent by memory
|
||||
layout — the preset press handler read the same out-of-range slots.
|
||||
Two real consequences: an out-of-bounds write, and it **destroyed the
|
||||
four control-mode lamps** created immediately above (`:1921`), so
|
||||
`NotifyOfControlModeChange` drove PRESET 1–4's lamps on the map flank
|
||||
and the Basic/Standard/Veteran/Master lamps on the upper-right MFD were
|
||||
never lit at all. `presetLamp[]` was meanwhile never populated or read.
|
||||
The preset pass now fills `presetLamp[]` (`:1960`), which is what the
|
||||
array was always for.
|
||||
2. **Keyboard preset switching desynchronized the lamps.** The lamp work
|
||||
lived in `SelectPresetMessageHandler`, so only the flank switches moved
|
||||
the lamps and keyboard `1`–`6` left the wrong one lit. It now lives in
|
||||
the virtual `NotifyOfPresetChange`, announced by `PresetEnable` itself
|
||||
(`:733`) — one place, every path. `VTVRIOMapper` overrides it to move
|
||||
the six flank lamps (`:1651`); the base mapper and the Thrustmaster
|
||||
mapper have no preset lamps and inherit the no-op (`:746`).
|
||||
|
||||
Verified by reading the commanded RIO lamp states out of the running
|
||||
game (`PadRIO::lampState`, PadRIO + `TEST.EGG`, at rest in Basic mode).
|
||||
Before and after are byte-identical except for lamp 0x33:
|
||||
|
||||
| lamps | before | after |
|
||||
|---|---|---|
|
||||
| 0x18 PRESET 1 / 0x19–0x1D PRESET 2–6 | 3c / 14 | 3c / 14 |
|
||||
| 0x30–0x32 MASTER/VETERAN/STANDARD | 14 | 14 |
|
||||
| **0x33 BASIC** | **14 (dim — never lit)** | **3c (lit)** |
|
||||
|
||||
Still open, by design rather than by accident: `PresetEnable` early-outs on
|
||||
`preset_number == previousPresetNumber`, so re-pressing the lit switch is a
|
||||
no-op. Correct for switching, but it also means a preset can never be used
|
||||
as a "reset to authored bindings" after the player has edited it in
|
||||
configuration mode.
|
||||
Reference in New Issue
Block a user