home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / frenzy1c / weapons.qc
Encoding:
Text File  |  1996-08-01  |  53.9 KB  |  1,880 lines

  1. //==========================================================================
  2. // GRENADE FRENZY                   Bill Lefler
  3. //                                  blefler@digital.net
  4. //
  5. // I threw together my favorite weapons patches. Thanks to the original
  6. // authors for their pioneering efforts!
  7. //
  8. //==========================================================================
  9. //==========================================================================
  10. // Modified weapons.qc - "Blaster" patch by Michael Dewberry.
  11. // Created 7.26.96.
  12. // - replaces single shotgun with laser
  13. //==========================================================================
  14. // Bouncing Fragmentation Grenade!    7/28/96 by Steve Bond
  15. // Email: wedge@nuc.net    WWW: http://www.nuc.net/quake
  16. //
  17. // modified by Bill Lefler 7/31/96
  18. //   - only take 2 grenades - 25 pieces of shrapnel.
  19. //                                  "IMPULSE 20" - fire frag grenade
  20. //==========================================================================
  21. // * Cluster-Bouncy-Proximity Grenades  -- Grenades are now bouncy
  22. // proximity mines.  A grenade will lay on the floor and hop at
  23. // intervals.  If a target is detected within range, the grenade will
  24. // hop towards the target and explode.  Grenades won't detect targets
  25. // while they're in the air.  When the grenade launcher is fired, if you
  26. // have less than five ammo you will fire a single grenade which
  27. // will behave as described above.  If you have 5 or more ammo, you'll
  28. // fire a cluster bomb which will explode and release five proximity
  29. // grenades.
  30. //
  31. // Mods by
  32. //         John Spickes jspickes@eng.umd.edu {JDS}
  33. //         Josh Spickes spickesj@wam.umd.edu
  34. //         Allen Seger
  35. //         Bill Lefler 8/1/96 ----> "IMPULSE 21" - fire proximity grenade
  36. //==========================================================================
  37. // PipeBombs
  38. //
  39. // Modifications by AsmodeusB (28/07/96)
  40. //
  41. // Bill Lefler 8/1/96 - changed keys to:
  42. //                                  "IMPULSE 22" - fire pipe bomb
  43. //                                  "IMPULSE 23" - detonate pipe bomps
  44. //==========================================================================
  45.  
  46. void()  player_axe1;
  47. void()  player_axeb1;
  48. void()  player_axec1;
  49. void()  player_axed1;
  50. void()  player_shot1;
  51. void()  player_nail1;
  52. void()  player_light1;
  53. void()  player_rocket1;
  54.  
  55.  
  56.  
  57. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  58. void () player_run;
  59. void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
  60. void(vector org, vector vel, float damage) SpawnBlood;
  61. void() SuperDamageSound;
  62.  
  63. void(vector org, vector vec) LaunchLaser;
  64.  
  65. // called by worldspawn
  66. void() W_Precache =
  67. {
  68.         precache_sound ("weapons/r_exp3.wav");  // new rocket explosion
  69.         precache_sound ("weapons/rocket1i.wav");        // spike gun
  70.         precache_sound ("weapons/sgun1.wav");
  71.         precache_sound ("weapons/guncock.wav"); // player shotgun
  72.         precache_sound ("weapons/ric1.wav");    // ricochet (used in c code)
  73.         precache_sound ("weapons/ric2.wav");    // ricochet (used in c code)
  74.         precache_sound ("weapons/ric3.wav");    // ricochet (used in c code)
  75.         precache_sound ("weapons/spike2.wav");  // super spikes
  76.         precache_sound ("weapons/tink1.wav");   // spikes tink (used in c code)
  77.         precache_sound ("weapons/grenade.wav"); // grenade launcher
  78.         precache_sound ("weapons/bounce.wav");          // grenade bounce
  79.         precache_sound ("weapons/shotgn2.wav"); // super shotgun
  80.         precache_model2 ("progs/laser.mdl");
  81.         precache_sound2 ("enforcer/enfire.wav");        // super shotgun
  82.         precache_sound2 ("enforcer/enfstop.wav");       // super shotgun
  83. };
  84.  
  85. float() crandom =
  86. {
  87.         return 2*(random() - 0.5);
  88. };
  89.  
  90. /*
  91. ================
  92. W_FireAxe
  93. ================
  94. */
  95. void() W_FireAxe =
  96. {
  97.         local   vector  source;
  98.         local   vector  org;
  99.  
  100.         source = self.origin + '0 0 16';
  101.         traceline (source, source + v_forward*64, FALSE, self);
  102.         if (trace_fraction == 1.0)
  103.                 return;
  104.  
  105.         org = trace_endpos - v_forward*4;
  106.  
  107.         if (trace_ent.takedamage)
  108.         {
  109.                 trace_ent.axhitme = 1;
  110.                 SpawnBlood (org, '0 0 0', 20);
  111.                 T_Damage (trace_ent, self, self, 20);
  112.         }
  113.         else
  114.         {       // hit wall
  115.                 sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  116.                 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  117.                 WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  118.                 WriteCoord (MSG_BROADCAST, org_x);
  119.                 WriteCoord (MSG_BROADCAST, org_y);
  120.                 WriteCoord (MSG_BROADCAST, org_z);
  121.         }
  122. };
  123.  
  124.  
  125. //============================================================================
  126.  
  127.  
  128. vector() wall_velocity =
  129. {
  130.         local vector    vel;
  131.  
  132.         vel = normalize (self.velocity);
  133.         vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  134.         vel = vel + 2*trace_plane_normal;
  135.         vel = vel * 200;
  136.  
  137.         return vel;
  138. };
  139.  
  140.  
  141. /*
  142. ================
  143. SpawnMeatSpray
  144. ================
  145. */
  146. void(vector org, vector vel) SpawnMeatSpray =
  147. {
  148.         local   entity missile, mpuff;
  149.         local   vector  org;
  150.  
  151.         missile = spawn ();
  152.         missile.owner = self;
  153.         missile.movetype = MOVETYPE_BOUNCE;
  154.         missile.solid = SOLID_NOT;
  155.  
  156.         makevectors (self.angles);
  157.  
  158.         missile.velocity = vel;
  159.         missile.velocity_z = missile.velocity_z + 250 + 50*random();
  160.  
  161.         missile.avelocity = '3000 1000 2000';
  162.  
  163. // set missile duration
  164.         missile.nextthink = time + 1;
  165.         missile.think = SUB_Remove;
  166.  
  167.         setmodel (missile, "progs/zom_gib.mdl");
  168.         setsize (missile, '0 0 0', '0 0 0');
  169.         setorigin (missile, org);
  170. };
  171.  
  172. /*
  173. ================
  174. SpawnBlood
  175. ================
  176. */
  177. void(vector org, vector vel, float damage) SpawnBlood =
  178. {
  179.         particle (org, vel*0.1, 73, damage*2);
  180. };
  181.  
  182. /*
  183. ================
  184. spawn_touchblood
  185. ================
  186. */
  187. void(float damage) spawn_touchblood =
  188. {
  189.         local vector    vel;
  190.  
  191.         vel = wall_velocity () * 0.2;
  192.         SpawnBlood (self.origin + vel*0.01, vel, damage);
  193. };
  194.  
  195.  
  196. /*
  197. ================
  198. SpawnChunk
  199. ================
  200. */
  201. void(vector org, vector vel) SpawnChunk =
  202. {
  203.         particle (org, vel*0.02, 0, 10);
  204. };
  205.  
  206. /*
  207. ==============================================================================
  208.  
  209. MULTI-DAMAGE
  210.  
  211. Collects multiple small damages into a single damage
  212.  
  213. ==============================================================================
  214. */
  215.  
  216. entity  multi_ent;
  217. float   multi_damage;
  218.  
  219. void() ClearMultiDamage =
  220. {
  221.         multi_ent = world;
  222.         multi_damage = 0;
  223. };
  224.  
  225. void() ApplyMultiDamage =
  226. {
  227.         if (!multi_ent)
  228.                 return;
  229.         T_Damage (multi_ent, self, self, multi_damage);
  230. };
  231.  
  232. void(entity hit, float damage) AddMultiDamage =
  233. {
  234.         if (!hit)
  235.                 return;
  236.  
  237.         if (hit != multi_ent)
  238.         {
  239.                 ApplyMultiDamage ();
  240.                 multi_damage = damage;
  241.                 multi_ent = hit;
  242.         }
  243.         else
  244.                 multi_damage = multi_damage + damage;
  245. };
  246.  
  247. /*
  248. ==============================================================================
  249.  
  250. BULLETS
  251.  
  252. ==============================================================================
  253. */
  254.  
  255. /*
  256. ================
  257. TraceAttack
  258. ================
  259. */
  260. void(float damage, vector dir) TraceAttack =
  261. {
  262.         local   vector  vel, org;
  263.  
  264.         vel = normalize(dir + v_up*crandom() + v_right*crandom());
  265.         vel = vel + 2*trace_plane_normal;
  266.         vel = vel * 200;
  267.  
  268.         org = trace_endpos - dir*4;
  269.  
  270.         if (trace_ent.takedamage)
  271.         {
  272.                 SpawnBlood (org, vel*0.2, damage);
  273.                 AddMultiDamage (trace_ent, damage);
  274.         }
  275.         else
  276.         {
  277.                 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  278.                 WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  279.                 WriteCoord (MSG_BROADCAST, org_x);
  280.                 WriteCoord (MSG_BROADCAST, org_y);
  281.                 WriteCoord (MSG_BROADCAST, org_z);
  282.         }
  283. };
  284.  
  285. /*
  286. ================
  287. FireBullets
  288.  
  289. Used by shotgun, super shotgun, and enemy soldier firing
  290. Go to the trouble of combining multiple pellets into a single damage call.
  291. ================
  292. */
  293. void(float shotcount, vector dir, vector spread) FireBullets =
  294. {
  295.         local   vector direction;
  296.         local   vector  src;
  297.  
  298.         makevectors(self.v_angle);
  299.  
  300.         src = self.origin + v_forward*10;
  301.         src_z = self.absmin_z + self.size_z * 0.7;
  302.  
  303.         ClearMultiDamage ();
  304.         while (shotcount > 0)
  305.         {
  306.                 direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  307.  
  308.                 traceline (src, src + direction*2048, FALSE, self);
  309.                 if (trace_fraction != 1.0)
  310.                         TraceAttack (4, direction);
  311.  
  312.                 shotcount = shotcount - 1;
  313.         }
  314.         ApplyMultiDamage ();
  315. };
  316.  
  317. /*
  318. ================
  319. W_FireShotgun
  320.  
  321. Procedures added and modified by Michael Dewberry - "Blaster" patch
  322. ================
  323. */
  324.  
  325. void( vector org, vector dir ) FireShot_Laser =
  326. {
  327.         local vector spread, direction;
  328.         spread = '0.04 0.04 0.04';
  329.  
  330.         // On quad damage, make a monster spread triple blast. :)
  331.         if (self.super_damage_finished > time)
  332.         {
  333.                     // For some reason, direction = dir + crandom*spread_x +                                                                                                   // crandom*spread_y ... etc. didn't work.
  334.                 // It works in other places in the code though.. weird.
  335.  
  336.                 direction_x = dir_x + crandom()*spread_x;
  337.                 direction_y = dir_y + crandom()*spread_y;
  338.                 direction_z = dir_z + crandom()*spread_z;
  339.                 LaunchLaser( org, direction );
  340.  
  341.                 direction_x = dir_x + crandom()*spread_x;
  342.                 direction_y = dir_y + crandom()*spread_y;
  343.                 direction_z = dir_z + crandom()*spread_z;
  344.                 LaunchLaser( org, direction );
  345.  
  346.                 direction_x = dir_x + crandom()*spread_x;
  347.                 direction_y = dir_y + crandom()*spread_y;
  348.                 direction_z = dir_z + crandom()*spread_z;
  349.                 LaunchLaser( org, direction );
  350.         }
  351.         else
  352.                 LaunchLaser( org, dir );
  353. };
  354.  
  355. // Third and final shot.
  356. void() W_FireShotgun3 =
  357. {
  358.         local vector dir, org;
  359.  
  360.         player_shot1 ();
  361.         self.punchangle_x = -2;
  362.         if (self.ammo_shells > 0)
  363.         {
  364.                 self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  365.  
  366.                 org = self.origin + v_forward*8 + '0 0 16';
  367.                 dir = aim (self, 100000);
  368.                 FireShot_Laser(org, dir);
  369.         }
  370. };
  371.  
  372. // Second shot.
  373. void() W_FireShotgun2 =
  374. {
  375.         local vector dir, org;
  376.  
  377.         player_shot1 ();
  378.         self.punchangle_x = -2;
  379.         if (self.ammo_shells > 0)
  380.         {
  381.                 self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  382.  
  383.                 org = self.origin + v_forward*8 + '0 0 16';
  384.                 dir = aim (self, 100000);
  385.                 FireShot_Laser(org, dir);
  386.         }
  387.         self.think = W_FireShotgun3;
  388.         self.nextthink = 1;
  389.  
  390. };
  391.  
  392. // First shot. Only called if there's shotgun ammo, so no need to check for
  393. // enough ammo here.
  394. void() W_FireShotgun =
  395. {
  396.         local vector dir, org;
  397.  
  398.         org = self.origin + v_forward*8 + '0 0 16';
  399.  
  400.         self.punchangle_x = -2;
  401.  
  402.         self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  403.         dir = aim (self, 100000);
  404.         FireShot_Laser(org, dir);
  405.         self.think = W_FireShotgun2;
  406.         self.nextthink = 1;
  407.  
  408. };
  409.  
  410.  
  411. /*
  412. ================
  413. W_FireSuperShotgun
  414. ================
  415. */
  416. void() W_FireSuperShotgun =
  417. {
  418.         local vector dir;
  419.  
  420.         if (self.currentammo == 1)
  421.         {
  422.                 W_FireShotgun ();
  423.                 return;
  424.         }
  425.  
  426.         sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
  427.  
  428.         self.punchangle_x = -4;
  429.  
  430.         self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  431.         dir = aim (self, 100000);
  432.         FireBullets (14, dir, '0.14 0.08 0');
  433. };
  434.  
  435.  
  436. /*
  437. ==============================================================================
  438.  
  439. ROCKETS
  440.  
  441. ==============================================================================
  442. */
  443.  
  444. void()  s_explode1      =       [0,             s_explode2] {};
  445. void()  s_explode2      =       [1,             s_explode3] {};
  446. void()  s_explode3      =       [2,             s_explode4] {};
  447. void()  s_explode4      =       [3,             s_explode5] {};
  448. void()  s_explode5      =       [4,             s_explode6] {};
  449. void()  s_explode6      =       [5,             SUB_Remove] {};
  450.  
  451. void() BecomeExplosion =
  452. {
  453.         self.movetype = MOVETYPE_NONE;
  454.         self.velocity = '0 0 0';
  455.         self.touch = SUB_Null;
  456.         setmodel (self, "progs/s_explod.spr");
  457.         self.solid = SOLID_NOT;
  458.         s_explode1 ();
  459. };
  460.  
  461. void() T_MissileTouch =
  462. {
  463.         local float     damg;
  464.  
  465.         if (other == self.owner)
  466.                 return;         // don't explode on owner
  467.  
  468.         if (pointcontents(self.origin) == CONTENT_SKY)
  469.         {
  470.                 remove(self);
  471.                 return;
  472.         }
  473.  
  474.         damg = 100 + random()*20;
  475.  
  476.         if (other.health)
  477.         {
  478.                 if (other.classname == "monster_shambler")
  479.                         damg = damg * 0.5;      // mostly immune
  480.                 T_Damage (other, self, self.owner, damg );
  481.         }
  482.  
  483.         // don't do radius damage to the other, because all the damage
  484.         // was done in the impact
  485.         T_RadiusDamage (self, self.owner, 120, other);
  486.  
  487. //      sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  488.         self.origin = self.origin - 8*normalize(self.velocity);
  489.  
  490.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  491.         WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  492.         WriteCoord (MSG_BROADCAST, self.origin_x);
  493.         WriteCoord (MSG_BROADCAST, self.origin_y);
  494.         WriteCoord (MSG_BROADCAST, self.origin_z);
  495.  
  496.         BecomeExplosion ();
  497. };
  498.  
  499.  
  500.  
  501. /*
  502. ================
  503. W_FireRocket
  504. ================
  505. */
  506. void() W_FireRocket =
  507. {
  508.         local   entity missile, mpuff;
  509.  
  510.         self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  511.  
  512.         sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  513.  
  514.         self.punchangle_x = -2;
  515.  
  516.         missile = spawn ();
  517.         missile.owner = self;
  518.         missile.movetype = MOVETYPE_FLYMISSILE;
  519.         missile.solid = SOLID_BBOX;
  520.  
  521. // set missile speed
  522.  
  523.         makevectors (self.v_angle);
  524.         missile.velocity = aim(self, 1000);
  525.         missile.velocity = missile.velocity * 1000;
  526.         missile.angles = vectoangles(missile.velocity);
  527.  
  528.         missile.touch = T_MissileTouch;
  529.  
  530. // set missile duration
  531.         missile.nextthink = time + 5;
  532.         missile.think = SUB_Remove;
  533.  
  534.         setmodel (missile, "progs/missile.mdl");
  535.         setsize (missile, '0 0 0', '0 0 0');
  536.         setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  537. };
  538.  
  539. /*
  540. ===============================================================================
  541.  
  542. LIGHTNING
  543.  
  544. ===============================================================================
  545. */
  546.  
  547. /*
  548. =================
  549. LightningDamage
  550. =================
  551. */
  552. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  553. {
  554.         local entity            e1, e2;
  555.         local vector            f;
  556.  
  557.         f = p2 - p1;
  558.         normalize (f);
  559.         f_x = 0 - f_y;
  560.         f_y = f_x;
  561.         f_z = 0;
  562.         f = f*16;
  563.  
  564.         e1 = e2 = world;
  565.  
  566.         traceline (p1, p2, FALSE, self);
  567.         if (trace_ent.takedamage)
  568.         {
  569.                 particle (trace_endpos, '0 0 100', 225, damage*4);
  570.                 T_Damage (trace_ent, from, from, damage);
  571.                 if (self.classname == "player")
  572.                 {
  573.                         if (other.classname == "player")
  574.                                 trace_ent.velocity_z = trace_ent.velocity_z + 400;
  575.                 }
  576.         }
  577.         e1 = trace_ent;
  578.  
  579.         traceline (p1 + f, p2 + f, FALSE, self);
  580.         if (trace_ent != e1 && trace_ent.takedamage)
  581.         {
  582.                 particle (trace_endpos, '0 0 100', 225, damage*4);
  583.                 T_Damage (trace_ent, from, from, damage);
  584.         }
  585.         e2 = trace_ent;
  586.  
  587.         traceline (p1 - f, p2 - f, FALSE, self);
  588.         if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  589.         {
  590.                 particle (trace_endpos, '0 0 100', 225, damage*4);
  591.                 T_Damage (trace_ent, from, from, damage);
  592.         }
  593. };
  594.  
  595.  
  596. void() W_FireLightning =
  597. {
  598.         local   vector          org;
  599.  
  600.         if (self.ammo_cells < 1)
  601.         {
  602.                 self.weapon = W_BestWeapon ();
  603.                 W_SetCurrentAmmo ();
  604.                 return;
  605.         }
  606.  
  607. // explode if under water
  608.         if (self.waterlevel > 1)
  609.         {
  610.                 T_RadiusDamage (self, self, 35*self.ammo_cells, world);
  611.                 self.ammo_cells = 0;
  612.                 W_SetCurrentAmmo ();
  613.                 return;
  614.         }
  615.  
  616.         if (self.t_width < time)
  617.         {
  618.                 sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  619.                 self.t_width = time + 0.6;
  620.         }
  621.         self.punchangle_x = -2;
  622.  
  623.         self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  624.  
  625.         org = self.origin + '0 0 16';
  626.  
  627.         traceline (org, org + v_forward*600, TRUE, self);
  628.  
  629.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  630.         WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  631.         WriteEntity (MSG_BROADCAST, self);
  632.         WriteCoord (MSG_BROADCAST, org_x);
  633.         WriteCoord (MSG_BROADCAST, org_y);
  634.         WriteCoord (MSG_BROADCAST, org_z);
  635.         WriteCoord (MSG_BROADCAST, trace_endpos_x);
  636.         WriteCoord (MSG_BROADCAST, trace_endpos_y);
  637.         WriteCoord (MSG_BROADCAST, trace_endpos_z);
  638.  
  639.         LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  640. };
  641.  
  642.  
  643. //=============================================================================
  644.  
  645.  
  646. void() GrenadeExplode =
  647. {
  648.         T_RadiusDamage (self, self.owner, 120, world);
  649.  
  650.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  651.         WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  652.         WriteCoord (MSG_BROADCAST, self.origin_x);
  653.         WriteCoord (MSG_BROADCAST, self.origin_y);
  654.         WriteCoord (MSG_BROADCAST, self.origin_z);
  655.  
  656.         BecomeExplosion ();
  657. };
  658.  
  659. void() GrenadeTouch =
  660. {
  661.         if (other == self.owner)
  662.                 return;         // don't explode on owner
  663.         if (other.takedamage == DAMAGE_AIM)
  664.         {
  665.                 GrenadeExplode();
  666.                 return;
  667.         }
  668.         sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);  // bounce sound
  669.         if (self.velocity == '0 0 0')
  670.                 self.avelocity = '0 0 0';
  671. };
  672.  
  673. /*
  674. ================
  675. W_FireGrenade
  676. ================
  677. */
  678. void() W_FireGrenade =
  679. {
  680.         local   entity missile, mpuff;
  681.  
  682.         self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  683.  
  684.         sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  685.  
  686.         self.punchangle_x = -2;
  687.  
  688.         missile = spawn ();
  689.         missile.owner = self;
  690.         missile.movetype = MOVETYPE_BOUNCE;
  691.         missile.solid = SOLID_BBOX;
  692.         missile.classname = "grenade";
  693.  
  694. // set missile speed
  695.  
  696.         makevectors (self.v_angle);
  697.  
  698.         if (self.v_angle_x)
  699.                 missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  700.         else
  701.         {
  702.                 missile.velocity = aim(self, 10000);
  703.                 missile.velocity = missile.velocity * 600;
  704.                 missile.velocity_z = 200;
  705.         }
  706.  
  707.         missile.avelocity = '300 300 300';
  708.  
  709.         missile.angles = vectoangles(missile.velocity);
  710.  
  711.         missile.touch = GrenadeTouch;
  712.  
  713. // set missile duration
  714.         missile.nextthink = time + 2.5;
  715.         missile.think = GrenadeExplode;
  716.  
  717.         setmodel (missile, "progs/grenade.mdl");
  718.         setsize (missile, '0 0 0', '0 0 0');
  719.         setorigin (missile, self.origin);
  720. };
  721.  
  722.  
  723. //=============================================================================
  724. void() ProxGrenadeThink;
  725. void() ProxGrenadeTouch;
  726. void() ProxGrenadeDeploy;
  727. void() ProxW_FireGrenade;
  728.  
  729. /*
  730. =============
  731. ProxGrenadeThink
  732.  
  733. {JDS}
  734. For Proximity grenades, look for nearby targets and hop around.
  735. =============
  736. */
  737.  
  738. void() ProxGrenadeThink =
  739. {
  740.         local entity head;
  741.         local vector dir;
  742.         if(self.flags & FL_ONGROUND) {
  743.         // Don't detect targets if I'm not on the ground
  744.                 head = findradius(self.origin, 200);
  745.                 while(head) {
  746.                         if (head.takedamage) {
  747.                                 if (self.avelocity == '0 0 0')
  748.                                         self.avelocity = '300 300 300';
  749.                                 self.origin_z = self.origin_z + 1;
  750.                                 dir = normalize(head.origin - self.origin);
  751.                                 self.velocity = dir*200 + '0 0 500';
  752.                                 if (self.flags & FL_ONGROUND)
  753.                                         self.flags = self.flags - FL_ONGROUND;
  754.  
  755.                                 self.nextthink = time + random()*1.5;
  756.                                 self.think = GrenadeExplode;
  757.                                 return;
  758.                         }
  759.                         head = head.chain;
  760.                 }
  761.         }
  762.         self.nextthink = time + 0.5;
  763.         self.think = ProxGrenadeThink;
  764.         if(self.wait < time)
  765.         {
  766.                 // Time to jump.
  767.                 self.wait = time + 15 + 15*random();
  768.         if (self.avelocity == '0 0 0')
  769.                 self.avelocity = '300 300 300';
  770.         self.origin_z = self.origin_z + 1;
  771.         self.velocity_x=(random()*400 - 200);
  772.         self.velocity_y=(random()*400 - 200);
  773.         self.velocity_z = 500;
  774.         if (self.flags & FL_ONGROUND)
  775.                 self.flags = self.flags - FL_ONGROUND;
  776.  
  777.          }
  778. };
  779.  
  780. void() ProxGrenadeTouch =
  781. {
  782.         if (other == self.owner)
  783.                 return;         // don't explode on owner
  784.         if (other.takedamage == DAMAGE_AIM)
  785.         {
  786.     // {JDS}  Don't explode on contect with enemies.
  787.                 return;
  788.         }
  789.         sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);  // bounce sound
  790.         if (self.velocity == '0 0 0')
  791.                 self.avelocity = '0 0 0';
  792. };
  793.  
  794. /*
  795. ================
  796. ProxGrenadeDeploy
  797.  
  798. {JDS}
  799. Explode and spray out five new proximity grenades.
  800. ================
  801. */
  802. void() ProxGrenadeDeploy =
  803. {
  804.         local float gnum = 0;
  805.         local entity missile;
  806.  
  807.         while(gnum < 5) {
  808.                 missile = spawn ();
  809.                 missile.owner = self.owner;
  810.                 missile.movetype = MOVETYPE_BOUNCE;
  811.                 missile.solid = SOLID_BBOX;
  812.                 missile.classname = "grenade";
  813.                 missile.wait = time + 15 + 15*random();
  814.                 missile.think = ProxGrenadeThink;
  815.                 missile.nextthink = time + 0.5;
  816.                 missile.velocity_z = 500;
  817.                 missile.velocity_x = 400*random() - 200;
  818.                 missile.velocity_y = 400*random() - 200;
  819.                 gnum = gnum + 1;
  820.                 missile.avelocity = '300 300 300';
  821.                 missile.angles = vectoangles(missile.velocity);
  822.                 missile.touch = ProxGrenadeTouch;
  823.                 setmodel (missile, "progs/grenade.mdl");
  824.                 setsize (missile, '0 0 0', '0 0 0');
  825.                 setorigin (missile, self.origin);
  826.         }
  827.         self.think = GrenadeExplode;
  828.         self.nextthink = time + 0.1;
  829. };
  830.  
  831. /*
  832. ================
  833. ProxW_FireGrenade
  834. ================
  835. */
  836. void() ProxW_FireGrenade =
  837. {
  838.         local   entity missile, mpuff;
  839.  
  840.  
  841.         sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  842.  
  843.         self.punchangle_x = -2;
  844.  
  845.         missile = spawn ();
  846.         missile.owner = self;
  847.         missile.movetype = MOVETYPE_BOUNCE;
  848.         missile.solid = SOLID_BBOX;
  849.         missile.classname = "grenade";
  850.         missile.wait = time + 15 + 15*random();
  851.  
  852. // set missile speed
  853.  
  854.         makevectors (self.v_angle);
  855.  
  856.         if (self.v_angle_x)
  857.                 missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  858.         else
  859.         {
  860.                 missile.velocity = aim(self, 10000);
  861.                 missile.velocity = missile.velocity * 600;
  862.                 missile.velocity_z = 200;
  863.         }
  864.  
  865.         missile.avelocity = '300 300 300';
  866.  
  867.         missile.angles = vectoangles(missile.velocity);
  868.  
  869.         missile.touch = ProxGrenadeTouch;
  870.  
  871.         // If we have enough for a cluster, fire a cluster, otherwise
  872.         // fire a bouncer.
  873.         if (self.ammo_rockets > 4) {
  874.                 self.currentammo = self.ammo_rockets = self.ammo_rockets - 5;
  875.                 missile.nextthink = time + 2+(random()*3);
  876.                 missile.think = ProxGrenadeDeploy;
  877.         }
  878.         else {
  879.                 self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  880.                 missile.nextthink = time + 2+(random()*2);
  881.                 missile.think = ProxGrenadeThink;
  882.         }
  883.  
  884.         setmodel (missile, "progs/grenade.mdl");
  885.         setsize (missile, '0 0 0', '0 0 0');
  886.         setorigin (missile, self.origin);
  887. };
  888.  
  889.  
  890. //=============================================================================
  891.  
  892. void() spike_touch;
  893. void() superspike_touch;
  894.  
  895.  
  896. /*
  897. ===============
  898. launch_spike
  899.  
  900. Used for both the player and the ogre
  901. ===============
  902. */
  903. void(vector org, vector dir) launch_spike =
  904. {
  905.         newmis = spawn ();
  906.         newmis.owner = self;
  907.         newmis.movetype = MOVETYPE_FLYMISSILE;
  908.         newmis.solid = SOLID_BBOX;
  909.  
  910.         newmis.angles = vectoangles(dir);
  911.  
  912.         newmis.touch = spike_touch;
  913.         newmis.classname = "spike";
  914.         newmis.think = SUB_Remove;
  915.         newmis.nextthink = time + 6;
  916.         setmodel (newmis, "progs/spike.mdl");
  917.         setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  918.         setorigin (newmis, org);
  919.  
  920.         newmis.velocity = dir * 1000;
  921. };
  922.  
  923. void() W_FireSuperSpikes =
  924. {
  925.         local vector    dir;
  926.         local entity    old;
  927.  
  928.         sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  929.         self.attack_finished = time + 0.2;
  930.         self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  931.         dir = aim (self, 1000);
  932.         launch_spike (self.origin + '0 0 16', dir);
  933.         newmis.touch = superspike_touch;
  934.         setmodel (newmis, "progs/s_spike.mdl");
  935.         setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  936.         self.punchangle_x = -2;
  937. };
  938.  
  939. void(float ox) W_FireSpikes =
  940. {
  941.         local vector    dir;
  942.         local entity    old;
  943.  
  944.         makevectors (self.v_angle);
  945.  
  946.         if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  947.         {
  948.                 W_FireSuperSpikes ();
  949.                 return;
  950.         }
  951.  
  952.         if (self.ammo_nails < 1)
  953.         {
  954.                 self.weapon = W_BestWeapon ();
  955.                 W_SetCurrentAmmo ();
  956.                 return;
  957.         }
  958.  
  959.         sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  960.         self.attack_finished = time + 0.2;
  961.         self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  962.         dir = aim (self, 1000);
  963.         launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  964.  
  965.         self.punchangle_x = -2;
  966. };
  967.  
  968.  
  969.  
  970. .float hit_z;
  971. void() spike_touch =
  972. {
  973. local float rand;
  974.         if (other == self.owner)
  975.                 return;
  976.  
  977.         if (other.solid == SOLID_TRIGGER)
  978.                 return; // trigger field, do nothing
  979.  
  980.         if (pointcontents(self.origin) == CONTENT_SKY)
  981.         {
  982.                 remove(self);
  983.                 return;
  984.         }
  985.  
  986. // hit something that bleeds
  987.         if (other.takedamage)
  988.         {
  989.                 spawn_touchblood (9);
  990.                 T_Damage (other, self, self.owner, 9);
  991.         }
  992.         else
  993.         {
  994.                 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  995.  
  996.                 if (self.classname == "wizspike")
  997.                         WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  998.                 else if (self.classname == "knightspike")
  999.                         WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  1000.                 else
  1001.                         WriteByte (MSG_BROADCAST, TE_SPIKE);
  1002.                 WriteCoord (MSG_BROADCAST, self.origin_x);
  1003.                 WriteCoord (MSG_BROADCAST, self.origin_y);
  1004.                 WriteCoord (MSG_BROADCAST, self.origin_z);
  1005.         }
  1006.  
  1007.         remove(self);
  1008.  
  1009. };
  1010.  
  1011. void() superspike_touch =
  1012. {
  1013. local float rand;
  1014.         if (other == self.owner)
  1015.                 return;
  1016.  
  1017.         if (other.solid == SOLID_TRIGGER)
  1018.                 return; // trigger field, do nothing
  1019.  
  1020.         if (pointcontents(self.origin) == CONTENT_SKY)
  1021.         {
  1022.                 remove(self);
  1023.                 return;
  1024.         }
  1025.  
  1026. // hit something that bleeds
  1027.         if (other.takedamage)
  1028.         {
  1029.                 spawn_touchblood (18);
  1030.                 T_Damage (other, self, self.owner, 18);
  1031.         }
  1032.         else
  1033.         {
  1034.                 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1035.                 WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  1036.                 WriteCoord (MSG_BROADCAST, self.origin_x);
  1037.                 WriteCoord (MSG_BROADCAST, self.origin_y);
  1038.                 WriteCoord (MSG_BROADCAST, self.origin_z);
  1039.         }
  1040.  
  1041.         remove(self);
  1042.  
  1043. };
  1044.  
  1045. /*========================================================================
  1046. BOUNCING FRAGMENTATION GRENADE - Version .9
  1047. 7/28/96 - Steve Bond  email:wedge@nuc.net
  1048. http://www.nuc.net/quake
  1049. =======================================================================*/
  1050.  
  1051. //This code segment handles the impact of shrapnel
  1052. //this is merely id's superspike_touch code, reworked
  1053. void() shrapnel_touch =
  1054. {
  1055. local float rand;
  1056. // has the shrapnel hit a switch?
  1057.         if (other.solid == SOLID_TRIGGER)
  1058.                 return; // trigger field, do nothing
  1059.  
  1060. // has the shrapnel hit the sky?
  1061.         if (pointcontents(self.origin) == CONTENT_SKY)
  1062.         {
  1063.                 remove(self);
  1064.                 return;
  1065.         }
  1066.  
  1067. // has the shrapnel hit a living thing?
  1068.         if (other.takedamage)
  1069.         {
  1070.                 spawn_touchblood (33);
  1071.                 T_Damage (other, self, self.owner, 33);
  1072.         }
  1073.         else
  1074.         {
  1075.                 WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1076.                 WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  1077.                 WriteCoord (MSG_BROADCAST, self.origin_x);
  1078.                 WriteCoord (MSG_BROADCAST, self.origin_y);
  1079.                 WriteCoord (MSG_BROADCAST, self.origin_z);
  1080.         }
  1081.         remove(self);
  1082. };
  1083.  
  1084. /*
  1085. Code to spawn ONE randomly directed piece of shrapnel
  1086. this is id's launch_spike code, reworked
  1087. Pass a vector to this function to determine the shrap's origin
  1088. */
  1089. void (vector org, float spin) launch_shrapnel=
  1090. {
  1091.         local float xdir,ydir,zdir;
  1092.  
  1093. //Assign a random direction for the shrapnel to fly in
  1094.         xdir = 110 * random() - 55;
  1095.         ydir = 110 * random() - 55;
  1096.         zdir = 50 * random() - 25;
  1097.  
  1098.         newmis = spawn ();
  1099.         newmis.owner = self;
  1100.         newmis.movetype = MOVETYPE_BOUNCE;
  1101.         self.touch = SUB_Null;
  1102.         newmis.solid = SOLID_BBOX;
  1103.  
  1104.         newmis.touch = shrapnel_touch;
  1105.         newmis.classname = "spike";
  1106.         newmis.think = SUB_Remove;
  1107.  
  1108. // this is how many seconds(?) the nails can exist.
  1109.         newmis.nextthink = time + 6;
  1110.  
  1111. // speed at which to move the shrapnel
  1112.         newmis.velocity_x = xdir * 5;
  1113.         newmis.velocity_y = ydir * 5;
  1114.         newmis.velocity_z = zdir * 4;
  1115.  
  1116. /*
  1117. as best I can figure, AVELOCITY means "attitude velocity"
  1118. or something thereabouts. Anyway, it makes shit spin on
  1119. the x,y,z axes by the given velocity for each axis. In this
  1120. case, it makes the shrapnel spin in flight. Good stuff.
  1121. this segment assigns one of five preset attitudes for
  1122. each piece of shrapnel, based on the number passed to the
  1123. function.
  1124. */
  1125.         if (spin == 0)
  1126.         newmis.avelocity='250 300 400';
  1127.         if (spin == 1)
  1128.         newmis.avelocity='400 250 300';
  1129.         if (spin == 2)
  1130.         newmis.avelocity='300 400 250';
  1131.         if (spin == 3)
  1132.         newmis.avelocity='300 300 300';
  1133.         if (spin == 4)
  1134.         newmis.avelocity='400 250 400';
  1135.  
  1136.         setmodel (newmis, "progs/s_spike.mdl");
  1137.         setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
  1138.         setorigin (newmis, org);
  1139. };
  1140.  
  1141. // This code segment detonates the 'second stage' of the grenade
  1142. // (After it has popped up)
  1143. void()  BouncerExplode =
  1144. {
  1145.  
  1146. // Do the damage
  1147.         T_RadiusDamage (self, self.owner, 120, world);
  1148. // Tell the network
  1149.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  1150.         WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  1151.         WriteCoord (MSG_BROADCAST, self.origin_x);
  1152.         WriteCoord (MSG_BROADCAST, self.origin_y);
  1153.         WriteCoord (MSG_BROADCAST, self.origin_z);
  1154.  
  1155. // Let Quake handle the explosion and deallocation of the grenade
  1156.         self.solid=SOLID_NOT;
  1157.         BecomeExplosion ();
  1158.  
  1159. // Launch a hail (20 pieces) of shrapnel
  1160.         launch_shrapnel (self.origin + '0 0 -1',0);
  1161.         launch_shrapnel (self.origin + '0 0 -1',1);
  1162.         launch_shrapnel (self.origin + '0 0 -1',2);
  1163.         launch_shrapnel (self.origin + '0 0 -1',3);
  1164.         launch_shrapnel (self.origin + '0 0 -1',4);
  1165.         launch_shrapnel (self.origin + '0 0 -1',0);
  1166.         launch_shrapnel (self.origin + '0 0 -1',1);
  1167.         launch_shrapnel (self.origin + '0 0 -1',2);
  1168.         launch_shrapnel (self.origin + '0 0 -1',3);
  1169.         launch_shrapnel (self.origin + '0 0 -1',4);
  1170.         launch_shrapnel (self.origin + '0 0 -1',0);
  1171.         launch_shrapnel (self.origin + '0 0 -1',1);
  1172.         launch_shrapnel (self.origin + '0 0 -1',2);
  1173.         launch_shrapnel (self.origin + '0 0 -1',3);
  1174.         launch_shrapnel (self.origin + '0 0 -1',4);
  1175.         launch_shrapnel (self.origin + '0 0 -1',0);
  1176.         launch_shrapnel (self.origin + '0 0 -1',1);
  1177.         launch_shrapnel (self.origin + '0 0 -1',2);
  1178.         launch_shrapnel (self.origin + '0 0 -1',3);
  1179.         launch_shrapnel (self.origin + '0 0 -1',4);
  1180.         launch_shrapnel (self.origin + '0 0 -1',0);
  1181.         launch_shrapnel (self.origin + '0 0 -1',1);
  1182.         launch_shrapnel (self.origin + '0 0 -1',2);
  1183.         launch_shrapnel (self.origin + '0 0 -1',3);
  1184.         launch_shrapnel (self.origin + '0 0 -1',4);
  1185. };
  1186.  
  1187. /*
  1188. This code segment makes the 'first stage' of the bouncer pop upward
  1189. after it's time has expired.
  1190. */
  1191. void() BouncerPopUp=
  1192. {
  1193.         local entity missile, mpuff;
  1194.  
  1195. // Make the grenade stop
  1196.         self.movetype=MOVETYPE_NONE;
  1197.         self.velocity='0 0 0';
  1198. // Draw a tiny explosion (no particles)
  1199.         setmodel (self, "progs/s_explod.spr");
  1200.         s_explode1 ();
  1201. // Make the :FOOMP: grenade launcher sound
  1202.         sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  1203. // Spawn and animate the 'second stage'
  1204.         missile = spawn ();
  1205.         missile.owner = self;
  1206.         missile.movetype = MOVETYPE_BOUNCE;
  1207.         missile.solid = SOLID_BBOX;
  1208.         missile.classname = "grenade";
  1209. // Set speed
  1210.         missile.velocity = '0 0 650';
  1211.         missile.angles = vectoangles(missile.velocity);
  1212.         missile.touch = BouncerExplode;
  1213. // Set Duration
  1214.         missile.nextthink = time + 1;
  1215.         missile.think = BouncerExplode;
  1216.  
  1217.         setmodel (missile, "progs/missile.mdl");
  1218.         setsize (missile, '0 0 0', '0 0 0');
  1219.         setorigin (missile, self.origin);
  1220. };
  1221.  
  1222. // This code segment handles collisions for the 'first stage'
  1223. // Of the grenade (after launch and before popup)
  1224.  
  1225. void() BouncerTouch =
  1226. {
  1227. //Did the grenade hit a 'living' thing?
  1228.         if (other.takedamage)
  1229.         {
  1230. // yes, so play the bounce sound
  1231.         sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1232. // now, exit the function without cause damage to the thing
  1233.         return;
  1234.         }
  1235.  
  1236. // This controls what happens when the grenade hits walls, etz
  1237. // It just plays the sound and bounces on
  1238.         sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
  1239.         if (self.velocity == '0 0 0')
  1240.                 self.avelocity = '0 0 0';
  1241. };
  1242.  
  1243. /*
  1244. This code segment handles the launching of the Bouncing Fragmentation Grenade
  1245. this is a reworked copy of id's W_launchgrenade code
  1246. */
  1247. void() W_LaunchBouncer =
  1248. {
  1249. // If player doesn't have 3 or more rockets, don't launch
  1250.         if (self.ammo_rockets < 2)
  1251.         {
  1252.         return;
  1253.         }
  1254.  
  1255.         local   entity missile, mpuff;
  1256.  
  1257. // Take 2 rockets from the player
  1258.         self.currentammo = self.ammo_rockets = self.ammo_rockets - 2;
  1259.  
  1260.         //sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  1261. /*
  1262. self.punchangle_x (x, y, or z) defines how hard the weapon
  1263. recoils (or 'punches' the player, making the screen shake)
  1264. */
  1265.         self.punchangle_x = -2;
  1266.  
  1267. // This spawns the grenade - it is all id's standard grenade code
  1268.         missile = spawn ();
  1269.         missile.owner = self;
  1270.         missile.movetype = MOVETYPE_BOUNCE;
  1271.         missile.solid = SOLID_BBOX;
  1272.         missile.classname = "grenade";
  1273.  
  1274. // set missile speed
  1275.  
  1276.         makevectors (self.v_angle);
  1277.  
  1278.         if (self.v_angle_x)
  1279.                 missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  1280.         else
  1281.         {
  1282.                 missile.velocity = aim(self, 10000);
  1283.                 missile.velocity = missile.velocity * 600;
  1284.                 missile.velocity_z = 200;
  1285.         }
  1286.  
  1287.         missile.avelocity = '300 300 300';
  1288.  
  1289.         missile.angles = vectoangles(missile.velocity);
  1290.  
  1291. // if the grenade touches anything, BouncerTouch() is called
  1292.         missile.touch = BouncerTouch;
  1293.  
  1294. // Grenade has a maximum lifespan of 1.5 (seconds?)
  1295. // set missile duration
  1296.         missile.nextthink = time + 1.5;
  1297.  
  1298. // when the grenade's lifespan has expired, BouncerPopUp() is called
  1299.         missile.think = BouncerPopUp;
  1300.  
  1301.         setmodel (missile, "progs/grenade.mdl");
  1302.         setsize (missile, '0 0 0', '0 0 0');
  1303.         setorigin (missile, self.origin);
  1304. };
  1305. /*
  1306. ===============================================================================
  1307. End of Bouncing Fragmentation Grenade code.
  1308. ===============================================================================
  1309. */
  1310.  
  1311. // ------------------------------------------
  1312. // Pipe Bombs
  1313. // ------------------------------------------
  1314.  
  1315. //===========================================================================
  1316. // Blow up the toys.  There is a range of 1000 units (pixels?), so you can't
  1317. // go wandering off.
  1318. //===========================================================================
  1319. void() DetPipeBombs =
  1320. {
  1321.         local entity    head;
  1322.  
  1323.         head = findradius (self.origin, 1000);
  1324.         while(head)
  1325.         {
  1326.                 if((head.classname == "pipebomb") && (head.owner == self))
  1327.                         head.nextthink = time;
  1328.                 head = head.chain;
  1329.         }
  1330. };
  1331.  
  1332. //===========================================================================
  1333. // What happens if it touches something
  1334. //===========================================================================
  1335.  
  1336. void() PipeBombTouch =
  1337. {
  1338.         if (other == self.owner)
  1339.                 return;         // don't explode on owner
  1340.         sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);  // bounce sound
  1341.         if (self.velocity == '0 0 0')
  1342.                 self.avelocity = '0 0 0';
  1343. };
  1344.  
  1345. //===========================================================================
  1346. // Fires a pipe bomb.  Can be detonated at any time.  Doesn't need a special
  1347. // weapon selected.
  1348. //===========================================================================
  1349.  
  1350. void() W_FirePipeBomb =
  1351. {
  1352.         local   entity missile, mpuff;
  1353.  
  1354.         if(self.ammo_rockets < 1)       // have to have ammo
  1355.           return;
  1356.         self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  1357.  
  1358. //      sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  1359.  
  1360. //      self.punchangle_x = -2;
  1361.  
  1362.         missile = spawn ();
  1363.         missile.owner = self;
  1364.         missile.movetype = MOVETYPE_BOUNCE;
  1365.         missile.solid = SOLID_BBOX;
  1366.         missile.classname = "pipebomb";
  1367.  
  1368. // set missile speed
  1369.  
  1370.         makevectors (self.v_angle);
  1371.  
  1372.         if (self.v_angle_x)
  1373.                 missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  1374.         else
  1375.         {
  1376.                 missile.velocity = aim(self, 10000);
  1377.                 missile.velocity = missile.velocity * 600;
  1378.                 missile.velocity_z = 200;
  1379.         }
  1380.  
  1381.         missile.avelocity = '300 300 300';
  1382.  
  1383.         missile.angles = vectoangles(missile.velocity);
  1384.  
  1385.         missile.touch = PipeBombTouch;
  1386.         missile.think = GrenadeExplode;
  1387.  
  1388.         setmodel (missile, "progs/grenade.mdl");
  1389.         setsize (missile, '0 0 0', '0 0 0');
  1390.         setorigin (missile, self.origin);
  1391. };
  1392.  
  1393. /*
  1394. ===============================================================================
  1395.  
  1396. PLAYER WEAPON USE
  1397.  
  1398. ===============================================================================
  1399. */
  1400.  
  1401. void() W_SetCurrentAmmo =
  1402. {
  1403.         player_run ();          // get out of any weapon firing states
  1404.  
  1405.         self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  1406.  
  1407.         if (self.weapon == IT_AXE)
  1408.         {
  1409.                 self.currentammo = 0;
  1410.                 self.weaponmodel = "progs/v_axe.mdl";
  1411.                 self.weaponframe = 0;
  1412.         }
  1413.         else if (self.weapon == IT_SHOTGUN)
  1414.         {
  1415.                 self.currentammo = self.ammo_shells;
  1416.                 self.weaponmodel = "progs/v_shot.mdl";
  1417.                 self.weaponframe = 0;
  1418.                 self.items = self.items | IT_SHELLS;
  1419.         }
  1420.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1421.         {
  1422.                 self.currentammo = self.ammo_shells;
  1423.                 self.weaponmodel = "progs/v_shot2.mdl";
  1424.                 self.weaponframe = 0;
  1425.                 self.items = self.items | IT_SHELLS;
  1426.         }
  1427.         else if (self.weapon == IT_NAILGUN)
  1428.         {
  1429.                 self.currentammo = self.ammo_nails;
  1430.                 self.weaponmodel = "progs/v_nail.mdl";
  1431.                 self.weaponframe = 0;
  1432.                 self.items = self.items | IT_NAILS;
  1433.         }
  1434.         else if (self.weapon == IT_SUPER_NAILGUN)
  1435.         {
  1436.                 self.currentammo = self.ammo_nails;
  1437.                 self.weaponmodel = "progs/v_nail2.mdl";
  1438.                 self.weaponframe = 0;
  1439.                 self.items = self.items | IT_NAILS;
  1440.         }
  1441.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1442.         {
  1443.                 self.currentammo = self.ammo_rockets;
  1444.                 self.weaponmodel = "progs/v_rock.mdl";
  1445.                 self.weaponframe = 0;
  1446.                 self.items = self.items | IT_ROCKETS;
  1447.         }
  1448.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1449.         {
  1450.                 self.currentammo = self.ammo_rockets;
  1451.                 self.weaponmodel = "progs/v_rock2.mdl";
  1452.                 self.weaponframe = 0;
  1453.                 self.items = self.items | IT_ROCKETS;
  1454.         }
  1455.         else if (self.weapon == IT_LIGHTNING)
  1456.         {
  1457.                 self.currentammo = self.ammo_cells;
  1458.                 self.weaponmodel = "progs/v_light.mdl";
  1459.                 self.weaponframe = 0;
  1460.                 self.items = self.items | IT_CELLS;
  1461.         }
  1462.         else
  1463.         {
  1464.                 self.currentammo = 0;
  1465.                 self.weaponmodel = "";
  1466.                 self.weaponframe = 0;
  1467.         }
  1468. };
  1469.  
  1470. float() W_BestWeapon =
  1471. {
  1472.         local   float   it;
  1473.  
  1474.         it = self.items;
  1475.  
  1476.         if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  1477.                 return IT_LIGHTNING;
  1478.         else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  1479.                 return IT_SUPER_NAILGUN;
  1480.         else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  1481.                 return IT_SUPER_SHOTGUN;
  1482.         else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  1483.                 return IT_NAILGUN;
  1484.         else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  1485.                 return IT_SHOTGUN;
  1486.  
  1487. /*
  1488.         if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  1489.                 return IT_ROCKET_LAUNCHER;
  1490.         else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
  1491.                 return IT_GRENADE_LAUNCHER;
  1492.  
  1493. */
  1494.  
  1495.         return IT_AXE;
  1496. };
  1497.  
  1498. float() W_CheckNoAmmo =
  1499. {
  1500.         if (self.currentammo > 0)
  1501.                 return TRUE;
  1502.  
  1503.         if (self.weapon == IT_AXE)
  1504.                 return TRUE;
  1505.  
  1506.         self.weapon = W_BestWeapon ();
  1507.  
  1508.         W_SetCurrentAmmo ();
  1509.  
  1510. // drop the weapon down
  1511.         return FALSE;
  1512. };
  1513.  
  1514. /*
  1515. ============
  1516. W_Attack
  1517.  
  1518. An attack impulse can be triggered now
  1519. ============
  1520. */
  1521. void()  player_axe1;
  1522. void()  player_axeb1;
  1523. void()  player_axec1;
  1524. void()  player_axed1;
  1525. void()  player_shot1;
  1526. void()  player_nail1;
  1527. void()  player_light1;
  1528. void()  player_rocket1;
  1529.  
  1530. void() W_Attack =
  1531. {
  1532.         local   float   r;
  1533.  
  1534.         if (!W_CheckNoAmmo ())
  1535.                 return;
  1536.  
  1537.         makevectors     (self.v_angle);                 // calculate forward angle for velocity
  1538.         self.show_hostile = time + 1;   // wake monsters up
  1539.  
  1540.         if (self.weapon == IT_AXE)
  1541.         {
  1542.                 sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  1543.                 r = random();
  1544.                 if (r < 0.25)
  1545.                         player_axe1 ();
  1546.                 else if (r<0.5)
  1547.                         player_axeb1 ();
  1548.                 else if (r<0.75)
  1549.                         player_axec1 ();
  1550.                 else
  1551.                         player_axed1 ();
  1552.                 self.attack_finished = time + 0.5;
  1553.         }
  1554.         else if (self.weapon == IT_SHOTGUN)
  1555.         {
  1556.                 player_shot1 ();
  1557.                 W_FireShotgun ();
  1558.                 self.attack_finished = time + 0.75;
  1559.         }
  1560.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1561.         {
  1562.                 player_shot1 ();
  1563.                 W_FireSuperShotgun ();
  1564.                 self.attack_finished = time + 0.7;
  1565.         }
  1566.         else if (self.weapon == IT_NAILGUN)
  1567.         {
  1568.                 player_nail1 ();
  1569.         }
  1570.         else if (self.weapon == IT_SUPER_NAILGUN)
  1571.         {
  1572.                 player_nail1 ();
  1573.         }
  1574.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1575.         {
  1576.                 player_rocket1();
  1577.                 W_FireGrenade();
  1578.                 self.attack_finished = time + 0.6;
  1579.         }
  1580.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1581.         {
  1582.                 player_rocket1();
  1583.                 W_FireRocket();
  1584.                 self.attack_finished = time + 0.8;
  1585.         }
  1586.         else if (self.weapon == IT_LIGHTNING)
  1587.         {
  1588.                 player_light1();
  1589.                 self.attack_finished = time + 0.1;
  1590.                 sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  1591.         }
  1592. };
  1593.  
  1594. /*
  1595. ============
  1596. W_ChangeWeapon
  1597.  
  1598. ============
  1599. */
  1600. void() W_ChangeWeapon =
  1601. {
  1602.         local   float   it, am, fl;
  1603.  
  1604.         it = self.items;
  1605.         am = 0;
  1606.  
  1607.         if (self.impulse == 1)
  1608.         {
  1609.                 fl = IT_AXE;
  1610.         }
  1611.         else if (self.impulse == 2)
  1612.         {
  1613.                 fl = IT_SHOTGUN;
  1614.                 if (self.ammo_shells < 1)
  1615.                         am = 1;
  1616.         }
  1617.         else if (self.impulse == 3)
  1618.         {
  1619.                 fl = IT_SUPER_SHOTGUN;
  1620.                 if (self.ammo_shells < 2)
  1621.                         am = 1;
  1622.         }
  1623.         else if (self.impulse == 4)
  1624.         {
  1625.                 fl = IT_NAILGUN;
  1626.                 if (self.ammo_nails < 1)
  1627.                         am = 1;
  1628.         }
  1629.         else if (self.impulse == 5)
  1630.         {
  1631.                 fl = IT_SUPER_NAILGUN;
  1632.                 if (self.ammo_nails < 2)
  1633.                         am = 1;
  1634.         }
  1635.         else if (self.impulse == 6)
  1636.         {
  1637.                 fl = IT_GRENADE_LAUNCHER;
  1638.                 if (self.ammo_rockets < 1)
  1639.                         am = 1;
  1640.         }
  1641.         else if (self.impulse == 7)
  1642.         {
  1643.                 fl = IT_ROCKET_LAUNCHER;
  1644.                 if (self.ammo_rockets < 1)
  1645.                         am = 1;
  1646.         }
  1647.         else if (self.impulse == 8)
  1648.         {
  1649.                 fl = IT_LIGHTNING;
  1650.                 if (self.ammo_cells < 1)
  1651.                         am = 1;
  1652.         }
  1653.  
  1654.         self.impulse = 0;
  1655.  
  1656.         if (!(self.items & fl))
  1657.         {       // don't have the weapon or the ammo
  1658.                 sprint (self, "no weapon.\n");
  1659.                 return;
  1660.         }
  1661.  
  1662.         if (am)
  1663.         {       // don't have the ammo
  1664.                 sprint (self, "not enough ammo.\n");
  1665.                 return;
  1666.         }
  1667.  
  1668. //
  1669. // set weapon, set ammo
  1670. //
  1671.         self.weapon = fl;
  1672.         W_SetCurrentAmmo ();
  1673. };
  1674.  
  1675. /*
  1676. ============
  1677. CheatCommand
  1678. ============
  1679. */
  1680. void() CheatCommand =
  1681. {
  1682.         if (deathmatch || coop)
  1683.                 return;
  1684.  
  1685.         self.ammo_rockets = 100;
  1686.         self.ammo_nails = 200;
  1687.         self.ammo_shells = 100;
  1688.         self.items = self.items |
  1689.                 IT_AXE |
  1690.                 IT_SHOTGUN |
  1691.                 IT_SUPER_SHOTGUN |
  1692.                 IT_NAILGUN |
  1693.                 IT_SUPER_NAILGUN |
  1694.                 IT_GRENADE_LAUNCHER |
  1695.                 IT_ROCKET_LAUNCHER |
  1696.                 IT_KEY1 | IT_KEY2;
  1697.  
  1698.         self.ammo_cells = 200;
  1699.         self.items = self.items | IT_LIGHTNING;
  1700.  
  1701.         self.weapon = IT_ROCKET_LAUNCHER;
  1702.         self.impulse = 0;
  1703.         W_SetCurrentAmmo ();
  1704. };
  1705.  
  1706. /*
  1707. ============
  1708. CycleWeaponCommand
  1709.  
  1710. Go to the next weapon with ammo
  1711. ============
  1712. */
  1713. void() CycleWeaponCommand =
  1714. {
  1715.         local   float   it, am;
  1716.  
  1717.         it = self.items;
  1718.         self.impulse = 0;
  1719.  
  1720.         while (1)
  1721.         {
  1722.                 am = 0;
  1723.  
  1724.                 if (self.weapon == IT_LIGHTNING)
  1725.                 {
  1726.                         self.weapon = IT_AXE;
  1727.                 }
  1728.                 else if (self.weapon == IT_AXE)
  1729.                 {
  1730.                         self.weapon = IT_SHOTGUN;
  1731.                         if (self.ammo_shells < 1)
  1732.                                 am = 1;
  1733.                 }
  1734.                 else if (self.weapon == IT_SHOTGUN)
  1735.                 {
  1736.                         self.weapon = IT_SUPER_SHOTGUN;
  1737.                         if (self.ammo_shells < 2)
  1738.                                 am = 1;
  1739.                 }
  1740.                 else if (self.weapon == IT_SUPER_SHOTGUN)
  1741.                 {
  1742.                         self.weapon = IT_NAILGUN;
  1743.                         if (self.ammo_nails < 1)
  1744.                                 am = 1;
  1745.                 }
  1746.                 else if (self.weapon == IT_NAILGUN)
  1747.                 {
  1748.                         self.weapon = IT_SUPER_NAILGUN;
  1749.                         if (self.ammo_nails < 2)
  1750.                                 am = 1;
  1751.                 }
  1752.                 else if (self.weapon == IT_SUPER_NAILGUN)
  1753.                 {
  1754.                         self.weapon = IT_GRENADE_LAUNCHER;
  1755.                         if (self.ammo_rockets < 1)
  1756.                                 am = 1;
  1757.                 }
  1758.                 else if (self.weapon == IT_GRENADE_LAUNCHER)
  1759.                 {
  1760.                         self.weapon = IT_ROCKET_LAUNCHER;
  1761.                         if (self.ammo_rockets < 1)
  1762.                                 am = 1;
  1763.                 }
  1764.                 else if (self.weapon == IT_ROCKET_LAUNCHER)
  1765.                 {
  1766.                         self.weapon = IT_LIGHTNING;
  1767.                         if (self.ammo_cells < 1)
  1768.                                 am = 1;
  1769.                 }
  1770.  
  1771.                 if ( (self.items & self.weapon) && am == 0)
  1772.                 {
  1773.                         W_SetCurrentAmmo ();
  1774.                         return;
  1775.                 }
  1776.         }
  1777.  
  1778. };
  1779.  
  1780. /*
  1781. ============
  1782. ServerflagsCommand
  1783.  
  1784. Just for development
  1785. ============
  1786. */
  1787. void() ServerflagsCommand =
  1788. {
  1789.         serverflags = serverflags * 2 + 1;
  1790. };
  1791.  
  1792. void() QuadCheat =
  1793. {
  1794.         if (deathmatch || coop)
  1795.                 return;
  1796.         self.super_time = 1;
  1797.         self.super_damage_finished = time + 30;
  1798.         self.items = self.items | IT_QUAD;
  1799.         dprint ("quad cheat\n");
  1800. };
  1801.  
  1802. /*
  1803. ============
  1804. ImpulseCommands
  1805.  
  1806. ============
  1807. */
  1808. void() ImpulseCommands =
  1809. {
  1810.         if (self.impulse >= 1 && self.impulse <= 8)
  1811.                 W_ChangeWeapon ();
  1812.  
  1813.         if (self.impulse == 9)
  1814.                 CheatCommand ();
  1815.         if (self.impulse == 10)
  1816.                 CycleWeaponCommand ();
  1817.         if (self.impulse == 11)
  1818.                 ServerflagsCommand ();
  1819.  
  1820.         if (self.impulse == 20 )  // Frag Grenade ===
  1821.           W_LaunchBouncer();
  1822.  
  1823.         if (self.impulse == 21 )  // Proximity Grenade ===
  1824.           ProxW_FireGrenade();
  1825.  
  1826.         if(self.impulse == 22)    // Pipe Bombs ===
  1827.           W_FirePipeBomb();
  1828.         if(self.impulse == 23)
  1829.           DetPipeBombs();
  1830.  
  1831.         if (self.impulse == 255)
  1832.                 QuadCheat ();
  1833.  
  1834.         self.impulse = 0;
  1835. };
  1836.  
  1837. /*
  1838. ============
  1839. W_WeaponFrame
  1840.  
  1841. Called every frame so impulse events can be handled as well as possible
  1842. ============
  1843. */
  1844. void() W_WeaponFrame =
  1845. {
  1846.         if (time < self.attack_finished)
  1847.                 return;
  1848.  
  1849.         ImpulseCommands ();
  1850.  
  1851. // check for attack
  1852.         if (self.button0)
  1853.         {
  1854.                 SuperDamageSound ();
  1855.                 W_Attack ();
  1856.         }
  1857. };
  1858.  
  1859. /*
  1860. ========
  1861. SuperDamageSound
  1862.  
  1863. Plays sound if needed
  1864. ========
  1865. */
  1866. void() SuperDamageSound =
  1867. {
  1868.         if (self.super_damage_finished > time)
  1869.         {
  1870.                 if (self.super_sound < time)
  1871.                 {
  1872.                         self.super_sound = time + 1;
  1873.                         sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1874.                 }
  1875.         }
  1876.         return;
  1877. };
  1878.  
  1879.  
  1880.