From b9d4e0c10b4ef3322947d2b5ed648544986b557c Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 1 Feb 2010 19:13:33 +0000 Subject: Create strife directory as a copy of doom directory, change Makefile.am to build libstrife.a rather than libdoom.a, add chocolate-strife to src/Makefile.am. Subversion-branch: /branches/strife-branch Subversion-revision: 1840 --- src/strife/p_pspr.c | 896 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 896 insertions(+) create mode 100644 src/strife/p_pspr.c (limited to 'src/strife/p_pspr.c') diff --git a/src/strife/p_pspr.c b/src/strife/p_pspr.c new file mode 100644 index 00000000..fe32c53f --- /dev/null +++ b/src/strife/p_pspr.c @@ -0,0 +1,896 @@ +// 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: +// Weapon sprite animation, weapon objects. +// Action functions for weapons. +// +//----------------------------------------------------------------------------- + + +#include "doomdef.h" +#include "d_event.h" + +#include "deh_misc.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 + + + +// +// 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 = deh_bfg_cells_per_shot; + 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 ((signed int) (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; +} + +// Doom does not check the bounds of the ammo array. As a result, +// it is possible to use an ammo type > 4 that overflows into the +// maxammo array and affects that instead. Through dehacked, for +// example, it is possible to make a weapon that decreases the max +// number of ammo for another weapon. Emulate this. + +static void DecreaseAmmo(player_t *player, int ammonum, int amount) +{ + if (ammonum < NUMAMMO) + { + player->ammo[ammonum] -= amount; + } + else + { + player->maxammo[ammonum - NUMAMMO] -= amount; + } +} + + +// +// A_FireMissile +// +void +A_FireMissile +( player_t* player, + pspdef_t* psp ) +{ + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); + P_SpawnPlayerMissile (player->mo, MT_ROCKET); +} + + +// +// A_FireBFG +// +void +A_FireBFG +( player_t* player, + pspdef_t* psp ) +{ + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, + deh_bfg_cells_per_shot); + P_SpawnPlayerMissile (player->mo, MT_BFG); +} + + + +// +// A_FirePlasma +// +void +A_FirePlasma +( player_t* player, + pspdef_t* psp ) +{ + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); + + 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); + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); + + 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); + + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); + + 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); + + DecreaseAmmo(player, 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); + DecreaseAmmo(player, weaponinfo[player->readyweapon].ammo, 1); + + 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 ; ipsprites[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 ; istate) ) + { + // 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; +} + + -- cgit v1.2.3