/* * CSB Round End Sound * Copyright (C) 2026 counter-strike-boost.com * * Plays a configurable sound at the end of every round depending on who won * (Terrorists, CTs or a draw), with a special track for a flawless round - one * where the winning team lost nobody. Sound paths are read from an ini so admins * can swap them without editing code, every path is precached, and each player * can mute the sounds for themselves with "say /rsounds". * * Inspired by the classic Round Sound plugins. Independent GPL re-implementation. * * 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 new const PLUGIN[] = "CSB Round End Sound" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define SND_T 0 #define SND_CT 1 #define SND_DRAW 2 #define SND_FLAWLESS 3 new g_szSnd[4][128] new bool:g_bMuted[33] new g_iDeadT, g_iDeadCT new g_pEnabled public plugin_precache() { /* sane defaults - overridden by the ini if present */ copy(g_szSnd[SND_T], charsmax(g_szSnd[]), "ambience/thunder_clap.wav") copy(g_szSnd[SND_CT], charsmax(g_szSnd[]), "ambience/thunder_clap.wav") copy(g_szSnd[SND_DRAW], charsmax(g_szSnd[]), "ambience/rain1.wav") copy(g_szSnd[SND_FLAWLESS], charsmax(g_szSnd[]), "ambience/des_wind3.wav") loadIni() for (new i = 0; i < 4; i++) { if (g_szSnd[i][0]) precache_sound(g_szSnd[i]) } } public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_rsnd_enabled", "1") register_clcmd("say /rsounds", "cmdToggle") register_clcmd("say_team /rsounds", "cmdToggle") register_logevent("eventRoundStart", 2, "1=Round_Start") register_event("DeathMsg", "eventDeath", "a", "1>0") register_event("TextMsg", "eventTerWin", "a", "2&#Terrorists_Win") register_event("TextMsg", "eventCtWin", "a", "2&#CTs_Win") register_event("TextMsg", "eventDraw", "a", "2&#Round_Draw") } public client_putinserver(id) { g_bMuted[id] = false } loadIni() { new cfgdir[128], path[160] get_localinfo("amxx_configsdir", cfgdir, charsmax(cfgdir)) if (!cfgdir[0]) return; formatex(path, charsmax(path), "%s/csb_round_sounds.ini", cfgdir) if (!file_exists(path)) return; new f = fopen(path, "rt") if (!f) return; new line[192], key[32], value[128] while (!feof(f)) { fgets(f, line, charsmax(line)) trim(line) if (!line[0] || line[0] == ';' || line[0] == '#') continue strtok(line, key, charsmax(key), value, charsmax(value), '=') trim(key) trim(value) if (!value[0]) continue if (equali(key, "t_win")) copy(g_szSnd[SND_T], charsmax(g_szSnd[]), value) else if (equali(key, "ct_win")) copy(g_szSnd[SND_CT], charsmax(g_szSnd[]), value) else if (equali(key, "draw")) copy(g_szSnd[SND_DRAW], charsmax(g_szSnd[]), value) else if (equali(key, "flawless")) copy(g_szSnd[SND_FLAWLESS], charsmax(g_szSnd[]), value) } fclose(f) } public cmdToggle(id) { g_bMuted[id] = !g_bMuted[id] client_print(id, print_chat, "[CSB] Round-end sounds %s.", g_bMuted[id] ? "muted" : "unmuted") return PLUGIN_HANDLED } public eventRoundStart() { g_iDeadT = 0 g_iDeadCT = 0 } public eventDeath() { new victim = read_data(2) if (victim < 1 || victim > 32) return; switch (get_user_team(victim)) { case 1: g_iDeadT++; case 2: g_iDeadCT++; } } public eventTerWin() { playFor(g_iDeadT == 0 ? SND_FLAWLESS : SND_T) } public eventCtWin() { playFor(g_iDeadCT == 0 ? SND_FLAWLESS : SND_CT) } public eventDraw() { playFor(SND_DRAW) } playFor(idx) { if (!get_pcvar_num(g_pEnabled) || idx < 0 || idx > 3 || !g_szSnd[idx][0]) return; new players[32], num get_players(players, num, "ch") for (new i = 0; i < num; i++) { new pl = players[i] if (g_bMuted[pl]) continue client_cmd(pl, "spk %s", g_szSnd[idx]) } }