/*
* CSB Jump Stats
* Copyright (C) 2026 counter-strike-boost.com
*
* Announces notable jumps. Every player is watched in PlayerPostThink: when they
* leave the ground the takeoff origin is stored, the peak horizontal speed while
* airborne is tracked, and on landing the horizontal distance covered is
* measured. Jumps over a distance threshold are printed to chat, and the longest
* jump on the current map is kept in an nVault, announced when it is beaten.
*
* 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
#include
new const PLUGIN[] = "CSB Jump Stats"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
#if !defined FL_ONGROUND
#define FL_ONGROUND (1<<9)
#endif
new g_pEnabled, g_pMinDist
new bool:g_bInAir[33]
new Float:g_fTakeoff[33][3]
new Float:g_fMaxSpeed[33]
new g_vault
new g_szMap[32]
new Float:g_fRecord
new g_szRecordHolder[32]
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_js_enabled", "1")
g_pMinDist = register_cvar("csb_js_mindist", "200")
register_forward(FM_PlayerPostThink, "fwPostThink")
register_clcmd("say /jumprecord", "cmdRecord")
register_clcmd("say_team /jumprecord", "cmdRecord")
get_mapname(g_szMap, charsmax(g_szMap))
g_vault = nvault_open("csb_jumpstats")
loadRecord()
}
public plugin_end()
{
nvault_close(g_vault)
}
loadRecord()
{
new key[48]
formatex(key, charsmax(key), "rec_%s", g_szMap)
new data[64]
if (nvault_get(g_vault, key, data, charsmax(data)))
{
new distStr[16]
strtok(data, distStr, charsmax(distStr), g_szRecordHolder, charsmax(g_szRecordHolder), '|')
g_fRecord = str_to_float(distStr)
}
else
{
g_fRecord = 0.0
copy(g_szRecordHolder, charsmax(g_szRecordHolder), "nobody")
}
}
saveRecord()
{
new key[48], data[64]
formatex(key, charsmax(key), "rec_%s", g_szMap)
formatex(data, charsmax(data), "%f|%s", g_fRecord, g_szRecordHolder)
nvault_set(g_vault, key, data)
}
public client_putinserver(id)
{
g_bInAir[id] = false
g_fMaxSpeed[id] = 0.0
}
public fwPostThink(id)
{
if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
return FMRES_IGNORED
new flags = pev(id, pev_flags)
new bool:onground = (flags & FL_ONGROUND) != 0
static Float:fVel[3]
pev(id, pev_velocity, fVel)
new Float:hspeed = floatsqroot(fVel[0] * fVel[0] + fVel[1] * fVel[1])
if (!onground)
{
if (!g_bInAir[id])
{
g_bInAir[id] = true
pev(id, pev_origin, g_fTakeoff[id])
g_fMaxSpeed[id] = hspeed
}
else if (hspeed > g_fMaxSpeed[id])
{
g_fMaxSpeed[id] = hspeed
}
}
else if (g_bInAir[id])
{
g_bInAir[id] = false
landed(id)
}
return FMRES_IGNORED
}
landed(id)
{
static Float:fNow[3]
pev(id, pev_origin, fNow)
new Float:dx = fNow[0] - g_fTakeoff[id][0]
new Float:dy = fNow[1] - g_fTakeoff[id][1]
new Float:dist = floatsqroot(dx * dx + dy * dy)
if (dist < get_pcvar_float(g_pMinDist))
return
new name[32]
get_user_name(id, name, charsmax(name))
client_print(id, print_chat, "^x04[CSB]^x01 Jump: %.1f units at %.0f u/s.", dist, g_fMaxSpeed[id])
if (dist > g_fRecord)
{
g_fRecord = dist
copy(g_szRecordHolder, charsmax(g_szRecordHolder), name)
saveRecord()
client_print(0, print_chat, "^x04[CSB]^x01 NEW MAP RECORD! %s jumped %.1f units!", name, dist)
}
}
public cmdRecord(id)
{
client_print(id, print_chat, "^x04[CSB]^x01 Longest jump on %s: %.1f units by %s.", g_szMap, g_fRecord, g_szRecordHolder)
return PLUGIN_HANDLED
}