1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *      Weapon sprite animation, weapon objects.
31  *      Action functions for weapons.
32  *
33  *-----------------------------------------------------------------------------*/
34 
35 #include "doomstat.h"
36 #include "r_main.h"
37 #include "p_map.h"
38 #include "p_inter.h"
39 #include "p_pspr.h"
40 #include "p_enemy.h"
41 #include "m_random.h"
42 #include "s_sound.h"
43 #include "sounds.h"
44 #include "d_event.h"
45 #include "r_demo.h"
46 
47 #define LOWERSPEED   (FRACUNIT*6)
48 #define RAISESPEED   (FRACUNIT*6)
49 #define WEAPONBOTTOM (FRACUNIT*128)
50 #define WEAPONTOP    (FRACUNIT*32)
51 
52 #define BFGCELLS bfgcells        /* Ty 03/09/98 externalized in p_inter.c */
53 
54 extern void P_Thrust(player_t *, angle_t, fixed_t);
55 
56 // The following array holds the recoil values         // phares
57 
58 static const int recoil_values[] = {    // phares
59   10, // wp_fist
60   10, // wp_pistol
61   30, // wp_shotgun
62   10, // wp_chaingun
63   100,// wp_missile
64   20, // wp_plasma
65   100,// wp_bfg
66   0,  // wp_chainsaw
67   80  // wp_supershotgun
68 };
69 
70 //
71 // P_SetPsprite
72 //
73 
P_SetPsprite(player_t * player,int position,statenum_t stnum)74 static void P_SetPsprite(player_t *player, int position, statenum_t stnum)
75 {
76   pspdef_t *psp = &player->psprites[position];
77 
78   do
79     {
80       state_t *state;
81 
82       if (!stnum)
83         {
84           // object removed itself
85           psp->state = NULL;
86           break;
87         }
88 
89       state = &states[stnum];
90       psp->state = state;
91       psp->tics = state->tics;        // could be 0
92 
93       if (state->misc1)
94         {
95           // coordinate set
96           psp->sx = state->misc1 << FRACBITS;
97           psp->sy = state->misc2 << FRACBITS;
98         }
99 
100       // Call action routine.
101       // Modified handling.
102       if (state->action)
103         {
104           state->action(player, psp);
105           if (!psp->state)
106             break;
107         }
108       stnum = psp->state->nextstate;
109     }
110   while (!psp->tics);     // an initial state of 0 could cycle through
111 }
112 
113 //
114 // P_BringUpWeapon
115 // Starts bringing the pending weapon up
116 // from the bottom of the screen.
117 // Uses player
118 //
119 
P_BringUpWeapon(player_t * player)120 static void P_BringUpWeapon(player_t *player)
121 {
122   statenum_t newstate;
123 
124   if (player->pendingweapon == wp_nochange)
125     player->pendingweapon = player->readyweapon;
126 
127   if (player->pendingweapon == wp_chainsaw)
128     S_StartSound (player->mo, sfx_sawup);
129 
130   newstate = weaponinfo[player->pendingweapon].upstate;
131 
132   player->pendingweapon = wp_nochange;
133   // killough 12/98: prevent pistol from starting visibly at bottom of screen:
134   player->psprites[ps_weapon].sy =
135     mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM;
136 
137   P_SetPsprite(player, ps_weapon, newstate);
138 }
139 
140 // The first set is where the weapon preferences from             // killough,
141 // default.cfg are stored. These values represent the keys used   // phares
142 // in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These    //    |
143 // are NOT the wp_* constants.                                    //    V
144 
145 int weapon_preferences[2][NUMWEAPONS+1] = {
146   {6, 9, 4, 3, 2, 8, 5, 7, 1, 0},  // !compatibility preferences
147   {6, 9, 4, 3, 2, 8, 5, 7, 1, 0},  //  compatibility preferences
148 };
149 
150 // P_SwitchWeapon checks current ammo levels and gives you the
151 // most preferred weapon with ammo. It will not pick the currently
152 // raised weapon. When called from P_CheckAmmo this won't matter,
153 // because the raised weapon has no ammo anyway. When called from
154 // G_BuildTiccmd you want to toggle to a different weapon regardless.
155 
P_SwitchWeapon(player_t * player)156 int P_SwitchWeapon(player_t *player)
157 {
158   int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98
159   int currentweapon = player->readyweapon;
160   int newweapon = currentweapon;
161   int i = NUMWEAPONS+1;   // killough 5/2/98
162 
163   // killough 2/8/98: follow preferences and fix BFG/SSG bugs
164 
165   do
166     switch (*prefer++)
167       {
168       case 1:
169         if (!player->powers[pw_strength])      // allow chainsaw override
170           break;
171       case 0:
172         newweapon = wp_fist;
173         break;
174       case 2:
175         if (player->ammo[am_clip])
176           newweapon = wp_pistol;
177         break;
178       case 3:
179         if (player->weaponowned[wp_shotgun] && player->ammo[am_shell])
180           newweapon = wp_shotgun;
181         break;
182       case 4:
183         if (player->weaponowned[wp_chaingun] && player->ammo[am_clip])
184           newweapon = wp_chaingun;
185         break;
186       case 5:
187         if (player->weaponowned[wp_missile] && player->ammo[am_misl])
188           newweapon = wp_missile;
189         break;
190       case 6:
191         if (player->weaponowned[wp_plasma] && player->ammo[am_cell] &&
192             gamemode != shareware)
193           newweapon = wp_plasma;
194         break;
195       case 7:
196         if (player->weaponowned[wp_bfg] && gamemode != shareware &&
197             player->ammo[am_cell] >= (demo_compatibility ? 41 : 40))
198           newweapon = wp_bfg;
199         break;
200       case 8:
201         if (player->weaponowned[wp_chainsaw])
202           newweapon = wp_chainsaw;
203         break;
204       case 9:
205         if (player->weaponowned[wp_supershotgun] && gamemode == commercial &&
206             player->ammo[am_shell] >= (demo_compatibility ? 3 : 2))
207           newweapon = wp_supershotgun;
208         break;
209       }
210   while (newweapon==currentweapon && --i);          // killough 5/2/98
211   return newweapon;
212 }
213 
214 // killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2.
P_WeaponPreferred(int w1,int w2)215 int P_WeaponPreferred(int w1, int w2)
216 {
217   return
218     (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 ||
219     (weapon_preferences[0][1] !=   w2 && (weapon_preferences[0][1] ==   w1 ||
220     (weapon_preferences[0][2] !=   w2 && (weapon_preferences[0][2] ==   w1 ||
221     (weapon_preferences[0][3] !=   w2 && (weapon_preferences[0][3] ==   w1 ||
222     (weapon_preferences[0][4] !=   w2 && (weapon_preferences[0][4] ==   w1 ||
223     (weapon_preferences[0][5] !=   w2 && (weapon_preferences[0][5] ==   w1 ||
224     (weapon_preferences[0][6] !=   w2 && (weapon_preferences[0][6] ==   w1 ||
225     (weapon_preferences[0][7] !=   w2 && (weapon_preferences[0][7] ==   w1
226    ))))))))))))))));
227 }
228 
229 //
230 // P_CheckAmmo
231 // Returns true if there is enough ammo to shoot.
232 // If not, selects the next weapon to use.
233 // (only in demo_compatibility mode -- killough 3/22/98)
234 //
235 
P_CheckAmmo(player_t * player)236 boolean P_CheckAmmo(player_t *player)
237 {
238   ammotype_t ammo = weaponinfo[player->readyweapon].ammo;
239   int count = 1;  // Regular
240 
241   if (player->readyweapon == wp_bfg)  // Minimal amount for one shot varies.
242     count = BFGCELLS;
243   else
244     if (player->readyweapon == wp_supershotgun)        // Double barrel.
245       count = 2;
246 
247   // Some do not need ammunition anyway.
248   // Return if current ammunition sufficient.
249 
250   if (ammo == am_noammo || player->ammo[ammo] >= count)
251     return true;
252 
253   // Out of ammo, pick a weapon to change to.
254   //
255   // killough 3/22/98: for old demos we do the switch here and now;
256   // for Boom games we cannot do this, and have different player
257   // preferences across demos or networks, so we have to use the
258   // G_BuildTiccmd() interface instead of making the switch here.
259 
260   if (demo_compatibility)
261     {
262       player->pendingweapon = P_SwitchWeapon(player);      // phares
263       // Now set appropriate weapon overlay.
264       P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate);
265     }
266 
267   return false;
268 }
269 
270 //
271 // P_FireWeapon.
272 //
273 
P_FireWeapon(player_t * player)274 static void P_FireWeapon(player_t *player)
275 {
276   statenum_t newstate;
277 
278   if (!P_CheckAmmo(player))
279     return;
280 
281   P_SetMobjState(player->mo, S_PLAY_ATK1);
282   newstate = weaponinfo[player->readyweapon].atkstate;
283   P_SetPsprite(player, ps_weapon, newstate);
284   P_NoiseAlert(player->mo, player->mo);
285 }
286 
287 //
288 // P_DropWeapon
289 // Player died, so put the weapon away.
290 //
291 
P_DropWeapon(player_t * player)292 void P_DropWeapon(player_t *player)
293 {
294   P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);
295 }
296 
297 //
298 // A_WeaponReady
299 // The player can fire the weapon
300 // or change to another weapon at this time.
301 // Follows after getting weapon up,
302 // or after previous attack/fire sequence.
303 //
304 
A_WeaponReady(player_t * player,pspdef_t * psp)305 void A_WeaponReady(player_t *player, pspdef_t *psp)
306 {
307   // get out of attack state
308   if (player->mo->state == &states[S_PLAY_ATK1]
309       || player->mo->state == &states[S_PLAY_ATK2] )
310     P_SetMobjState(player->mo, S_PLAY);
311 
312   if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW])
313     S_StartSound(player->mo, sfx_sawidl);
314 
315   // check for change
316   //  if player is dead, put the weapon away
317 
318   if (player->pendingweapon != wp_nochange || !player->health)
319     {
320       // change weapon (pending weapon should already be validated)
321       statenum_t newstate = weaponinfo[player->readyweapon].downstate;
322       P_SetPsprite(player, ps_weapon, newstate);
323       return;
324     }
325 
326   // check for fire
327   //  the missile launcher and bfg do not auto fire
328 
329   if (player->cmd.buttons & BT_ATTACK)
330     {
331       if (!player->attackdown || (player->readyweapon != wp_missile &&
332                                   player->readyweapon != wp_bfg))
333         {
334           player->attackdown = true;
335           P_FireWeapon(player);
336           return;
337         }
338     }
339   else
340     player->attackdown = false;
341 
342   // bob the weapon based on movement speed
343   {
344     int angle = (128*leveltime) & FINEMASK;
345     psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
346     angle &= FINEANGLES/2-1;
347     psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
348   }
349 }
350 
351 //
352 // A_ReFire
353 // The player can re-fire the weapon
354 // without lowering it entirely.
355 //
356 
A_ReFire(player_t * player,pspdef_t * psp)357 void A_ReFire(player_t *player, pspdef_t *psp)
358 {
359   // check for fire
360   //  (if a weaponchange is pending, let it go through instead)
361 
362   if ( (player->cmd.buttons & BT_ATTACK)
363        && player->pendingweapon == wp_nochange && player->health)
364     {
365       player->refire++;
366       P_FireWeapon(player);
367     }
368   else
369     {
370       player->refire = 0;
371       P_CheckAmmo(player);
372     }
373 }
374 
A_CheckReload(player_t * player,pspdef_t * psp)375 void A_CheckReload(player_t *player, pspdef_t *psp)
376 {
377   if (!P_CheckAmmo(player) && compatibility_level >= prboom_4_compatibility) {
378     /* cph 2002/08/08 - In old Doom, P_CheckAmmo would start the weapon lowering
379      * immediately. This was lost in Boom when the weapon switching logic was
380      * rewritten. But we must tell Doom that we don't need to complete the
381      * reload frames for the weapon here. G_BuildTiccmd will set ->pendingweapon
382      * for us later on. */
383     P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate);
384   }
385 }
386 
387 //
388 // A_Lower
389 // Lowers current weapon,
390 //  and changes weapon at bottom.
391 //
392 
A_Lower(player_t * player,pspdef_t * psp)393 void A_Lower(player_t *player, pspdef_t *psp)
394 {
395   psp->sy += LOWERSPEED;
396 
397   // Is already down.
398   if (psp->sy < WEAPONBOTTOM)
399     return;
400 
401   // Player is dead.
402   if (player->playerstate == PST_DEAD)
403     {
404       psp->sy = WEAPONBOTTOM;
405       return;      // don't bring weapon back up
406     }
407 
408   // The old weapon has been lowered off the screen,
409   // so change the weapon and start raising it
410 
411   if (!player->health)
412     {      // Player is dead, so keep the weapon off screen.
413       P_SetPsprite(player,  ps_weapon, S_NULL);
414       return;
415     }
416 
417   player->readyweapon = player->pendingweapon;
418 
419   P_BringUpWeapon(player);
420 }
421 
422 //
423 // A_Raise
424 //
425 
A_Raise(player_t * player,pspdef_t * psp)426 void A_Raise(player_t *player, pspdef_t *psp)
427 {
428   statenum_t newstate;
429 
430   psp->sy -= RAISESPEED;
431 
432   if (psp->sy > WEAPONTOP)
433     return;
434 
435   psp->sy = WEAPONTOP;
436 
437   // The weapon has been raised all the way,
438   //  so change to the ready state.
439 
440   newstate = weaponinfo[player->readyweapon].readystate;
441 
442   P_SetPsprite(player, ps_weapon, newstate);
443 }
444 
445 
446 // Weapons now recoil, amount depending on the weapon.              // phares
447 //                                                                  //   |
448 // The P_SetPsprite call in each of the weapon firing routines      //   V
449 // was moved here so the recoil could be synched with the
450 // muzzle flash, rather than the pressing of the trigger.
451 // The BFG delay caused this to be necessary.
452 
A_FireSomething(player_t * player,int adder)453 static void A_FireSomething(player_t* player,int adder)
454 {
455   P_SetPsprite(player, ps_flash,
456                weaponinfo[player->readyweapon].flashstate+adder);
457 
458   // killough 3/27/98: prevent recoil in no-clipping mode
459   if (!(player->mo->flags & MF_NOCLIP))
460     if (!compatibility && weapon_recoil)
461       P_Thrust(player,
462                ANG180+player->mo->angle,                          //   ^
463                2048*recoil_values[player->readyweapon]);          //   |
464 }                                                                 // phares
465 
466 //
467 // A_GunFlash
468 //
469 
A_GunFlash(player_t * player,pspdef_t * psp)470 void A_GunFlash(player_t *player, pspdef_t *psp)
471 {
472   P_SetMobjState(player->mo, S_PLAY_ATK2);
473 
474   A_FireSomething(player,0);                                      // phares
475 }
476 
477 //
478 // WEAPON ATTACKS
479 //
480 
481 //
482 // A_Punch
483 //
484 
A_Punch(player_t * player,pspdef_t * psp)485 void A_Punch(player_t *player, pspdef_t *psp)
486 {
487   angle_t angle;
488   int t, slope, damage = (P_Random(pr_punch)%10+1)<<1;
489 
490   if (player->powers[pw_strength])
491     damage *= 10;
492 
493   angle = player->mo->angle;
494 
495   // killough 5/5/98: remove dependence on order of evaluation:
496   t = P_Random(pr_punchangle);
497   angle += (t - P_Random(pr_punchangle))<<18;
498 
499   /* killough 8/2/98: make autoaiming prefer enemies */
500   if (!mbf_features ||
501       (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND),
502        !linetarget))
503     slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0);
504 
505   P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
506 
507   if (!linetarget)
508     return;
509 
510   S_StartSound(player->mo, sfx_punch);
511 
512   // turn to face target
513 
514   player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y,
515                                       linetarget->x, linetarget->y);
516   R_SmoothPlaying_Reset(player); // e6y
517 }
518 
519 //
520 // A_Saw
521 //
522 
A_Saw(player_t * player,pspdef_t * psp)523 void A_Saw(player_t *player, pspdef_t *psp)
524 {
525   int slope, damage = 2*(P_Random(pr_saw)%10+1);
526   angle_t angle = player->mo->angle;
527   // killough 5/5/98: remove dependence on order of evaluation:
528   int t = P_Random(pr_saw);
529   angle += (t - P_Random(pr_saw))<<18;
530 
531   /* Use meleerange + 1 so that the puff doesn't skip the flash
532    * killough 8/2/98: make autoaiming prefer enemies */
533   if (!mbf_features ||
534       (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND),
535        !linetarget))
536     slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0);
537 
538   P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage);
539 
540   if (!linetarget)
541     {
542       S_StartSound(player->mo, sfx_sawful);
543       return;
544     }
545 
546   S_StartSound(player->mo, sfx_sawhit);
547 
548   // turn to face target
549   angle = R_PointToAngle2(player->mo->x, player->mo->y,
550                           linetarget->x, linetarget->y);
551 
552   if (angle - player->mo->angle > ANG180) {
553     if (angle - player->mo->angle < -ANG90/20)
554       player->mo->angle = angle + ANG90/21;
555     else
556       player->mo->angle -= ANG90/20;
557   } else {
558     if (angle - player->mo->angle > ANG90/20)
559       player->mo->angle = angle - ANG90/21;
560     else
561       player->mo->angle += ANG90/20;
562   }
563 
564   player->mo->flags |= MF_JUSTATTACKED;
565   R_SmoothPlaying_Reset(player); // e6y
566 }
567 
568 //
569 // A_FireMissile
570 //
571 
A_FireMissile(player_t * player,pspdef_t * psp)572 void A_FireMissile(player_t *player, pspdef_t *psp)
573 {
574   player->ammo[weaponinfo[player->readyweapon].ammo]--;
575   P_SpawnPlayerMissile(player->mo, MT_ROCKET);
576 }
577 
578 //
579 // A_FireBFG
580 //
581 
A_FireBFG(player_t * player,pspdef_t * psp)582 void A_FireBFG(player_t *player, pspdef_t *psp)
583 {
584   player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
585   P_SpawnPlayerMissile(player->mo, MT_BFG);
586 }
587 
588 //
589 // A_FirePlasma
590 //
591 
A_FirePlasma(player_t * player,pspdef_t * psp)592 void A_FirePlasma(player_t *player, pspdef_t *psp)
593 {
594   player->ammo[weaponinfo[player->readyweapon].ammo]--;
595 
596   A_FireSomething(player,P_Random(pr_plasma)&1);              // phares
597   P_SpawnPlayerMissile(player->mo, MT_PLASMA);
598 }
599 
600 //
601 // P_BulletSlope
602 // Sets a slope so a near miss is at aproximately
603 // the height of the intended target
604 //
605 
606 static fixed_t bulletslope;
607 
P_BulletSlope(mobj_t * mo)608 static void P_BulletSlope(mobj_t *mo)
609 {
610   angle_t an = mo->angle;    // see which target is to be aimed at
611 
612   /* killough 8/2/98: make autoaiming prefer enemies */
613   uint_64_t mask = mbf_features ? MF_FRIEND : 0;
614 
615   do
616     {
617       bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask);
618       if (!linetarget)
619   bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask);
620       if (!linetarget)
621   bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask);
622     }
623   while (mask && (mask=0, !linetarget));  /* killough 8/2/98 */
624 }
625 
626 //
627 // P_GunShot
628 //
629 
P_GunShot(mobj_t * mo,boolean accurate)630 static void P_GunShot(mobj_t *mo, boolean accurate)
631 {
632   int damage = 5*(P_Random(pr_gunshot)%3+1);
633   angle_t angle = mo->angle;
634 
635   if (!accurate)
636     {  // killough 5/5/98: remove dependence on order of evaluation:
637       int t = P_Random(pr_misfire);
638       angle += (t - P_Random(pr_misfire))<<18;
639     }
640 
641   P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
642 }
643 
644 //
645 // A_FirePistol
646 //
647 
A_FirePistol(player_t * player,pspdef_t * psp)648 void A_FirePistol(player_t *player, pspdef_t *psp)
649 {
650   S_StartSound(player->mo, sfx_pistol);
651 
652   P_SetMobjState(player->mo, S_PLAY_ATK2);
653   player->ammo[weaponinfo[player->readyweapon].ammo]--;
654 
655   A_FireSomething(player,0);                                      // phares
656   P_BulletSlope(player->mo);
657   P_GunShot(player->mo, !player->refire);
658 }
659 
660 //
661 // A_FireShotgun
662 //
663 
A_FireShotgun(player_t * player,pspdef_t * psp)664 void A_FireShotgun(player_t *player, pspdef_t *psp)
665 {
666   int i;
667 
668   S_StartSound(player->mo, sfx_shotgn);
669   P_SetMobjState(player->mo, S_PLAY_ATK2);
670 
671   player->ammo[weaponinfo[player->readyweapon].ammo]--;
672 
673   A_FireSomething(player,0);                                      // phares
674 
675   P_BulletSlope(player->mo);
676 
677   for (i=0; i<7; i++)
678     P_GunShot(player->mo, false);
679 }
680 
681 //
682 // A_FireShotgun2
683 //
684 
A_FireShotgun2(player_t * player,pspdef_t * psp)685 void A_FireShotgun2(player_t *player, pspdef_t *psp)
686 {
687   int i;
688 
689   S_StartSound(player->mo, sfx_dshtgn);
690   P_SetMobjState(player->mo, S_PLAY_ATK2);
691   player->ammo[weaponinfo[player->readyweapon].ammo] -= 2;
692 
693   A_FireSomething(player,0);                                      // phares
694 
695   P_BulletSlope(player->mo);
696 
697   for (i=0; i<20; i++)
698     {
699       int damage = 5*(P_Random(pr_shotgun)%3+1);
700       angle_t angle = player->mo->angle;
701       // killough 5/5/98: remove dependence on order of evaluation:
702       int t = P_Random(pr_shotgun);
703       angle += (t - P_Random(pr_shotgun))<<19;
704       t = P_Random(pr_shotgun);
705       P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope +
706                    ((t - P_Random(pr_shotgun))<<5), damage);
707     }
708 }
709 
710 //
711 // A_FireCGun
712 //
713 
A_FireCGun(player_t * player,pspdef_t * psp)714 void A_FireCGun(player_t *player, pspdef_t *psp)
715 {
716   if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound])
717     S_StartSound(player->mo, sfx_pistol);
718 
719   if (!player->ammo[weaponinfo[player->readyweapon].ammo])
720     return;
721 
722   P_SetMobjState(player->mo, S_PLAY_ATK2);
723   player->ammo[weaponinfo[player->readyweapon].ammo]--;
724 
725   A_FireSomething(player,psp->state - &states[S_CHAIN1]);           // phares
726 
727   P_BulletSlope(player->mo);
728 
729   P_GunShot(player->mo, !player->refire);
730 }
731 
A_Light0(player_t * player,pspdef_t * psp)732 void A_Light0(player_t *player, pspdef_t *psp)
733 {
734   player->extralight = 0;
735 }
736 
A_Light1(player_t * player,pspdef_t * psp)737 void A_Light1 (player_t *player, pspdef_t *psp)
738 {
739   player->extralight = 1;
740 }
741 
A_Light2(player_t * player,pspdef_t * psp)742 void A_Light2 (player_t *player, pspdef_t *psp)
743 {
744   player->extralight = 2;
745 }
746 
747 //
748 // A_BFGSpray
749 // Spawn a BFG explosion on every monster in view
750 //
751 
A_BFGSpray(mobj_t * mo)752 void A_BFGSpray(mobj_t *mo)
753 {
754   int i;
755 
756   for (i=0 ; i<40 ; i++)  // offset angles from its attack angle
757     {
758       int j, damage;
759       angle_t an = mo->angle - ANG90/2 + ANG90/40*i;
760 
761       // mo->target is the originator (player) of the missile
762 
763       // killough 8/2/98: make autoaiming prefer enemies
764       if (!mbf_features ||
765          (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND),
766          !linetarget))
767         P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0);
768 
769       if (!linetarget)
770         continue;
771 
772       P_SpawnMobj(linetarget->x, linetarget->y,
773                   linetarget->z + (linetarget->height>>2), MT_EXTRABFG);
774 
775       for (damage=j=0; j<15; j++)
776         damage += (P_Random(pr_bfg)&7) + 1;
777 
778       P_DamageMobj(linetarget, mo->target, mo->target, damage);
779     }
780 }
781 
782 //
783 // A_BFGsound
784 //
785 
A_BFGsound(player_t * player,pspdef_t * psp)786 void A_BFGsound(player_t *player, pspdef_t *psp)
787 {
788   S_StartSound(player->mo, sfx_bfg);
789 }
790 
791 //
792 // P_SetupPsprites
793 // Called at start of level for each player.
794 //
795 
P_SetupPsprites(player_t * player)796 void P_SetupPsprites(player_t *player)
797 {
798   int i;
799 
800   // remove all psprites
801   for (i=0; i<NUMPSPRITES; i++)
802     player->psprites[i].state = NULL;
803 
804   // spawn the gun
805   player->pendingweapon = player->readyweapon;
806   P_BringUpWeapon(player);
807 }
808 
809 //
810 // P_MovePsprites
811 // Called every tic by player thinking routine.
812 //
813 
P_MovePsprites(player_t * player)814 void P_MovePsprites(player_t *player)
815 {
816   pspdef_t *psp = player->psprites;
817   int i;
818 
819   // a null state means not active
820   // drop tic count and possibly change state
821   // a -1 tic count never changes
822 
823   for (i=0; i<NUMPSPRITES; i++, psp++)
824     if (psp->state && psp->tics != -1 && !--psp->tics)
825       P_SetPsprite(player, i, psp->state->nextstate);
826 
827   player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
828   player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
829 }
830