#86: destroyed weapons can no longer fire -- the fire gates read a

never-written cell (the split-cell gotcha)

Both weapon fire gates (ProjectileWeapon gate 1 @4bbd36, Emitter
hard-failure @4baab9) test the binary's subsystem+0x40 for Destroyed(1).
In the 1995 layout that offset sits INSIDE the embedded status alarm
(statusAlarm@0x2C + level@+0x14 = 0x40) -- ONE cell, written by
ForceCriticalFailure when a zone's crit cascade kills the subsystem.  The
port models the same address as TWO members: the AlarmIndicator AND a
plain int simulationState@0x40.  Every destruction path writes the ALARM
(so the MFD draws its X correctly) while the gates read the plain int,
which nothing ever writes -- so a weapon on a blown-off arm showed
destroyed on every panel and kept firing and scoring, locally and on
peers (night-7: all three testers, screenshots of a missile leaving a
destroyed pod).

The tell had been sitting in our own logs for weeks:
  [ammo] SRM6_1 -> NoAmmo (gate1): destroyed=0 ...
on a mech whose launcher was X'd out.

Fix: both gates now read statusAlarm.GetLevel()==1 as well as the int.
Also added: the crit-cascade log names the destroyed subsystem, a
BT_SELF_DAMAGE_ZONE=dz_* named-zone bench mode, and BT_KILL_SUBSYS=<name>
(force ForceCriticalFailure on one named subsystem -- the exact call the
zone cascade makes, so a bench can ask 'the panel says dead, does it
still shoot?' without hunting for the zone that carries a given weapon).

Verified A/B in ONE run: before the kill both SRM6 launchers fired 2
salvos each; after, the destroyed launcher fired ZERO (gate log
destroyed=1) while its twin kept firing normally.

KB: new gotcha #22 (the SPLIT CELL -- one binary offset, two port
members, only one written; sibling of #1) + combat-damage entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Zh7PTkFy4KwTzVighLR9J
This commit is contained in:
Joe DiPrima
2026-07-31 12:11:09 -05:00
co-authored by Claude Fable 5
parent 62fc8409b6
commit 5410371b0c
6 changed files with 86 additions and 2 deletions
+7 -1
View File
@@ -428,7 +428,13 @@ void
// simulationFlags@0x28, a latent kill-switch), own heatAlarm at FailureHeat
// (this+0x184 == 2), or the owning mech disabled (FUN_0049fb54) -- a dead
// mech's weapons drop everything.
if (simulationState == 1 || GetFaultState() == 2 || BTMechDestroyed((Entity *)owner))
// #86 FIX (2026-07-31): the binary's +0x40 IS the statusAlarm level cell
// (indicator @0x2C, level at +0x14 = +0x40 -- ONE cell); the port split
// them and the destruction path writes only the alarm, so X'd-out energy
// weapons on a blown-off arm kept firing. Read BOTH cells (see
// projweap.cpp gate 1 for the full note).
if (simulationState == 1 || statusAlarm.GetLevel() == 1
|| GetFaultState() == 2 || BTMechDestroyed((Entity *)owner))
{
ResetFiringState(); // @004ba9a8
currentLevel = 0.0f; // 0x414