All pastes #716188 Raw Edit

Anonymous

public cpp v1 · immutable
#716188 ·published 2007-09-26 16:35 UTC
rendered paste body
//========= Copyright © 2006-2007, Tom Leighton (Marine), All rights reserved. ============////// Purpose: The Animation Controllers for the CS:S Player Models////=========================================================================================//#include "cbase.h"#include "base_playeranimstate.h"#include "tier0/vprof.h"#include "animation.h"#include "studio.h"#include "apparent_velocity_helper.h"#include "utldict.h"#include "weapon_hl2mpbasehlmpcombatweapon.h"#ifdef CLIENT_DLL#include "c_hl2mp_player.h"#include "bone_setup.h"#include "interpolatedvar.h"#else#include "hl2mp_player.h"#endif#include "css_anims.h"#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)#define RELOADSEQUENCE_LAYER	(FIRESEQUENCE_LAYER + 1)#define GRENADESEQUENCE_LAYER	(RELOADSEQUENCE_LAYER + 1)#define NUM_LAYERS_WANTED		(GRENADESEQUENCE_LAYER + 1)class CCSSPlayerAnimState : public CBasePlayerAnimState, ICSSPlayerAnimState	{	public:		DECLARE_CLASS( CCSSPlayerAnimState, CBasePlayerAnimState );		friend ICSSPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ICSSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences );		CCSSPlayerAnimState();		virtual void DoAnimationEvent( PlayerAnimEvent_t event );		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();		void InitCSS( CBaseAnimatingOverlay *pPlayer, ICSSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences );	protected:		int CalcFireLayerSequence(PlayerAnimEvent_t event);		void ComputeFireSequence(CStudioHdr *pStudioHdr);		void ComputeReloadSequence(CStudioHdr *pStudioHdr);		int CalcReloadLayerSequence();		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 );	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;		// 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;		// 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.		ICSSPlayerAnimStateHelpers *m_pHelpers;	};ICSSPlayerAnimState* CreatePlayerAnimState( CBaseAnimatingOverlay *pEntity, ICSSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences )	{	CCSSPlayerAnimState *pRet = new CCSSPlayerAnimState;	pRet->InitCSS( pEntity, pHelpers, legAnimType, bUseAimSequences );	return pRet;	}// ---------------- // CCSSPlayerAnimState Implementation// ----------------CCSSPlayerAnimState::CCSSPlayerAnimState()	{		m_pOuter = NULL;		m_bReloading = false;	}void CCSSPlayerAnimState::InitCSS( CBaseAnimatingOverlay *pEntity, ICSSPlayerAnimStateHelpers *pHelpers, LegAnimType_t legAnimType, bool bUseAimSequences )	{	CModAnimConfig config;	config.m_flMaxBodyYawDegrees = 90;	config.m_LegAnimType = legAnimType;	config.m_bUseAimSequences = bUseAimSequences;	m_pHelpers = pHelpers;	BaseClass::Init( pEntity, config );	}void CCSSPlayerAnimState::ClearAnimationState(){	m_bJumping = false;	m_bFiring = false;	m_bReloading = false;	m_bThrowingGrenade = m_bPrimingGrenade = false;	m_iLastThrowGrenadeCounter = GetOuterGrenadeThrowCounter();		BaseClass::ClearAnimationState();}void CCSSPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event ){	Assert( event != PLAYERANIMEVENT_THROW_GRENADE );	if ( event == PLAYERANIMEVENT_FIRE_GUN_PRIMARY || 		 event == 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;	}	else if ( event == PLAYERANIMEVENT_JUMP )	{		// Play the jump animation.		m_bJumping = true;		m_bFirstJumpFrame = true;		m_flJumpStartTime = gpGlobals->curtime;	}	else if ( event == PLAYERANIMEVENT_RELOAD )	{		m_iReloadSequence = CalcReloadLayerSequence();		if ( m_iReloadSequence != -1 )		{			m_bReloading = true;			m_flReloadCycle = 0;		}	}	else	{		Assert( !"CCSSPlayerAnimState::DoAnimationEvent" );	}}float g_flThrowGrenadeFraction = 0.25;bool CCSSPlayerAnimState::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 CCSSPlayerAnimState::CalcReloadLayerSequence(){	const char *pSuffix = GetWeaponSuffix();	if ( !pSuffix )		return -1;	CBaseHL2MPCombatWeapon *pWeapon = m_pHelpers->CSSAnim_GetActiveWeapon();	if ( !pWeapon )		return -1;	// First, look for reload_<weapon name>.	char szName[512];	Q_snprintf( szName, sizeof( szName ), "reload_%s", pSuffix );	int iReloadSequence = m_pOuter->LookupSequence( szName );	if ( iReloadSequence != -1 )		return iReloadSequence;	//CSSTODO/*	// Ok, look for generic categories.. pistol, shotgun, rifle, etc.	if ( pWeapon->GetCSSWpnData().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;}#ifdef CLIENT_DLL	void CCSSPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd )	{		if ( !bEnabled )			return;		// Increment the fire sequence's cycle.		flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime;		if ( flCurCycle > 1 )		{			if ( bWaitAtEnd )			{				flCurCycle = 1;			}			else			{				// Not firing anymore.				bEnabled = false;				iSequence = 0;				return;			}		}		// Now dump the state into its animation layer.		C_AnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer );		pLayer->m_flCycle = flCurCycle;		pLayer->m_nSequence = iSequence;		pLayer->m_flPlaybackRate = 1.0;		pLayer->m_flWeight = 1.0f;		pLayer->m_nOrder = iLayer;	}#endifbool CCSSPlayerAnimState::IsOuterGrenadePrimed(){////// HACK! FIX THIS SO GRENADES WORK FINE///	/*CBaseCombatCharacter *pChar = m_pOuter->MyCombatCharacterPointer();	if ( pChar )	{		CBaseCSSGrenade *pGren = dynamic_cast<CBaseCSSGrenade*>( pChar->GetActiveWeapon() );		return pGren && pGren->IsPinPulled();	}	else	{		return NULL;	}*/return NULL;}void CCSSPlayerAnimState::ComputeGrenadeSequence( CStudioHdr *pStudioHdr ){#ifdef CLIENT_DLL	if ( m_bThrowingGrenade )	{		UpdateLayerSequenceGeneric( pStudioHdr, GRENADESEQUENCE_LAYER, m_bThrowingGrenade, m_flGrenadeCycle, m_iGrenadeSequence, false );	}	else	{		// 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;		}	}#endif}int CCSSPlayerAnimState::CalcGrenadePrimeSequence(){	return CalcSequenceIndex( "idle_shoot_gren1" );}int CCSSPlayerAnimState::CalcGrenadeThrowSequence(){	return CalcSequenceIndex( "idle_shoot_gren2" );}int CCSSPlayerAnimState::GetOuterGrenadeThrowCounter(){	// HACK!!!	//CHL2MP_Player *pPlayer = dynamic_cast<CHL2MP_Player*>( m_pOuter );	//if ( pPlayer )	//	return pPlayer->m_iThrowGrenadeCounter;	//else	//	return 0;return 0;}void CCSSPlayerAnimState::ComputeReloadSequence( CStudioHdr *pStudioHdr ){#ifdef CLIENT_DLL	UpdateLayerSequenceGeneric( pStudioHdr, RELOADSEQUENCE_LAYER, m_bReloading, m_flReloadCycle, m_iReloadSequence, false );#else	// Server doesn't bother with different fire sequences.#endif}int CCSSPlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle ){	const char *pSuffix = GetWeaponSuffix();	if ( !pSuffix )		return 0;	if ( bForceIdle )	{		switch ( GetCurrentMainSequenceActivity() )		{			case ACT_CROUCHIDLE:				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* CCSSPlayerAnimState::GetWeaponSuffix(){	// Figure out the weapon suffix.	CBaseHL2MPCombatWeapon *pWeapon = m_pHelpers->CSSAnim_GetActiveWeapon();	if ( !pWeapon )		return "Pistol";	const char *pSuffix = pWeapon->GetHL2MPWpnData().m_szAnimationExtension;	return pSuffix;}int CCSSPlayerAnimState::CalcFireLayerSequence(PlayerAnimEvent_t event){	// Figure out the weapon suffix.	CBaseHL2MPCombatWeapon *pWeapon = m_pHelpers->CSSAnim_GetActiveWeapon();	if ( !pWeapon )		return 0;	const char *pSuffix = GetWeaponSuffix();	if ( !pSuffix )		return 0;			// Don't rely on their weapon here because the player has usually switched to their 	// pistol or rifle by the time the PLAYERANIMEVENT_THROW_GRENADE message gets to the client.	if ( event == PLAYERANIMEVENT_THROW_GRENADE )	{		pSuffix = "Gren"; 	}	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 CCSSPlayerAnimState::CanThePlayerMove(){	return m_pHelpers->CSSAnim_CanMove();}float CCSSPlayerAnimState::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 )		return ANIM_TOPSPEED_RUN;	else if ( currentActivity == ACT_RUN_CROUCH )		return ANIM_TOPSPEED_RUN_CROUCH;	else		return 0;}bool CCSSPlayerAnimState::HandleJumping(){	if ( m_bJumping )	{		if ( m_bFirstJumpFrame )		{			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 CCSSPlayerAnimState::CalcMainActivity(){	float flOuterSpeed = GetOuterXYSpeed();	if ( HandleJumping() )	{		return ACT_HOP;	}	else	{		Activity idealActivity = ACT_IDLE;		if ( m_pOuter->GetFlags() & FL_DUCKING )		{			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 CCSSPlayerAnimState::DebugShowAnimState( int iStartLine ){#ifdef CLIENT_DLL	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 );#endif}void CCSSPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ){	BaseClass::ComputeSequences( pStudioHdr );	ComputeFireSequence( pStudioHdr );	ComputeReloadSequence( pStudioHdr );	ComputeGrenadeSequence( pStudioHdr );}void CCSSPlayerAnimState::ClearAnimationLayers(){	if ( !m_pOuter )		return;	m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED );	for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ )	{		m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );	}}void CCSSPlayerAnimState::ComputeFireSequence( CStudioHdr *pStudioHdr ){#ifdef CLIENT_DLL	UpdateLayerSequenceGeneric( pStudioHdr, FIRESEQUENCE_LAYER, m_bFiring, m_flFireCycle, m_iFireSequence, false );#else	// Server doesn't bother with different fire sequences.#endif}