Issue #31: wire the EJECT button (EjectAmmo msg 0xb @004bb9b8) -- the in-mission unjam
Disasm-faithful transcription of the export-gap handler onto ProjectileWeapon (MESSAGE_ENTRY id 0xb, the #19 pattern). PRESS arms the ~3s UpdateEject countdown (bin alarm -> Ejecting(3); gate 2 parks the weapon offline mid-eject -- authentic). HOLD to completion = DumpAmmo jettisons the bay -> NoAmmo. TAP (release early) cycles ONE round out via FeedAmmo and returns the weapon to Loading -- clears a jam at the cost of a round (and recovers a FailureHeat 7 while rounds remain). Binary structure kept exactly incl. the press-no-bin fall-through into the release block. AmmoBin: Ejecting(3)/Ejected(4) alarm levels decoded + named SetAmmoState accessor (databinding rule). Always-on forensics: '[weap] EJECT tap' + '[ammo] bay DUMPED overboard (N rounds)'. Rig-verified live (BT_EJECTTEST=1 / =hold on LRM15): taps eject one round each and return the weapon to service (15->8 across cycles); hold dumps all 16 -> NoAmmo. Awaiting a human press of the actual ENG-page button on a jammed weapon. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
225fe43f0c
commit
2edd1b5363
@@ -169,11 +169,21 @@ Derivation
|
||||
);
|
||||
|
||||
// task #6: inherit MechWeapon's handler set (see emitter.cpp note).
|
||||
// issue #31 (2026-07-23): register the ammo-weapon handler table @0x512210
|
||||
// {0xb, "EjectAmmo" -> @004bb9b8} on top of MechWeapon's ids 9/10 -- the pod's
|
||||
// EJECT button (tap = eject one round / unjam, hold = jettison the bay) was
|
||||
// silently swallowed. (The energy-weapon branch binds 0xb to ToggleSeekVoltage
|
||||
// in ITS table instead -- see emitter.cpp.)
|
||||
Receiver::MessageHandlerSet&
|
||||
ProjectileWeapon::GetMessageHandlers()
|
||||
{
|
||||
static const Receiver::HandlerEntry entries[]=
|
||||
{
|
||||
MESSAGE_ENTRY(ProjectileWeapon, EjectAmmo) // id 0xb @004bb9b8
|
||||
};
|
||||
static Receiver::MessageHandlerSet messageHandlers(
|
||||
MechWeapon::GetMessageHandlers()); // copy-inherit
|
||||
ELEMENTS(entries), entries,
|
||||
MechWeapon::GetMessageHandlers()); // copy-inherit (ids 9/10)
|
||||
return messageHandlers;
|
||||
}
|
||||
Simulation::AttributeIndexSet ProjectileWeapon::AttributeIndex;
|
||||
@@ -495,6 +505,63 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @004bb9b8 -- the EJECT button (ammo-weapon handler table @0x512210, id 0xb).
|
||||
// Disasm-transcribed 2026-07-23 (the fn sits in a Ghidra export gap; issue
|
||||
// #31). PRESS (data > 0, bin resolved): bin alarm -> Ejecting(3), reset the
|
||||
// countdown, ejectState = 0 (UpdateEject runs it; hold ~3s to completion =
|
||||
// DumpAmmo whole bay -> NoAmmo). RELEASE with the countdown still live (a
|
||||
// TAP): bin alarm Ejected(4) -> Loaded(1), FeedAmmo cycles ONE round out;
|
||||
// bay dry -> weapon NoAmmo(7), else weapon -> Loading(3) + full recoil -- the
|
||||
// weapon RETURNS TO SERVICE (this is the in-mission UNJAM; it also recovers a
|
||||
// FailureHeat 7 while rounds remain). Binary structure kept exactly: a press
|
||||
// with NO bin falls THROUGH to the release block (jle/je both target 4bba29).
|
||||
//
|
||||
void
|
||||
ProjectileWeapon::EjectAmmoMessageHandler(ReceiverDataMessageOf<int> *message)
|
||||
{
|
||||
if (MechSubsystem::IsDamaged()) // @4ac9c8 -- NOVICE lockout bridge
|
||||
return;
|
||||
|
||||
AmmoBin *bin = (AmmoBin*)ammoBinLink.Resolve(); // FUN_00417ab4(this+0x43c)
|
||||
|
||||
if (message->dataContents > 0 && bin != 0) // PRESS @4bb9d0/4bb9e9
|
||||
{
|
||||
bin->SetAmmoState(AmmoBin::Ejecting); // SetLevel(bin+0x194, 3)
|
||||
timeToEject = totalTimeToEject; // this+0x3f4 = this+0x3f0
|
||||
percentOfEject = 0.0f; // this+0x3f8
|
||||
ejectState = 0; // this+0x400 -- countdown live
|
||||
return; // jmp 4bbad9
|
||||
}
|
||||
|
||||
// RELEASE (or press-no-bin fall-through) @4bba29
|
||||
if (ejectState == 0) // countdown still live -> a TAP
|
||||
{
|
||||
if (bin != 0)
|
||||
{
|
||||
bin->SetAmmoState(AmmoBin::Ejected); // SetLevel(bin+0x194, 4)
|
||||
bin->SetAmmoState(AmmoBin::Loaded); // SetLevel(bin+0x194, 1)
|
||||
bin->FeedAmmo(); // @4bd4f4 -- cycle one round out
|
||||
if (bin->GetAmmoState() == AmmoBin::Empty) // [bin+0x1a8] == 2
|
||||
weaponAlarm.SetLevel(NoAmmoState); // bay dry -> 7
|
||||
else
|
||||
{
|
||||
weaponAlarm.SetLevel(3); // -> Loading: BACK IN SERVICE
|
||||
recoil = rechargeRate; // this+0x3e8 = this+0x3dc (dial restarts)
|
||||
}
|
||||
DEBUG_STREAM << "[weap] " << GetName() << " EJECT tap: round out, "
|
||||
<< bin->GetAmmoCount() << " left -> "
|
||||
<< (bin->GetAmmoState() == AmmoBin::Empty ? "NoAmmo" : "reloading")
|
||||
<< "\n" << std::flush;
|
||||
timeToEject = totalTimeToEject;
|
||||
percentOfEject = 0.0f;
|
||||
}
|
||||
else
|
||||
weaponAlarm.SetLevel(NoAmmoState); // @4bbabe -> 7
|
||||
}
|
||||
ejectState = -1; // @4bbacf -- countdown cancelled
|
||||
}
|
||||
|
||||
//
|
||||
// @004bbc78 -- bleed the firing charge (MechWeapon recoil @0x3E8) at a rate set
|
||||
// by the available bus voltage and the AmmoBin's remaining supply ratio.
|
||||
|
||||
Reference in New Issue
Block a user