summaryrefslogtreecommitdiff
path: root/src/heretic/p_user.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/heretic/p_user.c')
-rw-r--r--src/heretic/p_user.c1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c
new file mode 100644
index 00000000..16dbed49
--- /dev/null
+++ b/src/heretic/p_user.c
@@ -0,0 +1,1028 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 1993-2008 Raven Software
+// Copyright(C) 2008 Simon Howard
+//
+// 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.
+//
+//-----------------------------------------------------------------------------
+
+// P_user.c
+
+#include <stdlib.h>
+
+#include "doomdef.h"
+#include "deh_str.h"
+#include "m_random.h"
+#include "p_local.h"
+#include "s_sound.h"
+
+void P_PlayerNextArtifact(player_t * player);
+
+// Macros
+
+#define MAXBOB 0x100000 // 16 pixels of bob
+
+// Data
+
+boolean onground;
+int newtorch; // used in the torch flicker effect.
+int newtorchdelta;
+
+boolean WeaponInShareware[] = {
+ true, // Staff
+ true, // Gold wand
+ true, // Crossbow
+ true, // Blaster
+ false, // Skull rod
+ false, // Phoenix rod
+ false, // Mace
+ true, // Gauntlets
+ true // Beak
+};
+
+/*
+==================
+=
+= P_Thrust
+=
+= moves the given origin along a given angle
+=
+==================
+*/
+
+void P_Thrust(player_t * player, angle_t angle, fixed_t move)
+{
+ angle >>= ANGLETOFINESHIFT;
+ if (player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+ else if (player->mo->subsector->sector->special == 15) // Friction_Low
+ {
+ player->mo->momx += FixedMul(move >> 2, finecosine[angle]);
+ player->mo->momy += FixedMul(move >> 2, finesine[angle]);
+ }
+ else
+ {
+ player->mo->momx += FixedMul(move, finecosine[angle]);
+ player->mo->momy += FixedMul(move, finesine[angle]);
+ }
+}
+
+
+/*
+==================
+=
+= P_CalcHeight
+=
+=Calculate the walking / running height adjustment
+=
+==================
+*/
+
+void P_CalcHeight(player_t * player)
+{
+ int angle;
+ fixed_t bob;
+
+//
+// regular movement bobbing (needs to be calculated for gun swing even
+// if not on ground)
+// OPTIMIZE: tablify angle
+
+ player->bob = FixedMul(player->mo->momx, player->mo->momx) +
+ FixedMul(player->mo->momy, player->mo->momy);
+ player->bob >>= 2;
+ if (player->bob > MAXBOB)
+ player->bob = MAXBOB;
+ if (player->mo->flags2 & MF2_FLY && !onground)
+ {
+ player->bob = FRACUNIT / 2;
+ }
+
+ if ((player->cheats & CF_NOMOMENTUM))
+ {
+ player->viewz = player->mo->z + VIEWHEIGHT;
+ if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
+ player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
+ player->viewz = player->mo->z + player->viewheight;
+ return;
+ }
+
+ angle = (FINEANGLES / 20 * leveltime) & FINEMASK;
+ bob = FixedMul(player->bob / 2, finesine[angle]);
+
+//
+// move viewheight
+//
+ if (player->playerstate == PST_LIVE)
+ {
+ player->viewheight += player->deltaviewheight;
+ if (player->viewheight > VIEWHEIGHT)
+ {
+ player->viewheight = VIEWHEIGHT;
+ player->deltaviewheight = 0;
+ }
+ if (player->viewheight < VIEWHEIGHT / 2)
+ {
+ player->viewheight = VIEWHEIGHT / 2;
+ if (player->deltaviewheight <= 0)
+ player->deltaviewheight = 1;
+ }
+
+ if (player->deltaviewheight)
+ {
+ player->deltaviewheight += FRACUNIT / 4;
+ if (!player->deltaviewheight)
+ player->deltaviewheight = 1;
+ }
+ }
+
+ if (player->chickenTics)
+ {
+ player->viewz = player->mo->z + player->viewheight - (20 * FRACUNIT);
+ }
+ else
+ {
+ player->viewz = player->mo->z + player->viewheight + bob;
+ }
+ if (player->mo->flags2 & MF2_FEETARECLIPPED
+ && player->playerstate != PST_DEAD
+ && player->mo->z <= player->mo->floorz)
+ {
+ player->viewz -= FOOTCLIPSIZE;
+ }
+ if (player->viewz > player->mo->ceilingz - 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->ceilingz - 4 * FRACUNIT;
+ }
+ if (player->viewz < player->mo->floorz + 4 * FRACUNIT)
+ {
+ player->viewz = player->mo->floorz + 4 * FRACUNIT;
+ }
+}
+
+/*
+=================
+=
+= P_MovePlayer
+=
+=================
+*/
+
+void P_MovePlayer(player_t * player)
+{
+ int look;
+ int fly;
+ ticcmd_t *cmd;
+
+ cmd = &player->cmd;
+ player->mo->angle += (cmd->angleturn << 16);
+
+ onground = (player->mo->z <= player->mo->floorz
+ || (player->mo->flags2 & MF2_ONMOBJ));
+
+ if (player->chickenTics)
+ { // Chicken speed
+ if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle, cmd->forwardmove * 2500);
+ if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2500);
+ }
+ else
+ { // Normal speed
+ if (cmd->forwardmove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle, cmd->forwardmove * 2048);
+ if (cmd->sidemove && (onground || player->mo->flags2 & MF2_FLY))
+ P_Thrust(player, player->mo->angle - ANG90, cmd->sidemove * 2048);
+ }
+
+ if (cmd->forwardmove || cmd->sidemove)
+ {
+ if (player->chickenTics)
+ {
+ if (player->mo->state == &states[S_CHICPLAY])
+ {
+ P_SetMobjState(player->mo, S_CHICPLAY_RUN1);
+ }
+ }
+ else
+ {
+ if (player->mo->state == &states[S_PLAY])
+ {
+ P_SetMobjState(player->mo, S_PLAY_RUN1);
+ }
+ }
+ }
+
+ look = cmd->lookfly & 15;
+ if (look > 7)
+ {
+ look -= 16;
+ }
+ if (look)
+ {
+ if (look == TOCENTER)
+ {
+ player->centering = true;
+ }
+ else
+ {
+ player->lookdir += 5 * look;
+ if (player->lookdir > 90 || player->lookdir < -110)
+ {
+ player->lookdir -= 5 * look;
+ }
+ }
+ }
+ if (player->centering)
+ {
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 8;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 8;
+ }
+ if (abs(player->lookdir) < 8)
+ {
+ player->lookdir = 0;
+ player->centering = false;
+ }
+ }
+ fly = cmd->lookfly >> 4;
+ if (fly > 7)
+ {
+ fly -= 16;
+ }
+ if (fly && player->powers[pw_flight])
+ {
+ if (fly != TOCENTER)
+ {
+ player->flyheight = fly * 2;
+ if (!(player->mo->flags2 & MF2_FLY))
+ {
+ player->mo->flags2 |= MF2_FLY;
+ player->mo->flags |= MF_NOGRAVITY;
+ }
+ }
+ else
+ {
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ }
+ }
+ else if (fly > 0)
+ {
+ P_PlayerUseArtifact(player, arti_fly);
+ }
+ if (player->mo->flags2 & MF2_FLY)
+ {
+ player->mo->momz = player->flyheight * FRACUNIT;
+ if (player->flyheight)
+ {
+ player->flyheight /= 2;
+ }
+ }
+}
+
+/*
+=================
+=
+= P_DeathThink
+=
+=================
+*/
+
+#define ANG5 (ANG90/18)
+
+void P_DeathThink(player_t * player)
+{
+ angle_t angle, delta;
+ extern int inv_ptr;
+ extern int curpos;
+ int lookDelta;
+
+ P_MovePsprites(player);
+
+ onground = (player->mo->z <= player->mo->floorz);
+ if (player->mo->type == MT_BLOODYSKULL)
+ { // Flying bloody skull
+ player->viewheight = 6 * FRACUNIT;
+ player->deltaviewheight = 0;
+ //player->damagecount = 20;
+ if (onground)
+ {
+ if (player->lookdir < 60)
+ {
+ lookDelta = (60 - player->lookdir) / 8;
+ if (lookDelta < 1 && (leveltime & 1))
+ {
+ lookDelta = 1;
+ }
+ else if (lookDelta > 6)
+ {
+ lookDelta = 6;
+ }
+ player->lookdir += lookDelta;
+ }
+ }
+ }
+ else
+ { // Fall to ground
+ player->deltaviewheight = 0;
+ if (player->viewheight > 6 * FRACUNIT)
+ player->viewheight -= FRACUNIT;
+ if (player->viewheight < 6 * FRACUNIT)
+ player->viewheight = 6 * FRACUNIT;
+ if (player->lookdir > 0)
+ {
+ player->lookdir -= 6;
+ }
+ else if (player->lookdir < 0)
+ {
+ player->lookdir += 6;
+ }
+ if (abs(player->lookdir) < 6)
+ {
+ player->lookdir = 0;
+ }
+ }
+ P_CalcHeight(player);
+
+ if (player->attacker && player->attacker != player->mo)
+ {
+ angle = R_PointToAngle2(player->mo->x, player->mo->y,
+ player->attacker->x, player->attacker->y);
+ delta = angle - player->mo->angle;
+ if (delta < ANG5 || delta > (unsigned) -ANG5)
+ { // Looking at killer, so fade damage flash down
+ player->mo->angle = angle;
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ }
+ else if (delta < ANG180)
+ player->mo->angle += ANG5;
+ else
+ player->mo->angle -= ANG5;
+ }
+ else if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+
+ if (player->cmd.buttons & BT_USE)
+ {
+ if (player == &players[consoleplayer])
+ {
+ I_SetPalette(W_CacheLumpName(DEH_String("PLAYPAL"), PU_CACHE));
+ inv_ptr = 0;
+ curpos = 0;
+ newtorch = 0;
+ newtorchdelta = 0;
+ }
+ player->playerstate = PST_REBORN;
+ // Let the mobj know the player has entered the reborn state. Some
+ // mobjs need to know when it's ok to remove themselves.
+ player->mo->special2 = 666;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ChickenPlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_ChickenPlayerThink(player_t * player)
+{
+ mobj_t *pmo;
+
+ if (player->health > 0)
+ { // Handle beak movement
+ P_UpdateBeak(player, &player->psprites[ps_weapon]);
+ }
+ if (player->chickenTics & 15)
+ {
+ return;
+ }
+ pmo = player->mo;
+ if (!(pmo->momx + pmo->momy) && P_Random() < 160)
+ { // Twitch view angle
+ pmo->angle += (P_Random() - P_Random()) << 19;
+ }
+ if ((pmo->z <= pmo->floorz) && (P_Random() < 32))
+ { // Jump and noise
+ pmo->momz += FRACUNIT;
+ P_SetMobjState(pmo, S_CHICPLAY_PAIN);
+ return;
+ }
+ if (P_Random() < 48)
+ { // Just noise
+ S_StartSound(pmo, sfx_chicact);
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_GetPlayerNum
+//
+//----------------------------------------------------------------------------
+
+int P_GetPlayerNum(player_t * player)
+{
+ int i;
+
+ for (i = 0; i < MAXPLAYERS; i++)
+ {
+ if (player == &players[i])
+ {
+ return (i);
+ }
+ }
+ return (0);
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UndoPlayerChicken
+//
+//----------------------------------------------------------------------------
+
+boolean P_UndoPlayerChicken(player_t * player)
+{
+ mobj_t *fog;
+ mobj_t *mo;
+ mobj_t *pmo;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ angle_t angle;
+ int playerNum;
+ weapontype_t weapon;
+ int oldFlags;
+ int oldFlags2;
+
+ pmo = player->mo;
+ x = pmo->x;
+ y = pmo->y;
+ z = pmo->z;
+ angle = pmo->angle;
+ weapon = pmo->special1;
+ oldFlags = pmo->flags;
+ oldFlags2 = pmo->flags2;
+ P_SetMobjState(pmo, S_FREETARGMOBJ);
+ mo = P_SpawnMobj(x, y, z, MT_PLAYER);
+ if (P_TestMobjLocation(mo) == false)
+ { // Didn't fit
+ P_RemoveMobj(mo);
+ mo = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
+ mo->angle = angle;
+ mo->health = player->health;
+ mo->special1 = weapon;
+ mo->player = player;
+ mo->flags = oldFlags;
+ mo->flags2 = oldFlags2;
+ player->mo = mo;
+ player->chickenTics = 2 * 35;
+ return (false);
+ }
+ playerNum = P_GetPlayerNum(player);
+ if (playerNum != 0)
+ { // Set color translation
+ mo->flags |= playerNum << MF_TRANSSHIFT;
+ }
+ mo->angle = angle;
+ mo->player = player;
+ mo->reactiontime = 18;
+ if (oldFlags2 & MF2_FLY)
+ {
+ mo->flags2 |= MF2_FLY;
+ mo->flags |= MF_NOGRAVITY;
+ }
+ player->chickenTics = 0;
+ player->powers[pw_weaponlevel2] = 0;
+ player->health = mo->health = MAXHEALTH;
+ player->mo = mo;
+ angle >>= ANGLETOFINESHIFT;
+ fog = P_SpawnMobj(x + 20 * finecosine[angle],
+ y + 20 * finesine[angle], z + TELEFOGHEIGHT, MT_TFOG);
+ S_StartSound(fog, sfx_telept);
+ P_PostChickenWeapon(player, weapon);
+ return (true);
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerThink
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerThink(player_t * player)
+{
+ ticcmd_t *cmd;
+ weapontype_t newweapon;
+
+ extern boolean ultimatemsg;
+
+ // No-clip cheat
+ if (player->cheats & CF_NOCLIP)
+ {
+ player->mo->flags |= MF_NOCLIP;
+ }
+ else
+ {
+ player->mo->flags &= ~MF_NOCLIP;
+ }
+ cmd = &player->cmd;
+ if (player->mo->flags & MF_JUSTATTACKED)
+ { // Gauntlets attack auto forward motion
+ cmd->angleturn = 0;
+ cmd->forwardmove = 0xc800 / 512;
+ cmd->sidemove = 0;
+ player->mo->flags &= ~MF_JUSTATTACKED;
+ }
+// messageTics is above the rest of the counters so that messages will
+// go away, even in death.
+ player->messageTics--; // Can go negative
+ if (!player->messageTics)
+ { // Refresh the screen when a message goes away
+ ultimatemsg = false; // clear out any chat messages.
+ BorderTopRefresh = true;
+ }
+ if (player->playerstate == PST_DEAD)
+ {
+ P_DeathThink(player);
+ return;
+ }
+ if (player->chickenTics)
+ {
+ P_ChickenPlayerThink(player);
+ }
+ // Handle movement
+ if (player->mo->reactiontime)
+ { // Player is frozen
+ player->mo->reactiontime--;
+ }
+ else
+ {
+ P_MovePlayer(player);
+ }
+ P_CalcHeight(player);
+ if (player->mo->subsector->sector->special)
+ {
+ P_PlayerInSpecialSector(player);
+ }
+ if (cmd->arti)
+ { // Use an artifact
+ if (cmd->arti == 0xff)
+ {
+ P_PlayerNextArtifact(player);
+ }
+ else
+ {
+ P_PlayerUseArtifact(player, cmd->arti);
+ }
+ }
+ // Check for weapon change
+ if (cmd->buttons & BT_SPECIAL)
+ { // A special event has no other buttons
+ cmd->buttons = 0;
+ }
+ if (cmd->buttons & BT_CHANGE)
+ {
+ // The actual changing of the weapon is done when the weapon
+ // psprite can do it (A_WeaponReady), so it doesn't happen in
+ // the middle of an attack.
+ newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT;
+ if (newweapon == wp_staff && player->weaponowned[wp_gauntlets]
+ && !(player->readyweapon == wp_gauntlets))
+ {
+ newweapon = wp_gauntlets;
+ }
+ if (player->weaponowned[newweapon]
+ && newweapon != player->readyweapon)
+ {
+ if (WeaponInShareware[newweapon] || gamemode != shareware)
+ {
+ player->pendingweapon = newweapon;
+ }
+ }
+ }
+ // Check for use
+ if (cmd->buttons & BT_USE)
+ {
+ if (!player->usedown)
+ {
+ P_UseLines(player);
+ player->usedown = true;
+ }
+ }
+ else
+ {
+ player->usedown = false;
+ }
+ // Chicken counter
+ if (player->chickenTics)
+ {
+ if (player->chickenPeck)
+ { // Chicken attack counter
+ player->chickenPeck -= 3;
+ }
+ if (!--player->chickenTics)
+ { // Attempt to undo the chicken
+ P_UndoPlayerChicken(player);
+ }
+ }
+ // Cycle psprites
+ P_MovePsprites(player);
+ // Other Counters
+ if (player->powers[pw_invulnerability])
+ {
+ player->powers[pw_invulnerability]--;
+ }
+ if (player->powers[pw_invisibility])
+ {
+ if (!--player->powers[pw_invisibility])
+ {
+ player->mo->flags &= ~MF_SHADOW;
+ }
+ }
+ if (player->powers[pw_infrared])
+ {
+ player->powers[pw_infrared]--;
+ }
+ if (player->powers[pw_flight])
+ {
+ if (!--player->powers[pw_flight])
+ {
+ // haleyjd: removed externdriver crap
+ if (player->mo->z != player->mo->floorz)
+ {
+ player->centering = true;
+ }
+
+ player->mo->flags2 &= ~MF2_FLY;
+ player->mo->flags &= ~MF_NOGRAVITY;
+ BorderTopRefresh = true; //make sure the sprite's cleared out
+ }
+ }
+ if (player->powers[pw_weaponlevel2])
+ {
+ if (!--player->powers[pw_weaponlevel2])
+ {
+ if ((player->readyweapon == wp_phoenixrod)
+ && (player->psprites[ps_weapon].state
+ != &states[S_PHOENIXREADY])
+ && (player->psprites[ps_weapon].state
+ != &states[S_PHOENIXUP]))
+ {
+ P_SetPsprite(player, ps_weapon, S_PHOENIXREADY);
+ player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
+ player->refire = 0;
+ }
+ else if ((player->readyweapon == wp_gauntlets)
+ || (player->readyweapon == wp_staff))
+ {
+ player->pendingweapon = player->readyweapon;
+ }
+ BorderTopRefresh = true;
+ }
+ }
+ if (player->damagecount)
+ {
+ player->damagecount--;
+ }
+ if (player->bonuscount)
+ {
+ player->bonuscount--;
+ }
+ // Colormaps
+ if (player->powers[pw_invulnerability])
+ {
+ if (player->powers[pw_invulnerability] > BLINKTHRESHOLD
+ || (player->powers[pw_invulnerability] & 8))
+ {
+ player->fixedcolormap = INVERSECOLORMAP;
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+ }
+ else if (player->powers[pw_infrared])
+ {
+ if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
+ {
+ if (player->powers[pw_infrared] & 8)
+ {
+ player->fixedcolormap = 0;
+ }
+ else
+ {
+ player->fixedcolormap = 1;
+ }
+ }
+ else if (!(leveltime & 16) && player == &players[consoleplayer])
+ {
+ if (newtorch)
+ {
+ if (player->fixedcolormap + newtorchdelta > 7
+ || player->fixedcolormap + newtorchdelta < 1
+ || newtorch == player->fixedcolormap)
+ {
+ newtorch = 0;
+ }
+ else
+ {
+ player->fixedcolormap += newtorchdelta;
+ }
+ }
+ else
+ {
+ newtorch = (M_Random() & 7) + 1;
+ newtorchdelta = (newtorch == player->fixedcolormap) ?
+ 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
+ }
+ }
+ }
+ else
+ {
+ player->fixedcolormap = 0;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_ArtiTele
+//
+//----------------------------------------------------------------------------
+
+void P_ArtiTele(player_t * player)
+{
+ int i;
+ int selections;
+ fixed_t destX;
+ fixed_t destY;
+ angle_t destAngle;
+
+ if (deathmatch)
+ {
+ selections = deathmatch_p - deathmatchstarts;
+ i = P_Random() % selections;
+ destX = deathmatchstarts[i].x << FRACBITS;
+ destY = deathmatchstarts[i].y << FRACBITS;
+ destAngle = ANG45 * (deathmatchstarts[i].angle / 45);
+ }
+ else
+ {
+ destX = playerstarts[0].x << FRACBITS;
+ destY = playerstarts[0].y << FRACBITS;
+ destAngle = ANG45 * (playerstarts[0].angle / 45);
+ }
+ P_Teleport(player->mo, destX, destY, destAngle);
+ S_StartSound(NULL, sfx_wpnup); // Full volume laugh
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerNextArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerNextArtifact(player_t * player)
+{
+ extern int inv_ptr;
+ extern int curpos;
+
+ if (player == &players[consoleplayer])
+ {
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ if (inv_ptr < 6)
+ {
+ curpos = inv_ptr;
+ }
+ else
+ {
+ curpos = 6;
+ }
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerRemoveArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerRemoveArtifact(player_t * player, int slot)
+{
+ int i;
+ extern int inv_ptr;
+ extern int curpos;
+
+ player->artifactCount--;
+ if (!(--player->inventory[slot].count))
+ { // Used last of a type - compact the artifact list
+ player->readyArtifact = arti_none;
+ player->inventory[slot].type = arti_none;
+ for (i = slot + 1; i < player->inventorySlotNum; i++)
+ {
+ player->inventory[i - 1] = player->inventory[i];
+ }
+ player->inventorySlotNum--;
+ if (player == &players[consoleplayer])
+ { // Set position markers and get next readyArtifact
+ inv_ptr--;
+ if (inv_ptr < 6)
+ {
+ curpos--;
+ if (curpos < 0)
+ {
+ curpos = 0;
+ }
+ }
+ if (inv_ptr >= player->inventorySlotNum)
+ {
+ inv_ptr = player->inventorySlotNum - 1;
+ }
+ if (inv_ptr < 0)
+ {
+ inv_ptr = 0;
+ }
+ player->readyArtifact = player->inventory[inv_ptr].type;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// PROC P_PlayerUseArtifact
+//
+//----------------------------------------------------------------------------
+
+void P_PlayerUseArtifact(player_t * player, artitype_t arti)
+{
+ int i;
+
+ for (i = 0; i < player->inventorySlotNum; i++)
+ {
+ if (player->inventory[i].type == arti)
+ { // Found match - try to use
+ if (P_UseArtifact(player, arti))
+ { // Artifact was used - remove it from inventory
+ P_PlayerRemoveArtifact(player, i);
+ if (player == &players[consoleplayer])
+ {
+ S_StartSound(NULL, sfx_artiuse);
+ ArtifactFlash = 4;
+ }
+ }
+ else
+ { // Unable to use artifact, advance pointer
+ P_PlayerNextArtifact(player);
+ }
+ break;
+ }
+ }
+}
+
+//----------------------------------------------------------------------------
+//
+// FUNC P_UseArtifact
+//
+// Returns true if artifact was used.
+//
+//----------------------------------------------------------------------------
+
+boolean P_UseArtifact(player_t * player, artitype_t arti)
+{
+ mobj_t *mo;
+ angle_t angle;
+
+ switch (arti)
+ {
+ case arti_invulnerability:
+ if (!P_GivePower(player, pw_invulnerability))
+ {
+ return (false);
+ }
+ break;
+ case arti_invisibility:
+ if (!P_GivePower(player, pw_invisibility))
+ {
+ return (false);
+ }
+ break;
+ case arti_health:
+ if (!P_GiveBody(player, 25))
+ {
+ return (false);
+ }
+ break;
+ case arti_superhealth:
+ if (!P_GiveBody(player, 100))
+ {
+ return (false);
+ }
+ break;
+ case arti_tomeofpower:
+ if (player->chickenTics)
+ { // Attempt to undo chicken
+ if (P_UndoPlayerChicken(player) == false)
+ { // Failed
+ P_DamageMobj(player->mo, NULL, NULL, 10000);
+ }
+ else
+ { // Succeeded
+ player->chickenTics = 0;
+ S_StartSound(player->mo, sfx_wpnup);
+ }
+ }
+ else
+ {
+ if (!P_GivePower(player, pw_weaponlevel2))
+ {
+ return (false);
+ }
+ if (player->readyweapon == wp_staff)
+ {
+ P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1);
+ }
+ else if (player->readyweapon == wp_gauntlets)
+ {
+ P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1);
+ }
+ }
+ break;
+ case arti_torch:
+ if (!P_GivePower(player, pw_infrared))
+ {
+ return (false);
+ }
+ break;
+ case arti_firebomb:
+ angle = player->mo->angle >> ANGLETOFINESHIFT;
+ mo = P_SpawnMobj(player->mo->x + 24 * finecosine[angle],
+ player->mo->y + 24 * finesine[angle],
+ player->mo->z -
+ 15 * FRACUNIT *
+ (player->mo->flags2 & MF2_FEETARECLIPPED) != 0,
+ MT_FIREBOMB);
+ mo->target = player->mo;
+ break;
+ case arti_egg:
+ mo = player->mo;
+ P_SpawnPlayerMissile(mo, MT_EGGFX);
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 6));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle - (ANG45 / 3));
+ P_SPMAngle(mo, MT_EGGFX, mo->angle + (ANG45 / 3));
+ break;
+ case arti_fly:
+ if (!P_GivePower(player, pw_flight))
+ {
+ return (false);
+ }
+ break;
+ case arti_teleport:
+ P_ArtiTele(player);
+ break;
+ default:
+ return (false);
+ }
+ return (true);
+}