weapons.qc 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. /* Copyright (C) 1996-1997 Id Software, Inc.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. /*
  16. */
  17. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  18. void () player_run;
  19. void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
  20. void(vector org, vector vel, float damage) SpawnBlood;
  21. void() SuperDamageSound;
  22. // called by worldspawn
  23. void() W_Precache =
  24. {
  25. precache_sound ("weapons/r_exp3.wav"); // new rocket explosion
  26. precache_sound ("weapons/rocket1i.wav"); // spike gun
  27. precache_sound ("weapons/sgun1.wav");
  28. precache_sound ("weapons/guncock.wav"); // player shotgun
  29. precache_sound ("weapons/ric1.wav"); // ricochet (used in c code)
  30. precache_sound ("weapons/ric2.wav"); // ricochet (used in c code)
  31. precache_sound ("weapons/ric3.wav"); // ricochet (used in c code)
  32. precache_sound ("weapons/spike2.wav"); // super spikes
  33. precache_sound ("weapons/tink1.wav"); // spikes tink (used in c code)
  34. precache_sound ("weapons/grenade.wav"); // grenade launcher
  35. precache_sound ("weapons/bounce.wav"); // grenade bounce
  36. precache_sound ("weapons/shotgn2.wav"); // super shotgun
  37. };
  38. float() crandom =
  39. {
  40. return 2*(random() - 0.5);
  41. };
  42. /*
  43. ================
  44. W_FireAxe
  45. ================
  46. */
  47. void() W_FireAxe =
  48. {
  49. local vector source;
  50. local vector org;
  51. source = self.origin + '0 0 16';
  52. traceline (source, source + v_forward*64, FALSE, self);
  53. if (trace_fraction == 1.0)
  54. return;
  55. org = trace_endpos - v_forward*4;
  56. if (trace_ent.takedamage)
  57. {
  58. trace_ent.axhitme = 1;
  59. SpawnBlood (org, '0 0 0', 20);
  60. T_Damage (trace_ent, self, self, 20);
  61. }
  62. else
  63. { // hit wall
  64. sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  65. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  66. WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  67. WriteCoord (MSG_BROADCAST, org_x);
  68. WriteCoord (MSG_BROADCAST, org_y);
  69. WriteCoord (MSG_BROADCAST, org_z);
  70. }
  71. };
  72. //============================================================================
  73. vector() wall_velocity =
  74. {
  75. local vector vel;
  76. vel = normalize (self.velocity);
  77. vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  78. vel = vel + 2*trace_plane_normal;
  79. vel = vel * 200;
  80. return vel;
  81. };
  82. /*
  83. ================
  84. SpawnMeatSpray
  85. ================
  86. */
  87. void(vector org, vector vel) SpawnMeatSpray =
  88. {
  89. local entity missile, mpuff;
  90. local vector org;
  91. missile = spawn ();
  92. missile.owner = self;
  93. missile.movetype = MOVETYPE_BOUNCE;
  94. missile.solid = SOLID_NOT;
  95. makevectors (self.angles);
  96. missile.velocity = vel;
  97. missile.velocity_z = missile.velocity_z + 250 + 50*random();
  98. missile.avelocity = '3000 1000 2000';
  99. // set missile duration
  100. missile.nextthink = time + 1;
  101. missile.think = SUB_Remove;
  102. setmodel (missile, "progs/zom_gib.mdl");
  103. setsize (missile, '0 0 0', '0 0 0');
  104. setorigin (missile, org);
  105. };
  106. /*
  107. ================
  108. SpawnBlood
  109. ================
  110. */
  111. void(vector org, vector vel, float damage) SpawnBlood =
  112. {
  113. particle (org, vel*0.1, 73, damage*2);
  114. };
  115. /*
  116. ================
  117. spawn_touchblood
  118. ================
  119. */
  120. void(float damage) spawn_touchblood =
  121. {
  122. local vector vel;
  123. vel = wall_velocity () * 0.2;
  124. SpawnBlood (self.origin + vel*0.01, vel, damage);
  125. };
  126. /*
  127. ================
  128. SpawnChunk
  129. ================
  130. */
  131. void(vector org, vector vel) SpawnChunk =
  132. {
  133. particle (org, vel*0.02, 0, 10);
  134. };
  135. /*
  136. ==============================================================================
  137. MULTI-DAMAGE
  138. Collects multiple small damages into a single damage
  139. ==============================================================================
  140. */
  141. entity multi_ent;
  142. float multi_damage;
  143. void() ClearMultiDamage =
  144. {
  145. multi_ent = world;
  146. multi_damage = 0;
  147. };
  148. void() ApplyMultiDamage =
  149. {
  150. if (!multi_ent)
  151. return;
  152. T_Damage (multi_ent, self, self, multi_damage);
  153. };
  154. void(entity hit, float damage) AddMultiDamage =
  155. {
  156. if (!hit)
  157. return;
  158. if (hit != multi_ent)
  159. {
  160. ApplyMultiDamage ();
  161. multi_damage = damage;
  162. multi_ent = hit;
  163. }
  164. else
  165. multi_damage = multi_damage + damage;
  166. };
  167. /*
  168. ==============================================================================
  169. BULLETS
  170. ==============================================================================
  171. */
  172. /*
  173. ================
  174. TraceAttack
  175. ================
  176. */
  177. void(float damage, vector dir) TraceAttack =
  178. {
  179. local vector vel, org;
  180. vel = normalize(dir + v_up*crandom() + v_right*crandom());
  181. vel = vel + 2*trace_plane_normal;
  182. vel = vel * 200;
  183. org = trace_endpos - dir*4;
  184. if (trace_ent.takedamage)
  185. {
  186. SpawnBlood (org, vel*0.2, damage);
  187. AddMultiDamage (trace_ent, damage);
  188. }
  189. else
  190. {
  191. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  192. WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  193. WriteCoord (MSG_BROADCAST, org_x);
  194. WriteCoord (MSG_BROADCAST, org_y);
  195. WriteCoord (MSG_BROADCAST, org_z);
  196. }
  197. };
  198. /*
  199. ================
  200. FireBullets
  201. Used by shotgun, super shotgun, and enemy soldier firing
  202. Go to the trouble of combining multiple pellets into a single damage call.
  203. ================
  204. */
  205. void(float shotcount, vector dir, vector spread) FireBullets =
  206. {
  207. local vector direction;
  208. local vector src;
  209. makevectors(self.v_angle);
  210. src = self.origin + v_forward*10;
  211. src_z = self.absmin_z + self.size_z * 0.7;
  212. ClearMultiDamage ();
  213. while (shotcount > 0)
  214. {
  215. direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  216. traceline (src, src + direction*2048, FALSE, self);
  217. if (trace_fraction != 1.0)
  218. TraceAttack (4, direction);
  219. shotcount = shotcount - 1;
  220. }
  221. ApplyMultiDamage ();
  222. };
  223. /*
  224. ================
  225. W_FireShotgun
  226. ================
  227. */
  228. void() W_FireShotgun =
  229. {
  230. local vector dir;
  231. sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
  232. self.punchangle_x = -2;
  233. self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  234. dir = aim (self, 100000);
  235. FireBullets (6, dir, '0.04 0.04 0');
  236. };
  237. /*
  238. ================
  239. W_FireSuperShotgun
  240. ================
  241. */
  242. void() W_FireSuperShotgun =
  243. {
  244. local vector dir;
  245. if (self.currentammo == 1)
  246. {
  247. W_FireShotgun ();
  248. return;
  249. }
  250. sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
  251. self.punchangle_x = -4;
  252. self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  253. dir = aim (self, 100000);
  254. FireBullets (14, dir, '0.14 0.08 0');
  255. };
  256. /*
  257. ==============================================================================
  258. ROCKETS
  259. ==============================================================================
  260. */
  261. void() s_explode1 = [0, s_explode2] {};
  262. void() s_explode2 = [1, s_explode3] {};
  263. void() s_explode3 = [2, s_explode4] {};
  264. void() s_explode4 = [3, s_explode5] {};
  265. void() s_explode5 = [4, s_explode6] {};
  266. void() s_explode6 = [5, SUB_Remove] {};
  267. void() BecomeExplosion =
  268. {
  269. self.movetype = MOVETYPE_NONE;
  270. self.velocity = '0 0 0';
  271. self.touch = SUB_Null;
  272. setmodel (self, "progs/s_explod.spr");
  273. self.solid = SOLID_NOT;
  274. s_explode1 ();
  275. };
  276. void() T_MissileTouch =
  277. {
  278. local float damg;
  279. if (other == self.owner)
  280. return; // don't explode on owner
  281. if (pointcontents(self.origin) == CONTENT_SKY)
  282. {
  283. remove(self);
  284. return;
  285. }
  286. damg = 100 + random()*20;
  287. if (other.health)
  288. {
  289. if (other.classname == "monster_shambler")
  290. damg = damg * 0.5; // mostly immune
  291. T_Damage (other, self, self.owner, damg );
  292. }
  293. // don't do radius damage to the other, because all the damage
  294. // was done in the impact
  295. T_RadiusDamage (self, self.owner, 120, other);
  296. // sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  297. self.origin = self.origin - 8*normalize(self.velocity);
  298. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  299. WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  300. WriteCoord (MSG_BROADCAST, self.origin_x);
  301. WriteCoord (MSG_BROADCAST, self.origin_y);
  302. WriteCoord (MSG_BROADCAST, self.origin_z);
  303. BecomeExplosion ();
  304. };
  305. /*
  306. ================
  307. W_FireRocket
  308. ================
  309. */
  310. void() W_FireRocket =
  311. {
  312. local entity missile, mpuff;
  313. self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  314. sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  315. self.punchangle_x = -2;
  316. missile = spawn ();
  317. missile.owner = self;
  318. missile.movetype = MOVETYPE_FLYMISSILE;
  319. missile.solid = SOLID_BBOX;
  320. // set missile speed
  321. makevectors (self.v_angle);
  322. missile.velocity = aim(self, 1000);
  323. missile.velocity = missile.velocity * 1000;
  324. missile.angles = vectoangles(missile.velocity);
  325. missile.touch = T_MissileTouch;
  326. // set missile duration
  327. missile.nextthink = time + 5;
  328. missile.think = SUB_Remove;
  329. setmodel (missile, "progs/missile.mdl");
  330. setsize (missile, '0 0 0', '0 0 0');
  331. setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  332. };
  333. /*
  334. ===============================================================================
  335. LIGHTNING
  336. ===============================================================================
  337. */
  338. /*
  339. =================
  340. LightningDamage
  341. =================
  342. */
  343. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  344. {
  345. local entity e1, e2;
  346. local vector f;
  347. f = p2 - p1;
  348. normalize (f);
  349. f_x = 0 - f_y;
  350. f_y = f_x;
  351. f_z = 0;
  352. f = f*16;
  353. e1 = e2 = world;
  354. traceline (p1, p2, FALSE, self);
  355. if (trace_ent.takedamage)
  356. {
  357. particle (trace_endpos, '0 0 100', 225, damage*4);
  358. T_Damage (trace_ent, from, from, damage);
  359. if (self.classname == "player")
  360. {
  361. if (other.classname == "player")
  362. trace_ent.velocity_z = trace_ent.velocity_z + 400;
  363. }
  364. }
  365. e1 = trace_ent;
  366. traceline (p1 + f, p2 + f, FALSE, self);
  367. if (trace_ent != e1 && trace_ent.takedamage)
  368. {
  369. particle (trace_endpos, '0 0 100', 225, damage*4);
  370. T_Damage (trace_ent, from, from, damage);
  371. }
  372. e2 = trace_ent;
  373. traceline (p1 - f, p2 - f, FALSE, self);
  374. if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  375. {
  376. particle (trace_endpos, '0 0 100', 225, damage*4);
  377. T_Damage (trace_ent, from, from, damage);
  378. }
  379. };
  380. void() W_FireLightning =
  381. {
  382. local vector org;
  383. if (self.ammo_cells < 1)
  384. {
  385. self.weapon = W_BestWeapon ();
  386. W_SetCurrentAmmo ();
  387. return;
  388. }
  389. // explode if under water
  390. if (self.waterlevel > 1)
  391. {
  392. T_RadiusDamage (self, self, 35*self.ammo_cells, world);
  393. self.ammo_cells = 0;
  394. W_SetCurrentAmmo ();
  395. return;
  396. }
  397. if (self.t_width < time)
  398. {
  399. sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  400. self.t_width = time + 0.6;
  401. }
  402. self.punchangle_x = -2;
  403. self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  404. org = self.origin + '0 0 16';
  405. traceline (org, org + v_forward*600, TRUE, self);
  406. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  407. WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  408. WriteEntity (MSG_BROADCAST, self);
  409. WriteCoord (MSG_BROADCAST, org_x);
  410. WriteCoord (MSG_BROADCAST, org_y);
  411. WriteCoord (MSG_BROADCAST, org_z);
  412. WriteCoord (MSG_BROADCAST, trace_endpos_x);
  413. WriteCoord (MSG_BROADCAST, trace_endpos_y);
  414. WriteCoord (MSG_BROADCAST, trace_endpos_z);
  415. LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  416. };
  417. //=============================================================================
  418. void() GrenadeExplode =
  419. {
  420. T_RadiusDamage (self, self.owner, 120, world);
  421. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  422. WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  423. WriteCoord (MSG_BROADCAST, self.origin_x);
  424. WriteCoord (MSG_BROADCAST, self.origin_y);
  425. WriteCoord (MSG_BROADCAST, self.origin_z);
  426. BecomeExplosion ();
  427. };
  428. void() GrenadeTouch =
  429. {
  430. if (other == self.owner)
  431. return; // don't explode on owner
  432. if (other.takedamage == DAMAGE_AIM)
  433. {
  434. GrenadeExplode();
  435. return;
  436. }
  437. sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM); // bounce sound
  438. if (self.velocity == '0 0 0')
  439. self.avelocity = '0 0 0';
  440. };
  441. /*
  442. ================
  443. W_FireGrenade
  444. ================
  445. */
  446. void() W_FireGrenade =
  447. {
  448. local entity missile, mpuff;
  449. self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  450. sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  451. self.punchangle_x = -2;
  452. missile = spawn ();
  453. missile.owner = self;
  454. missile.movetype = MOVETYPE_BOUNCE;
  455. missile.solid = SOLID_BBOX;
  456. missile.classname = "grenade";
  457. // set missile speed
  458. makevectors (self.v_angle);
  459. if (self.v_angle_x)
  460. missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  461. else
  462. {
  463. missile.velocity = aim(self, 10000);
  464. missile.velocity = missile.velocity * 600;
  465. missile.velocity_z = 200;
  466. }
  467. missile.avelocity = '300 300 300';
  468. missile.angles = vectoangles(missile.velocity);
  469. missile.touch = GrenadeTouch;
  470. // set missile duration
  471. missile.nextthink = time + 2.5;
  472. missile.think = GrenadeExplode;
  473. setmodel (missile, "progs/grenade.mdl");
  474. setsize (missile, '0 0 0', '0 0 0');
  475. setorigin (missile, self.origin);
  476. };
  477. //=============================================================================
  478. void() spike_touch;
  479. void() superspike_touch;
  480. /*
  481. ===============
  482. launch_spike
  483. Used for both the player and the ogre
  484. ===============
  485. */
  486. void(vector org, vector dir) launch_spike =
  487. {
  488. newmis = spawn ();
  489. newmis.owner = self;
  490. newmis.movetype = MOVETYPE_FLYMISSILE;
  491. newmis.solid = SOLID_BBOX;
  492. newmis.angles = vectoangles(dir);
  493. newmis.touch = spike_touch;
  494. newmis.classname = "spike";
  495. newmis.think = SUB_Remove;
  496. newmis.nextthink = time + 6;
  497. setmodel (newmis, "progs/spike.mdl");
  498. setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  499. setorigin (newmis, org);
  500. newmis.velocity = dir * 1000;
  501. };
  502. void() W_FireSuperSpikes =
  503. {
  504. local vector dir;
  505. local entity old;
  506. sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  507. self.attack_finished = time + 0.2;
  508. self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  509. dir = aim (self, 1000);
  510. launch_spike (self.origin + '0 0 16', dir);
  511. newmis.touch = superspike_touch;
  512. setmodel (newmis, "progs/s_spike.mdl");
  513. setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  514. self.punchangle_x = -2;
  515. };
  516. void(float ox) W_FireSpikes =
  517. {
  518. local vector dir;
  519. local entity old;
  520. makevectors (self.v_angle);
  521. if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  522. {
  523. W_FireSuperSpikes ();
  524. return;
  525. }
  526. if (self.ammo_nails < 1)
  527. {
  528. self.weapon = W_BestWeapon ();
  529. W_SetCurrentAmmo ();
  530. return;
  531. }
  532. sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  533. self.attack_finished = time + 0.2;
  534. self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  535. dir = aim (self, 1000);
  536. launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  537. self.punchangle_x = -2;
  538. };
  539. .float hit_z;
  540. void() spike_touch =
  541. {
  542. local float rand;
  543. if (other == self.owner)
  544. return;
  545. if (other.solid == SOLID_TRIGGER)
  546. return; // trigger field, do nothing
  547. if (pointcontents(self.origin) == CONTENT_SKY)
  548. {
  549. remove(self);
  550. return;
  551. }
  552. // hit something that bleeds
  553. if (other.takedamage)
  554. {
  555. spawn_touchblood (9);
  556. T_Damage (other, self, self.owner, 9);
  557. }
  558. else
  559. {
  560. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  561. if (self.classname == "wizspike")
  562. WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  563. else if (self.classname == "knightspike")
  564. WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  565. else
  566. WriteByte (MSG_BROADCAST, TE_SPIKE);
  567. WriteCoord (MSG_BROADCAST, self.origin_x);
  568. WriteCoord (MSG_BROADCAST, self.origin_y);
  569. WriteCoord (MSG_BROADCAST, self.origin_z);
  570. }
  571. remove(self);
  572. };
  573. void() superspike_touch =
  574. {
  575. local float rand;
  576. if (other == self.owner)
  577. return;
  578. if (other.solid == SOLID_TRIGGER)
  579. return; // trigger field, do nothing
  580. if (pointcontents(self.origin) == CONTENT_SKY)
  581. {
  582. remove(self);
  583. return;
  584. }
  585. // hit something that bleeds
  586. if (other.takedamage)
  587. {
  588. spawn_touchblood (18);
  589. T_Damage (other, self, self.owner, 18);
  590. }
  591. else
  592. {
  593. WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  594. WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  595. WriteCoord (MSG_BROADCAST, self.origin_x);
  596. WriteCoord (MSG_BROADCAST, self.origin_y);
  597. WriteCoord (MSG_BROADCAST, self.origin_z);
  598. }
  599. remove(self);
  600. };
  601. /*
  602. ===============================================================================
  603. PLAYER WEAPON USE
  604. ===============================================================================
  605. */
  606. void() W_SetCurrentAmmo =
  607. {
  608. player_run (); // get out of any weapon firing states
  609. self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  610. if (self.weapon == IT_AXE)
  611. {
  612. self.currentammo = 0;
  613. self.weaponmodel = "progs/v_axe.mdl";
  614. self.weaponframe = 0;
  615. }
  616. else if (self.weapon == IT_SHOTGUN)
  617. {
  618. self.currentammo = self.ammo_shells;
  619. self.weaponmodel = "progs/v_shot.mdl";
  620. self.weaponframe = 0;
  621. self.items = self.items | IT_SHELLS;
  622. }
  623. else if (self.weapon == IT_SUPER_SHOTGUN)
  624. {
  625. self.currentammo = self.ammo_shells;
  626. self.weaponmodel = "progs/v_shot2.mdl";
  627. self.weaponframe = 0;
  628. self.items = self.items | IT_SHELLS;
  629. }
  630. else if (self.weapon == IT_NAILGUN)
  631. {
  632. self.currentammo = self.ammo_nails;
  633. self.weaponmodel = "progs/v_nail.mdl";
  634. self.weaponframe = 0;
  635. self.items = self.items | IT_NAILS;
  636. }
  637. else if (self.weapon == IT_SUPER_NAILGUN)
  638. {
  639. self.currentammo = self.ammo_nails;
  640. self.weaponmodel = "progs/v_nail2.mdl";
  641. self.weaponframe = 0;
  642. self.items = self.items | IT_NAILS;
  643. }
  644. else if (self.weapon == IT_GRENADE_LAUNCHER)
  645. {
  646. self.currentammo = self.ammo_rockets;
  647. self.weaponmodel = "progs/v_rock.mdl";
  648. self.weaponframe = 0;
  649. self.items = self.items | IT_ROCKETS;
  650. }
  651. else if (self.weapon == IT_ROCKET_LAUNCHER)
  652. {
  653. self.currentammo = self.ammo_rockets;
  654. self.weaponmodel = "progs/v_rock2.mdl";
  655. self.weaponframe = 0;
  656. self.items = self.items | IT_ROCKETS;
  657. }
  658. else if (self.weapon == IT_LIGHTNING)
  659. {
  660. self.currentammo = self.ammo_cells;
  661. self.weaponmodel = "progs/v_light.mdl";
  662. self.weaponframe = 0;
  663. self.items = self.items | IT_CELLS;
  664. }
  665. else
  666. {
  667. self.currentammo = 0;
  668. self.weaponmodel = "";
  669. self.weaponframe = 0;
  670. }
  671. };
  672. float() W_BestWeapon =
  673. {
  674. local float it;
  675. it = self.items;
  676. if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  677. return IT_LIGHTNING;
  678. else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  679. return IT_SUPER_NAILGUN;
  680. else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  681. return IT_SUPER_SHOTGUN;
  682. else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  683. return IT_NAILGUN;
  684. else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  685. return IT_SHOTGUN;
  686. /*
  687. if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  688. return IT_ROCKET_LAUNCHER;
  689. else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
  690. return IT_GRENADE_LAUNCHER;
  691. */
  692. return IT_AXE;
  693. };
  694. float() W_CheckNoAmmo =
  695. {
  696. if (self.currentammo > 0)
  697. return TRUE;
  698. if (self.weapon == IT_AXE)
  699. return TRUE;
  700. self.weapon = W_BestWeapon ();
  701. W_SetCurrentAmmo ();
  702. // drop the weapon down
  703. return FALSE;
  704. };
  705. /*
  706. ============
  707. W_Attack
  708. An attack impulse can be triggered now
  709. ============
  710. */
  711. void() player_axe1;
  712. void() player_axeb1;
  713. void() player_axec1;
  714. void() player_axed1;
  715. void() player_shot1;
  716. void() player_nail1;
  717. void() player_light1;
  718. void() player_rocket1;
  719. void() W_Attack =
  720. {
  721. local float r;
  722. if (!W_CheckNoAmmo ())
  723. return;
  724. makevectors (self.v_angle); // calculate forward angle for velocity
  725. self.show_hostile = time + 1; // wake monsters up
  726. if (self.weapon == IT_AXE)
  727. {
  728. sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  729. r = random();
  730. if (r < 0.25)
  731. player_axe1 ();
  732. else if (r<0.5)
  733. player_axeb1 ();
  734. else if (r<0.75)
  735. player_axec1 ();
  736. else
  737. player_axed1 ();
  738. self.attack_finished = time + 0.5;
  739. }
  740. else if (self.weapon == IT_SHOTGUN)
  741. {
  742. player_shot1 ();
  743. W_FireShotgun ();
  744. self.attack_finished = time + 0.5;
  745. }
  746. else if (self.weapon == IT_SUPER_SHOTGUN)
  747. {
  748. player_shot1 ();
  749. W_FireSuperShotgun ();
  750. self.attack_finished = time + 0.7;
  751. }
  752. else if (self.weapon == IT_NAILGUN)
  753. {
  754. player_nail1 ();
  755. }
  756. else if (self.weapon == IT_SUPER_NAILGUN)
  757. {
  758. player_nail1 ();
  759. }
  760. else if (self.weapon == IT_GRENADE_LAUNCHER)
  761. {
  762. player_rocket1();
  763. W_FireGrenade();
  764. self.attack_finished = time + 0.6;
  765. }
  766. else if (self.weapon == IT_ROCKET_LAUNCHER)
  767. {
  768. player_rocket1();
  769. W_FireRocket();
  770. self.attack_finished = time + 0.8;
  771. }
  772. else if (self.weapon == IT_LIGHTNING)
  773. {
  774. player_light1();
  775. self.attack_finished = time + 0.1;
  776. sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  777. }
  778. };
  779. /*
  780. ============
  781. W_ChangeWeapon
  782. ============
  783. */
  784. void() W_ChangeWeapon =
  785. {
  786. local float it, am, fl;
  787. it = self.items;
  788. am = 0;
  789. if (self.impulse == 1)
  790. {
  791. fl = IT_AXE;
  792. }
  793. else if (self.impulse == 2)
  794. {
  795. fl = IT_SHOTGUN;
  796. if (self.ammo_shells < 1)
  797. am = 1;
  798. }
  799. else if (self.impulse == 3)
  800. {
  801. fl = IT_SUPER_SHOTGUN;
  802. if (self.ammo_shells < 2)
  803. am = 1;
  804. }
  805. else if (self.impulse == 4)
  806. {
  807. fl = IT_NAILGUN;
  808. if (self.ammo_nails < 1)
  809. am = 1;
  810. }
  811. else if (self.impulse == 5)
  812. {
  813. fl = IT_SUPER_NAILGUN;
  814. if (self.ammo_nails < 2)
  815. am = 1;
  816. }
  817. else if (self.impulse == 6)
  818. {
  819. fl = IT_GRENADE_LAUNCHER;
  820. if (self.ammo_rockets < 1)
  821. am = 1;
  822. }
  823. else if (self.impulse == 7)
  824. {
  825. fl = IT_ROCKET_LAUNCHER;
  826. if (self.ammo_rockets < 1)
  827. am = 1;
  828. }
  829. else if (self.impulse == 8)
  830. {
  831. fl = IT_LIGHTNING;
  832. if (self.ammo_cells < 1)
  833. am = 1;
  834. }
  835. self.impulse = 0;
  836. if (!(self.items & fl))
  837. { // don't have the weapon or the ammo
  838. sprint (self, "no weapon.\n");
  839. return;
  840. }
  841. if (am)
  842. { // don't have the ammo
  843. sprint (self, "not enough ammo.\n");
  844. return;
  845. }
  846. //
  847. // set weapon, set ammo
  848. //
  849. self.weapon = fl;
  850. W_SetCurrentAmmo ();
  851. };
  852. /*
  853. ============
  854. CheatCommand
  855. ============
  856. */
  857. void() CheatCommand =
  858. {
  859. if (deathmatch || coop)
  860. return;
  861. self.ammo_rockets = 100;
  862. self.ammo_nails = 200;
  863. self.ammo_shells = 100;
  864. self.items = self.items |
  865. IT_AXE |
  866. IT_SHOTGUN |
  867. IT_SUPER_SHOTGUN |
  868. IT_NAILGUN |
  869. IT_SUPER_NAILGUN |
  870. IT_GRENADE_LAUNCHER |
  871. IT_ROCKET_LAUNCHER |
  872. IT_KEY1 | IT_KEY2;
  873. self.ammo_cells = 200;
  874. self.items = self.items | IT_LIGHTNING;
  875. self.weapon = IT_ROCKET_LAUNCHER;
  876. self.impulse = 0;
  877. W_SetCurrentAmmo ();
  878. };
  879. /*
  880. ============
  881. CycleWeaponCommand
  882. Go to the next weapon with ammo
  883. ============
  884. */
  885. void() CycleWeaponCommand =
  886. {
  887. local float it, am;
  888. it = self.items;
  889. self.impulse = 0;
  890. while (1)
  891. {
  892. am = 0;
  893. if (self.weapon == IT_LIGHTNING)
  894. {
  895. self.weapon = IT_AXE;
  896. }
  897. else if (self.weapon == IT_AXE)
  898. {
  899. self.weapon = IT_SHOTGUN;
  900. if (self.ammo_shells < 1)
  901. am = 1;
  902. }
  903. else if (self.weapon == IT_SHOTGUN)
  904. {
  905. self.weapon = IT_SUPER_SHOTGUN;
  906. if (self.ammo_shells < 2)
  907. am = 1;
  908. }
  909. else if (self.weapon == IT_SUPER_SHOTGUN)
  910. {
  911. self.weapon = IT_NAILGUN;
  912. if (self.ammo_nails < 1)
  913. am = 1;
  914. }
  915. else if (self.weapon == IT_NAILGUN)
  916. {
  917. self.weapon = IT_SUPER_NAILGUN;
  918. if (self.ammo_nails < 2)
  919. am = 1;
  920. }
  921. else if (self.weapon == IT_SUPER_NAILGUN)
  922. {
  923. self.weapon = IT_GRENADE_LAUNCHER;
  924. if (self.ammo_rockets < 1)
  925. am = 1;
  926. }
  927. else if (self.weapon == IT_GRENADE_LAUNCHER)
  928. {
  929. self.weapon = IT_ROCKET_LAUNCHER;
  930. if (self.ammo_rockets < 1)
  931. am = 1;
  932. }
  933. else if (self.weapon == IT_ROCKET_LAUNCHER)
  934. {
  935. self.weapon = IT_LIGHTNING;
  936. if (self.ammo_cells < 1)
  937. am = 1;
  938. }
  939. if ( (self.items & self.weapon) && am == 0)
  940. {
  941. W_SetCurrentAmmo ();
  942. return;
  943. }
  944. }
  945. };
  946. /*
  947. ============
  948. ServerflagsCommand
  949. Just for development
  950. ============
  951. */
  952. void() ServerflagsCommand =
  953. {
  954. serverflags = serverflags * 2 + 1;
  955. };
  956. void() QuadCheat =
  957. {
  958. if (deathmatch || coop)
  959. return;
  960. self.super_time = 1;
  961. self.super_damage_finished = time + 30;
  962. self.items = self.items | IT_QUAD;
  963. dprint ("quad cheat\n");
  964. };
  965. /*
  966. ============
  967. ImpulseCommands
  968. ============
  969. */
  970. void() ImpulseCommands =
  971. {
  972. if (self.impulse >= 1 && self.impulse <= 8)
  973. W_ChangeWeapon ();
  974. if (self.impulse == 9)
  975. CheatCommand ();
  976. if (self.impulse == 10)
  977. CycleWeaponCommand ();
  978. if (self.impulse == 11)
  979. ServerflagsCommand ();
  980. if (self.impulse == 255)
  981. QuadCheat ();
  982. self.impulse = 0;
  983. };
  984. /*
  985. ============
  986. W_WeaponFrame
  987. Called every frame so impulse events can be handled as well as possible
  988. ============
  989. */
  990. void() W_WeaponFrame =
  991. {
  992. if (time < self.attack_finished)
  993. return;
  994. ImpulseCommands ();
  995. // check for attack
  996. if (self.button0)
  997. {
  998. SuperDamageSound ();
  999. W_Attack ();
  1000. }
  1001. };
  1002. /*
  1003. ========
  1004. SuperDamageSound
  1005. Plays sound if needed
  1006. ========
  1007. */
  1008. void() SuperDamageSound =
  1009. {
  1010. if (self.super_damage_finished > time)
  1011. {
  1012. if (self.super_sound < time)
  1013. {
  1014. self.super_sound = time + 1;
  1015. sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1016. }
  1017. }
  1018. return;
  1019. };