summaryrefslogtreecommitdiff
path: root/apps/plugins/doom/p_pspr.c
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
committerDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
commit47f4a458d636a889e955e68f896708f1276febc0 (patch)
tree99f770c02ef606f0abbdcd332ac39e69830d8007 /apps/plugins/doom/p_pspr.c
parentfff7d6157d56f233cad5c2003475e47a5ff809a7 (diff)
Patch #2969 - Doom! Currently only working on the H300.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/doom/p_pspr.c')
-rw-r--r--apps/plugins/doom/p_pspr.c853
1 files changed, 853 insertions, 0 deletions
diff --git a/apps/plugins/doom/p_pspr.c b/apps/plugins/doom/p_pspr.c
new file mode 100644
index 0000000000..9ef9e73978
--- /dev/null
+++ b/apps/plugins/doom/p_pspr.c
@@ -0,0 +1,853 @@
+/* Emacs style mode select -*- C++ -*-
+ *-----------------------------------------------------------------------------
+ *
+ *
+ * PrBoom a Doom port merged with LxDoom and LSDLDoom
+ * based on BOOM, a modified and improved DOOM engine
+ * Copyright (C) 1999 by
+ * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ * Copyright (C) 1999-2000 by
+ * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * DESCRIPTION:
+ * Weapon sprite animation, weapon objects.
+ * Action functions for weapons.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "doomstat.h"
+#include "r_main.h"
+#include "p_map.h"
+#include "p_inter.h"
+#include "p_pspr.h"
+#include "p_enemy.h"
+#include "m_random.h"
+#include "s_sound.h"
+#include "sounds.h"
+#include "d_event.h"
+#include "rockmacros.h"
+#define LOWERSPEED (FRACUNIT*6)
+#define RAISESPEED (FRACUNIT*6)
+#define WEAPONBOTTOM (FRACUNIT*128)
+#define WEAPONTOP (FRACUNIT*32)
+
+// plasma cells for a bfg attack
+#define BFGCELLS 40
+//#define BFGCELLS bfgcells /* Ty 03/09/98 externalized in p_inter.c */
+
+extern void P_Thrust(player_t *, angle_t, fixed_t);
+
+// The following array holds the recoil values // phares
+
+static const int recoil_values[] = { // phares
+ 10, // wp_fist
+ 10, // wp_pistol
+ 30, // wp_shotgun
+ 10, // wp_chaingun
+ 100,// wp_missile
+ 20, // wp_plasma
+ 100,// wp_bfg
+ 0, // wp_chainsaw
+ 80 // wp_supershotgun
+ };
+
+//
+// P_SetPsprite
+//
+
+static void P_SetPsprite(player_t *player, int position, statenum_t stnum)
+{
+ pspdef_t *psp = &player->psprites[position];
+
+ do
+ {
+ state_t *state;
+
+ 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)
+ {
+ // coordinate set
+ psp->sx = state->misc1 << FRACBITS;
+ psp->sy = state->misc2 << FRACBITS;
+ }
+
+ // Call action routine.
+ // Modified handling.
+ if (state->action)
+ {
+ state->action(player, psp);
+ if (!psp->state)
+ break;
+ }
+ stnum = psp->state->nextstate;
+ }
+ while (!psp->tics); // an initial state of 0 could cycle through
+}
+
+//
+// P_BringUpWeapon
+// Starts bringing the pending weapon up
+// from the bottom of the screen.
+// Uses player
+//
+
+static void P_BringUpWeapon(player_t *player)
+{
+ statenum_t newstate;
+
+ if (player->pendingweapon == wp_nochange)
+ player->pendingweapon = player->readyweapon;
+
+ if (player->pendingweapon == wp_chainsaw)
+ S_StartSound (player->mo, sfx_sawup);
+
+ newstate = weaponinfo[player->pendingweapon].upstate;
+
+ player->pendingweapon = wp_nochange;
+ // killough 12/98: prevent pistol from starting visibly at bottom of screen:
+ player->psprites[ps_weapon].sy =
+ mbf_features ? WEAPONBOTTOM+FRACUNIT*2 : WEAPONBOTTOM;
+
+ P_SetPsprite(player, ps_weapon, newstate);
+}
+
+// The first set is where the weapon preferences from // killough,
+// default.cfg are stored. These values represent the keys used // phares
+// in DOOM2 to bring up the weapon, i.e. 6 = plasma gun. These // |
+// are NOT the wp_* constants. // V
+
+int weapon_preferences[2][NUMWEAPONS+1] = {
+ {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // !compatibility preferences
+ {6, 9, 4, 3, 2, 8, 5, 7, 1, 0}, // compatibility preferences
+ };
+
+// P_SwitchWeapon checks current ammo levels and gives you the
+// most preferred weapon with ammo. It will not pick the currently
+// raised weapon. When called from P_CheckAmmo this won't matter,
+// because the raised weapon has no ammo anyway. When called from
+// G_BuildTiccmd you want to toggle to a different weapon regardless.
+
+int P_SwitchWeapon(player_t *player)
+{
+ int *prefer = weapon_preferences[demo_compatibility!=0]; // killough 3/22/98
+ int currentweapon = player->readyweapon;
+ int newweapon = currentweapon;
+ int i = NUMWEAPONS+1; // killough 5/2/98
+
+ // killough 2/8/98: follow preferences and fix BFG/SSG bugs
+
+ do
+ switch (*prefer++)
+ {
+ case 1:
+ if (!player->powers[pw_strength]) // allow chainsaw override
+ break;
+ case 0:
+ newweapon = wp_fist;
+ break;
+ case 2:
+ if (player->ammo[am_clip])
+ newweapon = wp_pistol;
+ break;
+ case 3:
+ if (player->weaponowned[wp_shotgun] && player->ammo[am_shell])
+ newweapon = wp_shotgun;
+ break;
+ case 4:
+ if (player->weaponowned[wp_chaingun] && player->ammo[am_clip])
+ newweapon = wp_chaingun;
+ break;
+ case 5:
+ if (player->weaponowned[wp_missile] && player->ammo[am_misl])
+ newweapon = wp_missile;
+ break;
+ case 6:
+ if (player->weaponowned[wp_plasma] && player->ammo[am_cell] &&
+ gamemode != shareware)
+ newweapon = wp_plasma;
+ break;
+ case 7:
+ if (player->weaponowned[wp_bfg] && gamemode != shareware &&
+ player->ammo[am_cell] >= (demo_compatibility ? 41 : 40))
+ newweapon = wp_bfg;
+ break;
+ case 8:
+ if (player->weaponowned[wp_chainsaw])
+ newweapon = wp_chainsaw;
+ break;
+ case 9:
+ if (player->weaponowned[wp_supershotgun] && gamemode == commercial &&
+ player->ammo[am_shell] >= (demo_compatibility ? 3 : 2))
+ newweapon = wp_supershotgun;
+ break;
+ }
+ while (newweapon==currentweapon && --i); // killough 5/2/98
+ return newweapon;
+}
+
+// killough 5/2/98: whether consoleplayer prefers weapon w1 over weapon w2.
+int P_WeaponPreferred(int w1, int w2)
+{
+ return
+ (weapon_preferences[0][0] != ++w2 && (weapon_preferences[0][0] == ++w1 ||
+ (weapon_preferences[0][1] != w2 && (weapon_preferences[0][1] == w1 ||
+ (weapon_preferences[0][2] != w2 && (weapon_preferences[0][2] == w1 ||
+ (weapon_preferences[0][3] != w2 && (weapon_preferences[0][3] == w1 ||
+ (weapon_preferences[0][4] != w2 && (weapon_preferences[0][4] == w1 ||
+ (weapon_preferences[0][5] != w2 && (weapon_preferences[0][5] == w1 ||
+ (weapon_preferences[0][6] != w2 && (weapon_preferences[0][6] == w1 ||
+ (weapon_preferences[0][7] != w2 && (weapon_preferences[0][7] == w1
+ ))))))))))))))));
+}
+
+//
+// P_CheckAmmo
+// Returns true if there is enough ammo to shoot.
+// If not, selects the next weapon to use.
+// (only in demo_compatibility mode -- killough 3/22/98)
+//
+
+boolean P_CheckAmmo(player_t *player)
+{
+ ammotype_t ammo = weaponinfo[player->readyweapon].ammo;
+ int count = 1; // Regular
+
+ if (player->readyweapon == wp_bfg) // Minimal amount for one shot varies.
+ count = BFGCELLS;
+ else
+ if (player->readyweapon == wp_supershotgun) // Double barrel.
+ count = 2;
+
+ // Some do not need ammunition anyway.
+ // Return if current ammunition sufficient.
+
+ if (ammo == am_noammo || player->ammo[ammo] >= count)
+ return true;
+
+ // Out of ammo, pick a weapon to change to.
+ //
+ // killough 3/22/98: for old demos we do the switch here and now;
+ // for Boom games we cannot do this, and have different player
+ // preferences across demos or networks, so we have to use the
+ // G_BuildTiccmd() interface instead of making the switch here.
+
+ if (demo_compatibility)
+ {
+ player->pendingweapon = P_SwitchWeapon(player); // phares
+ // Now set appropriate weapon overlay.
+ P_SetPsprite(player,ps_weapon,weaponinfo[player->readyweapon].downstate);
+ }
+
+ return false;
+}
+
+//
+// P_FireWeapon.
+//
+
+int lastshottic; // killough 3/22/98
+
+static void P_FireWeapon(player_t *player)
+{
+ statenum_t newstate;
+
+ if (!P_CheckAmmo(player))
+ return;
+
+ P_SetMobjState(player->mo, S_PLAY_ATK1);
+ newstate = weaponinfo[player->readyweapon].atkstate;
+ P_SetPsprite(player, ps_weapon, newstate);
+ P_NoiseAlert(player->mo, player->mo);
+ lastshottic = gametic; // killough 3/22/98
+}
+
+//
+// P_DropWeapon
+// Player died, so put the weapon away.
+//
+
+void P_DropWeapon(player_t *player)
+{
+ P_SetPsprite(player, ps_weapon, weaponinfo[player->readyweapon].downstate);
+}
+
+//
+// A_WeaponReady
+// The player can fire the weapon
+// or change to another weapon at this time.
+// Follows after getting weapon up,
+// or after previous attack/fire sequence.
+//
+
+void A_WeaponReady(player_t *player, pspdef_t *psp)
+{
+ // get out of attack state
+ if (player->mo->state == &states[S_PLAY_ATK1]
+ || player->mo->state == &states[S_PLAY_ATK2] )
+ P_SetMobjState(player->mo, S_PLAY);
+
+ if (player->readyweapon == wp_chainsaw && psp->state == &states[S_SAW])
+ S_StartSound(player->mo, sfx_sawidl);
+
+ // check for change
+ // if player is dead, put the weapon away
+
+ if (player->pendingweapon != wp_nochange || !player->health)
+ {
+ // change weapon (pending weapon should already be validated)
+ statenum_t newstate = weaponinfo[player->readyweapon].downstate;
+ P_SetPsprite(player, ps_weapon, newstate);
+ return;
+ }
+
+ // check for fire
+ // the missile launcher and bfg do not auto fire
+
+ if (player->cmd.buttons & BT_ATTACK)
+ {
+ if (!player->attackdown || (player->readyweapon != wp_missile &&
+ player->readyweapon != wp_bfg))
+ {
+ player->attackdown = true;
+ P_FireWeapon(player);
+ return;
+ }
+ }
+ else
+ player->attackdown = false;
+
+ // bob the weapon based on movement speed
+ {
+ int angle = (128*leveltime) & FINEMASK;
+ psp->sx = FRACUNIT + FixedMul(player->bob, finecosine[angle]);
+ angle &= FINEANGLES/2-1;
+ psp->sy = WEAPONTOP + FixedMul(player->bob, finesine[angle]);
+ }
+}
+
+//
+// A_ReFire
+// The player can re-fire the weapon
+// without lowering it entirely.
+//
+
+void A_ReFire(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ // check for fire
+ // (if a weaponchange is pending, let it go through instead)
+
+ if ( (player->cmd.buttons & BT_ATTACK)
+ && player->pendingweapon == wp_nochange && player->health)
+ {
+ player->refire++;
+ P_FireWeapon(player);
+ }
+ else
+ {
+ player->refire = 0;
+ P_CheckAmmo(player);
+ }
+}
+
+void A_CheckReload(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ P_CheckAmmo(player);
+}
+
+//
+// A_Lower
+// Lowers current weapon,
+// and changes weapon at bottom.
+//
+
+void A_Lower(player_t *player, pspdef_t *psp)
+{
+ psp->sy += LOWERSPEED;
+
+ // Is already down.
+ if (psp->sy < WEAPONBOTTOM)
+ return;
+
+ // Player is dead.
+ if (player->playerstate == PST_DEAD)
+ {
+ psp->sy = WEAPONBOTTOM;
+ return; // don't bring weapon back up
+ }
+
+ // The old weapon has been lowered off the screen,
+ // so change the weapon and start raising it
+
+ 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);
+}
+
+//
+// A_Raise
+//
+
+void A_Raise(player_t *player, pspdef_t *psp)
+{
+ statenum_t newstate;
+
+ psp->sy -= RAISESPEED;
+
+ if (psp->sy > WEAPONTOP)
+ return;
+
+ psp->sy = WEAPONTOP;
+
+ // The weapon has been raised all the way,
+ // so change to the ready state.
+
+ newstate = weaponinfo[player->readyweapon].readystate;
+
+ P_SetPsprite(player, ps_weapon, newstate);
+}
+
+
+// Weapons now recoil, amount depending on the weapon. // phares
+// // |
+// The P_SetPsprite call in each of the weapon firing routines // V
+// was moved here so the recoil could be synched with the
+// muzzle flash, rather than the pressing of the trigger.
+// The BFG delay caused this to be necessary.
+
+static void A_FireSomething(player_t* player,int adder)
+{
+ P_SetPsprite(player, ps_flash,
+ weaponinfo[player->readyweapon].flashstate+adder);
+
+ // killough 3/27/98: prevent recoil in no-clipping mode
+ if (!(player->mo->flags & MF_NOCLIP))
+ if (!compatibility && weapon_recoil)
+ P_Thrust(player,
+ ANG180+player->mo->angle, // ^
+ 2048*recoil_values[player->readyweapon]); // |
+} // phares
+
+//
+// A_GunFlash
+//
+
+void A_GunFlash(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+
+ A_FireSomething(player,0); // phares
+}
+
+//
+// WEAPON ATTACKS
+//
+
+//
+// A_Punch
+//
+
+void A_Punch(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ angle_t angle;
+ int t, slope, damage = (P_Random(pr_punch)%10+1)<<1;
+
+ if (player->powers[pw_strength])
+ damage *= 10;
+
+ angle = player->mo->angle;
+
+ // killough 5/5/98: remove dependence on order of evaluation:
+ t = P_Random(pr_punchangle);
+ angle += (t - P_Random(pr_punchangle))<<18;
+
+ /* killough 8/2/98: make autoaiming prefer enemies */
+ if (!mbf_features ||
+ (slope = P_AimLineAttack(player->mo, angle, MELEERANGE, MF_FRIEND),
+ !linetarget))
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE, 0);
+
+ P_LineAttack(player->mo, angle, MELEERANGE, slope, damage);
+
+ if (!linetarget)
+ return;
+
+ S_StartSound(player->mo, sfx_punch);
+
+ // turn to face target
+
+ player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y,
+ linetarget->x, linetarget->y);
+}
+
+//
+// A_Saw
+//
+
+void A_Saw(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ int slope, damage = 2*(P_Random(pr_saw)%10+1);
+ angle_t angle = player->mo->angle;
+ // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_saw);
+ angle += (t - P_Random(pr_saw))<<18;
+
+ /* Use meleerange + 1 so that the puff doesn't skip the flash
+ * killough 8/2/98: make autoaiming prefer enemies */
+ if (!mbf_features ||
+ (slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, MF_FRIEND),
+ !linetarget))
+ slope = P_AimLineAttack(player->mo, angle, MELEERANGE+1, 0);
+
+ P_LineAttack(player->mo, angle, MELEERANGE+1, slope, damage);
+
+ if (!linetarget)
+ {
+ S_StartSound(player->mo, sfx_sawful);
+ return;
+ }
+
+ S_StartSound(player->mo, sfx_sawhit);
+
+ // 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 < (unsigned)(-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;
+}
+
+//
+// A_FireMissile
+//
+
+void A_FireMissile(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+ P_SpawnPlayerMissile(player->mo, MT_ROCKET);
+}
+
+//
+// A_FireBFG
+//
+
+void A_FireBFG(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
+ P_SpawnPlayerMissile(player->mo, MT_BFG);
+}
+
+/*
+ * A_FireOldBFG
+ *
+ * This function emulates Doom's Pre-Beta BFG
+ * By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98
+ *
+ * This code may not be used in other mods without appropriate credit given.
+ * Code leeches will be telefragged.
+ */
+
+void A_FireOldBFG(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ (void)player;
+}
+
+//
+// A_FirePlasma
+//
+
+void A_FirePlasma(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ A_FireSomething(player,P_Random(pr_plasma)&1); // phares
+ P_SpawnPlayerMissile(player->mo, MT_PLASMA);
+}
+
+//
+// P_BulletSlope
+// Sets a slope so a near miss is at aproximately
+// the height of the intended target
+//
+
+static fixed_t bulletslope;
+
+static void P_BulletSlope(mobj_t *mo)
+{
+ angle_t an = mo->angle; // see which target is to be aimed at
+
+ /* killough 8/2/98: make autoaiming prefer enemies */
+ uint_64_t mask = mbf_features ? MF_FRIEND : 0;
+
+ do
+ {
+ bulletslope = P_AimLineAttack(mo, an, 16*64*FRACUNIT, mask);
+ if (!linetarget)
+ bulletslope = P_AimLineAttack(mo, an += 1<<26, 16*64*FRACUNIT, mask);
+ if (!linetarget)
+ bulletslope = P_AimLineAttack(mo, an -= 2<<26, 16*64*FRACUNIT, mask);
+ }
+ while (mask && (mask=0, !linetarget)); /* killough 8/2/98 */
+}
+
+//
+// P_GunShot
+//
+
+void P_GunShot(mobj_t *mo, boolean accurate)
+{
+ int damage = 5*(P_Random(pr_gunshot)%3+1);
+ angle_t angle = mo->angle;
+
+ if (!accurate)
+ { // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_misfire);
+ angle += (t - P_Random(pr_misfire))<<18;
+ }
+
+ P_LineAttack(mo, angle, MISSILERANGE, bulletslope, damage);
+}
+
+//
+// A_FirePistol
+//
+
+void A_FirePistol(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ S_StartSound(player->mo, sfx_pistol);
+
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ A_FireSomething(player,0); // phares
+ P_BulletSlope(player->mo);
+ P_GunShot(player->mo, !player->refire);
+}
+
+//
+// A_FireShotgun
+//
+
+void A_FireShotgun(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ int i;
+
+ S_StartSound(player->mo, sfx_shotgn);
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ A_FireSomething(player,0); // phares
+
+ P_BulletSlope(player->mo);
+
+ for (i=0; i<7; i++)
+ P_GunShot(player->mo, false);
+}
+
+//
+// A_FireShotgun2
+//
+
+void A_FireShotgun2(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ int i;
+
+ S_StartSound(player->mo, sfx_dshtgn);
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+ player->ammo[weaponinfo[player->readyweapon].ammo] -= 2;
+
+ A_FireSomething(player,0); // phares
+
+ P_BulletSlope(player->mo);
+
+ for (i=0; i<20; i++)
+ {
+ int damage = 5*(P_Random(pr_shotgun)%3+1);
+ angle_t angle = player->mo->angle;
+ // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_shotgun);
+ angle += (t - P_Random(pr_shotgun))<<19;
+ t = P_Random(pr_shotgun);
+ P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope +
+ ((t - P_Random(pr_shotgun))<<5), damage);
+ }
+}
+
+//
+// A_FireCGun
+//
+
+void A_FireCGun(player_t *player, pspdef_t *psp)
+{
+ if (player->ammo[weaponinfo[player->readyweapon].ammo] || comp[comp_sound])
+ S_StartSound(player->mo, sfx_pistol);
+
+ if (!player->ammo[weaponinfo[player->readyweapon].ammo])
+ return;
+
+ P_SetMobjState(player->mo, S_PLAY_ATK2);
+ player->ammo[weaponinfo[player->readyweapon].ammo]--;
+
+ A_FireSomething(player,psp->state - &states[S_CHAIN1]); // phares
+
+ P_BulletSlope(player->mo);
+
+ P_GunShot(player->mo, !player->refire);
+}
+
+void A_Light0(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->extralight = 0;
+}
+
+void A_Light1 (player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->extralight = 1;
+}
+
+void A_Light2 (player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ player->extralight = 2;
+}
+
+//
+// A_BFGSpray
+// Spawn a BFG explosion on every monster in view
+//
+
+void A_BFGSpray(mobj_t *mo)
+{
+ int i;
+
+ for (i=0 ; i<40 ; i++) // offset angles from its attack angle
+ {
+ int j, damage;
+ angle_t an = mo->angle - ANG90/2 + ANG90/40*i;
+
+ // mo->target is the originator (player) of the missile
+
+ // killough 8/2/98: make autoaiming prefer enemies
+ if (!mbf_features ||
+ (P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, MF_FRIEND),
+ !linetarget))
+ P_AimLineAttack(mo->target, an, 16*64*FRACUNIT, 0);
+
+ if (!linetarget)
+ continue;
+
+ P_SpawnMobj(linetarget->x, linetarget->y,
+ linetarget->z + (linetarget->height>>2), MT_EXTRABFG);
+
+ for (damage=j=0; j<15; j++)
+ damage += (P_Random(pr_bfg)&7) + 1;
+
+ P_DamageMobj(linetarget, mo->target, mo->target, damage);
+ }
+}
+
+//
+// A_BFGsound
+//
+
+void A_BFGsound(player_t *player, pspdef_t *psp)
+{
+ (void)psp;
+ S_StartSound(player->mo, sfx_bfg);
+}
+
+//
+// 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 gun
+ player->pendingweapon = player->readyweapon;
+ P_BringUpWeapon(player);
+}
+
+//
+// P_MovePsprites
+// Called every tic by player thinking routine.
+//
+
+void P_MovePsprites(player_t *player)
+{
+ pspdef_t *psp = player->psprites;
+ int i;
+
+ // a null state means not active
+ // drop tic count and possibly change state
+ // a -1 tic count never changes
+
+ for (i=0; i<NUMPSPRITES; i++, psp++)
+ if (psp->state && psp->tics != -1 && !--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;
+}