Promuj serwer
csb-chat-manager / addons / amxmodx / scripting / csb_chat_manager.sma
245 lines 5.9 KiB Pawn Raw Permalink History
/*
 * CSB Chat Manager
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * Full chat formatter. Every say / say_team line is rebuilt from a configurable
 * template made of tokens ({rank} {country} {vip} {admin} {team} {dead} {name}
 * {msg}) and re-broadcast as a coloured SayText message. The template is loaded
 * from a small ini in the amxx data dir (falling back to a sane default), rank
 * is derived from frags, country from the geoip module, and a swear-word filter
 * masks blacklisted words before the line goes out.
 *
 * Inspired by the classic Chat Manager (AMXX). 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 <https://www.gnu.org/licenses/> for details.
 */

#include <amxmodx>
#include <geoip>

new const PLUGIN[] = "CSB Chat Manager"
new const VERSION[] = "1.0.0"
new const AUTHOR[]  = "counter-strike-boost.com"

#define VIP_FLAG   ADMIN_LEVEL_H
#define ADMIN_FLAG ADMIN_KICK

new const g_szDefaultFmt[] = "{dead}{country} {vip}{admin}[{rank}] {name}: {msg}"

new const g_szBadWords[][] =
{
    "fuck", "shit", "bitch", "asshole", "nigger", "faggot", "cunt"
}

new g_pEnabled, g_pFilter, g_pVipTag, g_pAdminTag
new g_szFmt[192]
new g_iSayText

public plugin_init()
{
    register_plugin(PLUGIN, VERSION, AUTHOR)

    g_pEnabled  = register_cvar("csb_chat_enabled", "1")
    g_pFilter   = register_cvar("csb_chat_filter", "1")
    g_pVipTag   = register_cvar("csb_chat_viptag", "*VIP*")
    g_pAdminTag = register_cvar("csb_chat_admintag", "@ADMIN")

    register_clcmd("say", "cmdSay")
    register_clcmd("say_team", "cmdSayTeam")

    g_iSayText = get_user_msgid("SayText")

    loadFormat()
}

loadFormat()
{
    new dir[128]
    get_localinfo("amxx_datadir", dir, charsmax(dir))

    new path[160]
    formatex(path, charsmax(path), "%s/csb_chatformat.ini", dir)

    if (file_exists(path))
    {
        new line[192], len
        new f = fopen(path, "rt")

        while (f && !feof(f))
        {
            fgets(f, line, charsmax(line))
            trim(line)

            if (line[0] && line[0] != ';' && line[0] != '#')
            {
                copy(g_szFmt, charsmax(g_szFmt), line)
                len = 1
                break
            }
        }

        if (f)
            fclose(f)

        if (len)
            return
    }

    copy(g_szFmt, charsmax(g_szFmt), g_szDefaultFmt)
}

public cmdSay(id)
{
    return handle(id, false)
}

public cmdSayTeam(id)
{
    return handle(id, true)
}

handle(id, bool:team)
{
    if (!get_pcvar_num(g_pEnabled) || !is_user_connected(id))
        return PLUGIN_CONTINUE

    new msg[160]
    read_args(msg, charsmax(msg))
    remove_quotes(msg)
    trim(msg)

    if (!msg[0])
        return PLUGIN_HANDLED

    if (get_pcvar_num(g_pFilter))
        censor(msg)

    new out[192]
    build(id, msg, out, charsmax(out))

    sendColored(id, out, team)
    return PLUGIN_HANDLED
}

build(id, const msg[], out[], len)
{
    copy(out, len, g_szFmt)

    /* dead marker */
    replace_string(out, len, "{dead}", is_user_alive(id) ? "" : "^x03*DEAD* ")

    /* rank from frags */
    new frags = get_user_frags(id)
    new rank[16]

    if (frags >= 100)
        copy(rank, charsmax(rank), "Elite")
    else if (frags >= 40)
        copy(rank, charsmax(rank), "Veteran")
    else if (frags >= 10)
        copy(rank, charsmax(rank), "Regular")
    else
        copy(rank, charsmax(rank), "Rookie")

    replace_string(out, len, "{rank}", rank)

    /* country tag from geoip */
    new ip[32], ccode[3]
    get_user_ip(id, ip, charsmax(ip), 1)
    ccode[0] = 0

    if (ip[0])
        geoip_code2(ip, ccode)

    if (!ccode[0])
        copy(ccode, charsmax(ccode), "--")

    new country[8]
    formatex(country, charsmax(country), "[%s]", ccode)
    replace_string(out, len, "{country}", country)

    /* VIP / admin tags */
    new flags = get_user_flags(id)

    new vip[24]
    vip[0] = 0
    if (flags & VIP_FLAG)
    {
        new tag[16]
        get_pcvar_string(g_pVipTag, tag, charsmax(tag))
        formatex(vip, charsmax(vip), "^x04%s^x01 ", tag)
    }
    replace_string(out, len, "{vip}", vip)

    new admin[24]
    admin[0] = 0
    if (flags & ADMIN_FLAG)
    {
        new tag[16]
        get_pcvar_string(g_pAdminTag, tag, charsmax(tag))
        formatex(admin, charsmax(admin), "^x03%s^x01 ", tag)
    }
    replace_string(out, len, "{admin}", admin)

    /* team */
    new tname[8]
    switch (get_user_team(id))
    {
        case 1: copy(tname, charsmax(tname), "T")
        case 2: copy(tname, charsmax(tname), "CT")
        default: copy(tname, charsmax(tname), "SPEC")
    }
    replace_string(out, len, "{team}", tname)

    /* name and message */
    new name[32]
    get_user_name(id, name, charsmax(name))
    replace_string(out, len, "{name}", name)
    replace_string(out, len, "{msg}", msg)
}

censor(msg[])
{
    for (new w = 0; w < sizeof(g_szBadWords); w++)
    {
        new wlen = strlen(g_szBadWords[w])
        new start = 0, pos

        while ((pos = containi(msg[start], g_szBadWords[w])) != -1)
        {
            new at = start + pos

            for (new k = 0; k < wlen; k++)
                msg[at + k] = '*'

            start = at + wlen

            if (msg[start] == 0)
                break
        }
    }
}

sendColored(id, const text[], bool:team)
{
    new players[32], num
    get_players(players, num, "ch")

    for (new i = 0; i < num; i++)
    {
        new dst = players[i]

        if (team && get_user_team(dst) != get_user_team(id))
            continue

        message_begin(MSG_ONE, g_iSayText, _, dst)
        write_byte(id)
        write_string(text)
        message_end()
    }
}