/* * CSB Players Menu * Copyright (C) 2026 counter-strike-boost.com * * "say /players" opens a menu listing everyone on the server with their team, * frag count and (in the detail view) their rank, headshots, country and time * played. Selecting a player opens a detail page anyone can read. IP addresses * and SteamIDs are never shown - only a two-letter country code from GeoIP. * * 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 Players Menu" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define VIP_FLAG ADMIN_LEVEL_H new g_iConnectTime[33] public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) register_clcmd("say /players", "cmdPlayers") register_clcmd("say_team /players", "cmdPlayers") } public client_putinserver(id) { g_iConnectTime[id] = get_systime() } public cmdPlayers(id) { showList(id) return PLUGIN_HANDLED } teamName(id, out[], len) { switch (get_user_team(id)) { case 1: copy(out, len, "T") case 2: copy(out, len, "CT") default: copy(out, len, "SPEC") } } showList(id) { new menu = menu_create("\yPlayers Online\w - pick one:", "listHandler") new players[32], num get_players(players, num, "ch") new name[32], line[80], info[8], teamTag[8] for (new i = 0; i < num; i++) { new pl = players[i] get_user_name(pl, name, charsmax(name)) teamName(pl, teamTag, charsmax(teamTag)) formatex(line, charsmax(line), "%s \d[%s] %d frags\w", name, teamTag, get_user_frags(pl)) num_to_str(pl, info, charsmax(info)) menu_additem(menu, line, info, 0) } if (!num) menu_additem(menu, "\dNo players online", "0", 0) menu_setprop(menu, MPROP_EXIT, MEXIT_ALL) menu_display(id, menu, 0) } public listHandler(id, menu, item) { if (item == MENU_EXIT) { menu_destroy(menu) return PLUGIN_HANDLED } new info[8], name[32], access, callback menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback) menu_destroy(menu) new target = str_to_num(info) if (target < 1 || target > 32 || !is_user_connected(target)) { client_print(id, print_chat, "[CSB] That player already left.") return PLUGIN_HANDLED } showDetail(id, target) return PLUGIN_HANDLED } showDetail(id, target) { new name[32] get_user_name(target, name, charsmax(name)) new teamTag[8] teamName(target, teamTag, charsmax(teamTag)) /* rank / stats from csx */ new stats[8], body[8] new rank = get_user_stats(target, stats, body) new total = get_statsnum() /* country code from GeoIP (no IP is ever shown to the viewer) */ new ip[32], ccode[3] get_user_ip(target, ip, charsmax(ip), 1) if (!geoip_code2(ip, ccode)) copy(ccode, charsmax(ccode), "??") new mins = (get_systime() - g_iConnectTime[target]) / 60 new bool:vip = (get_user_flags(target) & VIP_FLAG) != 0 new title[256] formatex(title, charsmax(title), "\y%s\w^n\dTeam:\w %s \dFrags:\w %d^n\dRank:\w %d / %d \dHS:\w %d^n\dCountry:\w %s \dPlaytime:\w %d min^n\dVIP:\w %s", name, teamTag, get_user_frags(target), rank, total, stats[2], ccode, mins, vip ? "Yes" : "No") new menu = menu_create(title, "detailHandler") menu_additem(menu, "\wBack to list", "back", 0) menu_setprop(menu, MPROP_EXIT, MEXIT_ALL) menu_display(id, menu, 0) } public detailHandler(id, menu, item) { menu_destroy(menu) if (item == MENU_EXIT) return PLUGIN_HANDLED showList(id) return PLUGIN_HANDLED }