aboutsummaryrefslogtreecommitdiff
path: root/src/p_pspr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/p_pspr.c')
-rw-r--r--src/p_pspr.c829
1 files changed, 829 insertions, 0 deletions
diff --git a/src/p_pspr.c b/src/p_pspr.c
new file mode 100644
index 0000000..afac1fc
--- /dev/null
+++ b/src/p_pspr.c
@@ -0,0 +1,829 @@
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
54extern void P_Thrust(player_t *, angle_t, fixed_t);
55
56// The following array holds the recoil values // phares
57
58static 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
74static 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
120static 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
145int 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
156int 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.
215int 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
236boolean 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
274static 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
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 // 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
375void 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
393void 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
426void 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
453static 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
470void 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
485void 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
523void 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
572void 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
582void 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
592void 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
606static fixed_t bulletslope;
607
608static 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
630static 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
648void 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
664void 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
685void 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
714void 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
732void A_Light0(player_t *player, pspdef_t *psp)
733{
734 player->extralight = 0;
735}
736
737void A_Light1 (player_t *player, pspdef_t *psp)
738{
739 player->extralight = 1;
740}
741
742void 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
752void 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
786void 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
796void 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
814void 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}