2017-04-17 11:33:19 +00:00
//-----------------------------------------------------------------------------
//
// Copyright 1993-1996 id Software
// Copyright 1994-1996 Raven Software
// Copyright 1998-1998 Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
// Copyright 2016 Leonard2
//
// 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 3 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, see http://www.gnu.org/licenses/
//
//-----------------------------------------------------------------------------
//
2016-03-01 15:47:10 +00:00
// 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"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
2016-03-01 15:47:10 +00:00
// MACROS ------------------------------------------------------------------
2016-03-21 00:16:34 +00:00
# define LOWERSPEED 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 )
2017-04-30 23:55:35 +00:00
DEFINE_FIELD ( DPSprite , Flags )
2016-11-22 22:42:32 +00:00
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 )
2016-12-26 20:37:22 +00:00
DEFINE_FIELD ( DPSprite , alpha )
2016-11-22 22:42:32 +00:00
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 )
2017-05-26 00:46:36 +00:00
DEFINE_FIELD_BIT ( DPSprite , Flags , bMirror , PSPF_MIRROR )
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 ) ,
2017-01-05 13:50:10 +00:00
Sprite ( 0 ) ,
2016-06-17 08:08:45 +00:00
ID ( id ) ,
2017-03-11 18:02:00 +00:00
processPending ( true )
2016-05-09 18:03:47 +00:00
{
2017-03-11 18:02:00 +00:00
alpha = 1 ;
2017-04-15 14:41:00 +00:00
Renderstyle = STYLE_Normal ;
2017-03-11 18:02:00 +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
2017-02-08 14:47:22 +00:00
if ( Caller - > IsKindOf ( NAME_Weapon ) | | 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 )
{
2017-01-18 21:57:47 +00:00
newcaller = mo - > FindInventory ( NAME_PowerTargeter , true ) ;
2016-06-01 21:20:18 +00:00
}
}
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
{
2017-04-14 11:31:58 +00:00
pspr = Create < 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 ) ) ;
}
2017-04-15 14:41:00 +00:00
std : : pair < FRenderStyle , float > DPSprite : : GetRenderStyle ( FRenderStyle ownerstyle , double owneralpha )
{
FRenderStyle returnstyle , mystyle ;
double returnalpha ;
ownerstyle . CheckFuzz ( ) ;
mystyle = Renderstyle ;
mystyle . CheckFuzz ( ) ;
if ( Flags & PSPF_RENDERSTYLE )
{
if ( Flags & PSPF_FORCESTYLE )
{
returnstyle = mystyle ;
}
else if ( ownerstyle . BlendOp ! = STYLEOP_Add )
{
// all styles that do more than simple blending need to be fully preserved.
returnstyle = ownerstyle ;
}
else
{
returnstyle = mystyle ;
if ( ownerstyle . DestAlpha = = STYLEALPHA_One )
{
// If the owner is additive and the overlay translucent, force additive result.
returnstyle . DestAlpha = STYLEALPHA_One ;
}
if ( ownerstyle . Flags & ( STYLEF_ColorIsFixed | STYLEF_RedIsAlpha ) )
{
// If the owner's style is a stencil type, this must be preserved.
returnstyle . Flags = ownerstyle . Flags ;
}
}
}
else
{
returnstyle = ownerstyle ;
}
if ( ( Flags & PSPF_FORCEALPHA ) & & returnstyle . BlendOp ! = STYLEOP_Fuzz & & returnstyle . BlendOp ! = STYLEOP_Shadow )
{
// ALWAYS take priority if asked for, except fuzz. Fuzz does absolutely nothing
// no matter what way it's changed.
returnalpha = alpha ;
returnstyle . Flags & = ~ ( STYLEF_Alpha1 | STYLEF_TransSoulsAlpha ) ;
}
else if ( Flags & PSPF_ALPHA )
{
// Set the alpha based on if using the overlay's own or not. Also adjust
// and override the alpha if not forced.
if ( returnstyle . BlendOp ! = STYLEOP_Add )
{
returnalpha = owneralpha ;
}
else
{
returnalpha = owneralpha * alpha ;
}
}
2017-05-03 08:26:25 +00:00
else
{
returnalpha = owneralpha ;
}
2017-04-15 14:41:00 +00:00
// Should normal renderstyle come out on top at the end and we desire alpha,
// switch it to translucent. Normal never applies any sort of alpha.
if ( returnstyle . BlendOp = = STYLEOP_Add & & returnstyle . SrcAlpha = = STYLEALPHA_One & & returnstyle . DestAlpha = = STYLEALPHA_Zero & & returnalpha < 1. )
{
returnstyle = LegacyRenderStyles [ STYLE_Translucent ] ;
returnalpha = owneralpha * alpha ;
}
2017-05-03 08:26:25 +00:00
return { returnstyle , clamp < float > ( float ( returnalpha ) , 0.f , 1.f ) } ;
2017-04-15 14:41:00 +00:00
}
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.
{
2017-04-13 07:17:11 +00:00
Printf ( TEXTCOLOR_RED " State %s not flagged for use in overlays or weapons \n " , FState : : StaticGetStateName ( newstate ) . GetChars ( ) ) ;
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 ) )
{
2017-02-08 14:47:22 +00:00
if ( Caller - > IsKindOf ( NAME_Weapon ) )
2016-11-15 10:21:08 +00:00
{
2017-04-13 07:25:52 +00:00
Printf ( TEXTCOLOR_RED " State %s not flagged for use in weapons \n " , FState : : StaticGetStateName ( newstate ) . GetChars ( ) ) ;
2016-11-15 10:21:08 +00:00
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.
2016-12-08 16:51:13 +00:00
// Anything going through here cannot be reliably interpolated so this has to reset the interpolation coordinates if it changes the values.
2016-05-26 19:51:52 +00:00
if ( newstate - > GetMisc1 ( ) )
{ // Set coordinates.
2016-12-08 16:51:13 +00:00
oldx = x = newstate - > GetMisc1 ( ) ;
2016-05-26 19:51:52 +00:00
}
if ( newstate - > GetMisc2 ( ) )
{
2016-12-08 16:51:13 +00:00
oldy = y = newstate - > GetMisc2 ( ) ;
2016-05-26 19:51:52 +00:00
}
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.
2017-04-11 19:48:41 +00:00
Printf ( TEXTCOLOR_RED " Unsafe state call in state %sd to %s which accesses user variables. The action function has been removed from this state \n " ,
2017-04-13 07:17:11 +00:00
FState : : StaticGetStateName ( newstate ) . GetChars ( ) , 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 & &
2017-01-15 22:21:38 +00:00
player - > mo - > FindInventory ( PClass : : FindActor ( NAME_PowerWeaponLevel2 ) , true ) )
2016-03-01 15:47:10 +00:00
{
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
}
}
2017-01-19 12:25:56 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , BringUpWeapon )
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
P_BringUpWeapon ( self ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//---------------------------------------------------------------------------
//
// 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
}
}
2017-01-19 12:25:56 +00:00
DEFINE_ACTION_FUNCTION ( _PlayerInfo , DropWeapon )
{
PARAM_SELF_STRUCT_PROLOGUE ( player_t ) ;
P_DropWeapon ( self ) ;
return 0 ;
}
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 ;
}
}
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_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
}
}
}
2017-04-30 23:55:35 +00:00
DEFINE_ACTION_FUNCTION ( APlayerPawn , CheckWeaponButtons )
2016-03-01 15:47:10 +00:00
{
2017-04-30 23:55:35 +00:00
PARAM_SELF_PROLOGUE ( APlayerPawn ) ;
P_CheckWeaponButtons ( self - > player ) ;
2016-03-01 15:47:10 +00:00
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-12-08 16:51:13 +00:00
WOF_INTERPOLATE = 1 < < 3 ,
2016-05-17 20:44:03 +00:00
} ;
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
2016-09-29 02:20:15 +00:00
if ( player )
2016-05-17 20:44:03 +00:00
{
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-12-08 16:51:13 +00:00
if ( ! ( flags & WOF_INTERPOLATE ) ) psp - > oldx = psp - > x ;
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-12-08 16:51:13 +00:00
if ( ! ( flags & WOF_INTERPOLATE ) ) psp - > oldy = psp - > y ;
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-12-26 20:37:22 +00:00
//---------------------------------------------------------------------------
//
// PROC A_OverlayAlpha
// Sets the alpha of an overlay.
//---------------------------------------------------------------------------
2016-09-29 02:20:15 +00:00
2016-12-26 20:37:22 +00:00
DEFINE_ACTION_FUNCTION ( AActor , A_OverlayAlpha )
{
PARAM_ACTION_PROLOGUE ( AActor ) ;
PARAM_INT ( layer ) ;
PARAM_FLOAT ( alph ) ;
2016-09-29 02:20:15 +00:00
2016-12-26 20:37:22 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
DPSprite * pspr = self - > player - > FindPSprite ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) ;
2016-09-30 20:02:22 +00:00
2016-12-26 20:37:22 +00:00
if ( pspr ! = nullptr )
pspr - > alpha = clamp < double > ( alph , 0.0 , 1.0 ) ;
}
2016-09-29 02:20:15 +00:00
return 0 ;
}
// NON-ACTION function to get the overlay alpha of a layer.
DEFINE_ACTION_FUNCTION ( AActor , OverlayAlpha )
{
2016-12-26 20:37:22 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
PARAM_INT_DEF ( layer ) ;
2016-09-29 02:20:15 +00:00
2016-12-26 20:37:22 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
DPSprite * pspr = self - > player - > FindPSprite ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) ;
2016-09-30 20:02:22 +00:00
2016-12-26 20:37:22 +00:00
if ( pspr ! = nullptr )
2016-09-29 02:20:15 +00:00
{
2016-12-26 20:37:22 +00:00
ACTION_RETURN_FLOAT ( pspr - > alpha ) ;
2016-09-29 02:20:15 +00:00
}
2016-09-30 20:02:22 +00:00
}
2016-12-26 20:37:22 +00:00
ACTION_RETURN_FLOAT ( 0.0 ) ;
2016-09-30 20:02:22 +00:00
}
2016-09-29 02:20:15 +00:00
//---------------------------------------------------------------------------
//
// PROC A_OverlayRenderStyle
//
//---------------------------------------------------------------------------
DEFINE_ACTION_FUNCTION ( AActor , A_OverlayRenderStyle )
{
2016-12-26 20:37:22 +00:00
PARAM_ACTION_PROLOGUE ( AActor ) ;
2016-09-29 02:20:15 +00:00
PARAM_INT ( layer ) ;
PARAM_INT ( style ) ;
2016-09-30 20:02:22 +00:00
2016-12-26 20:37:22 +00:00
if ( ACTION_CALL_FROM_PSPRITE ( ) )
{
DPSprite * pspr = self - > player - > FindPSprite ( ( layer ! = 0 ) ? layer : stateinfo - > mPSPIndex ) ;
2016-09-29 02:20:15 +00:00
2016-12-26 20:37:22 +00:00
if ( pspr = = nullptr | | style > = STYLE_Count | | style < 0 )
return 0 ;
2016-09-29 02:20:15 +00:00
2017-04-15 14:41:00 +00:00
pspr - > Renderstyle = ERenderStyle ( style ) ;
2016-12-26 20:37:22 +00:00
}
2016-09-29 02:20:15 +00:00
return 0 ;
}
2016-09-30 20:02:22 +00:00
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 ;
2017-04-14 11:31:58 +00:00
pspr = Create < 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
//
// 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-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 ) ;
}
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 )
2016-09-29 02:20:15 +00:00
( " oldy " , oldy )
2016-12-26 20:37:22 +00:00
( " alpha " , alpha )
2017-04-15 14:41:00 +00:00
( " renderstyle_ " , Renderstyle ) ; // The underscore is intentional to avoid problems with old savegames which had this as an ERenderStyle (which is not future proof.)
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
{
2017-04-11 19:48:41 +00:00
if ( cls - > OwnsState ( flashstate ) )
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
2017-04-11 19:48:41 +00:00
if ( cls - > OwnsState ( flashstate + index ) )
2016-12-02 11:06:49 +00:00
{
// 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
//------------------------------------------------------------------------
//
//
//
//------------------------------------------------------------------------
2017-01-12 21:49:18 +00:00
void DPSprite : : OnDestroy ( )
2016-05-09 18:03:47 +00:00
{
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 ) ;
}
}
2017-01-12 21:49:18 +00:00
Super : : OnDestroy ( ) ;
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
}