diff --git a/game/reconstructed/btplayer.cpp b/game/reconstructed/btplayer.cpp index 63fec7a..3db4a4f 100644 --- a/game/reconstructed/btplayer.cpp +++ b/game/reconstructed/btplayer.cpp @@ -810,7 +810,20 @@ void && what->messageID == Player::ScoreMessageID && ((BTPlayer::ScoreMessage *)what)->scoreType == BTPlayer::ScoreMessage::DamageInflictedScore - ) + // + // MASTER ONLY. The binary intercepts unconditionally because its + // +0x278 is a console DELTA -- every node's contribution is flushed + // under the scoring player's ownerID and the CONSOLE totals it, so the + // computing node is irrelevant. Our port has no console tally + // (btconsole.py/btoperator.py handle no score at all) and reads +0x278 + // on the OWNING node for the SCORE gauge, CalcRanking and the replicated + // Player__UpdateRecord. Banking on the victim's replicant copy + // therefore loses the credit to the master's next update record. + // Falling through lets Entity::Dispatch reroute to the owner, where the + // wire delivery lands in ScoreMessageHandler's type-0 arm (which now + // delegates back to the inflicted handler). + // + && GetInstance() == Entity::MasterInstance) { ScoreInflictedMessageHandler((BTPlayer::ScoreMessage *)what); return; @@ -987,15 +1000,26 @@ void { case BTPlayer::ScoreMessage::DamageInflictedScore: // 0 // - // Inflicted-damage messages belong to ScoreInflictedMessageHandler. + // Inflicted-damage messages belong to ScoreInflictedMessageHandler, and + // the binary's Dispatch override (@004bffa0) guarantees they never reach + // here -- which is why the original arm is a bare Verify. // - Verify( - False, - "BTPlayer::ScoreMessageHandler should not be " - "given DamageInflictedScoreMessages!", // @0051324a - "d:\\tesla_bt\\bt\\btplayer.cpp", // @0051329a - 0x296 - ); + // PORT DIVERGENCE (2026-08-07), and it is a DELIVERY-PATH difference, + // not a scoring one. Damage is applied on the VICTIM's node, so block B + // dispatches the inflicted report to the SHOOTER's player object there -- + // a REPLICANT -- and Entity::Dispatch reroutes it to the owning host so + // the credit lands on the shooter's OWN machine (the same reroute that + // carries kill credit, ENTITY.cpp:244-251). But a message arriving over + // the WIRE is delivered through Receive(), straight to this handler + // table: the virtual Dispatch override is never called on the receiving + // side. So the rerouted report lands HERE, and Verify-rejecting it + // threw away every cross-node inflicted credit (benched: award=0.00). + // + // Delegate instead. Local deliveries are still intercepted by Dispatch + // exactly as the binary does; wire deliveries land here and get the same + // handler. One accumulator, on the machine that owns the score. + // + ScoreInflictedMessageHandler(message); break; case BTPlayer::ScoreMessage::DamageReceivedScore: // 1