fakemeta_util.inc
Original include source with line numbers.
| 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 | |