Announce forfeited match winners and show LIVESTATS lines only with -v

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <[email protected]>
This commit is contained in:
Debian
2026-09-18 12:19:23 +02:00
co-authored by Sisyphus
parent c08db27b57
commit 38f1446cde
2 changed files with 125 additions and 8 deletions
+36 -5
View File
@@ -171,10 +171,14 @@ class EventParser:
warmup = " ^8^3(Warmup)^0" if data.get('WARMUP', False) else ""
score_prefix = ""
# CA scores are damage-based server-side (kills + damage/100): frag
# deltas would corrupt them, so only PLAYER_STATS/LIVESTATS sync there
ca_scoring = self.game_state.server_info.gametype == 'Clan Arena'
# Environmental death (no killer)
if 'KILLER' not in data or not data['KILLER']:
# -1 for environmental death
if not data.get('WARMUP', False):
if not data.get('WARMUP', False) and not ca_scoring:
self.game_state.player_tracker.update_score(victim_name, -1)
score_prefix = "^8^1[-1]^7^0 "
@@ -199,10 +203,20 @@ class EventParser:
killer_prefix = get_team_prefix(killer_name, self.game_state.player_tracker)
# Suicide
if killer_name == victim_name:
# Suicide: names can differ cosmetically (color codes/whitespace) between
# the KILLER and VICTIM objects, so compare stripped. Steamid equality is
# only trusted for humans - bot ids are shared and would flag every
# bot-vs-bot frag as a suicide.
killer_steamid = str(killer.get('STEAM_ID', '') or '')
victim_steamid = str(victim.get('STEAM_ID', '') or '')
suicide = (strip_color_codes(killer_name).strip()
== strip_color_codes(victim_name).strip())
if (not suicide and killer_steamid.startswith('7656119')
and victim_steamid.startswith('7656119')):
suicide = killer_steamid == victim_steamid
if suicide:
# -1 for suicide
if not data.get('WARMUP', False):
if not data.get('WARMUP', False) and not ca_scoring:
self.game_state.player_tracker.update_score(victim_name, -1)
score_prefix = "^8^1[-1]^7^0 "
@@ -218,7 +232,7 @@ class EventParser:
return f"{score_prefix}{killer_prefix}^8{killer_name}^0 ^7committed suicide with the ^7{weapon_name}{warmup}\n"
# Regular kill: +1 for killer
if not data.get('WARMUP', False):
if not data.get('WARMUP', False) and not ca_scoring:
self.game_state.player_tracker.update_score(killer_name, 1)
score_prefix = "^8^2[+1]^7^0 "
@@ -333,6 +347,18 @@ class EventParser:
if not self.game_state.server_info.is_team_mode():
return None
# Aborted/restarted matches have no winner - except forfeits, where
# the remaining scores are final and name a winner
exit_msg = str(data.get('EXIT_MSG', '') or '')
is_forfeit = 'forfeit' in exit_msg.lower()
if data.get('ABORTED') in (True, 'true', '1', 1) and not is_forfeit:
return None
try:
if int(data.get('RESTARTED', 0) or 0) != 0:
return None
except (TypeError, ValueError):
return None
red_score = int(data.get('TSCORE0', '0'))
blue_score = int(data.get('TSCORE1', '0'))
report_prefix = "^8^1[GAME OVER]"
@@ -352,6 +378,11 @@ class EventParser:
kills = int(data.get('KILLS', '0'))
deaths = int(data.get('DEATHS', '0'))
# PLAYER_STATS SCORE is authoritative (the server's own counters) and
# in CA it is damage-based, so sync it instead of accumulating deltas
if data.get('SCORE') is not None:
self.game_state.player_tracker.set_score(name, data['SCORE'])
weapon_data = data.get('WEAPONS', {})
accuracies = calculate_weapon_accuracies(weapon_data)