From e0b91df3e1920ccb6ebba953937657dfb710acf5 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Fri, 7 Aug 2026 11:20:20 -0500 Subject: [PATCH] scoring: CORRECTION -- the death cost was never missing; my arithmetic was Retracts the "open item" claimed in 2fcce53. An ungated [deathcost] receipt at the block settles it: [deathcost] player 2:1 advDmg=1 role=bound penalty=500 scoreBefore=-779 -> APPLYING It fires once, on a self-kill, exactly as it does on a combat death. There is no combat-vs-self asymmetry. WHY I GOT IT WRONG: the cost is dispatched by a DIRECT Player::ScoreMessageHandler() base call, so it never reaches the BT matchlog. I computed the total from the LAST matchlog row and found no -500 in it -- but that row is emitted BEFORE the unlogged cost. I had noted the bypass one message earlier and still failed to apply it to my own sum. The lesson is the usual one: a value that cannot appear in the log you are reading is not evidence of absence. The receipt stays. A debit that moves the player-visible score while being structurally invisible to the forensic log is exactly the kind of thing that should announce itself. Chart status after this: -500 special-case death cost VERIFIED applying. The -1000 eject ROW remains unverified -- its components (self-damage credit, negated self-kill award, death cost) are each verified, but no real punch-out has ever fired in a bench, so the total is still arithmetic. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01NCJQkvq6G2JNrpVbA75tVZ --- game/reconstructed/btplayer.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/game/reconstructed/btplayer.cpp b/game/reconstructed/btplayer.cpp index d44ffe8..884bcdb 100644 --- a/game/reconstructed/btplayer.cpp +++ b/game/reconstructed/btplayer.cpp @@ -687,6 +687,20 @@ void // scoreboard (they read +0x278), so the pod's penalty may never have been // visible; our port has ONE currentScore, so it shows. // + // #45 receipt (ungated): this cost is dispatched by a DIRECT base-handler + // call, so it never reaches the BT matchlog and only the running total + // exposes it -- which is how a combat death costing -500 while a SELF-KILL + // cost nothing went unnoticed. Say out loud whether it fires and why not. + DEBUG_STREAM << "[deathcost] player " << BTMatchHostOf(GetEntityID()) + << ":" << (int)GetEntityID() + << " advDmg=" << (int)advancedDamageOn + << " role=" << (scenarioRole != 0 ? "bound" : "NULL") + << " penalty=" << (scenarioRole != 0 + ? (float)scenarioRole->GetSpecialCaseDeathPenalty() : 0.0f) + << " scoreBefore=" << (float)currentScore + << ((advancedDamageOn && scenarioRole != 0) ? " -> APPLYING" : " -> SKIPPED") + << "\n" << std::flush; + if (advancedDamageOn && scenarioRole != 0) // this+0x264 (binary derefs role unguarded) { BTPlayer::ScoreMessage death_cost(