#89 DEATH BLAST reconstructed: a dying mech splashes its neighborhood
The missing half of Advanced Damage, found by call-scanning Explosion::SplashDamage @0042fad0: TWO callers, not one -- Missile::Perform (the known #62 path) and 0x4a0bda, the UN-EXPORTED tail of Mech::TakeDamageMessageHandler itself. Raw disasm @0x4a07b8-0x4a0bda: when the victim ENTERS dead(9)/eject(10) during the applications, the binary sets the wreck burning (id 0x17, deferred -- handler not yet reconstructed), spawns the death Explosion (model 0x31 -- our death-list visuals stand in), and SPLASHES: gates : owning player's advancedDamageOn (+0x264) AND NOT suppressConsole (+0x258 -- eject sets it: PUNCH-OUTS NEVER BLAST, the authentic anti-suicide-bomb rule) damage: type 2 Explosive, amount = deathSplashDamage (mech+0x520), bursts = round(0.001 * moverMass * 15.0) -- scales with tonnage radius: deathSplashRadius (mech+0x524); per-victim falloff bursts/dist^1.25 in the shared core Draco's collision-divert suspicion is settled: the blast is TYPE 2, the divert never touched it -- the tail was simply never reconstructed. Port: deathSplashDamage/Radius PROMOTED from the Wword scratch bank to named Mech members (the bank is one GLOBAL array -- authored per-chassis values were clobbered to the last-loaded mech); BTSplashCore split out of the #62 weapon splash and shared; BTApplyDeathSplash + the death-edge arm in the handler tail; BTPlayerConsoleSuppressed bridge (friend). Bench (2-node, B parked 8.9u from a self-destructing A): blast fired with authored madcat data (radius=50, amount=5, mass=75000 -> 1125 base bursts), B took 73 bursts (falloff exact: 1125/8.91^1.25), cross-pod delivery + cylinder spray verified on B's own log ([dmghit] type=2 burst=73 across zones). ~365 damage at 9u -- Draco's 'double kills on drops' economy restored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
85d6ef4a59
commit
297127d0d7
@@ -1235,6 +1235,10 @@ static Scalar
|
||||
return radius;
|
||||
}
|
||||
|
||||
static void
|
||||
BTSplashCore(Entity *shooter, const Point3D ¢er, Entity *directVictim,
|
||||
const Damage &dmgTemplate, Scalar radius); // #89 shared core (below)
|
||||
|
||||
void
|
||||
BTApplySplashDamage(Entity *shooter, int weapon_subsys, const Point3D ¢er,
|
||||
Entity *directVictim, const Damage &dmgTemplate)
|
||||
@@ -1246,7 +1250,18 @@ void
|
||||
<< " radius=" << radius << "\n" << std::flush;
|
||||
if (radius <= 0.0f)
|
||||
return; // this weapon authors no splash
|
||||
BTSplashCore(shooter, center, directVictim, dmgTemplate, radius);
|
||||
}
|
||||
|
||||
//
|
||||
// #89: the splash CORE, shared by the weapon-detonation caller above and the
|
||||
// DEATH BLAST below (the binary's two Explosion::SplashDamage call sites).
|
||||
//
|
||||
static void
|
||||
BTSplashCore(Entity *shooter, const Point3D ¢er, Entity *directVictim,
|
||||
const Damage &dmgTemplate, Scalar radius)
|
||||
{
|
||||
static const int s_log = getenv("BT_SPLASH_LOG") ? 1 : 0;
|
||||
extern int BTIsRegisteredMech(Entity *e);
|
||||
extern int BTGetTargetCandidates(Entity *shooter, Entity **out, int maxOut);
|
||||
Entity *cand[32];
|
||||
@@ -1322,6 +1337,71 @@ void
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// #89 DEATH BLAST -- the second authentic SplashDamage call site (raw disasm
|
||||
// @0x4a07b8-0x4a0bda, the un-exported TakeDamage tail; provenance banner at
|
||||
// the caller, mech.cpp). A dying mech's explosion damages every mech inside
|
||||
// its authored DeathSplashRadius:
|
||||
// gates : owning player's advancedDamageOn (+0x264) AND
|
||||
// NOT suppressConsole (+0x258 -- eject sets it: punch-outs never
|
||||
// blast) [T1 @0x4a0aa8-0x4a0ad6]
|
||||
// damage : type 2 Explosive [T1 @0x4a0aef], amount = deathSplashDamage
|
||||
// (mech+0x520, authored "DeathSplashDamage"), impact = mech origin
|
||||
// bursts : round(0.001 * moverMass(+0x20c) * 15.0) [T1 @0x4a0b21-0x4a0b33]
|
||||
// -- the blast scales with the chassis mass; the per-victim
|
||||
// falloff (bursts/dist^1.25) applies in the core
|
||||
// radius : deathSplashRadius (mech+0x524, authored "DeathSplashRadius")
|
||||
// excluded: the dying mech itself (the binary's Explosion anchors on it;
|
||||
// the core's candidate walk already excludes the shooter)
|
||||
//
|
||||
void BTApplyDeathSplash(void *mech_v)
|
||||
{
|
||||
Mech *m = (Mech *)mech_v;
|
||||
static const int s_log = getenv("BT_SPLASH_LOG") ? 1 : 0;
|
||||
if (m == 0)
|
||||
return;
|
||||
extern int BTPlayerAdvancedDamageOn(void *player_v);
|
||||
extern int BTPlayerConsoleSuppressed(void *player_v);
|
||||
void *player = m->GetPlayerLink();
|
||||
if (player == 0)
|
||||
{
|
||||
// binary derefs mech+0x190 unguarded (every arcade mech had an owner);
|
||||
// the port's link-less solo dummy skips, loudly under the log.
|
||||
if (s_log)
|
||||
DEBUG_STREAM << "[splash] DEATH: no player link, skipped\n" << std::flush;
|
||||
return;
|
||||
}
|
||||
if (!BTPlayerAdvancedDamageOn(player) || BTPlayerConsoleSuppressed(player))
|
||||
{
|
||||
if (s_log)
|
||||
DEBUG_STREAM << "[splash] DEATH: gated (advDmg="
|
||||
<< BTPlayerAdvancedDamageOn(player)
|
||||
<< " suppress=" << BTPlayerConsoleSuppressed(player)
|
||||
<< ")\n" << std::flush;
|
||||
return;
|
||||
}
|
||||
if (!(m->deathSplashRadius > 0.0f))
|
||||
return; // chassis authors no blast
|
||||
|
||||
Damage dmg; // Damage::Damage @0x41db7c
|
||||
dmg.damageType = (Enumeration)2; // Explosive
|
||||
dmg.damageAmount = m->deathSplashDamage;
|
||||
dmg.impactPoint = m->localOrigin.linearPosition;
|
||||
int bursts = (int)(0.5f + 0.001f * (float)m->moverMass * 15.0f);
|
||||
if (bursts < 1) bursts = 1;
|
||||
dmg.burstCount = bursts;
|
||||
|
||||
if (s_log)
|
||||
DEBUG_STREAM << "[splash] DEATH BLAST mech=" << m->GetEntityID()
|
||||
<< " radius=" << (float)m->deathSplashRadius
|
||||
<< " amount=" << (float)m->deathSplashDamage
|
||||
<< " bursts=" << bursts
|
||||
<< " (mass=" << (float)m->moverMass << ")\n" << std::flush;
|
||||
|
||||
BTSplashCore((Entity *)m, m->localOrigin.linearPosition, (Entity *)m,
|
||||
dmg, m->deathSplashRadius);
|
||||
}
|
||||
|
||||
// Called from ProjectileWeapon / MissileLauncher::FireWeapon (via the extern below)
|
||||
// with the live muzzle, the SHOOTER mech (to resolve the real launch port), the owner's
|
||||
// locked target entity + point, the launch speed (|muzzleVelocity|), and per-shot damage.
|
||||
|
||||
Reference in New Issue
Block a user