home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / jsqcmod1 / weapons.qc < prev   
Encoding:
Text File  |  1996-07-30  |  29.9 KB  |  1,359 lines

  1. /*
  2.     weapons.qc
  3.  
  4.     Mods:
  5.         Electro-Axe
  6.         Cluster-Bouncy-Proximity Grenades (Now with quick deployment!)
  7.  
  8.     Detail:
  9.         * Electro-Axe -- The axe will now do 50 damage (instead of 20) when
  10.         an enemy is hit and you have cells.  5 cells will be used.  If you
  11.         have no cells, you'll do the normal amount of damage.  Also added a
  12.         nice *SMACK* sound (borrowed from the zombies) for when the axe hits
  13.         flesh.
  14.         * Cluster-Bouncy-Proximity Grenades  -- Grenades are now bouncy
  15.         proximity mines.  A grenade will lay on the floor and hop at
  16.         intervals.  If a target is detected within range, the grenade will
  17.         hop towards the target and explode.  Grenades won't detect targets
  18.         while they're in the air.  When the grenade launcher is fired, if you
  19.         have less than five ammo you will fire a single grenade which
  20.         will behave as described above.  If you have 5 or more ammo, you'll
  21.         fire a cluster bomb which will explode and release five proximity
  22.         grenades.
  23.  
  24.         Mods by
  25.                 John Spickes jspickes@eng.umd.edu {JDS}
  26.                 Josh Spickes spickesj@wam.umd.edu
  27.                 Allen Seger
  28. */
  29. void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
  30. void () player_run;
  31. void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
  32. void(vector org, vector vel, float damage) SpawnBlood;
  33. void() SuperDamageSound;
  34.  
  35.  
  36. // called by worldspawn
  37. void() W_Precache =
  38. {
  39.         precache_sound ("zombie/z_miss.wav");  // axe splat        
  40.     precache_sound ("weapons/r_exp3.wav");    // new rocket explosion
  41.     precache_sound ("weapons/rocket1i.wav");    // spike gun
  42.     precache_sound ("weapons/sgun1.wav");
  43.     precache_sound ("weapons/guncock.wav");    // player shotgun
  44.     precache_sound ("weapons/ric1.wav");    // ricochet (used in c code)
  45.     precache_sound ("weapons/ric2.wav");    // ricochet (used in c code)
  46.     precache_sound ("weapons/ric3.wav");    // ricochet (used in c code)
  47.     precache_sound ("weapons/spike2.wav");    // super spikes
  48.     precache_sound ("weapons/tink1.wav");    // spikes tink (used in c code)
  49.     precache_sound ("weapons/grenade.wav");    // grenade launcher
  50.     precache_sound ("weapons/bounce.wav");        // grenade bounce
  51.     precache_sound ("weapons/shotgn2.wav");    // super shotgun
  52. };
  53.  
  54. float() crandom =
  55. {
  56.     return 2*(random() - 0.5);
  57. };
  58.  
  59. /*
  60. ================
  61. W_FireAxe
  62. ================
  63. */
  64. void() W_FireAxe =
  65. {
  66.     local    vector    source;
  67.     local    vector    org;
  68.  
  69.         source = self.origin + '0 0 16';
  70.     traceline (source, source + v_forward*64, FALSE, self);
  71.     if (trace_fraction == 1.0)
  72.         return;
  73.     
  74.     org = trace_endpos - v_forward*4;
  75.  
  76.     if (trace_ent.takedamage)
  77.     {
  78.         trace_ent.axhitme = 1;
  79.         SpawnBlood (org, '0 0 0', 20);
  80.                 // {JDS} Play the *SMACK* sound
  81.                 sound (self, CHAN_WEAPON, "zombie/z_miss.wav", 1, ATTN_NORM);
  82.                 if (self.ammo_cells > 0)
  83.                 {
  84.                         // If you have cells, do bonus damage and use some cells.
  85.                         self.currentammo = self.ammo_cells = self.ammo_cells - 5;
  86.                         T_Damage (trace_ent, self, self, 50);
  87.                 }
  88.                 else
  89.                 {
  90.                         T_Damage (trace_ent, self, self, 20);
  91.                 }
  92.  
  93.     }
  94.     else
  95.     {    // hit wall
  96.         sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  97.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  98.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  99.         WriteCoord (MSG_BROADCAST, org_x);
  100.         WriteCoord (MSG_BROADCAST, org_y);
  101.         WriteCoord (MSG_BROADCAST, org_z);
  102.     }
  103. };
  104.  
  105.  
  106. //============================================================================
  107.  
  108.  
  109. vector() wall_velocity =
  110. {
  111.     local vector    vel;
  112.     
  113.     vel = normalize (self.velocity);
  114.     vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  115.     vel = vel + 2*trace_plane_normal;
  116.     vel = vel * 200;
  117.     
  118.     return vel;
  119. };
  120.  
  121.  
  122. /*
  123. ================
  124. SpawnMeatSpray
  125. ================
  126. */
  127. void(vector org, vector vel) SpawnMeatSpray =
  128. {
  129.     local    entity missile, mpuff;
  130.     local    vector    org;
  131.  
  132.     missile = spawn ();
  133.     missile.owner = self;
  134.     missile.movetype = MOVETYPE_BOUNCE;
  135.     missile.solid = SOLID_NOT;
  136.  
  137.     makevectors (self.angles);
  138.  
  139.     missile.velocity = vel;
  140.     missile.velocity_z = missile.velocity_z + 250 + 50*random();
  141.  
  142.     missile.avelocity = '3000 1000 2000';
  143.     
  144. // set missile duration
  145.     missile.nextthink = time + 1;
  146.     missile.think = SUB_Remove;
  147.  
  148.     setmodel (missile, "progs/zom_gib.mdl");
  149.     setsize (missile, '0 0 0', '0 0 0');        
  150.     setorigin (missile, org);
  151. };
  152.  
  153. /*
  154. ================
  155. SpawnBlood
  156. ================
  157. */
  158. void(vector org, vector vel, float damage) SpawnBlood =
  159. {
  160.     particle (org, vel*0.1, 73, damage*2);
  161. };
  162.  
  163. /*
  164. ================
  165. spawn_touchblood
  166. ================
  167. */
  168. void(float damage) spawn_touchblood =
  169. {
  170.     local vector    vel;
  171.  
  172.     vel = wall_velocity () * 0.2;
  173.     SpawnBlood (self.origin + vel*0.01, vel, damage);
  174. };
  175.  
  176.  
  177. /*
  178. ================
  179. SpawnChunk
  180. ================
  181. */
  182. void(vector org, vector vel) SpawnChunk =
  183. {
  184.     particle (org, vel*0.02, 0, 10);
  185. };
  186.  
  187. /*
  188. ==============================================================================
  189.  
  190. MULTI-DAMAGE
  191.  
  192. Collects multiple small damages into a single damage
  193.  
  194. ==============================================================================
  195. */
  196.  
  197. entity    multi_ent;
  198. float    multi_damage;
  199.  
  200. void() ClearMultiDamage =
  201. {
  202.     multi_ent = world;
  203.     multi_damage = 0;
  204. };
  205.  
  206. void() ApplyMultiDamage =
  207. {
  208.     if (!multi_ent)
  209.         return;
  210.     T_Damage (multi_ent, self, self, multi_damage);
  211. };
  212.  
  213. void(entity hit, float damage) AddMultiDamage =
  214. {
  215.     if (!hit)
  216.         return;
  217.     
  218.     if (hit != multi_ent)
  219.     {
  220.         ApplyMultiDamage ();
  221.         multi_damage = damage;
  222.         multi_ent = hit;
  223.     }
  224.     else
  225.         multi_damage = multi_damage + damage;
  226. };
  227.  
  228. /*
  229. ==============================================================================
  230.  
  231. BULLETS
  232.  
  233. ==============================================================================
  234. */
  235.  
  236. /*
  237. ================
  238. TraceAttack
  239. ================
  240. */
  241. void(float damage, vector dir) TraceAttack =
  242. {
  243.     local    vector    vel, org;
  244.     
  245.     vel = normalize(dir + v_up*crandom() + v_right*crandom());
  246.     vel = vel + 2*trace_plane_normal;
  247.     vel = vel * 200;
  248.  
  249.     org = trace_endpos - dir*4;
  250.  
  251.     if (trace_ent.takedamage)
  252.     {
  253.         SpawnBlood (org, vel*0.2, damage);
  254.         AddMultiDamage (trace_ent, damage);
  255.     }
  256.     else
  257.     {
  258.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  259.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  260.         WriteCoord (MSG_BROADCAST, org_x);
  261.         WriteCoord (MSG_BROADCAST, org_y);
  262.         WriteCoord (MSG_BROADCAST, org_z);
  263.     }
  264. };
  265.  
  266. /*
  267. ================
  268. FireBullets
  269.  
  270. Used by shotgun, super shotgun, and enemy soldier firing
  271. Go to the trouble of combining multiple pellets into a single damage call.
  272. ================
  273. */
  274. void(float shotcount, vector dir, vector spread) FireBullets =
  275. {
  276.     local    vector direction;
  277.     local    vector    src;
  278.     
  279.     makevectors(self.v_angle);
  280.  
  281.     src = self.origin + v_forward*10;
  282.     src_z = self.absmin_z + self.size_z * 0.7;
  283.  
  284.     ClearMultiDamage ();
  285.     while (shotcount > 0)
  286.     {
  287.         direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  288.  
  289.         traceline (src, src + direction*2048, FALSE, self);
  290.         if (trace_fraction != 1.0)
  291.             TraceAttack (4, direction);
  292.  
  293.         shotcount = shotcount - 1;
  294.     }
  295.     ApplyMultiDamage ();
  296. };
  297.  
  298. /*
  299. ================
  300. W_FireShotgun
  301. ================
  302. */
  303. void() W_FireShotgun =
  304. {
  305.     local vector dir;
  306.  
  307.     sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);    
  308.  
  309.     self.punchangle_x = -2;
  310.     
  311.     self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  312.     dir = aim (self, 100000);
  313.     FireBullets (6, dir, '0.04 0.04 0');
  314. };
  315.  
  316.  
  317. /*
  318. ================
  319. W_FireSuperShotgun
  320. ================
  321. */
  322. void() W_FireSuperShotgun =
  323. {
  324.     local vector dir;
  325.  
  326.     if (self.currentammo == 1)
  327.     {
  328.         W_FireShotgun ();
  329.         return;
  330.     }
  331.         
  332.     sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);    
  333.  
  334.     self.punchangle_x = -4;
  335.     
  336.         self.currentammo = self.ammo_shells = self.ammo_shells - 6;
  337.     dir = aim (self, 100000);
  338.         FireBullets (14, dir, '0.14 0.08 0');
  339. };
  340.  
  341.  
  342. /*
  343. ==============================================================================
  344.  
  345. ROCKETS
  346.  
  347. ==============================================================================
  348. */
  349.  
  350. void()    s_explode1    =    [0,        s_explode2] {};
  351. void()    s_explode2    =    [1,        s_explode3] {};
  352. void()    s_explode3    =    [2,        s_explode4] {};
  353. void()    s_explode4    =    [3,        s_explode5] {};
  354. void()    s_explode5    =    [4,        s_explode6] {};
  355. void()    s_explode6    =    [5,        SUB_Remove] {};
  356.  
  357. void() BecomeExplosion =
  358. {
  359.     self.movetype = MOVETYPE_NONE;
  360.     self.velocity = '0 0 0';
  361.     self.touch = SUB_Null;
  362.     setmodel (self, "progs/s_explod.spr");
  363.     self.solid = SOLID_NOT;
  364.     s_explode1 ();
  365. };
  366.  
  367. void() T_MissileTouch =
  368. {
  369.     local float    damg;
  370.  
  371.     if (other == self.owner)
  372.         return;        // don't explode on owner
  373.  
  374.     if (pointcontents(self.origin) == CONTENT_SKY)
  375.     {
  376.         remove(self);
  377.         return;
  378.     }
  379.  
  380.     damg = 100 + random()*20;
  381.     
  382.     if (other.health)
  383.     {
  384.         if (other.classname == "monster_shambler")
  385.             damg = damg * 0.5;    // mostly immune
  386.         T_Damage (other, self, self.owner, damg );
  387.     }
  388.  
  389.     // don't do radius damage to the other, because all the damage
  390.     // was done in the impact
  391.     T_RadiusDamage (self, self.owner, 120, other);
  392.  
  393. //    sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  394.     self.origin = self.origin - 8*normalize(self.velocity);
  395.  
  396.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  397.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  398.     WriteCoord (MSG_BROADCAST, self.origin_x);
  399.     WriteCoord (MSG_BROADCAST, self.origin_y);
  400.     WriteCoord (MSG_BROADCAST, self.origin_z);
  401.  
  402.     BecomeExplosion ();
  403. };
  404.  
  405.  
  406.  
  407. /*
  408. ================
  409. W_FireRocket
  410. ================
  411. */
  412. void() W_FireRocket =
  413. {
  414.     local    entity missile, mpuff;
  415.     
  416.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  417.     
  418.     sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  419.  
  420.     self.punchangle_x = -2;
  421.  
  422.     missile = spawn ();
  423.     missile.owner = self;
  424.     missile.movetype = MOVETYPE_FLYMISSILE;
  425.     missile.solid = SOLID_BBOX;
  426.         
  427. // set missile speed    
  428.  
  429.     makevectors (self.v_angle);
  430.     missile.velocity = aim(self, 1000);
  431.     missile.velocity = missile.velocity * 1000;
  432.     missile.angles = vectoangles(missile.velocity);
  433.     
  434.     missile.touch = T_MissileTouch;
  435.     
  436. // set missile duration
  437.     missile.nextthink = time + 5;
  438.     missile.think = SUB_Remove;
  439.  
  440.     setmodel (missile, "progs/missile.mdl");
  441.     setsize (missile, '0 0 0', '0 0 0');        
  442.     setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  443. };
  444.  
  445. /*
  446. ===============================================================================
  447.  
  448. LIGHTNING
  449.  
  450. ===============================================================================
  451. */
  452.  
  453. /*
  454. =================
  455. LightningDamage
  456. =================
  457. */
  458. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  459. {
  460.     local entity        e1, e2;
  461.     local vector        f;
  462.     
  463.     f = p2 - p1;
  464.     normalize (f);
  465.     f_x = 0 - f_y;
  466.     f_y = f_x;
  467.     f_z = 0;
  468.     f = f*16;
  469.  
  470.     e1 = e2 = world;
  471.  
  472.     traceline (p1, p2, FALSE, self);
  473.     if (trace_ent.takedamage)
  474.     {
  475.         particle (trace_endpos, '0 0 100', 225, damage*4);
  476.         T_Damage (trace_ent, from, from, damage);
  477.         if (self.classname == "player")
  478.         {
  479.             if (other.classname == "player")
  480.                 trace_ent.velocity_z = trace_ent.velocity_z + 400;
  481.         }
  482.     }
  483.     e1 = trace_ent;
  484.  
  485.     traceline (p1 + f, p2 + f, FALSE, self);
  486.     if (trace_ent != e1 && trace_ent.takedamage)
  487.     {
  488.         particle (trace_endpos, '0 0 100', 225, damage*4);
  489.         T_Damage (trace_ent, from, from, damage);
  490.     }
  491.     e2 = trace_ent;
  492.  
  493.     traceline (p1 - f, p2 - f, FALSE, self);
  494.     if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  495.     {
  496.         particle (trace_endpos, '0 0 100', 225, damage*4);
  497.         T_Damage (trace_ent, from, from, damage);
  498.     }
  499. };
  500.  
  501.  
  502. void() W_FireLightning =
  503. {
  504.     local    vector        org;
  505.  
  506.     if (self.ammo_cells < 1)
  507.     {
  508.         self.weapon = W_BestWeapon ();
  509.         W_SetCurrentAmmo ();
  510.         return;
  511.     }
  512.  
  513. // explode if under water
  514.     if (self.waterlevel > 1)
  515.     {
  516.         T_RadiusDamage (self, self, 35*self.ammo_cells, world);
  517.         self.ammo_cells = 0;
  518.         W_SetCurrentAmmo ();
  519.         return;
  520.     }
  521.  
  522.     if (self.t_width < time)
  523.     {
  524.         sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  525.         self.t_width = time + 0.6;
  526.     }
  527.     self.punchangle_x = -2;
  528.  
  529.     self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  530.  
  531.     org = self.origin + '0 0 16';
  532.     
  533.     traceline (org, org + v_forward*600, TRUE, self);
  534.  
  535.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  536.     WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  537.     WriteEntity (MSG_BROADCAST, self);
  538.     WriteCoord (MSG_BROADCAST, org_x);
  539.     WriteCoord (MSG_BROADCAST, org_y);
  540.     WriteCoord (MSG_BROADCAST, org_z);
  541.     WriteCoord (MSG_BROADCAST, trace_endpos_x);
  542.     WriteCoord (MSG_BROADCAST, trace_endpos_y);
  543.     WriteCoord (MSG_BROADCAST, trace_endpos_z);
  544.  
  545.     LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  546. };
  547.  
  548.  
  549. //=============================================================================
  550.  
  551.  
  552. void() GrenadeExplode =
  553. {
  554.     T_RadiusDamage (self, self.owner, 120, world);
  555.  
  556.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  557.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  558.     WriteCoord (MSG_BROADCAST, self.origin_x);
  559.     WriteCoord (MSG_BROADCAST, self.origin_y);
  560.     WriteCoord (MSG_BROADCAST, self.origin_z);
  561.  
  562.     BecomeExplosion ();
  563. };
  564.  
  565. /*
  566. =============
  567. GrenadeThink
  568.  
  569. {JDS}
  570. For Proximity grenades, look for nearby targets and hop around.
  571. =============
  572. */
  573.  
  574. void() GrenadeThink =
  575. {
  576.         local entity head;
  577.         local vector dir;
  578.         if(self.flags & FL_ONGROUND) {
  579.         // Don't detect targets if I'm not on the ground
  580.                 head = findradius(self.origin, 200);
  581.                 while(head) {
  582.                         if (head.takedamage) {
  583.                                 if (self.avelocity == '0 0 0')
  584.                                         self.avelocity = '300 300 300';
  585.                                 self.origin_z = self.origin_z + 1;
  586.                                 dir = normalize(head.origin - self.origin);
  587.                                 self.velocity = dir*200 + '0 0 500';
  588.                                 if (self.flags & FL_ONGROUND)
  589.                                         self.flags = self.flags - FL_ONGROUND;
  590.  
  591.                                 self.nextthink = time + random()*1.5;
  592.                                 self.think = GrenadeExplode;
  593.                                 return;
  594.                         }
  595.                         head = head.chain;
  596.                 }
  597.         }
  598.         self.nextthink = time + 0.5;
  599.         self.think = GrenadeThink;
  600.         if(self.wait < time)
  601.         {
  602.                 // Time to jump.
  603.                 self.wait = time + 15 + 15*random();
  604.         if (self.avelocity == '0 0 0')
  605.                 self.avelocity = '300 300 300';
  606.     self.origin_z = self.origin_z + 1;
  607.         self.velocity_x=(random()*400 - 200);
  608.         self.velocity_y=(random()*400 - 200);
  609.         self.velocity_z = 500;
  610.         if (self.flags & FL_ONGROUND)
  611.                 self.flags = self.flags - FL_ONGROUND;
  612.  
  613.          }
  614. };
  615.  
  616. void() GrenadeTouch =
  617. {
  618.     if (other == self.owner)
  619.         return;        // don't explode on owner
  620.     if (other.takedamage == DAMAGE_AIM)
  621.     {
  622.                 // {JDS}  Don't explode on contect with enemies.
  623.                 // GrenadeExplode();
  624.         return;
  625.     }
  626.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  627.     if (self.velocity == '0 0 0')
  628.         self.avelocity = '0 0 0';
  629. };
  630.  
  631. /*
  632. ================
  633. GrenadeDeploy
  634.  
  635. {JDS}
  636. Explode and spray out five new proximity grenades.
  637. ================
  638. */
  639. void() GrenadeDeploy =
  640. {
  641.         local float gnum = 0;
  642.         local entity missile;
  643.  
  644.         while(gnum < 5) {
  645.                 missile = spawn ();
  646.                 missile.owner = self.owner;
  647.                 missile.movetype = MOVETYPE_BOUNCE;
  648.                 missile.solid = SOLID_BBOX;
  649.                 missile.classname = "grenade";
  650.                 missile.wait = time + 15 + 15*random();
  651.                 missile.think = GrenadeThink;
  652.                 missile.nextthink = time + 0.5;
  653.                 missile.velocity_z = 500;
  654.                 missile.velocity_x = 400*random() - 200;
  655.                 missile.velocity_y = 400*random() - 200;
  656.                 gnum = gnum + 1;
  657.                 missile.avelocity = '300 300 300';
  658.                 missile.angles = vectoangles(missile.velocity);
  659.                 missile.touch = GrenadeTouch;
  660.                 setmodel (missile, "progs/grenade.mdl");
  661.                 setsize (missile, '0 0 0', '0 0 0');     
  662.                 setorigin (missile, self.origin);
  663.         }
  664.         self.think = GrenadeExplode;
  665.         self.nextthink = time + 0.1;
  666. };
  667.  
  668. /*
  669. ================
  670. W_FireGrenade
  671. ================
  672. */
  673. void() W_FireGrenade =
  674. {
  675.     local    entity missile, mpuff;
  676.  
  677.     
  678.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  679.  
  680.     self.punchangle_x = -2;
  681.  
  682.     missile = spawn ();
  683.     missile.owner = self;
  684.     missile.movetype = MOVETYPE_BOUNCE;
  685.     missile.solid = SOLID_BBOX;
  686.     missile.classname = "grenade";
  687.         missile.wait = time + 15 + 15*random();
  688.         
  689. // set missile speed    
  690.  
  691.     makevectors (self.v_angle);
  692.  
  693.     if (self.v_angle_x)
  694.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  695.     else
  696.     {
  697.         missile.velocity = aim(self, 10000);
  698.         missile.velocity = missile.velocity * 600;
  699.         missile.velocity_z = 200;
  700.     }
  701.  
  702.     missile.avelocity = '300 300 300';
  703.  
  704.     missile.angles = vectoangles(missile.velocity);
  705.     
  706.     missile.touch = GrenadeTouch;
  707.  
  708.         // If we have enough for a cluster, fire a cluster, otherwise
  709.         // fire a bouncer.
  710.         if (self.ammo_rockets > 4) {
  711.                 self.currentammo = self.ammo_rockets = self.ammo_rockets - 5;
  712.                 missile.nextthink = time + 2+(random()*3);
  713.                 missile.think = GrenadeDeploy;
  714.         }
  715.         else {
  716.                 self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  717.                 missile.nextthink = time + 2+(random()*2);
  718.                 missile.think = GrenadeThink;
  719.         }
  720.  
  721.     setmodel (missile, "progs/grenade.mdl");
  722.     setsize (missile, '0 0 0', '0 0 0');        
  723.     setorigin (missile, self.origin);
  724. };
  725.  
  726.  
  727. //=============================================================================
  728.  
  729. void() spike_touch;
  730. void() superspike_touch;
  731.  
  732.  
  733. /*
  734. ===============
  735. launch_spike
  736.  
  737. Used for both the player and the ogre
  738. ===============
  739. */
  740. void(vector org, vector dir) launch_spike =
  741. {
  742.     newmis = spawn ();
  743.     newmis.owner = self;
  744.     newmis.movetype = MOVETYPE_FLYMISSILE;
  745.     newmis.solid = SOLID_BBOX;
  746.  
  747.     newmis.angles = vectoangles(dir);
  748.     
  749.     newmis.touch = spike_touch;
  750.     newmis.classname = "spike";
  751.     newmis.think = SUB_Remove;
  752.     newmis.nextthink = time + 6;
  753.     setmodel (newmis, "progs/spike.mdl");
  754.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  755.     setorigin (newmis, org);
  756.  
  757.     newmis.velocity = dir * 1000;
  758. };
  759.  
  760. void() W_FireSuperSpikes =
  761. {
  762.     local vector    dir;
  763.     local entity    old;
  764.     
  765.     sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  766.     self.attack_finished = time + 0.2;
  767.     self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  768.     dir = aim (self, 1000);
  769.     launch_spike (self.origin + '0 0 16', dir);
  770.     newmis.touch = superspike_touch;
  771.     setmodel (newmis, "progs/s_spike.mdl");
  772.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  773.     self.punchangle_x = -2;
  774. };
  775.  
  776. void(float ox) W_FireSpikes =
  777. {
  778.     local vector    dir;
  779.     local entity    old;
  780.     
  781.     makevectors (self.v_angle);
  782.     
  783.     if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  784.     {
  785.         W_FireSuperSpikes ();
  786.         return;
  787.     }
  788.  
  789.     if (self.ammo_nails < 1)
  790.     {
  791.         self.weapon = W_BestWeapon ();
  792.         W_SetCurrentAmmo ();
  793.         return;
  794.     }
  795.  
  796.     sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  797.     self.attack_finished = time + 0.2;
  798.     self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  799.     dir = aim (self, 1000);
  800.     launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  801.  
  802.     self.punchangle_x = -2;
  803. };
  804.  
  805.  
  806.  
  807. .float hit_z;
  808. void() spike_touch =
  809. {
  810. local float rand;
  811.     if (other == self.owner)
  812.         return;
  813.  
  814.     if (other.solid == SOLID_TRIGGER)
  815.         return;    // trigger field, do nothing
  816.  
  817.     if (pointcontents(self.origin) == CONTENT_SKY)
  818.     {
  819.         remove(self);
  820.         return;
  821.     }
  822.     
  823. // hit something that bleeds
  824.     if (other.takedamage)
  825.     {
  826.         spawn_touchblood (9);
  827.         T_Damage (other, self, self.owner, 9);
  828.     }
  829.     else
  830.     {
  831.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  832.         
  833.         if (self.classname == "wizspike")
  834.             WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  835.         else if (self.classname == "knightspike")
  836.             WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  837.         else
  838.             WriteByte (MSG_BROADCAST, TE_SPIKE);
  839.         WriteCoord (MSG_BROADCAST, self.origin_x);
  840.         WriteCoord (MSG_BROADCAST, self.origin_y);
  841.         WriteCoord (MSG_BROADCAST, self.origin_z);
  842.     }
  843.  
  844.     remove(self);
  845.  
  846. };
  847.  
  848. void() superspike_touch =
  849. {
  850. local float rand;
  851.     if (other == self.owner)
  852.         return;
  853.  
  854.     if (other.solid == SOLID_TRIGGER)
  855.         return;    // trigger field, do nothing
  856.  
  857.     if (pointcontents(self.origin) == CONTENT_SKY)
  858.     {
  859.         remove(self);
  860.         return;
  861.     }
  862.     
  863. // hit something that bleeds
  864.     if (other.takedamage)
  865.     {
  866.         spawn_touchblood (18);
  867.         T_Damage (other, self, self.owner, 18);
  868.     }
  869.     else
  870.     {
  871.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  872.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  873.         WriteCoord (MSG_BROADCAST, self.origin_x);
  874.         WriteCoord (MSG_BROADCAST, self.origin_y);
  875.         WriteCoord (MSG_BROADCAST, self.origin_z);
  876.     }
  877.  
  878.     remove(self);
  879.  
  880. };
  881.  
  882.  
  883. /*
  884. ===============================================================================
  885.  
  886. PLAYER WEAPON USE
  887.  
  888. ===============================================================================
  889. */
  890.  
  891. void() W_SetCurrentAmmo =
  892. {
  893.     player_run ();        // get out of any weapon firing states
  894.  
  895.     self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  896.     
  897.     if (self.weapon == IT_AXE)
  898.     {
  899.         self.currentammo = 0;
  900.         self.weaponmodel = "progs/v_axe.mdl";
  901.         self.weaponframe = 0;
  902.     }
  903.     else if (self.weapon == IT_SHOTGUN)
  904.     {
  905.         self.currentammo = self.ammo_shells;
  906.         self.weaponmodel = "progs/v_shot.mdl";
  907.         self.weaponframe = 0;
  908.         self.items = self.items | IT_SHELLS;
  909.     }
  910.     else if (self.weapon == IT_SUPER_SHOTGUN)
  911.     {
  912.         self.currentammo = self.ammo_shells;
  913.         self.weaponmodel = "progs/v_shot2.mdl";
  914.         self.weaponframe = 0;
  915.         self.items = self.items | IT_SHELLS;
  916.     }
  917.     else if (self.weapon == IT_NAILGUN)
  918.     {
  919.         self.currentammo = self.ammo_nails;
  920.         self.weaponmodel = "progs/v_nail.mdl";
  921.         self.weaponframe = 0;
  922.         self.items = self.items | IT_NAILS;
  923.     }
  924.     else if (self.weapon == IT_SUPER_NAILGUN)
  925.     {
  926.         self.currentammo = self.ammo_nails;
  927.         self.weaponmodel = "progs/v_nail2.mdl";
  928.         self.weaponframe = 0;
  929.         self.items = self.items | IT_NAILS;
  930.     }
  931.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  932.     {
  933.         self.currentammo = self.ammo_rockets;
  934.         self.weaponmodel = "progs/v_rock.mdl";
  935.         self.weaponframe = 0;
  936.         self.items = self.items | IT_ROCKETS;
  937.     }
  938.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  939.     {
  940.         self.currentammo = self.ammo_rockets;
  941.         self.weaponmodel = "progs/v_rock2.mdl";
  942.         self.weaponframe = 0;
  943.         self.items = self.items | IT_ROCKETS;
  944.     }
  945.     else if (self.weapon == IT_LIGHTNING)
  946.     {
  947.         self.currentammo = self.ammo_cells;
  948.         self.weaponmodel = "progs/v_light.mdl";
  949.         self.weaponframe = 0;
  950.         self.items = self.items | IT_CELLS;
  951.     }
  952.     else
  953.     {
  954.         self.currentammo = 0;
  955.         self.weaponmodel = "";
  956.         self.weaponframe = 0;
  957.     }
  958. };
  959.  
  960. float() W_BestWeapon =
  961. {
  962.     local    float    it;
  963.     
  964.     it = self.items;
  965.  
  966.     if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  967.         return IT_LIGHTNING;
  968.     else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  969.         return IT_SUPER_NAILGUN;
  970.     else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  971.         return IT_SUPER_SHOTGUN;
  972.     else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  973.         return IT_NAILGUN;
  974.     else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  975.         return IT_SHOTGUN;
  976.         
  977. /*
  978.     if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
  979.         return IT_ROCKET_LAUNCHER;
  980.     else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
  981.         return IT_GRENADE_LAUNCHER;
  982.  
  983. */
  984.  
  985.     return IT_AXE;
  986. };
  987.  
  988. float() W_CheckNoAmmo =
  989. {
  990.     if (self.currentammo > 0)
  991.         return TRUE;
  992.  
  993.     if (self.weapon == IT_AXE)
  994.         return TRUE;
  995.     
  996.     self.weapon = W_BestWeapon ();
  997.  
  998.     W_SetCurrentAmmo ();
  999.     
  1000. // drop the weapon down
  1001.     return FALSE;
  1002. };
  1003.  
  1004. /*
  1005. ============
  1006. W_Attack
  1007.  
  1008. An attack impulse can be triggered now
  1009. ============
  1010. */
  1011. void()    player_axe1;
  1012. void()    player_axeb1;
  1013. void()    player_axec1;
  1014. void()    player_axed1;
  1015. void()    player_shot1;
  1016. void()    player_nail1;
  1017. void()    player_light1;
  1018. void()    player_rocket1;
  1019.  
  1020. void() W_Attack =
  1021. {
  1022.     local    float    r;
  1023.  
  1024.     if (!W_CheckNoAmmo ())
  1025.         return;
  1026.  
  1027.     makevectors    (self.v_angle);            // calculate forward angle for velocity
  1028.     self.show_hostile = time + 1;    // wake monsters up
  1029.  
  1030.     if (self.weapon == IT_AXE)
  1031.     {
  1032.         sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  1033.         r = random();
  1034.         if (r < 0.25)
  1035.             player_axe1 ();
  1036.         else if (r<0.5)
  1037.             player_axeb1 ();
  1038.         else if (r<0.75)
  1039.             player_axec1 ();
  1040.         else
  1041.             player_axed1 ();
  1042.         self.attack_finished = time + 0.5;
  1043.     }
  1044.     else if (self.weapon == IT_SHOTGUN)
  1045.     {
  1046.         player_shot1 ();
  1047.         W_FireShotgun ();
  1048.         self.attack_finished = time + 0.5;
  1049.     }
  1050.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1051.     {
  1052.         player_shot1 ();
  1053.         W_FireSuperShotgun ();
  1054.         self.attack_finished = time + 0.7;
  1055.     }
  1056.     else if (self.weapon == IT_NAILGUN)
  1057.     {
  1058.         player_nail1 ();
  1059.     }
  1060.     else if (self.weapon == IT_SUPER_NAILGUN)
  1061.     {
  1062.         player_nail1 ();
  1063.     }
  1064.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1065.     {
  1066.         player_rocket1();
  1067.         W_FireGrenade();
  1068.         self.attack_finished = time + 0.6;
  1069.     }
  1070.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1071.     {
  1072.         player_rocket1();
  1073.         W_FireRocket();
  1074.         self.attack_finished = time + 0.8;
  1075.     }
  1076.     else if (self.weapon == IT_LIGHTNING)
  1077.     {
  1078.         player_light1();
  1079.         self.attack_finished = time + 0.1;
  1080.         sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  1081.     }
  1082. };
  1083.  
  1084. /*
  1085. ============
  1086. W_ChangeWeapon
  1087.  
  1088. ============
  1089. */
  1090. void() W_ChangeWeapon =
  1091. {
  1092.     local    float    it, am, fl;
  1093.     
  1094.     it = self.items;
  1095.     am = 0;
  1096.     
  1097.     if (self.impulse == 1)
  1098.     {
  1099.         fl = IT_AXE;
  1100.     }
  1101.     else if (self.impulse == 2)
  1102.     {
  1103.         fl = IT_SHOTGUN;
  1104.         if (self.ammo_shells < 1)
  1105.             am = 1;
  1106.     }
  1107.     else if (self.impulse == 3)
  1108.     {
  1109.         fl = IT_SUPER_SHOTGUN;
  1110.         if (self.ammo_shells < 2)
  1111.             am = 1;
  1112.     }        
  1113.     else if (self.impulse == 4)
  1114.     {
  1115.         fl = IT_NAILGUN;
  1116.         if (self.ammo_nails < 1)
  1117.             am = 1;
  1118.     }
  1119.     else if (self.impulse == 5)
  1120.     {
  1121.         fl = IT_SUPER_NAILGUN;
  1122.         if (self.ammo_nails < 2)
  1123.             am = 1;
  1124.     }
  1125.     else if (self.impulse == 6)
  1126.     {
  1127.         fl = IT_GRENADE_LAUNCHER;
  1128.         if (self.ammo_rockets < 1)
  1129.             am = 1;
  1130.     }
  1131.     else if (self.impulse == 7)
  1132.     {
  1133.         fl = IT_ROCKET_LAUNCHER;
  1134.         if (self.ammo_rockets < 1)
  1135.             am = 1;
  1136.     }
  1137.     else if (self.impulse == 8)
  1138.     {
  1139.         fl = IT_LIGHTNING;
  1140.         if (self.ammo_cells < 1)
  1141.             am = 1;
  1142.     }
  1143.  
  1144.     self.impulse = 0;
  1145.     
  1146.     if (!(self.items & fl))
  1147.     {    // don't have the weapon or the ammo
  1148.         sprint (self, "no weapon.\n");
  1149.         return;
  1150.     }
  1151.     
  1152.     if (am)
  1153.     {    // don't have the ammo
  1154.         sprint (self, "not enough ammo.\n");
  1155.         return;
  1156.     }
  1157.  
  1158. //
  1159. // set weapon, set ammo
  1160. //
  1161.     self.weapon = fl;        
  1162.     W_SetCurrentAmmo ();
  1163. };
  1164.  
  1165. /*
  1166. ============
  1167. CheatCommand
  1168. ============
  1169. */
  1170. void() CheatCommand =
  1171. {
  1172.     if (deathmatch || coop)
  1173.         return;
  1174.  
  1175.     self.ammo_rockets = 100;
  1176.     self.ammo_nails = 200;
  1177.     self.ammo_shells = 100;
  1178.     self.items = self.items | 
  1179.         IT_AXE |
  1180.         IT_SHOTGUN |
  1181.         IT_SUPER_SHOTGUN |
  1182.         IT_NAILGUN |
  1183.         IT_SUPER_NAILGUN |
  1184.         IT_GRENADE_LAUNCHER |
  1185.         IT_ROCKET_LAUNCHER |
  1186.         IT_KEY1 | IT_KEY2;
  1187.  
  1188.     self.ammo_cells = 200;
  1189.     self.items = self.items | IT_LIGHTNING;
  1190.  
  1191.     self.weapon = IT_ROCKET_LAUNCHER;
  1192.     self.impulse = 0;
  1193.     W_SetCurrentAmmo ();
  1194. };
  1195.  
  1196. /*
  1197. ============
  1198. CycleWeaponCommand
  1199.  
  1200. Go to the next weapon with ammo
  1201. ============
  1202. */
  1203. void() CycleWeaponCommand =
  1204. {
  1205.     local    float    it, am;
  1206.     
  1207.     it = self.items;
  1208.     self.impulse = 0;
  1209.     
  1210.     while (1)
  1211.     {
  1212.         am = 0;
  1213.  
  1214.         if (self.weapon == IT_LIGHTNING)
  1215.         {
  1216.             self.weapon = IT_AXE;
  1217.         }
  1218.         else if (self.weapon == IT_AXE)
  1219.         {
  1220.             self.weapon = IT_SHOTGUN;
  1221.             if (self.ammo_shells < 1)
  1222.                 am = 1;
  1223.         }
  1224.         else if (self.weapon == IT_SHOTGUN)
  1225.         {
  1226.             self.weapon = IT_SUPER_SHOTGUN;
  1227.             if (self.ammo_shells < 2)
  1228.                 am = 1;
  1229.         }        
  1230.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1231.         {
  1232.             self.weapon = IT_NAILGUN;
  1233.             if (self.ammo_nails < 1)
  1234.                 am = 1;
  1235.         }
  1236.         else if (self.weapon == IT_NAILGUN)
  1237.         {
  1238.             self.weapon = IT_SUPER_NAILGUN;
  1239.             if (self.ammo_nails < 2)
  1240.                 am = 1;
  1241.         }
  1242.         else if (self.weapon == IT_SUPER_NAILGUN)
  1243.         {
  1244.             self.weapon = IT_GRENADE_LAUNCHER;
  1245.             if (self.ammo_rockets < 1)
  1246.                 am = 1;
  1247.         }
  1248.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1249.         {
  1250.             self.weapon = IT_ROCKET_LAUNCHER;
  1251.             if (self.ammo_rockets < 1)
  1252.                 am = 1;
  1253.         }
  1254.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1255.         {
  1256.             self.weapon = IT_LIGHTNING;
  1257.             if (self.ammo_cells < 1)
  1258.                 am = 1;
  1259.         }
  1260.     
  1261.         if ( (self.items & self.weapon) && am == 0)
  1262.         {
  1263.             W_SetCurrentAmmo ();
  1264.             return;
  1265.         }
  1266.     }
  1267.  
  1268. };
  1269.  
  1270. /*
  1271. ============
  1272. ServerflagsCommand
  1273.  
  1274. Just for development
  1275. ============
  1276. */
  1277. void() ServerflagsCommand =
  1278. {
  1279.     serverflags = serverflags * 2 + 1;
  1280. };
  1281.  
  1282. void() QuadCheat =
  1283. {
  1284.     if (deathmatch || coop)
  1285.         return;
  1286.     self.super_time = 1;
  1287.     self.super_damage_finished = time + 30;
  1288.     self.items = self.items | IT_QUAD;
  1289.     dprint ("quad cheat\n");
  1290. };
  1291.  
  1292. /*
  1293. ============
  1294. ImpulseCommands
  1295.  
  1296. ============
  1297. */
  1298. void() ImpulseCommands =
  1299. {
  1300.     if (self.impulse >= 1 && self.impulse <= 8)
  1301.         W_ChangeWeapon ();
  1302.  
  1303.     if (self.impulse == 9)
  1304.         CheatCommand ();
  1305.     if (self.impulse == 10)
  1306.         CycleWeaponCommand ();
  1307.     if (self.impulse == 11)
  1308.         ServerflagsCommand ();
  1309.  
  1310.     if (self.impulse == 255)
  1311.         QuadCheat ();
  1312.         
  1313.     self.impulse = 0;
  1314. };
  1315.  
  1316. /*
  1317. ============
  1318. W_WeaponFrame
  1319.  
  1320. Called every frame so impulse events can be handled as well as possible
  1321. ============
  1322. */
  1323. void() W_WeaponFrame =
  1324. {
  1325.     if (time < self.attack_finished)
  1326.         return;
  1327.  
  1328.     ImpulseCommands ();
  1329.     
  1330. // check for attack
  1331.     if (self.button0)
  1332.     {
  1333.         SuperDamageSound ();
  1334.         W_Attack ();
  1335.     }
  1336. };
  1337.  
  1338. /*
  1339. ========
  1340. SuperDamageSound
  1341.  
  1342. Plays sound if needed
  1343. ========
  1344. */
  1345. void() SuperDamageSound =
  1346. {
  1347.     if (self.super_damage_finished > time)
  1348.     {
  1349.         if (self.super_sound < time)
  1350.         {
  1351.             self.super_sound = time + 1;
  1352.             sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1353.         }
  1354.     }
  1355.     return;
  1356. };
  1357.  
  1358.  
  1359.