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