/*
* CSB Speed Boost
* Copyright (C) 2026 counter-strike-boost.com
*
* Timed speed boosts. A boost raises the player's maxspeed for a configurable
* number of seconds and is re-applied on every weapon switch (CurWeapon), so
* switching weapons does not cancel it. Boosts come from two sources:
* - boost zones placed per map in addons/amxmodx/data/csb_boostzones/<map>.txt
* (one "x y z radius" per line), and
* - the /boost command (for shop or VIP integration; free by default).
* A HUD line counts down the remaining boost time.
*
* 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 <https://www.gnu.org/licenses/> for details.
*/
#include <amxmodx>
#include <fun>
#include <fakemeta>
new const PLUGIN[] = "CSB Speed Boost"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#define MAX_ZONES 32
#define TASK_HUD 7331
new Float:g_fBoostUntil[33]
new Float:g_fBoostSpeed[33]
new Float:g_fZone[MAX_ZONES][4] /* x y z radius */
new g_iZones
new g_pEnabled, g_pSpeed, g_pDuration
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_boost_enabled", "1")
g_pSpeed = register_cvar("csb_boost_speed", "400.0")
g_pDuration = register_cvar("csb_boost_duration", "10.0")
register_event("CurWeapon", "OnCurWeapon", "be", "1=1")
register_clcmd("say /boost", "cmdBoost")
register_clcmd("say_team /boost", "cmdBoost")
loadZones()
set_task(0.5, "taskZones", TASK_HUD, _, _, "b")
}
loadZones()
{
g_iZones = 0
new map[32], dir[96], path[160]
get_mapname(map, charsmax(map))
get_localinfo("amxx_datadir", dir, charsmax(dir))
formatex(path, charsmax(path), "%s/csb_boostzones/%s.txt", dir, map)
if (!file_exists(path))
return
new file = fopen(path, "rt")
if (!file)
return
new line[128]
while (!feof(file) && g_iZones < MAX_ZONES)
{
fgets(file, line, charsmax(line))
trim(line)
if (!line[0] || line[0] == ';' || line[0] == '#')
continue
new sx[16], sy[16], sz[16], sr[16]
parse(line, sx, charsmax(sx), sy, charsmax(sy), sz, charsmax(sz), sr, charsmax(sr))
g_fZone[g_iZones][0] = str_to_float(sx)
g_fZone[g_iZones][1] = str_to_float(sy)
g_fZone[g_iZones][2] = str_to_float(sz)
g_fZone[g_iZones][3] = str_to_float(sr)
if (g_fZone[g_iZones][3] < 16.0)
g_fZone[g_iZones][3] = 16.0
g_iZones++
}
fclose(file)
log_amx("[CSB] Speed Boost: loaded %d zone(s).", g_iZones)
}
public cmdBoost(id)
{
if (!is_user_alive(id))
{
client_print(id, print_chat, "[CSB] You must be alive to use a boost.")
return PLUGIN_HANDLED
}
applyBoost(id, get_pcvar_float(g_pDuration))
return PLUGIN_HANDLED
}
public taskZones()
{
if (!get_pcvar_num(g_pEnabled))
return
new Float:now = get_gametime()
new Float:dur = get_pcvar_float(g_pDuration)
new players[32], num
get_players(players, num, "a")
for (new i = 0; i < num; i++)
{
new id = players[i]
/* zone pickup */
if (g_iZones > 0 && g_fBoostUntil[id] < now)
{
new Float:orig[3]
pev(id, pev_origin, orig)
for (new z = 0; z < g_iZones; z++)
{
new Float:dx = orig[0] - g_fZone[z][0]
new Float:dy = orig[1] - g_fZone[z][1]
new Float:dz = orig[2] - g_fZone[z][2]
if (floatsqroot(dx * dx + dy * dy + dz * dz) <= g_fZone[z][3])
{
applyBoost(id, dur)
break
}
}
}
/* HUD countdown */
if (g_fBoostUntil[id] > now)
{
set_hudmessage(60, 220, 90, -1.0, 0.82, 0, 0.0, 0.6, 0.0, 0.0, 4)
show_hudmessage(id, "Speed boost: %.1f s", g_fBoostUntil[id] - now)
}
}
}
public OnCurWeapon(id)
{
if (!is_user_alive(id))
return
if (g_fBoostUntil[id] > get_gametime())
set_user_maxspeed(id, g_fBoostSpeed[id])
}
applyBoost(id, Float:duration)
{
g_fBoostUntil[id] = get_gametime() + duration
g_fBoostSpeed[id] = get_pcvar_float(g_pSpeed)
set_user_maxspeed(id, g_fBoostSpeed[id])
client_print(id, print_chat, "[CSB] Speed boost for %.0f seconds!", duration)
}