From c206d0db049537e9f7d17f1bb611c7067440a4c0 Mon Sep 17 00:00:00 2001 From: geracosta Date: Mon, 10 Aug 2026 11:55:31 -0300 Subject: [PATCH] Credit kills by illusions of the victim instead of dropping them as suicides The attacker==victim filter is meant for suicides, but an illusion of the victim (Dark Portrait, Disruption, Wall of Replica) carries the victim's unit name and got dropped too. A real suicide is never dealt by an illusion, and sourcename already resolves the kill to the illusion's owner. Verified on match 8754463676: Muerta's death at 2057s to Grimstroke's Dark Portrait illusion is restored to kills_log/killed_by, matching the scoreboard (39 radiant kills), with the standard test replay byte-identical to master. --- src/main/java/opendota/CreateParsedDataBlob.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/opendota/CreateParsedDataBlob.java b/src/main/java/opendota/CreateParsedDataBlob.java index 147cf683..98b0ba58 100644 --- a/src/main/java/opendota/CreateParsedDataBlob.java +++ b/src/main/java/opendota/CreateParsedDataBlob.java @@ -792,7 +792,13 @@ private void handleDeathCombat(Entry e, List output, Metadata meta) { return; } - if (e.attackername != null && e.attackername.equals(key)) { + // Suicides (e.g. Techies) are not kills, but only when the attacker is + // the victim itself: an illusion OF the victim landing the killing blow + // (Dark Portrait, Disruption, Wall of Replica) has the same unit name + // while the kill belongs to the illusion's owner, which sourcename + // already resolves to + if (e.attackername != null && e.attackername.equals(key) + && (e.attackerillusion == null || !e.attackerillusion)) { return; }