hotfix: null-damageZone guard on the crit path (field crash, build 641, Conn Man's Owens)

First field session with real crits (#80) found a weapon subsystem with a
NULL damageZone: Mech__DamageZone::CriticalHit -> ApplyDamageAndMeasure ->
MechWeapon::TakeDamage +0xf (the engine base derefs the zone unguarded --
every 1995 subsystem shipped with one).  Stack symbolized from the field log;
the path was unreachable before tonight because ApplyDamageAndMeasure was a
stub until #80.

Guards at both choke points; a one-shot [crit] log NAMES the zoneless
subsystem when hit so the root cause (build that subsystem's zone) can be
fixed from the next field log.  Owens crit bench: no crash, guard inert on
zoned subsystems.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-07-29 21:41:02 -05:00
co-authored by Claude Fable 5
parent 1ac425860e
commit 98907f45af
2 changed files with 21 additions and 1 deletions
+16
View File
@@ -440,6 +440,22 @@ Logical
Scalar
MechSubsystem::ApplyDamageAndMeasure(Damage &damage)
{
// FIELD CRASH GUARD (2026-07-29, build 641, Conn Man's Owens): a crit
// landed on a weapon subsystem whose damageZone is NULL -- the engine
// base derefs it unguarded (every 1995 subsystem shipped with a zone).
// This path was unreachable until #80 made crits land for real. No
// zone -> nothing to damage or measure; the crit fizzles here. The
// one-shot log names the zoneless subsystem so its zone can be BUILT
// (the root-cause follow-up).
if (damageZone == 0)
{
static int s_nz = 0;
if (s_nz++ < 8)
DEBUG_STREAM << "[crit] NULL damageZone on subsystem '"
<< GetName() << "' -- crit fizzled (see the Owens field crash)\n"
<< std::flush;
return 0.0f;
}
Scalar before = ((DamageZone *)damageZone)->damageLevel; // dz+0x158 (engine view)
TakeDamage(damage); // (*this.vtable+0x24)(this, &damage)
return ((DamageZone *)damageZone)->damageLevel - before;
+5 -1
View File
@@ -405,7 +405,11 @@ Logical
void
MechWeapon::TakeDamage(Damage &damage)
{
Subsystem::TakeDamage(damage); // engine base (real chain: @004b0efc)
// FIELD CRASH GUARD (2026-07-29, build 641): the engine base derefs
// damageZone unguarded; an Owens weapon reached here with zone == NULL
// the first night crits could land (#80). See ApplyDamageAndMeasure.
if (this->Subsystem::damageZone != 0)
Subsystem::TakeDamage(damage); // engine base (real chain: @004b0efc)
// Port behavior (kept): a destroyed weapon clears its display alarm;
// otherwise the alarm tracks the resolved damage-zone state.