diff --git a/engine/MUNGA_L4/L4GLASSWIN.cpp b/engine/MUNGA_L4/L4GLASSWIN.cpp index de29d73..dd3e660 100644 --- a/engine/MUNGA_L4/L4GLASSWIN.cpp +++ b/engine/MUNGA_L4/L4GLASSWIN.cpp @@ -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) { diff --git a/game/reconstructed/projweap.cpp b/game/reconstructed/projweap.cpp index d3a98c7..d8249df 100644 --- a/game/reconstructed/projweap.cpp +++ b/game/reconstructed/projweap.cpp @@ -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)