summaryrefslogtreecommitdiff
path: root/src/heretic/p_pspr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/heretic/p_pspr.c')
-rw-r--r--src/heretic/p_pspr.c1869
1 files changed, 1869 insertions, 0 deletions
diff --git a/src/heretic/p_pspr.c b/src/heretic/p_pspr.c
new file mode 100644
index 00000000..aa8da282
--- /dev/null
+++ b/src/heretic/p_pspr.c
@@ -0,0 +1,1869 @@
+
+// P_pspr.c
+
+#include "DoomDef.h"
+#include "P_local.h"
+#include "soundst.h"
+
+// Macros
+
+#define LOWERSPEED FRACUNIT*6
+#define RAISESPEED FRACUNIT*6
+#define WEAPONBOTTOM 128*FRACUNIT
+#define WEAPONTOP 32*FRACUNIT
+#define FLAME_THROWER_TICS 10*35
+#define MAGIC_JUNK 1234
+#define MAX_MACE_SPOTS 8
+
+static int MaceSpotCount;
+static struct
+{
+ fixed_t x;
+ fixed_t y;
+} MaceSpots[MAX_MACE_SPOTS];
+
+fixed_t bulletslope;
+
+static int WeaponAmmoUsePL1[NUMWEAPONS] = {
+ 0, // staff
+ USE_GWND_AMMO_1, // gold wand
+ USE_CBOW_AMMO_1, // crossbow
+ USE_BLSR_AMMO_1, // blaster
+ USE_SKRD_AMMO_1, // skull rod
+ USE_PHRD_AMMO_1, // phoenix rod
+ USE_MACE_AMMO_1, // mace
+ 0, // gauntlets
+ 0 // beak
+};
+
+static int WeaponAmmoUsePL2[NUMWEAPONS] = {
+ 0, // staff
+ USE_GWND_AMMO_2, // gold wand
+ USE_CBOW_AMMO_2, // crossbow
+ USE_BLSR_AMMO_2, // blaster
+ USE_SKRD_AMMO_2, // skull rod
+ USE_PHRD_AMMO_2, // phoenix rod
+ USE_MACE_AMMO_2, // mace
+ 0, // gauntlets
+ 0 // beak
+};
+
+weaponinfo_t wpnlev1info[NUMWEAPONS] =
+{
+ { // Staff
+ am_noammo, // ammo
+ S_STAFFUP, // upstate
+ S_STAFFDOWN, // downstate
+ S_STAFFREADY, // readystate
+ S_STAFFATK1_1, // atkstate
+ S_STAFFATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gold wand
+ am_goldwand, // ammo
+ S_GOLDWANDUP, // upstate
+ S_GOLDWANDDOWN, // downstate
+ S_GOLDWANDREADY, // readystate
+ S_GOLDWANDATK1_1, // atkstate
+ S_GOLDWANDATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Crossbow
+ am_crossbow, // ammo
+ S_CRBOWUP, // upstate
+ S_CRBOWDOWN, // downstate
+ S_CRBOW1, // readystate
+ S_CRBOWATK1_1, // atkstate
+ S_CRBOWATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Blaster
+ am_blaster, // ammo
+ S_BLASTERUP, // upstate
+ S_BLASTERDOWN, // downstate
+ S_BLASTERREADY, // readystate
+ S_BLASTERATK1_1, // atkstate
+ S_BLASTERATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Skull rod
+ am_skullrod, // ammo
+ S_HORNRODUP, // upstate
+ S_HORNRODDOWN, // downstate
+ S_HORNRODREADY, // readystae
+ S_HORNRODATK1_1, // atkstate
+ S_HORNRODATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Phoenix rod
+ am_phoenixrod, // ammo
+ S_PHOENIXUP, // upstate
+ S_PHOENIXDOWN, // downstate
+ S_PHOENIXREADY, // readystate
+ S_PHOENIXATK1_1, // atkstate
+ S_PHOENIXATK1_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mace
+ am_mace, // ammo
+ S_MACEUP, // upstate
+ S_MACEDOWN, // downstate
+ S_MACEREADY, // readystate
+ S_MACEATK1_1, // atkstate
+ S_MACEATK1_2, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gauntlets
+ am_noammo, // ammo
+ S_GAUNTLETUP, // upstate
+ S_GAUNTLETDOWN, // downstate
+ S_GAUNTLETREADY, // readystate
+ S_GAUNTLETATK1_1, // atkstate
+ S_GAUNTLETATK1_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Beak
+ am_noammo, // ammo
+ S_BEAKUP, // upstate
+ S_BEAKDOWN, // downstate
+ S_BEAKREADY, // readystate
+ S_BEAKATK1_1, // atkstate
+ S_BEAKATK1_1, // holdatkstate
+ S_NULL // flashstate
+ }
+};
+
+weaponinfo_t wpnlev2info[NUMWEAPONS] =
+{
+ { // Staff
+ am_noammo, // ammo
+ S_STAFFUP2, // upstate
+ S_STAFFDOWN2, // downstate
+ S_STAFFREADY2_1, // readystate
+ S_STAFFATK2_1, // atkstate
+ S_STAFFATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gold wand
+ am_goldwand, // ammo
+ S_GOLDWANDUP, // upstate
+ S_GOLDWANDDOWN, // downstate
+ S_GOLDWANDREADY, // readystate
+ S_GOLDWANDATK2_1, // atkstate
+ S_GOLDWANDATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Crossbow
+ am_crossbow, // ammo
+ S_CRBOWUP, // upstate
+ S_CRBOWDOWN, // downstate
+ S_CRBOW1, // readystate
+ S_CRBOWATK2_1, // atkstate
+ S_CRBOWATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Blaster
+ am_blaster, // ammo
+ S_BLASTERUP, // upstate
+ S_BLASTERDOWN, // downstate
+ S_BLASTERREADY, // readystate
+ S_BLASTERATK2_1, // atkstate
+ S_BLASTERATK2_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Skull rod
+ am_skullrod, // ammo
+ S_HORNRODUP, // upstate
+ S_HORNRODDOWN, // downstate
+ S_HORNRODREADY, // readystae
+ S_HORNRODATK2_1, // atkstate
+ S_HORNRODATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Phoenix rod
+ am_phoenixrod, // ammo
+ S_PHOENIXUP, // upstate
+ S_PHOENIXDOWN, // downstate
+ S_PHOENIXREADY, // readystate
+ S_PHOENIXATK2_1, // atkstate
+ S_PHOENIXATK2_2, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Mace
+ am_mace, // ammo
+ S_MACEUP, // upstate
+ S_MACEDOWN, // downstate
+ S_MACEREADY, // readystate
+ S_MACEATK2_1, // atkstate
+ S_MACEATK2_1, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Gauntlets
+ am_noammo, // ammo
+ S_GAUNTLETUP2, // upstate
+ S_GAUNTLETDOWN2, // downstate
+ S_GAUNTLETREADY2_1, // readystate
+ S_GAUNTLETATK2_1, // atkstate
+ S_GAUNTLETATK2_3, // holdatkstate
+ S_NULL // flashstate
+ },
+ { // Beak
+ am_noammo, // ammo
+ S_BEAKUP, // upstate
+ S_BEAKDOWN, // downstate
+ S_BEAKREADY, // readystate
+ S_BEAKATK2_1, // atkstate
+ S_BEAKATK2_1, // holdatkstate
+ S_NULL // flashstate
+ }
+};
+
+//---------------------------------------------------------------------------
+//
+// PROC P_OpenWeapons
+//
+// Called at level load before things are loaded.
+//
+//---------------------------------------------------------------------------
+
+void P_OpenWeapons(void)
+{
+ MaceSpotCount = 0;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_AddMaceSpot
+//
+//---------------------------------------------------------------------------
+
+void P_AddMaceSpot(mapthing_t *mthing)
+{
+ if(MaceSpotCount == MAX_MACE_SPOTS)
+ {
+ I_Error("Too many mace spots.");
+ }
+ MaceSpots[MaceSpotCount].x = mthing->x<<FRACBITS;
+ MaceSpots[MaceSpotCount].y = mthing->y<<FRACBITS;
+ MaceSpotCount++;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_RepositionMace
+//
+// Chooses the next spot to place the mace.
+//
+//---------------------------------------------------------------------------
+
+void P_RepositionMace(mobj_t *mo)
+{
+ int spot;
+ subsector_t *ss;
+
+ P_UnsetThingPosition(mo);
+ spot = P_Random()%MaceSpotCount;
+ mo->x = MaceSpots[spot].x;
+ mo->y = MaceSpots[spot].y;
+ ss = R_PointInSubsector(mo->x, mo->y);
+ mo->z = mo->floorz = ss->sector->floorheight;
+ mo->ceilingz = ss->sector->ceilingheight;
+ P_SetThingPosition(mo);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_CloseWeapons
+//
+// Called at level load after things are loaded.
+//
+//---------------------------------------------------------------------------
+
+void P_CloseWeapons(void)
+{
+ int spot;
+
+ if(!MaceSpotCount)
+ { // No maces placed
+ return;
+ }
+ if(!deathmatch && P_Random() < 64)
+ { // Sometimes doesn't show up if not in deathmatch
+ return;
+ }
+ spot = P_Random()%MaceSpotCount;
+ P_SpawnMobj(MaceSpots[spot].x, MaceSpots[spot].y, ONFLOORZ, MT_WMACE);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_SetPsprite
+//
+//---------------------------------------------------------------------------
+
+void P_SetPsprite(player_t *player, int position, statenum_t stnum)
+{
+ pspdef_t *psp;
+ state_t *state;
+
+ psp = &player->psprites[position];
+ do
+ {
+ if(!stnum)
+ { // Object removed itself.
+ psp->state = NULL;
+ break;
+ }
+ state = &states[stnum];
+ psp->state = state;
+ psp->tics = state->tics; // could be 0
+ if(state->misc1)
+ { // Set coordinates.
+ psp->sx = state->misc1<<FRACBITS;
+ psp->sy = state->misc2<<FRACBITS;
+ }
+ if(state->action)
+ { // Call action routine.
+ state->action(player, psp);
+ if(!psp->state)
+ {
+ break;
+ }
+ }
+ stnum = psp->state->nextstate;
+ } while(!psp->tics); // An initial state of 0 could cycle through.
+}
+
+/*
+=================
+=
+= P_CalcSwing
+=
+=================
+*/
+
+/*
+fixed_t swingx, swingy;
+void P_CalcSwing (player_t *player)
+{
+ fixed_t swing;
+ int angle;
+
+// OPTIMIZE: tablify this
+
+ swing = player->bob;
+
+ angle = (FINEANGLES/70*leveltime)&FINEMASK;
+ swingx = FixedMul ( swing, finesine[angle]);
+
+ angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
+ swingy = -FixedMul ( swingx, finesine[angle]);
+}
+*/
+
+//---------------------------------------------------------------------------
+//
+// PROC P_ActivateBeak
+//
+//---------------------------------------------------------------------------
+
+void P_ActivateBeak(player_t *player)
+{
+ player->pendingweapon = wp_nochange;
+ player->readyweapon = wp_beak;
+ player->psprites[ps_weapon].sy = WEAPONTOP;
+ P_SetPsprite(player, ps_weapon, S_BEAKREADY);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_PostChickenWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_PostChickenWeapon(player_t *player, weapontype_t weapon)
+{
+ if(weapon == wp_beak)
+ { // Should never happen
+ weapon = wp_staff;
+ }
+ player->pendingweapon = wp_nochange;
+ player->readyweapon = weapon;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, wpnlev1info[weapon].upstate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_BringUpWeapon
+//
+// Starts bringing the pending weapon up from the bottom of the screen.
+//
+//---------------------------------------------------------------------------
+
+void P_BringUpWeapon(player_t *player)
+{
+ statenum_t new;
+
+ if(player->pendingweapon == wp_nochange)
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ if(player->pendingweapon == wp_gauntlets)
+ {
+ S_StartSound(player->mo, sfx_gntact);
+ }
+ if(player->powers[pw_weaponlevel2])
+ {
+ new = wpnlev2info[player->pendingweapon].upstate;
+ }
+ else
+ {
+ new = wpnlev1info[player->pendingweapon].upstate;
+ }
+ player->pendingweapon = wp_nochange;
+ player->psprites[ps_weapon].sy = WEAPONBOTTOM;
+ P_SetPsprite(player, ps_weapon, new);
+}
+
+//---------------------------------------------------------------------------
+//
+// FUNC P_CheckAmmo
+//
+// Returns true if there is enough ammo to shoot. If not, selects the
+// next weapon to use.
+//
+//---------------------------------------------------------------------------
+
+boolean P_CheckAmmo(player_t *player)
+{
+ ammotype_t ammo;
+ int *ammoUse;
+ int count;
+
+ ammo = wpnlev1info[player->readyweapon].ammo;
+ if(player->powers[pw_weaponlevel2] && !deathmatch)
+ {
+ ammoUse = WeaponAmmoUsePL2;
+ }
+ else
+ {
+ ammoUse = WeaponAmmoUsePL1;
+ }
+ count = ammoUse[player->readyweapon];
+ if(ammo == am_noammo || player->ammo[ammo] >= count)
+ {
+ return(true);
+ }
+ // out of ammo, pick a weapon to change to
+ do
+ {
+ if(player->weaponowned[wp_skullrod]
+ && player->ammo[am_skullrod] > ammoUse[wp_skullrod])
+ {
+ player->pendingweapon = wp_skullrod;
+ }
+ else if(player->weaponowned[wp_blaster]
+ && player->ammo[am_blaster] > ammoUse[wp_blaster])
+ {
+ player->pendingweapon = wp_blaster;
+ }
+ else if(player->weaponowned[wp_crossbow]
+ && player->ammo[am_crossbow] > ammoUse[wp_crossbow])
+ {
+ player->pendingweapon = wp_crossbow;
+ }
+ else if(player->weaponowned[wp_mace]
+ && player->ammo[am_mace] > ammoUse[wp_mace])
+ {
+ player->pendingweapon = wp_mace;
+ }
+ else if(player->ammo[am_goldwand] > ammoUse[wp_goldwand])
+ {
+ player->pendingweapon = wp_goldwand;
+ }
+ else if(player->weaponowned[wp_gauntlets])
+ {
+ player->pendingweapon = wp_gauntlets;
+ }
+ else if(player->weaponowned[wp_phoenixrod]
+ && player->ammo[am_phoenixrod] > ammoUse[wp_phoenixrod])
+ {
+ player->pendingweapon = wp_phoenixrod;
+ }
+ else
+ {
+ player->pendingweapon = wp_staff;
+ }
+ } while(player->pendingweapon == wp_nochange);
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+ return(false);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_FireWeapon
+//
+//---------------------------------------------------------------------------
+
+void P_FireWeapon(player_t *player)
+{
+ weaponinfo_t *wpinfo;
+ statenum_t attackState;
+
+ if(!P_CheckAmmo(player))
+ {
+ return;
+ }
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+ wpinfo = player->powers[pw_weaponlevel2] ? &wpnlev2info[0]
+ : &wpnlev1info[0];
+ attackState = player->refire ? wpinfo[player->readyweapon].holdatkstate
+ : wpinfo[player->readyweapon].atkstate;
+ P_SetPsprite(player, ps_weapon, attackState);
+ P_NoiseAlert(player->mo, player->mo);
+ if(player->readyweapon == wp_gauntlets && !player->refire)
+ { // Play the sound for the initial gauntlet attack
+ S_StartSound(player->mo, sfx_gntuse);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_DropWeapon
+//
+// The player died, so put the weapon away.
+//
+//---------------------------------------------------------------------------
+
+void P_DropWeapon(player_t *player)
+{
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_WeaponReady
+//
+// The player can fire the weapon or change to another weapon at this time.
+//
+//---------------------------------------------------------------------------
+
+void A_WeaponReady(player_t *player, pspdef_t *psp)
+{
+ int angle;
+
+ if(player->chickenTics)
+ { // Change to the chicken beak
+ P_ActivateBeak(player);
+ return;
+ }
+ // Change player from attack state
+ if(player->mo->state == &states[S_PLAY_ATK1]
+ || player->mo->state == &states[S_PLAY_ATK2])
+ {
+ P_SetMobjState(player->mo, S_PLAY);
+ }
+ // Check for staff PL2 active sound
+ if((player->readyweapon == wp_staff)
+ && (psp->state == &states[S_STAFFREADY2_1])
+ && P_Random() < 128)
+ {
+ S_StartSound(player->mo, sfx_stfcrk);
+ }
+ // Put the weapon away if the player has a pending weapon or has
+ // died.
+ if(player->pendingweapon != wp_nochange || !player->health)
+ {
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].downstate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].downstate);
+ }
+ return;
+ }
+
+ // Check for fire. The phoenix rod does not auto fire.
+ if(player->cmd.buttons&BT_ATTACK)
+ {
+ if(!player->attackdown || (player->readyweapon != wp_phoenixrod))
+ {
+ player->attackdown = true;
+ P_FireWeapon(player);
+ return;
+ }
+ }
+ else
+ {
+ player->attackdown = false;
+ }
+
+ // Bob the weapon based on movement speed.
+ angle = (128*leveltime)&FINEMASK;
+ psp->sx = FRACUNIT+FixedMul(player->bob, finecosine[angle]);
+ angle &= FINEANGLES/2-1;
+ psp->sy = WEAPONTOP+FixedMul(player->bob, finesine[angle]);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC P_UpdateBeak
+//
+//---------------------------------------------------------------------------
+
+void P_UpdateBeak(player_t *player, pspdef_t *psp)
+{
+ psp->sy = WEAPONTOP+(player->chickenPeck<<(FRACBITS-1));
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_BeakReady
+//
+//---------------------------------------------------------------------------
+
+void A_BeakReady(player_t *player, pspdef_t *psp)
+{
+ if(player->cmd.buttons&BT_ATTACK)
+ { // Chicken beak attack
+ player->attackdown = true;
+ P_SetMobjState(player->mo, S_CHICPLAY_ATK1);
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon, S_BEAKATK2_1);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon, S_BEAKATK1_1);
+ }
+ P_NoiseAlert(player->mo, player->mo);
+ }
+ else
+ {
+ if(player->mo->state == &states[S_CHICPLAY_ATK1])
+ { // Take out of attack state
+ P_SetMobjState(player->mo, S_CHICPLAY);
+ }
+ player->attackdown = false;
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_ReFire
+//
+// The player can re fire the weapon without lowering it entirely.
+//
+//---------------------------------------------------------------------------
+
+void A_ReFire(player_t *player, pspdef_t *psp)
+{
+ if((player->cmd.buttons&BT_ATTACK)
+ && player->pendingweapon == wp_nochange && player->health)
+ {
+ player->refire++;
+ P_FireWeapon(player);
+ }
+ else
+ {
+ player->refire = 0;
+ P_CheckAmmo(player);
+ }
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Lower
+//
+//---------------------------------------------------------------------------
+
+void A_Lower(player_t *player, pspdef_t *psp)
+{
+ if(player->chickenTics)
+ {
+ psp->sy = WEAPONBOTTOM;
+ }
+ else
+ {
+ psp->sy += LOWERSPEED;
+ }
+ if(psp->sy < WEAPONBOTTOM)
+ { // Not lowered all the way yet
+ return;
+ }
+ if(player->playerstate == PST_DEAD)
+ { // Player is dead, so don't bring up a pending weapon
+ psp->sy = WEAPONBOTTOM;
+ return;
+ }
+ if(!player->health)
+ { // Player is dead, so keep the weapon off screen
+ P_SetPsprite(player, ps_weapon, S_NULL);
+ return;
+ }
+ player->readyweapon = player->pendingweapon;
+ P_BringUpWeapon(player);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_BeakRaise
+//
+//---------------------------------------------------------------------------
+
+void A_BeakRaise(player_t *player, pspdef_t *psp)
+{
+ psp->sy = WEAPONTOP;
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].readystate);
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_Raise
+//
+//---------------------------------------------------------------------------
+
+void A_Raise(player_t *player, pspdef_t *psp)
+{
+ psp->sy -= RAISESPEED;
+ if(psp->sy > WEAPONTOP)
+ { // Not raised all the way yet
+ return;
+ }
+ psp->sy = WEAPONTOP;
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev2info[player->readyweapon].readystate);
+ }
+ else
+ {
+ P_SetPsprite(player, ps_weapon,
+ wpnlev1info[player->readyweapon].readystate);
+ }
+}
+
+/*
+===============
+=
+= P_BulletSlope
+=
+= Sets a slope so a near miss is at aproximately the height of the
+= intended target
+=
+===============
+*/
+
+void P_BulletSlope (mobj_t *mo)
+{
+ angle_t an;
+
+//
+// see which target is to be aimed at
+//
+ an = mo->angle;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an += 1<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
+ }
+ if (!linetarget)
+ {
+ an += 2<<26;
+ bulletslope = (mo->player->lookdir<<FRACBITS)/173;
+ }
+ }
+}
+
+//****************************************************************************
+//
+// WEAPON ATTACKS
+//
+//****************************************************************************
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeakAttackPL1
+//
+//----------------------------------------------------------------------------
+
+void A_BeakAttackPL1(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 1+(P_Random()&3);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_BEAKPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if(linetarget)
+ {
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x, linetarget->y);
+ }
+ S_StartSound(player->mo, sfx_chicpk1+(P_Random()%3));
+ player->chickenPeck = 12;
+ psp->tics -= P_Random()&7;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BeakAttackPL2
+//
+//----------------------------------------------------------------------------
+
+void A_BeakAttackPL2(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = HITDICE(4);
+ angle = player->mo->angle;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_BEAKPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if(linetarget)
+ {
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x, linetarget->y);
+ }
+ S_StartSound(player->mo, sfx_chicpk1+(P_Random()%3));
+ player->chickenPeck = 12;
+ psp->tics -= P_Random()&3;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_StaffAttackPL1
+//
+//----------------------------------------------------------------------------
+
+void A_StaffAttackPL1(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ damage = 5+(P_Random()&15);
+ angle = player->mo->angle;
+ angle += (P_Random()-P_Random())<<18;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_STAFFPUFF;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if(linetarget)
+ {
+ //S_StartSound(player->mo, sfx_stfhit);
+ // turn to face target
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x, linetarget->y);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_StaffAttackPL2
+//
+//----------------------------------------------------------------------------
+
+void A_StaffAttackPL2(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+
+ // P_inter.c:P_DamageMobj() handles target momentums
+ damage = 18+(P_Random()&63);
+ angle = player->mo->angle;
+ angle += (P_Random()-P_Random())<<18;
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE);
+ PuffType = MT_STAFFPUFF2;
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+ if(linetarget)
+ {
+ //S_StartSound(player->mo, sfx_stfpow);
+ // turn to face target
+ player->mo->angle = R_PointToAngle2(player->mo->x,
+ player->mo->y, linetarget->x, linetarget->y);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireBlasterPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireBlasterPL1(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+
+ mo = player->mo;
+ S_StartSound(mo, sfx_gldhit);
+ player->ammo[am_blaster] -= USE_BLSR_AMMO_1;
+ P_BulletSlope(mo);
+ damage = HITDICE(4);
+ angle = mo->angle;
+ if(player->refire)
+ {
+ angle += (P_Random()-P_Random())<<18;
+ }
+ PuffType = MT_BLASTERPUFF1;
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ S_StartSound(player->mo, sfx_blssht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireBlasterPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireBlasterPL2(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ player->ammo[am_blaster] -=
+ deathmatch ? USE_BLSR_AMMO_1 : USE_BLSR_AMMO_2;
+ mo = P_SpawnPlayerMissile(player->mo, MT_BLASTERFX1);
+ if(mo)
+ {
+ mo->thinker.function = P_BlasterMobjThinker;
+ }
+ S_StartSound(player->mo, sfx_blssht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireGoldWandPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireGoldWandPL1(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+
+ mo = player->mo;
+ player->ammo[am_goldwand] -= USE_GWND_AMMO_1;
+ P_BulletSlope(mo);
+ damage = 7+(P_Random()&7);
+ angle = mo->angle;
+ if(player->refire)
+ {
+ angle += (P_Random()-P_Random())<<18;
+ }
+ PuffType = MT_GOLDWANDPUFF1;
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ S_StartSound(player->mo, sfx_gldhit);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireGoldWandPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireGoldWandPL2(player_t *player, pspdef_t *psp)
+{
+ int i;
+ mobj_t *mo;
+ angle_t angle;
+ int damage;
+ fixed_t momz;
+
+ mo = player->mo;
+ player->ammo[am_goldwand] -=
+ deathmatch ? USE_GWND_AMMO_1 : USE_GWND_AMMO_2;
+ PuffType = MT_GOLDWANDPUFF2;
+ P_BulletSlope(mo);
+ momz = FixedMul(mobjinfo[MT_GOLDWANDFX2].speed, bulletslope);
+ P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle-(ANG45/8), momz);
+ P_SpawnMissileAngle(mo, MT_GOLDWANDFX2, mo->angle+(ANG45/8), momz);
+ angle = mo->angle-(ANG45/8);
+ for(i = 0; i < 5; i++)
+ {
+ damage = 1+(P_Random()&7);
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+ angle += ((ANG45/8)*2)/4;
+ }
+ S_StartSound(player->mo, sfx_gldhit);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL1B
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL1B(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+ mobj_t *ball;
+ angle_t angle;
+
+ if(player->ammo[am_mace] < USE_MACE_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_mace] -= USE_MACE_AMMO_1;
+ pmo = player->mo;
+ ball = P_SpawnMobj(pmo->x, pmo->y, pmo->z+28*FRACUNIT
+ - FOOTCLIPSIZE*(pmo->flags2&MF2_FEETARECLIPPED != 0), MT_MACEFX2);
+ ball->momz = 2*FRACUNIT+((player->lookdir)<<(FRACBITS-5));
+ angle = pmo->angle;
+ ball->target = pmo;
+ ball->angle = angle;
+ ball->z += (player->lookdir)<<(FRACBITS-4);
+ angle >>= ANGLETOFINESHIFT;
+ ball->momx = (pmo->momx>>1)
+ +FixedMul(ball->info->speed, finecosine[angle]);
+ ball->momy = (pmo->momy>>1)
+ +FixedMul(ball->info->speed, finesine[angle]);
+ S_StartSound(ball, sfx_lobsht);
+ P_CheckMissileSpawn(ball);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL1(player_t *player, pspdef_t *psp)
+{
+ mobj_t *ball;
+
+ if(P_Random() < 28)
+ {
+ A_FireMacePL1B(player, psp);
+ return;
+ }
+ if(player->ammo[am_mace] < USE_MACE_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_mace] -= USE_MACE_AMMO_1;
+ psp->sx = ((P_Random()&3)-2)*FRACUNIT;
+ psp->sy = WEAPONTOP+(P_Random()&3)*FRACUNIT;
+ ball = P_SPMAngle(player->mo, MT_MACEFX1, player->mo->angle
+ +(((P_Random()&7)-4)<<24));
+ if(ball)
+ {
+ ball->special1 = 16; // tics till dropoff
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MacePL1Check
+//
+//----------------------------------------------------------------------------
+
+void A_MacePL1Check(mobj_t *ball)
+{
+ angle_t angle;
+
+ if(ball->special1 == 0)
+ {
+ return;
+ }
+ ball->special1 -= 4;
+ if(ball->special1 > 0)
+ {
+ return;
+ }
+ ball->special1 = 0;
+ ball->flags2 |= MF2_LOGRAV;
+ angle = ball->angle>>ANGLETOFINESHIFT;
+ ball->momx = FixedMul(7*FRACUNIT, finecosine[angle]);
+ ball->momy = FixedMul(7*FRACUNIT, finesine[angle]);
+ ball->momz -= ball->momz>>1;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MaceBallImpact
+//
+//----------------------------------------------------------------------------
+
+void A_MaceBallImpact(mobj_t *ball)
+{
+ if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if((ball->health != MAGIC_JUNK) && (ball->z <= ball->floorz)
+ && ball->momz)
+ { // Bounce
+ ball->health = MAGIC_JUNK;
+ ball->momz = (ball->momz*192)>>8;
+ ball->flags2 &= ~MF2_FLOORBOUNCE;
+ P_SetMobjState(ball, ball->info->spawnstate);
+ S_StartSound(ball, sfx_bounce);
+ }
+ else
+ { // Explode
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~MF2_LOGRAV;
+ S_StartSound(ball, sfx_lobhit);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_MaceBallImpact2
+//
+//----------------------------------------------------------------------------
+
+void A_MaceBallImpact2(mobj_t *ball)
+{
+ mobj_t *tiny;
+ angle_t angle;
+
+ if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if((ball->z != ball->floorz) || (ball->momz < 2*FRACUNIT))
+ { // Explode
+ ball->momx = ball->momy = ball->momz = 0;
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~(MF2_LOGRAV|MF2_FLOORBOUNCE);
+ }
+ else
+ { // Bounce
+ ball->momz = (ball->momz*192)>>8;
+ P_SetMobjState(ball, ball->info->spawnstate);
+
+ tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
+ angle = ball->angle+ANG90;
+ tiny->target = ball->target;
+ tiny->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ tiny->momx = (ball->momx>>1)+FixedMul(ball->momz-FRACUNIT,
+ finecosine[angle]);
+ tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
+ finesine[angle]);
+ tiny->momz = ball->momz;
+ P_CheckMissileSpawn(tiny);
+
+ tiny = P_SpawnMobj(ball->x, ball->y, ball->z, MT_MACEFX3);
+ angle = ball->angle-ANG90;
+ tiny->target = ball->target;
+ tiny->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ tiny->momx = (ball->momx>>1)+FixedMul(ball->momz-FRACUNIT,
+ finecosine[angle]);
+ tiny->momy = (ball->momy>>1)+FixedMul(ball->momz-FRACUNIT,
+ finesine[angle]);
+ tiny->momz = ball->momz;
+ P_CheckMissileSpawn(tiny);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireMacePL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireMacePL2(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ player->ammo[am_mace] -=
+ deathmatch ? USE_MACE_AMMO_1 : USE_MACE_AMMO_2;
+ mo = P_SpawnPlayerMissile(player->mo, MT_MACEFX4);
+ if(mo)
+ {
+ mo->momx += player->mo->momx;
+ mo->momy += player->mo->momy;
+ mo->momz = 2*FRACUNIT+((player->lookdir)<<(FRACBITS-5));
+ if(linetarget)
+ {
+ mo->special1 = (int)linetarget;
+ }
+ }
+ S_StartSound(player->mo, sfx_lobsht);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_DeathBallImpact
+//
+//----------------------------------------------------------------------------
+
+void A_DeathBallImpact(mobj_t *ball)
+{
+ int i;
+ mobj_t *target;
+ angle_t angle;
+ boolean newAngle;
+
+ if((ball->z <= ball->floorz) && (P_HitFloor(ball) != FLOOR_SOLID))
+ { // Landed in some sort of liquid
+ P_RemoveMobj(ball);
+ return;
+ }
+ if((ball->z <= ball->floorz) && ball->momz)
+ { // Bounce
+ newAngle = false;
+ target = (mobj_t *)ball->special1;
+ if(target)
+ {
+ if(!(target->flags&MF_SHOOTABLE))
+ { // Target died
+ ball->special1 = 0;
+ }
+ else
+ { // Seek
+ angle = R_PointToAngle2(ball->x, ball->y,
+ target->x, target->y);
+ newAngle = true;
+ }
+ }
+ else
+ { // Find new target
+ angle = 0;
+ for(i = 0; i < 16; i++)
+ {
+ P_AimLineAttack(ball, angle, 10*64*FRACUNIT);
+ if(linetarget && ball->target != linetarget)
+ {
+ ball->special1 = (int)linetarget;
+ angle = R_PointToAngle2(ball->x, ball->y,
+ linetarget->x, linetarget->y);
+ newAngle = true;
+ break;
+ }
+ angle += ANGLE_45/2;
+ }
+ }
+ if(newAngle)
+ {
+ ball->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ ball->momx = FixedMul(ball->info->speed, finecosine[angle]);
+ ball->momy = FixedMul(ball->info->speed, finesine[angle]);
+ }
+ P_SetMobjState(ball, ball->info->spawnstate);
+ S_StartSound(ball, sfx_pstop);
+ }
+ else
+ { // Explode
+ ball->flags |= MF_NOGRAVITY;
+ ball->flags2 &= ~MF2_LOGRAV;
+ S_StartSound(ball, sfx_phohit);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SpawnRippers
+//
+//----------------------------------------------------------------------------
+
+void A_SpawnRippers(mobj_t *actor)
+{
+ int i;
+ angle_t angle;
+ mobj_t *ripper;
+
+ for(i = 0; i < 8; i++)
+ {
+ ripper = P_SpawnMobj(actor->x, actor->y, actor->z, MT_RIPPER);
+ angle = i*ANG45;
+ ripper->target = actor->target;
+ ripper->angle = angle;
+ angle >>= ANGLETOFINESHIFT;
+ ripper->momx = FixedMul(ripper->info->speed, finecosine[angle]);
+ ripper->momy = FixedMul(ripper->info->speed, finesine[angle]);
+ P_CheckMissileSpawn(ripper);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireCrossbowPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireCrossbowPL1(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+
+ pmo = player->mo;
+ player->ammo[am_crossbow] -= USE_CBOW_AMMO_1;
+ P_SpawnPlayerMissile(pmo, MT_CRBOWFX1);
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle-(ANG45/10));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle+(ANG45/10));
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireCrossbowPL2
+//
+//----------------------------------------------------------------------------
+
+void A_FireCrossbowPL2(player_t *player, pspdef_t *psp)
+{
+ mobj_t *pmo;
+
+ pmo = player->mo;
+ player->ammo[am_crossbow] -=
+ deathmatch ? USE_CBOW_AMMO_1 : USE_CBOW_AMMO_2;
+ P_SpawnPlayerMissile(pmo, MT_CRBOWFX2);
+ P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle-(ANG45/10));
+ P_SPMAngle(pmo, MT_CRBOWFX2, pmo->angle+(ANG45/10));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle-(ANG45/5));
+ P_SPMAngle(pmo, MT_CRBOWFX3, pmo->angle+(ANG45/5));
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_BoltSpark
+//
+//----------------------------------------------------------------------------
+
+void A_BoltSpark(mobj_t *bolt)
+{
+ mobj_t *spark;
+
+ if(P_Random() > 50)
+ {
+ spark = P_SpawnMobj(bolt->x, bolt->y, bolt->z, MT_CRBOWFX4);
+ spark->x += (P_Random()-P_Random())<<10;
+ spark->y += (P_Random()-P_Random())<<10;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireSkullRodPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FireSkullRodPL1(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+
+ if(player->ammo[am_skullrod] < USE_SKRD_AMMO_1)
+ {
+ return;
+ }
+ player->ammo[am_skullrod] -= USE_SKRD_AMMO_1;
+ mo = P_SpawnPlayerMissile(player->mo, MT_HORNRODFX1);
+ // Randomize the first frame
+ if(mo && P_Random() > 128)
+ {
+ P_SetMobjState(mo, S_HRODFX1_2);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FireSkullRodPL2
+//
+// The special2 field holds the player number that shot the rain missile.
+// The special1 field is used for the seeking routines, then as a counter
+// for the sound looping.
+//
+//----------------------------------------------------------------------------
+
+void A_FireSkullRodPL2(player_t *player, pspdef_t *psp)
+{
+ player->ammo[am_skullrod] -=
+ deathmatch ? USE_SKRD_AMMO_1 : USE_SKRD_AMMO_2;
+ P_SpawnPlayerMissile(player->mo, MT_HORNRODFX2);
+ // Use MissileMobj instead of the return value from
+ // P_SpawnPlayerMissile because we need to give info to the mobj
+ // even if it exploded immediately.
+ if(netgame)
+ { // Multi-player game
+ MissileMobj->special2 = P_GetPlayerNum(player);
+ }
+ else
+ { // Always use red missiles in single player games
+ MissileMobj->special2 = 2;
+ }
+ if(linetarget)
+ {
+ MissileMobj->special1 = (int)linetarget;
+ }
+ S_StartSound(MissileMobj, sfx_hrnpow);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullRodPL2Seek
+//
+//----------------------------------------------------------------------------
+
+void A_SkullRodPL2Seek(mobj_t *actor)
+{
+ P_SeekerMissile(actor, ANGLE_1*10, ANGLE_1*30);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_AddPlayerRain
+//
+//----------------------------------------------------------------------------
+
+void A_AddPlayerRain(mobj_t *actor)
+{
+ int playerNum;
+ player_t *player;
+
+ playerNum = netgame ? actor->special2 : 0;
+ if(!playeringame[playerNum])
+ { // Player left the game
+ return;
+ }
+ player = &players[playerNum];
+ if(player->health <= 0)
+ { // Player is dead
+ return;
+ }
+ if(player->rain1 && player->rain2)
+ { // Terminate an active rain
+ if(player->rain1->health < player->rain2->health)
+ {
+ if(player->rain1->health > 16)
+ {
+ player->rain1->health = 16;
+ }
+ player->rain1 = NULL;
+ }
+ else
+ {
+ if(player->rain2->health > 16)
+ {
+ player->rain2->health = 16;
+ }
+ player->rain2 = NULL;
+ }
+ }
+ // Add rain mobj to list
+ if(player->rain1)
+ {
+ player->rain2 = actor;
+ }
+ else
+ {
+ player->rain1 = actor;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_SkullRodStorm
+//
+//----------------------------------------------------------------------------
+
+void A_SkullRodStorm(mobj_t *actor)
+{
+ fixed_t x;
+ fixed_t y;
+ mobj_t *mo;
+ int playerNum;
+ player_t *player;
+
+ if(actor->health-- == 0)
+ {
+ P_SetMobjState(actor, S_NULL);
+ playerNum = netgame ? actor->special2 : 0;
+ if(!playeringame[playerNum])
+ { // Player left the game
+ return;
+ }
+ player = &players[playerNum];
+ if(player->health <= 0)
+ { // Player is dead
+ return;
+ }
+ if(player->rain1 == actor)
+ {
+ player->rain1 = NULL;
+ }
+ else if(player->rain2 == actor)
+ {
+ player->rain2 = NULL;
+ }
+ return;
+ }
+ if(P_Random() < 25)
+ { // Fudge rain frequency
+ return;
+ }
+ x = actor->x+((P_Random()&127)-64)*FRACUNIT;
+ y = actor->y+((P_Random()&127)-64)*FRACUNIT;
+ mo = P_SpawnMobj(x, y, ONCEILINGZ, MT_RAINPLR1+actor->special2);
+ mo->target = actor->target;
+ mo->momx = 1; // Force collision detection
+ mo->momz = -mo->info->speed;
+ mo->special2 = actor->special2; // Transfer player number
+ P_CheckMissileSpawn(mo);
+ if(!(actor->special1&31))
+ {
+ S_StartSound(actor, sfx_ramrain);
+ }
+ actor->special1++;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_RainImpact
+//
+//----------------------------------------------------------------------------
+
+void A_RainImpact(mobj_t *actor)
+{
+ if(actor->z > actor->floorz)
+ {
+ P_SetMobjState(actor, S_RAINAIRXPLR1_1+actor->special2);
+ }
+ else if(P_Random() < 40)
+ {
+ P_HitFloor(actor);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_HideInCeiling
+//
+//----------------------------------------------------------------------------
+
+void A_HideInCeiling(mobj_t *actor)
+{
+ actor->z = actor->ceilingz+4*FRACUNIT;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FirePhoenixPL1
+//
+//----------------------------------------------------------------------------
+
+void A_FirePhoenixPL1(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_1;
+ P_SpawnPlayerMissile(player->mo, MT_PHOENIXFX1);
+ //P_SpawnPlayerMissile(player->mo, MT_MNTRFX2);
+ angle = player->mo->angle+ANG180;
+ angle >>= ANGLETOFINESHIFT;
+ player->mo->momx += FixedMul(4*FRACUNIT, finecosine[angle]);
+ player->mo->momy += FixedMul(4*FRACUNIT, finesine[angle]);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_PhoenixPuff
+//
+//----------------------------------------------------------------------------
+
+void A_PhoenixPuff(mobj_t *actor)
+{
+ mobj_t *puff;
+ angle_t angle;
+
+ P_SeekerMissile(actor, ANGLE_1*5, ANGLE_1*10);
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
+ angle = actor->angle+ANG90;
+ angle >>= ANGLETOFINESHIFT;
+ puff->momx = FixedMul(FRACUNIT*1.3, finecosine[angle]);
+ puff->momy = FixedMul(FRACUNIT*1.3, finesine[angle]);
+ puff->momz = 0;
+ puff = P_SpawnMobj(actor->x, actor->y, actor->z, MT_PHOENIXPUFF);
+ angle = actor->angle-ANG90;
+ angle >>= ANGLETOFINESHIFT;
+ puff->momx = FixedMul(FRACUNIT*1.3, finecosine[angle]);
+ puff->momy = FixedMul(FRACUNIT*1.3, finesine[angle]);
+ puff->momz = 0;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_InitPhoenixPL2
+//
+//----------------------------------------------------------------------------
+
+void A_InitPhoenixPL2(player_t *player, pspdef_t *psp)
+{
+ player->flamecount = FLAME_THROWER_TICS;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FirePhoenixPL2
+//
+// Flame thrower effect.
+//
+//----------------------------------------------------------------------------
+
+void A_FirePhoenixPL2(player_t *player, pspdef_t *psp)
+{
+ mobj_t *mo;
+ mobj_t *pmo;
+ angle_t angle;
+ fixed_t x, y, z;
+ fixed_t slope;
+
+ if(--player->flamecount == 0)
+ { // Out of flame
+ P_SetPsprite(player, ps_weapon, S_PHOENIXATK2_4);
+ player->refire = 0;
+ return;
+ }
+ pmo = player->mo;
+ angle = pmo->angle;
+ x = pmo->x+((P_Random()-P_Random())<<9);
+ y = pmo->y+((P_Random()-P_Random())<<9);
+ z = pmo->z+26*FRACUNIT+((player->lookdir)<<FRACBITS)/173;
+ if(pmo->flags2&MF2_FEETARECLIPPED)
+ {
+ z -= FOOTCLIPSIZE;
+ }
+ slope = ((player->lookdir)<<FRACBITS)/173+(FRACUNIT/10);
+ mo = P_SpawnMobj(x, y, z, MT_PHOENIXFX2);
+ mo->target = pmo;
+ mo->angle = angle;
+ mo->momx = pmo->momx+FixedMul(mo->info->speed,
+ finecosine[angle>>ANGLETOFINESHIFT]);
+ mo->momy = pmo->momy+FixedMul(mo->info->speed,
+ finesine[angle>>ANGLETOFINESHIFT]);
+ mo->momz = FixedMul(mo->info->speed, slope);
+ if(!player->refire || !(leveltime%38))
+ {
+ S_StartSound(player->mo, sfx_phopow);
+ }
+ P_CheckMissileSpawn(mo);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_ShutdownPhoenixPL2
+//
+//----------------------------------------------------------------------------
+
+void A_ShutdownPhoenixPL2(player_t *player, pspdef_t *psp)
+{
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FlameEnd
+//
+//----------------------------------------------------------------------------
+
+void A_FlameEnd(mobj_t *actor)
+{
+ actor->momz += 1.5*FRACUNIT;
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC A_FloatPuff
+//
+//----------------------------------------------------------------------------
+
+void A_FloatPuff(mobj_t *puff)
+{
+ puff->momz += 1.8*FRACUNIT;
+}
+
+//---------------------------------------------------------------------------
+//
+// PROC A_GauntletAttack
+//
+//---------------------------------------------------------------------------
+
+void A_GauntletAttack(player_t *player, pspdef_t *psp)
+{
+ angle_t angle;
+ int damage;
+ int slope;
+ int randVal;
+ fixed_t dist;
+
+ psp->sx = ((P_Random()&3)-2)*FRACUNIT;
+ psp->sy = WEAPONTOP+(P_Random()&3)*FRACUNIT;
+ angle = player->mo->angle;
+ if(player->powers[pw_weaponlevel2])
+ {
+ damage = HITDICE(2);
+ dist = 4*MELEERANGE;
+ angle += (P_Random()-P_Random())<<17;
+ PuffType = MT_GAUNTLETPUFF2;
+ }
+ else
+ {
+ damage = HITDICE(2);
+ dist = MELEERANGE+1;
+ angle += (P_Random()-P_Random())<<18;
+ PuffType = MT_GAUNTLETPUFF1;
+ }
+ slope = P_AimLineAttack(player->mo, angle, dist);
+ P_LineAttack(player->mo, angle, dist, slope, damage);
+ if(!linetarget)
+ {
+ if(P_Random() > 64)
+ {
+ player->extralight = !player->extralight;
+ }
+ S_StartSound(player->mo, sfx_gntful);
+ return;
+ }
+ randVal = P_Random();
+ if(randVal < 64)
+ {
+ player->extralight = 0;
+ }
+ else if(randVal < 160)
+ {
+ player->extralight = 1;
+ }
+ else
+ {
+ player->extralight = 2;
+ }
+ if(player->powers[pw_weaponlevel2])
+ {
+ P_GiveBody(player, damage>>1);
+ S_StartSound(player->mo, sfx_gntpow);
+ }
+ else
+ {
+ S_StartSound(player->mo, sfx_gnthit);
+ }
+ // turn to face target
+ angle = R_PointToAngle2(player->mo->x, player->mo->y,
+ linetarget->x, linetarget->y);
+ if(angle-player->mo->angle > ANG180)
+ {
+ if(angle-player->mo->angle < -ANG90/20)
+ player->mo->angle = angle+ANG90/21;
+ else
+ player->mo->angle -= ANG90/20;
+ }
+ else
+ {
+ if(angle-player->mo->angle > ANG90/20)
+ player->mo->angle = angle-ANG90/21;
+ else
+ player->mo->angle += ANG90/20;
+ }
+ player->mo->flags |= MF_JUSTATTACKED;
+}
+
+void A_Light0(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 0;
+}
+
+void A_Light1(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 1;
+}
+
+void A_Light2(player_t *player, pspdef_t *psp)
+{
+ player->extralight = 2;
+}
+
+//------------------------------------------------------------------------
+//
+// PROC P_SetupPsprites
+//
+// Called at start of level for each player
+//
+//------------------------------------------------------------------------
+
+void P_SetupPsprites(player_t *player)
+{
+ int i;
+
+ // Remove all psprites
+ for(i = 0; i < NUMPSPRITES; i++)
+ {
+ player->psprites[i].state = NULL;
+ }
+ // Spawn the ready weapon
+ player->pendingweapon = player->readyweapon;
+ P_BringUpWeapon(player);
+}
+
+//------------------------------------------------------------------------
+//
+// PROC P_MovePsprites
+//
+// Called every tic by player thinking routine
+//
+//------------------------------------------------------------------------
+
+void P_MovePsprites(player_t *player)
+{
+ int i;
+ pspdef_t *psp;
+ state_t *state;
+
+ psp = &player->psprites[0];
+ for(i = 0; i < NUMPSPRITES; i++, psp++)
+ {
+ if((state = psp->state) != 0) // a null state means not active
+ {
+ // drop tic count and possibly change state
+ if(psp->tics != -1) // a -1 tic count never changes
+ {
+ psp->tics--;
+ if(!psp->tics)
+ {
+ P_SetPsprite(player, i, psp->state->nextstate);
+ }
+ }
+ }
+ }
+ player->psprites[ps_flash].sx = player->psprites[ps_weapon].sx;
+ player->psprites[ps_flash].sy = player->psprites[ps_weapon].sy;
+}