/* * CSB Ready System * Copyright (C) 2026 counter-strike-boost.com * * A pre-match readiness gate: every non-spectator types /ready, a HUD shows how * many players are ready, and once everyone is ready the plugin runs an LO3 * (three restarts) and goes live. Admins can force the match live and any player * un-readying during the countdown aborts it. * * 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 Ready System" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define TASK_HUD 4100 #define TASK_LO3 4200 new bool:g_bReady[33] new bool:g_bLive new bool:g_bCounting new g_iRestartsLeft new g_pEnabled, g_pMinPlayers, g_pAdminFlag public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_ready_enabled", "1") g_pMinPlayers = register_cvar("csb_ready_minplayers", "2") g_pAdminFlag = register_cvar("csb_ready_adminflag", "d") register_clcmd("say /ready", "cmdReady") register_clcmd("say_team /ready", "cmdReady") register_clcmd("say /notready", "cmdNotReady") register_clcmd("say_team /notready", "cmdNotReady") register_clcmd("say /forceready", "cmdForceReady") register_event("HLTV", "eNewRound", "a", "1=0", "2=0") set_task(1.0, "taskHud", TASK_HUD, _, _, "b") } public client_putinserver(id) { g_bReady[id] = false } public client_disconnected(id) { g_bReady[id] = false } public eNewRound() { /* keep restarting the score to zero during LO3 */ } public cmdReady(id) { if (!get_pcvar_num(g_pEnabled) || g_bLive) return PLUGIN_HANDLED if (get_user_team(id) == 0) { client_print(id, print_chat, "[CSB] Join a team before readying up.") return PLUGIN_HANDLED } if (g_bReady[id]) { client_print(id, print_chat, "[CSB] You are already ready.") return PLUGIN_HANDLED } g_bReady[id] = true new name[32] get_user_name(id, name, charsmax(name)) chatAll("^x04[CSB]^x03 %s^x01 is ready.", name) checkAllReady() return PLUGIN_HANDLED } public cmdNotReady(id) { if (!get_pcvar_num(g_pEnabled) || g_bLive) return PLUGIN_HANDLED if (!g_bReady[id]) return PLUGIN_HANDLED g_bReady[id] = false new name[32] get_user_name(id, name, charsmax(name)) chatAll("^x04[CSB]^x03 %s^x01 is NOT ready.", name) if (g_bCounting) { abortCountdown() chatAll("^x04[CSB]^x01 Countdown aborted - someone un-readied.") } return PLUGIN_HANDLED } public cmdForceReady(id) { new flags = read_flags_cvar() if (!(get_user_flags(id) & flags)) { client_print(id, print_chat, "[CSB] You do not have access to force the match live.") return PLUGIN_HANDLED } if (g_bLive) return PLUGIN_HANDLED new name[32] get_user_name(id, name, charsmax(name)) chatAll("^x04[CSB]^x03 %s^x01 forced the match to go live.", name) startLive() return PLUGIN_HANDLED } read_flags_cvar() { new sflag[8] get_pcvar_string(g_pAdminFlag, sflag, charsmax(sflag)) return read_flags(sflag) } countPlayers(&ready, &total) { new players[32], num, pid ready = 0 total = 0 get_players(players, num) for (new i = 0; i < num; i++) { pid = players[i] if (get_user_team(pid) == 0 || is_user_bot(pid)) continue total++ if (g_bReady[pid]) ready++ } } checkAllReady() { if (g_bLive || g_bCounting) return new ready, total countPlayers(ready, total) if (total < get_pcvar_num(g_pMinPlayers)) return if (ready == total && total > 0) startLive() } startLive() { g_bCounting = true g_iRestartsLeft = 3 chatAll("^x04[CSB]^x01 All players ready - going live! LO3 starting.") set_task(1.0, "taskLo3", TASK_LO3, _, _, "a", 3) } public taskLo3() { g_iRestartsLeft-- server_cmd("sv_restartround 1") server_cmd("sv_restart 1") if (g_iRestartsLeft > 0) { chatAll("^x04[CSB]^x01 Restart^x04 %d^x01 of 3...", 3 - g_iRestartsLeft) } else { g_bCounting = false g_bLive = true chatAll("^x04[CSB]^x01 *** MATCH IS LIVE *** GO GO GO!") client_print(0, print_center, "MATCH IS LIVE") } } abortCountdown() { remove_task(TASK_LO3) g_bCounting = false g_iRestartsLeft = 0 } public taskHud() { if (!get_pcvar_num(g_pEnabled) || g_bLive) return new ready, total countPlayers(ready, total) if (total <= 0) return set_hudmessage(0, 200, 80, -1.0, 0.15, 0, 0.0, 1.1, 0.0, 0.0, -1) if (g_bCounting) show_hudmessage(0, "LIVE ON 3 - GET READY^nReady: %d / %d", ready, total) else show_hudmessage(0, "WARMUP - type /ready^nReady: %d / %d", ready, total) } chatAll(const fmt[], any:...) { new msg[192] vformat(msg, charsmax(msg), fmt, 2) new players[32], num, msgid = get_user_msgid("SayText") get_players(players, num, "ch") for (new i = 0; i < num; i++) { message_begin(MSG_ONE, msgid, _, players[i]) write_byte(players[i]) write_string(msg) message_end() } }