/*
* 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: .
*/
#include
#include
#include
#include
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)
}