Promouvoir serveur
csb-spawn-protection / addons / amxmodx / scripting / csb_spawn_protection.sma
163 lines 4.3 KiB Pawn Raw Permalink History
/*
 * CSB Spawn Protection
 * Copyright (C) 2026 counter-strike-boost.com
 *
 * Gives players a short window of invulnerability when they spawn, with a
 * visible glow shell so everyone can see who is still protected. Protection is
 * dropped early when the player fires (cvar) or moves (cvar), and always ends
 * when the timer runs out. Built for DM / CSDM style servers where players
 * respawn constantly and spawn-camping is a real problem.
 *
 * This is an independent GPL implementation; it is not based on any other
 * plugin's source.
 *
 * 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 the GNU General
 * Public License for more details: <https://www.gnu.org/licenses/>.
 */

#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <fun>

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

#define TASK_END 5000

new g_pEnabled, g_pTime, g_pBreakFire, g_pBreakMove, g_pAlpha

new bool:g_bProtected[33]

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

    g_pEnabled    = register_cvar("csb_spawnprot_enabled", "1")
    g_pTime       = register_cvar("csb_spawnprot_time", "3.0")
    g_pBreakFire  = register_cvar("csb_spawnprot_breakfire", "1")
    g_pBreakMove  = register_cvar("csb_spawnprot_breakmove", "0")
    g_pAlpha      = register_cvar("csb_spawnprot_alpha", "160")

    RegisterHam(Ham_Spawn, "player", "fwdSpawnPost", 1)
    register_forward(FM_CmdStart, "fwdCmdStart")
    register_event("DeathMsg", "evDeath", "a")
}

public fwdSpawnPost(id)
{
    if (!get_pcvar_num(g_pEnabled))
        return

    if (!is_user_alive(id) || !is_user_connected(id))
        return

    new Float:seconds = get_pcvar_float(g_pTime)

    if (seconds <= 0.0)
        return

    startProtection(id, seconds)
}

startProtection(id, Float:seconds)
{
    g_bProtected[id] = true
    set_user_godmode(id, 1)

    new r, g, b
    teamColor(id, r, g, b)

    set_user_rendering(id, kRenderFxGlowShell, r, g, b, kRenderNormal, 16)

    /* also make the model itself slightly translucent */
    new alpha = clamp(get_pcvar_num(g_pAlpha), 0, 255)
    set_pev(id, pev_rendermode, kRenderTransColor)
    set_pev(id, pev_renderamt, float(alpha))

    remove_task(id + TASK_END)
    set_task(seconds, "taskEnd", id + TASK_END)

    client_print(id, print_center, "* Spawn protection active for %.1f seconds *", seconds)
}

teamColor(id, &r, &g, &b)
{
    /* CS: team 1 = T (red), team 2 = CT (blue) */
    switch (pev(id, pev_team))
    {
        case 1: { r = 255; g = 80;  b = 80;  }
        case 2: { r = 80;  g = 120; b = 255; }
        default: { r = 200; g = 200; b = 200; }
    }
}

public taskEnd(taskid)
{
    new id = taskid - TASK_END
    endProtection(id, true)
}

endProtection(id, bool:notify)
{
    if (!g_bProtected[id])
        return

    g_bProtected[id] = false
    remove_task(id + TASK_END)

    if (is_user_connected(id))
    {
        set_user_godmode(id, 0)
        set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 16)
        set_pev(id, pev_rendermode, kRenderNormal)
        set_pev(id, pev_renderamt, 0.0)

        if (notify && is_user_alive(id))
            client_print(id, print_center, "* Spawn protection ended *")
    }
}

public fwdCmdStart(id, uc_handle, seed)
{
    if (!g_bProtected[id] || !is_user_alive(id))
        return FMRES_IGNORED

    new buttons = get_uc(uc_handle, UC_Buttons)

    if (get_pcvar_num(g_pBreakFire) && (buttons & IN_ATTACK))
    {
        endProtection(id, true)
        return FMRES_IGNORED
    }

    if (get_pcvar_num(g_pBreakMove))
    {
        new moveMask = IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP | IN_DUCK

        if (buttons & moveMask)
            endProtection(id, true)
    }

    return FMRES_IGNORED
}

public evDeath()
{
    new victim = read_data(2)

    if (1 <= victim <= 32)
        endProtection(victim, false)
}

public client_disconnected(id)
{
    g_bProtected[id] = false
    remove_task(id + TASK_END)
}