2020-04-22 18:56:21 +02:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
# include "cbase.h"
# include "cs_playeranimstate.h"
# include "base_playeranimstate.h"
# include "tier0/vprof.h"
# include "animation.h"
# include "weapon_csbase.h"
# include "studio.h"
# include "apparent_velocity_helper.h"
# include "utldict.h"
# include "weapon_basecsgrenade.h"
# include "datacache/imdlcache.h"
# ifdef CLIENT_DLL
# include "c_cs_player.h"
# include "bone_setup.h"
# include "interpolatedvar.h"
# include "c_cs_hostage.h"
# else
# include "cs_player.h"
# include "cs_simple_hostage.h"
# include "cs_gamestats.h"
# endif
# define ANIM_TOPSPEED_WALK 100
# define ANIM_TOPSPEED_RUN 250
# define ANIM_TOPSPEED_RUN_CROUCH 85
# define DEFAULT_IDLE_NAME "idle_upper_"
# define DEFAULT_CROUCH_IDLE_NAME "crouch_idle_upper_"
# define DEFAULT_CROUCH_WALK_NAME "crouch_walk_upper_"
# define DEFAULT_WALK_NAME "walk_upper_"
# define DEFAULT_RUN_NAME "run_upper_"
# define DEFAULT_FIRE_IDLE_NAME "idle_shoot_"
# define DEFAULT_FIRE_CROUCH_NAME "crouch_idle_shoot_"
# define DEFAULT_FIRE_CROUCH_WALK_NAME "crouch_walk_shoot_"
# define DEFAULT_FIRE_WALK_NAME "walk_shoot_"
# define DEFAULT_FIRE_RUN_NAME "run_shoot_"
# define FIRESEQUENCE_LAYER (AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS+1)
# define RELOADSEQUENCE_LAYER (FIRESEQUENCE_LAYER + 1)
# define GRENADESEQUENCE_LAYER (RELOADSEQUENCE_LAYER + 1)
# define NUM_LAYERS_WANTED (GRENADESEQUENCE_LAYER + 1)
// ------------------------------------------------------------------------------------------------ //
// CCSPlayerAnimState declaration.
// ------------------------------------------------------------------------------------------------ //
class CCSPlayerAnimState : public CBasePlayerAnimState , public ICSPlayerAnimState
{
public :
DECLARE_CLASS ( CCSPlayerAnimState , CBasePlayerAnimState ) ;
friend ICSPlayerAnimState * CreatePlayerAnimState ( CBaseAnimatingOverlay * pEntity , ICSPlayerAnimStateHelpers * pHelpers , LegAnimType_t legAnimType , bool bUseAimSequences ) ;
CCSPlayerAnimState ( ) ;
virtual void DoAnimationEvent ( PlayerAnimEvent_t event , int nData ) ;
virtual bool IsThrowingGrenade ( ) ;
virtual int CalcAimLayerSequence ( float * flCycle , float * flAimSequenceWeight , bool bForceIdle ) ;
virtual void ClearAnimationState ( ) ;
virtual bool CanThePlayerMove ( ) ;
virtual float GetCurrentMaxGroundSpeed ( ) ;
virtual Activity CalcMainActivity ( ) ;
virtual void DebugShowAnimState ( int iStartLine ) ;
virtual void ComputeSequences ( CStudioHdr * pStudioHdr ) ;
virtual void ClearAnimationLayers ( ) ;
virtual int SelectWeightedSequence ( Activity activity ) ;
void InitCS ( CBaseAnimatingOverlay * pPlayer , ICSPlayerAnimStateHelpers * pHelpers , LegAnimType_t legAnimType , bool bUseAimSequences ) ;
protected :
int CalcFireLayerSequence ( PlayerAnimEvent_t event ) ;
void ComputeFireSequence ( CStudioHdr * pStudioHdr ) ;
void ComputeReloadSequence ( CStudioHdr * pStudioHdr ) ;
int CalcReloadLayerSequence ( PlayerAnimEvent_t event ) ;
bool IsOuterGrenadePrimed ( ) ;
void ComputeGrenadeSequence ( CStudioHdr * pStudioHdr ) ;
int CalcGrenadePrimeSequence ( ) ;
int CalcGrenadeThrowSequence ( ) ;
int GetOuterGrenadeThrowCounter ( ) ;
const char * GetWeaponSuffix ( ) ;
bool HandleJumping ( ) ;
void UpdateLayerSequenceGeneric ( CStudioHdr * pStudioHdr , int iLayer , bool & bEnabled , float & flCurCycle , int & iSequence , bool bWaitAtEnd ) ;
virtual int CalcSequenceIndex ( const char * pBaseName , . . . ) ;
private :
// Current state variables.
bool m_bJumping ; // Set on a jump event.
float m_flJumpStartTime ;
bool m_bFirstJumpFrame ;
// Aim sequence plays reload while this is on.
bool m_bReloading ;
float m_flReloadCycle ;
int m_iReloadSequence ;
float m_flReloadHoldEndTime ; // Intermediate shotgun reloads get held a fraction of a second
// This is set to true if ANY animation is being played in the fire layer.
bool m_bFiring ; // If this is on, then it'll continue the fire animation in the fire layer
// until it completes.
int m_iFireSequence ; // (For any sequences in the fire layer, including grenade throw).
float m_flFireCycle ;
PlayerAnimEvent_t m_delayedFire ; // if we fire while reloading, delay the fire by one frame so we can cancel the reload first
// These control grenade animations.
bool m_bThrowingGrenade ;
bool m_bPrimingGrenade ;
float m_flGrenadeCycle ;
int m_iGrenadeSequence ;
int m_iLastThrowGrenadeCounter ; // used to detect when the guy threw the grenade.
CCSPlayer * m_pPlayer ;
ICSPlayerAnimStateHelpers * m_pHelpers ;
void CheckCachedSequenceValidity ( void ) ;
int m_sequenceCache [ ACT_CROUCHIDLE + 1 ] ; // Cache the first N sequences, since we don't have weights.
int m_cachedModelIndex ; // Model index for which the sequence cache is valid.
CUtlDict < int , int > m_namedSequence ; // Dictionary of sequences computed with CalcSequenceIndex. This is because LookupSequence is a performance hit - CS:S player models have 750+ sequences!
} ;
ICSPlayerAnimState * CreatePlayerAnimState ( CBaseAnimatingOverlay * pEntity , ICSPlayerAnimStateHelpers * pHelpers , LegAnimType_t legAnimType , bool bUseAimSequences )
{
CCSPlayerAnimState * pRet = new CCSPlayerAnimState ;
pRet - > InitCS ( pEntity , pHelpers , legAnimType , bUseAimSequences ) ;
return pRet ;
}
//----------------------------------------------------------------------------------------------
/**
* Hostage animation mechanism
*/
class CCSHostageAnimState : public CCSPlayerAnimState
{
public :
DECLARE_CLASS ( CCSHostageAnimState , CCSPlayerAnimState ) ;
CCSHostageAnimState ( ) ;
virtual Activity CalcMainActivity ( ) ;
// No need to cache sequences, and we *do* have multiple sequences per activity
virtual int SelectWeightedSequence ( Activity activity ) { return GetOuter ( ) - > SelectWeightedSequence ( activity ) ; }
} ;
//----------------------------------------------------------------------------------------------
ICSPlayerAnimState * CreateHostageAnimState ( CBaseAnimatingOverlay * pEntity , ICSPlayerAnimStateHelpers * pHelpers , LegAnimType_t legAnimType , bool bUseAimSequences )
{
CCSHostageAnimState * anim = new CCSHostageAnimState ;
anim - > InitCS ( pEntity , pHelpers , legAnimType , bUseAimSequences ) ;
return anim ;
}
//----------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------
CCSHostageAnimState : : CCSHostageAnimState ( )
{
}
//----------------------------------------------------------------------------------------------
/**
* Set hostage animation state
*/
Activity CCSHostageAnimState : : CalcMainActivity ( )
{
float flOuterSpeed = GetOuterXYSpeed ( ) ;
if ( HandleJumping ( ) )
{
return ACT_HOP ;
}
else
{
Assert ( dynamic_cast < CHostage * > ( m_pOuter ) ) ;
CHostage * me = ( CHostage * ) m_pOuter ;
// if we have no leader, hang out
Activity idealActivity = me - > GetLeader ( ) ? ACT_IDLE : ACT_BUSY_QUEUE ;
if ( m_pOuter - > GetFlags ( ) & FL_DUCKING )
{
if ( flOuterSpeed > MOVING_MINIMUM_SPEED )
idealActivity = ACT_RUN_CROUCH ;
else
idealActivity = ACT_COVER_LOW ;
}
else
{
if ( flOuterSpeed > MOVING_MINIMUM_SPEED )
{
if ( flOuterSpeed > ARBITRARY_RUN_SPEED )
idealActivity = ACT_RUN ;
else
idealActivity = ACT_WALK ;
}
}
return idealActivity ;
}
}
// ------------------------------------------------------------------------------------------------ //
// CCSPlayerAnimState implementation.
// ------------------------------------------------------------------------------------------------ //
CCSPlayerAnimState : : CCSPlayerAnimState ( )
{
m_pOuter = NULL ;
m_bJumping = false ;
m_flJumpStartTime = 0.0f ;
m_bFirstJumpFrame = false ;
m_bReloading = false ;
m_flReloadCycle = 0.0f ;
m_iReloadSequence = - 1 ;
m_flReloadHoldEndTime = 0.0f ;
m_bFiring = false ;
m_iFireSequence = - 1 ;
m_flFireCycle = 0.0f ;
m_delayedFire = PLAYERANIMEVENT_COUNT ;
m_bThrowingGrenade = false ;
m_bPrimingGrenade = false ;
m_flGrenadeCycle = 0.0f ;
m_iGrenadeSequence = - 1 ;
m_iLastThrowGrenadeCounter = 0 ;
m_cachedModelIndex = - 1 ;
m_pPlayer = NULL ;
m_pHelpers = NULL ;
}
void CCSPlayerAnimState : : InitCS ( CBaseAnimatingOverlay * pEntity , ICSPlayerAnimStateHelpers * pHelpers , LegAnimType_t legAnimType , bool bUseAimSequences )
{
CModAnimConfig config ;
config . m_flMaxBodyYawDegrees = 90 ;
config . m_LegAnimType = legAnimType ;
config . m_bUseAimSequences = bUseAimSequences ;
m_pPlayer = ToCSPlayer ( pEntity ) ;
m_pHelpers = pHelpers ;
BaseClass : : Init ( pEntity , config ) ;
}
//--------------------------------------------------------------------------------------------------------------
void CCSPlayerAnimState : : CheckCachedSequenceValidity ( void )
{
if ( m_cachedModelIndex ! = GetOuter ( ) - > GetModelIndex ( ) )
{
m_namedSequence . RemoveAll ( ) ;
m_cachedModelIndex = GetOuter ( ) - > GetModelIndex ( ) ;
for ( int i = 0 ; i < = ACT_CROUCHIDLE ; + + i )
{
m_sequenceCache [ i ] = - 1 ;
}
// precache the sequences we'll be using for movement
if ( m_cachedModelIndex > 0 )
{
m_sequenceCache [ ACT_HOP - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_HOP ) ;
m_sequenceCache [ ACT_IDLE - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_IDLE ) ;
m_sequenceCache [ ACT_RUN_CROUCH - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_RUN_CROUCH ) ;
m_sequenceCache [ ACT_CROUCHIDLE - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_CROUCHIDLE ) ;
m_sequenceCache [ ACT_RUN - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_RUN ) ;
m_sequenceCache [ ACT_WALK - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_WALK ) ;
m_sequenceCache [ ACT_IDLE - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( ACT_IDLE ) ;
}
}
}
//--------------------------------------------------------------------------------------------------------------
/**
* Cache the sequence numbers for the first ACT_HOP activities , since the CS player doesn ' t have multiple
* sequences per activity .
*/
int CCSPlayerAnimState : : SelectWeightedSequence ( Activity activity )
{
VPROF ( " CCSPlayerAnimState::ComputeMainSequence " ) ;
if ( activity > ACT_CROUCHIDLE | | activity < 1 )
{
return GetOuter ( ) - > SelectWeightedSequence ( activity ) ;
}
CheckCachedSequenceValidity ( ) ;
int sequence = m_sequenceCache [ activity - 1 ] ;
if ( sequence < 0 )
{
// just in case, look up the sequence if we didn't precache it above
sequence = m_sequenceCache [ activity - 1 ] = GetOuter ( ) - > SelectWeightedSequence ( activity ) ;
}
# if defined(CLIENT_DLL) && defined(_DEBUG)
int realSequence = GetOuter ( ) - > SelectWeightedSequence ( activity ) ;
Assert ( realSequence = = sequence ) ;
# endif
return sequence ;
}
//--------------------------------------------------------------------------------------------------------------
/**
* Try to look up named sequences in a CUtlDict cache before falling back to the normal LookupSequence . It ' s
* best to avoid the normal LookupSequence when your models have 750 + sequences . . .
*/
int CCSPlayerAnimState : : CalcSequenceIndex ( const char * pBaseName , . . . )
{
VPROF ( " CCSPlayerAnimState::CalcSequenceIndex " ) ;
CheckCachedSequenceValidity ( ) ;
char szFullName [ 512 ] ;
va_list marker ;
va_start ( marker , pBaseName ) ;
Q_vsnprintf ( szFullName , sizeof ( szFullName ) , pBaseName , marker ) ;
va_end ( marker ) ;
int iSequence = m_namedSequence . Find ( szFullName ) ;
if ( iSequence = = m_namedSequence . InvalidIndex ( ) )
{
iSequence = GetOuter ( ) - > LookupSequence ( szFullName ) ;
m_namedSequence . Insert ( szFullName , iSequence ) ;
}
else
{
iSequence = m_namedSequence [ iSequence ] ;
}
# if defined(CLIENT_DLL) && defined(_DEBUG)
int realSequence = GetOuter ( ) - > LookupSequence ( szFullName ) ;
Assert ( realSequence = = iSequence ) ;
# endif
// Show warnings if we can't find anything here.
if ( iSequence = = - 1 )
{
static CUtlDict < int , int > dict ;
if ( dict . Find ( szFullName ) = = - 1 )
{
dict . Insert ( szFullName , 0 ) ;
Warning ( " CalcSequenceIndex: can't find '%s'. \n " , szFullName ) ;
}
iSequence = 0 ;
}
return iSequence ;
}
void CCSPlayerAnimState : : ClearAnimationState ( )
{
m_bJumping = false ;
m_bFiring = false ;
m_bReloading = false ;
m_flReloadHoldEndTime = 0.0f ;
m_bThrowingGrenade = m_bPrimingGrenade = false ;
m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter ( ) ;
BaseClass : : ClearAnimationState ( ) ;
}
void CCSPlayerAnimState : : DoAnimationEvent ( PlayerAnimEvent_t event , int nData )
{
Assert ( event ! = PLAYERANIMEVENT_THROW_GRENADE ) ;
MDLCACHE_CRITICAL_SECTION ( ) ;
switch ( event )
{
case PLAYERANIMEVENT_FIRE_GUN_PRIMARY :
case PLAYERANIMEVENT_FIRE_GUN_SECONDARY :
// Regardless of what we're doing in the fire layer, restart it.
m_flFireCycle = 0 ;
m_iFireSequence = CalcFireLayerSequence ( event ) ;
m_bFiring = m_iFireSequence ! = - 1 ;
// If we are interrupting a (shotgun) reload, cancel the reload, and fire next frame.
if ( m_bFiring & & m_bReloading )
{
m_bReloading = false ;
m_iReloadSequence = - 1 ;
m_delayedFire = event ;
m_bFiring = false ;
m_iFireSequence = - 1 ;
CAnimationLayer * pLayer = m_pOuter - > GetAnimOverlay ( RELOADSEQUENCE_LAYER ) ;
if ( pLayer )
{
pLayer - > m_flWeight = 0.0f ;
pLayer - > m_nOrder = 15 ;
}
}
# ifdef CLIENT_DLL
if ( m_bFiring & & ! m_bReloading )
{
if ( m_pPlayer )
{
m_pPlayer - > ProcessMuzzleFlashEvent ( ) ;
}
}
# endif
break ;
case PLAYERANIMEVENT_JUMP :
// Play the jump animation.
m_bJumping = true ;
m_bFirstJumpFrame = true ;
m_flJumpStartTime = gpGlobals - > curtime ;
break ;
case PLAYERANIMEVENT_RELOAD :
{
// ignore normal reload events for shotguns - they get sent to trigger sounds etc only
CWeaponCSBase * pWeapon = m_pHelpers - > CSAnim_GetActiveWeapon ( ) ;
if ( pWeapon & & pWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_SHOTGUN )
{
m_iReloadSequence = CalcReloadLayerSequence ( event ) ;
if ( m_iReloadSequence ! = - 1 )
{
m_bReloading = true ;
m_flReloadCycle = 0 ;
}
else
{
m_bReloading = false ;
}
}
}
break ;
case PLAYERANIMEVENT_RELOAD_START :
case PLAYERANIMEVENT_RELOAD_LOOP :
// Set the hold time for _start and _loop anims, then fall through to the _end case
m_flReloadHoldEndTime = gpGlobals - > curtime + 0.75f ;
case PLAYERANIMEVENT_RELOAD_END :
{
// ignore shotgun reload events for non-shotguns
CWeaponCSBase * pWeapon = m_pHelpers - > CSAnim_GetActiveWeapon ( ) ;
if ( pWeapon & & pWeapon - > GetCSWpnData ( ) . m_WeaponType ! = WEAPONTYPE_SHOTGUN )
{
m_flReloadHoldEndTime = 0.0f ; // clear this out in case we set it in _START or _LOOP above
}
else
{
m_iReloadSequence = CalcReloadLayerSequence ( event ) ;
if ( m_iReloadSequence ! = - 1 )
{
m_bReloading = true ;
m_flReloadCycle = 0 ;
}
else
{
m_bReloading = false ;
}
}
}
break ;
case PLAYERANIMEVENT_CLEAR_FIRING :
{
m_iFireSequence = - 1 ;
}
break ;
default :
Assert ( ! " CCSPlayerAnimState::DoAnimationEvent " ) ;
}
}
float g_flThrowGrenadeFraction = 0.25 ;
bool CCSPlayerAnimState : : IsThrowingGrenade ( )
{
if ( m_bThrowingGrenade )
{
// An animation event would be more appropriate here.
return m_flGrenadeCycle < g_flThrowGrenadeFraction ;
}
else
{
bool bThrowPending = ( m_iLastThrowGrenadeCounter ! = GetOuterGrenadeThrowCounter ( ) ) ;
return bThrowPending | | IsOuterGrenadePrimed ( ) ;
}
}
int CCSPlayerAnimState : : CalcReloadLayerSequence ( PlayerAnimEvent_t event )
{
if ( m_delayedFire ! = PLAYERANIMEVENT_COUNT )
return - 1 ;
const char * weaponSuffix = GetWeaponSuffix ( ) ;
if ( ! weaponSuffix )
return - 1 ;
CWeaponCSBase * pWeapon = m_pHelpers - > CSAnim_GetActiveWeapon ( ) ;
if ( ! pWeapon )
return - 1 ;
const char * prefix = " " ;
switch ( GetCurrentMainSequenceActivity ( ) )
{
case ACT_PLAYER_RUN_FIRE :
case ACT_RUN :
prefix = " run " ;
break ;
case ACT_PLAYER_WALK_FIRE :
case ACT_WALK :
prefix = " walk " ;
break ;
case ACT_PLAYER_CROUCH_FIRE :
case ACT_CROUCHIDLE :
prefix = " crouch_idle " ;
break ;
case ACT_PLAYER_CROUCH_WALK_FIRE :
case ACT_RUN_CROUCH :
prefix = " crouch_walk " ;
break ;
default :
case ACT_PLAYER_IDLE_FIRE :
prefix = " idle " ;
break ;
}
const char * reloadSuffix = " " ;
switch ( event )
{
case PLAYERANIMEVENT_RELOAD_START :
reloadSuffix = " _start " ;
break ;
case PLAYERANIMEVENT_RELOAD_LOOP :
reloadSuffix = " _loop " ;
break ;
case PLAYERANIMEVENT_RELOAD_END :
reloadSuffix = " _end " ;
break ;
}
// First, look for <prefix>_reload_<weapon name><_start|_loop|_end>.
char szName [ 512 ] ;
Q_snprintf ( szName , sizeof ( szName ) , " %s_reload_%s%s " , prefix , weaponSuffix , reloadSuffix ) ;
int iReloadSequence = m_pOuter - > LookupSequence ( szName ) ;
if ( iReloadSequence ! = - 1 )
return iReloadSequence ;
// Next, look for reload_<weapon name><_start|_loop|_end>.
Q_snprintf ( szName , sizeof ( szName ) , " reload_%s%s " , weaponSuffix , reloadSuffix ) ;
iReloadSequence = m_pOuter - > LookupSequence ( szName ) ;
if ( iReloadSequence ! = - 1 )
return iReloadSequence ;
// Ok, look for generic categories.. pistol, shotgun, rifle, etc.
if ( pWeapon - > GetCSWpnData ( ) . m_WeaponType = = WEAPONTYPE_PISTOL )
{
Q_snprintf ( szName , sizeof ( szName ) , " reload_pistol " ) ;
iReloadSequence = m_pOuter - > LookupSequence ( szName ) ;
if ( iReloadSequence ! = - 1 )
return iReloadSequence ;
}
// Fall back to reload_m4.
iReloadSequence = CalcSequenceIndex ( " reload_m4 " ) ;
if ( iReloadSequence > 0 )
return iReloadSequence ;
return - 1 ;
}
2024-09-02 10:33:13 +02:00
void CCSPlayerAnimState : : UpdateLayerSequenceGeneric ( CStudioHdr * pStudioHdr ,
int iLayer ,
bool & bEnabled ,
float & flCurCycle ,
int & iSequence ,
bool bWaitAtEnd )
2020-04-22 18:56:21 +02:00
{
if ( ! bEnabled | | iSequence < 0 )
2024-09-02 10:33:13 +02:00
{
2020-04-22 18:56:21 +02:00
return ;
2024-09-02 10:33:13 +02:00
}
// Increment the fire sequence's cycle.
flCurCycle + = m_pOuter - > GetSequenceCycleRate ( pStudioHdr , iSequence ) * gpGlobals - > frametime ;
2020-04-22 18:56:21 +02:00
2024-09-02 10:33:13 +02:00
if ( flCurCycle > 1 )
{
if ( bWaitAtEnd )
2020-04-22 18:56:21 +02:00
{
2024-09-02 10:33:13 +02:00
flCurCycle = 1 ;
2020-04-22 18:56:21 +02:00
}
2024-09-02 10:33:13 +02:00
else
{
// Not firing anymore.
bEnabled = false ;
iSequence = 0 ;
2020-04-22 18:56:21 +02:00
2024-09-02 10:33:13 +02:00
CAnimationLayer * pLayer = m_pOuter - > GetAnimOverlay ( iLayer ) ;
pLayer - > m_fFlags = 0 ;
return ;
}
}
2020-04-22 18:56:21 +02:00
2024-09-02 10:33:13 +02:00
// Now dump the state into its animation layer.
CAnimationLayer * pLayer = m_pOuter - > GetAnimOverlay ( iLayer ) ;
pLayer - > m_flCycle = flCurCycle ;
pLayer - > m_nSequence = iSequence ;
pLayer - > m_flPlaybackRate = 1.0f ;
pLayer - > m_flWeight = 1.0f ;
pLayer - > m_nOrder = iLayer ;
pLayer - > m_fFlags | = ANIM_LAYER_ACTIVE ;
2020-04-22 18:56:21 +02:00
}
bool CCSPlayerAnimState : : IsOuterGrenadePrimed ( )
{
CBaseCombatCharacter * pChar = m_pOuter - > MyCombatCharacterPointer ( ) ;
if ( pChar )
{
CBaseCSGrenade * pGren = dynamic_cast < CBaseCSGrenade * > ( pChar - > GetActiveWeapon ( ) ) ;
return pGren & & pGren - > IsPinPulled ( ) ;
}
else
{
return NULL ;
}
}
void CCSPlayerAnimState : : ComputeGrenadeSequence ( CStudioHdr * pStudioHdr )
{
VPROF ( " CCSPlayerAnimState::ComputeGrenadeSequence " ) ;
if ( m_bThrowingGrenade )
{
UpdateLayerSequenceGeneric ( pStudioHdr , GRENADESEQUENCE_LAYER , m_bThrowingGrenade , m_flGrenadeCycle , m_iGrenadeSequence , false ) ;
}
else
{
if ( m_pPlayer )
{
CBaseCombatWeapon * pWeapon = m_pPlayer - > GetActiveWeapon ( ) ;
CBaseCSGrenade * pGren = dynamic_cast < CBaseCSGrenade * > ( pWeapon ) ;
if ( ! pGren )
{
// The player no longer has a grenade equipped. Bail.
m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter ( ) ;
return ;
}
}
// Priming the grenade isn't an event.. we just watch the player for it.
// Also play the prime animation first if he wants to throw the grenade.
bool bThrowPending = ( m_iLastThrowGrenadeCounter ! = GetOuterGrenadeThrowCounter ( ) ) ;
if ( IsOuterGrenadePrimed ( ) | | bThrowPending )
{
if ( ! m_bPrimingGrenade )
{
// If this guy just popped into our PVS, and he's got his grenade primed, then
// let's assume that it's all the way primed rather than playing the prime
// animation from the start.
if ( TimeSinceLastAnimationStateClear ( ) < 0.4f )
{
m_flGrenadeCycle = 1 ;
}
else
{
m_flGrenadeCycle = 0 ;
}
m_iGrenadeSequence = CalcGrenadePrimeSequence ( ) ;
m_bPrimingGrenade = true ;
}
UpdateLayerSequenceGeneric ( pStudioHdr , GRENADESEQUENCE_LAYER , m_bPrimingGrenade , m_flGrenadeCycle , m_iGrenadeSequence , true ) ;
// If we're waiting to throw and we're done playing the prime animation...
if ( bThrowPending & & m_flGrenadeCycle = = 1 )
{
m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter ( ) ;
// Now play the throw animation.
m_iGrenadeSequence = CalcGrenadeThrowSequence ( ) ;
if ( m_iGrenadeSequence ! = - 1 )
{
// Configure to start playing
m_bThrowingGrenade = true ;
m_bPrimingGrenade = false ;
m_flGrenadeCycle = 0 ;
}
}
}
else
{
m_bPrimingGrenade = false ;
}
}
}
int CCSPlayerAnimState : : CalcGrenadePrimeSequence ( )
{
return CalcSequenceIndex ( " idle_shoot_gren1 " ) ;
}
int CCSPlayerAnimState : : CalcGrenadeThrowSequence ( )
{
return CalcSequenceIndex ( " idle_shoot_gren2 " ) ;
}
int CCSPlayerAnimState : : GetOuterGrenadeThrowCounter ( )
{
if ( m_pPlayer )
return m_pPlayer - > m_iThrowGrenadeCounter ;
else
return 0 ;
}
void CCSPlayerAnimState : : ComputeReloadSequence ( CStudioHdr * pStudioHdr )
{
VPROF ( " CCSPlayerAnimState::ComputeReloadSequence " ) ;
bool hold = m_flReloadHoldEndTime > gpGlobals - > curtime ;
UpdateLayerSequenceGeneric ( pStudioHdr , RELOADSEQUENCE_LAYER , m_bReloading , m_flReloadCycle , m_iReloadSequence , hold ) ;
if ( ! m_bReloading )
{
m_flReloadHoldEndTime = 0.0f ;
}
}
int CCSPlayerAnimState : : CalcAimLayerSequence ( float * flCycle , float * flAimSequenceWeight , bool bForceIdle )
{
VPROF ( " CCSPlayerAnimState::CalcAimLayerSequence " ) ;
const char * pSuffix = GetWeaponSuffix ( ) ;
if ( ! pSuffix )
return 0 ;
if ( bForceIdle )
{
switch ( GetCurrentMainSequenceActivity ( ) )
{
case ACT_CROUCHIDLE :
case ACT_RUN_CROUCH :
return CalcSequenceIndex ( " %s%s " , DEFAULT_CROUCH_IDLE_NAME , pSuffix ) ;
default :
return CalcSequenceIndex ( " %s%s " , DEFAULT_IDLE_NAME , pSuffix ) ;
}
}
else
{
switch ( GetCurrentMainSequenceActivity ( ) )
{
case ACT_RUN :
return CalcSequenceIndex ( " %s%s " , DEFAULT_RUN_NAME , pSuffix ) ;
case ACT_WALK :
case ACT_RUNTOIDLE :
case ACT_IDLETORUN :
return CalcSequenceIndex ( " %s%s " , DEFAULT_WALK_NAME , pSuffix ) ;
case ACT_CROUCHIDLE :
return CalcSequenceIndex ( " %s%s " , DEFAULT_CROUCH_IDLE_NAME , pSuffix ) ;
case ACT_RUN_CROUCH :
return CalcSequenceIndex ( " %s%s " , DEFAULT_CROUCH_WALK_NAME , pSuffix ) ;
case ACT_IDLE :
default :
return CalcSequenceIndex ( " %s%s " , DEFAULT_IDLE_NAME , pSuffix ) ;
}
}
}
const char * CCSPlayerAnimState : : GetWeaponSuffix ( )
{
VPROF ( " CCSPlayerAnimState::GetWeaponSuffix " ) ;
// Figure out the weapon suffix.
CWeaponCSBase * pWeapon = m_pHelpers - > CSAnim_GetActiveWeapon ( ) ;
if ( ! pWeapon )
return 0 ;
const char * pSuffix = pWeapon - > GetCSWpnData ( ) . m_szAnimExtension ;
# ifdef CS_SHIELD_ENABLED
if ( m_pOuter - > HasShield ( ) = = true )
{
if ( m_pOuter - > IsShieldDrawn ( ) = = true )
pSuffix = " shield " ;
else
pSuffix = " shield_undeployed " ;
}
# endif
return pSuffix ;
}
int CCSPlayerAnimState : : CalcFireLayerSequence ( PlayerAnimEvent_t event )
{
// Figure out the weapon suffix.
CWeaponCSBase * pWeapon = m_pHelpers - > CSAnim_GetActiveWeapon ( ) ;
if ( ! pWeapon )
return - 1 ;
const char * pSuffix = GetWeaponSuffix ( ) ;
if ( ! pSuffix )
return - 1 ;
char tempsuffix [ 32 ] ;
if ( pWeapon - > GetWeaponID ( ) = = WEAPON_ELITE )
{
bool bPrimary = ( event = = PLAYERANIMEVENT_FIRE_GUN_PRIMARY ) ;
Q_snprintf ( tempsuffix , sizeof ( tempsuffix ) , " %s_%c " , pSuffix , bPrimary ? ' r ' : ' l ' ) ;
pSuffix = tempsuffix ;
}
// Grenades handle their fire events separately
if ( event = = PLAYERANIMEVENT_THROW_GRENADE | |
pWeapon - > GetWeaponID ( ) = = WEAPON_HEGRENADE | |
pWeapon - > GetWeaponID ( ) = = WEAPON_SMOKEGRENADE | |
pWeapon - > GetWeaponID ( ) = = WEAPON_FLASHBANG )
{
return - 1 ;
}
switch ( GetCurrentMainSequenceActivity ( ) )
{
case ACT_PLAYER_RUN_FIRE :
case ACT_RUN :
return CalcSequenceIndex ( " %s%s " , DEFAULT_FIRE_RUN_NAME , pSuffix ) ;
case ACT_PLAYER_WALK_FIRE :
case ACT_WALK :
return CalcSequenceIndex ( " %s%s " , DEFAULT_FIRE_WALK_NAME , pSuffix ) ;
case ACT_PLAYER_CROUCH_FIRE :
case ACT_CROUCHIDLE :
return CalcSequenceIndex ( " %s%s " , DEFAULT_FIRE_CROUCH_NAME , pSuffix ) ;
case ACT_PLAYER_CROUCH_WALK_FIRE :
case ACT_RUN_CROUCH :
return CalcSequenceIndex ( " %s%s " , DEFAULT_FIRE_CROUCH_WALK_NAME , pSuffix ) ;
default :
case ACT_PLAYER_IDLE_FIRE :
return CalcSequenceIndex ( " %s%s " , DEFAULT_FIRE_IDLE_NAME , pSuffix ) ;
}
}
bool CCSPlayerAnimState : : CanThePlayerMove ( )
{
return m_pHelpers - > CSAnim_CanMove ( ) ;
}
float CCSPlayerAnimState : : GetCurrentMaxGroundSpeed ( )
{
Activity currentActivity = m_pOuter - > GetSequenceActivity ( m_pOuter - > GetSequence ( ) ) ;
if ( currentActivity = = ACT_WALK | | currentActivity = = ACT_IDLE )
return ANIM_TOPSPEED_WALK ;
else if ( currentActivity = = ACT_RUN )
{
if ( m_pPlayer )
{
CBaseCombatWeapon * activeWeapon = m_pPlayer - > GetActiveWeapon ( ) ;
if ( activeWeapon )
{
CWeaponCSBase * csWeapon = dynamic_cast < CWeaponCSBase * > ( activeWeapon ) ;
if ( csWeapon )
{
return csWeapon - > GetMaxSpeed ( ) ;
}
}
}
return ANIM_TOPSPEED_RUN ;
}
else if ( currentActivity = = ACT_RUN_CROUCH )
return ANIM_TOPSPEED_RUN_CROUCH ;
else
return 0 ;
}
bool CCSPlayerAnimState : : HandleJumping ( )
{
if ( m_bJumping )
{
if ( m_bFirstJumpFrame )
{
# if !defined(CLIENT_DLL)
//=============================================================================
// HPE_BEGIN:
// [dwenger] Needed for fun-fact implementation
//=============================================================================
CCS_GameStats . IncrementStat ( m_pPlayer , CSSTAT_TOTAL_JUMPS , 1 ) ;
//=============================================================================
// HPE_END
//=============================================================================
# endif
m_bFirstJumpFrame = false ;
RestartMainSequence ( ) ; // Reset the animation.
}
// Don't check if he's on the ground for a sec.. sometimes the client still has the
// on-ground flag set right when the message comes in.
if ( gpGlobals - > curtime - m_flJumpStartTime > 0.2f )
{
if ( m_pOuter - > GetFlags ( ) & FL_ONGROUND )
{
m_bJumping = false ;
RestartMainSequence ( ) ; // Reset the animation.
}
}
}
// Are we still jumping? If so, keep playing the jump animation.
return m_bJumping ;
}
Activity CCSPlayerAnimState : : CalcMainActivity ( )
{
float flOuterSpeed = GetOuterXYSpeed ( ) ;
if ( HandleJumping ( ) )
{
return ACT_HOP ;
}
else
{
Activity idealActivity = ACT_IDLE ;
if ( m_pOuter - > GetFlags ( ) & FL_ANIMDUCKING )
{
if ( flOuterSpeed > MOVING_MINIMUM_SPEED )
idealActivity = ACT_RUN_CROUCH ;
else
idealActivity = ACT_CROUCHIDLE ;
}
else
{
if ( flOuterSpeed > MOVING_MINIMUM_SPEED )
{
if ( flOuterSpeed > ARBITRARY_RUN_SPEED )
idealActivity = ACT_RUN ;
else
idealActivity = ACT_WALK ;
}
else
{
idealActivity = ACT_IDLE ;
}
}
return idealActivity ;
}
}
void CCSPlayerAnimState : : DebugShowAnimState ( int iStartLine )
{
engine - > Con_NPrintf ( iStartLine + + , " fire : %s, cycle: %.2f \n " , m_bFiring ? GetSequenceName ( m_pOuter - > GetModelPtr ( ) , m_iFireSequence ) : " [not firing] " , m_flFireCycle ) ;
engine - > Con_NPrintf ( iStartLine + + , " reload: %s, cycle: %.2f \n " , m_bReloading ? GetSequenceName ( m_pOuter - > GetModelPtr ( ) , m_iReloadSequence ) : " [not reloading] " , m_flReloadCycle ) ;
BaseClass : : DebugShowAnimState ( iStartLine ) ;
}
void CCSPlayerAnimState : : ComputeSequences ( CStudioHdr * pStudioHdr )
{
BaseClass : : ComputeSequences ( pStudioHdr ) ;
VPROF ( " CCSPlayerAnimState::ComputeSequences " ) ;
ComputeFireSequence ( pStudioHdr ) ;
ComputeReloadSequence ( pStudioHdr ) ;
ComputeGrenadeSequence ( pStudioHdr ) ;
}
void CCSPlayerAnimState : : ClearAnimationLayers ( )
{
if ( ! m_pOuter )
return ;
m_pOuter - > SetNumAnimOverlays ( NUM_LAYERS_WANTED ) ;
for ( int i = 0 ; i < m_pOuter - > GetNumAnimOverlays ( ) ; i + + )
{
// Client obeys Order of CBaseAnimatingOverlay::MAX_OVERLAYS (15), but server trusts only the ANIM_LAYER_ACTIVE flag.
m_pOuter - > GetAnimOverlay ( i ) - > SetOrder ( CBaseAnimatingOverlay : : MAX_OVERLAYS ) ;
# ifndef CLIENT_DLL
m_pOuter - > GetAnimOverlay ( i ) - > m_fFlags = 0 ;
# endif
}
}
void CCSPlayerAnimState : : ComputeFireSequence ( CStudioHdr * pStudioHdr )
{
VPROF ( " CCSPlayerAnimState::ComputeFireSequence " ) ;
if ( m_delayedFire ! = PLAYERANIMEVENT_COUNT )
{
DoAnimationEvent ( m_delayedFire , 0 ) ;
m_delayedFire = PLAYERANIMEVENT_COUNT ;
}
UpdateLayerSequenceGeneric ( pStudioHdr , FIRESEQUENCE_LAYER , m_bFiring , m_flFireCycle , m_iFireSequence , false ) ;
}