AMXX-BG.INFO fakemeta_util.inc Raw include

fakemeta_util.inc

Original include source with line numbers.

Back Download .inc
1 /* Fakemeta Utilities
2 *
3 * by VEN
4 *
5 * This file is provided as is (no warranties).
6 */
7
8 #if !defined _fakemeta_included
9 #include <fakemeta>
10 #endif
11
12 #if defined _fakemeta_util_included
13 #endinput
14 #endif
15 #define _fakemeta_util_included
16
17 #include <xs>
18
19
20 /* Engine functions */
21
22 #define fm_precache_generic(%1) engfunc(EngFunc_PrecacheGeneric, %1)
23 /* stock fm_precache_generic(const file[])
24 return engfunc(EngFunc_PrecacheGeneric, file) */
25
26 #define fm_precache_event(%1,%2) engfunc(EngFunc_PrecacheEvent, %1, %2)
27 /* stock fm_precache_event(type, const name[])
28 return engfunc(EngFunc_PrecacheEvent, type, name) */
29
30 // ported by v3x
31 #define fm_drop_to_floor(%1) engfunc(EngFunc_DropToFloor, %1)
32 /* stock fm_drop_to_floor(entity)
33 return engfunc(EngFunc_DropToFloor, entity) */
34
35 #define fm_force_use(%1,%2) dllfunc(DLLFunc_Use, %2, %1)
36 /* stock fm_force_use(user, used)
37 return dllfunc(DLLFunc_Use, used, user) */
38
39 #define fm_entity_set_size(%1,%2,%3) engfunc(EngFunc_SetSize, %1, %2, %3)
40 /* stock fm_entity_set_size(index, const Float:mins[3], const Float:maxs[3])
41 return engfunc(EngFunc_SetSize, index, mins, maxs) */
42
43 #define fm_get_decal_index(%1) engfunc(EngFunc_DecalIndex, %1)
44 /* stock fm_get_decal_index(const decalname[])
45 return engfunc(EngFunc_DecalIndex, decalname) */
46
47 stock Float:fm_entity_range(ent1, ent2) {
48 new Float:origin1[3], Float:origin2[3]
49 pev(ent1, pev_origin, origin1)
50 pev(ent2, pev_origin, origin2)
51
52 return get_distance_f(origin1, origin2)
53 }
54
55 // based on KoST's port, upgraded version fits into the macros
56 #define fm_create_entity(%1) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, %1))
57 /* stock fm_create_entity(const classname[])
58 return engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, classname)) */
59
60 #define fm_find_ent_by_class(%1,%2) engfunc(EngFunc_FindEntityByString, %1, "classname", %2)
61 /* stock fm_find_ent_by_class(index, const classname[])
62 return engfunc(EngFunc_FindEntityByString, index, "classname", classname) */
63
64 stock fm_find_ent_by_owner(index, const classname[], owner, jghgtype = 0) {
65 new strtype[11] = "classname", ent = index
66 switch (jghgtype) {
67 case 1: strtype = "target"
68 case 2: strtype = "targetname"
69 }
70
71 while ((ent = engfunc(EngFunc_FindEntityByString, ent, strtype, classname)) && pev(ent, pev_owner) != owner) {}
72
73 return ent
74 }
75
76 #define fm_find_ent_by_target(%1,%2) engfunc(EngFunc_FindEntityByString, %1, "target", %2)
77 /* stock fm_find_ent_by_target(index, const target[])
78 return engfunc(EngFunc_FindEntityByString, index, "target", target) */
79
80 #define fm_find_ent_by_tname(%1,%2) engfunc(EngFunc_FindEntityByString, %1, "targetname", %2)
81 /* stock fm_find_ent_by_tname(index, const targetname[])
82 return engfunc(EngFunc_FindEntityByString, index, "targetname", targetname) */
83
84 stock fm_find_ent_by_model(index, const classname[], const model[]) {
85 new ent = index, mdl[72]
86 while ((ent = fm_find_ent_by_class(ent, classname))) {
87 pev(ent, pev_model, mdl, sizeof mdl - 1)
88 if (equal(mdl, model))
89 return ent
90 }
91
92 return 0
93 }
94
95 #define fm_find_ent_in_sphere(%1,%2,%3) engfunc(EngFunc_FindEntityInSphere, %1, %2, %3)
96 /* stock fm_find_ent_in_sphere(index, const Float:origin[3], Float:radius)
97 return engfunc(EngFunc_FindEntityInSphere, index, origin, radius) */
98
99 #define fm_call_think(%1) dllfunc(DLLFunc_Think, %1)
100 /* stock fm_call_think(entity)
101 return dllfunc(DLLFunc_Think, entity) */
102
103 #define fm_is_valid_ent(%1) pev_valid(%1)
104 /* stock fm_is_valid_ent(index)
105 return pev_valid(index) */
106
107 stock fm_entity_set_origin(index, const Float:origin[3]) {
108 new Float:mins[3], Float:maxs[3]
109 pev(index, pev_mins, mins)
110 pev(index, pev_maxs, maxs)
111 engfunc(EngFunc_SetSize, index, mins, maxs)
112
113 return engfunc(EngFunc_SetOrigin, index, origin)
114 }
115
116 #define fm_entity_set_model(%1,%2) engfunc(EngFunc_SetModel, %1, %2)
117 /* stock fm_entity_set_model(index, const model[])
118 return engfunc(EngFunc_SetModel, index, model) */
119
120 // ported by v3x
121 #define fm_remove_entity(%1) engfunc(EngFunc_RemoveEntity, %1)
122 /* stock fm_remove_entity(index)
123 return engfunc(EngFunc_RemoveEntity, index) */
124
125 #define fm_entity_count() engfunc(EngFunc_NumberOfEntities)
126 /* stock fm_entity_count()
127 return engfunc(EngFunc_NumberOfEntities) */
128
129 #define fm_fake_touch(%1,%2) dllfunc(DLLFunc_Touch, %1, %2)
130 /* stock fm_fake_touch(toucher, touched)
131 return dllfunc(DLLFunc_Touch, toucher, touched) */
132
133 #define fm_DispatchSpawn(%1) dllfunc(DLLFunc_Spawn, %1)
134 /* stock fm_DispatchSpawn(entity)
135 return dllfunc(DLLFunc_Spawn, entity) */
136
137 // ported by v3x
138 #define fm_point_contents(%1) engfunc(EngFunc_PointContents, %1)
139 /* stock fm_point_contents(const Float:point[3])
140 return engfunc(EngFunc_PointContents, point) */
141
142 stock fm_trace_line(ignoreent, const Float:start[3], const Float:end[3], Float:ret[3]) {
143 engfunc(EngFunc_TraceLine, start, end, ignoreent == -1 ? 1 : 0, ignoreent, 0)
144
145 new ent = get_tr2(0, TR_pHit)
146 get_tr2(0, TR_vecEndPos, ret)
147
148 return pev_valid(ent) ? ent : 0
149 }
150
151 stock fm_trace_hull(const Float:origin[3], hull, ignoredent = 0, ignoremonsters = 0) {
152 new result = 0
153 engfunc(EngFunc_TraceHull, origin, origin, ignoremonsters, hull, ignoredent > 0 ? ignoredent : 0, 0)
154
155 if (get_tr2(0, TR_StartSolid))
156 result += 1
157 if (get_tr2(0, TR_AllSolid))
158 result += 2
159 if (!get_tr2(0, TR_InOpen))
160 result += 4
161
162 return result
163 }
164
165 stock fm_trace_normal(ignoreent, const Float:start[3], const Float:end[3], Float:ret[3]) {
166 engfunc(EngFunc_TraceLine, start, end, 0, ignoreent, 0)
167 get_tr2(0, TR_vecPlaneNormal, ret)
168
169 new Float:fraction
170 get_tr2(0, TR_flFraction, fraction)
171 if (fraction >= 1.0)
172 return 0
173
174 return 1
175 }
176
177 // note that for CS planted C4 has a "grenade" classname as well
178 stock fm_get_grenade_id(id, model[], len, grenadeid = 0) {
179 new ent = fm_find_ent_by_owner(grenadeid, "grenade", id)
180 if (ent && len > 0)
181 pev(ent, pev_model, model, len)
182
183 return ent
184 }
185
186 #define fm_halflife_time() get_gametime()
187 /* stock Float:fm_halflife_time()
188 return get_gametime() */
189
190 #define fm_attach_view(%1,%2) engfunc(EngFunc_SetView, %1, %2)
191 /* stock fm_attach_view(index, entity)
192 return engfunc(EngFunc_SetView, index, entity) */
193
194 stock fm_playback_event(flags, invoker, eventindex, Float:delay, const Float:origin[3], const Float:angles[3], Float:fparam1, Float:fparam2, iparam1, iparam2, bparam1, bparam2) {
195 return engfunc(EngFunc_PlaybackEvent, flags, invoker, eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2)
196 }
197
198 #define fm_eng_get_string(%1,%2,%3) engfunc(EngFunc_SzFromIndex, %1, %2, %3)
199 /* stock fm_eng_get_string(istring, string[], len)
200 return engfunc(EngFunc_SzFromIndex, istring, string, len) */
201
202
203 /* HLSDK functions */
204
205 // the dot product is performed in 2d, making the view cone infinitely tall
206 stock bool:fm_is_in_viewcone(index, const Float:point[3]) {
207 new Float:angles[3]
208 pev(index, pev_angles, angles)
209 engfunc(EngFunc_MakeVectors, angles)
210 global_get(glb_v_forward, angles)
211 angles[2] = 0.0
212
213 new Float:origin[3], Float:diff[3], Float:norm[3]
214 pev(index, pev_origin, origin)
215 xs_vec_sub(point, origin, diff)
216 diff[2] = 0.0
217 xs_vec_normalize(diff, norm)
218
219 new Float:dot, Float:fov
220 dot = xs_vec_dot(norm, angles)
221 pev(index, pev_fov, fov)
222 if (dot >= floatcos(fov * M_PI / 360))
223 return true
224
225 return false
226 }
227
228 stock bool:fm_is_visible(index, const Float:point[3], ignoremonsters = 0) {
229 new Float:start[3], Float:view_ofs[3]
230 pev(index, pev_origin, start)
231 pev(index, pev_view_ofs, view_ofs)
232 xs_vec_add(start, view_ofs, start)
233
234 engfunc(EngFunc_TraceLine, start, point, ignoremonsters, index, 0)
235
236 new Float:fraction
237 get_tr2(0, TR_flFraction, fraction)
238 if (fraction == 1.0)
239 return true
240
241 return false
242 }
243
244
245 /* Engine_stocks functions */
246
247 stock fm_fakedamage(victim, const classname[], Float:takedmgdamage, damagetype) {
248 new class[] = "trigger_hurt"
249 new entity = fm_create_entity(class)
250 if (!entity)
251 return 0
252
253 new value[16]
254 float_to_str(takedmgdamage * 2, value, sizeof value - 1)
255 fm_set_kvd(entity, "dmg", value, class)
256
257 num_to_str(damagetype, value, sizeof value - 1)
258 fm_set_kvd(entity, "damagetype", value, class)
259
260 fm_set_kvd(entity, "origin", "8192 8192 8192", class)
261 fm_DispatchSpawn(entity)
262
263 set_pev(entity, pev_classname, classname)
264 fm_fake_touch(entity, victim)
265 fm_remove_entity(entity)
266
267 return 1
268 }
269
270 #define fm_find_ent(%1,%2) engfunc(EngFunc_FindEntityByString, %1, "classname", %2)
271 /* stock fm_find_ent(index, const classname[])
272 return engfunc(EngFunc_FindEntityByString, index, "classname", classname) */
273
274 #define fm_get_user_button(%1) pev(%1, pev_button)
275 /* stock fm_get_user_button(index)
276 return pev(index, pev_button) */
277
278 #define fm_get_user_oldbutton(%1) pev(%1, pev_oldbuttons)
279 /* stock fm_get_user_oldbutton(index)
280 return pev(index, pev_oldbuttons) */
281
282 #define fm_get_entity_flags(%1) pev(%1, pev_flags)
283 /* stock fm_get_entity_flags(index)
284 return pev(index, pev_flags) */
285
286 #define fm_get_entity_distance(%1,%2) floatround(fm_entity_range(%1, %2))
287 /* stock fm_get_entity_distance(ent1, ent2)
288 return floatround(fm_entity_range(ent1, ent2)) */
289
290 #define fm_get_grenade(%1) fm_get_grenade_id(%1, "", 0)
291 /* stock fm_get_grenade(id)
292 return fm_get_grenade_id(id, "", 0) */
293
294 // optimization idea by Orangutanz
295 stock fm_get_brush_entity_origin(index, Float:origin[3]) {
296 new Float:mins[3], Float:maxs[3]
297 pev(index, pev_mins, mins)
298 pev(index, pev_maxs, maxs)
299
300 origin[0] = (mins[0] + maxs[0]) * 0.5
301 origin[1] = (mins[1] + maxs[1]) * 0.5
302 origin[2] = (mins[2] + maxs[2]) * 0.5
303
304 return 1
305 }
306
307 // based on v3x's port, upgraded version returns number of removed entities
308 stock fm_remove_entity_name(const classname[]) {
309 new ent = -1, num = 0
310 while ((ent = fm_find_ent_by_class(ent, classname)))
311 num += fm_remove_entity(ent)
312
313 return num
314 }
315
316 stock fm_ViewContents(id) {
317 new origin[3], Float:Orig[3]
318 get_user_origin(id, origin, 3)
319 IVecFVec(origin, Orig)
320
321 return fm_point_contents(Orig)
322 }
323
324 stock fm_get_speed(entity) {
325 new Float:Vel[3]
326 pev(entity, pev_velocity, Vel)
327
328 return floatround(vector_length(Vel))
329 }
330
331 stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16) {
332 new Float:RenderColor[3]
333 RenderColor[0] = float(r)
334 RenderColor[1] = float(g)
335 RenderColor[2] = float(b)
336
337 set_pev(entity, pev_renderfx, fx)
338 set_pev(entity, pev_rendercolor, RenderColor)
339 set_pev(entity, pev_rendermode, render)
340 set_pev(entity, pev_renderamt, float(amount))
341
342 return 1
343 }
344
345 stock fm_set_entity_flags(index, flag, onoff) {
346 new flags = pev(index, pev_flags)
347 if ((flags & flag) > 0)
348 return onoff == 1 ? 2 : 1 + 0 * set_pev(index, pev_flags, flags - flag)
349 else
350 return onoff == 0 ? 2 : 1 + 0 * set_pev(index, pev_flags, flags + flag)
351
352 return 0
353 }
354
355 stock fm_set_entity_visibility(index, visible = 1) {
356 set_pev(index, pev_effects, visible == 1 ? pev(index, pev_effects) & ~EF_NODRAW : pev(index, pev_effects) | EF_NODRAW)
357
358 return 1
359 }
360
361 #define fm_get_entity_visibility(%1) (!(pev(%1, pev_effects) & EF_NODRAW))
362 /* stock fm_get_entity_visibility(index)
363 return !(pev(index, pev_effects) & EF_NODRAW) */
364
365 stock fm_set_user_velocity(entity, const Float:vector[3]) {
366 set_pev(entity, pev_velocity, vector)
367
368 return 1
369 }
370
371 #define fm_get_user_velocity(%1,%2) pev(%1, pev_velocity, %2)
372 /* stock fm_get_user_velocity(entity, Float:vector[3])
373 return pev(entity, pev_velocity, vector) */
374
375
376 /* Fun functions */
377
378 #define fm_get_client_listen(%1,%2) engfunc(EngFunc_GetClientListening, %1, %2)
379 /* stock fm_get_client_listen(receiver, sender)
380 return engfunc(EngFunc_GetClientListening, receiver, sender) */
381
382 #define fm_set_client_listen(%1,%2,%3) engfunc(EngFunc_SetClientListening, %1, %2, %3)
383 /* stock fm_set_client_listen(receiver, sender, listen)
384 return engfunc(EngFunc_SetClientListening, receiver, sender, listen) */
385
386 stock fm_get_user_godmode(index) {
387 new Float:val
388 pev(index, pev_takedamage, val)
389
390 return (val == DAMAGE_NO)
391 }
392
393 stock fm_set_user_godmode(index, godmode = 0) {
394 set_pev(index, pev_takedamage, godmode == 1 ? DAMAGE_NO : DAMAGE_AIM)
395
396 return 1
397 }
398
399 stock fm_set_user_armor(index, armor) {
400 set_pev(index, pev_armorvalue, float(armor))
401
402 return 1
403 }
404
405 stock fm_set_user_health(index, health) {
406 health > 0 ? set_pev(index, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, index)
407
408 return 1
409 }
410
411 stock fm_set_user_origin(index, /* const */ origin[3]) {
412 new Float:orig[3]
413 IVecFVec(origin, orig)
414
415 return fm_entity_set_origin(index, orig)
416 }
417
418 stock fm_set_user_rendering(index, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16) {
419 return fm_set_rendering(index, fx, r, g, b, render, amount)
420 }
421
422 stock fm_give_item(index, const item[]) {
423 if (!equal(item, "weapon_", 7) && !equal(item, "ammo_", 5) && !equal(item, "item_", 5) && !equal(item, "tf_weapon_", 10))
424 return 0
425
426 new ent = fm_create_entity(item)
427 if (!pev_valid(ent))
428 return 0
429
430 new Float:origin[3]
431 pev(index, pev_origin, origin)
432 set_pev(ent, pev_origin, origin)
433 set_pev(ent, pev_spawnflags, pev(ent, pev_spawnflags) | SF_NORESPAWN)
434 dllfunc(DLLFunc_Spawn, ent)
435
436 new save = pev(ent, pev_solid)
437 dllfunc(DLLFunc_Touch, ent, index)
438 if (pev(ent, pev_solid) != save)
439 return ent
440
441 engfunc(EngFunc_RemoveEntity, ent)
442
443 return -1
444 }
445
446 stock fm_set_user_maxspeed(index, Float:speed = -1.0) {
447 engfunc(EngFunc_SetClientMaxspeed, index, speed)
448 set_pev(index, pev_maxspeed, speed)
449
450 return 1
451 }
452
453 stock Float:fm_get_user_maxspeed(index) {
454 new Float:speed
455 pev(index, pev_maxspeed, speed)
456
457 return speed
458 }
459
460 stock fm_set_user_gravity(index, Float:gravity = 1.0) {
461 set_pev(index, pev_gravity, gravity)
462
463 return 1
464 }
465
466 stock Float:fm_get_user_gravity(index) {
467 new Float:gravity
468 pev(index, pev_gravity, gravity)
469
470 return gravity
471 }
472
473 /* interferes with FM_Spawn enum, just use fm_DispatchSpawn
474 stock fm_spawn(entity) {
475 return dllfunc(DLLFunc_Spawn, entity)
476 }
477 */
478
479 stock fm_set_user_noclip(index, noclip = 0) {
480 set_pev(index, pev_movetype, noclip == 1 ? MOVETYPE_NOCLIP : MOVETYPE_WALK)
481
482 return 1
483 }
484
485 #define fm_get_user_noclip(%1) (pev(%1, pev_movetype) == MOVETYPE_NOCLIP)
486 /* stock fm_get_user_noclip(index)
487 return (pev(index, pev_movetype) == MOVETYPE_NOCLIP) */
488
489 // note: get_user_weapon will still return former weapon index
490 stock fm_strip_user_weapons(index) {
491 new ent = fm_create_entity("player_weaponstrip")
492 if (!pev_valid(ent))
493 return 0
494
495 dllfunc(DLLFunc_Spawn, ent)
496 dllfunc(DLLFunc_Use, ent, index)
497 engfunc(EngFunc_RemoveEntity, ent)
498
499 return 1
500 }
501
502 stock fm_set_user_frags(index, frags) {
503 set_pev(index, pev_frags, float(frags))
504
505 return 1
506 }
507
508
509 /* Cstrike functions */
510
511 stock fm_cs_user_spawn(index) {
512 set_pev(index, pev_deadflag, DEAD_RESPAWNABLE)
513 dllfunc(DLLFunc_Spawn, index)
514 set_pev(index, pev_iuser1, 0)
515
516 return 1
517 }
518
519
520 /* Custom functions */
521
522 // based on Basic-Master's set_keyvalue, upgraded version accepts an optional classname (a bit more efficient if it is passed)
523 stock fm_set_kvd(entity, const key[], const value[], const classname[] = "") {
524 if (classname[0])
525 set_kvd(0, KV_ClassName, classname)
526 else {
527 new class[32]
528 pev(entity, pev_classname, class, sizeof class - 1)
529 set_kvd(0, KV_ClassName, class)
530 }
531
532 set_kvd(0, KV_KeyName, key)
533 set_kvd(0, KV_Value, value)
534 set_kvd(0, KV_fHandled, 0)
535
536 return dllfunc(DLLFunc_KeyValue, entity, 0)
537 }
538
539 stock fm_find_ent_by_integer(index, pev_field, value) {
540 static maxents
541 if (!maxents)
542 maxents = global_get(glb_maxEntities)
543
544 for (new i = index + 1; i < maxents; ++i) {
545 if (pev_valid(i) && pev(i, pev_field) == value)
546 return i
547 }
548
549 return 0
550 }
551
552 stock fm_find_ent_by_flags(index, pev_field, flags) {
553 static maxents
554 if (!maxents)
555 maxents = global_get(glb_maxEntities)
556
557 for (new i = index + 1; i < maxents; ++i) {
558 if (pev_valid(i) && (pev(i, pev_field) & flags) == flags)
559 return i
560 }
561
562 return 0
563 }
564
565 stock Float:fm_distance_to_box(const Float:point[3], const Float:mins[3], const Float:maxs[3]) {
566 new Float:dist[3]
567 for (new i = 0; i < 3; ++i) {
568 if (point[i] > maxs[i])
569 dist[i] = point[i] - maxs[i]
570 else if (mins[i] > point[i])
571 dist[i] = mins[i] - point[i]
572 }
573
574 return vector_length(dist)
575 }
576
577 stock Float:fm_boxes_distance(const Float:mins1[3], const Float:maxs1[3], const Float:mins2[3], const Float:maxs2[3]) {
578 new Float:dist[3]
579 for (new i = 0; i < 3; ++i) {
580 if (mins1[i] > maxs2[i])
581 dist[i] = mins1[i] - maxs2[i]
582 else if (mins2[i] > maxs1[i])
583 dist[i] = mins2[i] - maxs1[i]
584 }
585
586 return vector_length(dist)
587 }
588
589 stock Float:fm_distance_to_boxent(entity, boxent) {
590 new Float:point[3]
591 pev(entity, pev_origin, point)
592
593 new Float:mins[3], Float:maxs[3]
594 pev(boxent, pev_absmin, mins)
595 pev(boxent, pev_absmax, maxs)
596
597 return fm_distance_to_box(point, mins, maxs)
598 }
599
600 stock Float:fm_boxents_distance(boxent1, boxent2) {
601 new Float:mins1[3], Float:maxs1[3]
602 pev(boxent1, pev_absmin, mins1)
603 pev(boxent1, pev_absmax, maxs1)
604
605 new Float:mins2[3], Float:maxs2[3]
606 pev(boxent2, pev_absmin, mins2)
607 pev(boxent2, pev_absmax, maxs2)
608
609 return fm_boxes_distance(mins1, maxs1, mins2, maxs2)
610 }
611
612 // projects a center of a player's feet base (originally by P34nut, improved)
613 stock Float:fm_distance_to_floor(index, ignoremonsters = 1) {
614 new Float:start[3], Float:dest[3], Float:end[3]
615 pev(index, pev_origin, start)
616 dest[0] = start[0]
617 dest[1] = start[1]
618 dest[2] = -8191.0
619
620 engfunc(EngFunc_TraceLine, start, dest, ignoremonsters, index, 0)
621 get_tr2(0, TR_vecEndPos, end)
622
623 pev(index, pev_absmin, start)
624 new Float:ret = start[2] - end[2]
625
626 return ret > 0 ? ret : 0.0
627 }
628
629 // potential to crash (?) if used on weaponbox+weapon_* entity pair (use fm_remove_weaponbox instead)
630 stock fm_kill_entity(index) {
631 set_pev(index, pev_flags, pev(index, pev_flags) | FL_KILLME)
632
633 return 1
634 }
635
636 // if weapon index isn't passed then assuming that it's the current weapon
637 stock fm_get_user_weapon_entity(id, wid = 0) {
638 new weap = wid, clip, ammo
639 if (!weap && !(weap = get_user_weapon(id, clip, ammo)))
640 return 0
641
642 new class[32]
643 get_weaponname(weap, class, sizeof class - 1)
644
645 return fm_find_ent_by_owner(-1, class, id)
646 }
647
648 // only weapon index or its name can be passed, if neither is passed then the current gun will be stripped
649 stock bool:fm_strip_user_gun(index, wid = 0, const wname[] = "") {
650 new ent_class[32]
651 if (!wid && wname[0])
652 copy(ent_class, sizeof ent_class - 1, wname)
653 else {
654 new weapon = wid, clip, ammo
655 if (!weapon && !(weapon = get_user_weapon(index, clip, ammo)))
656 return false
657
658 get_weaponname(weapon, ent_class, sizeof ent_class - 1)
659 }
660
661 new ent_weap = fm_find_ent_by_owner(-1, ent_class, index)
662 if (!ent_weap)
663 return false
664
665 engclient_cmd(index, "drop", ent_class)
666
667 new ent_box = pev(ent_weap, pev_owner)
668 if (!ent_box || ent_box == index)
669 return false
670
671 dllfunc(DLLFunc_Think, ent_box)
672
673 return true
674 }
675
676 // only weapon index or its name can be passed, if neither is passed then the current gun will be transferred
677 stock bool:fm_transfer_user_gun(index1, index2, wid = 0, const wname[] = "") {
678 new ent_class[32]
679 if (!wid && wname[0])
680 copy(ent_class, sizeof ent_class - 1, wname)
681 else {
682 new weapon = wid, clip, ammo
683 if (!weapon && !(weapon = get_user_weapon(index1, clip, ammo)))
684 return false
685
686 get_weaponname(weapon, ent_class, sizeof ent_class - 1)
687 }
688
689 new ent_weap = fm_find_ent_by_owner(-1, ent_class, index1)
690 if (!ent_weap)
691 return false
692
693 engclient_cmd(index1, "drop", ent_class)
694
695 new ent_box = pev(ent_weap, pev_owner)
696 if (!ent_box || ent_box == index1)
697 return false
698
699 set_pev(ent_box, pev_flags, pev(ent_box, pev_flags) | FL_ONGROUND)
700 dllfunc(DLLFunc_Touch, ent_box, index2)
701 if (pev(ent_weap, pev_owner) != index2)
702 return false
703
704 return true
705 }
706
707 stock bool:fm_is_ent_visible(index, entity, ignoremonsters = 0) {
708 new Float:start[3], Float:dest[3]
709 pev(index, pev_origin, start)
710 pev(index, pev_view_ofs, dest)
711 xs_vec_add(start, dest, start)
712
713 pev(entity, pev_origin, dest)
714 engfunc(EngFunc_TraceLine, start, dest, ignoremonsters, index, 0)
715
716 new Float:fraction
717 get_tr2(0, TR_flFraction, fraction)
718 if (fraction == 1.0 || get_tr2(0, TR_pHit) == entity)
719 return true
720
721 return false
722 }
723
724 // ported from AMXX's core get_user_origin(..., 3) (suggested by Greenberet)
725 stock fm_get_aim_origin(index, Float:origin[3]) {
726 new Float:start[3], Float:view_ofs[3]
727 pev(index, pev_origin, start)
728 pev(index, pev_view_ofs, view_ofs)
729 xs_vec_add(start, view_ofs, start)
730
731 new Float:dest[3]
732 pev(index, pev_v_angle, dest)
733 engfunc(EngFunc_MakeVectors, dest)
734 global_get(glb_v_forward, dest)
735 xs_vec_mul_scalar(dest, 9999.0, dest)
736 xs_vec_add(start, dest, dest)
737
738 engfunc(EngFunc_TraceLine, start, dest, 0, index, 0)
739 get_tr2(0, TR_vecEndPos, origin)
740
741 return 1
742 }
743
744 stock bool:fm_get_user_longjump(index) {
745 new value[2]
746 engfunc(EngFunc_GetPhysicsKeyValue, index, "slj", value, 1)
747 switch (value[0]) {
748 case '1': return true
749 }
750
751 return false
752 }
753
754 stock fm_set_user_longjump(index, bool:longjump = true, bool:tempicon = true) {
755 if (longjump == fm_get_user_longjump(index))
756 return
757
758 if (longjump) {
759 engfunc(EngFunc_SetPhysicsKeyValue, index, "slj", "1")
760 if (tempicon) {
761 static msgid_itempickup
762 if (!msgid_itempickup)
763 msgid_itempickup = get_user_msgid("ItemPickup")
764
765 message_begin(MSG_ONE, msgid_itempickup, _, index)
766 write_string("item_longjump")
767 message_end()
768 }
769 }
770 else
771 engfunc(EngFunc_SetPhysicsKeyValue, index, "slj", "0")
772 }
773
774 #define WEAPON_SUIT 31
775
776 stock bool:fm_get_user_suit(index) {
777 return bool:(!(!(pev(index, pev_weapons) & (1<<WEAPON_SUIT)))) // i'm not insane, this is a trick!
778 }
779
780 stock fm_set_user_suit(index, bool:suit = true, bool:sound = true) {
781 new weapons = pev(index, pev_weapons)
782 if (!suit)
783 set_pev(index, pev_weapons, weapons & ~(1<<WEAPON_SUIT))
784 else if (!(weapons & (1<<WEAPON_SUIT))) {
785 set_pev(index, pev_weapons, weapons | (1<<WEAPON_SUIT))
786 if (sound)
787 emit_sound(index, CHAN_VOICE, "items/tr_kevlar.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
788 }
789 }
790
791 #define FEV_RELIABLE (1<<1)
792 #define FEV_GLOBAL (1<<2)
793
794 // removes all created decals and players' corpses from the world
795 // set a specific index to remove decals only for the given client
796 stock fm_cs_remove_decals(index = 0) {
797 static eventindex_decal_reset
798 if (!eventindex_decal_reset)
799 eventindex_decal_reset = engfunc(EngFunc_PrecacheEvent, 1, "events/decal_reset.sc")
800
801 new flags = FEV_RELIABLE
802 if (!index)
803 flags |= FEV_GLOBAL
804
805 engfunc(EngFunc_PlaybackEvent, flags, index, eventindex_decal_reset, 0.0, Float:{0.0, 0.0, 0.0}, Float:{0.0, 0.0, 0.0}, 0.0, 0.0, 0, 0, 0, 0)
806 }
807
808 // checks whether the entity's classname is equal to the passed classname
809 stock bool:fm_is_ent_classname(index, const classname[]) {
810 if (!pev_valid(index))
811 return false
812
813 new class[32]
814 pev(index, pev_classname, class, sizeof class - 1)
815 if (equal(class, classname))
816 return true
817
818 return false
819 }
820
821 // the same as AMXX's core user_kill but fixes the issue when the scoreboard doesn't update immediately if flag is set to 1
822 stock fm_user_kill(index, flag = 0) {
823 if (flag) {
824 new Float:frags
825 pev(index, pev_frags, frags)
826 set_pev(index, pev_frags, ++frags)
827 }
828
829 dllfunc(DLLFunc_ClientKill, index)
830
831 return 1
832 }
833
834 // returns a degree angle between player-to-point and player's view vectors
835 stock Float:fm_get_view_angle_diff(index, const Float:point[3]) {
836 new Float:vec[3], Float:ofs[3], Float:aim[3]
837 pev(index, pev_origin, vec)
838 pev(index, pev_view_ofs, ofs)
839 xs_vec_add(vec, ofs, vec)
840 xs_vec_sub(point, vec, vec)
841 xs_vec_normalize(vec, vec)
842
843 pev(index, pev_v_angle, aim)
844 engfunc(EngFunc_MakeVectors, aim)
845 global_get(glb_v_forward, aim)
846
847 return xs_vec_angle(vec, aim)
848 }
849
850 // gets a weapon type of the linked to weaponbox weapon_* entity
851 stock fm_get_weaponbox_type(entity) {
852 static max_clients, max_entities
853 if (!max_clients)
854 max_clients = global_get(glb_maxClients)
855 if (!max_entities)
856 max_entities = global_get(glb_maxEntities)
857
858 for (new i = max_clients + 1; i < max_entities; ++i) {
859 if (pev_valid(i) && entity == pev(i, pev_owner)) {
860 new wname[32]
861 pev(i, pev_classname, wname, sizeof wname - 1)
862 return get_weaponid(wname)
863 }
864 }
865
866 return 0
867 }
868
869 // safe removal of weaponbox+weapon_* entity pair (delay =~= 0.03 second)
870 #define fm_remove_weaponbox(%1) dllfunc(DLLFunc_Think, %1)
871 /* stock fm_remove_weaponbox(entity)
872 return dllfunc(DLLFunc_Think, entity) */
873