/* * CSB Reserved Slots * Copyright (C) 2026 counter-strike-boost.com * * Keeps a configurable number of slots free for flagged VIPs/admins. When the * free-slot count drops below the reserve, the plugin removes the "worst" * non-VIP present (bots first, then the highest-ping player) so a reserved slot * is available again. Enforced on connect and on a short repeating timer. * * Inspired by the Reserved Slots plugin shipped with AMX Mod X (AMX Mod X * Development Team). Independent GPL re-implementation; no original code reused. * * 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 new const PLUGIN[] = "CSB Reserved Slots" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pEnabled, g_pReserved, g_pFlag public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_slots_enabled", "1") g_pReserved = register_cvar("csb_slots_reserved", "1") g_pFlag = register_cvar("csb_slots_flag", "a") set_task(8.0, "taskEnforce", 0, _, _, "b") } public client_putinserver(id) { if (is_user_bot(id)) return set_task(1.5, "taskEnforce") } hasReserved(id) { new flags[8] get_pcvar_string(g_pFlag, flags, charsmax(flags)) new access = read_flags(flags) return (get_user_flags(id) & access) ? 1 : 0 } pickVictim() { new players[32], num, pid get_players(players, num) new bestBot = 0 new worst = 0, worstPing = -1 for (new i = 0; i < num; i++) { pid = players[i] if (is_user_bot(pid)) { bestBot = pid continue } if (is_user_hltv(pid)) continue /* never kick a VIP or an immune admin to free a reserved slot */ if (hasReserved(pid)) continue if (get_user_flags(pid) & ADMIN_IMMUNITY) continue new ping, loss get_user_ping(pid, ping, loss) if (ping > worstPing) { worstPing = ping worst = pid } } /* prefer removing a bot before a real player */ if (bestBot) return bestBot return worst } public taskEnforce() { if (!get_pcvar_num(g_pEnabled)) return new reserved = get_pcvar_num(g_pReserved) if (reserved < 1) return new maxSlots = get_maxplayers() new players[32], num get_players(players, num) new free = maxSlots - num while (free < reserved) { new victim = pickVictim() if (!victim) break new name[32] get_user_name(victim, name, charsmax(name)) server_cmd("kick #%d ^"Slot reserved for a VIP - please rejoin later^"", get_user_userid(victim)) log_amx("[CSB Slots] freed a reserved slot by removing %s", name) free++ } }