/*
* CSB Respawn On Join
* Copyright (C) 2026 counter-strike-boost.com
*
* Players who join a team mid-round are respawned right away instead of waiting
* for the next round. The respawn goes through Ham_CS_RoundRespawn, the player
* gets a few seconds of spawn protection (godmode + a glow), and an end-of-round
* guard stops it from spawning people into a round that is about to end.
*
* 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. See for details.
*/
#include
#include
#include
new const PLUGIN[] = "CSB Respawn On Join"
new const VERSION[] = "1.0.0"
new const AUTHOR[] = "counter-strike-boost.com"
new g_pEnabled, g_pDelay, g_pProtect, g_pEndGuard
new Float:g_fRoundStart
new bool:g_bRoundActive
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
g_pEnabled = register_cvar("csb_roj_enabled", "1")
g_pDelay = register_cvar("csb_roj_delay", "2.0")
g_pProtect = register_cvar("csb_roj_protect", "3.0")
g_pEndGuard = register_cvar("csb_roj_endguard", "20") /* seconds before round end to stop respawning */
register_event("TeamInfo", "evTeamInfo", "a")
register_logevent("evRoundStart", 2, "1=Round_Start")
register_logevent("evRoundEnd", 2, "1=Round_End")
RegisterHam(Ham_Spawn, "player", "fwSpawnPost", 1)
}
public evRoundStart()
{
g_fRoundStart = get_gametime()
g_bRoundActive = true
}
public evRoundEnd()
{
g_bRoundActive = false
}
/* TeamInfo fires when a player is assigned a team. arg1 = index, arg2 = team. */
public evTeamInfo()
{
if (!get_pcvar_num(g_pEnabled))
return
new id = read_data(1)
if (id < 1 || id > get_maxplayers() || !is_user_connected(id))
return
new team[8]
read_data(2, team, charsmax(team))
/* only real playing teams */
if (!equal(team, "TERRORIST") && !equal(team, "CT"))
return
/* already alive? nothing to do */
if (is_user_alive(id))
return
if (!g_bRoundActive)
return
if (isNearRoundEnd())
return
new Float:delay = get_pcvar_float(g_pDelay)
if (delay < 0.1)
delay = 0.1
set_task(delay, "taskRespawn", id + 20000)
}
bool:isNearRoundEnd()
{
new guard = get_pcvar_num(g_pEndGuard)
if (guard <= 0)
return false
new Float:roundTime = get_cvar_float("mp_roundtime") * 60.0 /* mp_roundtime is in minutes */
if (roundTime <= 0.0)
return false
new Float:elapsed = get_gametime() - g_fRoundStart
return (elapsed > (roundTime - float(guard)))
}
public taskRespawn(param)
{
new id = param - 20000
if (!is_user_connected(id) || is_user_alive(id) || !g_bRoundActive)
return
new team = get_user_team(id)
if (team != 1 && team != 2)
return
ExecuteHamB(Ham_CS_RoundRespawn, id)
}
/* Give spawn protection on every spawn (natural or our forced one). */
public fwSpawnPost(id)
{
if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id))
return
new Float:protect = get_pcvar_float(g_pProtect)
if (protect <= 0.0)
return
set_user_godmode(id, 1)
set_user_rendering(id, kRenderFxGlowShell, 0, 200, 255, kRenderNormal, 12)
set_task(protect, "taskEndProtect", id + 20000)
}
public taskEndProtect(param)
{
new id = param - 20000
if (!is_user_connected(id))
return
set_user_godmode(id, 0)
if (is_user_alive(id))
set_user_rendering(id, kRenderFxNone, 0, 0, 0, kRenderNormal, 16)
}