Beams CUT on a destroyed target (the real FUN_0049fb54, was a mislabeled stub)
Answers "can I keep targeting the dead mech?": the lock isn't cleared by anything we've found, but the binary REFUSES to sustain energy beams on a destroyed mech: ServiceDischarge (@004ba8d0) and ContinueDischarge (@004baa20) check the beam's target EVERY discharge frame -- IsDerivedFrom(Mech) then Mech::IsDestroyed (FUN_0049fb54 = movementMode 2||9) -- and kill the beam the moment it dies. EmitterSimulation (@004baa88) applies the same check to the OWNER (a dead mech's own weapons drop everything). Our recon had FUN_0049fb54 as a mislabeled "cockpit/HUD query" no-op stub called with NULL, and never set the beam's target (0x474) at fire -- all three authentic gates were dead. Now: FireWeapon stashes the owner's target entity; both discharge paths + the owner gate run the real check (BTMechDestroyed). Verified: 40 beam samples before the kill, 0 after -- lasers flash-fail on the wreck instead of cutting it like butter (heat is still spent per the binary's FireWeapon, which fires blind; only the DISCHARGE checks the corpse). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
cba4c3098f
commit
c2f70f6348
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user