Combat: critical-subsystem plugs BOUND -- zone destruction damages carried subsystems (task #2)

The binding was in the zone ctor all along: Ghidra dropped the two arg
pushes @0049d0e1 (Slot::AddImplementation(subsystemArray[streamedIndex])),
making it read as a bare Resolve().  DZSlot stand-in -> engine SlotOf<T>;
SendSubsystemDamage rewritten to the recovered @0049c9a8 body (allotment
into the subsystem's OWN private zone; vital -> graphicAlarm 9); CriticalHit
-> real ApplyDamageAndMeasure; parentArtifactZone.Add revived (LOD damage
averaging); videoObjectFlag renamed vitalSubsystem (+0xE4).  BT_CRIT_PROBE
diag added.  Verified: 66 plugs bound/mech; probe-destroyed zone -> crits
damaged/DESTROYED, statusAlarm + destroyed-skin chain fire; MP kill + solo
un-regressed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-11 12:10:43 -05:00
co-authored by Claude Fable 5
parent a652ddcdbc
commit 87c25b9206
6 changed files with 172 additions and 63 deletions
+21 -3
View File
@@ -126,7 +126,7 @@ MechSubsystem::MechSubsystem(
this->owner = owner; // this[0x34] -- the owning Mech (canonical)
hostEntity = owner; // this[0x3a] = param_7
subsystemId2 = subsystem_ID; // this[0x3b] = param_8
videoObjectFlag = 0; // this[0x39]
vitalSubsystem = 0; // this[0x39]
BindName(refCount, "None"); // FUN_00402a98(.,this+0x3d,"None") @0x50df7a
alarmModel = 0; // identity ResourceID // FUN_00408440(this+0x3e, identity)
criticalReference = 0; // this[0x42]
@@ -163,7 +163,7 @@ MechSubsystem::MechSubsystem(
subsystemId2 = subsystem_ID; // this[0x3b]=param_7
resource = subsystem_resource; // this[0x3c]
vitalSubsystemIndex = -1; // this[0x44]
videoObjectFlag = (subsystem_resource->vitalSubsystemIndex == 1); // res+0x48==1
vitalSubsystem = (subsystem_resource->vitalSubsystemIndex == 1); // res+0x48==1
BindName(refCount, subsystem_resource->videoObjectName); // res+0x4c
alarmModel = subsystem_resource->alarmModel; // res+0xcc -> this[0x3e]
@@ -218,6 +218,24 @@ Scalar MechSubsystem::GetSubsystemDamageLevel() const
return damageZone ? ((DamageZone *)damageZone)->damageLevel : 0.0f;
}
//
// @0049c9a8 (zone-side inline) -- the destroyed-side effects applied when a
// crit drives this subsystem's own zone to 1.0: status Destroyed, the gated
// debug print, and the zone's state valve. (task #2)
//
void MechSubsystem::ForceCriticalFailure()
{
statusAlarm.SetLevel(1); // +0x2C: 1 = Destroyed
if (printSimulationState) // +0x104 gate
{
PrintState(); // vtable slot 0x34 @4ac8c0
}
if (damageZone != 0)
{
((DamageZone *)damageZone)->SetDamageZoneState(1); // zone+0x10
}
}
void MechSubsystem::SetSubsystemDamageLevel(Scalar level)
{
if (damageZone)
@@ -263,7 +281,7 @@ Logical
OnAlarmChanged(); // (*this.vtable+0x34)(this)
}
damageZone->structureLevel = 1.0f; // dz+0x158 = 1.0
if (videoObjectFlag != 0) // this[0x39]
if (vitalSubsystem != 0) // this[0x39]
{
((Mech *)owner)->RaiseStatusAlarm(9); // FUN_0041bbd8(owner+0x2c, 9)
}