From 0df2cb80cf03d7259746834220d209b306a8c503 Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Thu, 4 Sep 2008 23:15:36 +0000 Subject: Add GPLed Heretic/Hexen source. Subversion-branch: /branches/raven-branch Subversion-revision: 1195 --- src/heretic/p_user.c | 1007 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1007 insertions(+) create mode 100644 src/heretic/p_user.c (limited to 'src/heretic/p_user.c') diff --git a/src/heretic/p_user.c b/src/heretic/p_user.c new file mode 100644 index 00000000..3f8ffa0f --- /dev/null +++ b/src/heretic/p_user.c @@ -0,0 +1,1007 @@ + +// P_user.c + +#include "DoomDef.h" +#include "P_local.h" +#include "soundst.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((byte *)W_CacheLumpName("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<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] || !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]) + { +#ifdef __WATCOMC__ + if(player->mo->z != player->mo->floorz && !useexterndriver) + { + player->centering = true; + } +#else + if(player->mo->z != player->mo->floorz) + { + player->centering = true; + } +#endif + + 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<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); +} -- cgit v1.2.3