/* * CSB Bounty * Copyright (C) 2026 counter-strike-boost.com * * Players (or the server) can place a cash bounty on another player's head. * Bounties are stored per SteamID in a Trie, shown in the HUD, announced on * placement / increase / claim, and paid to whoever kills the target. An * anti-farm cooldown blocks payouts for repeatedly killing the same victim. * * 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 Bounty" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new Trie:g_tBounty new g_pEnabled, g_pMin, g_pCooldown new g_szAuth[33][35] new Float:g_fLastKill[33][33] new g_iSync public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_tBounty = TrieCreate() g_pEnabled = register_cvar("csb_bounty_enabled", "1") g_pMin = register_cvar("csb_bounty_min", "500") g_pCooldown = register_cvar("csb_bounty_cooldown", "45") register_clcmd("say", "cmdSay") register_clcmd("say_team", "cmdSay") register_concmd("amx_bounty", "cmdAdminBounty", ADMIN_LEVEL_A, " - place a server bounty") register_event("DeathMsg", "eventDeath", "a", "1>0") register_logevent("eventRoundStart", 2, "1=Round_Start") g_iSync = CreateHudSyncObj() set_task(1.0, "taskHud", 0, _, _, "b") } public plugin_end() { TrieDestroy(g_tBounty) } public client_authorized(id) { get_user_authid(id, g_szAuth[id], charsmax(g_szAuth[])) } public client_disconnected(id) { if (g_szAuth[id][0]) TrieDeleteKey(g_tBounty, g_szAuth[id]) g_szAuth[id][0] = 0 } getBounty(id) { if (!g_szAuth[id][0]) return 0 new amount if (TrieGetCell(g_tBounty, g_szAuth[id], amount)) return amount return 0 } setBounty(id, amount) { if (!g_szAuth[id][0]) return if (amount <= 0) TrieDeleteKey(g_tBounty, g_szAuth[id]) else TrieSetCell(g_tBounty, g_szAuth[id], amount) } public cmdSay(id) { new args[128] read_args(args, charsmax(args)) remove_quotes(args) if (containi(args, "/bounty") != 0) return PLUGIN_CONTINUE if (!get_pcvar_num(g_pEnabled)) { client_print(id, print_chat, "[CSB] Bounties are disabled.") return PLUGIN_HANDLED } /* format: /bounty */ new rest[96] copy(rest, charsmax(rest), args[7]) trim(rest) new targetName[32], amountStr[16] strtok(rest, targetName, charsmax(targetName), amountStr, charsmax(amountStr), ' ') trim(targetName) trim(amountStr) if (!targetName[0] || !amountStr[0]) { client_print(id, print_chat, "[CSB] Usage: /bounty ") return PLUGIN_HANDLED } new target = findByName(targetName) if (!target) { client_print(id, print_chat, "[CSB] No player matching '%s'.", targetName) return PLUGIN_HANDLED } if (target == id) { client_print(id, print_chat, "[CSB] You cannot put a bounty on yourself.") return PLUGIN_HANDLED } new amount = str_to_num(amountStr) new minB = get_pcvar_num(g_pMin) if (amount < minB) { client_print(id, print_chat, "[CSB] Minimum bounty is $%d.", minB) return PLUGIN_HANDLED } new money = cs_get_user_money(id) if (money < amount) { client_print(id, print_chat, "[CSB] You only have $%d.", money) return PLUGIN_HANDLED } cs_set_user_money(id, money - amount) new was = getBounty(target) setBounty(target, was + amount) new placer[32], victim[32] get_user_name(id, placer, charsmax(placer)) get_user_name(target, victim, charsmax(victim)) if (was > 0) client_print(0, print_chat, "[CSB] %s raised the bounty on %s to $%d!", placer, victim, was + amount) else client_print(0, print_chat, "[CSB] %s placed a $%d bounty on %s!", placer, amount, victim) return PLUGIN_HANDLED } public cmdAdminBounty(id, level, cid) { if (!cmd_access(id, level, cid, 3)) return PLUGIN_HANDLED new arg1[32], arg2[16] read_argv(1, arg1, charsmax(arg1)) read_argv(2, arg2, charsmax(arg2)) new target = findByName(arg1) if (!target) { console_print(id, "[CSB] No player matching '%s'.", arg1) return PLUGIN_HANDLED } new amount = str_to_num(arg2) if (amount <= 0) { console_print(id, "[CSB] Amount must be positive.") return PLUGIN_HANDLED } new was = getBounty(target) setBounty(target, was + amount) new victim[32] get_user_name(target, victim, charsmax(victim)) client_print(0, print_chat, "[CSB] The server placed a $%d bounty on %s!", amount, victim) return PLUGIN_HANDLED } findByName(const name[]) { new players[32], num get_players(players, num, "ch") for (new i = 0; i < num; i++) { new pn[32] get_user_name(players[i], pn, charsmax(pn)) if (containi(pn, name) != -1) return players[i] } return 0 } public eventDeath() { new killer = read_data(1) new victim = read_data(2) if (victim < 1 || victim > 32) return new reward = getBounty(victim) if (reward <= 0) return if (killer < 1 || killer > 32 || killer == victim) { /* suicide / world: bounty stays */ return } /* anti-farm: same killer killing same victim too soon pays nothing */ new Float:cd = get_pcvar_float(g_pCooldown) if (get_gametime() - g_fLastKill[killer][victim] < cd) { setBounty(victim, 0) return } g_fLastKill[killer][victim] = get_gametime() new money = cs_get_user_money(killer) new give = money + reward if (give > 16000) give = 16000 cs_set_user_money(killer, give) setBounty(victim, 0) new kn[32], vn[32] get_user_name(killer, kn, charsmax(kn)) get_user_name(victim, vn, charsmax(vn)) client_print(0, print_chat, "[CSB] %s claimed the $%d bounty on %s!", kn, reward, vn) } public eventRoundStart() { TrieClear(g_tBounty) } public taskHud() { new best = 0, bestVal = 0 new players[32], num, pid get_players(players, num, "ch") for (new i = 0; i < num; i++) { pid = players[i] new b = getBounty(pid) if (b > bestVal) { bestVal = b best = pid } } if (!best) return new name[32] get_user_name(best, name, charsmax(name)) set_hudmessage(255, 200, 0, 0.02, 0.20, 0, 0.0, 1.1, 0.0, 0.0, -1) ShowSyncHudMsg(0, g_iSync, "TOP BOUNTY: %s - $%d", name, bestVal) }