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