home *** CD-ROM | disk | FTP | other *** search
/ PC Gamer 3.2 / 1997-05_Disc_3.2.iso / QUAKECTF / SRC / CTF / WEAPONS.QC < prev    next >
Text File  |  1997-01-30  |  34KB  |  1,685 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. void() HasteSound;
  9.  
  10. // called by worldspawn
  11. void() W_Precache =
  12. {
  13.     precache_sound ("hknight/hit.wav");  // flamethrower
  14.  
  15.     precache_sound ("weapons/r_exp3.wav");    // new rocket explosion
  16.     precache_sound ("weapons/rocket1i.wav");    // spike gun
  17.     precache_sound ("weapons/sgun1.wav");
  18.     precache_sound ("weapons/guncock.wav");    // player shotgun
  19.     precache_sound ("weapons/ric1.wav");    // ricochet (used in c code)
  20.     precache_sound ("weapons/ric2.wav");    // ricochet (used in c code)
  21.     precache_sound ("weapons/ric3.wav");    // ricochet (used in c code)
  22.     precache_sound ("weapons/spike2.wav");    // super spikes
  23.     precache_sound ("weapons/tink1.wav");    // spikes tink (used in c code)
  24.     precache_sound ("weapons/grenade.wav");    // grenade launcher
  25.     precache_sound ("weapons/bounce.wav");        // grenade bounce
  26.     precache_sound ("weapons/shotgn2.wav");    // super shotgun
  27.  
  28.     precache_sound2 ("blob/land1.wav");     // chain go splorch!
  29.     if (cvar("teamplay") & TEAM_CAPTURE_CUSTOM) {
  30.         precache_sound ("weapons/chain1.wav");
  31.         precache_sound ("weapons/chain2.wav");
  32.         precache_sound ("weapons/chain3.wav");
  33.         precache_sound ("weapons/bounce2.wav");
  34.     }
  35.  
  36.     // ZOID:
  37.     // normally the weapon models are precached in the individual item
  38.     // creation routines.  But since we've added impulse 21 we can drop
  39.     // weapons at any time.  Must precache all weapon models.
  40.     precache_model ("progs/g_shot.mdl");
  41.     precache_model ("progs/g_nail.mdl");
  42.     precache_model ("progs/g_nail2.mdl");
  43.     precache_model ("progs/g_rock.mdl");
  44.     precache_model ("progs/g_rock2.mdl");
  45.     precache_model ("progs/g_light.mdl");
  46. };
  47.  
  48. float() crandom =
  49. {
  50.     return 2*(random() - 0.5);
  51. };
  52.  
  53. /*
  54. ================
  55. W_FireAxe
  56. ================
  57. */
  58. void() W_FireAxe =
  59. {
  60.     local    vector    source;
  61.     local    vector    org;
  62.  
  63.     makevectors (self.v_angle);
  64.     source = self.origin + '0 0 16';
  65.     traceline (source, source + v_forward*64, FALSE, self);
  66.     if (trace_fraction == 1.0)
  67.         return;
  68.     
  69.     org = trace_endpos - v_forward*4;
  70.  
  71.     if (trace_ent.takedamage)
  72.     {
  73.         trace_ent.axhitme = 1;
  74.         SpawnBlood (org, '0 0 0', 20);
  75.         T_Damage (trace_ent, self, self, 20);
  76.     }
  77.     else
  78.     {    // hit wall
  79.         sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
  80.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  81.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  82.         WriteCoord (MSG_BROADCAST, org_x);
  83.         WriteCoord (MSG_BROADCAST, org_y);
  84.         WriteCoord (MSG_BROADCAST, org_z);
  85.     }
  86. };
  87.  
  88.  
  89. //============================================================================
  90.  
  91.  
  92. vector() wall_velocity =
  93. {
  94.     local vector    vel;
  95.     
  96.     vel = normalize (self.velocity);
  97.     vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
  98.     vel = vel + 2*trace_plane_normal;
  99.     vel = vel * 200;
  100.     
  101.     return vel;
  102. };
  103.  
  104.  
  105. /*
  106. ================
  107. SpawnMeatSpray
  108. ================
  109. */
  110. void(vector org, vector vel) SpawnMeatSpray =
  111. {
  112.     local    entity missile, mpuff;
  113.     local    vector    org;
  114.  
  115.     missile = spawn ();
  116.     missile.owner = self;
  117.     missile.movetype = MOVETYPE_BOUNCE;
  118.     missile.solid = SOLID_NOT;
  119.  
  120.     makevectors (self.angles);
  121.  
  122.     missile.velocity = vel;
  123.     missile.velocity_z = missile.velocity_z + 250 + 50*random();
  124.  
  125.     missile.avelocity = '3000 1000 2000';
  126.     
  127. // set missile duration
  128.     missile.nextthink = time + 1;
  129.     missile.think = SUB_Remove;
  130.  
  131.     setmodel (missile, "progs/zom_gib.mdl");
  132.     setsize (missile, '0 0 0', '0 0 0');        
  133.     setorigin (missile, org);
  134. };
  135.  
  136. /*
  137. ================
  138. SpawnBlood
  139. ================
  140. */
  141. void(vector org, vector vel, float damage) SpawnBlood =
  142. {
  143.     particle (org, vel*0.1, 73, damage*2);
  144. };
  145.  
  146. /*
  147. ================
  148. spawn_touchblood
  149. ================
  150. */
  151. void(float damage) spawn_touchblood =
  152. {
  153.     local vector    vel;
  154.  
  155.     vel = wall_velocity () * 0.2;
  156.     SpawnBlood (self.origin + vel*0.01, vel, damage);
  157. };
  158.  
  159.  
  160. /*
  161. ================
  162. SpawnChunk
  163. ================
  164. */
  165. void(vector org, vector vel) SpawnChunk =
  166. {
  167.     particle (org, vel*0.02, 0, 10);
  168. };
  169.  
  170. /*
  171. ==============================================================================
  172.  
  173. MULTI-DAMAGE
  174.  
  175. Collects multiple small damages into a single damage
  176.  
  177. ==============================================================================
  178. */
  179.  
  180. entity    multi_ent;
  181. float    multi_damage;
  182.  
  183. void() ClearMultiDamage =
  184. {
  185.     multi_ent = world;
  186.     multi_damage = 0;
  187. };
  188.  
  189. void() ApplyMultiDamage =
  190. {
  191.     if (!multi_ent)
  192.         return;
  193.     T_Damage (multi_ent, self, self, multi_damage);
  194. };
  195.  
  196. void(entity hit, float damage) AddMultiDamage =
  197. {
  198.     if (!hit)
  199.         return;
  200.     
  201.     if (hit != multi_ent)
  202.     {
  203.         ApplyMultiDamage ();
  204.         multi_damage = damage;
  205.         multi_ent = hit;
  206.     }
  207.     else
  208.         multi_damage = multi_damage + damage;
  209. };
  210.  
  211. /*
  212. ==============================================================================
  213.  
  214. BULLETS
  215.  
  216. ==============================================================================
  217. */
  218.  
  219. /*
  220. ================
  221. TraceAttack
  222. ================
  223. */
  224. void(float damage, vector dir) TraceAttack =
  225. {
  226.     local    vector    vel, org;
  227.     
  228.     vel = normalize(dir + v_up*crandom() + v_right*crandom());
  229.     vel = vel + 2*trace_plane_normal;
  230.     vel = vel * 200;
  231.  
  232.     org = trace_endpos - dir*4;
  233.  
  234.     if (trace_ent.takedamage)
  235.     {
  236.         SpawnBlood (org, vel*0.2, damage);
  237.         AddMultiDamage (trace_ent, damage);
  238.     }
  239.     else
  240.     {
  241.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  242.         WriteByte (MSG_BROADCAST, TE_GUNSHOT);
  243.         WriteCoord (MSG_BROADCAST, org_x);
  244.         WriteCoord (MSG_BROADCAST, org_y);
  245.         WriteCoord (MSG_BROADCAST, org_z);
  246.     }
  247. };
  248.  
  249. /*
  250. ================
  251. FireBullets
  252.  
  253. Used by shotgun, super shotgun, and enemy soldier firing
  254. Go to the trouble of combining multiple pellets into a single damage call.
  255. ================
  256. */
  257. void(float shotcount, vector dir, vector spread) FireBullets =
  258. {
  259.     local    vector direction;
  260.     local    vector    src;
  261.     
  262.     makevectors(self.v_angle);
  263.  
  264.     src = self.origin + v_forward*10;
  265.     src_z = self.absmin_z + self.size_z * 0.7;
  266.  
  267.     ClearMultiDamage ();
  268.     while (shotcount > 0)
  269.     {
  270.         direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
  271.  
  272.         traceline (src, src + direction*2048, FALSE, self);
  273.         if (trace_fraction != 1.0)
  274.             TraceAttack (4, direction);
  275.  
  276.         shotcount = shotcount - 1;
  277.     }
  278.     ApplyMultiDamage ();
  279. };
  280.  
  281. /*
  282. ================
  283. W_FireShotgun
  284. ================
  285. */
  286. void() W_FireShotgun =
  287. {
  288.     local vector dir;
  289.  
  290.     sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);    
  291.  
  292.     self.punchangle_x = -2;
  293.     
  294.     self.currentammo = self.ammo_shells = self.ammo_shells - 1;
  295.     
  296.     if (self.classname == "player")        // CTFBOT
  297.         dir = aim (self, 100000);
  298.     else if (self.classname == "bot")    // CTFBOT
  299.         dir = self.bot_aim;    // CTFBOT
  300.  
  301.     FireBullets (6, dir, '0.04 0.04 0');
  302. };
  303.  
  304.  
  305. /*
  306. ================
  307. W_FireSuperShotgun
  308. ================
  309. */
  310. void() W_FireSuperShotgun =
  311. {
  312.     local vector dir;
  313.  
  314.     if (self.currentammo == 1)
  315.     {
  316.         W_FireShotgun ();
  317.         return;
  318.     }
  319.         
  320.     sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);    
  321.  
  322.     self.punchangle_x = -4;
  323.     
  324.     self.currentammo = self.ammo_shells = self.ammo_shells - 2;
  325.  
  326.     if (self.classname == "player")        // CTFBOT
  327.         dir = aim (self, 100000);
  328.     else if (self.classname == "bot")    // CTFBOT
  329.         dir = self.bot_aim;        // CTFBOT
  330.  
  331.     FireBullets (14, dir, '0.14 0.08 0');
  332. };
  333.  
  334.  
  335. /*
  336. ==============================================================================
  337.  
  338. ROCKETS
  339.  
  340. ==============================================================================
  341. */
  342.  
  343. void()    s_explode1    =    [0,        s_explode2] {};
  344. void()    s_explode2    =    [1,        s_explode3] {};
  345. void()    s_explode3    =    [2,        s_explode4] {};
  346. void()    s_explode4    =    [3,        s_explode5] {};
  347. void()    s_explode5    =    [4,        s_explode6] {};
  348. void()    s_explode6    =    [5,        SUB_Remove] {};
  349.  
  350. void() BecomeExplosion =
  351. {
  352.     self.movetype = MOVETYPE_NONE;
  353.     self.velocity = '0 0 0';
  354.     self.touch = SUB_Null;
  355.     setmodel (self, "progs/s_explod.spr");
  356.     self.solid = SOLID_NOT;
  357.     s_explode1 ();
  358. };
  359.  
  360. void() T_MissileTouch =
  361. {
  362.     local float    damg;
  363.  
  364.     if (other == self.owner)
  365.         return;        // don't explode on owner
  366.  
  367.     if (pointcontents(self.origin) == CONTENT_SKY)
  368.     {
  369.         remove(self);
  370.         return;
  371.     }
  372.     
  373.     if (other.classname == "player" || other.classname == "bot")
  374.         other.gib_velocity = self.velocity;        // CTFBOT EXTRAS
  375.  
  376.     damg = 100 + random()*20;
  377.     
  378.     if (other.health)
  379.     {
  380.         if (other.classname == "monster_shambler")
  381.             damg = damg * 0.5;    // mostly immune
  382.         T_Damage (other, self, self.owner, damg );
  383.     }
  384.  
  385.     // don't do radius damage to the other, because all the damage
  386.     // was done in the impact
  387.     T_RadiusDamage (self, self.owner, 120, other);
  388.  
  389. //    sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
  390.     self.origin = self.origin - 8*normalize(self.velocity);
  391.  
  392.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  393.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  394.     WriteCoord (MSG_BROADCAST, self.origin_x);
  395.     WriteCoord (MSG_BROADCAST, self.origin_y);
  396.     WriteCoord (MSG_BROADCAST, self.origin_z);
  397.  
  398.     BecomeExplosion ();
  399. };
  400.  
  401.  
  402.  
  403. /*
  404. ================
  405. W_FireRocket
  406. ================
  407. */
  408. void() W_FireRocket =
  409. {
  410.     local    entity missile, mpuff;
  411.     
  412.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  413.     
  414.     sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
  415.  
  416.     self.punchangle_x = -2;
  417.  
  418.     missile = spawn ();
  419.     missile.owner = self;
  420.     missile.movetype = MOVETYPE_FLYMISSILE;
  421.     missile.solid = SOLID_BBOX;
  422.     missile.classname = "missile";
  423.         
  424. // set missile speed    
  425.  
  426.     makevectors (self.v_angle);
  427.  
  428.     if (self.classname == "player")        // CTFBOT
  429.         missile.velocity = aim (self, 1000);
  430.     else if (self.classname == "bot")    // CTFBOT
  431.         missile.velocity = self.bot_aim;        // CTFBOT
  432.  
  433.     missile.velocity = missile.velocity * 1000;
  434.     missile.angles = vectoangles(missile.velocity);
  435.     
  436.     missile.touch = T_MissileTouch;
  437.     
  438. // set missile duration
  439.     missile.nextthink = time + 5;
  440.     missile.think = SUB_Remove;
  441.  
  442.     setmodel (missile, "progs/missile.mdl");
  443.     setsize (missile, '0 0 0', '0 0 0');        
  444.     setorigin (missile, self.origin + v_forward*8 + '0 0 16');
  445. };
  446.  
  447. /*
  448. ===============================================================================
  449.  
  450. LIGHTNING
  451.  
  452. ===============================================================================
  453. */
  454.  
  455. /*
  456. =================
  457. LightningDamage
  458. =================
  459. */
  460. void(vector p1, vector p2, entity from, float damage) LightningDamage =
  461. {
  462.     local entity        e1, e2;
  463.     local vector        f;
  464.     
  465.     f = p2 - p1;
  466.     normalize (f);
  467.     f_x = 0 - f_y;
  468.     f_y = f_x;
  469.     f_z = 0;
  470.     f = f*16;
  471.  
  472.     e1 = e2 = world;
  473.  
  474.     traceline (p1, p2, FALSE, self);
  475.     if (trace_ent.takedamage)
  476.     {
  477.         particle (trace_endpos, '0 0 100', 225, damage*4);
  478.         T_Damage (trace_ent, from, from, damage);
  479.         if (self.classname == "player")
  480.         {
  481.             if (other.classname == "player")
  482.                 trace_ent.velocity_z = trace_ent.velocity_z + 400;
  483.         }
  484.     }
  485.     e1 = trace_ent;
  486.  
  487.     traceline (p1 + f, p2 + f, FALSE, self);
  488.     if (trace_ent != e1 && trace_ent.takedamage)
  489.     {
  490.         particle (trace_endpos, '0 0 100', 225, damage*4);
  491.         T_Damage (trace_ent, from, from, damage);
  492.     }
  493.     e2 = trace_ent;
  494.  
  495.     traceline (p1 - f, p2 - f, FALSE, self);
  496.     if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
  497.     {
  498.         particle (trace_endpos, '0 0 100', 225, damage*4);
  499.         T_Damage (trace_ent, from, from, damage);
  500.     }
  501. };
  502.  
  503.  
  504. void() W_FireLightning =
  505. {
  506.     local    vector        org;
  507.     local    float        cells;
  508.  
  509.     if (self.ammo_cells < 1)
  510.     {
  511.         self.weapon = W_BestWeapon ();
  512.         W_SetCurrentAmmo ();
  513.         return;
  514.     }
  515.  
  516. // explode if under water
  517.  
  518.     if (self.waterlevel > 1)
  519.     {
  520.         cells = self.ammo_cells;
  521.         self.ammo_cells = 0;
  522.         W_SetCurrentAmmo ();
  523.         T_RadiusDamage (self, self, 35*cells, world);
  524.         return;
  525.     }
  526.  
  527.     if (self.t_width < time)
  528.     {
  529.         sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
  530.         self.t_width = time + 0.6;
  531.     }
  532.     self.punchangle_x = -2;
  533.  
  534.     self.currentammo = self.ammo_cells = self.ammo_cells - 1;
  535.  
  536.     org = self.origin + '0 0 16';
  537.  
  538.     if (self.classname == "player")
  539.  
  540.         traceline (org, org + v_forward*600, TRUE, self);
  541.  
  542.     // CTFBOT [[[
  543.  
  544.     else if (self.classname == "bot")
  545.  
  546.     {
  547.  
  548.         if (bot_debug >= 3)
  549.  
  550.         {
  551.  
  552.             dprint(self.netname);
  553.  
  554.             dprint(" FireLightning\n");
  555.  
  556.         }
  557.  
  558.         local vector ba2;
  559.  
  560.         ba2 = self.bot_aim;
  561.  
  562.         ba2 = normalize(ba2);
  563.  
  564.         traceline (org, org + ba2*600, TRUE, self);
  565.  
  566.     }
  567.  
  568.     // CTFBOT ]]]
  569.  
  570.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  571.     WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
  572.     WriteEntity (MSG_BROADCAST, self);
  573.     WriteCoord (MSG_BROADCAST, org_x);
  574.     WriteCoord (MSG_BROADCAST, org_y);
  575.     WriteCoord (MSG_BROADCAST, org_z);
  576.     WriteCoord (MSG_BROADCAST, trace_endpos_x);
  577.     WriteCoord (MSG_BROADCAST, trace_endpos_y);
  578.     WriteCoord (MSG_BROADCAST, trace_endpos_z);
  579.  
  580.  
  581.     LightningDamage (self.origin, trace_endpos + v_forward*4, self, 30);
  582. };
  583.  
  584.  
  585. //=============================================================================
  586.  
  587.  
  588. void() GrenadeExplode =
  589. {
  590.     T_RadiusDamage (self, self.owner, 120, world);
  591.  
  592.     WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  593.     WriteByte (MSG_BROADCAST, TE_EXPLOSION);
  594.     WriteCoord (MSG_BROADCAST, self.origin_x);
  595.     WriteCoord (MSG_BROADCAST, self.origin_y);
  596.     WriteCoord (MSG_BROADCAST, self.origin_z);
  597.  
  598.     BecomeExplosion ();
  599. };
  600.  
  601. void() GrenadeTouch =
  602. {
  603.     if (other == self.owner)
  604.         return;        // don't explode on owner
  605.     if (other.takedamage == DAMAGE_AIM)
  606.     {
  607.         GrenadeExplode();
  608.         return;
  609.     }
  610.     sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);    // bounce sound
  611.     if (self.velocity == '0 0 0')
  612.         self.avelocity = '0 0 0';
  613. };
  614.  
  615. /*
  616. ================
  617. W_FireGrenade
  618. ================
  619. */
  620. void() W_FireGrenade =
  621. {
  622.     local    entity missile, mpuff;
  623.     
  624.     self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
  625.     
  626.     sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
  627.  
  628.     self.punchangle_x = -2;
  629.  
  630.     missile = spawn ();
  631.     missile.owner = self;
  632.     missile.movetype = MOVETYPE_BOUNCE;
  633.     missile.solid = SOLID_BBOX;
  634.     missile.classname = "grenade";
  635.         
  636. // set missile speed    
  637.  
  638.  
  639.  
  640.     // CTFBOT [[[
  641.  
  642.     if (self.classname == "bot")
  643.  
  644.     {
  645.  
  646.         self.angles = vectoangles(self.bot_aim);
  647.  
  648.         makevectors(self.angles);
  649.  
  650.         missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  651.  
  652.     }
  653.  
  654.     else
  655.  
  656.     {
  657.     // CTFBOT ]]]
  658.  
  659.  
  660.  
  661.         makevectors (self.v_angle);
  662.  
  663.         if (self.v_angle_x)
  664.             missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
  665.         else
  666.         {
  667.             missile.velocity = aim (self, 10000);
  668.  
  669.             missile.velocity = missile.velocity * 600;
  670.             missile.velocity_z = 200;
  671.         }
  672.  
  673.  
  674.  
  675.     }     // CTFBOT
  676.  
  677.     missile.avelocity = '300 300 300';
  678.  
  679.     missile.angles = vectoangles(missile.velocity);
  680.     
  681.     missile.touch = GrenadeTouch;
  682.     
  683. // set missile duration
  684.     missile.nextthink = time + 2.5;
  685.     missile.think = GrenadeExplode;
  686.  
  687.     setmodel (missile, "progs/grenade.mdl");
  688.     setsize (missile, '0 0 0', '0 0 0');        
  689.     setorigin (missile, self.origin);
  690. };
  691.  
  692.  
  693. //=============================================================================
  694.  
  695. void() spike_touch;
  696. void() superspike_touch;
  697.  
  698.  
  699. /*
  700. ===============
  701. launch_spike
  702.  
  703. Used for both the player and the ogre
  704. ===============
  705. */
  706. void(vector org, vector dir) launch_spike =
  707. {
  708.     newmis = spawn ();
  709.     newmis.owner = self;
  710.     newmis.movetype = MOVETYPE_FLYMISSILE;
  711.     newmis.solid = SOLID_BBOX;
  712.  
  713.     newmis.angles = vectoangles(dir);
  714.     
  715.     newmis.touch = spike_touch;
  716.     newmis.classname = "spike";
  717.     newmis.think = SUB_Remove;
  718.     newmis.nextthink = time + 6;
  719.     setmodel (newmis, "progs/spike.mdl");
  720.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  721.     setorigin (newmis, org);
  722.  
  723.     newmis.velocity = dir * 1000;
  724. };
  725.  
  726. void() W_FireSuperSpikes =
  727. {
  728.     local vector    dir;
  729.     local entity    old;
  730.     
  731.     sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
  732.     self.attack_finished = time + 0.2;
  733.     self.currentammo = self.ammo_nails = self.ammo_nails - 2;
  734.  
  735.     if (self.classname == "player")        // CTFBOT
  736.         dir = aim (self, 1000);
  737.     else if (self.classname == "bot")    // CTFBOT
  738.         dir = self.bot_aim;        // CTFBOT
  739.  
  740.     launch_spike (self.origin + '0 0 16', dir);
  741.     newmis.touch = superspike_touch;
  742.     setmodel (newmis, "progs/s_spike.mdl");
  743.     setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);        
  744.     self.punchangle_x = -2;
  745. };
  746.  
  747. void(float ox) W_FireSpikes =
  748. {
  749.     local vector    dir;
  750.     local entity    old;
  751.     
  752.     makevectors (self.v_angle);
  753.     
  754.     if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
  755.     {
  756.         W_FireSuperSpikes ();
  757.         return;
  758.     }
  759.  
  760.     if (self.ammo_nails < 1)
  761.     {
  762.         self.weapon = W_BestWeapon ();
  763.         W_SetCurrentAmmo ();
  764.         return;
  765.     }
  766.  
  767.     sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
  768.     self.attack_finished = time + 0.2;
  769.     self.currentammo = self.ammo_nails = self.ammo_nails - 1;
  770.     
  771.     if (self.classname == "player")        // CTFBOT
  772.         dir = aim (self, 1000);
  773.     else if (self.classname == "bot")    // CTFBOT
  774.         dir = self.bot_aim;        // CTFBOT
  775.         
  776.     launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
  777.  
  778.     self.punchangle_x = -2;
  779. };
  780.  
  781.  
  782.  
  783. .float hit_z;
  784. void() spike_touch =
  785. {
  786. local float rand;
  787.     if (other == self.owner)
  788.         return;
  789.  
  790.     if (other.solid == SOLID_TRIGGER)
  791.         return;    // trigger field, do nothing
  792.  
  793.     if (pointcontents(self.origin) == CONTENT_SKY)
  794.     {
  795.         remove(self);
  796.         return;
  797.     }
  798.     
  799. // hit something that bleeds
  800.     if (other.takedamage)
  801.     {
  802.         spawn_touchblood (9);
  803.         T_Damage (other, self, self.owner, 9);
  804.     }
  805.     else
  806.     {
  807.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  808.         
  809.         if (self.classname == "wizspike")
  810.             WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
  811.         else if (self.classname == "knightspike")
  812.             WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
  813.         else
  814.             WriteByte (MSG_BROADCAST, TE_SPIKE);
  815.         WriteCoord (MSG_BROADCAST, self.origin_x);
  816.         WriteCoord (MSG_BROADCAST, self.origin_y);
  817.         WriteCoord (MSG_BROADCAST, self.origin_z);
  818.     }
  819.  
  820.     remove(self);
  821.  
  822. };
  823.  
  824. void() superspike_touch =
  825. {
  826. local float rand;
  827.     if (other == self.owner)
  828.         return;
  829.  
  830.     if (other.solid == SOLID_TRIGGER)
  831.         return;    // trigger field, do nothing
  832.  
  833.     if (pointcontents(self.origin) == CONTENT_SKY)
  834.     {
  835.         remove(self);
  836.         return;
  837.     }
  838.     
  839. // hit something that bleeds
  840.     if (other.takedamage)
  841.     {
  842.         spawn_touchblood (18);
  843.         T_Damage (other, self, self.owner, 18);
  844.     }
  845.     else
  846.     {
  847.         WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
  848.         WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
  849.         WriteCoord (MSG_BROADCAST, self.origin_x);
  850.         WriteCoord (MSG_BROADCAST, self.origin_y);
  851.         WriteCoord (MSG_BROADCAST, self.origin_z);
  852.     }
  853.  
  854.     remove(self);
  855.  
  856. };
  857.  
  858.  
  859. /*
  860. ===============================================================================
  861.  
  862. PLAYER WEAPON USE
  863.  
  864. ===============================================================================
  865. */
  866.  
  867. void() W_SetCurrentAmmo =
  868. {
  869.  
  870.     if (self.classname == "player")        // CTFBOT
  871.         player_run ();        // get out of any weapon firing states
  872.  
  873.     else if (self.classname == "bot")
  874.  
  875.         self.think = BotAnimationThink;
  876.  
  877.  
  878.     if ((bot_debug >= 2) && (self.classname == "bot"))
  879.  
  880.     {
  881.  
  882.         dprint(self.netname);
  883.  
  884.         dprint(" ");
  885.  
  886.         local string st;
  887.  
  888.         st = ftos(self.weapon);
  889.  
  890.         dprint(st);
  891.  
  892.         dprint(" W_SetCurrentAmmo\n");
  893.  
  894.     }
  895.  
  896.  
  897.     self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );
  898.     
  899.     if (self.weapon == IT_AXE)
  900.     {
  901.         self.currentammo = 0;
  902.         self.weaponmodel = "progs/v_axe.mdl";
  903.         self.weaponframe = 0;
  904.     }
  905.     else if (self.weapon == IT_HOOK)
  906.     {
  907.         self.currentammo = 0;
  908.         if (teamplay & TEAM_CAPTURE_CUSTOM) 
  909.             self.weaponmodel = "progs/v_star.mdl";
  910.         else
  911.             self.weaponmodel = "progs/v_axe.mdl";
  912.         self.weaponframe = 0;
  913.     }
  914.     else if (self.weapon == IT_SHOTGUN)
  915.     {
  916.         self.currentammo = self.ammo_shells;
  917.         self.weaponmodel = "progs/v_shot.mdl";
  918.         self.weaponframe = 0;
  919.         self.items = self.items | IT_SHELLS;
  920.     }
  921.     else if (self.weapon == IT_SUPER_SHOTGUN)
  922.     {
  923.         self.currentammo = self.ammo_shells;
  924.         self.weaponmodel = "progs/v_shot2.mdl";
  925.         self.weaponframe = 0;
  926.         self.items = self.items | IT_SHELLS;
  927.     }
  928.     else if (self.weapon == IT_NAILGUN)
  929.     {
  930.         self.currentammo = self.ammo_nails;
  931.         self.weaponmodel = "progs/v_nail.mdl";
  932.         self.weaponframe = 0;
  933.         self.items = self.items | IT_NAILS;
  934.     }
  935.     else if (self.weapon == IT_SUPER_NAILGUN)
  936.     {
  937.         self.currentammo = self.ammo_nails;
  938.         self.weaponmodel = "progs/v_nail2.mdl";
  939.         self.weaponframe = 0;
  940.         self.items = self.items | IT_NAILS;
  941.     }
  942.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  943.     {
  944.         self.currentammo = self.ammo_rockets;
  945.         self.weaponmodel = "progs/v_rock.mdl";
  946.         self.weaponframe = 0;
  947.         self.items = self.items | IT_ROCKETS;
  948.     }
  949.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  950.     {
  951.         self.currentammo = self.ammo_rockets;
  952.         self.weaponmodel = "progs/v_rock2.mdl";
  953.         self.weaponframe = 0;
  954.         self.items = self.items | IT_ROCKETS;
  955.     }
  956.     else if (self.weapon == IT_LIGHTNING)
  957.     {
  958.         self.currentammo = self.ammo_cells;
  959.         self.weaponmodel = "progs/v_light.mdl";
  960.         self.weaponframe = 0;
  961.         self.items = self.items | IT_CELLS;
  962.     }
  963.     else
  964.     {
  965.         self.currentammo = 0;
  966.         self.weaponmodel = "";
  967.         self.weaponframe = 0;
  968.     }
  969. };
  970.  
  971. float() W_BestWeapon =
  972. {
  973.     local    float    it;
  974.  
  975.     if (self.classname == "bot")        // CTFBOT
  976.  
  977.     {
  978.  
  979.         local float bw;
  980.  
  981.         bw = Bot_BestWeapon();        // CTFBOT
  982.  
  983.         return bw;
  984.  
  985.     }
  986.  
  987.     else
  988.     {
  989.     it = self.items;
  990.  
  991.     if (self.waterlevel <= 1 && self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
  992.         return IT_LIGHTNING;
  993.     if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
  994.         return IT_SUPER_NAILGUN;
  995.     if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
  996.         return IT_SUPER_SHOTGUN;
  997.     if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
  998.         return IT_NAILGUN;
  999.     if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
  1000.         return IT_SHOTGUN;
  1001.     return IT_AXE;
  1002.  
  1003.     }
  1004. };
  1005.  
  1006. float() W_CheckNoAmmo =
  1007. {
  1008.     if (self.currentammo > 0)
  1009.         return TRUE;
  1010.  
  1011.     if (self.weapon == IT_AXE || self.weapon == IT_HOOK)
  1012.         return TRUE;
  1013.     
  1014.     self.weapon = W_BestWeapon ();
  1015.  
  1016.     if ((bot_debug >= 2) && (self.classname == "bot"))
  1017.     {
  1018.         dprint(self.netname);
  1019.         local string st;
  1020.         dprint(" BestWeapon ");
  1021.         st = ftos(self.weapon);
  1022.         dprint(st);
  1023.         dprint("\n");
  1024.     }
  1025.  
  1026.     W_SetCurrentAmmo ();
  1027.     
  1028. // drop the weapon down
  1029.     return FALSE;
  1030. };
  1031.  
  1032. /*
  1033. ============
  1034. W_Attack
  1035.  
  1036. An attack impulse can be triggered now
  1037. ============
  1038. */
  1039. void()    player_axe1;
  1040. void()    player_axeb1;
  1041. void()    player_axec1;
  1042. void()    player_axed1;
  1043. void()    player_shot1;
  1044. void()    player_nail1;
  1045. void()    player_light1;
  1046. void()    player_rocket1;
  1047. void()    player_chain1;
  1048. void()  player_chain3;
  1049.  
  1050. void() W_Attack =
  1051. {
  1052.     local    float    r;
  1053.  
  1054.     if (!W_CheckNoAmmo ())
  1055.         return;
  1056.  
  1057.  
  1058.     if ((bot_debug >= 2) && (self.classname == "bot"))
  1059.  
  1060.     {
  1061.  
  1062.         dprint(self.netname);
  1063.  
  1064.         dprint(" ");
  1065.  
  1066.         local string st;
  1067.  
  1068.         st = ftos(self.weapon);
  1069.  
  1070.         dprint(st);
  1071.  
  1072.         dprint(" W_Attack\n");
  1073.  
  1074.     }
  1075.  
  1076.  
  1077.     makevectors    (self.v_angle);            // calculate forward angle for velocity
  1078.     self.show_hostile = time + 1;    // wake monsters up
  1079.  
  1080.     if (self.weapon == IT_AXE)
  1081.     {
  1082.         sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
  1083.         r = random();
  1084.         if (r < 0.25)
  1085.             player_axe1 ();
  1086.         else if (r<0.5)
  1087.             player_axeb1 ();
  1088.         else if (r<0.75)
  1089.             player_axec1 ();
  1090.         else
  1091.             player_axed1 ();
  1092.         // RUNE: rune of hell magic
  1093.         if (self.player_flag & ITEM_RUNE3_FLAG) {
  1094.             self.attack_finished = time + 0.3;
  1095.             HasteSound();
  1096.         } else
  1097.             self.attack_finished = time + 0.5;
  1098.     }
  1099.     else if (self.weapon == IT_SHOTGUN)
  1100.     {
  1101.         player_shot1 ();
  1102.         W_FireShotgun ();
  1103.         // RUNE: rune of hell magic
  1104.         if (self.player_flag & ITEM_RUNE3_FLAG) {
  1105.             self.attack_finished = time + 0.3;
  1106.             HasteSound();
  1107.         } else
  1108.         self.attack_finished = time + 0.5;
  1109.     }
  1110.     else if (self.weapon == IT_SUPER_SHOTGUN)
  1111.     {
  1112.         player_shot1 ();
  1113.         W_FireSuperShotgun ();
  1114.         // RUNE: rune of hell magic
  1115.         if (self.player_flag & ITEM_RUNE3_FLAG) {
  1116.             self.attack_finished = time + 0.4;
  1117.             HasteSound();
  1118.         } else
  1119.         self.attack_finished = time + 0.7;
  1120.     }
  1121.     else if (self.weapon == IT_NAILGUN)
  1122.     {
  1123.         player_nail1 ();
  1124.     }
  1125.     else if (self.weapon == IT_SUPER_NAILGUN)
  1126.     {
  1127.         player_nail1 ();
  1128.     }
  1129.     else if (self.weapon == IT_GRENADE_LAUNCHER)
  1130.     {
  1131.         player_rocket1();
  1132.         W_FireGrenade();
  1133.         // RUNE: rune of hell magic
  1134.         if (self.player_flag & ITEM_RUNE3_FLAG) {
  1135.             self.attack_finished = time + 0.3;
  1136.             HasteSound();
  1137.         } else
  1138.             self.attack_finished = time + 0.6;
  1139.     }
  1140.     else if (self.weapon == IT_ROCKET_LAUNCHER)
  1141.     {
  1142.         player_rocket1();
  1143.         W_FireRocket();
  1144.         // RUNE: rune of hell magic
  1145.         if (self.player_flag & ITEM_RUNE3_FLAG) {
  1146.             self.attack_finished = time + 0.4;
  1147.             HasteSound();
  1148.         } else
  1149.             self.attack_finished = time + 0.8;
  1150.     }
  1151.     else if (self.weapon == IT_LIGHTNING)
  1152.     {
  1153.         player_light1();
  1154.         self.attack_finished = time + 0.1;
  1155.         sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
  1156.     }
  1157.     else if (self.weapon == IT_HOOK)
  1158.     {
  1159.         if (!self.hook_out)
  1160.             player_chain1();
  1161.         else
  1162.             player_chain3();
  1163.         self.attack_finished = time + 0.1;
  1164.     }
  1165. };
  1166.  
  1167. void() NotifyWeapon =
  1168. {
  1169.     if (self.weapon == IT_AXE)
  1170.         sprint(self, "Axe selected.\n");
  1171.     else if (self.weapon == IT_HOOK)
  1172.         sprint(self, "Grappling hook selected.\n");
  1173. };
  1174.  
  1175. /*
  1176. ============
  1177. W_ChangeWeapon
  1178.  
  1179. ============
  1180. */
  1181. void() W_ChangeWeapon =
  1182. {
  1183.     local    float    it, am, fl;
  1184.     
  1185.     it = self.items;
  1186.     am = 0;
  1187.     
  1188.     if (self.impulse == 1) {
  1189.         if (self.weapon == IT_AXE)
  1190.             fl = IT_HOOK;
  1191.         else
  1192.             fl = IT_AXE;
  1193.     } else if (self.impulse == 31) {
  1194.         fl = IT_AXE;
  1195.     } else if (self.impulse == 2 || self.impulse == 32) {
  1196.         fl = IT_SHOTGUN;
  1197.         if (self.ammo_shells < 1)
  1198.             am = 1;
  1199.     } else if (self.impulse == 3 || self.impulse == 33) {
  1200.         fl = IT_SUPER_SHOTGUN;
  1201.         if (self.ammo_shells < 2)
  1202.             am = 1;
  1203.     } else if (self.impulse == 4 || self.impulse == 34) {
  1204.         fl = IT_NAILGUN;
  1205.         if (self.ammo_nails < 1)
  1206.             am = 1;
  1207.     } else if (self.impulse == 5) {
  1208.         fl = IT_SUPER_NAILGUN;
  1209.         if (self.ammo_nails < 2)
  1210.             am = 1;
  1211.     } else if (self.impulse == 35) {
  1212.         fl = IT_SUPER_NAILGUN;
  1213.         if (self.ammo_nails < 2)
  1214.             am = 1;
  1215.     } else if (self.impulse == 6 || self.impulse == 36) {
  1216.         fl = IT_GRENADE_LAUNCHER;
  1217.         if (self.ammo_rockets < 1)
  1218.             am = 1;
  1219.     } else if (self.impulse == 7 || self.impulse == 37) {
  1220.         fl = IT_ROCKET_LAUNCHER;
  1221.         if (self.ammo_rockets < 1)
  1222.             am = 1;
  1223.     } else if (self.impulse == 8 || self.impulse == 38) {
  1224.         fl = IT_LIGHTNING;
  1225.         if (self.ammo_cells < 1)
  1226.             am = 1;
  1227.     } else if (self.impulse == 22 || self.impulse == 39) {
  1228.         fl = IT_HOOK;
  1229.     }
  1230.  
  1231.     self.impulse = 0;
  1232.     
  1233.     if (!(self.items & fl))
  1234.     {    // don't have the weapon or the ammo
  1235.         sprint (self, "no weapon.\n");
  1236.         return;
  1237.     }
  1238.     
  1239.     if (am)
  1240.     {    // don't have the ammo
  1241.         sprint (self, "not enough ammo.\n");
  1242.         return;
  1243.     }
  1244.  
  1245. //McBain: save current weapon
  1246. // For explicite weapon selection, allow previous weapon and new weapon to be
  1247. // same except for IT_HOOK.
  1248.     if (self.weapon != IT_HOOK || fl != IT_HOOK)
  1249.         self.previous_weapon = self.weapon;
  1250.  
  1251. //
  1252. // set weapon, set ammo
  1253. //
  1254.     self.weapon = fl;        
  1255.     NotifyWeapon();
  1256.     W_SetCurrentAmmo ();
  1257. };
  1258.  
  1259. /*
  1260. ============
  1261. CheatCommand
  1262. ============
  1263. */
  1264. void() CheatCommand =
  1265. {
  1266.     if (deathmatch || coop)
  1267.         return;
  1268.  
  1269.     self.ammo_rockets = 100;
  1270.     self.ammo_nails = 200;
  1271.     self.ammo_shells = 100;
  1272.     self.items = self.items | 
  1273.         IT_AXE |
  1274.         IT_HOOK |
  1275.         IT_SHOTGUN |
  1276.         IT_SUPER_SHOTGUN |
  1277.         IT_NAILGUN |
  1278.         IT_SUPER_NAILGUN |
  1279.         IT_GRENADE_LAUNCHER |
  1280.         IT_ROCKET_LAUNCHER |
  1281.         IT_KEY1 | IT_KEY2;
  1282.  
  1283.     self.ammo_cells = 200;
  1284.     self.items = self.items | IT_LIGHTNING;
  1285.  
  1286.     self.weapon = IT_ROCKET_LAUNCHER;
  1287.     self.impulse = 0;
  1288.     W_SetCurrentAmmo ();
  1289. };
  1290.  
  1291. /*
  1292. ============
  1293. CycleWeaponCommand
  1294.  
  1295. Go to the next weapon with ammo
  1296. ============
  1297. */
  1298. void() CycleWeaponCommand =
  1299. {
  1300.     local    float    it, am;
  1301.     
  1302.     it = self.items;
  1303.     self.impulse = 0;
  1304.     
  1305. //McBain: save current weapon
  1306.     self.previous_weapon = self.weapon;
  1307.  
  1308.     while (1)
  1309.     {
  1310.         am = 0;
  1311.  
  1312.         if (self.weapon == IT_LIGHTNING) {
  1313.             self.weapon = IT_AXE;
  1314.         } else if (self.weapon == IT_AXE) {
  1315.             self.weapon = IT_HOOK;
  1316.         } else if (self.weapon == IT_HOOK) {
  1317.             self.weapon = IT_SHOTGUN;
  1318.             if (self.ammo_shells < 1)
  1319.                 am = 1;
  1320.         } else if (self.weapon == IT_SHOTGUN) {
  1321.             self.weapon = IT_SUPER_SHOTGUN;
  1322.             if (self.ammo_shells < 2)
  1323.                 am = 1;
  1324.         } else if (self.weapon == IT_SUPER_SHOTGUN) {
  1325.             self.weapon = IT_NAILGUN;
  1326.             if (self.ammo_nails < 1)
  1327.                 am = 1;
  1328.         } else if (self.weapon == IT_NAILGUN) {
  1329.             self.weapon = IT_SUPER_NAILGUN;
  1330.             if (self.ammo_nails < 2)
  1331.                 am = 1;
  1332.         } else if (self.weapon == IT_SUPER_NAILGUN) {
  1333.             self.weapon = IT_GRENADE_LAUNCHER;
  1334.             if (self.ammo_rockets < 1)
  1335.                 am = 1;
  1336.         } else if (self.weapon == IT_GRENADE_LAUNCHER) {
  1337.             self.weapon = IT_ROCKET_LAUNCHER;
  1338.             if (self.ammo_rockets < 1)
  1339.                 am = 1;
  1340.         } else if (self.weapon == IT_ROCKET_LAUNCHER) {
  1341.             self.weapon = IT_LIGHTNING;
  1342.             if (self.ammo_cells < 1)
  1343.                 am = 1;
  1344.         }
  1345.     
  1346.         if ( (it & self.weapon) && am == 0)
  1347.         {
  1348.             NotifyWeapon();
  1349.             W_SetCurrentAmmo ();
  1350.             return;
  1351.         }
  1352.     }
  1353.  
  1354. };
  1355.  
  1356. /*
  1357. ============
  1358. CycleWeaponReverseCommand
  1359.  
  1360. Go to the prev weapon with ammo
  1361. ============
  1362. */
  1363. void() CycleWeaponReverseCommand =
  1364. {
  1365.     local    float    it, am;
  1366.     
  1367.     it = self.items;
  1368.     self.impulse = 0;
  1369.  
  1370. //McBain: save current weapon
  1371.     self.previous_weapon = self.weapon;
  1372.  
  1373.     while (1)
  1374.     {
  1375.         am = 0;
  1376.  
  1377.         if (self.weapon == IT_LIGHTNING)
  1378.         {
  1379.             self.weapon = IT_ROCKET_LAUNCHER;
  1380.             if (self.ammo_rockets < 1)
  1381.                 am = 1;
  1382.         }
  1383.         else if (self.weapon == IT_ROCKET_LAUNCHER)
  1384.         {
  1385.             self.weapon = IT_GRENADE_LAUNCHER;
  1386.             if (self.ammo_rockets < 1)
  1387.                 am = 1;
  1388.         }
  1389.         else if (self.weapon == IT_GRENADE_LAUNCHER)
  1390.         {
  1391.             self.weapon = IT_SUPER_NAILGUN;
  1392.             if (self.ammo_nails < 1)
  1393.                 am = 1;
  1394.         }
  1395.         else if (self.weapon == IT_SUPER_NAILGUN)
  1396.         {
  1397.             self.weapon = IT_NAILGUN;
  1398.             if (self.ammo_nails < 1)
  1399.                 am = 1;
  1400.         }
  1401.         else if (self.weapon == IT_NAILGUN)
  1402.         {
  1403.             self.weapon = IT_SUPER_SHOTGUN;
  1404.             if (self.ammo_shells < 2)
  1405.                 am = 1;
  1406.         }        
  1407.         else if (self.weapon == IT_SUPER_SHOTGUN)
  1408.         {
  1409.             self.weapon = IT_SHOTGUN;
  1410.             if (self.ammo_shells < 1)
  1411.                 am = 1;
  1412.         }
  1413.         else if (self.weapon == IT_SHOTGUN)
  1414.         {
  1415.             self.weapon = IT_HOOK;
  1416.         }
  1417.         else if (self.weapon == IT_HOOK)
  1418.         {
  1419.             self.weapon = IT_AXE;
  1420.         }
  1421.         else if (self.weapon == IT_AXE)
  1422.         {
  1423.             self.weapon = IT_LIGHTNING;
  1424.             if (self.ammo_cells < 1)
  1425.                 am = 1;
  1426.         }
  1427.     
  1428.         if ( (it & self.weapon) && am == 0)
  1429.         {
  1430.             NotifyWeapon();
  1431.             W_SetCurrentAmmo ();
  1432.             return;
  1433.         }
  1434.     }
  1435.  
  1436. };
  1437.  
  1438. //McBain: Here's the beef...
  1439. /*
  1440. ============
  1441. PreviousWeaponCommand
  1442. ============
  1443. */
  1444. void() PreviousWeaponCommand =
  1445. {
  1446.     local    float    fl, am;
  1447.     
  1448.     self.impulse = 0;
  1449.     am = 0;
  1450.  
  1451.     fl = self.weapon;
  1452.     self.weapon = self.previous_weapon;
  1453.     self.previous_weapon = fl;
  1454.  
  1455.     // this might not be the best method, but I'll be able to play sooner
  1456.     if (self.weapon == IT_SHOTGUN || self.weapon == IT_SUPER_SHOTGUN) {
  1457.         if (self.ammo_shells < 1)
  1458.             am = 1;
  1459.     }
  1460.     else if (self.weapon == IT_NAILGUN || self.weapon == IT_SUPER_NAILGUN) {
  1461.         if (self.ammo_nails < 1)
  1462.             am = 1;
  1463.     }
  1464.     else if (self.weapon == IT_GRENADE_LAUNCHER || self.weapon == IT_ROCKET_LAUNCHER) {
  1465.         if (self.ammo_rockets < 1)
  1466.             am = 1;
  1467.     }
  1468.     else if (self.weapon == IT_LIGHTNING) {
  1469.         if (self.ammo_cells < 1)
  1470.             am = 1;
  1471.     }
  1472.     // ignore AXE & HOOK -- no ammo needed
  1473.  
  1474.     if (am)
  1475.         self.weapon = W_BestWeapon ();
  1476.  
  1477.     W_SetCurrentAmmo ();
  1478. };
  1479.  
  1480. /*
  1481. ============
  1482. ServerflagsCommand
  1483.  
  1484. Just for development
  1485. ============
  1486. */
  1487. void() ServerflagsCommand =
  1488. {
  1489.     serverflags = serverflags * 2 + 1;
  1490. // ZOID:  Bug fix
  1491.     serverflags = (serverflags & 15);
  1492. };
  1493.  
  1494. void() QuadCheat =
  1495. {
  1496.     if (deathmatch || coop)
  1497.         return;
  1498.     self.super_time = 1;
  1499.     self.super_damage_finished = time + 30;
  1500.     self.items = self.items | IT_QUAD;
  1501.     dprint ("quad cheat\n");
  1502. };
  1503.  
  1504. //ZOID:  Uhm, where am I?
  1505. void() PrintLocation =
  1506. {
  1507.     local string p;
  1508.  
  1509.     p = vtos(self.origin);
  1510.  
  1511.     sprint(self, "You are at ");
  1512.     sprint(self, p);
  1513.     sprint(self, "\n");
  1514. };
  1515.  
  1516. /*
  1517. ============
  1518. ImpulseCommands
  1519.  
  1520. ============
  1521. */
  1522. //ZOID: Note, changed it all to an if/else construct.  No need to check
  1523. //remaining impulses if we have one already.  Much cleaner and a tad
  1524. //more efficient.  Using a non-existant impulse is still the worst case. :(
  1525. void() ImpulseCommands =
  1526. {
  1527.     // CTFBOT EXTRAS [[[
  1528.     if ((self.observer) && (self.classname == "player"))
  1529.     {
  1530.         sprint(self, "You are an observer\n");
  1531.         sprint(self, "You cannot execute impulses\n");
  1532.     }
  1533.     // CTFBOT EXTRAS ]]]
  1534.  
  1535.  
  1536.     if (self.classname != "player")
  1537.         return;
  1538.  
  1539.     if (self.impulse != 0)
  1540.     if (self.accessparm) // admin functions
  1541.         CheckAdminCmd();
  1542.  
  1543.     if (self.impulse != 0)
  1544.     if (!CheckBotImpulseCommands())        // CTFBOT
  1545.     {                                    // CTFBOT
  1546.  
  1547.     if (!self.observer &&
  1548.         ((self.impulse >= 1 && self.impulse <= 8) || self.impulse == 22 ||
  1549.         (self.impulse >= 31 && self.impulse <= 40) ||
  1550.          self.impulse == 50))
  1551.         W_ChangeWeapon ();
  1552.  
  1553.     else if (self.impulse == 9)
  1554.         CheatCommand ();
  1555.  
  1556.     else if (!self.observer && self.impulse == 10)
  1557.         CycleWeaponCommand ();
  1558.  
  1559.     else if (self.impulse == 11)
  1560.         ServerflagsCommand ();
  1561.  
  1562.     else if (!self.observer && self.impulse == 12)
  1563.         CycleWeaponReverseCommand ();
  1564.  
  1565. //McBain: I picked 69 -- seems appropriate!  I hope 69 hasn't been used in
  1566. // other add-ons.  This is my first attempt at Quake C, and I hope I haven't
  1567. // violated any Quake C ettiquette.  :(
  1568.     else if (!self.observer && self.impulse == 69)
  1569.         PreviousWeaponCommand ();
  1570.  
  1571.     else if (self.impulse == 99)
  1572.         PrintLocation();
  1573.         
  1574. // *TEAMPLAY*
  1575. // If we're allowed to drop items, enable impulse 20 and 21
  1576.     else if (!self.observer && (teamplay & TEAM_DROP_ITEMS) && self.impulse == 20)
  1577.         TossBackpack ();
  1578.  
  1579.     else if (!self.observer && (teamplay & TEAM_DROP_ITEMS) && self.impulse == 21)
  1580.         TossWeapon ();
  1581.  
  1582. // *TEAMPLAY*
  1583. // Impulse 25 prints info about the current teamplay settings.
  1584.     else if (self.impulse == 25)
  1585.         TeamPrintSettings ();
  1586.  
  1587. // *Capture The Flag - Status report by Wonko
  1588. // Impulse 23 prints the current status of your flag and the
  1589. // enemy flag (summarizes the endless messages)
  1590.     else if (self.impulse == 23)
  1591.         TeamFlagStatusReport();
  1592.  
  1593.     else if (self.impulse == 255)
  1594.         QuadCheat ();
  1595.     else
  1596.         CheckAdminCmd();
  1597.     
  1598.     }    // CTFBOT
  1599.     
  1600.     self.impulse = 0;
  1601. };
  1602.  
  1603. /*
  1604. ============
  1605. W_WeaponFrame
  1606.  
  1607. Called every frame so impulse events can be handled as well as possible
  1608. ============
  1609. */
  1610. void() W_WeaponFrame =
  1611. {
  1612.     if (time < self.attack_finished)
  1613.         return;
  1614.  
  1615. //ZOID: Only call ImpulseCommands() if needed!  This saves a good chunk
  1616. //of cpu.  'profile' in console listed ImpulseCommands() as #1 user of
  1617. //cpu (instructions), adding this one line caused it to not even be in
  1618. //the top ten.
  1619.     if (self.impulse && (self.classname == "player"))        // CTFBOT
  1620.         ImpulseCommands ();
  1621.     
  1622. // check for attack
  1623.     if (self.button0)
  1624.     {
  1625.         SuperDamageSound ();
  1626.         W_Attack ();
  1627.     }
  1628. };
  1629.  
  1630. /*
  1631. ========
  1632. SuperDamageSound
  1633.  
  1634. Plays sound if needed
  1635. ========
  1636. */
  1637. void() SuperDamageSound =
  1638. {
  1639. // RUNE play super damage sound if player has Black Magic, too
  1640.     if (self.super_damage_finished > time || (self.player_flag & ITEM_RUNE2_FLAG)) {
  1641.         if (self.super_sound < time) {
  1642.             self.super_sound = time + 1;
  1643.             sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
  1644.         }
  1645.     }
  1646.     return;
  1647. };
  1648.  
  1649. /*
  1650. ========
  1651. RegenerationSound
  1652.  
  1653. Plays sound if needed
  1654. ========
  1655. */
  1656. void() RegenerationSound =
  1657. {
  1658. // RUNE play healing sound if player has Elder Magic
  1659.     if (self.player_flag & ITEM_RUNE4_FLAG) {
  1660.         if (self.regeneration_sound < time) {
  1661.             self.regeneration_sound = time + 1;
  1662.             sound(self, CHAN_BODY, "items/r_item1.wav", 1, ATTN_NORM);
  1663.         }
  1664.     }
  1665.     return;
  1666. };
  1667.  
  1668. /*
  1669. ========
  1670. HasteSound
  1671.  
  1672. Plays sound if needed
  1673. ========
  1674. */
  1675. void() HasteSound =
  1676. {
  1677. // RUNE play haste (Chthon's roar) sound if player has Hell Magic
  1678.     if (self.player_flag & ITEM_RUNE3_FLAG) {
  1679.         if (self.haste_sound < time) {
  1680.             self.haste_sound = time + 2;
  1681.             sound(self, CHAN_BODY, "boss1/sight1.wav", 1, ATTN_NORM);
  1682.         }
  1683.     }
  1684.     return;
  1685. };