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