Issue #19: wire ToggleSeekVoltage (Myomers id 9 + energy weapons id 0xb)

Root cause -- NOT issue #2 (the experience mis-seed pins everyone to VETERAN,
which PASSES the novice lockout; the gates were never the blocker).  Two
unwired handlers, the same silent-swallow pattern ToggleCooling had
(Receiver::Receive -> NullHandler for an unregistered id):

- Myomers (handler table @0x51158C {9,"ToggleSeekVoltage"@004b8a48}): the
  reconstruction had an EMPTY stub (the address falls in the untagged decomp
  gap 0x4b8837..0x4b8a8c) and never registered the id.  Body reconstructed
  faithfully from the raw disassembly (tools/disas2.py 0x4b8a48): novice
  lockout (@4ac9c8) -> heat-model gate (@4ad7d4) -> press-only (msg+0xc>0) ->
  currentSeekVoltageIndex@0x320 = (idx+1) % (maxSeekVoltageIndex@0x32C + 1).
  Modulo from zero, min index not consulted, no ResetFiringState.

- Emitter (energy-weapon table @0x511DB8 {0xb,"ToggleSeekVoltage"@004ba478}):
  the faithful body already existed as the orphaned "AdvanceSeekVoltage"
  (ZERO callers) -- converted to the registered message handler (same guards;
  cycle + ResetFiringState when not wrapping, disasm re-verified).  PPC and
  GaussRifle copy-inherit the set; the ammo branch keeps its own id 0xb ==
  EjectAmmo (still unwired, tracked separately).

Both registered via MESSAGE_ENTRY on top of the inherited chains.  Permanent
diagnostics: [seek] gear log (BT_SEEK_LOG) + BT_SEEKTEST scripted dispatch
harness (mech4.cpp, the cooltoggle pattern).

VERIFIED headless: [seek] Myomers -> 3,0,1,2,3... and [seek] PPC_1 ->
3,0,1,2,3... (modulo-4 wrap, matching the binary's arithmetic).  Awaiting
the tester's live ADV-mode confirmation for the real MFD button route (the
routing layer is the same streamed-EventMapping path ToggleCooling verified).

KB: decomp-reference.md message-table rows marked wired.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-21 12:57:18 -05:00
co-authored by Claude Opus 4.8
parent c18d2b0213
commit 4aab10ba89
6 changed files with 133 additions and 28 deletions
+41
View File
@@ -5613,6 +5613,47 @@ void
}
}
// issue #19 verify (BT_SEEKTEST): dispatch the seek-gear messages every
// ~2s -- ToggleSeekVoltage id 9 to Myomers (0xBC6) and id 0xb to the
// first ENERGY weapon (Emitter 0xBC8 / GaussRifle 0xBCE / PPC 0xBD4;
// NOT the ammo branch, whose id 0xb is EjectAmmo). BT_SEEK_LOG shows
// the gear cycling.
if (getenv("BT_SEEKTEST") && (Entity *)this == application->GetViewpointEntity())
{
static int s_seekTest = 0;
if ((++s_seekTest % 120) == 0)
{
int sentMyo = 0, sentWpn = 0;
for (int s = 1; s < GetSubsystemCount(); ++s)
{
Subsystem *sub = GetSubsystem(s);
if (sub == 0)
continue;
int cid = (int)sub->GetClassID();
if (!sentMyo && cid == 0xBC6)
{
ReceiverDataMessageOf<ControlsButton> msg(
9 /*Myomers::ToggleSeekVoltageMessageID*/,
sizeof(ReceiverDataMessageOf<ControlsButton>),
(ControlsButton)1 /*press*/);
sub->Dispatch(&msg);
sentMyo = 1;
}
else if (!sentWpn && (cid == 0xBC8 || cid == 0xBCE || cid == 0xBD4))
{
ReceiverDataMessageOf<ControlsButton> msg(
0x0b /*Emitter::ToggleSeekVoltageMessageID*/,
sizeof(ReceiverDataMessageOf<ControlsButton>),
(ControlsButton)1 /*press*/);
sub->Dispatch(&msg);
sentWpn = 1;
}
if (sentMyo && sentWpn)
break;
}
}
}
// task #6 dev harness: the config-session BRACKET. 'G' edge ->
// dispatch ConfigureMappables (id 9) press/release to the selected
// weapon -- the exact ReceiverDataMessageOf<ControlsButton> payload