#45/#134 authentic score/death report tail -- replaces the scoring stand-ins
Reconstructs the dark-gap tail of Mech::TakeDamageMessageHandler
(@0x4a02f4-0x4a0890, raw disasm): the three id-0x16 score reports (kill to
the shooter's player / type-0 wire-fidelity / received to the victim's
player) and the BT 0x38-byte VehicleDeadMessage extension {killed-by player,
kill zone} dispatched from the death tail. Retires BTPostDamageScore /
BTPostKillScore and the per-hit inflicted credit (never existed in 1995:
@0x4c0200 is bound in no handler-table entry -- byte-scan receipt in
decomp-reference). Suicides now dispatch and the handler negates the award
(the #134 panic penalty). Collision divert falls through to the death tail
per @0x4a0375 (wall deaths respawn + blast; no score). ScoreMessage fields
renamed to decoded truth (vitalHit/zoneIndex/subsysID) + wire asserts;
console VTVDamaged points_transfered corrected (Round(award), not Now()).
Benches: scorekill.sh cross-node kill (kills=1 award=4.88, killedBy=2:1
zone=3, single death cycle), scoreself.sh suicide (type=2 award=-39.00
kills=0), deathblast2.sh re-verified (72 bursts at ~9u).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
06a8edbff2
commit
91bd28669e
@@ -705,10 +705,12 @@ static int gEnemyDestroyed = 0;
|
||||
// BRING-UP: the spawned target/enemy mech (defined in btplayer.cpp). The player
|
||||
// mech locks onto it as its current target each frame (see targeting step below).
|
||||
extern Entity *gEnemyMech;
|
||||
// gauge scoring wave: producers (btplayer.cpp) -- feed the scoreboard from combat.
|
||||
extern void BTPostDamageScore(Entity *victim, Scalar damage, Entity *shooter); // per-hit SCORE (ScoreInflicted)
|
||||
// RETIRED 2026-08-05: the BTPostDamageScore / BTPostKillScore producers.
|
||||
// Scoring now flows through the authentic report tail in the victim's
|
||||
// TakeDamageMessageHandler (BTMechPostCombatReports, btplayer.cpp) -- the
|
||||
// shooter-side posts here double-credited against it. See the tombstone in
|
||||
// btplayer.cpp.
|
||||
float gBTWalkElev = 0.0f; // #124 zone walker: servo-driven aim elevation (rad)
|
||||
extern void BTPostKillScore(Entity *victim, Scalar damage); // KILL (+ MP death)
|
||||
|
||||
// Mech target slots (verified vs the binary's weapon/fire path, part_013.c):
|
||||
// mech+0x37c Point3D current target world position (range/aim source)
|
||||
@@ -1311,12 +1313,11 @@ static void
|
||||
shooter->GetEntityID(), -1 /*unaimed -> cylinder resolves*/, dmg);
|
||||
e->Dispatch(&td);
|
||||
|
||||
// SCORE (#95 follow-up): the binary's victim handler tallies EVERY
|
||||
// TakeDamage -- splash included -- and reports it to the INFLICTING
|
||||
// player (id-0x16, deferred #45), so a bystander blast is score too.
|
||||
// The bridge itself refuses a shooter that is not the local vehicle
|
||||
// (this function's death-blast caller passes the DYING mech).
|
||||
BTPostDamageScore(e, dmg.damageAmount * (Scalar)bursts, shooter);
|
||||
// SCORE: handled by the victim's own TakeDamage handler now -- the
|
||||
// dispatch above lands in the authentic report tail (#45), which
|
||||
// posts the kill/received reports itself. The shooter-side
|
||||
// BTPostDamageScore call that lived here was RETIRED 2026-08-05
|
||||
// (per-hit inflicted credit never existed in the 1995 pod).
|
||||
|
||||
// MP MATCH FORENSICS (matchlog.hpp): shooter-side splash delivery
|
||||
// to a bystander (pairs with the victim's DMG burst>1 line).
|
||||
@@ -1864,17 +1865,12 @@ static void
|
||||
(p.shooter != 0) ? p.shooter->GetEntityID() : EntityID::Null,
|
||||
-1 /*unaimed -> cylinder resolves*/, dmg, p.weaponSubsys);
|
||||
tgt->Dispatch(&take_damage);
|
||||
// gauge scoring wave (Step 6): a projectile hit credits SCORE with
|
||||
// the DELIVERED amount -- per-missile damage x the rolled cluster
|
||||
// count, the same figure the dispatch above hands the victim's
|
||||
// handler (which applies it burstCount times, tallying the amount
|
||||
// per burst @0x4a04da). Posting the bare per-missile amount here
|
||||
// was the "LRM10 registered ~3 points to score" defect (#95): the
|
||||
// armour took the full salvo while the scoreboard banked one
|
||||
// missile. (Crit bonuses in the tally remain victim-side
|
||||
// knowledge -- the deferred id-0x16 report, #45.)
|
||||
BTPostDamageScore((Entity *)tgt,
|
||||
p.damage * (Scalar)dmg.burstCount, p.shooter);
|
||||
// SCORE: handled by the victim's own TakeDamage handler now --
|
||||
// the dispatch above lands in the authentic report tail (#45),
|
||||
// which tallies every burst (crit bonuses included) itself.
|
||||
// The shooter-side BTPostDamageScore call that lived here (and
|
||||
// its #95 salvo-credit fix) was RETIRED 2026-08-05: per-hit
|
||||
// inflicted credit never existed in the 1995 pod.
|
||||
|
||||
// MP MATCH FORENSICS (matchlog.hpp): shooter-side
|
||||
// projectile impact delivery (pairs with the victim's
|
||||
@@ -2425,12 +2421,11 @@ void
|
||||
// boresight pick skips a dead mech, so that block never ran against
|
||||
// it again: internally dead, smoking, standing, invulnerable.
|
||||
{
|
||||
// KILL score (once; the ownerless dummy yields no death for us).
|
||||
// task #60: pass the REAL killing-blow magnitude (latched in the damage
|
||||
// handler), not the flat bring-up kShotDamage -- the score handler
|
||||
// @0x4c02e4 derives the whole kill award from this damageAmount, so a
|
||||
// flat 12 made every kill score identically regardless of weapon.
|
||||
BTPostKillScore((Entity *)this, lastInflictingDamage);
|
||||
// KILL score: RETIRED here 2026-08-05 -- the authentic kill report now
|
||||
// posts from the TakeDamage report tail (@0x4a04da, block A) with the
|
||||
// REAL applied tally, which supersedes the lastInflictingDamage relay
|
||||
// this site needed (#60). Suicides dispatch too (the handler negates
|
||||
// the award -- the #134 panic-penalty path this site's filter blocked).
|
||||
if ((Entity *)this == gEnemyMech)
|
||||
gEnemyDestroyed = 1; // latches off damage score
|
||||
|
||||
@@ -2496,55 +2491,19 @@ void
|
||||
}
|
||||
|
||||
//
|
||||
// --- RESPAWN CYCLE (task #52): notify the owning player of the death. ---
|
||||
// The BTPlayer VehicleDead handler @004c05c4 receives this with
|
||||
// deathCount == -1 (the ctor default = "immediate death notification"),
|
||||
// does the death bookkeeping, severs playerVehicle (this wreck entity
|
||||
// STAYS in the world) and re-posts the message to itself at +5 seconds
|
||||
// (5.0f @004c0830) -> the engine drop-zone hunt -> DropZoneReply ->
|
||||
// CreatePlayerVehicle (a NEW mech). Only the owner pod's master has a
|
||||
// live playerLink, which is exactly where the cycle must run; replicant
|
||||
// wrecks just mirror the master's death. [T1 the handler @004c05c4;
|
||||
// T3 this dispatch site -- the binary's exact sender is undecoded, but
|
||||
// the once-per-death transition is the only death edge and the message
|
||||
// ctor's deathCount=-1 default exists for precisely this notification.]
|
||||
// --- RESPAWN CYCLE (task #52): the VehicleDead notify MOVED 2026-08-05. ---
|
||||
// This site carried [T3 -- the binary's exact sender is undecoded]. The
|
||||
// sender is now decoded [T1]: the death tail of the TakeDamage handler
|
||||
// that killed the mech (@0x4a07d4-0x4a0890, raw disasm) builds the BT
|
||||
// 0x38-byte VehicleDeadMessage extension {killed-by player, kill zone}
|
||||
// and dispatches it to the owning player. BTMechPostVehicleDead
|
||||
// (btplayer.cpp) is that sender; the #55 NULL-playerLink fallback and the
|
||||
// DEAD_NOTIFY forensics moved into it intact. Every path that reaches
|
||||
// this transition does so inside the killing TakeDamage (weapon zones,
|
||||
// collision rattle via the divert fallthrough, the eject charge), so the
|
||||
// tail covers every death this site covered -- with one dispatch, keeping
|
||||
// the #81 single-VehicleDead rule.
|
||||
//
|
||||
{
|
||||
Player *owner = GetPlayerLink();
|
||||
// #55 step 1 (the David fix): the death notification used to hinge on
|
||||
// this single never-retried pointer -- playerLink is written once by
|
||||
// Entity::PlayerLinkMessageHandler with no null check, so a lost race
|
||||
// silently swallowed the whole respawn cycle. Resolve the SAME object
|
||||
// by the reverse link the binary's own respawn branch uses
|
||||
// (player+0x1FC == playerVehicle): the mission player whose vehicle is
|
||||
// this mech. Not a stand-in -- the identical entity, second index.
|
||||
if (owner == 0 && application != 0)
|
||||
{
|
||||
Player *mission_player = (Player *)application->GetMissionPlayer();
|
||||
if (mission_player != 0
|
||||
&& mission_player->GetPlayerVehicle() == (Entity *)this)
|
||||
{
|
||||
owner = mission_player;
|
||||
}
|
||||
}
|
||||
// #55 step 0: a NULL link was a SILENT swallow -- record the
|
||||
// resolution unconditionally so the matchlog can prove it either way.
|
||||
BTMatchLog("DEAD_NOTIFY", "mech=%d:%d link=%p",
|
||||
BTMatchHostOf(GetEntityID()), (int)GetEntityID(),
|
||||
(void *)owner);
|
||||
if (owner != 0)
|
||||
{
|
||||
Player::VehicleDeadMessage
|
||||
vehicle_dead(
|
||||
Player::VehicleDeadMessageID,
|
||||
sizeof(Player::VehicleDeadMessage)
|
||||
);
|
||||
owner->Dispatch(&vehicle_dead);
|
||||
if (getenv("BT_DEATH_LOG"))
|
||||
DEBUG_STREAM << "[death] VehicleDead(-1) dispatched to the owning player\n"
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Peer heading published each sim update, sampled by the render loop (BT_RENDHDG).
|
||||
|
||||
Reference in New Issue
Block a user