2016-03-01 15:47:10 +00:00
//**************************************************************************
//**
//** p_pspr.c : Heretic 2 : Raven Software, Corp.
//**
//** $RCSfile: p_pspr.c,v $
//** $Revision: 1.105 $
//** $Date: 96/01/06 03:23:35 $
//** $Author: bgokey $
//**
//**************************************************************************
// HEADER FILES ------------------------------------------------------------
# include <stdlib.h>
# include "doomdef.h"
# include "d_event.h"
# include "c_cvars.h"
# include "m_random.h"
# include "p_enemy.h"
# include "p_local.h"
# include "s_sound.h"
# include "doomstat.h"
# include "gi.h"
# include "p_pspr.h"
# include "templates.h"
# include "g_level.h"
# include "d_player.h"
2016-09-20 08:27:53 +00:00
# include "serializer.h"
2016-11-13 11:02:41 +00:00
# include "v_text.h"
2016-11-19 15:39:45 +00:00
# include "cmdlib.h"
2016-03-01 15:47:10 +00:00
// MACROS ------------------------------------------------------------------
2016-03-21 00:16:34 +00:00
# define LOWERSPEED 6.
# define RAISESPEED 6.
2016-03-01 15:47:10 +00:00
// TYPES -------------------------------------------------------------------
struct FGenericButtons
{
int ReadyFlag ; // Flag passed to A_WeaponReady
int StateFlag ; // Flag set in WeaponState
int ButtonFlag ; // Button to press
ENamedName StateName ; // Name of the button/state
} ;
enum EWRF_Options
{
WRF_NoBob = 1 ,
WRF_NoSwitch = 1 < < 1 ,
WRF_NoPrimary = 1 < < 2 ,
WRF_NoSecondary = 1 < < 3 ,
WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary ,
WRF_AllowReload = 1 < < 4 ,
WRF_AllowZoom = 1 < < 5 ,
WRF_DisableSwitch = 1 < < 6 ,
WRF_AllowUser1 = 1 < < 7 ,
WRF_AllowUser2 = 1 < < 8 ,
WRF_AllowUser3 = 1 < < 9 ,
WRF_AllowUser4 = 1 < < 10 ,
} ;
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PUBLIC DATA DEFINITIONS -------------------------------------------------
// [SO] 1=Weapons states are all 1 tick
// 2=states with a function 1 tick, others 0 ticks.
CVAR ( Int , sv_fastweapons , false , CVAR_SERVERINFO ) ;
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FRandom pr_wpnreadysnd ( " WpnReadySnd " ) ;
static const FGenericButtons ButtonChecks [ ] =
{
{ WRF_AllowZoom , WF_WEAPONZOOMOK , BT_ZOOM , NAME_Zoom } ,
{ WRF_AllowReload , WF_WEAPONRELOADOK , BT_RELOAD , NAME_Reload } ,
{ WRF_AllowUser1 , WF_USER1OK , BT_USER1 , NAME_User1 } ,
{ WRF_AllowUser2 , WF_USER2OK , BT_USER2 , NAME_User2 } ,
{ WRF_AllowUser3 , WF_USER3OK , BT_USER3 , NAME_User3 } ,
{ WRF_AllowUser4 , WF_USER4OK , BT_USER4 , NAME_User4 } ,
} ;
// CODE --------------------------------------------------------------------
2016-05-09 18:03:47 +00:00
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2016-11-24 20:36:02 +00:00
IMPLEMENT_CLASS ( DPSprite , false , true )
2016-11-05 16:08:54 +00:00
IMPLEMENT_POINTERS_START ( DPSprite )
IMPLEMENT_POINTER ( Caller )
IMPLEMENT_POINTER ( Next )
IMPLEMENT_POINTERS_END
2016-05-09 18:03:47 +00:00
2016-11-22 22:42:32 +00:00
DEFINE_FIELD_NAMED ( DPSprite , State , CurState ) // deconflict with same named type
DEFINE_FIELD ( DPSprite , Caller )
DEFINE_FIELD ( DPSprite , Next )
DEFINE_FIELD ( DPSprite , Owner )
DEFINE_FIELD ( DPSprite , Sprite )
DEFINE_FIELD ( DPSprite , Frame )
DEFINE_FIELD ( DPSprite , ID )
DEFINE_FIELD ( DPSprite , processPending )
DEFINE_FIELD ( DPSprite , x )
DEFINE_FIELD ( DPSprite , y )
DEFINE_FIELD ( DPSprite , oldx )
DEFINE_FIELD ( DPSprite , oldy )
DEFINE_FIELD ( DPSprite , firstTic )
DEFINE_FIELD ( DPSprite , Tics )
DEFINE_FIELD_BIT ( DPSprite , Flags , bAddWeapon , PSPF_ADDWEAPON )
DEFINE_FIELD_BIT ( DPSprite , Flags , bAddBob , PSPF_ADDBOB )
DEFINE_FIELD_BIT ( DPSprite , Flags , bPowDouble , PSPF_POWDOUBLE )
DEFINE_FIELD_BIT ( DPSprite , Flags , bCVarFast , PSPF_CVARFAST )
DEFINE_FIELD_BIT ( DPSprite , Flags , bFlip , PSPF_FLIP )
2016-11-19 15:39:45 +00:00
2016-05-09 18:03:47 +00:00
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2016-06-03 17:18:58 +00:00
DPSprite : : DPSprite ( player_t * owner , AActor * caller , int id )
2016-06-17 08:08:45 +00:00
: x ( .0 ) , y ( .0 ) ,
2016-05-27 20:56:42 +00:00
oldx ( .0 ) , oldy ( .0 ) ,
2016-06-17 08:08:45 +00:00
firstTic ( true ) ,
Flags ( 0 ) ,
2016-05-27 20:56:42 +00:00
Caller ( caller ) ,
2016-06-17 08:08:45 +00:00
Owner ( owner ) ,
ID ( id ) ,
processPending ( true )
2016-05-09 18:03:47 +00:00
{
2016-05-21 11:11:43 +00:00
DPSprite * prev = nullptr ;
DPSprite * next = Owner - > psprites ;
while ( next ! = nullptr & & next - > ID < ID )
{
prev = next ;
next = next - > Next ;
}
Next = next ;
GC : : WriteBarrier ( this , next ) ;
2016-05-26 19:58:46 +00:00
if ( prev = = nullptr )
2016-05-21 11:11:43 +00:00
{
Owner - > psprites = this ;
GC : : WriteBarrier ( this ) ;
}
else
{
prev - > Next = this ;
GC : : WriteBarrier ( prev , this ) ;
}
2016-05-09 18:03:47 +00:00
if ( Next & & Next - > ID = = ID & & ID ! = 0 )
Next - > Destroy ( ) ; // Replace it.
2016-05-26 19:51:52 +00:00
2016-06-03 17:18:58 +00:00
if ( Caller - > IsKindOf ( RUNTIME_CLASS ( AWeapon ) ) | | Caller - > IsKindOf ( RUNTIME_CLASS ( APlayerPawn ) ) )
2016-06-02 21:58:21 +00:00
Flags = ( PSPF_ADDWEAPON | PSPF_ADDBOB | PSPF_POWDOUBLE | PSPF_CVARFAST ) ;
2016-05-09 18:03:47 +00:00
}
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2016-05-26 19:58:46 +00:00
DPSprite * player_t : : FindPSprite ( int layer )
2016-05-09 18:03:47 +00:00
{
2016-05-26 19:58:46 +00:00
if ( layer = = 0 )
return nullptr ;
2016-05-09 18:03:47 +00:00
DPSprite * pspr = psprites ;
while ( pspr )
{
if ( pspr - > ID = = layer )
2016-05-26 19:58:46 +00:00
break ;
2016-05-09 18:03:47 +00:00
pspr = pspr - > Next ;
}
return pspr ;
}
2016-11-22 18:20:31 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , FindPSprite ) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit)
2016-11-22 11:21:55 +00:00
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
PARAM_INT ( id ) ;
ACTION_RETURN_OBJECT ( self - > FindPSprite ( ( PSPLayers ) id ) ) ;
}
2016-05-18 12:20:36 +00:00
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2016-06-16 12:24:00 +00:00
void P_SetPsprite ( player_t * player , PSPLayers id , FState * state , bool pending )
{
if ( player = = nullptr ) return ;
player - > GetPSprite ( id ) - > SetState ( state , pending ) ;
}
2016-11-22 18:20:31 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , SetPSprite ) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit)
2016-11-19 12:56:29 +00:00
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
PARAM_INT ( id ) ;
PARAM_POINTER ( state , FState ) ;
PARAM_BOOL_DEF ( pending ) ;
P_SetPsprite ( self , ( PSPLayers ) id , state , pending ) ;
return 0 ;
}
2016-05-27 16:08:56 +00:00
DPSprite * player_t : : GetPSprite ( PSPLayers layer )
2016-05-18 12:20:36 +00:00
{
2016-06-03 17:18:58 +00:00
AActor * oldcaller = nullptr ;
AActor * newcaller = nullptr ;
2016-06-01 21:20:18 +00:00
if ( layer > = PSP_TARGETCENTER )
{
if ( mo ! = nullptr )
{
newcaller = mo - > FindInventory ( RUNTIME_CLASS ( APowerTargeter ) , true ) ;
}
}
2016-06-03 17:46:31 +00:00
else if ( layer = = PSP_STRIFEHANDS )
{
newcaller = mo ;
}
2016-06-01 21:20:18 +00:00
else
{
newcaller = ReadyWeapon ;
}
assert ( newcaller ! = nullptr ) ;
2016-05-30 13:09:03 +00:00
2016-05-26 19:51:52 +00:00
DPSprite * pspr = FindPSprite ( layer ) ;
if ( pspr = = nullptr )
2016-05-30 13:09:03 +00:00
{
2016-06-01 21:20:18 +00:00
pspr = new DPSprite ( this , newcaller , layer ) ;
2016-05-30 13:09:03 +00:00
}
else
{
oldcaller = pspr - > Caller ;
}
// Always update the caller here in case we switched weapon
2016-06-18 09:29:02 +00:00
// or if the layer was being used by something else before.
2016-06-01 21:20:18 +00:00
pspr - > Caller = newcaller ;
2016-05-30 13:09:03 +00:00
2016-06-01 21:20:18 +00:00
if ( newcaller ! = oldcaller )
2016-07-08 09:13:58 +00:00
{ // Only reset stuff if this layer was created now or if it was being used before.
2016-06-02 21:58:21 +00:00
if ( layer > = PSP_TARGETCENTER )
{ // The targeter layers were affected by those.
2016-06-18 09:29:02 +00:00
pspr - > Flags = ( PSPF_CVARFAST | PSPF_POWDOUBLE ) ;
}
else
{
pspr - > Flags = ( PSPF_ADDWEAPON | PSPF_ADDBOB | PSPF_CVARFAST | PSPF_POWDOUBLE ) ;
2016-06-02 21:58:21 +00:00
}
2016-06-18 07:46:55 +00:00
if ( layer = = PSP_STRIFEHANDS )
{
2016-06-18 08:48:13 +00:00
// Some of the old hacks rely on this layer coming from the FireHands state.
// This is the ONLY time a psprite's state is actually null.
pspr - > State = nullptr ;
2016-06-18 07:46:55 +00:00
pspr - > y = WEAPONTOP ;
}
2016-07-08 09:13:58 +00:00
2016-07-30 21:50:14 +00:00
pspr - > firstTic = true ;
2016-05-30 13:09:03 +00:00
}
2016-05-26 19:58:46 +00:00
2016-05-18 12:20:36 +00:00
return pspr ;
}
2016-11-22 18:20:31 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , GetPSprite ) // the underscore is needed to get past the name mangler which removes the first clas name character to match the class representation (needs to be fixed in a later commit)
2016-11-19 15:39:45 +00:00
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
PARAM_INT ( id ) ;
ACTION_RETURN_OBJECT ( self - > GetPSprite ( ( PSPLayers ) id ) ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC P_NewPspriteTick
//
//---------------------------------------------------------------------------
2016-05-09 18:03:47 +00:00
void DPSprite : : NewTick ( )
2016-03-01 15:47:10 +00:00
{
// This function should be called after the beginning of a tick, before any possible
// prprite-event, or near the end, after any possible psprite event.
// Because data is reset for every tick (which it must be) this has no impact on savegames.
2016-05-09 18:03:47 +00:00
for ( int i = 0 ; i < MAXPLAYERS ; i + + )
2016-03-01 15:47:10 +00:00
{
if ( playeringame [ i ] )
{
2016-05-09 18:03:47 +00:00
DPSprite * pspr = players [ i ] . psprites ;
while ( pspr )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
pspr - > processPending = true ;
2016-10-31 17:51:58 +00:00
pspr - > ResetInterpolation ( ) ;
2016-05-09 18:03:47 +00:00
pspr = pspr - > Next ;
2016-03-01 15:47:10 +00:00
}
}
}
}
//---------------------------------------------------------------------------
//
// PROC P_SetPsprite
//
//---------------------------------------------------------------------------
2016-05-09 18:03:47 +00:00
void DPSprite : : SetState ( FState * newstate , bool pending )
2016-03-01 15:47:10 +00:00
{
2016-05-27 16:08:56 +00:00
if ( ID = = PSP_WEAPON )
2016-03-01 15:47:10 +00:00
{ // A_WeaponReady will re-set these as needed
2016-05-09 18:03:47 +00:00
Owner - > WeaponState & = ~ ( WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK |
2016-03-01 15:47:10 +00:00
WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK ) ;
}
2016-05-09 18:03:47 +00:00
processPending = pending ;
2016-03-01 15:47:10 +00:00
do
{
2016-05-09 18:03:47 +00:00
if ( newstate = = nullptr )
2016-03-01 15:47:10 +00:00
{ // Object removed itself.
2016-05-09 18:03:47 +00:00
Destroy ( ) ;
return ;
2016-03-01 15:47:10 +00:00
}
2016-11-14 23:18:57 +00:00
if ( ! ( newstate - > UseFlags & ( SUF_OVERLAY | SUF_WEAPON ) ) ) // Weapon and overlay are mostly the same, the main difference is that weapon states restrict the self pointer to class Actor.
{
auto so = FState : : StaticFindStateOwner ( newstate ) ;
2016-11-15 10:21:08 +00:00
Printf ( TEXTCOLOR_RED " State %s.%d not flagged for use in overlays or weapons \n " , so - > TypeName . GetChars ( ) , int ( newstate - so - > OwnedStates ) ) ;
2016-11-14 23:18:57 +00:00
State = nullptr ;
Destroy ( ) ;
return ;
}
2016-11-15 10:21:08 +00:00
else if ( ! ( newstate - > UseFlags & SUF_WEAPON ) )
{
if ( Caller - > IsKindOf ( RUNTIME_CLASS ( AWeapon ) ) )
{
auto so = FState : : StaticFindStateOwner ( newstate ) ;
Printf ( TEXTCOLOR_RED " State %s.%d not flagged for use in weapons \n " , so - > TypeName . GetChars ( ) , int ( newstate - so - > OwnedStates ) ) ;
State = nullptr ;
Destroy ( ) ;
return ;
}
}
2016-11-14 23:18:57 +00:00
2016-05-09 18:03:47 +00:00
State = newstate ;
2016-03-01 15:47:10 +00:00
2016-05-09 18:03:47 +00:00
if ( newstate - > sprite ! = SPR_FIXED )
2016-03-01 15:47:10 +00:00
{ // okay to change sprite and/or frame
2016-05-09 18:03:47 +00:00
if ( ! newstate - > GetSameFrame ( ) )
2016-03-01 15:47:10 +00:00
{ // okay to change frame
2016-05-09 18:03:47 +00:00
Frame = newstate - > GetFrame ( ) ;
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
if ( newstate - > sprite ! = SPR_NOCHANGE )
2016-03-01 15:47:10 +00:00
{ // okay to change sprite
2016-05-09 18:03:47 +00:00
Sprite = newstate - > sprite ;
2016-03-01 15:47:10 +00:00
}
}
2016-05-09 18:03:47 +00:00
Tics = newstate - > GetTics ( ) ; // could be 0
2016-03-01 15:47:10 +00:00
2016-06-02 21:58:21 +00:00
if ( Flags & PSPF_CVARFAST )
2016-06-01 21:20:18 +00:00
{
2016-05-27 16:08:56 +00:00
if ( sv_fastweapons = = 2 & & ID = = PSP_WEAPON )
2016-05-09 18:03:47 +00:00
Tics = newstate - > ActionFunc = = nullptr ? 0 : 1 ;
else if ( sv_fastweapons = = 3 )
Tics = ( newstate - > GetTics ( ) ! = 0 ) ;
else if ( sv_fastweapons )
Tics = 1 ; // great for producing decals :)
}
2016-03-01 15:47:10 +00:00
2016-05-27 16:08:56 +00:00
if ( ID ! = PSP_FLASH )
2016-05-26 19:51:52 +00:00
{ // It's still possible to set the flash layer's offsets with the action function.
if ( newstate - > GetMisc1 ( ) )
{ // Set coordinates.
x = newstate - > GetMisc1 ( ) ;
}
if ( newstate - > GetMisc2 ( ) )
{
y = newstate - > GetMisc2 ( ) ;
}
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
if ( Owner - > mo ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
FState * nextstate ;
2016-06-16 14:11:00 +00:00
FStateParamInfo stp = { newstate , STATE_Psprite , ID } ;
2016-11-13 11:02:41 +00:00
if ( newstate - > ActionFunc ! = nullptr & & newstate - > ActionFunc - > Unsafe )
{
// If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash.
auto owner = FState : : StaticFindStateOwner ( newstate ) ;
Printf ( TEXTCOLOR_RED " Unsafe state call in state %s.%d to %s which accesses user variables. The action function has been removed from this state \n " ,
2016-11-26 11:45:17 +00:00
owner - > TypeName . GetChars ( ) , int ( newstate - owner - > OwnedStates ) , newstate - > ActionFunc - > PrintableName . GetChars ( ) ) ;
2016-11-13 11:02:41 +00:00
newstate - > ActionFunc = nullptr ;
}
2016-06-16 14:11:00 +00:00
if ( newstate - > CallAction ( Owner - > mo , Caller , & stp , & nextstate ) )
2016-03-01 15:47:10 +00:00
{
2016-05-11 21:13:02 +00:00
// It's possible this call resulted in this very layer being replaced.
if ( ObjectFlags & OF_EuthanizeMe )
{
return ;
}
2016-05-09 18:03:47 +00:00
if ( nextstate ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
newstate = nextstate ;
Tics = 0 ;
2016-03-01 15:47:10 +00:00
continue ;
}
2016-05-09 18:03:47 +00:00
if ( State = = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
Destroy ( ) ;
return ;
2016-03-01 15:47:10 +00:00
}
}
}
2016-05-09 18:03:47 +00:00
newstate = State - > GetNextState ( ) ;
} while ( ! Tics ) ; // An initial state of 0 could cycle through.
return ;
2016-03-01 15:47:10 +00:00
}
2016-11-28 13:39:25 +00:00
DEFINE_ACTION_FUNCTION ( DPSprite , SetState )
{
PARAM_SELF_PROLOGUE ( DPSprite ) ;
PARAM_POINTER ( state , FState ) ;
PARAM_BOOL_DEF ( pending ) ;
self - > SetState ( state , pending ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC P_BringUpWeapon
//
// Starts bringing the pending weapon up from the bottom of the screen.
// This is only called to start the rising, not throughout it.
//
//---------------------------------------------------------------------------
void P_BringUpWeapon ( player_t * player )
{
AWeapon * weapon ;
if ( player - > PendingWeapon = = WP_NOCHANGE )
{
2016-05-09 18:03:47 +00:00
if ( player - > ReadyWeapon ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-05-30 13:37:02 +00:00
player - > GetPSprite ( PSP_WEAPON ) - > y = WEAPONTOP ;
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_WEAPON , player - > ReadyWeapon - > GetReadyState ( ) ) ;
2016-03-01 15:47:10 +00:00
}
return ;
}
weapon = player - > PendingWeapon ;
// If the player has a tome of power, use this weapon's powered up
// version, if one is available.
2016-05-09 18:03:47 +00:00
if ( weapon ! = nullptr & &
2016-03-01 15:47:10 +00:00
weapon - > SisterWeapon & &
weapon - > SisterWeapon - > WeaponFlags & WIF_POWERED_UP & &
player - > mo - > FindInventory ( RUNTIME_CLASS ( APowerWeaponLevel2 ) , true ) )
{
weapon = weapon - > SisterWeapon ;
}
2016-05-30 13:37:02 +00:00
player - > PendingWeapon = WP_NOCHANGE ;
player - > ReadyWeapon = weapon ;
player - > mo - > weaponspecial = 0 ;
2016-05-09 18:03:47 +00:00
if ( weapon ! = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( weapon - > UpSound )
{
S_Sound ( player - > mo , CHAN_WEAPON , weapon - > UpSound , 1 , ATTN_NORM ) ;
}
player - > refire = 0 ;
2016-05-30 13:37:02 +00:00
player - > GetPSprite ( PSP_WEAPON ) - > y = player - > cheats & CF_INSTANTWEAPSWITCH
? WEAPONTOP : WEAPONBOTTOM ;
// make sure that the previous weapon's flash state is terminated.
// When coming here from a weapon drop it may still be active.
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_FLASH , nullptr ) ;
P_SetPsprite ( player , PSP_WEAPON , weapon - > GetUpState ( ) ) ;
2016-03-01 15:47:10 +00:00
}
}
//---------------------------------------------------------------------------
//
// PROC P_FireWeapon
//
//---------------------------------------------------------------------------
void P_FireWeapon ( player_t * player , FState * state )
{
AWeapon * weapon ;
// [SO] 9/2/02: People were able to do an awful lot of damage
// when they were observers...
2016-05-09 18:03:47 +00:00
if ( player - > Bot = = nullptr & & bot_observer )
2016-03-01 15:47:10 +00:00
{
return ;
}
weapon = player - > ReadyWeapon ;
2016-05-09 18:03:47 +00:00
if ( weapon = = nullptr | | ! weapon - > CheckAmmo ( AWeapon : : PrimaryFire , true ) )
2016-03-01 15:47:10 +00:00
{
return ;
}
player - > mo - > PlayAttacking ( ) ;
weapon - > bAltFire = false ;
2016-05-09 18:03:47 +00:00
if ( state = = nullptr )
2016-03-01 15:47:10 +00:00
{
state = weapon - > GetAtkState ( ! ! player - > refire ) ;
}
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_WEAPON , state ) ;
2016-03-01 15:47:10 +00:00
if ( ! ( weapon - > WeaponFlags & WIF_NOALERT ) )
{
P_NoiseAlert ( player - > mo , player - > mo , false ) ;
}
}
//---------------------------------------------------------------------------
//
// PROC P_FireWeaponAlt
//
//---------------------------------------------------------------------------
void P_FireWeaponAlt ( player_t * player , FState * state )
{
AWeapon * weapon ;
// [SO] 9/2/02: People were able to do an awful lot of damage
// when they were observers...
2016-05-09 18:03:47 +00:00
if ( player - > Bot = = nullptr & & bot_observer )
2016-03-01 15:47:10 +00:00
{
return ;
}
weapon = player - > ReadyWeapon ;
2016-05-09 18:03:47 +00:00
if ( weapon = = nullptr | | weapon - > FindState ( NAME_AltFire ) = = nullptr | | ! weapon - > CheckAmmo ( AWeapon : : AltFire , true ) )
2016-03-01 15:47:10 +00:00
{
return ;
}
player - > mo - > PlayAttacking ( ) ;
weapon - > bAltFire = true ;
2016-05-09 18:03:47 +00:00
if ( state = = nullptr )
2016-03-01 15:47:10 +00:00
{
state = weapon - > GetAltAtkState ( ! ! player - > refire ) ;
}
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_WEAPON , state ) ;
2016-03-01 15:47:10 +00:00
if ( ! ( weapon - > WeaponFlags & WIF_NOALERT ) )
{
P_NoiseAlert ( player - > mo , player - > mo , false ) ;
}
}
//---------------------------------------------------------------------------
//
// PROC P_DropWeapon
//
// The player died, so put the weapon away.
//
//---------------------------------------------------------------------------
void P_DropWeapon ( player_t * player )
{
2016-05-09 18:03:47 +00:00
if ( player = = nullptr )
2016-03-01 15:47:10 +00:00
{
return ;
}
// Since the weapon is dropping, stop blocking switching.
player - > WeaponState & = ~ WF_DISABLESWITCH ;
2016-07-22 14:37:32 +00:00
if ( ( player - > ReadyWeapon ! = nullptr ) & & ( player - > health > 0 | | ! ( player - > ReadyWeapon - > WeaponFlags & WIF_NODEATHDESELECT ) ) )
2016-03-01 15:47:10 +00:00
{
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_WEAPON , player - > ReadyWeapon - > GetDownState ( ) ) ;
2016-03-01 15:47:10 +00:00
}
}
//============================================================================
//
// P_BobWeapon
//
// [RH] Moved this out of A_WeaponReady so that the weapon can bob every
// tic and not just when A_WeaponReady is called. Not all weapons execute
// A_WeaponReady every tic, and it looks bad if they don't bob smoothly.
//
// [XA] Added new bob styles and exposed bob properties. Thanks, Ryan Cordell!
2016-09-16 07:01:52 +00:00
// [SP] Added new user option for bob speed
2016-03-01 15:47:10 +00:00
//
//============================================================================
2016-05-09 18:03:47 +00:00
void P_BobWeapon ( player_t * player , float * x , float * y , double ticfrac )
2016-03-01 15:47:10 +00:00
{
2016-03-23 19:45:48 +00:00
static float curbob ;
2016-04-07 09:48:23 +00:00
double xx [ 2 ] , yy [ 2 ] ;
2016-03-01 15:47:10 +00:00
AWeapon * weapon ;
2016-03-23 19:45:48 +00:00
float bobtarget ;
2016-03-01 15:47:10 +00:00
weapon = player - > ReadyWeapon ;
2016-05-09 18:03:47 +00:00
if ( weapon = = nullptr | | weapon - > WeaponFlags & WIF_DONTBOB )
2016-03-01 15:47:10 +00:00
{
* x = * y = 0 ;
return ;
}
// [XA] Get the current weapon's bob properties.
int bobstyle = weapon - > BobStyle ;
2016-03-23 19:45:48 +00:00
float BobSpeed = ( weapon - > BobSpeed * 128 ) ;
float Rangex = weapon - > BobRangeX ;
float Rangey = weapon - > BobRangeY ;
2016-03-01 15:47:10 +00:00
2016-04-07 09:48:23 +00:00
for ( int i = 0 ; i < 2 ; i + + )
2016-03-01 15:47:10 +00:00
{
2016-09-16 07:48:09 +00:00
// Bob the weapon based on movement speed. ([SP] And user's bob speed setting)
FAngle angle = ( BobSpeed * player - > userinfo . GetWBobSpeed ( ) * 35 /
TICRATE * ( level . time - 1 + i ) ) * ( 360.f / 8192.f ) ;
2016-04-07 09:48:23 +00:00
// [RH] Smooth transitions between bobbing and not-bobbing frames.
// This also fixes the bug where you can "stick" a weapon off-center by
// shooting it when it's at the peak of its swing.
bobtarget = float ( ( player - > WeaponState & WF_WEAPONBOBBING ) ? player - > bob : 0. ) ;
if ( curbob ! = bobtarget )
2016-03-01 15:47:10 +00:00
{
2016-04-07 09:48:23 +00:00
if ( fabsf ( bobtarget - curbob ) < = 1 )
2016-03-01 15:47:10 +00:00
{
2016-04-07 09:48:23 +00:00
curbob = bobtarget ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-04-07 09:48:23 +00:00
float zoom = MAX ( 1.f , fabsf ( curbob - bobtarget ) / 40 ) ;
if ( curbob > bobtarget )
{
curbob - = zoom ;
}
else
{
curbob + = zoom ;
}
2016-03-01 15:47:10 +00:00
}
}
2016-04-07 09:48:23 +00:00
if ( curbob ! = 0 )
2016-03-01 15:47:10 +00:00
{
2016-09-26 11:24:37 +00:00
//[SP] Added in decorate player.viewbob checks
float bobx = float ( player - > bob * Rangex * ( float ) player - > mo - > ViewBob ) ;
float boby = float ( player - > bob * Rangey * ( float ) player - > mo - > ViewBob ) ;
2016-04-07 09:48:23 +00:00
switch ( bobstyle )
{
case AWeapon : : BobNormal :
xx [ i ] = bobx * angle . Cos ( ) ;
yy [ i ] = boby * fabsf ( angle . Sin ( ) ) ;
break ;
case AWeapon : : BobInverse :
xx [ i ] = bobx * angle . Cos ( ) ;
yy [ i ] = boby * ( 1.f - fabsf ( angle . Sin ( ) ) ) ;
break ;
case AWeapon : : BobAlpha :
xx [ i ] = bobx * angle . Sin ( ) ;
yy [ i ] = boby * fabsf ( angle . Sin ( ) ) ;
break ;
case AWeapon : : BobInverseAlpha :
xx [ i ] = bobx * angle . Sin ( ) ;
yy [ i ] = boby * ( 1.f - fabsf ( angle . Sin ( ) ) ) ;
break ;
case AWeapon : : BobSmooth :
xx [ i ] = bobx * angle . Cos ( ) ;
yy [ i ] = 0.5f * ( boby * ( 1.f - ( ( angle * 2 ) . Cos ( ) ) ) ) ;
break ;
case AWeapon : : BobInverseSmooth :
xx [ i ] = bobx * angle . Cos ( ) ;
yy [ i ] = 0.5f * ( boby * ( 1.f + ( ( angle * 2 ) . Cos ( ) ) ) ) ;
}
}
else
{
xx [ i ] = 0 ;
yy [ i ] = 0 ;
2016-03-01 15:47:10 +00:00
}
}
2016-04-07 09:48:23 +00:00
* x = ( float ) ( xx [ 0 ] * ( 1. - ticfrac ) + xx [ 1 ] * ticfrac ) ;
* y = ( float ) ( yy [ 0 ] * ( 1. - ticfrac ) + yy [ 1 ] * ticfrac ) ;
2016-03-01 15:47:10 +00:00
}
//============================================================================
//
// PROC A_WeaponReady
//
// Readies a weapon for firing or bobbing with its three ancillary functions,
// DoReadyWeaponToSwitch(), DoReadyWeaponToFire() and DoReadyWeaponToBob().
// [XA] Added DoReadyWeaponToReload() and DoReadyWeaponToZoom()
//
//============================================================================
void DoReadyWeaponToSwitch ( AActor * self , bool switchable )
{
// Prepare for switching action.
player_t * player ;
if ( self & & ( player = self - > player ) )
{
if ( switchable )
{
player - > WeaponState | = WF_WEAPONSWITCHOK | WF_REFIRESWITCHOK ;
}
else
{
// WF_WEAPONSWITCHOK is automatically cleared every tic by P_SetPsprite().
player - > WeaponState & = ~ WF_REFIRESWITCHOK ;
}
}
}
void DoReadyWeaponDisableSwitch ( AActor * self , INTBOOL disable )
{
// Discard all switch attempts?
player_t * player ;
if ( self & & ( player = self - > player ) )
{
if ( disable )
{
player - > WeaponState | = WF_DISABLESWITCH ;
player - > WeaponState & = ~ WF_REFIRESWITCHOK ;
}
else
{
player - > WeaponState & = ~ WF_DISABLESWITCH ;
}
}
}
void DoReadyWeaponToFire ( AActor * self , bool prim , bool alt )
{
player_t * player ;
AWeapon * weapon ;
if ( ! self | | ! ( player = self - > player ) | | ! ( weapon = player - > ReadyWeapon ) )
{
return ;
}
// Change player from attack state
if ( self - > InStateSequence ( self - > state , self - > MissileState ) | |
self - > InStateSequence ( self - > state , self - > MeleeState ) )
{
static_cast < APlayerPawn * > ( self ) - > PlayIdle ( ) ;
}
// Play ready sound, if any.
2016-05-27 17:01:03 +00:00
if ( weapon - > ReadySound & & player - > GetPSprite ( PSP_WEAPON ) - > GetState ( ) = = weapon - > FindState ( NAME_Ready ) )
2016-03-01 15:47:10 +00:00
{
if ( ! ( weapon - > WeaponFlags & WIF_READYSNDHALF ) | | pr_wpnreadysnd ( ) < 128 )
{
S_Sound ( self , CHAN_WEAPON , weapon - > ReadySound , 1 , ATTN_NORM ) ;
}
}
// Prepare for firing action.
player - > WeaponState | = ( ( prim ? WF_WEAPONREADY : 0 ) | ( alt ? WF_WEAPONREADYALT : 0 ) ) ;
return ;
}
void DoReadyWeaponToBob ( AActor * self )
{
if ( self & & self - > player & & self - > player - > ReadyWeapon )
{
// Prepare for bobbing action.
self - > player - > WeaponState | = WF_WEAPONBOBBING ;
2016-05-27 17:01:03 +00:00
self - > player - > GetPSprite ( PSP_WEAPON ) - > x = 0 ;
self - > player - > GetPSprite ( PSP_WEAPON ) - > y = WEAPONTOP ;
2016-03-01 15:47:10 +00:00
}
}
void DoReadyWeaponToGeneric ( AActor * self , int paramflags )
{
int flags = 0 ;
for ( size_t i = 0 ; i < countof ( ButtonChecks ) ; + + i )
{
if ( paramflags & ButtonChecks [ i ] . ReadyFlag )
{
flags | = ButtonChecks [ i ] . StateFlag ;
}
}
if ( self ! = NULL & & self - > player ! = NULL )
{
self - > player - > WeaponState | = flags ;
}
}
// This function replaces calls to A_WeaponReady in other codepointers.
void DoReadyWeapon ( AActor * self )
{
DoReadyWeaponToBob ( self ) ;
DoReadyWeaponToFire ( self ) ;
DoReadyWeaponToSwitch ( self ) ;
DoReadyWeaponToGeneric ( self , ~ 0 ) ;
}
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_WeaponReady )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( flags ) ;
2016-03-01 15:47:10 +00:00
DoReadyWeaponToSwitch ( self , ! ( flags & WRF_NoSwitch ) ) ;
if ( ( flags & WRF_NoFire ) ! = WRF_NoFire ) DoReadyWeaponToFire ( self , ! ( flags & WRF_NoPrimary ) , ! ( flags & WRF_NoSecondary ) ) ;
if ( ! ( flags & WRF_NoBob ) ) DoReadyWeaponToBob ( self ) ;
DoReadyWeaponToGeneric ( self , flags ) ;
DoReadyWeaponDisableSwitch ( self , flags & WRF_DisableSwitch ) ;
return 0 ;
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponFire
//
// The player can fire the weapon.
// [RH] This was in A_WeaponReady before, but that only works well when the
// weapon's ready frames have a one tic delay.
//
//---------------------------------------------------------------------------
void P_CheckWeaponFire ( player_t * player )
{
AWeapon * weapon = player - > ReadyWeapon ;
if ( weapon = = NULL )
return ;
// Check for fire. Some weapons do not auto fire.
if ( ( player - > WeaponState & WF_WEAPONREADY ) & & ( player - > cmd . ucmd . buttons & BT_ATTACK ) )
{
if ( ! player - > attackdown | | ! ( weapon - > WeaponFlags & WIF_NOAUTOFIRE ) )
{
player - > attackdown = true ;
P_FireWeapon ( player , NULL ) ;
return ;
}
}
else if ( ( player - > WeaponState & WF_WEAPONREADYALT ) & & ( player - > cmd . ucmd . buttons & BT_ALTATTACK ) )
{
if ( ! player - > attackdown | | ! ( weapon - > WeaponFlags & WIF_NOAUTOFIRE ) )
{
player - > attackdown = true ;
P_FireWeaponAlt ( player , NULL ) ;
return ;
}
}
else
{
player - > attackdown = false ;
}
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponSwitch
//
// The player can change to another weapon at this time.
// [GZ] This was cut from P_CheckWeaponFire.
//
//---------------------------------------------------------------------------
void P_CheckWeaponSwitch ( player_t * player )
{
if ( player = = NULL )
{
return ;
}
if ( ( player - > WeaponState & WF_DISABLESWITCH ) | | // Weapon changing has been disabled.
player - > morphTics ! = 0 ) // Morphed classes cannot change weapons.
{ // ...so throw away any pending weapon requests.
player - > PendingWeapon = WP_NOCHANGE ;
}
// Put the weapon away if the player has a pending weapon or has died, and
// we're at a place in the state sequence where dropping the weapon is okay.
if ( ( player - > PendingWeapon ! = WP_NOCHANGE | | player - > health < = 0 ) & &
player - > WeaponState & WF_WEAPONSWITCHOK )
{
P_DropWeapon ( player ) ;
}
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponButtons
//
// Check extra button presses for weapons.
//
//---------------------------------------------------------------------------
static void P_CheckWeaponButtons ( player_t * player )
{
2016-05-09 18:03:47 +00:00
if ( player - > Bot = = nullptr & & bot_observer )
2016-03-01 15:47:10 +00:00
{
return ;
}
AWeapon * weapon = player - > ReadyWeapon ;
2016-05-09 18:03:47 +00:00
if ( weapon = = nullptr )
2016-03-01 15:47:10 +00:00
{
return ;
}
// The button checks are ordered by precedence. The first one to match a
// button press and affect a state change wins.
for ( size_t i = 0 ; i < countof ( ButtonChecks ) ; + + i )
{
if ( ( player - > WeaponState & ButtonChecks [ i ] . StateFlag ) & &
( player - > cmd . ucmd . buttons & ButtonChecks [ i ] . ButtonFlag ) )
{
FState * state = weapon - > GetStateForButtonName ( ButtonChecks [ i ] . StateName ) ;
// [XA] don't change state if still null, so if the modder
// sets WRF_xxx to true but forgets to define the corresponding
// state, the weapon won't disappear. ;)
2016-05-09 18:03:47 +00:00
if ( state ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_WEAPON , state ) ;
2016-03-01 15:47:10 +00:00
return ;
2016-05-09 18:03:47 +00:00
}
2016-03-01 15:47:10 +00:00
}
}
}
//---------------------------------------------------------------------------
//
// PROC A_ReFire
//
// The player can re-fire the weapon without lowering it entirely.
//
//---------------------------------------------------------------------------
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_ReFire )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-11-14 13:12:27 +00:00
PARAM_STATE_ACTION_DEF ( state ) ;
2016-03-01 15:47:10 +00:00
A_ReFire ( self , state ) ;
return 0 ;
}
void A_ReFire ( AActor * self , FState * state )
{
player_t * player = self - > player ;
bool pending ;
if ( NULL = = player )
{
return ;
}
pending = player - > PendingWeapon ! = WP_NOCHANGE & & ( player - > WeaponState & WF_REFIRESWITCHOK ) ;
if ( ( player - > cmd . ucmd . buttons & BT_ATTACK )
& & ! player - > ReadyWeapon - > bAltFire & & ! pending & & player - > health > 0 )
{
player - > refire + + ;
P_FireWeapon ( player , state ) ;
}
else if ( ( player - > cmd . ucmd . buttons & BT_ALTATTACK )
& & player - > ReadyWeapon - > bAltFire & & ! pending & & player - > health > 0 )
{
player - > refire + + ;
P_FireWeaponAlt ( player , state ) ;
}
else
{
player - > refire = 0 ;
player - > ReadyWeapon - > CheckAmmo ( player - > ReadyWeapon - > bAltFire
? AWeapon : : AltFire : AWeapon : : PrimaryFire , true ) ;
}
}
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_ClearReFire )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-03-01 15:47:10 +00:00
player_t * player = self - > player ;
if ( NULL ! = player )
{
player - > refire = 0 ;
}
return 0 ;
}
//---------------------------------------------------------------------------
//
// PROC A_CheckReload
//
// Present in Doom, but unused. Also present in Strife, and actually used.
// This and what I call A_XBowReFire are actually the same thing in Strife,
// not two separate functions as I have them here.
//
//---------------------------------------------------------------------------
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_CheckReload )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-03-01 15:47:10 +00:00
if ( self - > player ! = NULL )
{
self - > player - > ReadyWeapon - > CheckAmmo (
self - > player - > ReadyWeapon - > bAltFire ? AWeapon : : AltFire
: AWeapon : : PrimaryFire , true ) ;
}
return 0 ;
}
2016-05-17 20:44:03 +00:00
//---------------------------------------------------------------------------
//
2016-05-18 12:20:36 +00:00
// PROC A_OverlayOffset
2016-05-17 20:44:03 +00:00
//
//---------------------------------------------------------------------------
enum WOFFlags
{
WOF_KEEPX = 1 ,
WOF_KEEPY = 1 < < 1 ,
WOF_ADD = 1 < < 2 ,
} ;
2016-05-18 12:20:36 +00:00
void A_OverlayOffset ( AActor * self , int layer , double wx , double wy , int flags )
2016-05-17 20:44:03 +00:00
{
if ( ( flags & WOF_KEEPX ) & & ( flags & WOF_KEEPY ) )
{
2016-05-18 12:20:36 +00:00
return ;
2016-05-17 20:44:03 +00:00
}
player_t * player = self - > player ;
2016-05-09 18:03:47 +00:00
DPSprite * psp ;
2016-05-17 20:44:03 +00:00
if ( player & & ( player - > playerstate ! = PST_DEAD ) )
{
2016-05-18 12:20:36 +00:00
psp = player - > FindPSprite ( layer ) ;
if ( psp = = nullptr )
return ;
2016-05-17 20:44:03 +00:00
if ( ! ( flags & WOF_KEEPX ) )
{
if ( flags & WOF_ADD )
{
2016-05-09 18:03:47 +00:00
psp - > x + = wx ;
2016-05-17 20:44:03 +00:00
}
else
{
2016-05-09 18:03:47 +00:00
psp - > x = wx ;
2016-05-17 20:44:03 +00:00
}
}
if ( ! ( flags & WOF_KEEPY ) )
{
if ( flags & WOF_ADD )
{
2016-05-09 18:03:47 +00:00
psp - > y + = wy ;
2016-05-17 20:44:03 +00:00
}
else
{
2016-05-09 18:03:47 +00:00
psp - > y = wy ;
2016-05-17 20:44:03 +00:00
}
}
}
2016-05-18 12:20:36 +00:00
}
2016-06-03 17:18:58 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_OverlayOffset )
2016-05-18 12:20:36 +00:00
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( layer )
PARAM_FLOAT_DEF ( wx )
PARAM_FLOAT_DEF ( wy )
PARAM_INT_DEF ( flags )
2016-10-08 16:04:12 +00:00
A_OverlayOffset ( self , ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) , wx , wy , flags ) ;
2016-05-18 12:20:36 +00:00
return 0 ;
}
2016-06-03 17:18:58 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_WeaponOffset )
2016-05-18 12:20:36 +00:00
{
2016-10-22 15:49:08 +00:00
PARAM_SELF_PROLOGUE ( AActor ) ;
2016-10-27 22:32:52 +00:00
PARAM_FLOAT_DEF ( wx )
PARAM_FLOAT_DEF ( wy )
PARAM_INT_DEF ( flags )
2016-05-27 16:08:56 +00:00
A_OverlayOffset ( self , PSP_WEAPON , wx , wy , flags ) ;
2016-05-17 20:44:03 +00:00
return 0 ;
}
2016-05-26 19:51:52 +00:00
//---------------------------------------------------------------------------
//
// PROC A_OverlayFlags
//
//---------------------------------------------------------------------------
2016-06-03 17:18:58 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_OverlayFlags )
2016-05-26 19:51:52 +00:00
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-05-26 19:51:52 +00:00
PARAM_INT ( layer ) ;
PARAM_INT ( flags ) ;
PARAM_BOOL ( set ) ;
2016-10-08 16:04:12 +00:00
if ( ! ACTION_CALL_FROM_PSPRITE ( ) )
2016-05-26 19:51:52 +00:00
return 0 ;
2016-10-08 16:04:12 +00:00
DPSprite * pspr = self - > player - > FindPSprite ( ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) ) ;
2016-05-26 19:51:52 +00:00
if ( pspr = = nullptr )
return 0 ;
if ( set )
pspr - > Flags | = flags ;
else
pspr - > Flags & = ~ flags ;
return 0 ;
}
2016-10-08 16:04:12 +00:00
//---------------------------------------------------------------------------
//
// PROC OverlayX/Y
// Action function to return the X/Y of an overlay.
//---------------------------------------------------------------------------
static double GetOverlayPosition ( AActor * self , int layer , bool gety )
{
if ( layer )
{
DPSprite * pspr = self - > player - > FindPSprite ( layer ) ;
if ( pspr ! = nullptr )
{
return gety ? ( pspr - > y ) : ( pspr - > x ) ;
}
}
return 0. ;
}
DEFINE_ACTION_FUNCTION ( AActor , OverlayX )
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( layer ) ;
2016-10-08 16:04:12 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
double res = GetOverlayPosition ( self , ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) , false ) ;
ACTION_RETURN_FLOAT ( res ) ;
}
ACTION_RETURN_FLOAT ( 0. ) ;
}
DEFINE_ACTION_FUNCTION ( AActor , OverlayY )
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( layer ) ;
2016-10-08 16:04:12 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
double res = GetOverlayPosition ( self , ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) , true ) ;
ACTION_RETURN_FLOAT ( res ) ;
}
ACTION_RETURN_FLOAT ( 0. ) ;
}
2016-09-30 20:02:22 +00:00
//---------------------------------------------------------------------------
//
// PROC OverlayID
// Because non-action functions cannot acquire the ID of the overlay...
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION ( AActor , OverlayID )
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-09-30 20:02:22 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
ACTION_RETURN_INT ( stateinfo - > mPSPIndex ) ;
}
ACTION_RETURN_INT ( 0 ) ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// PROC A_Lower
//
//---------------------------------------------------------------------------
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_Lower )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-03-01 15:47:10 +00:00
player_t * player = self - > player ;
2016-05-09 18:03:47 +00:00
DPSprite * psp ;
2016-03-01 15:47:10 +00:00
2016-05-09 18:03:47 +00:00
if ( nullptr = = player )
2016-03-01 15:47:10 +00:00
{
return 0 ;
}
2016-06-01 21:00:04 +00:00
if ( nullptr = = player - > ReadyWeapon )
{
P_BringUpWeapon ( player ) ;
return 0 ;
}
2016-05-27 17:01:03 +00:00
psp = player - > GetPSprite ( PSP_WEAPON ) ;
2016-03-01 15:47:10 +00:00
if ( player - > morphTics | | player - > cheats & CF_INSTANTWEAPSWITCH )
{
2016-05-09 18:03:47 +00:00
psp - > y = WEAPONBOTTOM ;
2016-03-01 15:47:10 +00:00
}
else
{
2016-05-09 18:03:47 +00:00
psp - > y + = LOWERSPEED ;
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
if ( psp - > y < WEAPONBOTTOM )
2016-03-01 15:47:10 +00:00
{ // Not lowered all the way yet
return 0 ;
}
if ( player - > playerstate = = PST_DEAD )
{ // Player is dead, so don't bring up a pending weapon
// Player is dead, so keep the weapon off screen
2016-07-16 13:22:36 +00:00
P_SetPsprite ( player , PSP_FLASH , nullptr ) ;
2016-07-01 03:41:14 +00:00
psp - > SetState ( player - > ReadyWeapon - > FindState ( NAME_DeadLowered ) ) ;
2016-03-01 15:47:10 +00:00
return 0 ;
}
// [RH] Clear the flash state. Only needed for Strife.
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_FLASH , nullptr ) ;
2016-03-01 15:47:10 +00:00
P_BringUpWeapon ( player ) ;
return 0 ;
}
//---------------------------------------------------------------------------
//
// PROC A_Raise
//
//---------------------------------------------------------------------------
2016-12-02 17:52:58 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_Raise )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-03-01 15:47:10 +00:00
2016-05-09 18:03:47 +00:00
if ( self = = nullptr )
2016-03-01 15:47:10 +00:00
{
return 0 ;
}
player_t * player = self - > player ;
2016-05-09 18:03:47 +00:00
DPSprite * psp ;
2016-03-01 15:47:10 +00:00
2016-05-09 18:03:47 +00:00
if ( nullptr = = player )
2016-03-01 15:47:10 +00:00
{
return 0 ;
}
if ( player - > PendingWeapon ! = WP_NOCHANGE )
{
P_DropWeapon ( player ) ;
return 0 ;
}
2016-06-01 21:00:04 +00:00
if ( player - > ReadyWeapon = = nullptr )
{
return 0 ;
}
2016-05-27 17:01:03 +00:00
psp = player - > GetPSprite ( PSP_WEAPON ) ;
2016-05-09 18:03:47 +00:00
psp - > y - = RAISESPEED ;
if ( psp - > y > WEAPONTOP )
2016-03-01 15:47:10 +00:00
{ // Not raised all the way yet
return 0 ;
}
2016-05-09 18:03:47 +00:00
psp - > y = WEAPONTOP ;
2016-06-01 21:00:04 +00:00
psp - > SetState ( player - > ReadyWeapon - > GetReadyState ( ) ) ;
2016-03-01 15:47:10 +00:00
return 0 ;
}
2016-05-11 21:13:02 +00:00
//---------------------------------------------------------------------------
//
// PROC A_Overlay
//
//---------------------------------------------------------------------------
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_Overlay )
2016-05-11 21:13:02 +00:00
{
2016-10-22 15:49:08 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-05-11 21:13:02 +00:00
PARAM_INT ( layer ) ;
2016-11-14 13:12:27 +00:00
PARAM_STATE_ACTION_DEF ( state ) ;
2016-10-27 22:32:52 +00:00
PARAM_BOOL_DEF ( dontoverride ) ;
2016-05-11 21:13:02 +00:00
player_t * player = self - > player ;
2016-03-01 15:47:10 +00:00
2016-06-18 12:43:59 +00:00
if ( player = = nullptr | | ( dontoverride & & ( player - > FindPSprite ( layer ) ! = nullptr ) ) )
2016-06-17 20:33:01 +00:00
{
ACTION_RETURN_BOOL ( false ) ;
}
2016-06-18 12:43:59 +00:00
DPSprite * pspr ;
2016-06-03 17:18:58 +00:00
pspr = new DPSprite ( player , stateowner , layer ) ;
2016-05-11 21:13:02 +00:00
pspr - > SetState ( state ) ;
2016-06-17 20:33:01 +00:00
ACTION_RETURN_BOOL ( true ) ;
}
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_ClearOverlays )
2016-06-17 20:33:01 +00:00
{
2016-10-22 15:49:08 +00:00
PARAM_SELF_PROLOGUE ( AActor ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( start ) ;
PARAM_INT_DEF ( stop ) ;
PARAM_BOOL_DEF ( safety )
2016-06-17 20:33:01 +00:00
2016-07-16 14:07:31 +00:00
if ( self - > player = = nullptr )
2016-06-17 20:33:01 +00:00
ACTION_RETURN_INT ( 0 ) ;
2016-06-18 12:43:59 +00:00
2016-06-17 20:33:01 +00:00
if ( ! start & & ! stop )
{
2016-06-19 17:43:05 +00:00
start = INT_MIN ;
stop = safety ? PSP_TARGETCENTER - 1 : INT_MAX ;
2016-06-17 20:33:01 +00:00
}
2016-07-16 14:07:31 +00:00
unsigned int count = 0 ;
int id ;
for ( DPSprite * pspr = self - > player - > psprites ; pspr ! = nullptr ; pspr = pspr - > GetNext ( ) )
2016-06-17 20:33:01 +00:00
{
2016-07-16 14:07:31 +00:00
id = pspr - > GetID ( ) ;
2016-06-18 12:43:59 +00:00
2016-07-16 14:07:31 +00:00
if ( id < start | | id = = 0 )
2016-06-18 12:43:59 +00:00
continue ;
2016-07-16 14:07:31 +00:00
else if ( id > stop )
2016-06-18 12:49:15 +00:00
break ;
2016-06-18 12:43:59 +00:00
2016-06-17 20:33:01 +00:00
if ( safety )
{
2016-06-18 12:43:59 +00:00
if ( id > = PSP_TARGETCENTER )
2016-06-17 20:33:01 +00:00
break ;
2016-07-16 14:07:31 +00:00
else if ( id = = PSP_STRIFEHANDS | | id = = PSP_WEAPON | | id = = PSP_FLASH )
2016-06-17 20:33:01 +00:00
continue ;
}
2016-06-18 12:43:59 +00:00
pspr - > SetState ( nullptr ) ;
count + + ;
2016-06-17 20:33:01 +00:00
}
2016-07-16 14:07:31 +00:00
2016-06-17 20:33:01 +00:00
ACTION_RETURN_INT ( count ) ;
2016-05-11 21:13:02 +00:00
}
2016-03-01 15:47:10 +00:00
//
// A_GunFlash
//
enum GF_Flags
{
GFF_NOEXTCHANGE = 1 ,
} ;
2016-11-16 00:36:21 +00:00
DEFINE_ACTION_FUNCTION ( AStateProvider , A_GunFlash )
2016-03-01 15:47:10 +00:00
{
2016-12-02 17:52:58 +00:00
PARAM_ACTION_PROLOGUE ( AStateProvider ) ;
2016-11-14 13:12:27 +00:00
PARAM_STATE_ACTION_DEF ( flash ) ;
2016-10-27 22:32:52 +00:00
PARAM_INT_DEF ( flags ) ;
2016-03-01 15:47:10 +00:00
player_t * player = self - > player ;
2016-05-09 18:03:47 +00:00
if ( nullptr = = player )
2016-03-01 15:47:10 +00:00
{
return 0 ;
}
if ( ! ( flags & GFF_NOEXTCHANGE ) )
{
player - > mo - > PlayAttacking2 ( ) ;
}
2016-05-09 18:03:47 +00:00
if ( flash = = nullptr )
2016-03-01 15:47:10 +00:00
{
if ( player - > ReadyWeapon - > bAltFire )
{
flash = player - > ReadyWeapon - > FindState ( NAME_AltFlash ) ;
}
2016-05-09 18:03:47 +00:00
if ( flash = = nullptr )
2016-03-01 15:47:10 +00:00
{
flash = player - > ReadyWeapon - > FindState ( NAME_Flash ) ;
}
}
2016-06-16 12:24:00 +00:00
P_SetPsprite ( player , PSP_FLASH , flash ) ;
2016-03-01 15:47:10 +00:00
return 0 ;
}
//
// WEAPON ATTACKS
//
//
// P_BulletSlope
// Sets a slope so a near miss is at aproximately
// the height of the intended target
//
2016-03-17 10:38:56 +00:00
DAngle P_BulletSlope ( AActor * mo , FTranslatedLineTarget * pLineTarget , int aimflags )
2016-03-01 15:47:10 +00:00
{
2016-03-17 10:38:56 +00:00
static const double angdiff [ 3 ] = { - 5.625f , 5.625f , 0 } ;
2016-03-01 15:47:10 +00:00
int i ;
2016-03-17 10:38:56 +00:00
DAngle an ;
DAngle pitch ;
2016-03-01 15:47:10 +00:00
FTranslatedLineTarget scratch ;
if ( pLineTarget = = NULL ) pLineTarget = & scratch ;
// see which target is to be aimed at
i = 2 ;
do
{
2016-03-17 10:38:56 +00:00
an = mo - > Angles . Yaw + angdiff [ i ] ;
pitch = P_AimLineAttack ( mo , an , 16. * 64 , pLineTarget , 0. , aimflags ) ;
2016-03-01 15:47:10 +00:00
if ( mo - > player ! = NULL & &
level . IsFreelookAllowed ( ) & &
2016-03-17 10:38:56 +00:00
mo - > player - > userinfo . GetAimDist ( ) < = 0.5 )
2016-03-01 15:47:10 +00:00
{
break ;
}
} while ( pLineTarget - > linetarget = = NULL & & - - i > = 0 ) ;
return pitch ;
}
2016-11-19 12:56:29 +00:00
DEFINE_ACTION_FUNCTION ( AActor , BulletSlope )
{
PARAM_SELF_PROLOGUE ( AActor ) ;
PARAM_POINTER_DEF ( t , FTranslatedLineTarget ) ;
PARAM_INT_DEF ( aimflags ) ;
ACTION_RETURN_FLOAT ( P_BulletSlope ( self , t , aimflags ) . Degrees ) ;
}
2016-11-14 13:12:27 +00:00
AActor * P_AimTarget ( AActor * mo )
{
FTranslatedLineTarget t ;
P_BulletSlope ( mo , & t , ALF_PORTALRESTRICT ) ;
return t . linetarget ;
}
DEFINE_ACTION_FUNCTION ( AActor , AimTarget )
{
PARAM_SELF_PROLOGUE ( AActor ) ;
ACTION_RETURN_OBJECT ( P_AimTarget ( self ) ) ;
}
2016-03-01 15:47:10 +00:00
//------------------------------------------------------------------------
//
// PROC P_SetupPsprites
//
// Called at start of level for each player
//
//------------------------------------------------------------------------
void P_SetupPsprites ( player_t * player , bool startweaponup )
{
// Remove all psprites
2016-05-09 18:03:47 +00:00
player - > DestroyPSprites ( ) ;
2016-03-01 15:47:10 +00:00
// Spawn the ready weapon
player - > PendingWeapon = ! startweaponup ? player - > ReadyWeapon : WP_NOCHANGE ;
P_BringUpWeapon ( player ) ;
}
//------------------------------------------------------------------------
//
// PROC P_MovePsprites
//
// Called every tic by player thinking routine
//
//------------------------------------------------------------------------
2016-05-09 18:03:47 +00:00
void player_t : : TickPSprites ( )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
DPSprite * pspr = psprites ;
while ( pspr )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
// Destroy the psprite if it's from a weapon that isn't currently selected by the player
// or if it's from an inventory item that the player no longer owns.
2016-05-30 13:09:03 +00:00
if ( ( pspr - > Caller = = nullptr | |
2016-06-03 17:18:58 +00:00
( pspr - > Caller - > IsKindOf ( RUNTIME_CLASS ( AInventory ) ) & & barrier_cast < AInventory * > ( pspr - > Caller ) - > Owner ! = pspr - > Owner - > mo ) | |
2016-05-30 13:09:03 +00:00
( pspr - > Caller - > IsKindOf ( RUNTIME_CLASS ( AWeapon ) ) & & pspr - > Caller ! = pspr - > Owner - > ReadyWeapon ) ) )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
pspr - > Destroy ( ) ;
2016-03-01 15:47:10 +00:00
}
2016-05-30 13:09:03 +00:00
else
2016-05-09 18:03:47 +00:00
{
pspr - > Tick ( ) ;
}
pspr = pspr - > Next ;
}
2016-07-01 21:43:30 +00:00
if ( ( health > 0 ) | | ( ReadyWeapon ! = nullptr & & ! ( ReadyWeapon - > WeaponFlags & WIF_NODEATHINPUT ) ) )
2016-05-09 18:03:47 +00:00
{
2016-07-01 21:43:30 +00:00
if ( ReadyWeapon = = nullptr )
{
if ( PendingWeapon ! = WP_NOCHANGE )
P_BringUpWeapon ( this ) ;
}
else
2016-03-01 15:47:10 +00:00
{
2016-07-01 21:43:30 +00:00
P_CheckWeaponSwitch ( this ) ;
if ( WeaponState & ( WF_WEAPONREADY | WF_WEAPONREADYALT ) )
{
P_CheckWeaponFire ( this ) ;
}
// Check custom buttons
P_CheckWeaponButtons ( this ) ;
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
}
}
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
void DPSprite : : Tick ( )
{
if ( processPending )
{
// drop tic count and possibly change state
if ( Tics ! = - 1 ) // a -1 tic count never changes
{
Tics - - ;
// [BC] Apply double firing speed.
2016-06-02 21:58:21 +00:00
if ( ( Flags & PSPF_POWDOUBLE ) & & Tics & & ( Owner - > cheats & CF_DOUBLEFIRINGSPEED ) )
2016-05-09 18:03:47 +00:00
Tics - - ;
if ( ! Tics )
SetState ( State - > GetNextState ( ) ) ;
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
}
}
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2016-09-20 08:27:53 +00:00
void DPSprite : : Serialize ( FSerializer & arc )
2016-05-09 18:03:47 +00:00
{
Super : : Serialize ( arc ) ;
2016-09-20 08:27:53 +00:00
arc ( " next " , Next )
( " caller " , Caller )
( " owner " , Owner )
( " flags " , Flags )
( " state " , State )
( " tics " , Tics )
. Sprite ( " sprite " , Sprite , nullptr )
( " frame " , Frame )
( " id " , ID )
( " x " , x )
( " y " , y )
( " oldx " , oldx )
( " oldy " , oldy ) ;
2016-05-09 18:03:47 +00:00
}
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
void player_t : : DestroyPSprites ( )
{
DPSprite * pspr = psprites ;
2016-05-21 11:11:43 +00:00
psprites = nullptr ;
2016-05-09 18:03:47 +00:00
while ( pspr )
{
2016-05-21 11:11:43 +00:00
DPSprite * next = pspr - > Next ;
pspr - > Next = nullptr ;
2016-05-09 18:03:47 +00:00
pspr - > Destroy ( ) ;
2016-05-21 11:11:43 +00:00
pspr = next ;
2016-05-09 18:03:47 +00:00
}
}
2016-11-19 15:39:45 +00:00
//------------------------------------------------------------------------------------
//
// Setting a random flash like some of Doom's weapons can easily crash when the
// definition is overridden incorrectly so let's check that the state actually exists.
// Be aware though that this will not catch all DEHACKED related problems. But it will
// find all DECORATE related ones.
//
//------------------------------------------------------------------------------------
void P_SetSafeFlash ( AWeapon * weapon , player_t * player , FState * flashstate , int index )
{
2016-12-02 11:06:49 +00:00
if ( flashstate ! = nullptr )
2016-11-19 15:39:45 +00:00
{
2016-12-02 11:06:49 +00:00
PClassActor * cls = weapon - > GetClass ( ) ;
while ( cls ! = RUNTIME_CLASS ( AWeapon ) )
2016-11-19 15:39:45 +00:00
{
2016-12-02 11:06:49 +00:00
if ( flashstate > = cls - > OwnedStates & & flashstate < cls - > OwnedStates + cls - > NumOwnedStates )
2016-11-19 15:39:45 +00:00
{
2016-12-02 11:06:49 +00:00
// The flash state belongs to this class.
// Now let's check if the actually wanted state does also
if ( flashstate + index < cls - > OwnedStates + cls - > NumOwnedStates )
{
// we're ok so set the state
P_SetPsprite ( player , PSP_FLASH , flashstate + index , true ) ;
return ;
}
else
{
// oh, no! The state is beyond the end of the state table so use the original flash state.
P_SetPsprite ( player , PSP_FLASH , flashstate , true ) ;
return ;
}
2016-11-19 15:39:45 +00:00
}
2016-12-02 11:06:49 +00:00
// try again with parent class
cls = static_cast < PClassActor * > ( cls - > ParentClass ) ;
}
// if we get here the state doesn't seem to belong to any class in the inheritance chain
// This can happen with Dehacked if the flash states are remapped.
// The only way to check this would be to go through all Dehacked modifiable actors, convert
// their states into a single flat array and find the correct one.
// Rather than that, just check to make sure it belongs to something.
if ( FState : : StaticFindStateOwner ( flashstate + index ) = = NULL )
{ // Invalid state. With no index offset, it should at least be valid.
index = 0 ;
2016-11-19 15:39:45 +00:00
}
}
P_SetPsprite ( player , PSP_FLASH , flashstate + index , true ) ;
}
2016-11-22 18:20:31 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , SetSafeFlash )
2016-11-19 15:39:45 +00:00
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
2016-12-02 11:06:49 +00:00
PARAM_OBJECT_NOT_NULL ( weapon , AWeapon ) ;
2016-11-19 15:39:45 +00:00
PARAM_POINTER ( state , FState ) ;
PARAM_INT ( index ) ;
P_SetSafeFlash ( weapon , self , state , index ) ;
return 0 ;
}
2016-05-09 18:03:47 +00:00
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
void DPSprite : : Destroy ( )
{
2016-05-21 11:11:43 +00:00
// Do not crash if this gets called on partially initialized objects.
if ( Owner ! = nullptr & & Owner - > psprites ! = nullptr )
{
if ( Owner - > psprites ! = this )
{
DPSprite * prev = Owner - > psprites ;
while ( prev ! = nullptr & & prev - > Next ! = this )
prev = prev - > Next ;
2016-05-09 18:03:47 +00:00
2016-05-21 11:11:43 +00:00
if ( prev ! = nullptr & & prev - > Next = = this )
{
prev - > Next = Next ;
GC : : WriteBarrier ( prev , Next ) ;
}
}
else
{
Owner - > psprites = Next ;
GC : : WriteBarrier ( Next ) ;
}
}
2016-05-09 18:03:47 +00:00
Super : : Destroy ( ) ;
2016-03-01 15:47:10 +00:00
}
2016-05-09 18:03:47 +00:00
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
ADD_STAT ( psprites )
2016-03-01 15:47:10 +00:00
{
2016-05-09 18:03:47 +00:00
FString out ;
DPSprite * pspr ;
for ( int i = 0 ; i < MAXPLAYERS ; i + + )
{
if ( ! playeringame [ i ] )
continue ;
out . AppendFormat ( " [psprites] player: %d | layers: " , i ) ;
pspr = players [ i ] . psprites ;
while ( pspr )
{
out . AppendFormat ( " %d, " , pspr - > GetID ( ) ) ;
pspr = pspr - > GetNext ( ) ;
}
out . AppendFormat ( " \n " ) ;
}
return out ;
2016-03-01 15:47:10 +00:00
}