BT410 Phase 5.3.17: the destruction cascade -- zone deaths DESTROY things

Mech::DamageZone::TakeDamage is the full binary cascade (@0049c690): LOD
artifact router with same-attacker clustering (@0049c40c, hysteresis 0.33),
artifact parent level = mean of children, Energy-hit generator shorts
through the crit plug binding (novice-exempt), weighted CriticalHit
(@0049ccc4), zone-death allotment push (SendSubsystemDamage @0049c9a8) and
the segment-table destruction descent (RecurseSegmentTable @0049cad4 --
SIBS + DESCEND via the engine EntitySegment iterators).

Supporting bricks: Mech's OWN handler table with the TakeDamage override
(latches lastInflictingID @0x43c; gyro feed staged; cylinder table
deferred); friend class Mech__DamageZone (authentic); subsystem private
zones ARMED (structureReference + armorByFacing[5] normalized -- crits are
measurable); ApplyDamageAndMeasure; ForceCriticalFailure sets
DestroyedState so the weapon FSMs' GetSimulationState()==1 hard gate went
live; Generator::ForceShort + PoweredSubsystem::ForceShortRecovery.

Fight-verified (mutual BT_SPAWN_ENEMY + BT_FORCE_ZONE=8 concentrated fire):
arm zone to 1.0 -> sibling searchlight zone dies (Searchlight2/ThermalSight
crits destroyed, HUD degrading) -> DESCEND kills the gun zone -> PPC_2 +
ERMLaser_2 + Condenser6 DESTROYED and FALL SILENT (0 shots after death;
undamaged PPC_1 keeps firing); vital-zone hit = MECH KILL; PPC hit shorted
GeneratorD. This art has zero artifact zones (redirect=0 across all 20 --
router verified dormant-correct). Smoke + novice regressions clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Cyd
2026-07-24 11:13:28 -05:00
co-authored by Claude Fable 5
parent 86d6b950e5
commit d4f0aef6e1
13 changed files with 856 additions and 27 deletions
+56 -1
View File
@@ -64,10 +64,29 @@ Derivation
"Mech"
);
//
// The Mech's OWN handler table, chained to the JointedMover set. The
// TakeDamage entry OVERRIDES Entity's by message ID (Build overlays the
// inherited slot -- no gap risk, the parent chain already registered the
// ID); every other inherited message still routes to its base handler.
//
const Receiver::HandlerEntry
Mech::MessageHandlerEntries[] =
{
MESSAGE_ENTRY(Mech, TakeDamage)
};
Mech::MessageHandlerSet
Mech::MessageHandlers(
ELEMENTS(Mech::MessageHandlerEntries),
Mech::MessageHandlerEntries,
JointedMover::MessageHandlers
);
Mech::SharedData
Mech::DefaultData(
Mech::ClassDerivations,
JointedMover::MessageHandlers,
Mech::MessageHandlers,
JointedMover::AttributeIndex,
33,
(Entity::MakeHandler)Mech::Make
@@ -167,6 +186,7 @@ Mech::Mech(
lookPitch = 0.0f;
lookYaw = 0.0f;
targetEntity = NULL;
lastInflictingID = EntityID::Null;
//
// Look-view angles: defaults until the GameModel read below overrides them
@@ -551,6 +571,41 @@ Mech::~Mech()
{
}
//
//#############################################################################
// TakeDamageMessageHandler -- the Mech override of the Entity damage entry
// (binary hub @004a0230 via the handler glue @0049ed0c).
//
// Order in the binary: (1) feed the RAW Damage record to the gyro cockpit
// bounce FIRST -- even an invalid-zone hit shakes the cockpit (STAGED: the
// gyro bounce math is the gyro/feel wave; a gated log marks the feed site);
// (2) latch the attacker (mech+0x43c -- the zone LOD router keys its
// same-attacker redirect reuse off it); (3) resolve an unaimed hit's zone
// (invalidDamageZone) from the cylinder hit-location table -- DEFERRED, the
// type-0x1d table is not loaded yet, so unaimed hits fall through to the
// base handler's zone==-1 drop (authentic base behavior); (4) chain to the
// Entity handler which routes damageZones[zone]->TakeDamage.
//#############################################################################
//
void
Mech::TakeDamageMessageHandler(TakeDamageMessage *message)
{
Check(this);
Check(message);
if (gyroSubsystem != NULL && getenv("BT_MECH_LOG"))
{
DEBUG_STREAM << "[gyro] hit feed staged (type="
<< (int)message->damageData.damageType
<< " amt=" << message->damageData.damageAmount << ")"
<< endl << flush;
}
lastInflictingID = message->inflictingEntity;
Entity::TakeDamageMessageHandler(message);
}
void
Mech::SetMappingSubsystem(Subsystem *subsystem)
{