1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 1993-2008 Raven Software
4 // Copyright(C) 2005-2014 Simon Howard
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 
17 // P_pspr.c
18 
19 #include "doomdef.h"
20 #include "i_system.h"
21 #include "m_random.h"
22 #include "p_local.h"
23 #include "s_sound.h"
24 
25 // Macros
26 
27 #define LOWERSPEED FRACUNIT*6
28 #define RAISESPEED FRACUNIT*6
29 #define WEAPONBOTTOM 128*FRACUNIT
30 #define WEAPONTOP 32*FRACUNIT
31 #define FLAME_THROWER_TICS 10*35
32 #define MAGIC_JUNK 1234
33 #define MAX_MACE_SPOTS 8
34 
35 static int MaceSpotCount;
36 static struct
37 {
38     fixed_t x;
39     fixed_t y;
40 } MaceSpots[MAX_MACE_SPOTS];
41 
42 fixed_t bulletslope;
43 
44 static int WeaponAmmoUsePL1[NUMWEAPONS] = {
45     0,                          // staff
46     USE_GWND_AMMO_1,            // gold wand
47     USE_CBOW_AMMO_1,            // crossbow
48     USE_BLSR_AMMO_1,            // blaster
49     USE_SKRD_AMMO_1,            // skull rod
50     USE_PHRD_AMMO_1,            // phoenix rod
51     USE_MACE_AMMO_1,            // mace
52     0,                          // gauntlets
53     0                           // beak
54 };
55 
56 static int WeaponAmmoUsePL2[NUMWEAPONS] = {
57     0,                          // staff
58     USE_GWND_AMMO_2,            // gold wand
59     USE_CBOW_AMMO_2,            // crossbow
60     USE_BLSR_AMMO_2,            // blaster
61     USE_SKRD_AMMO_2,            // skull rod
62     USE_PHRD_AMMO_2,            // phoenix rod
63     USE_MACE_AMMO_2,            // mace
64     0,                          // gauntlets
65     0                           // beak
66 };
67 
68 weaponinfo_t wpnlev1info[NUMWEAPONS] = {
69     {                           // Staff
70      am_noammo,                 // ammo
71      S_STAFFUP,                 // upstate
72      S_STAFFDOWN,               // downstate
73      S_STAFFREADY,              // readystate
74      S_STAFFATK1_1,             // atkstate
75      S_STAFFATK1_1,             // holdatkstate
76      S_NULL                     // flashstate
77      },
78     {                           // Gold wand
79      am_goldwand,               // ammo
80      S_GOLDWANDUP,              // upstate
81      S_GOLDWANDDOWN,            // downstate
82      S_GOLDWANDREADY,           // readystate
83      S_GOLDWANDATK1_1,          // atkstate
84      S_GOLDWANDATK1_1,          // holdatkstate
85      S_NULL                     // flashstate
86      },
87     {                           // Crossbow
88      am_crossbow,               // ammo
89      S_CRBOWUP,                 // upstate
90      S_CRBOWDOWN,               // downstate
91      S_CRBOW1,                  // readystate
92      S_CRBOWATK1_1,             // atkstate
93      S_CRBOWATK1_1,             // holdatkstate
94      S_NULL                     // flashstate
95      },
96     {                           // Blaster
97      am_blaster,                // ammo
98      S_BLASTERUP,               // upstate
99      S_BLASTERDOWN,             // downstate
100      S_BLASTERREADY,            // readystate
101      S_BLASTERATK1_1,           // atkstate
102      S_BLASTERATK1_3,           // holdatkstate
103      S_NULL                     // flashstate
104      },
105     {                           // Skull rod
106      am_skullrod,               // ammo
107      S_HORNRODUP,               // upstate
108      S_HORNRODDOWN,             // downstate
109      S_HORNRODREADY,            // readystae
110      S_HORNRODATK1_1,           // atkstate
111      S_HORNRODATK1_1,           // holdatkstate
112      S_NULL                     // flashstate
113      },
114     {                           // Phoenix rod
115      am_phoenixrod,             // ammo
116      S_PHOENIXUP,               // upstate
117      S_PHOENIXDOWN,             // downstate
118      S_PHOENIXREADY,            // readystate
119      S_PHOENIXATK1_1,           // atkstate
120      S_PHOENIXATK1_1,           // holdatkstate
121      S_NULL                     // flashstate
122      },
123     {                           // Mace
124      am_mace,                   // ammo
125      S_MACEUP,                  // upstate
126      S_MACEDOWN,                // downstate
127      S_MACEREADY,               // readystate
128      S_MACEATK1_1,              // atkstate
129      S_MACEATK1_2,              // holdatkstate
130      S_NULL                     // flashstate
131      },
132     {                           // Gauntlets
133      am_noammo,                 // ammo
134      S_GAUNTLETUP,              // upstate
135      S_GAUNTLETDOWN,            // downstate
136      S_GAUNTLETREADY,           // readystate
137      S_GAUNTLETATK1_1,          // atkstate
138      S_GAUNTLETATK1_3,          // holdatkstate
139      S_NULL                     // flashstate
140      },
141     {                           // Beak
142      am_noammo,                 // ammo
143      S_BEAKUP,                  // upstate
144      S_BEAKDOWN,                // downstate
145      S_BEAKREADY,               // readystate
146      S_BEAKATK1_1,              // atkstate
147      S_BEAKATK1_1,              // holdatkstate
148      S_NULL                     // flashstate
149      }
150 };
151 
152 weaponinfo_t wpnlev2info[NUMWEAPONS] = {
153     {                           // Staff
154      am_noammo,                 // ammo
155      S_STAFFUP2,                // upstate
156      S_STAFFDOWN2,              // downstate
157      S_STAFFREADY2_1,           // readystate
158      S_STAFFATK2_1,             // atkstate
159      S_STAFFATK2_1,             // holdatkstate
160      S_NULL                     // flashstate
161      },
162     {                           // Gold wand
163      am_goldwand,               // ammo
164      S_GOLDWANDUP,              // upstate
165      S_GOLDWANDDOWN,            // downstate
166      S_GOLDWANDREADY,           // readystate
167      S_GOLDWANDATK2_1,          // atkstate
168      S_GOLDWANDATK2_1,          // holdatkstate
169      S_NULL                     // flashstate
170      },
171     {                           // Crossbow
172      am_crossbow,               // ammo
173      S_CRBOWUP,                 // upstate
174      S_CRBOWDOWN,               // downstate
175      S_CRBOW1,                  // readystate
176      S_CRBOWATK2_1,             // atkstate
177      S_CRBOWATK2_1,             // holdatkstate
178      S_NULL                     // flashstate
179      },
180     {                           // Blaster
181      am_blaster,                // ammo
182      S_BLASTERUP,               // upstate
183      S_BLASTERDOWN,             // downstate
184      S_BLASTERREADY,            // readystate
185      S_BLASTERATK2_1,           // atkstate
186      S_BLASTERATK2_3,           // holdatkstate
187      S_NULL                     // flashstate
188      },
189     {                           // Skull rod
190      am_skullrod,               // ammo
191      S_HORNRODUP,               // upstate
192      S_HORNRODDOWN,             // downstate
193      S_HORNRODREADY,            // readystae
194      S_HORNRODATK2_1,           // atkstate
195      S_HORNRODATK2_1,           // holdatkstate
196      S_NULL                     // flashstate
197      },
198     {                           // Phoenix rod
199      am_phoenixrod,             // ammo
200      S_PHOENIXUP,               // upstate
201      S_PHOENIXDOWN,             // downstate
202      S_PHOENIXREADY,            // readystate
203      S_PHOENIXATK2_1,           // atkstate
204      S_PHOENIXATK2_2,           // holdatkstate
205      S_NULL                     // flashstate
206      },
207     {                           // Mace
208      am_mace,                   // ammo
209      S_MACEUP,                  // upstate
210      S_MACEDOWN,                // downstate
211      S_MACEREADY,               // readystate
212      S_MACEATK2_1,              // atkstate
213      S_MACEATK2_1,              // holdatkstate
214      S_NULL                     // flashstate
215      },
216     {                           // Gauntlets
217      am_noammo,                 // ammo
218      S_GAUNTLETUP2,             // upstate
219      S_GAUNTLETDOWN2,           // downstate
220      S_GAUNTLETREADY2_1,        // readystate
221      S_GAUNTLETATK2_1,          // atkstate
222      S_GAUNTLETATK2_3,          // holdatkstate
223      S_NULL                     // flashstate
224      },
225     {                           // Beak
226      am_noammo,                 // ammo
227      S_BEAKUP,                  // upstate
228      S_BEAKDOWN,                // downstate
229      S_BEAKREADY,               // readystate
230      S_BEAKATK2_1,              // atkstate
231      S_BEAKATK2_1,              // holdatkstate
232      S_NULL                     // flashstate
233      }
234 };
235 
236 //---------------------------------------------------------------------------
237 //
238 // PROC P_OpenWeapons
239 //
240 // Called at level load before things are loaded.
241 //
242 //---------------------------------------------------------------------------
243 
P_OpenWeapons(void)244 void P_OpenWeapons(void)
245 {
246     MaceSpotCount = 0;
247 }
248 
249 //---------------------------------------------------------------------------
250 //
251 // PROC P_AddMaceSpot
252 //
253 //---------------------------------------------------------------------------
254 
P_AddMaceSpot(mapthing_t * mthing)255 void P_AddMaceSpot(mapthing_t * mthing)
256 {
257     if (MaceSpotCount == MAX_MACE_SPOTS)
258     {
259         I_Error("Too many mace spots.");
260     }
261     MaceSpots[MaceSpotCount].x = mthing->x << FRACBITS;
262     MaceSpots[MaceSpotCount].y = mthing->y << FRACBITS;
263     MaceSpotCount++;
264 }
265 
266 //---------------------------------------------------------------------------
267 //
268 // PROC P_RepositionMace
269 //
270 // Chooses the next spot to place the mace.
271 //
272 //---------------------------------------------------------------------------
273 
P_RepositionMace(mobj_t * mo)274 void P_RepositionMace(mobj_t * mo)
275 {
276     int spot;
277     subsector_t *ss;
278 
279     P_UnsetThingPosition(mo);
280     spot = P_Random() % MaceSpotCount;
281     mo->x = MaceSpots[spot].x;
282     mo->y = MaceSpots[spot].y;
283     ss = R_PointInSubsector(mo->x, mo->y);
284     mo->z = mo->floorz = ss->sector->floorheight;
285     mo->ceilingz = ss->sector->ceilingheight;
286     P_SetThingPosition(mo);
287 }
288 
289 //---------------------------------------------------------------------------
290 //
291 // PROC P_CloseWeapons
292 //
293 // Called at level load after things are loaded.
294 //
295 //---------------------------------------------------------------------------
296 
P_CloseWeapons(void)297 void P_CloseWeapons(void)
298 {
299     int spot;
300 
301     if (!MaceSpotCount)
302     {                           // No maces placed
303         return;
304     }
305     if (!deathmatch && P_Random() < 64)
306     {                           // Sometimes doesn't show up if not in deathmatch
307         return;
308     }
309     spot = P_Random() % MaceSpotCount;
310     P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE);
311 }
312 
313 //---------------------------------------------------------------------------
314 //
315 // PROC P_SetPsprite
316 //
317 //---------------------------------------------------------------------------
318 
P_SetPsprite(player_t * player,int position,statenum_t stnum)319 void P_SetPsprite(player_t * player, int position, statenum_t stnum)
320 {
321     pspdef_t *psp;
322     state_t *state;
323 
324     psp = &player->psprites[position];
325     do
326     {
327         if (!stnum)
328         {                       // Object removed itself.
329             psp->state = NULL;
330             break;
331         }
332         state = &states[stnum];
333         psp->state = state;
334         psp->tics = state->tics;        // could be 0
335         if (state->misc1)
336         {                       // Set coordinates.
337             psp->sx = state->misc1 << FRACBITS;
338             psp->sy = state->misc2 << FRACBITS;
339         }
340         if (state->action)
341         {                       // Call action routine.
342             state->action(player, psp);
343             if (!psp->state)
344             {
345                 break;
346             }
347         }
348         stnum = psp->state->nextstate;
349     }
350     while (!psp->tics);         // An initial state of 0 could cycle through.
351 }
352 
353 /*
354 =================
355 =
356 = P_CalcSwing
357 =
358 =================
359 */
360 
361 /*
362 fixed_t	swingx, swingy;
363 void P_CalcSwing (player_t *player)
364 {
365 	fixed_t	swing;
366 	int		angle;
367 
368 // OPTIMIZE: tablify this
369 
370 	swing = player->bob;
371 
372 	angle = (FINEANGLES/70*leveltime)&FINEMASK;
373 	swingx = FixedMul ( swing, finesine[angle]);
374 
375 	angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
376 	swingy = -FixedMul ( swingx, finesine[angle]);
377 }
378 */
379 
380 //---------------------------------------------------------------------------
381 //
382 // PROC P_ActivateBeak
383 //
384 //---------------------------------------------------------------------------
385 
P_ActivateBeak(player_t * player)386 void P_ActivateBeak(player_t * player)
387 {
388     player->pendingweapon = wp_nochange;
389     player->readyweapon = wp_beak;
390     player->psprites[ps_weapon].sy = WEAPONTOP;
391     P_SetPsprite(player, ps_weapon, S_BEAKREADY);
392 }
393 
394 //---------------------------------------------------------------------------
395 //
396 // PROC P_PostChickenWeapon
397 //
398 //---------------------------------------------------------------------------
399 
P_PostChickenWeapon(player_t * player,weapontype_t weapon)400 void P_PostChickenWeapon(player_t * player, weapontype_t weapon)
401 {
402     if (weapon == wp_beak)
403     {                           // Should never happen
404         weapon = wp_staff;
405     }
406     player->pendingweapon = wp_nochange;
407     player->readyweapon = weapon;
408     player->psprites[ps_weapon].sy = WEAPONBOTTOM;
409     P_SetPsprite(player, ps_weapon, wpnlev1info[weapon].upstate);
410 }
411 
412 //---------------------------------------------------------------------------
413 //
414 // PROC P_BringUpWeapon
415 //
416 // Starts bringing the pending weapon up from the bottom of the screen.
417 //
418 //---------------------------------------------------------------------------
419 
P_BringUpWeapon(player_t * player)420 void P_BringUpWeapon(player_t * player)
421 {
422     statenum_t new;
423 
424     if (player->pendingweapon == wp_nochange)
425     {
426         player->pendingweapon = player->readyweapon;
427     }
428     if (player->pendingweapon == wp_gauntlets)
429     {
430         S_StartSound(player->mo, sfx_gntact);
431     }
432     if (player->powers[pw_weaponlevel2])
433     {
434         new = wpnlev2info[player->pendingweapon].upstate;
435     }
436     else
437     {
438         new = wpnlev1info[player->pendingweapon].upstate;
439     }
440     player->pendingweapon = wp_nochange;
441     player->psprites[ps_weapon].sy = WEAPONBOTTOM;
442     P_SetPsprite(player, ps_weapon, new);
443 }
444 
445 //---------------------------------------------------------------------------
446 //
447 // FUNC P_CheckAmmo
448 //
449 // Returns true if there is enough ammo to shoot.  If not, selects the
450 // next weapon to use.
451 //
452 //---------------------------------------------------------------------------
453 
P_CheckAmmo(player_t * player)454 boolean P_CheckAmmo(player_t * player)
455 {
456     ammotype_t ammo;
457     int *ammoUse;
458     int count;
459 
460     ammo = wpnlev1info[player->readyweapon].ammo;
461     if (player->powers[pw_weaponlevel2] && !deathmatch)
462     {
463         ammoUse = WeaponAmmoUsePL2;
464     }
465     else
466     {
467         ammoUse = WeaponAmmoUsePL1;
468     }
469     count = ammoUse[player->readyweapon];
470     if (ammo == am_noammo || player->ammo[ammo] >= count)
471     {
472         return (true);
473     }
474     // out of ammo, pick a weapon to change to
475     do
476     {
477         if (player->weaponowned[wp_skullrod]
478             && player->ammo[am_skullrod] > ammoUse[wp_skullrod])
479         {
480             player->pendingweapon = wp_skullrod;
481         }
482         else if (player->weaponowned[wp_blaster]
483                  && player->ammo[am_blaster] > ammoUse[wp_blaster])
484         {
485             player->pendingweapon = wp_blaster;
486         }
487         else if (player->weaponowned[wp_crossbow]
488                  && player->ammo[am_crossbow] > ammoUse[wp_crossbow])
489         {
490             player->pendingweapon = wp_crossbow;
491         }
492         else if (player->weaponowned[wp_mace]
493                  && player->ammo[am_mace] > ammoUse[wp_mace])
494         {
495             player->pendingweapon = wp_mace;
496         }
497         else if (player->ammo[am_goldwand] > ammoUse[wp_goldwand])
498         {
499             player->pendingweapon = wp_goldwand;
500         }
501         else if (player->weaponowned[wp_gauntlets])
502         {
503             player->pendingweapon = wp_gauntlets;
504         }
505         else if (player->weaponowned[wp_phoenixrod]
506                  && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod])
507         {
508             player->pendingweapon = wp_phoenixrod;
509         }
510         else
511         {
512             player->pendingweapon = wp_staff;
513         }
514     }
515     while (player->pendingweapon == wp_nochange);
516     if (player->powers[pw_weaponlevel2])
517     {
518         P_SetPsprite(player, ps_weapon,
519                      wpnlev2info[player->readyweapon].downstate);
520     }
521     else
522     {
523         P_SetPsprite(player, ps_weapon,
524                      wpnlev1info[player->readyweapon].downstate);
525     }
526     return (false);
527 }
528 
529 //---------------------------------------------------------------------------
530 //
531 // PROC P_FireWeapon
532 //
533 //---------------------------------------------------------------------------
534 
P_FireWeapon(player_t * player)535 void P_FireWeapon(player_t * player)
536 {
537     weaponinfo_t *wpinfo;
538     statenum_t attackState;
539 
540     if (!P_CheckAmmo(player))
541     {
542         return;
543     }
544     P_SetMobjState(player->mo, S_PLAY_ATK2);
545     wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[0]
546         : &wpnlev1info[0];
547     attackState = player->refire ? wpinfo[player->readyweapon].holdatkstate
548         : wpinfo[player->readyweapon].atkstate;
549     P_SetPsprite(player, ps_weapon, attackState);
550     P_NoiseAlert(player->mo, player->mo);
551     if (player->readyweapon == wp_gauntlets && !player->refire)
552     {                           // Play the sound for the initial gauntlet attack
553         S_StartSound(player->mo, sfx_gntuse);
554     }
555 }
556 
557 //---------------------------------------------------------------------------
558 //
559 // PROC P_DropWeapon
560 //
561 // The player died, so put the weapon away.
562 //
563 //---------------------------------------------------------------------------
564 
P_DropWeapon(player_t * player)565 void P_DropWeapon(player_t * player)
566 {
567     if (player->powers[pw_weaponlevel2])
568     {
569         P_SetPsprite(player, ps_weapon,
570                      wpnlev2info[player->readyweapon].downstate);
571     }
572     else
573     {
574         P_SetPsprite(player, ps_weapon,
575                      wpnlev1info[player->readyweapon].downstate);
576     }
577 }
578 
579 //---------------------------------------------------------------------------
580 //
581 // PROC A_WeaponReady
582 //
583 // The player can fire the weapon or change to another weapon at this time.
584 //
585 //---------------------------------------------------------------------------
586 
A_WeaponReady(player_t * player,pspdef_t * psp)587 void A_WeaponReady(player_t * player, pspdef_t * psp)
588 {
589     int angle;
590 
591     if (player->chickenTics)
592     {                           // Change to the chicken beak
593         P_ActivateBeak(player);
594         return;
595     }
596     // Change player from attack state
597     if (player->mo->state == &states[S_PLAY_ATK1]
598         || player->mo->state == &states[S_PLAY_ATK2])
599     {
600         P_SetMobjState(player->mo, S_PLAY);
601     }
602     // Check for staff PL2 active sound
603     if ((player->readyweapon == wp_staff)
604         && (psp->state == &states[S_STAFFREADY2_1]) && P_Random() < 128)
605     {
606         S_StartSound(player->mo, sfx_stfcrk);
607     }
608     // Put the weapon away if the player has a pending weapon or has
609     // died.
610     if (player->pendingweapon != wp_nochange || !player->health)
611     {
612         if (player->powers[pw_weaponlevel2])
613         {
614             P_SetPsprite(player, ps_weapon,
615                          wpnlev2info[player->readyweapon].downstate);
616         }
617         else
618         {
619             P_SetPsprite(player, ps_weapon,
620                          wpnlev1info[player->readyweapon].downstate);
621         }
622         return;
623     }
624 
625     // Check for fire.  The phoenix rod does not auto fire.
626     if (player->cmd.buttons & BT_ATTACK)
627     {
628         if (!player->attackdown || (player->readyweapon != wp_phoenixrod))
629         {
630             player->attackdown = true;
631             P_FireWeapon(player);
632             return;
633         }
634     }
635     else
636     {
637         player->attackdown = false;
638     }
639 
640     // Bob the weapon based on movement speed.
641     angle = (128 * leveltime) & FINEMASK;
642     psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
643     angle &= FINEANGLES / 2 - 1;
644     psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
645 }
646 
647 //---------------------------------------------------------------------------
648 //
649 // PROC P_UpdateBeak
650 //
651 //---------------------------------------------------------------------------
652 
P_UpdateBeak(player_t * player,pspdef_t * psp)653 void P_UpdateBeak(player_t * player, pspdef_t * psp)
654 {
655     psp->sy = WEAPONTOP + (player->chickenPeck << (FRACBITS - 1));
656 }
657 
658 //---------------------------------------------------------------------------
659 //
660 // PROC A_BeakReady
661 //
662 //---------------------------------------------------------------------------
663 
A_BeakReady(player_t * player,pspdef_t * psp)664 void A_BeakReady(player_t * player, pspdef_t * psp)
665 {
666     if (player->cmd.buttons & BT_ATTACK)
667     {                           // Chicken beak attack
668         player->attackdown = true;
669         P_SetMobjState(player->mo, S_CHICPLAY_ATK1);
670         if (player->powers[pw_weaponlevel2])
671         {
672             P_SetPsprite(player, ps_weapon, S_BEAKATK2_1);
673         }
674         else
675         {
676             P_SetPsprite(player, ps_weapon, S_BEAKATK1_1);
677         }
678         P_NoiseAlert(player->mo, player->mo);
679     }
680     else
681     {
682         if (player->mo->state == &states[S_CHICPLAY_ATK1])
683         {                       // Take out of attack state
684             P_SetMobjState(player->mo, S_CHICPLAY);
685         }
686         player->attackdown = false;
687     }
688 }
689 
690 //---------------------------------------------------------------------------
691 //
692 // PROC A_ReFire
693 //
694 // The player can re fire the weapon without lowering it entirely.
695 //
696 //---------------------------------------------------------------------------
697 
A_ReFire(player_t * player,pspdef_t * psp)698 void A_ReFire(player_t * player, pspdef_t * psp)
699 {
700     if ((player->cmd.buttons & BT_ATTACK)
701         && player->pendingweapon == wp_nochange && player->health)
702     {
703         player->refire++;
704         P_FireWeapon(player);
705     }
706     else
707     {
708         player->refire = 0;
709         P_CheckAmmo(player);
710     }
711 }
712 
713 //---------------------------------------------------------------------------
714 //
715 // PROC A_Lower
716 //
717 //---------------------------------------------------------------------------
718 
A_Lower(player_t * player,pspdef_t * psp)719 void A_Lower(player_t * player, pspdef_t * psp)
720 {
721     if (player->chickenTics)
722     {
723         psp->sy = WEAPONBOTTOM;
724     }
725     else
726     {
727         psp->sy += LOWERSPEED;
728     }
729     if (psp->sy < WEAPONBOTTOM)
730     {                           // Not lowered all the way yet
731         return;
732     }
733     if (player->playerstate == PST_DEAD)
734     {                           // Player is dead, so don't bring up a pending weapon
735         psp->sy = WEAPONBOTTOM;
736         return;
737     }
738     if (!player->health)
739     {                           // Player is dead, so keep the weapon off screen
740         P_SetPsprite(player, ps_weapon, S_NULL);
741         return;
742     }
743     player->readyweapon = player->pendingweapon;
744     P_BringUpWeapon(player);
745 }
746 
747 //---------------------------------------------------------------------------
748 //
749 // PROC A_BeakRaise
750 //
751 //---------------------------------------------------------------------------
752 
A_BeakRaise(player_t * player,pspdef_t * psp)753 void A_BeakRaise(player_t * player, pspdef_t * psp)
754 {
755     psp->sy = WEAPONTOP;
756     P_SetPsprite(player, ps_weapon,
757                  wpnlev1info[player->readyweapon].readystate);
758 }
759 
760 //---------------------------------------------------------------------------
761 //
762 // PROC A_Raise
763 //
764 //---------------------------------------------------------------------------
765 
A_Raise(player_t * player,pspdef_t * psp)766 void A_Raise(player_t * player, pspdef_t * psp)
767 {
768     psp->sy -= RAISESPEED;
769     if (psp->sy > WEAPONTOP)
770     {                           // Not raised all the way yet
771         return;
772     }
773     psp->sy = WEAPONTOP;
774     if (player->powers[pw_weaponlevel2])
775     {
776         P_SetPsprite(player, ps_weapon,
777                      wpnlev2info[player->readyweapon].readystate);
778     }
779     else
780     {
781         P_SetPsprite(player, ps_weapon,
782                      wpnlev1info[player->readyweapon].readystate);
783     }
784 }
785 
786 /*
787 ===============
788 =
789 = P_BulletSlope
790 =
791 = Sets a slope so a near miss is at aproximately the height of the
792 = intended target
793 =
794 ===============
795 */
796 
P_BulletSlope(mobj_t * mo)797 void P_BulletSlope(mobj_t * mo)
798 {
799     angle_t an;
800 
801 //
802 // see which target is to be aimed at
803 //
804     an = mo->angle;
805     bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
806     if (!linetarget)
807     {
808         an += 1 << 26;
809         bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
810         if (!linetarget)
811         {
812             an -= 2 << 26;
813             bulletslope = P_AimLineAttack(mo, an, 16 * 64 * FRACUNIT);
814         }
815         if (!linetarget)
816         {
817             an += 2 << 26;
818             bulletslope = (mo->player->lookdir << FRACBITS) / 173;
819         }
820     }
821 }
822 
823 //****************************************************************************
824 //
825 // WEAPON ATTACKS
826 //
827 //****************************************************************************
828 
829 //----------------------------------------------------------------------------
830 //
831 // PROC A_BeakAttackPL1
832 //
833 //----------------------------------------------------------------------------
834 
A_BeakAttackPL1(player_t * player,pspdef_t * psp)835 void A_BeakAttackPL1(player_t * player, pspdef_t * psp)
836 {
837     angle_t angle;
838     int damage;
839     int slope;
840 
841     damage = 1 + (P_Random() & 3);
842     angle = player->mo->angle;
843     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
844     PuffType = MT_BEAKPUFF;
845     P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
846     if (linetarget)
847     {
848         player->mo->angle = R_PointToAngle2(player->mo->x,
849                                             player->mo->y, linetarget->x,
850                                             linetarget->y);
851     }
852     S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
853     player->chickenPeck = 12;
854     psp->tics -= P_Random() & 7;
855 }
856 
857 //----------------------------------------------------------------------------
858 //
859 // PROC A_BeakAttackPL2
860 //
861 //----------------------------------------------------------------------------
862 
A_BeakAttackPL2(player_t * player,pspdef_t * psp)863 void A_BeakAttackPL2(player_t * player, pspdef_t * psp)
864 {
865     angle_t angle;
866     int damage;
867     int slope;
868 
869     damage = HITDICE(4);
870     angle = player->mo->angle;
871     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
872     PuffType = MT_BEAKPUFF;
873     P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
874     if (linetarget)
875     {
876         player->mo->angle = R_PointToAngle2(player->mo->x,
877                                             player->mo->y, linetarget->x,
878                                             linetarget->y);
879     }
880     S_StartSound(player->mo, sfx_chicpk1 + (P_Random() % 3));
881     player->chickenPeck = 12;
882     psp->tics -= P_Random() & 3;
883 }
884 
885 //----------------------------------------------------------------------------
886 //
887 // PROC A_StaffAttackPL1
888 //
889 //----------------------------------------------------------------------------
890 
A_StaffAttackPL1(player_t * player,pspdef_t * psp)891 void A_StaffAttackPL1(player_t * player, pspdef_t * psp)
892 {
893     angle_t angle;
894     int damage;
895     int slope;
896 
897     damage = 5 + (P_Random() & 15);
898     angle = player->mo->angle;
899     angle += P_SubRandom() << 18;
900     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
901     PuffType = MT_STAFFPUFF;
902     P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
903     if (linetarget)
904     {
905         //S_StartSound(player->mo, sfx_stfhit);
906         // turn to face target
907         player->mo->angle = R_PointToAngle2(player->mo->x,
908                                             player->mo->y, linetarget->x,
909                                             linetarget->y);
910     }
911 }
912 
913 //----------------------------------------------------------------------------
914 //
915 // PROC A_StaffAttackPL2
916 //
917 //----------------------------------------------------------------------------
918 
A_StaffAttackPL2(player_t * player,pspdef_t * psp)919 void A_StaffAttackPL2(player_t * player, pspdef_t * psp)
920 {
921     angle_t angle;
922     int damage;
923     int slope;
924 
925     // P_inter.c:P_DamageMobj() handles target momentums
926     damage = 18 + (P_Random() & 63);
927     angle = player->mo->angle;
928     angle += P_SubRandom() << 18;
929     slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
930     PuffType = MT_STAFFPUFF2;
931     P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
932     if (linetarget)
933     {
934         //S_StartSound(player->mo, sfx_stfpow);
935         // turn to face target
936         player->mo->angle = R_PointToAngle2(player->mo->x,
937                                             player->mo->y, linetarget->x,
938                                             linetarget->y);
939     }
940 }
941 
942 //----------------------------------------------------------------------------
943 //
944 // PROC A_FireBlasterPL1
945 //
946 //----------------------------------------------------------------------------
947 
A_FireBlasterPL1(player_t * player,pspdef_t * psp)948 void A_FireBlasterPL1(player_t * player, pspdef_t * psp)
949 {
950     mobj_t *mo;
951     angle_t angle;
952     int damage;
953 
954     mo = player->mo;
955     S_StartSound(mo, sfx_gldhit);
956     player->ammo[am_blaster] -= USE_BLSR_AMMO_1;
957     P_BulletSlope(mo);
958     damage = HITDICE(4);
959     angle = mo->angle;
960     if (player->refire)
961     {
962         angle += P_SubRandom() << 18;
963     }
964     PuffType = MT_BLASTERPUFF1;
965     P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
966     S_StartSound(player->mo, sfx_blssht);
967 }
968 
969 //----------------------------------------------------------------------------
970 //
971 // PROC A_FireBlasterPL2
972 //
973 //----------------------------------------------------------------------------
974 
A_FireBlasterPL2(player_t * player,pspdef_t * psp)975 void A_FireBlasterPL2(player_t * player, pspdef_t * psp)
976 {
977     mobj_t *mo;
978 
979     player->ammo[am_blaster] -=
980         deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2;
981     mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1);
982     if (mo)
983     {
984         mo->thinker.function = P_BlasterMobjThinker;
985     }
986     S_StartSound(player->mo, sfx_blssht);
987 }
988 
989 //----------------------------------------------------------------------------
990 //
991 // PROC A_FireGoldWandPL1
992 //
993 //----------------------------------------------------------------------------
994 
A_FireGoldWandPL1(player_t * player,pspdef_t * psp)995 void A_FireGoldWandPL1(player_t * player, pspdef_t * psp)
996 {
997     mobj_t *mo;
998     angle_t angle;
999     int damage;
1000 
1001     mo = player->mo;
1002     player->ammo[am_goldwand] -= USE_GWND_AMMO_1;
1003     P_BulletSlope(mo);
1004     damage = 7 + (P_Random() & 7);
1005     angle = mo->angle;
1006     if (player->refire)
1007     {
1008         angle += P_SubRandom() << 18;
1009     }
1010     PuffType = MT_GOLDWANDPUFF1;
1011     P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
1012     S_StartSound(player->mo, sfx_gldhit);
1013 }
1014 
1015 //----------------------------------------------------------------------------
1016 //
1017 // PROC A_FireGoldWandPL2
1018 //
1019 //----------------------------------------------------------------------------
1020 
A_FireGoldWandPL2(player_t * player,pspdef_t * psp)1021 void A_FireGoldWandPL2(player_t * player, pspdef_t * psp)
1022 {
1023     int i;
1024     mobj_t *mo;
1025     angle_t angle;
1026     int damage;
1027     fixed_t momz;
1028 
1029     mo = player->mo;
1030     player->ammo[am_goldwand] -=
1031         deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2;
1032     PuffType = MT_GOLDWANDPUFF2;
1033     P_BulletSlope(mo);
1034     momz = FixedMul(mobjinfo[MT_GOLDWANDFX2].speed, bulletslope);
1035     P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle - (ANG45 / 8), momz);
1036     P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle + (ANG45 / 8), momz);
1037     angle = mo->angle - (ANG45 / 8);
1038     for (i = 0; i < 5; i++)
1039     {
1040         damage = 1 + (P_Random() & 7);
1041         P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
1042         angle += ((ANG45 / 8) * 2) / 4;
1043     }
1044     S_StartSound(player->mo, sfx_gldhit);
1045 }
1046 
1047 //----------------------------------------------------------------------------
1048 //
1049 // PROC A_FireMacePL1B
1050 //
1051 //----------------------------------------------------------------------------
1052 
A_FireMacePL1B(player_t * player,pspdef_t * psp)1053 void A_FireMacePL1B(player_t * player, pspdef_t * psp)
1054 {
1055     mobj_t *pmo;
1056     mobj_t *ball;
1057     angle_t angle;
1058 
1059     if (player->ammo[am_mace] < USE_MACE_AMMO_1)
1060     {
1061         return;
1062     }
1063     player->ammo[am_mace] -= USE_MACE_AMMO_1;
1064     pmo = player->mo;
1065 
1066     // Vanilla bug here:
1067     // Original code here looks like:
1068     //   (pmo->flags2 & MF2_FEETARECLIPPED != 0)
1069     // C's operator precedence interprets this as:
1070     //   (pmo->flags2 & (MF2_FEETARECLIPPED != 0))
1071     // Which simplifies to:
1072     //   (pmo->flags2 & 1)
1073     ball = P_SpawnMobj(pmo->x, pmo->y, pmo->z + 28 * FRACUNIT
1074                        - FOOTCLIPSIZE * (pmo->flags2 & 1), MT_MACEFX2);
1075 
1076     ball->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
1077     angle = pmo->angle;
1078     ball->target = pmo;
1079     ball->angle = angle;
1080     ball->z += (player->lookdir) << (FRACBITS - 4);
1081     angle >>= ANGLETOFINESHIFT;
1082     ball->momx = (pmo->momx >> 1)
1083         + FixedMul(ball->info->speed, finecosine[angle]);
1084     ball->momy = (pmo->momy >> 1)
1085         + FixedMul(ball->info->speed, finesine[angle]);
1086     S_StartSound(ball, sfx_lobsht);
1087     P_CheckMissileSpawn(ball);
1088 }
1089 
1090 //----------------------------------------------------------------------------
1091 //
1092 // PROC A_FireMacePL1
1093 //
1094 //----------------------------------------------------------------------------
1095 
A_FireMacePL1(player_t * player,pspdef_t * psp)1096 void A_FireMacePL1(player_t * player, pspdef_t * psp)
1097 {
1098     mobj_t *ball;
1099 
1100     if (P_Random() < 28)
1101     {
1102         A_FireMacePL1B(player, psp);
1103         return;
1104     }
1105     if (player->ammo[am_mace] < USE_MACE_AMMO_1)
1106     {
1107         return;
1108     }
1109     player->ammo[am_mace] -= USE_MACE_AMMO_1;
1110     psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
1111     psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
1112     ball = P_SPMAngle(player->mo, MT_MACEFX1, player->mo->angle
1113                       + (((P_Random() & 7) - 4) << 24));
1114     if (ball)
1115     {
1116         ball->special1.i = 16;    // tics till dropoff
1117     }
1118 }
1119 
1120 //----------------------------------------------------------------------------
1121 //
1122 // PROC A_MacePL1Check
1123 //
1124 //----------------------------------------------------------------------------
1125 
A_MacePL1Check(mobj_t * ball)1126 void A_MacePL1Check(mobj_t * ball)
1127 {
1128     angle_t angle;
1129 
1130     if (ball->special1.i == 0)
1131     {
1132         return;
1133     }
1134     ball->special1.i -= 4;
1135     if (ball->special1.i > 0)
1136     {
1137         return;
1138     }
1139     ball->special1.i = 0;
1140     ball->flags2 |= MF2_LOGRAV;
1141     angle = ball->angle >> ANGLETOFINESHIFT;
1142     ball->momx = FixedMul(7 * FRACUNIT, finecosine[angle]);
1143     ball->momy = FixedMul(7 * FRACUNIT, finesine[angle]);
1144     ball->momz -= ball->momz >> 1;
1145 }
1146 
1147 //----------------------------------------------------------------------------
1148 //
1149 // PROC A_MaceBallImpact
1150 //
1151 //----------------------------------------------------------------------------
1152 
A_MaceBallImpact(mobj_t * ball)1153 void A_MaceBallImpact(mobj_t * ball)
1154 {
1155     if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1156     {                           // Landed in some sort of liquid
1157         P_RemoveMobj(ball);
1158         return;
1159     }
1160     if ((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz)
1161         && ball->momz)
1162     {                           // Bounce
1163         ball->health = MAGIC_JUNK;
1164         ball->momz = (ball->momz * 192) >> 8;
1165         ball->flags2 &= ~MF2_FLOORBOUNCE;
1166         P_SetMobjState(ball, ball->info->spawnstate);
1167         S_StartSound(ball, sfx_bounce);
1168     }
1169     else
1170     {                           // Explode
1171         ball->flags |= MF_NOGRAVITY;
1172         ball->flags2 &= ~MF2_LOGRAV;
1173         S_StartSound(ball, sfx_lobhit);
1174     }
1175 }
1176 
1177 //----------------------------------------------------------------------------
1178 //
1179 // PROC A_MaceBallImpact2
1180 //
1181 //----------------------------------------------------------------------------
1182 
A_MaceBallImpact2(mobj_t * ball)1183 void A_MaceBallImpact2(mobj_t * ball)
1184 {
1185     mobj_t *tiny;
1186     angle_t angle;
1187 
1188     if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1189     {                           // Landed in some sort of liquid
1190         P_RemoveMobj(ball);
1191         return;
1192     }
1193     if ((ball->z != ball->floorz) || (ball->momz < 2 * FRACUNIT))
1194     {                           // Explode
1195         ball->momx = ball->momy = ball->momz = 0;
1196         ball->flags |= MF_NOGRAVITY;
1197         ball->flags2 &= ~(MF2_LOGRAV | MF2_FLOORBOUNCE);
1198     }
1199     else
1200     {                           // Bounce
1201         ball->momz = (ball->momz * 192) >> 8;
1202         P_SetMobjState(ball, ball->info->spawnstate);
1203 
1204         tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
1205         angle = ball->angle + ANG90;
1206         tiny->target = ball->target;
1207         tiny->angle = angle;
1208         angle >>= ANGLETOFINESHIFT;
1209         tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
1210                                                   finecosine[angle]);
1211         tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
1212                                                   finesine[angle]);
1213         tiny->momz = ball->momz;
1214         P_CheckMissileSpawn(tiny);
1215 
1216         tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
1217         angle = ball->angle - ANG90;
1218         tiny->target = ball->target;
1219         tiny->angle = angle;
1220         angle >>= ANGLETOFINESHIFT;
1221         tiny->momx = (ball->momx >> 1) + FixedMul(ball->momz - FRACUNIT,
1222                                                   finecosine[angle]);
1223         tiny->momy = (ball->momy >> 1) + FixedMul(ball->momz - FRACUNIT,
1224                                                   finesine[angle]);
1225         tiny->momz = ball->momz;
1226         P_CheckMissileSpawn(tiny);
1227     }
1228 }
1229 
1230 //----------------------------------------------------------------------------
1231 //
1232 // PROC A_FireMacePL2
1233 //
1234 //----------------------------------------------------------------------------
1235 
A_FireMacePL2(player_t * player,pspdef_t * psp)1236 void A_FireMacePL2(player_t * player, pspdef_t * psp)
1237 {
1238     mobj_t *mo;
1239 
1240     player->ammo[am_mace] -= deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2;
1241     mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4);
1242     if (mo)
1243     {
1244         mo->momx += player->mo->momx;
1245         mo->momy += player->mo->momy;
1246         mo->momz = 2 * FRACUNIT + ((player->lookdir) << (FRACBITS - 5));
1247         if (linetarget)
1248         {
1249             mo->special1.m = linetarget;
1250         }
1251     }
1252     S_StartSound(player->mo, sfx_lobsht);
1253 }
1254 
1255 //----------------------------------------------------------------------------
1256 //
1257 // PROC A_DeathBallImpact
1258 //
1259 //----------------------------------------------------------------------------
1260 
A_DeathBallImpact(mobj_t * ball)1261 void A_DeathBallImpact(mobj_t * ball)
1262 {
1263     int i;
1264     mobj_t *target;
1265     angle_t angle;
1266     boolean newAngle;
1267 
1268     if ((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1269     {                           // Landed in some sort of liquid
1270         P_RemoveMobj(ball);
1271         return;
1272     }
1273     if ((ball->z <= ball->floorz) && ball->momz)
1274     {                           // Bounce
1275         newAngle = false;
1276         target = (mobj_t *) ball->special1.m;
1277         if (target)
1278         {
1279             if (!(target->flags & MF_SHOOTABLE))
1280             {                   // Target died
1281                 ball->special1.m = NULL;
1282             }
1283             else
1284             {                   // Seek
1285                 angle = R_PointToAngle2(ball->x, ball->y,
1286                                         target->x, target->y);
1287                 newAngle = true;
1288             }
1289         }
1290         else
1291         {                       // Find new target
1292             angle = 0;
1293             for (i = 0; i < 16; i++)
1294             {
1295                 P_AimLineAttack(ball, angle, 10 * 64 * FRACUNIT);
1296                 if (linetarget && ball->target != linetarget)
1297                 {
1298                     ball->special1.m = linetarget;
1299                     angle = R_PointToAngle2(ball->x, ball->y,
1300                                             linetarget->x, linetarget->y);
1301                     newAngle = true;
1302                     break;
1303                 }
1304                 angle += ANG45 / 2;
1305             }
1306         }
1307         if (newAngle)
1308         {
1309             ball->angle = angle;
1310             angle >>= ANGLETOFINESHIFT;
1311             ball->momx = FixedMul(ball->info->speed, finecosine[angle]);
1312             ball->momy = FixedMul(ball->info->speed, finesine[angle]);
1313         }
1314         P_SetMobjState(ball, ball->info->spawnstate);
1315         S_StartSound(ball, sfx_pstop);
1316     }
1317     else
1318     {                           // Explode
1319         ball->flags |= MF_NOGRAVITY;
1320         ball->flags2 &= ~MF2_LOGRAV;
1321         S_StartSound(ball, sfx_phohit);
1322     }
1323 }
1324 
1325 //----------------------------------------------------------------------------
1326 //
1327 // PROC A_SpawnRippers
1328 //
1329 //----------------------------------------------------------------------------
1330 
A_SpawnRippers(mobj_t * actor)1331 void A_SpawnRippers(mobj_t * actor)
1332 {
1333     unsigned int i;
1334     angle_t angle;
1335     mobj_t *ripper;
1336 
1337     for (i = 0; i < 8; i++)
1338     {
1339         ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER);
1340         angle = i * ANG45;
1341         ripper->target = actor->target;
1342         ripper->angle = angle;
1343         angle >>= ANGLETOFINESHIFT;
1344         ripper->momx = FixedMul(ripper->info->speed, finecosine[angle]);
1345         ripper->momy = FixedMul(ripper->info->speed, finesine[angle]);
1346         P_CheckMissileSpawn(ripper);
1347     }
1348 }
1349 
1350 //----------------------------------------------------------------------------
1351 //
1352 // PROC A_FireCrossbowPL1
1353 //
1354 //----------------------------------------------------------------------------
1355 
A_FireCrossbowPL1(player_t * player,pspdef_t * psp)1356 void A_FireCrossbowPL1(player_t * player, pspdef_t * psp)
1357 {
1358     mobj_t *pmo;
1359 
1360     pmo = player->mo;
1361     player->ammo[am_crossbow] -= USE_CBOW_AMMO_1;
1362     P_SpawnPlayerMissile(pmo, MT_CRBOWFX1);
1363     P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 10));
1364     P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 10));
1365 }
1366 
1367 //----------------------------------------------------------------------------
1368 //
1369 // PROC A_FireCrossbowPL2
1370 //
1371 //----------------------------------------------------------------------------
1372 
A_FireCrossbowPL2(player_t * player,pspdef_t * psp)1373 void A_FireCrossbowPL2(player_t * player, pspdef_t * psp)
1374 {
1375     mobj_t *pmo;
1376 
1377     pmo = player->mo;
1378     player->ammo[am_crossbow] -=
1379         deathmatch ? USE_CBOW_AMMO_1 : USE_CBOW_AMMO_2;
1380     P_SpawnPlayerMissile(pmo, MT_CRBOWFX2);
1381     P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle - (ANG45 / 10));
1382     P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle + (ANG45 / 10));
1383     P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle - (ANG45 / 5));
1384     P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle + (ANG45 / 5));
1385 }
1386 
1387 //----------------------------------------------------------------------------
1388 //
1389 // PROC A_BoltSpark
1390 //
1391 //----------------------------------------------------------------------------
1392 
A_BoltSpark(mobj_t * bolt)1393 void A_BoltSpark(mobj_t * bolt)
1394 {
1395     mobj_t *spark;
1396 
1397     if (P_Random() > 50)
1398     {
1399         spark = P_SpawnMobj(bolt->x, bolt->y, bolt->z, MT_CRBOWFX4);
1400         spark->x += P_SubRandom() << 10;
1401         spark->y += P_SubRandom() << 10;
1402     }
1403 }
1404 
1405 //----------------------------------------------------------------------------
1406 //
1407 // PROC A_FireSkullRodPL1
1408 //
1409 //----------------------------------------------------------------------------
1410 
A_FireSkullRodPL1(player_t * player,pspdef_t * psp)1411 void A_FireSkullRodPL1(player_t * player, pspdef_t * psp)
1412 {
1413     mobj_t *mo;
1414 
1415     if (player->ammo[am_skullrod] < USE_SKRD_AMMO_1)
1416     {
1417         return;
1418     }
1419     player->ammo[am_skullrod] -= USE_SKRD_AMMO_1;
1420     mo = P_SpawnPlayerMissile(player->mo, MT_HORNRODFX1);
1421     // Randomize the first frame
1422     if (mo && P_Random() > 128)
1423     {
1424         P_SetMobjState(mo, S_HRODFX1_2);
1425     }
1426 }
1427 
1428 //----------------------------------------------------------------------------
1429 //
1430 // PROC A_FireSkullRodPL2
1431 //
1432 // The special2 field holds the player number that shot the rain missile.
1433 // The special1 field is used for the seeking routines, then as a counter
1434 // for the sound looping.
1435 //
1436 //----------------------------------------------------------------------------
1437 
A_FireSkullRodPL2(player_t * player,pspdef_t * psp)1438 void A_FireSkullRodPL2(player_t * player, pspdef_t * psp)
1439 {
1440     player->ammo[am_skullrod] -=
1441         deathmatch ? USE_SKRD_AMMO_1 : USE_SKRD_AMMO_2;
1442     P_SpawnPlayerMissile(player->mo, MT_HORNRODFX2);
1443     // Use MissileMobj instead of the return value from
1444     // P_SpawnPlayerMissile because we need to give info to the mobj
1445     // even if it exploded immediately.
1446     if (netgame)
1447     {                           // Multi-player game
1448         MissileMobj->special2.i = P_GetPlayerNum(player);
1449     }
1450     else
1451     {                           // Always use red missiles in single player games
1452         MissileMobj->special2.i = 2;
1453     }
1454     if (linetarget)
1455     {
1456         MissileMobj->special1.m = linetarget;
1457     }
1458     S_StartSound(MissileMobj, sfx_hrnpow);
1459 }
1460 
1461 //----------------------------------------------------------------------------
1462 //
1463 // PROC A_SkullRodPL2Seek
1464 //
1465 //----------------------------------------------------------------------------
1466 
A_SkullRodPL2Seek(mobj_t * actor)1467 void A_SkullRodPL2Seek(mobj_t * actor)
1468 {
1469     P_SeekerMissile(actor, ANG1_X * 10, ANG1_X * 30);
1470 }
1471 
1472 //----------------------------------------------------------------------------
1473 //
1474 // PROC A_AddPlayerRain
1475 //
1476 //----------------------------------------------------------------------------
1477 
A_AddPlayerRain(mobj_t * actor)1478 void A_AddPlayerRain(mobj_t * actor)
1479 {
1480     int playerNum;
1481     player_t *player;
1482 
1483     playerNum = netgame ? actor->special2.i : 0;
1484     if (!playeringame[playerNum])
1485     {                           // Player left the game
1486         return;
1487     }
1488     player = &players[playerNum];
1489     if (player->health <= 0)
1490     {                           // Player is dead
1491         return;
1492     }
1493     if (player->rain1 && player->rain2)
1494     {                           // Terminate an active rain
1495         if (player->rain1->health < player->rain2->health)
1496         {
1497             if (player->rain1->health > 16)
1498             {
1499                 player->rain1->health = 16;
1500             }
1501             player->rain1 = NULL;
1502         }
1503         else
1504         {
1505             if (player->rain2->health > 16)
1506             {
1507                 player->rain2->health = 16;
1508             }
1509             player->rain2 = NULL;
1510         }
1511     }
1512     // Add rain mobj to list
1513     if (player->rain1)
1514     {
1515         player->rain2 = actor;
1516     }
1517     else
1518     {
1519         player->rain1 = actor;
1520     }
1521 }
1522 
1523 //----------------------------------------------------------------------------
1524 //
1525 // PROC A_SkullRodStorm
1526 //
1527 //----------------------------------------------------------------------------
1528 
A_SkullRodStorm(mobj_t * actor)1529 void A_SkullRodStorm(mobj_t * actor)
1530 {
1531     fixed_t x;
1532     fixed_t y;
1533     mobj_t *mo;
1534     int playerNum;
1535     player_t *player;
1536 
1537     if (actor->health-- == 0)
1538     {
1539         P_SetMobjState(actor, S_NULL);
1540         playerNum = netgame ? actor->special2.i : 0;
1541         if (!playeringame[playerNum])
1542         {                       // Player left the game
1543             return;
1544         }
1545         player = &players[playerNum];
1546         if (player->health <= 0)
1547         {                       // Player is dead
1548             return;
1549         }
1550         if (player->rain1 == actor)
1551         {
1552             player->rain1 = NULL;
1553         }
1554         else if (player->rain2 == actor)
1555         {
1556             player->rain2 = NULL;
1557         }
1558         return;
1559     }
1560     if (P_Random() < 25)
1561     {                           // Fudge rain frequency
1562         return;
1563     }
1564     x = actor->x + ((P_Random() & 127) - 64) * FRACUNIT;
1565     y = actor->y + ((P_Random() & 127) - 64) * FRACUNIT;
1566     mo = P_SpawnMobj(x, y, ONCEILINGZ, MT_RAINPLR1 + actor->special2.i);
1567     mo->target = actor->target;
1568     mo->momx = 1;               // Force collision detection
1569     mo->momz = -mo->info->speed;
1570     mo->special2.i = actor->special2.i;     // Transfer player number
1571     P_CheckMissileSpawn(mo);
1572     if (!(actor->special1.i & 31))
1573     {
1574         S_StartSound(actor, sfx_ramrain);
1575     }
1576     actor->special1.i++;
1577 }
1578 
1579 //----------------------------------------------------------------------------
1580 //
1581 // PROC A_RainImpact
1582 //
1583 //----------------------------------------------------------------------------
1584 
A_RainImpact(mobj_t * actor)1585 void A_RainImpact(mobj_t * actor)
1586 {
1587     if (actor->z > actor->floorz)
1588     {
1589         P_SetMobjState(actor, S_RAINAIRXPLR1_1 + actor->special2.i);
1590     }
1591     else if (P_Random() < 40)
1592     {
1593         P_HitFloor(actor);
1594     }
1595 }
1596 
1597 //----------------------------------------------------------------------------
1598 //
1599 // PROC A_HideInCeiling
1600 //
1601 //----------------------------------------------------------------------------
1602 
A_HideInCeiling(mobj_t * actor)1603 void A_HideInCeiling(mobj_t * actor)
1604 {
1605     actor->z = actor->ceilingz + 4 * FRACUNIT;
1606 }
1607 
1608 //----------------------------------------------------------------------------
1609 //
1610 // PROC A_FirePhoenixPL1
1611 //
1612 //----------------------------------------------------------------------------
1613 
A_FirePhoenixPL1(player_t * player,pspdef_t * psp)1614 void A_FirePhoenixPL1(player_t * player, pspdef_t * psp)
1615 {
1616     angle_t angle;
1617 
1618     player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_1;
1619     P_SpawnPlayerMissile(player->mo, MT_PHOENIXFX1);
1620     //P_SpawnPlayerMissile(player->mo, MT_MNTRFX2);
1621     angle = player->mo->angle + ANG180;
1622     angle >>= ANGLETOFINESHIFT;
1623     player->mo->momx += FixedMul(4 * FRACUNIT, finecosine[angle]);
1624     player->mo->momy += FixedMul(4 * FRACUNIT, finesine[angle]);
1625 }
1626 
1627 //----------------------------------------------------------------------------
1628 //
1629 // PROC A_PhoenixPuff
1630 //
1631 //----------------------------------------------------------------------------
1632 
A_PhoenixPuff(mobj_t * actor)1633 void A_PhoenixPuff(mobj_t * actor)
1634 {
1635     mobj_t *puff;
1636     angle_t angle;
1637 
1638     P_SeekerMissile(actor, ANG1_X * 5, ANG1_X * 10);
1639     puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1640     angle = actor->angle + ANG90;
1641     angle >>= ANGLETOFINESHIFT;
1642     puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
1643     puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
1644     puff->momz = 0;
1645     puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
1646     angle = actor->angle - ANG90;
1647     angle >>= ANGLETOFINESHIFT;
1648     puff->momx = FixedMul((fixed_t)(FRACUNIT * 1.3), finecosine[angle]);
1649     puff->momy = FixedMul((fixed_t)(FRACUNIT * 1.3), finesine[angle]);
1650     puff->momz = 0;
1651 }
1652 
1653 //
1654 // This function was present in the Heretic 1.0 executable for the
1655 // removed "secondary phoenix flash" object (MT_PHOENIXFX_REMOVED).
1656 // The purpose of this object is unknown, as is this function.
1657 //
1658 
A_RemovedPhoenixFunc(mobj_t * actor)1659 void A_RemovedPhoenixFunc(mobj_t *actor)
1660 {
1661     I_Error("Action function invoked for removed Phoenix action!");
1662 }
1663 
1664 //----------------------------------------------------------------------------
1665 //
1666 // PROC A_InitPhoenixPL2
1667 //
1668 //----------------------------------------------------------------------------
1669 
A_InitPhoenixPL2(player_t * player,pspdef_t * psp)1670 void A_InitPhoenixPL2(player_t * player, pspdef_t * psp)
1671 {
1672     player->flamecount = FLAME_THROWER_TICS;
1673 }
1674 
1675 //----------------------------------------------------------------------------
1676 //
1677 // PROC A_FirePhoenixPL2
1678 //
1679 // Flame thrower effect.
1680 //
1681 //----------------------------------------------------------------------------
1682 
A_FirePhoenixPL2(player_t * player,pspdef_t * psp)1683 void A_FirePhoenixPL2(player_t * player, pspdef_t * psp)
1684 {
1685     mobj_t *mo;
1686     mobj_t *pmo;
1687     angle_t angle;
1688     fixed_t x, y, z;
1689     fixed_t slope;
1690 
1691     if (--player->flamecount == 0)
1692     {                           // Out of flame
1693         P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4);
1694         player->refire = 0;
1695         return;
1696     }
1697     pmo = player->mo;
1698     angle = pmo->angle;
1699     x = pmo->x + (P_SubRandom() << 9);
1700     y = pmo->y + (P_SubRandom() << 9);
1701     z = pmo->z + 26 * FRACUNIT + ((player->lookdir) << FRACBITS) / 173;
1702     if (pmo->flags2 & MF2_FEETARECLIPPED)
1703     {
1704         z -= FOOTCLIPSIZE;
1705     }
1706     slope = ((player->lookdir) << FRACBITS) / 173 + (FRACUNIT / 10);
1707     mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2);
1708     mo->target = pmo;
1709     mo->angle = angle;
1710     mo->momx = pmo->momx + FixedMul(mo->info->speed,
1711                                     finecosine[angle >> ANGLETOFINESHIFT]);
1712     mo->momy = pmo->momy + FixedMul(mo->info->speed,
1713                                     finesine[angle >> ANGLETOFINESHIFT]);
1714     mo->momz = FixedMul(mo->info->speed, slope);
1715     if (!player->refire || !(leveltime % 38))
1716     {
1717         S_StartSound(player->mo, sfx_phopow);
1718     }
1719     P_CheckMissileSpawn(mo);
1720 }
1721 
1722 //----------------------------------------------------------------------------
1723 //
1724 // PROC A_ShutdownPhoenixPL2
1725 //
1726 //----------------------------------------------------------------------------
1727 
A_ShutdownPhoenixPL2(player_t * player,pspdef_t * psp)1728 void A_ShutdownPhoenixPL2(player_t * player, pspdef_t * psp)
1729 {
1730     player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
1731 }
1732 
1733 //----------------------------------------------------------------------------
1734 //
1735 // PROC A_FlameEnd
1736 //
1737 //----------------------------------------------------------------------------
1738 
A_FlameEnd(mobj_t * actor)1739 void A_FlameEnd(mobj_t * actor)
1740 {
1741     actor->momz += (fixed_t)(1.5 * FRACUNIT);
1742 }
1743 
1744 //----------------------------------------------------------------------------
1745 //
1746 // PROC A_FloatPuff
1747 //
1748 //----------------------------------------------------------------------------
1749 
A_FloatPuff(mobj_t * puff)1750 void A_FloatPuff(mobj_t * puff)
1751 {
1752     puff->momz += (fixed_t)(1.8 * FRACUNIT);
1753 }
1754 
1755 //---------------------------------------------------------------------------
1756 //
1757 // PROC A_GauntletAttack
1758 //
1759 //---------------------------------------------------------------------------
1760 
A_GauntletAttack(player_t * player,pspdef_t * psp)1761 void A_GauntletAttack(player_t * player, pspdef_t * psp)
1762 {
1763     angle_t angle;
1764     int damage;
1765     int slope;
1766     int randVal;
1767     fixed_t dist;
1768 
1769     psp->sx = ((P_Random() & 3) - 2) * FRACUNIT;
1770     psp->sy = WEAPONTOP + (P_Random() & 3) * FRACUNIT;
1771     angle = player->mo->angle;
1772     if (player->powers[pw_weaponlevel2])
1773     {
1774         damage = HITDICE(2);
1775         dist = 4 * MELEERANGE;
1776         angle += P_SubRandom() << 17;
1777         PuffType = MT_GAUNTLETPUFF2;
1778     }
1779     else
1780     {
1781         damage = HITDICE(2);
1782         dist = MELEERANGE + 1;
1783         angle += P_SubRandom() << 18;
1784         PuffType = MT_GAUNTLETPUFF1;
1785     }
1786     slope = P_AimLineAttack(player->mo, angle, dist);
1787     P_LineAttack(player->mo, angle, dist, slope, damage);
1788     if (!linetarget)
1789     {
1790         if (P_Random() > 64)
1791         {
1792             player->extralight = !player->extralight;
1793         }
1794         S_StartSound(player->mo, sfx_gntful);
1795         return;
1796     }
1797     randVal = P_Random();
1798     if (randVal < 64)
1799     {
1800         player->extralight = 0;
1801     }
1802     else if (randVal < 160)
1803     {
1804         player->extralight = 1;
1805     }
1806     else
1807     {
1808         player->extralight = 2;
1809     }
1810     if (player->powers[pw_weaponlevel2])
1811     {
1812         P_GiveBody(player, damage >> 1);
1813         S_StartSound(player->mo, sfx_gntpow);
1814     }
1815     else
1816     {
1817         S_StartSound(player->mo, sfx_gnthit);
1818     }
1819     // turn to face target
1820     angle = R_PointToAngle2(player->mo->x, player->mo->y,
1821                             linetarget->x, linetarget->y);
1822     if (angle - player->mo->angle > ANG180)
1823     {
1824         if (angle - player->mo->angle < -ANG90 / 20)
1825             player->mo->angle = angle + ANG90 / 21;
1826         else
1827             player->mo->angle -= ANG90 / 20;
1828     }
1829     else
1830     {
1831         if (angle - player->mo->angle > ANG90 / 20)
1832             player->mo->angle = angle - ANG90 / 21;
1833         else
1834             player->mo->angle += ANG90 / 20;
1835     }
1836     player->mo->flags |= MF_JUSTATTACKED;
1837 }
1838 
A_Light0(player_t * player,pspdef_t * psp)1839 void A_Light0(player_t * player, pspdef_t * psp)
1840 {
1841     player->extralight = 0;
1842 }
1843 
A_Light1(player_t * player,pspdef_t * psp)1844 void A_Light1(player_t * player, pspdef_t * psp)
1845 {
1846     player->extralight = 1;
1847 }
1848 
A_Light2(player_t * player,pspdef_t * psp)1849 void A_Light2(player_t * player, pspdef_t * psp)
1850 {
1851     player->extralight = 2;
1852 }
1853 
1854 //------------------------------------------------------------------------
1855 //
1856 // PROC P_SetupPsprites
1857 //
1858 // Called at start of level for each player
1859 //
1860 //------------------------------------------------------------------------
1861 
P_SetupPsprites(player_t * player)1862 void P_SetupPsprites(player_t * player)
1863 {
1864     int i;
1865 
1866     // Remove all psprites
1867     for (i = 0; i < NUMPSPRITES; i++)
1868     {
1869         player->psprites[i].state = NULL;
1870     }
1871     // Spawn the ready weapon
1872     player->pendingweapon = player->readyweapon;
1873     P_BringUpWeapon(player);
1874 }
1875 
1876 //------------------------------------------------------------------------
1877 //
1878 // PROC P_MovePsprites
1879 //
1880 // Called every tic by player thinking routine
1881 //
1882 //------------------------------------------------------------------------
1883 
P_MovePsprites(player_t * player)1884 void P_MovePsprites(player_t * player)
1885 {
1886     int i;
1887     pspdef_t *psp;
1888 
1889     psp = &player->psprites[0];
1890     for (i = 0; i < NUMPSPRITES; i++, psp++)
1891     {
1892         if (psp->state != 0)  // a null state means not active
1893         {
1894             // drop tic count and possibly change state
1895             if (psp->tics != -1)        // a -1 tic count never changes
1896             {
1897                 psp->tics--;
1898                 if (!psp->tics)
1899                 {
1900                     P_SetPsprite(player, i, psp->state->nextstate);
1901                 }
1902             }
1903         }
1904     }
1905     player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
1906     player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
1907 }
1908