diff --git a/game/reconstructed/emitter.cpp b/game/reconstructed/emitter.cpp index d02071a..bce823a 100644 --- a/game/reconstructed/emitter.cpp +++ b/game/reconstructed/emitter.cpp @@ -51,7 +51,7 @@ // FUN_004b0bd0 PoweredSubsystem simulation step FUN_004b0d50 PoweredSubsystem scalar query // FUN_004ad7d4 HeatableSubsystem "is online/active" FUN_004ac9c8 HeatableSubsystem heat-state query // FUN_00417ab4 follow a SharedData link (voltage source / ammo bin) -// FUN_0049fb54 cockpit/HUD query FUN_0041a1a4 IsDerivedFrom(classDerivations) +// FUN_0049fb54 Mech::IsDestroyed (movementMode 2||9) FUN_0041a1a4 IsDerivedFrom(classDerivations) // FUN_0041bbd8 AlarmIndicator::SetLevel(n) (weaponAlarm @0x350, state @0x364) // FUN_0041c350 Subsystem::SendMessage(template, a, b) // FUN_00408440 Vector copy FUN_00409968 Vector set FUN_0040a968 Vector negate/copy @@ -102,7 +102,20 @@ static void CopyColor(void *, const void *) {} // engine-internal artifacts the decomp called by address (stand-ins) static int FUN_004ad7d4(void *) { return 1; } // HeatableSubsystem active? -static int FUN_0049fb54(int) { return 0; } // cockpit/HUD query +// FUN_0049fb54 == Mech::IsDestroyed (movementMode 2||9; reconstructed as +// Mech::IsDisabled). Was a mislabeled "cockpit/HUD query" no-op stub -- so a +// live beam never CUT when its target mech died (@004ba8d0/@004baa20 check +// this every discharge frame), and a destroyed mech's own weapons kept firing +// (@004baa88). The binary's call sites first verify the object IS a Mech +// (IsDerivedFrom vs 0x50bdb4 = Mech::ClassDerivations), reproduced here. +static int BTMechDestroyed(Entity *e) +{ + if (e == 0) + return 0; + if (!e->IsDerivedFrom(*Mech::GetClassDerivations())) + return 0; + return ((Mech *)e)->IsDisabled() ? 1 : 0; +} static Scalar FUN_004b0d50(void *) { return 1.0f; }// PoweredSubsystem dt scale static int FUN_004ac9c8(void *) { return 0; } // heat-state query static void *FUN_00417ab4(void *) { return 0; } // follow SharedData link @@ -215,8 +228,13 @@ void DrawWeaponPip(aimTransform); // FUN_004b9728 } - // stash the beam endpoint for replication (world hit point) + // stash the beam endpoint for replication (world hit point) + the beam's + // TARGET (0x474 -- the discharge checks read it every frame: the beam cuts + // the moment this mech is destroyed). The owner's target slot is the same + // raw 0x388 the rest of the weapon path uses (HasActiveTarget/mech4). beamEndpoint = targetPoint; // 0x460 <- targetPoint + targetEntity = (owner != 0) + ? *(Entity **)((char *)owner + 0x388) : 0; // 0x474 <- mech target entity targetLocalFlag = 1; // 0x470 SetDirty(); // this+6 |= 1 (needs replication) @@ -259,8 +277,9 @@ void Logical fireEdge = CheckFireEdge(); // @004b9608 targetWithinRange = UpdateTargeting(); // @004b9bdc -> this+0x34c - // hard failure: powered-off, faulted, or destroyed -> drop everything - if (GetFlags() == 1 || GetFaultState() == 2 || FUN_0049fb54(0)) + // hard failure: powered-off, faulted, or the OWNING MECH destroyed (@004baa88 + // checks IsDestroyed on the owner -- a dead mech's weapons drop everything) + if (GetFlags() == 1 || GetFaultState() == 2 || BTMechDestroyed((Entity *)owner)) { ResetFiringState(); // @004ba9a8 currentLevel = 0.0f; // 0x414 @@ -382,7 +401,7 @@ void weaponAlarm.SetLevel(0); // Firing dischargeTimer -= time_slice; // 0x440 if (dischargeTimer <= 0.0f // _DAT_004ba9a4 - || (targetEntity != 0 && FUN_0049fb54(0))) // or the targeted subsystem is gone + || BTMechDestroyed(targetEntity)) // the beam CUTS when its target mech dies { firingActive = 0; weaponAlarm.SetLevel(2); // Loaded @@ -420,7 +439,7 @@ void { if (beamFlag != 0) // 0x46c { - if (targetEntity != 0 && FUN_0049fb54(0)) // targeted subsystem gone + if (BTMechDestroyed(targetEntity)) // the beam CUTS when its target mech dies { ResetFiringState(); // @004ba9a8 return;