Admins grab a player or entity with +grab, push/pull it with the mouse wheel and throw it on release.
csb_admin_grab.sma v1.0.0
1
/*
2
* CSB Admin Grab
3
* Copyright (C) 2026 counter-strike-boost.com
4
*
5
* Lets an admin grab a player (or a physics entity) with +grab: while the key is
6
* held the target is pinned in the air at a fixed distance along the admin's aim
7
* direction, updated every frame in PlayerPreThink. invnext / invprev change the
8
* hold distance, and releasing +grab throws the target with velocity along the
9
* aim vector.
10
*
11
* Inspired by Admin Grab by KRoTaL. Independent GPL re-implementation; no
12
* original code is reused.
13
*
14
* This program is free software: you can redistribute it and/or modify it under
15
* the terms of the GNU General Public License as published by the Free Software
16
* Foundation, either version 3 of the License, or (at your option) any later
17
* version. It is distributed in the hope that it will be useful, but WITHOUT
18
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19
* FOR A PARTICULAR PURPOSE. See <https://www.gnu.org/licenses/> for details.
20
*/
21
22
#include <amxmodx>
23
#include <fakemeta>
24
25
new const PLUGIN[] = "CSB Admin Grab"
26
new const VERSION[] = "1.0.0"
27
new const AUTHOR[] = "counter-strike-boost.com"
28
29
#define ACCESS_FLAG ADMIN_BAN
30
31
new g_pEnabled, g_pThrow, g_pMaxDist
32
33
new g_iTarget[33]
34
new Float:g_fDist[33]
35
36
public plugin_init()
37
{
38
register_plugin(PLUGIN, VERSION, AUTHOR)
39
40
g_pEnabled = register_cvar("csb_grab_enabled", "1")
41
g_pThrow = register_cvar("csb_grab_throw", "900")
42
g_pMaxDist = register_cvar("csb_grab_maxdist", "800")
43
44
register_clcmd("+grab", "cmdGrabStart")
45
register_clcmd("-grab", "cmdGrabStop")
46
register_clcmd("invnext", "cmdNext")
47
register_clcmd("invprev", "cmdPrev")
48
49
register_forward(FM_PlayerPreThink, "fwPreThink")
50
}
51
52
public client_putinserver(id)
53
{
54
g_iTarget[id] = 0
55
g_fDist[id] = 120.0
56
}
57
58
public client_disconnected(id)
59
{
60
g_iTarget[id] = 0
61
}
62
63
bool:hasAccess(id)
64
{
65
return (get_user_flags(id) & ACCESS_FLAG) != 0
66
}
67
68
public cmdGrabStart(id)
69
{
70
if (!get_pcvar_num(g_pEnabled) || !hasAccess(id) || !is_user_alive(id))
71
return PLUGIN_HANDLED
72
73
new ent, body
74
get_user_aiming(id, ent, body, 4096)
75
76
if (ent < 1 || !pev_valid(ent))
77
{
78
client_print(id, print_chat, "[CSB] Nothing grabbable in your crosshair.")
79
return PLUGIN_HANDLED
80
}
81
82
/* set the hold distance to the current distance to the target */
83
static Float:fMe[3], Float:fThem[3]
84
pev(id, pev_origin, fMe)
85
pev(ent, pev_origin, fThem)
86
87
g_fDist[id] = vector_distance(fMe, fThem)
88
g_iTarget[id] = ent
89
90
new cap = get_pcvar_num(g_pMaxDist)
91
if (g_fDist[id] > float(cap))
92
g_fDist[id] = float(cap)
93
94
client_print(id, print_chat, "[CSB] Grabbed entity %d. Use mouse wheel to push/pull, release to throw.", ent)
95
return PLUGIN_HANDLED
96
}
97
98
public cmdGrabStop(id)
99
{
100
new ent = g_iTarget[id]
101
g_iTarget[id] = 0
102
103
if (ent < 1 || !pev_valid(ent))
104
return PLUGIN_HANDLED
105
106
/* throw along the admin aim vector */
107
static Float:fAng[3], Float:fFwd[3]
108
pev(id, pev_v_angle, fAng)
109
angle_vector(fAng, ANGLEVECTOR_FORWARD, fFwd)
110
111
new Float:speed = get_pcvar_float(g_pThrow)
112
113
static Float:fVel[3]
114
fVel[0] = fFwd[0] * speed
115
fVel[1] = fFwd[1] * speed
116
fVel[2] = fFwd[2] * speed + 100.0
117
118
set_pev(ent, pev_velocity, fVel)
119
return PLUGIN_HANDLED
120
}
121
122
public cmdNext(id)
123
{
124
if (g_iTarget[id] > 0)
125
{
126
g_fDist[id] += 30.0
127
128
new cap = get_pcvar_num(g_pMaxDist)
129
if (g_fDist[id] > float(cap))
130
g_fDist[id] = float(cap)
131
132
return PLUGIN_HANDLED
133
}
134
135
return PLUGIN_CONTINUE
136
}
137
138
public cmdPrev(id)
139
{
140
if (g_iTarget[id] > 0)
141
{
142
g_fDist[id] -= 30.0
143
144
if (g_fDist[id] < 40.0)
145
g_fDist[id] = 40.0
146
147
return PLUGIN_HANDLED
148
}
149
150
return PLUGIN_CONTINUE
151
}
152
153
public fwPreThink(id)
154
{
155
new ent = g_iTarget[id]
156
157
if (ent < 1)
158
return FMRES_IGNORED
159
160
if (!is_user_alive(id) || !pev_valid(ent))
161
{
162
g_iTarget[id] = 0
163
return FMRES_IGNORED
164
}
165
166
static Float:fEye[3], Float:fOfs[3], Float:fAng[3], Float:fFwd[3]
167
pev(id, pev_origin, fEye)
168
pev(id, pev_view_ofs, fOfs)
169
fEye[0] += fOfs[0]
170
fEye[1] += fOfs[1]
171
fEye[2] += fOfs[2]
172
173
pev(id, pev_v_angle, fAng)
174
angle_vector(fAng, ANGLEVECTOR_FORWARD, fFwd)
175
176
static Float:fDest[3]
177
fDest[0] = fEye[0] + fFwd[0] * g_fDist[id]
178
fDest[1] = fEye[1] + fFwd[1] * g_fDist[id]
179
fDest[2] = fEye[2] + fFwd[2] * g_fDist[id]
180
181
/* hold it in place: zero velocity and set origin each frame */
182
static Float:fZero[3]
183
fZero[0] = 0.0
184
fZero[1] = 0.0
185
fZero[2] = 0.0
186
set_pev(ent, pev_velocity, fZero)
187
188
engfunc(EngFunc_SetOrigin, ent, fDest)
189
return FMRES_IGNORED
190
}
191









