Votre serveur ici Participez à l'enchère hebdomadaire Promouvoir serveur
csb-rules-menu / addons / amxmodx / scripting / csb_rules_menu.sma
173 lines 4.5 KiB Pawn Raw Permalink History
/*
 * CSB Rules Menu
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * "say /rules" opens a menu of the server rules, loaded from an ini split into
 * [Section] blocks. Selecting a section shows its text in an MOTD window. Players
 * who just connected get a short one-line reminder to read the rules, and admins
 * can reload the ini without changing the map with amx_reloadrules.
 *
 * 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 <amxmisc>

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

#define MAX_SECTIONS 16

new g_szTitle[MAX_SECTIONS][48]
new g_szBody[MAX_SECTIONS][512]
new g_iSections

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

    register_clcmd("say /rules", "cmdRules")
    register_clcmd("say_team /rules", "cmdRules")

    register_concmd("amx_reloadrules", "cmdReload", ADMIN_CFG, "- reload the server rules ini")
}

public plugin_cfg()
{
    loadRules()
}

loadRules()
{
    g_iSections = 0

    new cfgdir[128], path[160]
    get_localinfo("amxx_configsdir", cfgdir, charsmax(cfgdir))
    formatex(path, charsmax(path), "%s/csb_rules.ini", cfgdir)

    if (!file_exists(path))
    {
        /* fall back to a built-in rule set so the menu is never empty */
        copy(g_szTitle[0], charsmax(g_szTitle[]), "General")
        copy(g_szBody[0], charsmax(g_szBody[]),
            "1. Respect all players and admins.^n2. No cheating of any kind.^n3. No advertising or spam.^n4. Admin decisions are final.")
        g_iSections = 1
        return
    }

    new f = fopen(path, "rt")

    if (!f)
        return

    new line[256], cur = -1

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

        if (!line[0] || line[0] == ';' || line[0] == '#')
            continue

        if (line[0] == '[')
        {
            new title[48]
            copy(title, charsmax(title), line[1])

            new close = contain(title, "]")
            if (close != -1)
                title[close] = 0

            trim(title)

            cur = g_iSections
            copy(g_szTitle[cur], charsmax(g_szTitle[]), title)
            g_szBody[cur][0] = 0
            g_iSections++
        }
        else if (cur >= 0)
        {
            if (g_szBody[cur][0])
                add(g_szBody[cur], charsmax(g_szBody[]), "^n")

            add(g_szBody[cur], charsmax(g_szBody[]), line)
        }
    }

    fclose(f)

    if (!g_iSections)
    {
        copy(g_szTitle[0], charsmax(g_szTitle[]), "General")
        copy(g_szBody[0], charsmax(g_szBody[]), "Be excellent to each other.")
        g_iSections = 1
    }
}

public client_putinserver(id)
{
    set_task(12.0, "taskReminder", id)
}

public taskReminder(id)
{
    if (is_user_connected(id))
        client_print(id, print_chat, "[CSB] Type /rules to read the server rules.")
}

public cmdRules(id)
{
    new menu = menu_create("\yServer Rules\w - pick a section:", "rulesHandler")

    new info[8]
    for (new i = 0; i < g_iSections; i++)
    {
        num_to_str(i, info, charsmax(info))
        menu_additem(menu, g_szTitle[i], info, 0)
    }

    menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
    menu_display(id, menu, 0)
    return PLUGIN_HANDLED
}

public rulesHandler(id, menu, item)
{
    if (item == MENU_EXIT)
    {
        menu_destroy(menu)
        return PLUGIN_HANDLED
    }

    new info[8], name[48], access, callback
    menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback)
    menu_destroy(menu)

    new sec = str_to_num(info)

    if (sec < 0 || sec >= g_iSections)
        return PLUGIN_HANDLED

    new head[64]
    formatex(head, charsmax(head), "Rules - %s", g_szTitle[sec])
    show_motd(id, g_szBody[sec], head)
    return PLUGIN_HANDLED
}

public cmdReload(id, level, cid)
{
    if (!cmd_access(id, level, cid, 1))
        return PLUGIN_HANDLED

    loadRules()
    console_print(id, "[CSB] Reloaded %d rule section(s).", g_iSections)
    client_print(id, print_chat, "[CSB] Rules reloaded (%d sections).", g_iSections)
    return PLUGIN_HANDLED
}