CORRECTION: EJECT tap IS the in-mission unjam (EjectAmmo @004bb9b8 decoded)

Old-timer testimony (tap = eject one round, hold = eject the bay, eject
clears a jam) checked against the binary: raw disasm of the export-gap
handler @004bb9b8 confirms it byte-for-byte.  PRESS arms the ~3s
UpdateEject countdown (hold-to-completion = DumpAmmo whole bay ->
NoAmmo); RELEASE before completion (TAP) ejects ONE round (@004bd4f4)
and, with ammo remaining, sets weaponAlarm 3 + restarts the reload --
the weapon returns to service.  A tap even recovers a FailureHeat
level-7 launcher while rounds remain (empty-bin gate 2 re-pins 7 only
when the bay is dry).

The earlier 'jams are mission-permanent / no unjam exists' claim read
only the HOLD path -- corrected + swept: projweap.cpp case-5/jam-log/
CheckForJam comments, players/README.txt, decomp-reference.md
(message-tables entry), open-questions.md (state-7 recovery note).
Gitea #31 updated; wiring the handler now restores the pod's actual
jam-recovery mechanic.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-23 12:21:06 -05:00
co-authored by Claude Opus 4.8
parent a999e5c49f
commit 225fe43f0c
4 changed files with 39 additions and 15 deletions
+15 -11
View File
@@ -551,8 +551,11 @@ Logical
// so gate the roll on the weapon actually being in a degraded HEAT STATE (heatAlarm
// level >= 1) instead of the raw heatLoad. In bring-up the alarm stays 0 (temp <<
// degradation threshold) -> weapons fire reliably; real jams return once the heat model
// drives true temps. (The old FOLLOW-UP suggesting an "unjam delay" is RETIRED --
// 2026-07-23 decomp check: the binary has NO in-mission unjam; permanence is authentic.)
// drives true temps. (2026-07-23 CORRECTION, 2nd pass: an in-mission unjam DOES
// exist -- the EjectAmmo handler @004bb9b8 (msg 0xb, TAP = eject one round ->
// weaponAlarm 3 Loading + reload restart). The earlier "no unjam" claim read only
// the HOLD path (UpdateEject -> DumpAmmo -> NoAmmo); the tap path sat in a decomp
// export gap. Old-timer testimony matched the bytes: tap = round, hold = bay.)
if (heatAlarm.GetLevel() < HeatSink::DegradationHeat) // was: if (heatLoad <= 0.0f)
return False;
@@ -710,11 +713,11 @@ void
weaponAlarm.SetLevel(7); // -> unavailable (gate 2 re-pins it)
else if (CheckForJam()) // @4bbf2a call 0x4bbfcc (heat-scaled roll)
{
// ALWAYS log a jam (rare + mission-permanent; field 2026-07-23)
// ALWAYS log a jam (rare; cleared by an EJECT tap -- @004bb9b8)
DEBUG_STREAM << "[weap] " << GetName() << " JAMMED (T="
<< currentTemperature << "/" << failureTemperature
<< " heatAlarm=" << (int)heatAlarm.GetLevel()
<< ") -- permanent until mission end\n" << std::flush;
<< ") -- EJECT tap to clear\n" << std::flush;
weaponAlarm.SetLevel(JammedState); // @4bbf34 -> 5
}
else
@@ -775,13 +778,14 @@ void
// -- the recharge dial ANIMATES
break;
case 5: // Jammed @4bbe8e -- cleared ONLY by ResetToInitialState (mission
// reset/respawn). ⚠ CORRECTED 2026-07-23: msg 2 CAUSES a jam
// (HandleMessage @004bcabc: SetLevel(this+0x350, 5) -- a
// malfunction inducer), it does NOT clear one; the old comment
// had it backwards. There is NO in-mission unjam in the
// binary -- the EJECT cycle (UpdateEject) is the anti-cook-off
// ammo JETTISON (DumpAmmo -> NoAmmo), not an unjam.
case 5: // Jammed @4bbe8e. Within THIS state machine nothing exits 5, but
// the EJECT button does (⚠ 2nd CORRECTION 2026-07-23, disasm of the
// export-gap handler @004bb9b8, msg 0xb EjectAmmo, novice-guarded):
// TAP (press then release) ejects ONE round (@4bd4f4 count--) and,
// with ammo remaining, SetLevel(+0x350, 3) + reload restart -- the
// weapon RETURNS TO SERVICE. HOLD ~3s runs UpdateEject to DumpAmmo
// (whole bay -> NoAmmo 7). So: tap = unjam, hold = jettison the bay
// (anti-cook-off). msg 2 still CAUSES a jam (@004bcabc inducer).
if (trigger)
{
weaponAlarm.SetLevel(TriggerDuringJamState); // @4bbe95 blip 6