#150 -- one kill credited twice (Rajel on Oracle, Oracle on Conn Man). CAUGHT: one death -> two type-2 arms 1ms apart (awards 501.96/505.88 -- the tally GREW between them), victim inst=R. Mechanism: this port deliberately applies damage on replicants for local visual response; the report tail ran there too, and a replicant's movement mode cannot flip to wreck until the victim's death record round-trips -- so each round of a killing VOLLEY inside that window re-posted the kill. Why missiles, why intermittent. The binary forbids the whole situation: its handler OPENS with the assertion if ((flags & 0xc) == 4) Fail("Replicant Mech recieving takedamage", MECH.CPP, 0x3da) [part_012.c:14613] -- TakeDamage on a replicant was a BUG in 1995; the tail only ever ran on the victim's master. Fix: (1) gate the REPORT TAIL master-only (local damage application stays); (2) adopt the binary's once-latch -- the 0->1 edge of IsMechDestroyed() across the handler call (local_14), replacing the deathBlastArmed form for the report gate. VERIFIED (scratchpad/night14/scorepair.sh): 3 victim deaths, 5 shooter respawns -> exactly one type-2 per credited kill, kills 0->1->2, zero doubles (was: kills 0->2 on one death). #151 -- panic eject "-499 instead of 0" is AUTHENTIC 1995 SCORING, decoded from EjectPilot @0049f854: the punch-out dispatches a SELF TakeDamage of damageAmount = role->killBonus (+0x1c, 500 in dfltrole), type Explosive, senderMechID = SELF, player->suppressConsole = 1, graphicAlarm -> 10 which flows through the report tail as a SUICIDE kill: award = -CalcKillScore (your own death), plus the type-1 death cost. 1000 - ~999 - 500 = -499: the binary predicts Oracle's exact number. Our port already used role->killBonus for the blast (mech.cpp:652) -- faithful end to end; bench shows each eject charged exactly once (-900/-1050 across three ejects). Panic eject = scored as suicide. Whether that is fun is a design question; it is not a porting defect. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC
This commit is contained in:
co-authored by
Claude Opus 5
parent
773595b347
commit
46ff8dd262
@@ -1032,6 +1032,12 @@ void
|
||||
{
|
||||
Check(message);
|
||||
|
||||
// #150 -- the binary's ONCE-PER-DEATH latch (local_14 @0x4a0230 body,
|
||||
// part_012.c:14625-14629): IsMechDestroyed() sampled AT ENTRY. The kill
|
||||
// report posts only on the 0->1 edge (!destroyedAtEntry && destroyed-now);
|
||||
// a later salvo of the killing volley takes the inflicted-only path.
|
||||
const int destroyedAtEntry = IsMechDestroyed();
|
||||
|
||||
// MP DIAGNOSTIC (task #47): confirm the handler runs on the OWNING MASTER
|
||||
// for a cross-pod (network-delivered) TakeDamage + what state it carries.
|
||||
if (getenv("BT_MP_NET"))
|
||||
@@ -1242,11 +1248,31 @@ void
|
||||
// vital-wreck flag, and the loop-ENTRY zone. This retires
|
||||
// BTPostDamageScore/BTPostKillScore -- see the btplayer.cpp tombstone.
|
||||
//
|
||||
// #150 DOUBLE-KILL FIX, two binary-grounded gates (2026-08-10):
|
||||
//
|
||||
// (1) MASTER ONLY. The binary OPENS this handler with the assertion
|
||||
// `if ((flags & 0xc) == 4) Fail("Replicant Mech recieving takedam...",
|
||||
// MECH.CPP, 0x3da)` (part_012.c:14613-14616) -- in 1995 a replicant
|
||||
// executing TakeDamage was a BUG, so the report tail could only ever
|
||||
// run on the victim's master, once. This port deliberately applies
|
||||
// damage on replicants too (local visual responsiveness), so the tail
|
||||
// ALSO ran there -- and the replicant's movement mode can't flip to
|
||||
// wreck until the death record round-trips, so a multi-round killing
|
||||
// volley posted a kill report PER ROUND inside that window. Measured:
|
||||
// one death -> two type-2 arms 1ms apart, kills 0->2 (the field's
|
||||
// "one kill counted twice", #150). Gate the REPORTS to the master;
|
||||
// the local damage application stays.
|
||||
//
|
||||
// (2) ENTRY LATCH. The binary's newly-destroyed test is the 0->1 edge of
|
||||
// IsMechDestroyed() across THIS handler call (local_14), not the
|
||||
// movement-mode-derived deathBlastArmed -- on the master both agree,
|
||||
// but the binary's form is the spec.
|
||||
if (GetInstance() != ReplicantInstance)
|
||||
{
|
||||
extern void BTMechPostCombatReports(void *, void *, float, int, int, int);
|
||||
BTMechPostCombatReports((void *)this, (void *)message,
|
||||
(float)damageTally, zoneDestroyed, reportZone,
|
||||
deathBlastArmed && IsMechDestroyed());
|
||||
!destroyedAtEntry && IsMechDestroyed());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user