/* * CSB Admin Tag * Copyright (C) 2026 counter-strike-boost.com * * Prints a configurable coloured prefix (e.g. [ADMIN], [OWNER]) before an * admin's chat line based on their access flags. Tags are read from * configs/csb_tags.ini. The say/say_team message is intercepted and re-sent via * the SayText user message so the *DEAD* marker and team colouring stay correct. * * Inspired by Admin Prefix by Alka. Independent GPL re-implementation; no * original code is reused. * * 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 #define MAX_TAGS 24 new const PLUGIN[] = "CSB Admin Tag" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pEnabled new g_msgSayText new g_iTagFlags[MAX_TAGS] new g_szTagText[MAX_TAGS][24] new g_iTagCount = 0 public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_tag_enabled", "1") register_clcmd("say", "hookSay") register_clcmd("say_team", "hookSayTeam") g_msgSayText = get_user_msgid("SayText") loadTags() } loadTags() { new dir[128] get_localinfo("amxx_configsdir", dir, charsmax(dir)) new path[160] formatex(path, charsmax(path), "%s/csb_tags.ini", dir) if (!file_exists(path)) { /* seed a sane default so admins have something to edit */ write_file(path, "; CSB Admin Tag - one rule per line: ") write_file(path, "; flags use AMXX access letters; first matching line wins.") write_file(path, "z [OWNER]") write_file(path, "b [ADMIN]") write_file(path, "c [MOD]") } new f = fopen(path, "rt") if (!f) { log_amx("[CSB Tag] could not open %s", path) return } new line[128], flagStr[32], tag[24] while (!feof(f) && g_iTagCount < MAX_TAGS) { fgets(f, line, charsmax(line)) trim(line) if (!line[0] || line[0] == ';' || line[0] == '#') continue strtok(line, flagStr, charsmax(flagStr), tag, charsmax(tag), ' ') trim(tag) if (!flagStr[0] || !tag[0]) continue g_iTagFlags[g_iTagCount] = read_flags(flagStr) copy(g_szTagText[g_iTagCount], charsmax(g_szTagText[]), tag) g_iTagCount++ } fclose(f) log_amx("[CSB Tag] loaded %d tag rule(s).", g_iTagCount) } tagFor(id, out[], len) { out[0] = 0 new flags = get_user_flags(id) for (new i = 0; i < g_iTagCount; i++) { if (flags & g_iTagFlags[i]) { copy(out, len, g_szTagText[i]) return } } } public hookSay(id) { return handleChat(id, false) } public hookSayTeam(id) { return handleChat(id, true) } handleChat(id, bool:teamOnly) { if (!get_pcvar_num(g_pEnabled) || !is_user_connected(id)) return PLUGIN_CONTINUE new tag[24] tagFor(id, tag, charsmax(tag)) if (!tag[0]) return PLUGIN_CONTINUE new msg[160] read_args(msg, charsmax(msg)) remove_quotes(msg) trim(msg) if (!msg[0]) return PLUGIN_HANDLED /* leave command-style lines to the plugins that own them */ if (msg[0] == '/' || msg[0] == '!') return PLUGIN_CONTINUE new name[32] get_user_name(id, name, charsmax(name)) new bool:dead = !is_user_alive(id) new senderTeam = get_user_team(id) new out[192] formatex(out, charsmax(out), "%s^x04 %s ^x03%s^x01 : %s", dead ? "*DEAD* " : "", tag, name, msg) new players[32], num, pid get_players(players, num, "ch") for (new i = 0; i < num; i++) { pid = players[i] if (teamOnly) { /* team chat: same team, or dead players see dead team chat */ if (get_user_team(pid) != senderTeam) continue } message_begin(MSG_ONE, g_msgSayText, _, pid) write_byte(id) write_string(out) message_end() } return PLUGIN_HANDLED }