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
18 static int MaceSpotCount;
23 } MaceSpots[MAX_MACE_SPOTS];
27 static int WeaponAmmoUsePL1[NUMWEAPONS] = {
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
39 static int WeaponAmmoUsePL2[NUMWEAPONS] = {
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
51 weaponinfo_t wpnlev1info[NUMWEAPONS] =
56 S_STAFFDOWN, // downstate
57 S_STAFFREADY, // readystate
58 S_STAFFATK1_1, // atkstate
59 S_STAFFATK1_1, // holdatkstate
64 S_GOLDWANDUP, // upstate
65 S_GOLDWANDDOWN, // downstate
66 S_GOLDWANDREADY, // readystate
67 S_GOLDWANDATK1_1, // atkstate
68 S_GOLDWANDATK1_1, // holdatkstate
74 S_CRBOWDOWN, // downstate
75 S_CRBOW1, // readystate
76 S_CRBOWATK1_1, // atkstate
77 S_CRBOWATK1_1, // holdatkstate
82 S_BLASTERUP, // upstate
83 S_BLASTERDOWN, // downstate
84 S_BLASTERREADY, // readystate
85 S_BLASTERATK1_1, // atkstate
86 S_BLASTERATK1_3, // holdatkstate
91 S_HORNRODUP, // upstate
92 S_HORNRODDOWN, // downstate
93 S_HORNRODREADY, // readystae
94 S_HORNRODATK1_1, // atkstate
95 S_HORNRODATK1_1, // holdatkstate
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
110 S_MACEDOWN, // downstate
111 S_MACEREADY, // readystate
112 S_MACEATK1_1, // atkstate
113 S_MACEATK1_2, // holdatkstate
118 S_GAUNTLETUP, // upstate
119 S_GAUNTLETDOWN, // downstate
120 S_GAUNTLETREADY, // readystate
121 S_GAUNTLETATK1_1, // atkstate
122 S_GAUNTLETATK1_3, // holdatkstate
128 S_BEAKDOWN, // downstate
129 S_BEAKREADY, // readystate
130 S_BEAKATK1_1, // atkstate
131 S_BEAKATK1_1, // holdatkstate
136 weaponinfo_t wpnlev2info[NUMWEAPONS] =
140 S_STAFFUP2, // upstate
141 S_STAFFDOWN2, // downstate
142 S_STAFFREADY2_1, // readystate
143 S_STAFFATK2_1, // atkstate
144 S_STAFFATK2_1, // holdatkstate
149 S_GOLDWANDUP, // upstate
150 S_GOLDWANDDOWN, // downstate
151 S_GOLDWANDREADY, // readystate
152 S_GOLDWANDATK2_1, // atkstate
153 S_GOLDWANDATK2_1, // holdatkstate
158 S_CRBOWUP, // upstate
159 S_CRBOWDOWN, // downstate
160 S_CRBOW1, // readystate
161 S_CRBOWATK2_1, // atkstate
162 S_CRBOWATK2_1, // holdatkstate
167 S_BLASTERUP, // upstate
168 S_BLASTERDOWN, // downstate
169 S_BLASTERREADY, // readystate
170 S_BLASTERATK2_1, // atkstate
171 S_BLASTERATK2_3, // holdatkstate
176 S_HORNRODUP, // upstate
177 S_HORNRODDOWN, // downstate
178 S_HORNRODREADY, // readystae
179 S_HORNRODATK2_1, // atkstate
180 S_HORNRODATK2_1, // holdatkstate
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
195 S_MACEDOWN, // downstate
196 S_MACEREADY, // readystate
197 S_MACEATK2_1, // atkstate
198 S_MACEATK2_1, // holdatkstate
203 S_GAUNTLETUP2, // upstate
204 S_GAUNTLETDOWN2, // downstate
205 S_GAUNTLETREADY2_1, // readystate
206 S_GAUNTLETATK2_1, // atkstate
207 S_GAUNTLETATK2_3, // holdatkstate
213 S_BEAKDOWN, // downstate
214 S_BEAKREADY, // readystate
215 S_BEAKATK2_1, // atkstate
216 S_BEAKATK2_1, // holdatkstate
221 //---------------------------------------------------------------------------
223 // PROC P_OpenWeapons
225 // Called at level load before things are loaded.
227 //---------------------------------------------------------------------------
229 void P_OpenWeapons(void)
234 //---------------------------------------------------------------------------
236 // PROC P_AddMaceSpot
238 //---------------------------------------------------------------------------
240 void P_AddMaceSpot(mapthing_t *mthing)
242 if(MaceSpotCount == MAX_MACE_SPOTS)
244 I_Error("Too many mace spots.");
246 MaceSpots[MaceSpotCount].x = mthing->x<<FRACBITS;
247 MaceSpots[MaceSpotCount].y = mthing->y<<FRACBITS;
251 //---------------------------------------------------------------------------
253 // PROC P_RepositionMace
255 // Chooses the next spot to place the mace.
257 //---------------------------------------------------------------------------
259 void P_RepositionMace(mobj_t *mo)
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);
274 //---------------------------------------------------------------------------
276 // PROC P_CloseWeapons
278 // Called at level load after things are loaded.
280 //---------------------------------------------------------------------------
282 void P_CloseWeapons(void)
290 if(!deathmatch && P_Random() < 64)
291 { // Sometimes doesn't show up if not in deathmatch
294 spot = P_Random()%MaceSpotCount;
295 P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE);
298 //---------------------------------------------------------------------------
302 //---------------------------------------------------------------------------
304 void P_SetPsprite(player_t *player, int position, statenum_t stnum)
309 psp = &player->psprites[position];
313 { // Object removed itself.
317 state = &states[stnum];
319 psp->tics = state->tics; // could be 0
321 { // Set coordinates.
322 psp->sx = state->misc1<<FRACBITS;
323 psp->sy = state->misc2<<FRACBITS;
326 { // Call action routine.
327 state->action(player, psp);
333 stnum = psp->state->nextstate;
334 } while(!psp->tics); // An initial state of 0 could cycle through.
346 fixed_t swingx, swingy;
347 void P_CalcSwing (player_t *player)
352 // OPTIMIZE: tablify this
356 angle = (FINEANGLES/70*leveltime)&FINEMASK;
357 swingx = FixedMul ( swing, finesine[angle]);
359 angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
360 swingy = -FixedMul ( swingx, finesine[angle]);
364 //---------------------------------------------------------------------------
366 // PROC P_ActivateBeak
368 //---------------------------------------------------------------------------
370 void P_ActivateBeak(player_t *player)
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);
378 //---------------------------------------------------------------------------
380 // PROC P_PostChickenWeapon
382 //---------------------------------------------------------------------------
384 void P_PostChickenWeapon(player_t *player, weapontype_t weapon)
386 if(weapon == wp_beak)
387 { // Should never happen
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);
396 //---------------------------------------------------------------------------
398 // PROC P_BringUpWeapon
400 // Starts bringing the pending weapon up from the bottom of the screen.
402 //---------------------------------------------------------------------------
404 void P_BringUpWeapon(player_t *player)
408 if(player->pendingweapon == wp_nochange)
410 player->pendingweapon = player->readyweapon;
412 if(player->pendingweapon == wp_gauntlets)
414 S_StartSound(player->mo, sfx_gntact);
416 if(player->powers[pw_weaponlevel2])
418 new = wpnlev2info[player->pendingweapon].upstate;
422 new = wpnlev1info[player->pendingweapon].upstate;
424 player->pendingweapon = wp_nochange;
425 player->psprites[ps_weapon].sy = WEAPONBOTTOM;
426 P_SetPsprite(player, ps_weapon, new);
429 //---------------------------------------------------------------------------
433 // Returns true if there is enough ammo to shoot. If not, selects the
434 // next weapon to use.
436 //---------------------------------------------------------------------------
438 boolean P_CheckAmmo(player_t *player)
444 ammo = wpnlev1info[player->readyweapon].ammo;
445 if(player->powers[pw_weaponlevel2] && !deathmatch)
447 ammoUse = WeaponAmmoUsePL2;
451 ammoUse = WeaponAmmoUsePL1;
453 count = ammoUse[player->readyweapon];
454 if(ammo == am_noammo || player->ammo[ammo] >= count)
458 // out of ammo, pick a weapon to change to
461 if(player->weaponowned[wp_skullrod]
462 && player->ammo[am_skullrod] > ammoUse[wp_skullrod])
464 player->pendingweapon = wp_skullrod;
466 else if(player->weaponowned[wp_blaster]
467 && player->ammo[am_blaster] > ammoUse[wp_blaster])
469 player->pendingweapon = wp_blaster;
471 else if(player->weaponowned[wp_crossbow]
472 && player->ammo[am_crossbow] > ammoUse[wp_crossbow])
474 player->pendingweapon = wp_crossbow;
476 else if(player->weaponowned[wp_mace]
477 && player->ammo[am_mace] > ammoUse[wp_mace])
479 player->pendingweapon = wp_mace;
481 else if(player->ammo[am_goldwand] > ammoUse[wp_goldwand])
483 player->pendingweapon = wp_goldwand;
485 else if(player->weaponowned[wp_gauntlets])
487 player->pendingweapon = wp_gauntlets;
489 else if(player->weaponowned[wp_phoenixrod]
490 && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod])
492 player->pendingweapon = wp_phoenixrod;
496 player->pendingweapon = wp_staff;
498 } while(player->pendingweapon == wp_nochange);
499 if(player->powers[pw_weaponlevel2])
501 P_SetPsprite(player, ps_weapon,
502 wpnlev2info[player->readyweapon].downstate);
506 P_SetPsprite(player, ps_weapon,
507 wpnlev1info[player->readyweapon].downstate);
512 //---------------------------------------------------------------------------
516 //---------------------------------------------------------------------------
518 void P_FireWeapon(player_t *player)
520 weaponinfo_t *wpinfo;
521 statenum_t attackState;
523 if(!P_CheckAmmo(player))
527 P_SetMobjState(player->mo, S_PLAY_ATK2);
528 wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[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);
540 //---------------------------------------------------------------------------
544 // The player died, so put the weapon away.
546 //---------------------------------------------------------------------------
548 void P_DropWeapon(player_t *player)
550 if(player->powers[pw_weaponlevel2])
552 P_SetPsprite(player, ps_weapon,
553 wpnlev2info[player->readyweapon].downstate);
557 P_SetPsprite(player, ps_weapon,
558 wpnlev1info[player->readyweapon].downstate);
562 //---------------------------------------------------------------------------
564 // PROC A_WeaponReady
566 // The player can fire the weapon or change to another weapon at this time.
568 //---------------------------------------------------------------------------
570 void A_WeaponReady(player_t *player, pspdef_t *psp)
574 if(player->chickenTics)
575 { // Change to the chicken beak
576 P_ActivateBeak(player);
579 // Change player from attack state
580 if(player->mo->state == &states[S_PLAY_ATK1]
581 || player->mo->state == &states[S_PLAY_ATK2])
583 P_SetMobjState(player->mo, S_PLAY);
585 // Check for staff PL2 active sound
586 if((player->readyweapon == wp_staff)
587 && (psp->state == &states[S_STAFFREADY2_1])
590 S_StartSound(player->mo, sfx_stfcrk);
592 // Put the weapon away if the player has a pending weapon or has
594 if(player->pendingweapon != wp_nochange || !player->health)
596 if(player->powers[pw_weaponlevel2])
598 P_SetPsprite(player, ps_weapon,
599 wpnlev2info[player->readyweapon].downstate);
603 P_SetPsprite(player, ps_weapon,
604 wpnlev1info[player->readyweapon].downstate);
609 // Check for fire. The phoenix rod does not auto fire.
610 if(player->cmd.buttons&BT_ATTACK)
612 if(!player->attackdown || (player->readyweapon != wp_phoenixrod))
614 player->attackdown = true;
615 P_FireWeapon(player);
621 player->attackdown = false;
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]);
631 //---------------------------------------------------------------------------
635 //---------------------------------------------------------------------------
637 void P_UpdateBeak(player_t *player, pspdef_t *psp)
639 psp->sy = WEAPONTOP+(player->chickenPeck<<(FRACBITS-1));
642 //---------------------------------------------------------------------------
646 //---------------------------------------------------------------------------
648 void A_BeakReady(player_t *player, pspdef_t *psp)
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])
656 P_SetPsprite(player, ps_weapon, S_BEAKATK2_1);
660 P_SetPsprite(player, ps_weapon, S_BEAKATK1_1);
662 P_NoiseAlert(player->mo, player->mo);
666 if(player->mo->state == &states[S_CHICPLAY_ATK1])
667 { // Take out of attack state
668 P_SetMobjState(player->mo, S_CHICPLAY);
670 player->attackdown = false;
674 //---------------------------------------------------------------------------
678 // The player can re fire the weapon without lowering it entirely.
680 //---------------------------------------------------------------------------
682 void A_ReFire(player_t *player, pspdef_t *psp)
684 if((player->cmd.buttons&BT_ATTACK)
685 && player->pendingweapon == wp_nochange && player->health)
688 P_FireWeapon(player);
697 //---------------------------------------------------------------------------
701 //---------------------------------------------------------------------------
703 void A_Lower(player_t *player, pspdef_t *psp)
705 if(player->chickenTics)
707 psp->sy = WEAPONBOTTOM;
711 psp->sy += LOWERSPEED;
713 if(psp->sy < WEAPONBOTTOM)
714 { // Not lowered all the way yet
717 if(player->playerstate == PST_DEAD)
718 { // Player is dead, so don't bring up a pending weapon
719 psp->sy = WEAPONBOTTOM;
723 { // Player is dead, so keep the weapon off screen
724 P_SetPsprite(player, ps_weapon, S_NULL);
727 player->readyweapon = player->pendingweapon;
728 P_BringUpWeapon(player);
731 //---------------------------------------------------------------------------
735 //---------------------------------------------------------------------------
737 void A_BeakRaise(player_t *player, pspdef_t *psp)
740 P_SetPsprite(player, ps_weapon,
741 wpnlev1info[player->readyweapon].readystate);
744 //---------------------------------------------------------------------------
748 //---------------------------------------------------------------------------
750 void A_Raise(player_t *player, pspdef_t *psp)
752 psp->sy -= RAISESPEED;
753 if(psp->sy > WEAPONTOP)
754 { // Not raised all the way yet
758 if(player->powers[pw_weaponlevel2])
760 P_SetPsprite(player, ps_weapon,
761 wpnlev2info[player->readyweapon].readystate);
765 P_SetPsprite(player, ps_weapon,
766 wpnlev1info[player->readyweapon].readystate);
775 = Sets a slope so a near miss is at aproximately the height of the
781 void P_BulletSlope (mobj_t *mo)
786 // see which target is to be aimed at
789 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
793 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
797 bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
802 bulletslope = (mo->player->lookdir<<FRACBITS)/173;
807 //****************************************************************************
811 //****************************************************************************
813 //----------------------------------------------------------------------------
815 // PROC A_BeakAttackPL1
817 //----------------------------------------------------------------------------
819 void A_BeakAttackPL1(player_t *player, pspdef_t *psp)
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);
832 player->mo->angle = R_PointToAngle2(player->mo->x,
833 player->mo->y, linetarget->x, linetarget->y);
835 S_StartSound(player->mo, sfx_chicpk1+(P_Random()%3));
836 player->chickenPeck = 12;
837 psp->tics -= P_Random()&7;
840 //----------------------------------------------------------------------------
842 // PROC A_BeakAttackPL2
844 //----------------------------------------------------------------------------
846 void A_BeakAttackPL2(player_t *player, pspdef_t *psp)
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);
859 player->mo->angle = R_PointToAngle2(player->mo->x,
860 player->mo->y, linetarget->x, linetarget->y);
862 S_StartSound(player->mo, sfx_chicpk1+(P_Random()%3));
863 player->chickenPeck = 12;
864 psp->tics -= P_Random()&3;
867 //----------------------------------------------------------------------------
869 // PROC A_StaffAttackPL1
871 //----------------------------------------------------------------------------
873 void A_StaffAttackPL1(player_t *player, pspdef_t *psp)
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);
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);
894 //----------------------------------------------------------------------------
896 // PROC A_StaffAttackPL2
898 //----------------------------------------------------------------------------
900 void A_StaffAttackPL2(player_t *player, pspdef_t *psp)
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);
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);
922 //----------------------------------------------------------------------------
924 // PROC A_FireBlasterPL1
926 //----------------------------------------------------------------------------
928 void A_FireBlasterPL1(player_t *player, pspdef_t *psp)
935 S_StartSound(mo, sfx_gldhit);
936 player->ammo[am_blaster] -= USE_BLSR_AMMO_1;
942 angle += (P_Random()-P_Random())<<18;
944 PuffType = MT_BLASTERPUFF1;
945 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
946 S_StartSound(player->mo, sfx_blssht);
949 //----------------------------------------------------------------------------
951 // PROC A_FireBlasterPL2
953 //----------------------------------------------------------------------------
955 void A_FireBlasterPL2(player_t *player, pspdef_t *psp)
959 player->ammo[am_blaster] -=
960 deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2;
961 mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1);
964 mo->thinker.function = P_BlasterMobjThinker;
966 S_StartSound(player->mo, sfx_blssht);
969 //----------------------------------------------------------------------------
971 // PROC A_FireGoldWandPL1
973 //----------------------------------------------------------------------------
975 void A_FireGoldWandPL1(player_t *player, pspdef_t *psp)
982 player->ammo[am_goldwand] -= USE_GWND_AMMO_1;
984 damage = 7+(P_Random()&7);
988 angle += (P_Random()-P_Random())<<18;
990 PuffType = MT_GOLDWANDPUFF1;
991 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
992 S_StartSound(player->mo, sfx_gldhit);
995 //----------------------------------------------------------------------------
997 // PROC A_FireGoldWandPL2
999 //----------------------------------------------------------------------------
1001 void A_FireGoldWandPL2(player_t *player, pspdef_t *psp)
1010 player->ammo[am_goldwand] -=
1011 deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2;
1012 PuffType = MT_GOLDWANDPUFF2;
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++)
1020 damage = 1+(P_Random()&7);
1021 P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
1022 angle += ((ANG45/8)*2)/4;
1024 S_StartSound(player->mo, sfx_gldhit);
1027 //----------------------------------------------------------------------------
1029 // PROC A_FireMacePL1B
1031 //----------------------------------------------------------------------------
1033 void A_FireMacePL1B(player_t *player, pspdef_t *psp)
1039 if(player->ammo[am_mace] < USE_MACE_AMMO_1)
1043 player->ammo[am_mace] -= USE_MACE_AMMO_1;
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));
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);
1061 //----------------------------------------------------------------------------
1063 // PROC A_FireMacePL1
1065 //----------------------------------------------------------------------------
1067 void A_FireMacePL1(player_t *player, pspdef_t *psp)
1073 A_FireMacePL1B(player, psp);
1076 if(player->ammo[am_mace] < USE_MACE_AMMO_1)
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));
1087 ball->special1 = 16; // tics till dropoff
1091 //----------------------------------------------------------------------------
1093 // PROC A_MacePL1Check
1095 //----------------------------------------------------------------------------
1097 void A_MacePL1Check(mobj_t *ball)
1101 if(ball->special1 == 0)
1105 ball->special1 -= 4;
1106 if(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;
1118 //----------------------------------------------------------------------------
1120 // PROC A_MaceBallImpact
1122 //----------------------------------------------------------------------------
1124 void A_MaceBallImpact(mobj_t *ball)
1126 if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1127 { // Landed in some sort of liquid
1131 if((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz)
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);
1142 ball->flags |= MF_NOGRAVITY;
1143 ball->flags2 &= ~MF2_LOGRAV;
1144 S_StartSound(ball, sfx_lobhit);
1148 //----------------------------------------------------------------------------
1150 // PROC A_MaceBallImpact2
1152 //----------------------------------------------------------------------------
1154 void A_MaceBallImpact2(mobj_t *ball)
1159 if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1160 { // Landed in some sort of liquid
1164 if((ball->z != ball->floorz) || (ball->momz < 2*FRACUNIT))
1166 ball->momx = ball->momy = ball->momz = 0;
1167 ball->flags |= MF_NOGRAVITY;
1168 ball->flags2 &= ~(MF2_LOGRAV|MF2_FLOORBOUNCE);
1172 ball->momz = (ball->momz*192)>>8;
1173 P_SetMobjState(ball, ball->info->spawnstate);
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,
1182 tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
1184 tiny->momz = ball->momz;
1185 P_CheckMissileSpawn(tiny);
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,
1194 tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
1196 tiny->momz = ball->momz;
1197 P_CheckMissileSpawn(tiny);
1201 //----------------------------------------------------------------------------
1203 // PROC A_FireMacePL2
1205 //----------------------------------------------------------------------------
1207 void A_FireMacePL2(player_t *player, pspdef_t *psp)
1211 player->ammo[am_mace] -=
1212 deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2;
1213 mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4);
1216 mo->momx += player->mo->momx;
1217 mo->momy += player->mo->momy;
1218 mo->momz = 2*FRACUNIT+((player->lookdir)<<(FRACBITS-5));
1221 mo->special1 = (int)linetarget;
1224 S_StartSound(player->mo, sfx_lobsht);
1227 //----------------------------------------------------------------------------
1229 // PROC A_DeathBallImpact
1231 //----------------------------------------------------------------------------
1233 void A_DeathBallImpact(mobj_t *ball)
1240 if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
1241 { // Landed in some sort of liquid
1245 if((ball->z <= ball->floorz) && ball->momz)
1248 target = (mobj_t *)ball->special1;
1251 if(!(target->flags&MF_SHOOTABLE))
1257 angle = R_PointToAngle2(ball->x, ball->y,
1258 target->x, target->y);
1263 { // Find new target
1265 for(i = 0; i < 16; i++)
1267 P_AimLineAttack(ball, angle, 10*64*FRACUNIT);
1268 if(linetarget && ball->target != linetarget)
1270 ball->special1 = (int)linetarget;
1271 angle = R_PointToAngle2(ball->x, ball->y,
1272 linetarget->x, linetarget->y);
1276 angle += ANGLE_45/2;
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]);
1286 P_SetMobjState(ball, ball->info->spawnstate);
1287 S_StartSound(ball, sfx_pstop);
1291 ball->flags |= MF_NOGRAVITY;
1292 ball->flags2 &= ~MF2_LOGRAV;
1293 S_StartSound(ball, sfx_phohit);
1297 //----------------------------------------------------------------------------
1299 // PROC A_SpawnRippers
1301 //----------------------------------------------------------------------------
1303 void A_SpawnRippers(mobj_t *actor)
1309 for(i = 0; i < 8; i++)
1311 ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER);
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);
1322 //----------------------------------------------------------------------------
1324 // PROC A_FireCrossbowPL1
1326 //----------------------------------------------------------------------------
1328 void A_FireCrossbowPL1(player_t *player, pspdef_t *psp)
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));
1339 //----------------------------------------------------------------------------
1341 // PROC A_FireCrossbowPL2
1343 //----------------------------------------------------------------------------
1345 void A_FireCrossbowPL2(player_t *player, pspdef_t *psp)
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));
1359 //----------------------------------------------------------------------------
1363 //----------------------------------------------------------------------------
1365 void A_BoltSpark(mobj_t *bolt)
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;
1377 //----------------------------------------------------------------------------
1379 // PROC A_FireSkullRodPL1
1381 //----------------------------------------------------------------------------
1383 void A_FireSkullRodPL1(player_t *player, pspdef_t *psp)
1387 if(player->ammo[am_skullrod] < USE_SKRD_AMMO_1)
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)
1396 P_SetMobjState(mo, S_HRODFX1_2);
1400 //----------------------------------------------------------------------------
1402 // PROC A_FireSkullRodPL2
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.
1408 //----------------------------------------------------------------------------
1410 void A_FireSkullRodPL2(player_t *player, pspdef_t *psp)
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.
1419 { // Multi-player game
1420 MissileMobj->special2 = P_GetPlayerNum(player);
1423 { // Always use red missiles in single player games
1424 MissileMobj->special2 = 2;
1428 MissileMobj->special1 = (int)linetarget;
1430 S_StartSound(MissileMobj, sfx_hrnpow);
1433 //----------------------------------------------------------------------------
1435 // PROC A_SkullRodPL2Seek
1437 //----------------------------------------------------------------------------
1439 void A_SkullRodPL2Seek(mobj_t *actor)
1441 P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*30);
1444 //----------------------------------------------------------------------------
1446 // PROC A_AddPlayerRain
1448 //----------------------------------------------------------------------------
1450 void A_AddPlayerRain(mobj_t *actor)
1455 playerNum = netgame ? actor->special2 : 0;
1456 if(!playeringame[playerNum])
1457 { // Player left the game
1460 player = &players[playerNum];
1461 if(player->health <= 0)
1465 if(player->rain1 && player->rain2)
1466 { // Terminate an active rain
1467 if(player->rain1->health < player->rain2->health)
1469 if(player->rain1->health > 16)
1471 player->rain1->health = 16;
1473 player->rain1 = NULL;
1477 if(player->rain2->health > 16)
1479 player->rain2->health = 16;
1481 player->rain2 = NULL;
1484 // Add rain mobj to list
1487 player->rain2 = actor;
1491 player->rain1 = actor;
1495 //----------------------------------------------------------------------------
1497 // PROC A_SkullRodStorm
1499 //----------------------------------------------------------------------------
1501 void A_SkullRodStorm(mobj_t *actor)
1509 if(actor->health-- == 0)
1511 P_SetMobjState(actor, S_NULL);
1512 playerNum = netgame ? actor->special2 : 0;
1513 if(!playeringame[playerNum])
1514 { // Player left the game
1517 player = &players[playerNum];
1518 if(player->health <= 0)
1522 if(player->rain1 == actor)
1524 player->rain1 = NULL;
1526 else if(player->rain2 == actor)
1528 player->rain2 = NULL;
1533 { // Fudge rain frequency
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))
1546 S_StartSound(actor, sfx_ramrain);
1551 //----------------------------------------------------------------------------
1553 // PROC A_RainImpact
1555 //----------------------------------------------------------------------------
1557 void A_RainImpact(mobj_t *actor)
1559 if(actor->z > actor->floorz)
1561 P_SetMobjState(actor, S_RAINAIRXPLR1_1+actor->special2);
1563 else if(P_Random() < 40)
1569 //----------------------------------------------------------------------------
1571 // PROC A_HideInCeiling
1573 //----------------------------------------------------------------------------
1575 void A_HideInCeiling(mobj_t *actor)
1577 actor->z = actor->ceilingz+4*FRACUNIT;
1580 //----------------------------------------------------------------------------
1582 // PROC A_FirePhoenixPL1
1584 //----------------------------------------------------------------------------
1586 void A_FirePhoenixPL1(player_t *player, pspdef_t *psp)
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]);
1599 //----------------------------------------------------------------------------
1601 // PROC A_PhoenixPuff
1603 //----------------------------------------------------------------------------
1605 void A_PhoenixPuff(mobj_t *actor)
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]);
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]);
1625 //----------------------------------------------------------------------------
1627 // PROC A_InitPhoenixPL2
1629 //----------------------------------------------------------------------------
1631 void A_InitPhoenixPL2(player_t *player, pspdef_t *psp)
1633 player->flamecount = FLAME_THROWER_TICS;
1636 //----------------------------------------------------------------------------
1638 // PROC A_FirePhoenixPL2
1640 // Flame thrower effect.
1642 //----------------------------------------------------------------------------
1644 void A_FirePhoenixPL2(player_t *player, pspdef_t *psp)
1652 if(--player->flamecount == 0)
1654 P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4);
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)
1667 slope = ((player->lookdir)<<FRACBITS)/173+(FRACUNIT/10);
1668 mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2);
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))
1678 S_StartSound(player->mo, sfx_phopow);
1680 P_CheckMissileSpawn(mo);
1683 //----------------------------------------------------------------------------
1685 // PROC A_ShutdownPhoenixPL2
1687 //----------------------------------------------------------------------------
1689 void A_ShutdownPhoenixPL2(player_t *player, pspdef_t *psp)
1691 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
1694 //----------------------------------------------------------------------------
1698 //----------------------------------------------------------------------------
1700 void A_FlameEnd(mobj_t *actor)
1702 actor->momz += 1.5*FRACUNIT;
1705 //----------------------------------------------------------------------------
1709 //----------------------------------------------------------------------------
1711 void A_FloatPuff(mobj_t *puff)
1713 puff->momz += 1.8*FRACUNIT;
1716 //---------------------------------------------------------------------------
1718 // PROC A_GauntletAttack
1720 //---------------------------------------------------------------------------
1722 void A_GauntletAttack(player_t *player, pspdef_t *psp)
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])
1735 damage = HITDICE(2);
1736 dist = 4*MELEERANGE;
1737 angle += (P_Random()-P_Random())<<17;
1738 PuffType = MT_GAUNTLETPUFF2;
1742 damage = HITDICE(2);
1743 dist = MELEERANGE+1;
1744 angle += (P_Random()-P_Random())<<18;
1745 PuffType = MT_GAUNTLETPUFF1;
1747 slope = P_AimLineAttack(player->mo, angle, dist);
1748 P_LineAttack(player->mo, angle, dist, slope, damage);
1753 player->extralight = !player->extralight;
1755 S_StartSound(player->mo, sfx_gntful);
1758 randVal = P_Random();
1761 player->extralight = 0;
1763 else if(randVal < 160)
1765 player->extralight = 1;
1769 player->extralight = 2;
1771 if(player->powers[pw_weaponlevel2])
1773 P_GiveBody(player, damage>>1);
1774 S_StartSound(player->mo, sfx_gntpow);
1778 S_StartSound(player->mo, sfx_gnthit);
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)
1785 if(angle-player->mo->angle < -ANG90/20)
1786 player->mo->angle = angle+ANG90/21;
1788 player->mo->angle -= ANG90/20;
1792 if(angle-player->mo->angle > ANG90/20)
1793 player->mo->angle = angle-ANG90/21;
1795 player->mo->angle += ANG90/20;
1797 player->mo->flags |= MF_JUSTATTACKED;
1800 void A_Light0(player_t *player, pspdef_t *psp)
1802 player->extralight = 0;
1805 void A_Light1(player_t *player, pspdef_t *psp)
1807 player->extralight = 1;
1810 void A_Light2(player_t *player, pspdef_t *psp)
1812 player->extralight = 2;
1815 //------------------------------------------------------------------------
1817 // PROC P_SetupPsprites
1819 // Called at start of level for each player
1821 //------------------------------------------------------------------------
1823 void P_SetupPsprites(player_t *player)
1827 // Remove all psprites
1828 for(i = 0; i < NUMPSPRITES; i++)
1830 player->psprites[i].state = NULL;
1832 // Spawn the ready weapon
1833 player->pendingweapon = player->readyweapon;
1834 P_BringUpWeapon(player);
1837 //------------------------------------------------------------------------
1839 // PROC P_MovePsprites
1841 // Called every tic by player thinking routine
1843 //------------------------------------------------------------------------
1845 void P_MovePsprites(player_t *player)
1851 psp = &player->psprites[0];
1852 for(i = 0; i < NUMPSPRITES; i++, psp++)
1854 if((state = psp->state) != 0) // a null state means not active
1856 // drop tic count and possibly change state
1857 if(psp->tics != -1) // a -1 tic count never changes
1862 P_SetPsprite(player, i, psp->state->nextstate);
1867 player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
1868 player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;