#166 mechanism pinned + two input-layer fixes: Oracle's LRM jam = the ammo bin PARKED at Ejecting(3) with rounds aboard (his log: 'NoAmmo (gate2): rounds=18 binState=3', twice; eject tap cleared it exactly as the handler predicts). The MFD/HUD 'desync' is honest: the full green circle is the RECHARGE dial (untouched by the gate2 pin) and the btejam lamp keys only on weaponAlarm 5 (binary @004c9a38) -- state-7 pins show neither, authentically. The parking producer needs an unpaired eject PRESS, which pod hardware cannot make but our glass mouse layer could: (1) WM_CAPTURECHANGED now releases a held panel button when capture is stolen (Steam overlay/popups ate the WM_LBUTTONUP), (2) a new press releases any still-held previous button instead of orphaning it. Forensics: every EJECT message now logs data/bin/ejectState/binState/rounds always-on (ejects are rare) -- Friday names the producer if it recurs. Smoke: BT_EJECTTEST replays the full press/hold/dump receipt chain incl. the authentic mid-eject gate2 pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-11 16:45:12 -05:00
co-authored by Claude Fable 5
parent 18fba98298
commit 14c62f184d
2 changed files with 35 additions and 0 deletions
+23
View File
@@ -1768,6 +1768,14 @@ static LRESULT CALLBACK
}
else
{
// #166: a press must never ORPHAN a previous one -- if a
// prior button is still logically down (capture stolen by
// an overlay/popup so its WM_LBUTTONUP never arrived),
// release it before pressing the new one. An orphaned
// press on the ammo-EJECT panel button is a permanent
// weapon jam (bin parked at Ejecting).
if (pressedAddress >= 0 && pressedAddress != a)
PadRIO::SetScreenButton(pressedAddress, 0);
pressedAddress = a;
SetCapture(window);
PadRIO::SetScreenButton(a, 1);
@@ -1787,6 +1795,21 @@ static LRESULT CALLBACK
}
return 0;
case WM_CAPTURECHANGED:
// #166: mouse capture stolen mid-press (Steam overlay, popups, focus
// change) -- WM_LBUTTONUP will never arrive, so release the held
// button NOW instead of leaving its control (e.g. ammo EJECT) pressed
// forever from the game's point of view.
if (pressedAddress >= 0)
{
DEBUG_STREAM << "[glasswin] capture LOST with button 0x" << std::hex
<< pressedAddress << std::dec << " down -- releasing\n" << std::flush;
PadRIO::SetScreenButton(pressedAddress, 0);
pressedAddress = -1;
InvalidateRect(window, NULL, FALSE);
}
return 0;
case WM_RBUTTONDOWN:
if (w != NULL)
{
+12
View File
@@ -579,6 +579,18 @@ void
AmmoBin *bin = (AmmoBin*)ammoBinLink.Resolve(); // FUN_00417ab4(this+0x43c)
// #166 forensics (ALWAYS on -- ejects are rare): every entry, with the
// state that decides which branch runs. Oracle's field jam (bin parked
// at Ejecting(3), rounds aboard, countdown dead) can only come from a
// press/release sequence this line will capture -- the prime suspect is
// a press whose bin-resolve fails falling through to the release block.
DEBUG_STREAM << "[weap] " << GetName() << " EJECT msg data=" << message->dataContents
<< " bin=" << (void *)bin
<< " ejectState=" << ejectState
<< " binState=" << (bin != 0 ? bin->GetAmmoState() : -1)
<< " rounds=" << (bin != 0 ? bin->GetAmmoCount() : -1)
<< "\n" << std::flush;
if (message->dataContents > 0 && bin != 0) // PRESS @4bb9d0/4bb9e9
{
bin->SetAmmoState(AmmoBin::Ejecting); // SetLevel(bin+0x194, 3)