A build phase where builders grab, carry, rotate and lock map props, followed by a fight phase where the other team must break in.
csb_base_builder.sma v1.0.0
1
/*
2
* CSB Base Builder
3
* Copyright (C) 2026 counter-strike-boost.com
4
*
5
* Base Builder core. Each round opens with a build phase in which the builder
6
* team can grab, carry, rotate and lock map props: /grab pins whatever brush
7
* prop your crosshair is on in front of you (moved every frame in
8
* PlayerPreThink), /rotate spins it, /lock freezes it in place, /drop releases
9
* it. Each builder is limited to a number of locked props. When the build timer
10
* expires the fight phase starts, every prop is frozen and the attacking team
11
* must break in.
12
*
13
* Inspired by Base Builder (ConnorMcLeod / Kreedz community). Independent GPL
14
* re-implementation.
15
*
16
* This program is free software: you can redistribute it and/or modify it under
17
* the terms of the GNU General Public License as published by the Free Software
18
* Foundation, either version 3 of the License, or (at your option) any later
19
* version. It is distributed in the hope that it will be useful, but WITHOUT
20
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21
* FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
22
*/
23
24
#include <amxmodx>
25
#include <fakemeta>
26
27
new const PLUGIN[] = "CSB Base Builder"
28
new const VERSION[] = "1.0.0"
29
new const AUTHOR[] = "counter-strike-boost.com"
30
31
#define PHASE_BUILD 0
32
#define PHASE_FIGHT 1
33
34
new g_pEnabled, g_pBuildTime, g_pBuilderTeam, g_pPropLimit
35
36
new g_iPhase
37
new g_iGrab[33]
38
new Float:g_fGrabDist[33]
39
new Float:g_fGrabYaw[33]
40
new g_iLockedCount[33]
41
new g_iHudSync
42
43
public plugin_init()
44
{
45
register_plugin(PLUGIN, VERSION, AUTHOR)
46
47
g_pEnabled = register_cvar("csb_bb_enabled", "1")
48
g_pBuildTime = register_cvar("csb_bb_buildtime", "45")
49
g_pBuilderTeam = register_cvar("csb_bb_builderteam", "2") /* 1=T 2=CT */
50
g_pPropLimit = register_cvar("csb_bb_proplimit", "6")
51
52
register_clcmd("say /grab", "cmdGrab")
53
register_clcmd("say /drop", "cmdDrop")
54
register_clcmd("say /rotate", "cmdRotate")
55
register_clcmd("say /lock", "cmdLock")
56
57
register_forward(FM_PlayerPreThink, "fwPreThink")
58
register_logevent("eventRoundStart", 2, "1=Round_Start")
59
60
g_iHudSync = CreateHudSyncObj()
61
62
set_task(1.0, "taskHud", 0, _, _, "b")
63
}
64
65
public client_putinserver(id)
66
{
67
g_iGrab[id] = 0
68
g_iLockedCount[id] = 0
69
}
70
71
public client_disconnected(id)
72
{
73
g_iGrab[id] = 0
74
}
75
76
public eventRoundStart()
77
{
78
if (!get_pcvar_num(g_pEnabled))
79
return
80
81
g_iPhase = PHASE_BUILD
82
83
for (new id = 1; id <= 32; id++)
84
{
85
g_iGrab[id] = 0
86
g_iLockedCount[id] = 0
87
}
88
89
client_print(0, print_chat, "[CSB] BUILD PHASE - %d seconds. Builders: /grab /rotate /lock /drop", get_pcvar_num(g_pBuildTime))
90
91
set_task(float(get_pcvar_num(g_pBuildTime)), "taskFightPhase", 9911)
92
}
93
94
public taskFightPhase()
95
{
96
g_iPhase = PHASE_FIGHT
97
98
/* drop and freeze everything */
99
for (new id = 1; id <= 32; id++)
100
{
101
if (g_iGrab[id] > 0)
102
{
103
freezeProp(g_iGrab[id])
104
g_iGrab[id] = 0
105
}
106
}
107
108
client_print(0, print_chat, "[CSB] FIGHT PHASE - break into the base!")
109
}
110
111
bool:isBuilder(id)
112
{
113
return get_user_team(id) == get_pcvar_num(g_pBuilderTeam)
114
}
115
116
bool:isGrabbable(ent)
117
{
118
if (ent <= 32 || !pev_valid(ent))
119
return false
120
121
static cls[32]
122
pev(ent, pev_classname, cls, charsmax(cls))
123
124
if (equal(cls, "worldspawn") || equal(cls, "player"))
125
return false
126
127
/* brush props and pushables only */
128
if (equal(cls, "func_pushable") || equal(cls, "func_breakable")
129
|| equal(cls, "func_wall") || equal(cls, "func_door")
130
|| containi(cls, "func_") == 0)
131
return true
132
133
return false
134
}
135
136
public cmdGrab(id)
137
{
138
if (!get_pcvar_num(g_pEnabled) || g_iPhase != PHASE_BUILD)
139
{
140
client_print(id, print_chat, "[CSB] You can only build during the build phase.")
141
return PLUGIN_HANDLED
142
}
143
144
if (!isBuilder(id) || !is_user_alive(id))
145
return PLUGIN_HANDLED
146
147
if (g_iGrab[id] > 0)
148
{
149
client_print(id, print_chat, "[CSB] You are already carrying a prop. /drop or /lock first.")
150
return PLUGIN_HANDLED
151
}
152
153
new ent, body
154
get_user_aiming(id, ent, body, 700)
155
156
if (!isGrabbable(ent))
157
{
158
client_print(id, print_chat, "[CSB] No movable prop in your crosshair.")
159
return PLUGIN_HANDLED
160
}
161
162
static Float:fMe[3], Float:fProp[3]
163
pev(id, pev_origin, fMe)
164
pev(ent, pev_origin, fProp)
165
166
g_iGrab[id] = ent
167
g_fGrabDist[id] = vector_distance(fMe, fProp)
168
169
if (g_fGrabDist[id] > 200.0)
170
g_fGrabDist[id] = 200.0
171
else if (g_fGrabDist[id] < 80.0)
172
g_fGrabDist[id] = 80.0
173
174
static Float:fAng[3]
175
pev(ent, pev_angles, fAng)
176
g_fGrabYaw[id] = fAng[1]
177
178
/* make it float freely while carried */
179
set_pev(ent, pev_movetype, MOVETYPE_NOCLIP)
180
181
client_print(id, print_chat, "[CSB] Prop grabbed. /rotate to spin, /lock to place.")
182
return PLUGIN_HANDLED
183
}
184
185
public cmdDrop(id)
186
{
187
if (g_iGrab[id] > 0)
188
{
189
set_pev(g_iGrab[id], pev_movetype, MOVETYPE_TOSS)
190
g_iGrab[id] = 0
191
client_print(id, print_chat, "[CSB] Prop dropped.")
192
}
193
194
return PLUGIN_HANDLED
195
}
196
197
public cmdRotate(id)
198
{
199
if (g_iGrab[id] > 0)
200
{
201
g_fGrabYaw[id] += 45.0
202
203
if (g_fGrabYaw[id] >= 360.0)
204
g_fGrabYaw[id] -= 360.0
205
206
client_print(id, print_chat, "[CSB] Rotated to %d degrees.", floatround(g_fGrabYaw[id]))
207
}
208
209
return PLUGIN_HANDLED
210
}
211
212
public cmdLock(id)
213
{
214
if (g_iGrab[id] <= 0)
215
return PLUGIN_HANDLED
216
217
if (g_iLockedCount[id] >= get_pcvar_num(g_pPropLimit))
218
{
219
client_print(id, print_chat, "[CSB] You reached your prop limit (%d).", get_pcvar_num(g_pPropLimit))
220
return PLUGIN_HANDLED
221
}
222
223
new ent = g_iGrab[id]
224
freezeProp(ent)
225
set_pev(ent, pev_owner, id)
226
227
g_iGrab[id] = 0
228
g_iLockedCount[id]++
229
230
client_print(id, print_chat, "[CSB] Prop locked in place (%d/%d).", g_iLockedCount[id], get_pcvar_num(g_pPropLimit))
231
return PLUGIN_HANDLED
232
}
233
234
freezeProp(ent)
235
{
236
if (!pev_valid(ent))
237
return
238
239
static Float:fZero[3]
240
set_pev(ent, pev_velocity, fZero)
241
set_pev(ent, pev_movetype, MOVETYPE_PUSHSTEP)
242
}
243
244
public fwPreThink(id)
245
{
246
new ent = g_iGrab[id]
247
248
if (ent <= 0)
249
return
250
251
if (!is_user_alive(id) || !pev_valid(ent))
252
{
253
g_iGrab[id] = 0
254
return
255
}
256
257
static Float:fEye[3], Float:fOfs[3], Float:fAng[3], Float:fFwd[3], Float:fDest[3]
258
pev(id, pev_origin, fEye)
259
pev(id, pev_view_ofs, fOfs)
260
fEye[0] += fOfs[0]
261
fEye[1] += fOfs[1]
262
fEye[2] += fOfs[2]
263
264
pev(id, pev_v_angle, fAng)
265
angle_vector(fAng, ANGLEVECTOR_FORWARD, fFwd)
266
267
fDest[0] = fEye[0] + fFwd[0] * g_fGrabDist[id]
268
fDest[1] = fEye[1] + fFwd[1] * g_fGrabDist[id]
269
fDest[2] = fEye[2] + fFwd[2] * g_fGrabDist[id]
270
271
static Float:fZero[3]
272
set_pev(ent, pev_velocity, fZero)
273
engfunc(EngFunc_SetOrigin, ent, fDest)
274
275
static Float:fSet[3]
276
fSet[0] = 0.0
277
fSet[1] = g_fGrabYaw[id]
278
fSet[2] = 0.0
279
set_pev(ent, pev_angles, fSet)
280
}
281
282
public taskHud()
283
{
284
if (!get_pcvar_num(g_pEnabled))
285
return
286
287
new players[32], num
288
get_players(players, num, "ch")
289
290
for (new i = 0; i < num; i++)
291
{
292
new id = players[i]
293
294
set_hudmessage(255, 180, 0, 0.02, 0.12, 0, 0.0, 1.1, 0.0, 0.0, -1)
295
296
if (g_iPhase == PHASE_BUILD && isBuilder(id))
297
ShowSyncHudMsg(id, g_iHudSync, "BUILD PHASE | props %d/%d", g_iLockedCount[id], get_pcvar_num(g_pPropLimit))
298
else if (g_iPhase == PHASE_BUILD)
299
ShowSyncHudMsg(id, g_iHudSync, "BUILD PHASE | wait for the fight")
300
else
301
ShowSyncHudMsg(id, g_iHudSync, "FIGHT PHASE")
302
}
303
}
304









