/* * CSB Punish Menu * Copyright (C) 2026 counter-strike-boost.com * * One unified moderation menu. Open it with say /punish (or amx_punish), pick a * player, pick an action - slap, slay, freeze/unfreeze, gag, kick or ban - and * for the serious actions pick a reason from a list loaded from an ini file so * punishments are consistent and every action is written to the AMXX log. * * This is an independent GPL implementation; it is not based on any other * plugin's source. * * 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 the GNU General * Public License for more details: . */ #include #include #include #include new const PLUGIN[] = "CSB Punish Menu" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define ACCESS ADMIN_KICK #define ACT_SLAP 1 #define ACT_SLAY 2 #define ACT_FREEZE 3 #define ACT_GAG 4 #define ACT_KICK 5 #define ACT_BAN 6 #define MAX_REASONS 32 new g_pEnabled, g_pSlapDmg, g_pBanTime, g_pFreezeTime new g_iTarget[33] /* selected target userid */ new g_iAction[33] /* pending action awaiting a reason */ new bool:g_bFrozen[33] new bool:g_bGagged[33] new g_szReasons[MAX_REASONS][48] new g_iReasonCount = 0 public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_punish_enabled", "1") g_pSlapDmg = register_cvar("csb_punish_slapdmg", "5") g_pBanTime = register_cvar("csb_punish_bantime", "30") g_pFreezeTime = register_cvar("csb_punish_freezetime", "5.0") register_clcmd("amx_punish", "cmdPunish", ACCESS, "- opens the CSB punish menu") register_clcmd("say /punish", "cmdPunish", ACCESS, "- opens the CSB punish menu") register_clcmd("say_team /punish", "cmdPunish", ACCESS, "- opens the CSB punish menu") } public plugin_cfg() { loadReasons() } loadReasons() { g_iReasonCount = 0 new path[128] get_localinfo("amxx_configsdir", path, charsmax(path)) if (!path[0]) copy(path, charsmax(path), "addons/amxmodx/configs") add(path, charsmax(path), "/csb_punish_reasons.ini") if (file_exists(path)) { new line[48], len for (new i = 0; i < 512; i++) { if (!read_file(path, i, line, charsmax(line), len)) break trim(line) if (!line[0] || line[0] == ';' || line[0] == '#') continue if (g_iReasonCount >= MAX_REASONS) break copy(g_szReasons[g_iReasonCount], charsmax(g_szReasons[]), line) g_iReasonCount++ } } if (!g_iReasonCount) { copy(g_szReasons[g_iReasonCount++], charsmax(g_szReasons[]), "Cheating") copy(g_szReasons[g_iReasonCount++], charsmax(g_szReasons[]), "Abusive language") copy(g_szReasons[g_iReasonCount++], charsmax(g_szReasons[]), "Team attacking") copy(g_szReasons[g_iReasonCount++], charsmax(g_szReasons[]), "Advertising") } } public cmdPunish(id, level, cid) { if (!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED if (!get_pcvar_num(g_pEnabled)) { client_print(id, print_chat, "[CSB] The punish menu is disabled.") return PLUGIN_HANDLED } showPlayerMenu(id) return PLUGIN_HANDLED } showPlayerMenu(id) { new menu = menu_create("\yCSB Punish\w^nSelect a player", "menuPlayer") new players[32], num, pid, name[32], info[8], line[64] get_players(players, num, "ch") for (new i = 0; i < num; i++) { pid = players[i] get_user_name(pid, name, charsmax(name)) formatex(info, charsmax(info), "%d", get_user_userid(pid)) formatex(line, charsmax(line), "%s %s", name, is_user_alive(pid) ? "" : "\r(dead)") menu_additem(menu, line, info, 0) } menu_setprop(menu, MPROP_EXITNAME, "Close") menu_display(id, menu, 0) } public menuPlayer(id, menu, item) { if (item == MENU_EXIT) { menu_destroy(menu) return PLUGIN_HANDLED } new info[8], name[32], access, callback menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback) menu_destroy(menu) g_iTarget[id] = str_to_num(info) showActionMenu(id) return PLUGIN_HANDLED } showActionMenu(id) { new target = find_player("k", g_iTarget[id]) if (!target) { client_print(id, print_chat, "[CSB] That player already left.") showPlayerMenu(id) return } new tname[32], title[96] get_user_name(target, tname, charsmax(tname)) formatex(title, charsmax(title), "\yCSB Punish\w^nTarget: \r%s", tname) new menu = menu_create(title, "menuAction") menu_additem(menu, "Slap (light damage)", "1", 0) menu_additem(menu, "Slay", "2", 0) menu_additem(menu, g_bFrozen[target] ? "Unfreeze" : "Freeze", "3", 0) menu_additem(menu, g_bGagged[target] ? "Ungag" : "Gag", "4", 0) menu_additem(menu, "Kick", "5", 0) menu_additem(menu, "Ban", "6", 0) menu_setprop(menu, MPROP_EXITNAME, "Back") menu_display(id, menu, 0) } public menuAction(id, menu, item) { if (item == MENU_EXIT) { menu_destroy(menu) showPlayerMenu(id) return PLUGIN_HANDLED } new info[8], name[32], access, callback menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback) menu_destroy(menu) new action = str_to_num(info) new target = find_player("k", g_iTarget[id]) if (!target) { client_print(id, print_chat, "[CSB] That player already left.") return PLUGIN_HANDLED } if (get_user_flags(target) & ADMIN_IMMUNITY) { client_print(id, print_chat, "[CSB] That player is immune.") showActionMenu(id) return PLUGIN_HANDLED } /* gag/kick/ban need a reason - the rest fire straight away */ if (action == ACT_GAG || action == ACT_KICK || action == ACT_BAN) { /* ungag needs no reason */ if (action == ACT_GAG && g_bGagged[target]) { applyAction(id, target, action, "") showActionMenu(id) return PLUGIN_HANDLED } g_iAction[id] = action showReasonMenu(id) return PLUGIN_HANDLED } applyAction(id, target, action, "") showActionMenu(id) return PLUGIN_HANDLED } showReasonMenu(id) { new menu = menu_create("\yCSB Punish\w^nSelect a reason", "menuReason") new info[8] for (new i = 0; i < g_iReasonCount; i++) { formatex(info, charsmax(info), "%d", i) menu_additem(menu, g_szReasons[i], info, 0) } menu_setprop(menu, MPROP_EXITNAME, "Back") menu_display(id, menu, 0) } public menuReason(id, menu, item) { if (item == MENU_EXIT) { menu_destroy(menu) showActionMenu(id) return PLUGIN_HANDLED } new info[8], name[48], access, callback menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback) menu_destroy(menu) new idx = str_to_num(info) new reason[48] if (idx >= 0 && idx < g_iReasonCount) copy(reason, charsmax(reason), g_szReasons[idx]) else copy(reason, charsmax(reason), "no reason given") new target = find_player("k", g_iTarget[id]) if (!target) { client_print(id, print_chat, "[CSB] That player already left.") return PLUGIN_HANDLED } applyAction(id, target, g_iAction[id], reason) return PLUGIN_HANDLED } applyAction(id, target, action, const reason[]) { new aname[32], tname[32] getAdminName(id, aname, charsmax(aname)) get_user_name(target, tname, charsmax(tname)) new what[96] switch (action) { case ACT_SLAP: { if (!is_user_alive(target)) { client_print(id, print_chat, "[CSB] %s is dead.", tname); return; } user_slap(target, get_pcvar_num(g_pSlapDmg)) formatex(what, charsmax(what), "slapped %s", tname) } case ACT_SLAY: { if (!is_user_alive(target)) { client_print(id, print_chat, "[CSB] %s is dead.", tname); return; } user_kill(target, 1) formatex(what, charsmax(what), "slayed %s", tname) } case ACT_FREEZE: { toggleFreeze(target) formatex(what, charsmax(what), "%s %s", g_bFrozen[target] ? "froze" : "unfroze", tname) } case ACT_GAG: { g_bGagged[target] = !g_bGagged[target] formatex(what, charsmax(what), "%s %s (%s)", g_bGagged[target] ? "gagged" : "ungagged", tname, reason[0] ? reason : "no reason") } case ACT_KICK: { formatex(what, charsmax(what), "kicked %s (%s)", tname, reason) server_cmd("kick #%d ^"Kicked: %s^"", get_user_userid(target), reason) } case ACT_BAN: { new mins = get_pcvar_num(g_pBanTime) formatex(what, charsmax(what), "banned %s for %d min (%s)", tname, mins, reason) server_cmd("banid %d #%d kick", mins, get_user_userid(target)) server_cmd("writeid") } } announce(aname, what) } toggleFreeze(target) { if (g_bFrozen[target]) { g_bFrozen[target] = false set_pev(target, pev_flags, pev(target, pev_flags) & ~FL_FROZEN) set_user_maxspeed(target, -1.0) return } g_bFrozen[target] = true set_pev(target, pev_flags, pev(target, pev_flags) | FL_FROZEN) set_user_maxspeed(target, 1.0) new Float:ftime = get_pcvar_float(g_pFreezeTime) if (ftime > 0.0) { remove_task(target + 7000) set_task(ftime, "taskUnfreeze", target + 7000) } } public taskUnfreeze(taskid) { new target = taskid - 7000 if (is_user_connected(target) && g_bFrozen[target]) { g_bFrozen[target] = false set_pev(target, pev_flags, pev(target, pev_flags) & ~FL_FROZEN) set_user_maxspeed(target, -1.0) } } public client_command(id) { if (!g_bGagged[id]) return PLUGIN_CONTINUE new cmd[16] read_argv(0, cmd, charsmax(cmd)) if (equali(cmd, "say") || equali(cmd, "say_team")) { client_print(id, print_chat, "[CSB] You are gagged by an admin.") return PLUGIN_HANDLED_MAIN } return PLUGIN_CONTINUE } public client_disconnected(id) { g_bFrozen[id] = false g_bGagged[id] = false remove_task(id + 7000) } getAdminName(id, name[], len) { if (id) get_user_name(id, name, len) else copy(name, len, "CONSOLE") } announce(const aname[], const what[]) { client_print_color(0, print_team_default, "^x04[CSB]^x03 %s^x01 %s.", aname, what) log_amx("[CSB Punish] %s %s", aname, what) }