123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880 |
- // 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;
- }
|