home *** CD-ROM | disk | FTP | other *** search
- /* Emacs style mode select -*- C++ -*- */
- /* ----------------------------------------------------------------------------- */
- /* */
- /* $Id:$ */
- /* */
- /* Copyright (C) 1993-1996 by id Software, Inc. */
- /* */
- /* This source is available for distribution and/or modification */
- /* only under the terms of the DOOM Source Code License as */
- /* published by id Software. All rights reserved. */
- /* */
- /* The source is distributed in the hope that it will be useful, */
- /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
- /* FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License */
- /* for more details. */
- /* */
- /* $Log:$ */
- /* */
- /* DESCRIPTION: */
- /* Weapon sprite animation, weapon objects. */
- /* Action functions for weapons. */
- /* */
- /* ----------------------------------------------------------------------------- */
-
- static const char
- rcsid[] = "$Id: p_pspr.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
-
- #include "doomdef.h"
- #include "d_event.h"
-
-
- #include "m_random.h"
- #include "p_local.h"
- #include "s_sound.h"
-
- /* State. */
- #include "doomstat.h"
-
- /* Data. */
- #include "sounds.h"
-
- #include "p_pspr.h"
-
- #define LOWERSPEED FRACUNIT*6
- #define RAISESPEED FRACUNIT*6
-
- #define WEAPONBOTTOM 128*FRACUNIT
- #define WEAPONTOP 32*FRACUNIT
-
-
- /* plasma cells for a bfg attack */
- #define BFGCELLS 40
-
-
- /* */
- /* P_SetPsprite */
- /* */
- void
- P_SetPsprite
- ( player_t* player,
- int position,
- statenum_t stnum )
- {
- pspdef_t* psp;
- state_t* state;
-
- psp = &player->psprites[position];
-
- do
- {
- 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.acp2)
- {
- state->action.acp2(player, psp);
- if (!psp->state)
- break;
- }
-
- stnum = psp->state->nextstate;
-
- } while (!psp->tics);
- /* an initial state of 0 could cycle through */
- }
-
-
-
- /* */
- /* P_CalcSwing */
- /* */
- fixed_t swingx;
- fixed_t swingy;
-
- void P_CalcSwing (player_t* player)
- {
- fixed_t swing;
- int angle;
-
- /* OPTIMIZE: tablify this. */
- /* A LUT would allow for different modes, */
- /* and add flexibility. */
-
- swing = player->bob;
-
- angle = (FINEANGLES/70*leveltime)&FINEMASK;
- swingx = FixedMul ( swing, finesine[angle]);
-
- angle = (FINEANGLES/70*leveltime+FINEANGLES/2)&FINEMASK;
- swingy = -FixedMul ( swingx, finesine[angle]);
- }
-
-
-
- /* */
- /* P_BringUpWeapon */
- /* Starts bringing the pending weapon up */
- /* from the bottom of the screen. */
- /* Uses player */
- /* */
- 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;
- player->psprites[ps_weapon].sy = WEAPONBOTTOM;
-
- P_SetPsprite (player, ps_weapon, newstate);
- }
-
- /* */
- /* P_CheckAmmo */
- /* Returns true if there is enough ammo to shoot. */
- /* If not, selects the next weapon to use. */
- /* */
- boolean P_CheckAmmo (player_t* player)
- {
- ammotype_t ammo;
- int count;
-
- ammo = weaponinfo[player->readyweapon].ammo;
-
- /* Minimal amount for one shot varies. */
- if (player->readyweapon == wp_bfg)
- count = BFGCELLS;
- else if (player->readyweapon == wp_supershotgun)
- count = 2; /* Double barrel. */
- else
- count = 1; /* Regular. */
-
- /* 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. */
- /* Preferences are set here. */
- do
- {
- if (player->weaponowned[wp_plasma]
- && player->ammo[am_cell]
- && (gamemode != shareware) )
- {
- player->pendingweapon = wp_plasma;
- }
- else if (player->weaponowned[wp_supershotgun]
- && player->ammo[am_shell]>2
- && (gamemode == commercial) )
- {
- player->pendingweapon = wp_supershotgun;
- }
- else if (player->weaponowned[wp_chaingun]
- && player->ammo[am_clip])
- {
- player->pendingweapon = wp_chaingun;
- }
- else if (player->weaponowned[wp_shotgun]
- && player->ammo[am_shell])
- {
- player->pendingweapon = wp_shotgun;
- }
- else if (player->ammo[am_clip])
- {
- player->pendingweapon = wp_pistol;
- }
- else if (player->weaponowned[wp_chainsaw])
- {
- player->pendingweapon = wp_chainsaw;
- }
- else if (player->weaponowned[wp_missile]
- && player->ammo[am_misl])
- {
- player->pendingweapon = wp_missile;
- }
- else if (player->weaponowned[wp_bfg]
- && player->ammo[am_cell]>40
- && (gamemode != shareware) )
- {
- player->pendingweapon = wp_bfg;
- }
- else
- {
- /* If everything fails. */
- player->pendingweapon = wp_fist;
- }
-
- } while (player->pendingweapon == wp_nochange);
-
- /* Now set appropriate weapon overlay. */
- P_SetPsprite (player,
- ps_weapon,
- weaponinfo[player->readyweapon].downstate);
-
- return false;
- }
-
-
- /* */
- /* P_FireWeapon. */
- /* */
- 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);
- }
-
-
-
- /* */
- /* 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 )
- {
- statenum_t newstate;
- int angle;
-
- /* 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 allready be validated) */
- 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 */
- 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 )
- {
-
- /* 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 )
- {
- P_CheckAmmo (player);
- #if 0
- if (player->ammo[am_shell]<2)
- P_SetPsprite (player, ps_weapon, S_DSNR1);
- #endif
- }
-
-
-
- /* */
- /* 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;
-
- /* don't bring weapon back up */
- return;
- }
-
- /* 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);
- }
-
-
-
- /* */
- /* A_GunFlash */
- /* */
- void
- A_GunFlash
- ( player_t* player,
- pspdef_t* psp )
- {
- P_SetMobjState (player->mo, S_PLAY_ATK2);
- P_SetPsprite (player,ps_flash,weaponinfo[player->readyweapon].flashstate);
- }
-
-
-
- /* */
- /* WEAPON ATTACKS */
- /* */
-
-
- /* */
- /* A_Punch */
- /* */
- void
- A_Punch
- ( player_t* player,
- pspdef_t* psp )
- {
- angle_t angle;
- int damage;
- int slope;
-
- damage = (P_Random ()%10+1)<<1;
-
- if (player->powers[pw_strength])
- damage *= 10;
-
- angle = player->mo->angle;
- angle += (P_Random()-P_Random())<<18;
- slope = P_AimLineAttack (player->mo, angle, MELEERANGE);
- P_LineAttack (player->mo, angle, MELEERANGE, slope, damage);
-
- /* turn to face target */
- if (linetarget)
- {
- S_StartSound (player->mo, sfx_punch);
- 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 )
- {
- angle_t angle;
- int damage;
- int slope;
-
- damage = 2*(P_Random ()%10+1);
- angle = player->mo->angle;
- angle += (P_Random()-P_Random())<<18;
-
- /* use meleerange + 1 se the puff doesn't skip the flash */
- slope = P_AimLineAttack (player->mo, angle, MELEERANGE+1);
- 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 < -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 )
- {
- player->ammo[weaponinfo[player->readyweapon].ammo]--;
- P_SpawnPlayerMissile (player->mo, MT_ROCKET);
- }
-
-
- /* */
- /* A_FireBFG */
- /* */
- void
- A_FireBFG
- ( player_t* player,
- pspdef_t* psp )
- {
- player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS;
- P_SpawnPlayerMissile (player->mo, MT_BFG);
- }
-
-
-
- /* */
- /* A_FirePlasma */
- /* */
- void
- A_FirePlasma
- ( player_t* player,
- pspdef_t* psp )
- {
- player->ammo[weaponinfo[player->readyweapon].ammo]--;
-
- P_SetPsprite (player,
- ps_flash,
- weaponinfo[player->readyweapon].flashstate+(P_Random ()&1) );
-
- P_SpawnPlayerMissile (player->mo, MT_PLASMA);
- }
-
-
-
- /* */
- /* P_BulletSlope */
- /* Sets a slope so a near miss is at aproximately */
- /* the height of the intended target */
- /* */
- fixed_t bulletslope;
-
-
- void P_BulletSlope (mobj_t* mo)
- {
- angle_t an;
-
- /* see which target is to be aimed at */
- an = mo->angle;
- bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
-
- if (!linetarget)
- {
- an += 1<<26;
- bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
- if (!linetarget)
- {
- an -= 2<<26;
- bulletslope = P_AimLineAttack (mo, an, 16*64*FRACUNIT);
- }
- }
- }
-
-
- /* */
- /* P_GunShot */
- /* */
- void
- P_GunShot
- ( mobj_t* mo,
- boolean accurate )
- {
- angle_t angle;
- int damage;
-
- damage = 5*(P_Random ()%3+1);
- angle = mo->angle;
-
- if (!accurate)
- angle += (P_Random()-P_Random())<<18;
-
- P_LineAttack (mo, angle, MISSILERANGE, bulletslope, damage);
- }
-
-
- /* */
- /* A_FirePistol */
- /* */
- void
- A_FirePistol
- ( player_t* player,
- pspdef_t* psp )
- {
- S_StartSound (player->mo, sfx_pistol);
-
- P_SetMobjState (player->mo, S_PLAY_ATK2);
- player->ammo[weaponinfo[player->readyweapon].ammo]--;
-
- P_SetPsprite (player,
- ps_flash,
- weaponinfo[player->readyweapon].flashstate);
-
- P_BulletSlope (player->mo);
- P_GunShot (player->mo, !player->refire);
- }
-
-
- /* */
- /* A_FireShotgun */
- /* */
- void
- A_FireShotgun
- ( player_t* player,
- pspdef_t* psp )
- {
- int i;
-
- S_StartSound (player->mo, sfx_shotgn);
- P_SetMobjState (player->mo, S_PLAY_ATK2);
-
- player->ammo[weaponinfo[player->readyweapon].ammo]--;
-
- P_SetPsprite (player,
- ps_flash,
- weaponinfo[player->readyweapon].flashstate);
-
- 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 )
- {
- int i;
- angle_t angle;
- int damage;
-
-
- S_StartSound (player->mo, sfx_dshtgn);
- P_SetMobjState (player->mo, S_PLAY_ATK2);
-
- player->ammo[weaponinfo[player->readyweapon].ammo]-=2;
-
- P_SetPsprite (player,
- ps_flash,
- weaponinfo[player->readyweapon].flashstate);
-
- P_BulletSlope (player->mo);
-
- for (i=0 ; i<20 ; i++)
- {
- damage = 5*(P_Random ()%3+1);
- angle = player->mo->angle;
- angle += (P_Random()-P_Random())<<19;
- P_LineAttack (player->mo,
- angle,
- MISSILERANGE,
- bulletslope + ((P_Random()-P_Random())<<5), damage);
- }
- }
-
-
- /* */
- /* A_FireCGun */
- /* */
- void
- A_FireCGun
- ( player_t* player,
- pspdef_t* psp )
- {
- 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]--;
-
- P_SetPsprite (player,
- ps_flash,
- weaponinfo[player->readyweapon].flashstate
- + psp->state
- - &states[S_CHAIN1] );
-
- P_BulletSlope (player->mo);
-
- P_GunShot (player->mo, !player->refire);
- }
-
-
-
- /* */
- /* ? */
- /* */
- void A_Light0 (player_t *player, pspdef_t *psp)
- {
- player->extralight = 0;
- }
-
- void A_Light1 (player_t *player, pspdef_t *psp)
- {
- player->extralight = 1;
- }
-
- void A_Light2 (player_t *player, pspdef_t *psp)
- {
- player->extralight = 2;
- }
-
-
- /* */
- /* A_BFGSpray */
- /* Spawn a BFG explosion on every monster in view */
- /* */
- void A_BFGSpray (mobj_t* mo)
- {
- int i;
- int j;
- int damage;
- angle_t an;
-
- /* offset angles from its attack angle */
- for (i=0 ; i<40 ; i++)
- {
- an = mo->angle - ANG90/2 + ANG90/40*i;
-
- /* mo->target is the originator (player) */
- /* of the missile */
- P_AimLineAttack (mo->target, an, 16*64*FRACUNIT);
-
- if (!linetarget)
- continue;
-
- P_SpawnMobj (linetarget->x,
- linetarget->y,
- linetarget->z + (linetarget->height>>2),
- MT_EXTRABFG);
-
- damage = 0;
- for (j=0;j<15;j++)
- damage += (P_Random()&7) + 1;
-
- P_DamageMobj (linetarget, mo->target,mo->target, damage);
- }
- }
-
-
- /* */
- /* A_BFGsound */
- /* */
- void
- A_BFGsound
- ( player_t* player,
- pspdef_t* 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)
- {
- int i;
- pspdef_t* psp;
- state_t* state;
-
- psp = &player->psprites[0];
- for (i=0 ; i<NUMPSPRITES ; i++, psp++)
- {
- /* a null state means not active */
- if ( (state = psp->state) )
- {
- /* drop tic count and possibly change state */
-
- /* a -1 tic count never changes */
- if (psp->tics != -1)
- {
- psp->tics--;
- if (!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;
- }
-
-
-