Daemon666 / CSB Random Spawns Public

Randomizes which spawn point a player gets each respawn, validating points with a hull trace and distance check.

v1.0.0 131 downloads GPL-3.0 Last updated Aug 23, 2026
csb_random_spawns.sma v1.0.0 142 lines · 4.0 KB Raw
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