/* * CSB Headshot Counter * Copyright (C) 2026 counter-strike-boost.com * * Tracks headshots per round, per map and lifetime (nVault) from the DeathMsg * headshot flag, shows a small HUD counter, announces the round's best headshot * hunter, and exposes say /hs to print a player's headshot ratio. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. It is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See for details. */ #include #include #include new const PLUGIN[] = "CSB Headshot Counter" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define NO_VAULT (-1) new g_iVault = NO_VAULT new g_pEnabled, g_pHud new g_iRound[33] new g_iMap[33] new g_iLifeHs[33] new g_iLifeKills[33] new g_szAuth[33][35] public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_hs_enabled", "1") g_pHud = register_cvar("csb_hs_hud", "1") register_event("DeathMsg", "eventDeath", "a", "1>0") register_logevent("eventRoundEnd", 2, "1=Round_End") register_clcmd("say /hs", "cmdHs") register_clcmd("say_team /hs", "cmdHs") } public plugin_cfg() { g_iVault = nvault_open("csb_headshots") if (g_iVault == NO_VAULT) log_amx("[CSB HS] could not open nVault 'csb_headshots' - lifetime stats disabled.") } public plugin_end() { if (g_iVault != NO_VAULT) nvault_close(g_iVault) } public client_authorized(id) { g_iRound[id] = 0 g_iMap[id] = 0 g_iLifeHs[id] = 0 g_iLifeKills[id] = 0 g_szAuth[id][0] = 0 if (is_user_bot(id) || is_user_hltv(id)) return get_user_authid(id, g_szAuth[id], charsmax(g_szAuth[])) if (g_iVault == NO_VAULT) return new value[32] if (nvault_get(g_iVault, g_szAuth[id], value, charsmax(value))) { new hs[16], kills[16] strtok(value, hs, charsmax(hs), kills, charsmax(kills), ' ') g_iLifeHs[id] = str_to_num(hs) g_iLifeKills[id] = str_to_num(kills) } } public client_disconnected(id) { saveLifetime(id) } saveLifetime(id) { if (g_iVault == NO_VAULT || !g_szAuth[id][0]) return new value[32] formatex(value, charsmax(value), "%d %d", g_iLifeHs[id], g_iLifeKills[id]) nvault_pset(g_iVault, g_szAuth[id], value) } public eventDeath() { if (!get_pcvar_num(g_pEnabled)) return new killer = read_data(1) new victim = read_data(2) new hs = read_data(3) if (killer < 1 || killer > 32 || killer == victim) return g_iLifeKills[killer]++ if (hs) { g_iRound[killer]++ g_iMap[killer]++ g_iLifeHs[killer]++ if (get_pcvar_num(g_pHud) && is_user_connected(killer)) { set_hudmessage(0, 220, 255, 0.02, 0.55, 0, 0.0, 3.0, 0.1, 0.2, -1) show_hudmessage(killer, "Headshots this map: %d", g_iMap[killer]) } } } public eventRoundEnd() { new best = 0, bestHs = 0 new players[32], num, pid get_players(players, num, "c") for (new i = 0; i < num; i++) { pid = players[i] if (g_iRound[pid] > bestHs) { bestHs = g_iRound[pid] best = pid } g_iRound[pid] = 0 } if (best && bestHs >= 2) { new name[32] get_user_name(best, name, charsmax(name)) client_print(0, print_chat, "[CSB] Best headshot hunter this round: %s with %d headshot(s).", name, bestHs) } } public cmdHs(id) { new pct = 0 if (g_iLifeKills[id] > 0) pct = (g_iLifeHs[id] * 100) / g_iLifeKills[id] client_print(id, print_chat, "[CSB] Headshots - this map: %d | lifetime: %d of %d kills (%d%% HS ratio).", g_iMap[id], g_iLifeHs[id], g_iLifeKills[id], pct) return PLUGIN_HANDLED }