home *** CD-ROM | disk | FTP | other *** search
/ Quake 'em / QUAKEEM.BIN / quake / programs / qplus10 / weapons.qc < prev    next >
Encoding:
Text File  |  1996-08-18  |  29.2 KB  |  1,427 lines

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