/*
* CSB CVar Menu
* Copyright (C) 2026 counter-strike-boost.com
*
* A menu of the cvars server admins change most often (friendly fire, gravity,
* freeze time, round time, buy time, auto team balance, start money, C4 timer).
* Each entry shows its current value and cycles through a preset list when
* selected, applying it immediately with set_cvar_string.
*
* Inspired by the AMX Mod X CVar menu (AMX Mod X Development Team). 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
#include
new const PLUGIN[] = "CSB CVar Menu"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
/* cvar name, friendly label and a pipe-separated list of preset values */
new const g_cvarName[][] = {
"mp_friendlyfire",
"sv_gravity",
"mp_freezetime",
"mp_roundtime",
"mp_buytime",
"mp_autoteambalance",
"mp_startmoney",
"mp_c4timer"
}
new const g_cvarLabel[][] = {
"Friendly Fire",
"Gravity",
"Freeze Time",
"Round Time",
"Buy Time",
"Auto Team Balance",
"Start Money",
"C4 Timer"
}
new const g_cvarPreset[][] = {
"0|1",
"400|600|800|1000",
"0|3|6",
"1.75|3|5|9",
"0.25|0.5|1",
"0|1",
"800|1600|8000|16000",
"30|35|45|60"
}
#define ENTRIES sizeof(g_cvarName)
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_concmd("amx_cvarmenu", "cmdCvarMenu", ADMIN_CVAR, "- open the quick cvar menu")
register_clcmd("say /cvars", "sayCvarMenu")
}
public sayCvarMenu(id)
{
if (get_user_flags(id) & ADMIN_CVAR)
showMenu(id)
return PLUGIN_HANDLED
}
public cmdCvarMenu(id, level, cid)
{
if (!cmd_access(id, level, cid, 1))
return PLUGIN_HANDLED
showMenu(id)
return PLUGIN_HANDLED
}
showMenu(id)
{
new title[64]
formatex(title, charsmax(title), "\yCSB CVar Menu^n\wPick a cvar to cycle its value")
new menu = menu_create(title, "menuHandler")
new line[96], cur[24], info[4]
for (new i = 0; i < ENTRIES; i++)
{
get_cvar_string(g_cvarName[i], cur, charsmax(cur))
formatex(line, charsmax(line), "%s: \y%s", g_cvarLabel[i], cur)
num_to_str(i, info, charsmax(info))
menu_additem(menu, line, info, 0)
}
menu_display(id, menu, 0)
}
public menuHandler(id, menu, item)
{
if (item == MENU_EXIT || item < 0)
{
menu_destroy(menu)
return PLUGIN_HANDLED
}
new info[4], name[2], access, callback
menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback)
menu_destroy(menu)
new idx = str_to_num(info)
if (idx < 0 || idx >= ENTRIES)
return PLUGIN_HANDLED
cycleCvar(id, idx)
showMenu(id)
return PLUGIN_HANDLED
}
cycleCvar(id, idx)
{
new presets[64]
copy(presets, charsmax(presets), g_cvarPreset[idx])
new cur[24]
get_cvar_string(g_cvarName[idx], cur, charsmax(cur))
/* split the preset list on '|' and find the current value, then take next */
new values[6][24], count = 0
new start = 0, len = strlen(presets)
for (new i = 0; i <= len && count < sizeof(values); i++)
{
if (presets[i] == '|' || presets[i] == 0)
{
new sub = i - start
if (sub > 0)
{
if (sub > charsmax(values[]))
sub = charsmax(values[])
copy(values[count], sub, presets[start])
count++
}
start = i + 1
}
}
if (!count)
return
new nextIdx = 0
for (new i = 0; i < count; i++)
{
if (equal(values[i], cur))
{
nextIdx = (i + 1) % count
break
}
}
set_cvar_string(g_cvarName[idx], values[nextIdx])
new aname[32]
get_user_name(id, aname, charsmax(aname))
log_amx("[CSB CVar] %s set %s to %s", aname, g_cvarName[idx], values[nextIdx])
client_print(id, print_chat, "[CSB] %s = %s", g_cvarLabel[idx], values[nextIdx])
}