diff options
Diffstat (limited to 'src/strife/p_user.c')
-rw-r--r-- | src/strife/p_user.c | 922 |
1 files changed, 922 insertions, 0 deletions
diff --git a/src/strife/p_user.c b/src/strife/p_user.c new file mode 100644 index 00000000..a6d74b9f --- /dev/null +++ b/src/strife/p_user.c @@ -0,0 +1,922 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 1993-1996 Id Software, Inc. +// Copyright(C) 2005 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. +// +// DESCRIPTION: +// Player related stuff. +// Bobbing POV/weapon, movement. +// Pending weapon. +// +//----------------------------------------------------------------------------- + +#include <stdlib.h> + +#include "doomdef.h" +#include "d_event.h" +#include "p_local.h" +#include "sounds.h" // villsa [STRIFE] +#include "p_dialog.h" // villsa [STRIFE] +#include "d_main.h" // villsa [STRIFE] +#include "doomstat.h" +#include "deh_str.h" // haleyjd [STRIFE] +#include "z_zone.h" +#include "w_wad.h" +#include "p_pspr.h" +#include "m_random.h" +#include "s_sound.h" +#include "p_inter.h" + + + +// Index of the special effects (INVUL inverse) map. +#define LOOKPITCHAMOUNT 6 // villsa [STRIFE] +#define CENTERVIEWAMOUNT (LOOKPITCHAMOUNT + 2) // villsa [STRIFE] +#define LOOKUPMAX 90 // villsa [STRIFE] +#define LOOKDOWNMAX -110 // villsa [STRIFE] + + +void P_DropInventoryItem(player_t* player, int sprite); // villsa [STRIFE] +boolean P_ItemBehavior(player_t* player, int item); // villsa [STRIFE] +static char useinventorymsg[44]; // villsa [STRIFE] + +// +// Movement. +// + +// 16 pixels of bob +#define MAXBOB 0x100000 + +boolean onground; + + +// +// P_Thrust +// Moves the given origin along a given angle. +// +// [STRIFE] Verified unmodified +// +void +P_Thrust +( player_t* player, + angle_t angle, + fixed_t move ) +{ + angle >>= ANGLETOFINESHIFT; + + player->mo->momx += FixedMul(move,finecosine[angle]); + player->mo->momy += FixedMul(move,finesine[angle]); +} + + + + +// +// P_CalcHeight +// Calculate the walking / running height adjustment +// +// [STRIFE] Some odd adjustments, and terrain view 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 + // Note: a LUT allows for effects + // like a ramp with low health. + 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; + + // haleyjd 20110205 [STRIFE]: No CF_NOMOMENTUM check, and Rogue also removed + // the dead code inside. + if (!onground) + { + /* + 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; + } + } + player->viewz = player->mo->z + player->viewheight + bob; + + // villsa [STRIFE] account for terrain lowering the view + if(player->mo->flags & MF_FEETCLIPPED) + player->viewz -= 13*FRACUNIT; + + if (player->viewz > player->mo->ceilingz-4*FRACUNIT) + player->viewz = player->mo->ceilingz-4*FRACUNIT; + + // haleyjd [STRIFE]: added a floorz clip here + if (player->viewz < player->mo->floorz) + player->viewz = player->mo->floorz; +} + + + +// +// P_MovePlayer +// +// [STRIFE] Adjustments to allow air control, jumping, and up/down look. +// +void P_MovePlayer (player_t* player) +{ + ticcmd_t* cmd; + + cmd = &player->cmd; + + player->mo->angle += (cmd->angleturn<<16); + + // Do not let the player control movement + // if not onground. + onground = (player->mo->z <= player->mo->floorz); + + // villsa [STRIFE] allows player to climb over things by jumping + // haleyjd 20110205: air control thrust should be 256, not cmd->forwardmove + if(!onground) + { + if(cmd->forwardmove) + P_Thrust (player, player->mo->angle, 256); + } + else + { + // villsa [STRIFE] jump button + if (cmd->buttons2 & BT2_JUMP) + { + if(!player->deltaviewheight) + player->mo->momz += 8*FRACUNIT; + } + + // haleyjd 20110205 [STRIFE] Either Rogue or Watcom removed the + // redundant "onground" checks from these if's. + if (cmd->forwardmove) + P_Thrust (player, player->mo->angle, cmd->forwardmove*2048); + + if (cmd->sidemove) + P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048); + } + + // villsa [STRIFE] player walking state set + if ( (cmd->forwardmove || cmd->sidemove) + && player->mo->state == &states[S_PLAY_00] ) + { + P_SetMobjState (player->mo, S_PLAY_01); + } + + // villsa [STRIFE] centerview button + if (cmd->buttons2 & BT2_CENTERVIEW) + player->centerview = 1; + + // villsa [STRIFE] adjust player's pitch when centerviewing + if (player->centerview) + { + if (player->pitch <= 0) + { + if (player->pitch < 0) + player->pitch = player->pitch + CENTERVIEWAMOUNT; + } + else + { + player->pitch = player->pitch - CENTERVIEWAMOUNT; + } + if (abs(player->pitch) < CENTERVIEWAMOUNT) + { + player->pitch = 0; + player->centerview = 0; + } + } + + // villsa [STRIFE] look up action + if (cmd->buttons2 & BT2_LOOKUP) + { + player->pitch += LOOKPITCHAMOUNT; + if (player->pitch > LOOKUPMAX || + player->pitch < LOOKDOWNMAX) + player->pitch -= LOOKPITCHAMOUNT; + } + else + { + // villsa [STRIFE] look down action + if (cmd->buttons2 & BT2_LOOKDOWN) + { + player->pitch -= LOOKPITCHAMOUNT; + if (player->pitch > LOOKUPMAX || + player->pitch < LOOKDOWNMAX) + player->pitch += LOOKPITCHAMOUNT; + } + } + +} + + + +// +// P_DeathThink +// Fall on your face when dying. +// Decrease POV height to floor height. +// +// [STRIFE] Modifications for up/down look. +// +#define ANG5 (ANG90/18) + +void P_DeathThink(player_t* player) +{ + angle_t angle; + angle_t delta; + + P_MovePsprites(player); + + // fall to the ground + if (player->viewheight > 6*FRACUNIT) + player->viewheight -= FRACUNIT; + + if (player->viewheight < 6*FRACUNIT) + player->viewheight = 6*FRACUNIT; + + player->deltaviewheight = 0; + onground = (player->mo->z <= player->mo->floorz); + 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--; + + // villsa [STRIFE] + if(player->pitch <= 90) + player->pitch = player->pitch + 3; + + if(player->cmd.buttons & BT_USE) + player->playerstate = PST_REBORN; +} + + + +// +// P_PlayerThink +// +// [STRIFE] Massive changes/additions: +// * NOCLIP hack removed +// * P_DeathThink moved up +// * Inventory use/dropping +// * Strife weapons logic +// * Dialog +// * Strife powerups and nukage behavior +// * Fire Death/Sigil Shock +// +void P_PlayerThink (player_t* player) +{ + ticcmd_t* cmd; + weapontype_t newweapon; + + // villsa [STRIFE] unused code (see ST_Responder) + /* + // fixme: do this in the cheat code + if (player->cheats & CF_NOCLIP) + player->mo->flags |= MF_NOCLIP; + else + player->mo->flags &= ~MF_NOCLIP; + */ + + // haleyjd 20110205 [STRIFE]: P_DeathThink moved up + if (player->playerstate == PST_DEAD) + { + P_DeathThink (player); + return; + } + + // chain saw run forward + cmd = &player->cmd; + if (player->mo->flags & MF_JUSTATTACKED) + { + cmd->angleturn = 0; + cmd->forwardmove = 0xc800/512; + cmd->sidemove = 0; + player->mo->flags &= ~MF_JUSTATTACKED; + } + + // Move around. + // Reactiontime is used to prevent movement + // for a bit after a teleport. + if (player->mo->reactiontime) + player->mo->reactiontime--; + else + P_MovePlayer (player); + + P_CalcHeight (player); + + if (player->mo->subsector->sector->special) + P_PlayerInSpecialSector (player); + + // villsa [STRIFE] handle inventory input + if(cmd->buttons2 & (BT2_HEALTH|BT2_INVUSE|BT2_INVDROP)) + { + if(!player->inventorydown) + { + if(cmd->buttons2 & BT2_HEALTH) + P_UseInventoryItem(player, SPR_FULL); + else if(cmd->buttons2 & BT2_INVUSE) + P_UseInventoryItem(player, cmd->inventory); + else if(cmd->buttons2 & BT2_INVDROP) + { + P_DropInventoryItem(player, cmd->inventory); + + // haleyjd 20110205: removed incorrect "else" here + // villsa [STRIFE] + if(workparm) + { + int cheat = player->cheats ^ 1; + player->cheats ^= CF_NOCLIP; + + if(cheat & CF_NOCLIP) + { + player->message = DEH_String("No Clipping Mode ON"); + player->mo->flags |= MF_NOCLIP; + } + else + { + player->mo->flags &= ~MF_NOCLIP; + player->message = DEH_String("No Clipping Mode OFF"); + } + } + } + } + + player->inventorydown = true; + } + else + player->inventorydown = false; + + // Check for weapon change. + + // A special event has no other buttons. + if(cmd->buttons & BT_SPECIAL) + cmd->buttons = 0; + + if(cmd->buttons & BT_CHANGE) + { + // The actual changing of the weapon is done + // when the weapon psprite can do it + // (read: not in the middle of an attack). + newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT; + + // villsa [STRIFE] select poison bow + if(newweapon == wp_elecbow) + { + if(player->weaponowned[wp_poisonbow] && player->readyweapon == wp_elecbow) + { + if(player->ammo[weaponinfo[wp_poisonbow].ammo]) + newweapon = wp_poisonbow; + } + } + + // villsa [STRIFE] select wp grenade launcher + if(newweapon == wp_hegrenade) + { + if(player->weaponowned[wp_wpgrenade] && player->readyweapon == wp_hegrenade) + { + if(player->ammo[weaponinfo[wp_wpgrenade].ammo]) + newweapon = wp_wpgrenade; + } + } + + // villsa [STRIFE] select torpedo + if(newweapon == wp_mauler) + { + if(player->weaponowned[wp_torpedo] && player->readyweapon == wp_mauler) + { + if(player->ammo[weaponinfo[am_cell].ammo] >= 30) + newweapon = wp_torpedo; + } + } + + if(player->weaponowned[newweapon] && newweapon != player->readyweapon) + { + // villsa [STRIFE] check weapon if in demo mode or not + if(weaponinfo[newweapon].availabledemo || !isdemoversion) + { + if(player->ammo[weaponinfo[newweapon].ammo]) + player->pendingweapon = newweapon; + else + { + // decide between electric bow or poison arrow + if(newweapon == wp_elecbow && + player->ammo[am_poisonbolts] && + player->readyweapon != wp_poisonbow) + { + player->pendingweapon = wp_poisonbow; + } + // decide between hp grenade launcher or wp grenade launcher + else if(newweapon == wp_hegrenade && + player->ammo[am_wpgrenades] && + player->readyweapon != wp_wpgrenade) + { + player->pendingweapon = wp_wpgrenade; + } + + // villsa [STRIFE] - no check for mauler/torpedo?? + } + } + } + } + + // check for use + if(cmd->buttons & BT_USE) + { + if(!player->usedown) + { + P_DialogStart(player); // villsa [STRIFE] + P_UseLines (player); + player->usedown = true; + } + } + else + player->usedown = false; + + // cycle psprites + P_MovePsprites (player); + + // Counters, time dependend power ups. + + // Strength counts up to diminish fade. + if (player->powers[pw_strength]) + player->powers[pw_strength]++; + + // villsa [STRIFE] targeter powerup + if(player->powers[pw_targeter]) + { + player->powers[pw_targeter]--; + if(player->powers[pw_targeter] == 1) + { + P_SetPsprite(player, ps_targcenter, S_NULL); + P_SetPsprite(player, ps_targleft, S_NULL); + P_SetPsprite(player, ps_targright, S_NULL); + } + else if(player->powers[pw_targeter] - 1 < 5*TICRATE) + { + if(player->powers[pw_targeter] & 32) + { + P_SetPsprite(player, ps_targright, S_NULL); + P_SetPsprite(player, ps_targleft, S_TRGT_01); // 11 + } + else if(player->powers[pw_targeter] & 16) // haleyjd 20110205: missing else + { + P_SetPsprite(player, ps_targright, S_TRGT_02); // 12 + P_SetPsprite(player, ps_targleft, S_NULL); + } + } + } + + if(player->powers[pw_invisibility]) + { + // villsa [STRIFE] remove mvis flag as well + if(!--player->powers[pw_invisibility]) + player->mo->flags &= ~(MF_SHADOW|MF_MVIS); + } + + if(player->powers[pw_ironfeet]) + { + player->powers[pw_ironfeet]--; + + // villsa [STRIFE] gasmask sound + if(!(leveltime & 0x3f)) + S_StartSound(player->mo, sfx_mask); + } + + if(player->powers[pw_allmap] > 1) + player->powers[pw_allmap]--; + + // haleyjd 08/30/10: [STRIFE] + // Nukage count keeps track of exposure to hazardous conditions over time. + // After accumulating 16 total seconds or more of exposure, you will take + // 5 damage roughly once per second until the count drops back under 560 + // tics. + if(player->nukagecount) + { + player->nukagecount--; + if(!(leveltime & 0x1f) && player->nukagecount > 16*TICRATE) + P_DamageMobj(player->mo, NULL, NULL, 5); + } + + if(player->damagecount) + player->damagecount--; + + if(player->bonuscount) + player->bonuscount--; + + // villsa [STRIFE] checks for extralight + if(player->extralight >= 0) + { + if(player->cheats & CF_ONFIRE) + player->fixedcolormap = 1; + else + player->fixedcolormap = 0; + } + else // Sigil shock: + player->fixedcolormap = INVERSECOLORMAP; +} + + +// +// P_RemoveInventoryItem +// villsa [STRIFE] new function +// +char* P_RemoveInventoryItem(player_t *player, int slot, int amount) +{ + mobjtype_t type; + + player->inventory[slot].amount -= amount; + player->st_update = true; + + type = player->inventory[slot].type; + + if(!player->inventory[slot].amount) + { + // shift everything above it down + // see P_TakeDialogItem for notes on possible bugs + int j; + + for(j = slot + 1; j <= player->numinventory; j++) + { + inventory_t *item1 = &(player->inventory[j - 1]); + inventory_t *item2 = &(player->inventory[j]); + + *item1 = *item2; + } + + player->inventory[player->numinventory].type = NUMMOBJTYPES; + player->inventory[player->numinventory].sprite = -1; + player->numinventory--; + + // update cursor position + if(player->inventorycursor >= player->numinventory) + { + if(player->inventorycursor) + player->inventorycursor--; + } + } + + return mobjinfo[type].name; +} + +// +// P_DropInventoryItem +// villsa [STRIFE] new function +// +void P_DropInventoryItem(player_t* player, int sprite) +{ + int invslot; + inventory_t *item; + mobjtype_t type; + int amount; + + invslot = 0; + amount = 1; + + while(invslot < player->numinventory && sprite != player->inventory[invslot].sprite) + invslot++; + + item = &(player->inventory[invslot]); + type = item->type; + + if(item->amount) + { + angle_t angle; + fixed_t dist; + mobj_t* mo; + mobj_t* mobjitem; + fixed_t x; + fixed_t y; + fixed_t z; + int r; + + if(item->type == MT_MONY_1) + { + if(item->amount >= 50) + { + type = MT_MONY_50; + amount = 50; + } + else if(item->amount >= 25) + { + type = MT_MONY_25; + amount = 25; + } + else if(item->amount >= 10) + { + type = MT_MONY_10; + amount = 10; + } + } + + if(type >= NUMMOBJTYPES) + return; + + angle = player->mo->angle; + r = P_Random(); + angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT; + + if(angle < 7618 && angle >= 6718) + angle = 7618; + + else if(angle < 5570 && angle >= 4670) + angle = 5570; + + else if(angle < 3522 && angle >= 2622) + angle = 3522; + + else if(angle < 1474 && angle >= 574) + angle = 1474; + + mo = player->mo; + dist = mobjinfo[type].radius + mo->info->radius + (4*FRACUNIT); + + x = mo->x + FixedMul(finecosine[angle], dist); + y = mo->y + FixedMul(finesine[angle], dist); + z = mo->z + (10*FRACUNIT); + mobjitem = P_SpawnMobj(x, y, z, type); + mobjitem->flags |= (MF_SPECIAL|MF_DROPPED); + + if(P_CheckPosition(mobjitem, x, y)) + { + mobjitem->angle = (angle << ANGLETOFINESHIFT); + mobjitem->momx = FixedMul(finecosine[angle], (5*FRACUNIT)) + mo->momx; + mobjitem->momy = FixedMul(finesine[angle], (5*FRACUNIT)) + mo->momy; + mobjitem->momz = FRACUNIT; + + P_RemoveInventoryItem(player, invslot, amount); + } + else + P_RemoveMobj(mobjitem); + } +} + +// +// P_TossDegninOre +// villsa [STRIFE] new function +// +boolean P_TossDegninOre(player_t* player) +{ + angle_t angle; + mobj_t* mo; + mobj_t* ore; + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t dist; + + angle = player->mo->angle >> ANGLETOFINESHIFT; + + if(angle < 7618 && angle >= 6718) + angle = 7618; + + else if(angle < 5570 && angle >= 4670) + angle = 5570; + + else if(angle < 3522 && angle >= 2622) + angle = 3522; + + else if(angle < 1474 && angle >= 574) + angle = 1474; + + mo = player->mo; + dist = mobjinfo[MT_DEGNINORE].radius + mo->info->radius + (4*FRACUNIT); + + x = mo->x + FixedMul(finecosine[angle], dist); + y = mo->y + FixedMul(finesine[angle], dist); + z = mo->z + (10*FRACUNIT); + ore = P_SpawnMobj(x, y, z, MT_DEGNINORE); + + if(P_CheckPosition(ore, x, y)) + { + ore->target = mo; + ore->angle = (angle << ANGLETOFINESHIFT); + ore->momx = FixedMul(finecosine[angle], (5*FRACUNIT)); + ore->momy = FixedMul(finesine[angle], (5*FRACUNIT)); + ore->momz = FRACUNIT; + return true; + } + else + P_RemoveMobj(ore); + + return false; +} + +// +// P_SpawnTeleportBeacon +// villsa [STRIFE] new function +// +boolean P_SpawnTeleportBeacon(player_t* player) +{ + angle_t angle; + int r; + mobj_t* mo; + mobj_t* beacon; + fixed_t x; + fixed_t y; + fixed_t z; + fixed_t dist; + + angle = player->mo->angle; + r = P_Random(); + angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT; + + if(angle < 7618 && angle >= 6718) + angle = 7618; + + else if(angle < 5570 && angle >= 4670) + angle = 5570; + + else if(angle < 3522 && angle >= 2622) + angle = 3522; + + else if(angle < 1474 && angle >= 574) + angle = 1474; + + mo = player->mo; + dist = mobjinfo[MT_BEACON].radius + mo->info->radius + (4*FRACUNIT); + + x = mo->x + FixedMul(finecosine[angle], dist); + y = mo->y + FixedMul(finesine[angle], dist); + z = mo->z + (10*FRACUNIT); + beacon = P_SpawnMobj(x, y, z, MT_BEACON); + + if(P_CheckPosition(beacon, x, y)) + { + beacon->target = mo; + beacon->miscdata = mo->miscdata; + beacon->angle = (angle << ANGLETOFINESHIFT); + beacon->momx = FixedMul(finecosine[angle], (5*FRACUNIT)); + beacon->momy = FixedMul(finesine[angle], (5*FRACUNIT)); + beacon->momz = FRACUNIT; + P_SetMobjState(beacon, beacon->info->seestate); + return true; + } + else + P_RemoveMobj(beacon); + + return false; +} + +// +// P_UseInventoryItem +// villsa [STRIFE] new function +// +boolean P_UseInventoryItem(player_t* player, int item) +{ + int i; + char* name; + + if(player->cheats & CF_ONFIRE) + return false; + + for(i = 0; i < player->numinventory; i++) + { + if(item != player->inventory[i].sprite) + continue; + + if(!P_ItemBehavior(player, item)) + return false; + + name = P_RemoveInventoryItem(player, i, 1); + if(name == NULL) + name = "Item"; + + sprintf(useinventorymsg, "You used the %s.", name); + player->message = useinventorymsg; + + if(player == &players[consoleplayer]) + S_StartSound(NULL, sfx_itemup); + + return true; + } + + return false; +} + +// +// P_ItemBehavior +// villsa [STRIFE] new function +// +boolean P_ItemBehavior(player_t* player, int item) +{ + switch(item) + { + case SPR_ARM1: // 136 + return P_GiveArmor(player, 2); + + case SPR_ARM2: // 137 + return P_GiveArmor(player, 1); + + case SPR_SHD1: // 186 + return P_GivePower(player, pw_invisibility); + + case SPR_MASK: // 187 + return P_GivePower(player, pw_ironfeet); + + case SPR_PMUP: // 191 + if(!player->powers[pw_allmap]) + { + player->message = "The scanner won't work without a map!"; + return false; + } + player->powers[pw_allmap] = PMUPTICS; + return true; // haleyjd 20110228: repaired + + case SPR_STMP: // 180 + return P_GiveBody(player, 10); + + case SPR_MDKT: // 181 + return P_GiveBody(player, 25); + + case SPR_FULL: // 130 + return P_GiveBody(player, 200); + + case SPR_BEAC: // 135 + return P_SpawnTeleportBeacon(player); + + case SPR_TARG: // 108 + return P_GivePower(player, pw_targeter); + } + + return false; +} |