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