/* P_user.c */ #include "doomdef.h" #include "p_local.h" #include "soundst.h" extern int lmousey; extern boolean g_bMlook; 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 { #ifndef GL_HERETIC #define RATIO(x) (int)((float)x*(float)screenheight/200) #else #define RATIO(x) x #endif /* player->lookdir += 5*look; */ player->lookdir += RATIO(5*look); if(player->lookdir > RATIO(90) || player->lookdir < RATIO(-110)) { player->lookdir -= RATIO(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]) { 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<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); }