Randomizes which spawn point a player gets each respawn, validating points with a hull trace and distance check.
csb_random_spawns.sma v1.0.0
1
/*
2
* CSB Random Spawns
3
* Copyright (C) 2026 counter-strike-boost.com
4
*
5
* Overrides the map's normal spawn assignment with a randomized pick from all
6
* info_player_deathmatch / info_player_start / info_vip_start entities. Before
7
* a point is used it is validated with a hull trace (must not start in solid)
8
* and a distance check against living players, so nobody spawns inside a
9
* teammate or in front of an enemy's crosshair. Designed for deathmatch and
10
* gungame servers to reduce spawn camping.
11
*
12
* This program is free software: you can redistribute it and/or modify it under
13
* the terms of the GNU General Public License as published by the Free Software
14
* Foundation, either version 3 of the License, or (at your option) any later
15
* version. It is distributed in the hope that it will be useful, but WITHOUT
16
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
* FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
18
*/
19
20
#include <amxmodx>
21
#include <hamsandwich>
22
#include <fakemeta>
23
#include <engine>
24
25
new const PLUGIN[] = "CSB Random Spawns"
26
new const VERSION[] = "1.0.0"
27
new const AUTHOR[] = "counter-strike-boost.com"
28
29
#define MAX_SPAWNS 128
30
31
new g_iSpawnCount
32
new Float:g_fSpawnOrigin[MAX_SPAWNS][3]
33
new Float:g_fSpawnAngles[MAX_SPAWNS][3]
34
35
new g_pEnabled, g_pMinDist
36
37
public plugin_init()
38
{
39
register_plugin(PLUGIN, VERSION, AUTHOR)
40
41
g_pEnabled = register_cvar("csb_rspawns_enabled", "1")
42
g_pMinDist = register_cvar("csb_rspawns_mindist", "70.0")
43
44
RegisterHam(Ham_Spawn, "player", "OnPlayerSpawn", 1)
45
46
collectSpawns("info_player_deathmatch")
47
collectSpawns("info_player_start")
48
collectSpawns("info_vip_start")
49
50
log_amx("[CSB] Random Spawns: collected %d spawn point(s).", g_iSpawnCount)
51
}
52
53
collectSpawns(const className[])
54
{
55
new ent = -1
56
57
while ((ent = find_ent_by_class(ent, className)) > 0)
58
{
59
if (g_iSpawnCount >= MAX_SPAWNS)
60
break
61
62
new Float:orig[3], Float:ang[3]
63
pev(ent, pev_origin, orig)
64
pev(ent, pev_angles, ang)
65
66
/* lift slightly so the hull never clips the floor */
67
orig[2] += 2.0
68
69
g_fSpawnOrigin[g_iSpawnCount][0] = orig[0]
70
g_fSpawnOrigin[g_iSpawnCount][1] = orig[1]
71
g_fSpawnOrigin[g_iSpawnCount][2] = orig[2]
72
g_fSpawnAngles[g_iSpawnCount][0] = ang[0]
73
g_fSpawnAngles[g_iSpawnCount][1] = ang[1]
74
g_fSpawnAngles[g_iSpawnCount][2] = ang[2]
75
g_iSpawnCount++
76
}
77
}
78
79
public OnPlayerSpawn(id)
80
{
81
if (!get_pcvar_num(g_pEnabled) || !is_user_alive(id) || g_iSpawnCount < 1)
82
return
83
84
new team = get_user_team(id)
85
if (team != 1 && team != 2)
86
return
87
88
new start = random_num(0, g_iSpawnCount - 1)
89
new Float:minDist = get_pcvar_float(g_pMinDist)
90
91
for (new i = 0; i < g_iSpawnCount; i++)
92
{
93
new idx = (start + i) % g_iSpawnCount
94
95
if (!spawnFree(idx, id, minDist))
96
continue
97
98
new Float:orig[3], Float:ang[3]
99
orig[0] = g_fSpawnOrigin[idx][0]
100
orig[1] = g_fSpawnOrigin[idx][1]
101
orig[2] = g_fSpawnOrigin[idx][2]
102
ang[0] = g_fSpawnAngles[idx][0]
103
ang[1] = g_fSpawnAngles[idx][1]
104
ang[2] = g_fSpawnAngles[idx][2]
105
106
set_pev(id, pev_origin, orig)
107
set_pev(id, pev_angles, ang)
108
set_pev(id, pev_v_angle, ang)
109
set_pev(id, pev_fixangle, 1)
110
return
111
}
112
}
113
114
bool:spawnFree(idx, id, Float:minDist)
115
{
116
static Float:orig[3]
117
orig[0] = g_fSpawnOrigin[idx][0]
118
orig[1] = g_fSpawnOrigin[idx][1]
119
orig[2] = g_fSpawnOrigin[idx][2]
120
121
/* bit 1 (StartSolid) means a player hull does not fit here */
122
if (trace_hull(orig, HULL_HUMAN, id) & 1)
123
return false
124
125
static players[32], num
126
get_players(players, num, "a")
127
128
for (new i = 0; i < num; i++)
129
{
130
if (players[i] == id)
131
continue
132
133
static Float:o2[3]
134
pev(players[i], pev_origin, o2)
135
136
if (get_distance_f(orig, o2) < minDist)
137
return false
138
}
139
140
return true
141
}
142









