HLMOD.HU Forrás Megtekintés - www.hlmod.hu
  1. #include <amxmodx>
  2. #include <amxmisc>
  3. #include <fakemeta>
  4. #include <xs>
  5.  
  6. #if AMXX_VERSION_NUM < 180
  7.  
  8. #define HAM_IGNORED 1
  9. #define HAM_HANDLED 2
  10. #define Ham_Spawn Ham:0
  11. #define Ham_TraceAttack Ham:8
  12. #define Ham_TakeDamage Ham:9
  13. #define Ham_Touch Ham:42
  14.  
  15. native HamHook:RegisterHam(Ham:function, const EntityClass[], const Callback[], Post=0)
  16. native SetHamParamFloat(which, Float:value)
  17. native DisableHamForward(HamHook:fwd)
  18. native EnableHamForward(HamHook:fwd)
  19.  
  20. #else
  21.  
  22. #include <hamsandwich>
  23.  
  24. #endif
  25.  
  26. #define PLUGIN "Weapon Physics"
  27. #define VERSION "2.1"
  28. #define AUTHOR "Nomexous"
  29.  
  30. /*
  31.  
  32. Version 1.0
  33.  - Initial release.
  34.  
  35. Version 2.0
  36.  - Added. Ability to compile on amxmodx.org's online compiler.
  37.  - Added. Menu for enabling/disabling the plugin.
  38.  - Added. Ability for weapons to be moved when shot.
  39.  - Added. Sparks when weapon hits a wall while moving above a certain speed.
  40.  - Added. Hooking of custom classes.
  41.  - Fixed. Looping bounce sound when touching dead bodies in DoD.
  42.  
  43. Version 2.1
  44.  - Fixed. Custom item spawn debug message removed.
  45.  - Fixed. Non-visible entities no longer react to explosions (e.g. armoury_entities that have been picked up).
  46.  - Changed. Shooting of weapons now off by default.
  47.  - Added. Menu option for weapon clatter.
  48.  
  49. */
  50.  
  51. #define BOUNCE "items/weapondrop1.wav"
  52. #define RIC "debris/metal6.wav"
  53.  
  54. // Persistant items that don't disappear when picked up.
  55. new const persistant[][] = { "armoury_entity" }
  56.  
  57. // Dropped items.
  58. new const classes[][] = { "weaponbox", "item_thighpack", "weapon_shield" }
  59.  
  60. // The base is what the entity is created as, e.g. ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target")).
  61. // Put all of them here. Make sure that this custom entity can take damage, otherwise it won't work!
  62. new const custom_base[][] = { "info_target" }
  63. // What the entity's classname is changed to after it's created, e.g. set_pev(ent, pev_classname, "fakeweapon")
  64. new const custom_classname[][] = { "fakeweapon" }
  65.  
  66. #define HOOK_COUNT 4 * (sizeof persistant + sizeof classes + sizeof custom_base)
  67.  
  68. new HamHook:hamhooks[HOOK_COUNT]
  69. new traceline_fid = 0
  70.  
  71. new custom_count, shootweapons_pcvar, physics_pcvar, clatter_sound_pcvar
  72.  
  73. new Float:multiplier = 15.0
  74.  
  75. public plugin_precache()
  76. {
  77. custom_count = sizeof custom_classname
  78. precache_sound(BOUNCE)
  79. precache_sound(RIC)
  80.  
  81. physics_pcvar = register_cvar("weapon_physics_enabled", "1")
  82. shootweapons_pcvar = register_cvar("weapon_physics_shoot_weapons", "0")
  83. clatter_sound_pcvar = register_cvar("weapon_physics_weapons_clatter", "1")
  84.  
  85. do_ham_hooks()
  86. }
  87.  
  88. public do_ham_hooks()
  89. {
  90. new count = 0
  91.  
  92. for (new i; i < sizeof persistant; i++)
  93. {
  94. hamhooks[count++] = RegisterHam(Ham_Spawn, persistant[i], "spawn_persistant_item", 1)
  95. hamhooks[count++] = RegisterHam(Ham_Touch, persistant[i], "touch_item")
  96. hamhooks[count++] = RegisterHam(Ham_TakeDamage, persistant[i], "damage_item")
  97. hamhooks[count++] = RegisterHam(Ham_TraceAttack, persistant[i], "shoot_item")
  98. }
  99.  
  100. for (new x; x < sizeof classes; x++)
  101. {
  102. hamhooks[count++] = RegisterHam(Ham_Spawn, classes[x], "spawn_item", 1)
  103. hamhooks[count++] = RegisterHam(Ham_Touch, classes[x], "touch_item")
  104. hamhooks[count++] = RegisterHam(Ham_TakeDamage, classes[x], "damage_item")
  105. hamhooks[count++] = RegisterHam(Ham_TraceAttack, classes[x], "shoot_item")
  106. }
  107.  
  108. for (new n; n < sizeof custom_base; n++)
  109. {
  110. hamhooks[count++] = RegisterHam(Ham_Spawn, custom_base[n], "spawn_custom_item", 1)
  111. hamhooks[count++] = RegisterHam(Ham_Touch, custom_base[n], "touch_custom_item")
  112. hamhooks[count++] = RegisterHam(Ham_TakeDamage, custom_base[n], "damage_custom_item")
  113. hamhooks[count++] = RegisterHam(Ham_TraceAttack, custom_base[n], "shoot_item")
  114. }
  115. }
  116.  
  117. public update_hooks_and_forwards()
  118. {
  119. if (get_pcvar_num(physics_pcvar))
  120. {
  121. for (new i; i < sizeof hamhooks; i++)
  122. {
  123. EnableHamForward(hamhooks[i])
  124. }
  125. }
  126. else
  127. {
  128. for (new i; i < sizeof hamhooks; i++)
  129. {
  130. DisableHamForward(hamhooks[i])
  131. }
  132. }
  133.  
  134. if (get_pcvar_num(shootweapons_pcvar) && get_pcvar_num(physics_pcvar) && !traceline_fid)
  135. {
  136. traceline_fid = register_forward(FM_TraceLine, "fw_traceline")
  137. }
  138.  
  139. if ((!get_pcvar_num(shootweapons_pcvar) || !get_pcvar_num(physics_pcvar)) && traceline_fid)
  140. {
  141. unregister_forward(FM_TraceLine, traceline_fid)
  142. traceline_fid = 0
  143. }
  144. }
  145.  
  146. public plugin_init()
  147. {
  148. register_plugin(PLUGIN, VERSION, AUTHOR)
  149.  
  150. register_event("HLTV", "restart", "a", "1=0", "2=0")
  151.  
  152. update_hooks_and_forwards()
  153.  
  154. register_clcmd("amx_weapon_physics_menu", "conjure_menu", ADMIN_SLAY, "Shows weapon physics menu.")
  155.  
  156. // This multiplier controls how fast the grenade will propel items. Originally, I wanted it to just be proportional to
  157. // the damage, but CZ and CS has different grenade strengths. Add your own here.
  158. new mods[][] = { "cstrike", "czero" }
  159. new Float:mult[] = { 22.0, 17.0 }
  160.  
  161. new modname[10]
  162. get_modname(modname, 9)
  163.  
  164. for (new i; i < sizeof mods; i++)
  165. {
  166. if (equal(modname, mods[i]))
  167. {
  168. multiplier = mult[i]
  169. }
  170. }
  171. }
  172.  
  173. public conjure_menu(id, level, cid)
  174. {
  175. if (cmd_access(id, level, cid, 1))
  176. {
  177. wpm(id)
  178. }
  179. return PLUGIN_HANDLED
  180. }
  181.  
  182. public wpm(id)
  183. {
  184. static wpmenu
  185.  
  186. wpmenu = menu_create("Weapon Physics", "menu_h")
  187.  
  188. get_pcvar_num(physics_pcvar) ? menu_additem(wpmenu, "Weapon physics: \yEnabled", "1") : menu_additem(wpmenu, "Weapon phyics: \rDisabled", "1")
  189. get_pcvar_num(shootweapons_pcvar) ? menu_additem(wpmenu, "Shoot weapons: \yEnabled", "2") : menu_additem(wpmenu, "Shoot weapons: \rDisabled", "2")
  190. get_pcvar_num(clatter_sound_pcvar) ? menu_additem(wpmenu, "Weapons clatter: \yEnabled", "3") : menu_additem(wpmenu, "Weapons clatter: \rDisabled", "3")
  191.  
  192. menu_display(id, wpmenu, 0)
  193. return PLUGIN_HANDLED
  194. }
  195.  
  196. public menu_h(id, menu, item)
  197. {
  198. switch (item)
  199. {
  200. case 0:
  201. {
  202. set_pcvar_num(physics_pcvar, !get_pcvar_num(physics_pcvar))
  203. }
  204.  
  205. case 1:
  206. {
  207. set_pcvar_num(shootweapons_pcvar, !get_pcvar_num(shootweapons_pcvar))
  208. }
  209.  
  210. case 2:
  211. {
  212. set_pcvar_num(clatter_sound_pcvar, !get_pcvar_num(clatter_sound_pcvar))
  213. }
  214.  
  215. default:
  216. {
  217. update_hooks_and_forwards()
  218. menu_destroy(menu)
  219. return PLUGIN_HANDLED
  220. }
  221. }
  222.  
  223. menu_destroy(menu)
  224. wpm(id)
  225. return PLUGIN_HANDLED
  226. }
  227.  
  228. public restart()
  229. {
  230. for (new i; i < sizeof persistant; i++)
  231. {
  232. new o
  233. while ((o = engfunc(EngFunc_FindEntityByString, o, "classname", persistant[i])))
  234. {
  235. static Float:origin[3], Float:angles[3]
  236. pev(o, pev_vuser1, origin)
  237. pev(o, pev_vuser2, angles)
  238. set_pev(o, pev_angles, angles)
  239. set_pev(o, pev_avelocity, Float:{0.0, 0.0, 0.0})
  240. engfunc(EngFunc_SetOrigin, o, origin)
  241. engfunc(EngFunc_DropToFloor, o)
  242. }
  243. }
  244. }
  245.  
  246. public spawn_item(ent)
  247. {
  248. set_pev(ent, pev_movetype, MOVETYPE_BOUNCE)
  249. set_pev(ent, pev_takedamage, DAMAGE_YES)
  250. set_pev(ent, pev_health, 100.0)
  251.  
  252. return HAM_IGNORED
  253. }
  254.  
  255. public spawn_persistant_item(ent)
  256. {
  257. set_pev(ent, pev_movetype, MOVETYPE_BOUNCE)
  258. set_pev(ent, pev_takedamage, DAMAGE_YES)
  259. set_pev(ent, pev_health, 100.0)
  260.  
  261. new Float:origin[3], Float:angles[3]
  262. pev(ent, pev_origin, origin)
  263. pev(ent, pev_angles, angles)
  264. set_pev(ent, pev_vuser1, origin)
  265. set_pev(ent, pev_vuser2, angles)
  266.  
  267. return HAM_IGNORED
  268. }
  269.  
  270. public spawn_custom_item(ent)
  271. {
  272. if (is_custom_ent(ent))
  273. {
  274. return spawn_item(ent)
  275. }
  276. return HAM_IGNORED
  277. }
  278.  
  279. public damage_item(ent, inflictor, attacker, Float:damage, damagebits)
  280. {
  281. if (pev(ent, pev_effects) & EF_NODRAW) return HAM_IGNORED
  282.  
  283. static Float:ent_v[3], Float:ent_o[3], Float:inflictor_o[3], Float:temp[3]
  284. pev(ent, pev_velocity, ent_v)
  285. pev(ent, pev_origin, ent_o)
  286. pev(inflictor, pev_origin, inflictor_o)
  287. xs_vec_sub(ent_o, inflictor_o, temp)
  288. xs_vec_normalize(temp, temp)
  289. xs_vec_mul_scalar(temp, damage, temp)
  290. xs_vec_mul_scalar(temp, multiplier, temp)
  291. xs_vec_add(ent_v, temp, ent_v)
  292. set_pev(ent, pev_velocity, ent_v)
  293.  
  294. // Set a random yaw. I would've set random pitch and roll, but then the weapons don't land flat, even with my Lie Flat plugin.
  295. static Float:av[3]
  296. //av[0] = random_float(-1000.0, 1000.0)
  297. av[1] = random_float(-1000.0, 1000.0)
  298. //av[2] = random_float(-1000.0, 1000.0)
  299. set_pev(ent, pev_avelocity, av)
  300.  
  301. SetHamParamFloat(4, 0.0)
  302. return HAM_HANDLED
  303. }
  304.  
  305. public damage_custom_item(ent, inflictor, attacker, Float:damage, damagebits)
  306. {
  307. if (is_custom_ent(ent))
  308. {
  309. static Float:ent_v[3], Float:ent_o[3], Float:inflictor_o[3], Float:temp[3]
  310. pev(ent, pev_velocity, ent_v)
  311. pev(ent, pev_origin, ent_o)
  312. pev(inflictor, pev_origin, inflictor_o)
  313. xs_vec_sub(ent_o, inflictor_o, temp)
  314. xs_vec_normalize(temp, temp)
  315. xs_vec_mul_scalar(temp, damage, temp)
  316. xs_vec_mul_scalar(temp, multiplier, temp)
  317. xs_vec_add(ent_v, temp, ent_v)
  318. set_pev(ent, pev_velocity, ent_v)
  319.  
  320. // Set a random yaw. I would've set random pitch and roll, but then the weapons don't land flat, even with my Lie Flat plugin.
  321. static Float:av[3]
  322. av[1] = random_float(-1000.0, 1000.0)
  323. set_pev(ent, pev_avelocity, av)
  324.  
  325. SetHamParamFloat(4, 0.0)
  326. return HAM_HANDLED
  327. }
  328. return HAM_IGNORED
  329. }
  330.  
  331. public touch_item(ent, touched)
  332. {
  333. if (pev(touched, pev_solid) < SOLID_BBOX) return HAM_IGNORED
  334.  
  335. if (1 <= touched <= 32) return HAM_IGNORED // Prevents bugginess when someone drops a gun (or in DoD, when a gun gets stuck inside a dead body).
  336.  
  337. static Float:v[3]
  338. pev(ent, pev_velocity, v)
  339.  
  340. if (xs_vec_len(v) > 700.0)
  341. {
  342. static Float:origin[3]
  343. pev(ent, pev_origin, origin)
  344. origin[0] += random_float(-10.0, 10.0)
  345. origin[1] += random_float(-10.0, 10.0)
  346. origin[2] += random_float(-10.0, 10.0)
  347. draw_spark(origin)
  348. }
  349.  
  350. xs_vec_mul_scalar(v, 0.4, v)
  351. set_pev(ent, pev_velocity, v)
  352.  
  353. if (get_pcvar_num(clatter_sound_pcvar))
  354. {
  355. engfunc(EngFunc_EmitSound, ent, CHAN_WEAPON, BOUNCE, 0.25, ATTN_STATIC, 0, PITCH_NORM)
  356. }
  357.  
  358. return HAM_IGNORED
  359. }
  360.  
  361. public touch_custom_item(ent, touched)
  362. {
  363. if (is_custom_ent(ent))
  364. {
  365. return touch_item(ent, touched)
  366. }
  367. return HAM_IGNORED
  368. }
  369.  
  370. public shoot_item(ent, attacker, Float:damage, Float:direction[3], trace, damagebits)
  371. {
  372. static Float:endpoint[3]
  373. get_tr2(trace, TR_vecEndPos, endpoint)
  374. draw_spark(endpoint)
  375.  
  376. static Float:velocity[3]
  377. pev(ent, pev_velocity, velocity)
  378.  
  379. xs_vec_mul_scalar(direction, damage, direction)
  380. xs_vec_mul_scalar(direction, multiplier, direction)
  381. xs_vec_add(direction, velocity, velocity)
  382. set_pev(ent, pev_velocity, velocity)
  383.  
  384. engfunc(EngFunc_EmitSound, ent, CHAN_ITEM, RIC, 0.5, ATTN_STATIC, 0, PITCH_NORM)
  385.  
  386. return HAM_IGNORED
  387. }
  388.  
  389. public fw_traceline(Float:start[3], Float:end[3], conditions, id, trace)
  390. {
  391. // Spectators don't need to run this.
  392. if (!is_user_alive(id)) return FMRES_IGNORED
  393.  
  394. // If we hit a player, don't bother searching for an item nearby.
  395. if (is_user_alive(get_tr2(trace, TR_pHit))) return FMRES_IGNORED
  396.  
  397. static Float:endpt[3], tr = 0, i
  398.  
  399. get_tr2(trace, TR_vecEndPos, endpt)
  400.  
  401. i = 0
  402.  
  403. while ((i = engfunc(EngFunc_FindEntityInSphere, i, endpt, 20.0)))
  404. {
  405. if (is_shootable_ent(i))
  406. {
  407. engfunc(EngFunc_TraceModel, start, end, HULL_POINT, i, tr)
  408.  
  409. if (pev_valid(get_tr2(tr, TR_pHit)))
  410. {
  411. get_tr2(tr, TR_vecEndPos, endpt)
  412. set_tr2(trace, TR_vecEndPos, endpt)
  413.  
  414. set_tr2(trace, TR_pHit, i)
  415.  
  416. return FMRES_IGNORED
  417. }
  418. }
  419. }
  420.  
  421. return FMRES_IGNORED
  422. }
  423.  
  424. public is_shootable_ent(ent)
  425. {
  426. static classname[32]
  427. pev(ent, pev_classname, classname, 31)
  428.  
  429. for (new i; i < sizeof classes; i++)
  430. {
  431. if (equal(classname, classes[i]))
  432. {
  433. return true
  434. }
  435. }
  436.  
  437. for (new i; i < sizeof persistant; i++)
  438. {
  439. if (equal(classname, persistant[i]))
  440. {
  441. return true
  442. }
  443. }
  444.  
  445. for (new i; i < sizeof custom_classname; i++)
  446. {
  447. if (equal(classname, custom_classname[i]))
  448. {
  449. return true
  450. }
  451. }
  452.  
  453. return false
  454. }
  455.  
  456. public is_custom_ent(ent)
  457. {
  458. static classname[40]
  459. pev(ent, pev_classname, classname, 39)
  460.  
  461. for (new i; i < custom_count; i++)
  462. {
  463. if (equal(classname, custom_classname[i]))
  464. {
  465. return true
  466. }
  467. }
  468.  
  469. return false
  470. }
  471.  
  472. stock draw_spark(Float:origin[3])
  473. {
  474. message_begin(MSG_ALL, SVC_TEMPENTITY)
  475. write_byte(TE_SPARKS)
  476. engfunc(EngFunc_WriteCoord, origin[0])
  477. engfunc(EngFunc_WriteCoord, origin[1])
  478. engfunc(EngFunc_WriteCoord, origin[2])
  479. message_end()
  480. }
  481.