You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
323 lines
6.7 KiB
323 lines
6.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "tfc_playeranimstate.h" |
|
#include "base_playeranimstate.h" |
|
#include "tier0/vprof.h" |
|
#include "animation.h" |
|
#include "studio.h" |
|
#include "apparent_velocity_helper.h" |
|
#include "utldict.h" |
|
|
|
|
|
#ifdef CLIENT_DLL |
|
#include "c_tfc_player.h" |
|
#else |
|
#include "tfc_player.h" |
|
#endif |
|
|
|
|
|
// When moving this fast, he plays run anim. |
|
#define ARBITRARY_RUN_SPEED 175.0f |
|
|
|
#define MAX_STANDING_RUN_SPEED 320 |
|
#define MAX_CROUCHED_RUN_SPEED 110 |
|
|
|
|
|
// ------------------------------------------------------------------------------------------------ // |
|
// CPlayerAnimState declaration. |
|
// ------------------------------------------------------------------------------------------------ // |
|
|
|
class CTFCPlayerAnimState : public ITFCPlayerAnimState, public CBasePlayerAnimState |
|
{ |
|
public: |
|
|
|
DECLARE_CLASS( CTFCPlayerAnimState, CBasePlayerAnimState ); |
|
|
|
CTFCPlayerAnimState(); |
|
void InitTFC( CTFCPlayer *pPlayer ); |
|
|
|
// This is called by both the client and the server in the same way to trigger events for |
|
// players firing, jumping, throwing grenades, etc. |
|
virtual void DoAnimationEvent( PlayerAnimEvent_t event, int nData ); |
|
virtual int CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight ); |
|
virtual float SetOuterBodyYaw( float flValue ); |
|
virtual Activity CalcMainActivity(); |
|
virtual float GetCurrentMaxGroundSpeed(); |
|
virtual void ClearAnimationState(); |
|
virtual bool ShouldUpdateAnimState(); |
|
|
|
|
|
private: |
|
|
|
const char* GetWeaponSuffix(); |
|
bool HandleJumping(); |
|
bool HandleDeath( Activity *deathActivity ); |
|
|
|
|
|
private: |
|
|
|
CTFCPlayer *m_pOuterTFC; |
|
|
|
bool m_bJumping; |
|
bool m_bFirstJumpFrame; |
|
float m_flJumpStartTime; |
|
|
|
bool m_bFiring; |
|
float m_flFireStartTime; |
|
|
|
bool m_bDying; |
|
Activity m_DeathActivity; |
|
}; |
|
|
|
|
|
ITFCPlayerAnimState* CreatePlayerAnimState( CTFCPlayer *pPlayer ) |
|
{ |
|
CTFCPlayerAnimState *pRet = new CTFCPlayerAnimState; |
|
pRet->InitTFC( pPlayer ); |
|
return pRet; |
|
} |
|
|
|
|
|
// ----------------------------------------------------------------------------- // |
|
// CTFCPlayerAnimState implementation. |
|
// ----------------------------------------------------------------------------- // |
|
|
|
CTFCPlayerAnimState::CTFCPlayerAnimState() |
|
{ |
|
m_pOuterTFC = NULL; |
|
m_bJumping = false; |
|
m_bFirstJumpFrame = false; |
|
m_bFiring = false; |
|
} |
|
|
|
|
|
void CTFCPlayerAnimState::InitTFC( CTFCPlayer *pPlayer ) |
|
{ |
|
m_pOuterTFC = pPlayer; |
|
|
|
CModAnimConfig config; |
|
config.m_flMaxBodyYawDegrees = 30; |
|
config.m_LegAnimType = LEGANIM_GOLDSRC; |
|
config.m_bUseAimSequences = true; |
|
|
|
BaseClass::Init( pPlayer, config ); |
|
} |
|
|
|
|
|
const char* CTFCPlayerAnimState::GetWeaponSuffix() |
|
{ |
|
CBaseCombatWeapon *pWeapon = m_pOuterTFC->GetActiveWeapon(); |
|
if ( pWeapon ) |
|
return pWeapon->GetWpnData().szAnimationPrefix; |
|
else |
|
return "shotgun"; |
|
} |
|
|
|
|
|
int CTFCPlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight ) |
|
{ |
|
const char *pWeaponSuffix = GetWeaponSuffix(); |
|
if ( !pWeaponSuffix ) |
|
return 0; |
|
|
|
// Are we aiming or firing? |
|
const char *pAimOrShoot = "aim"; |
|
if ( m_bFiring ) |
|
pAimOrShoot = "shoot"; |
|
|
|
// Are we standing or crouching? |
|
int iSequence = 0; |
|
const char *pPrefix = "ref"; |
|
if ( m_bDying ) |
|
{ |
|
// While dying, only play the main sequence.. don't layer this one on top. |
|
*flAimSequenceWeight = 0; |
|
} |
|
else |
|
{ |
|
switch ( GetCurrentMainSequenceActivity() ) |
|
{ |
|
case ACT_CROUCHIDLE: |
|
case ACT_RUN_CROUCH: |
|
pPrefix = "crouch"; |
|
break; |
|
} |
|
} |
|
|
|
iSequence = CalcSequenceIndex( "%s_%s_%s", pPrefix, pAimOrShoot, pWeaponSuffix ); |
|
|
|
// Check if we're done firing. |
|
if ( m_bFiring ) |
|
{ |
|
float dur = m_pOuterTFC->SequenceDuration( iSequence ); |
|
*flCycle = (gpGlobals->curtime - m_flFireStartTime) / dur; |
|
if ( *flCycle >= 1 ) |
|
{ |
|
*flCycle = 1; |
|
m_bFiring = false; |
|
} |
|
} |
|
|
|
return iSequence; |
|
} |
|
|
|
|
|
void CTFCPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) |
|
{ |
|
if ( event == PLAYERANIMEVENT_JUMP ) |
|
{ |
|
// Main animation goes to ACT_HOP. |
|
m_bJumping = true; |
|
m_bFirstJumpFrame = true; |
|
m_flJumpStartTime = gpGlobals->curtime; |
|
} |
|
else if ( event == PLAYERANIMEVENT_FIRE_GUN ) |
|
{ |
|
// The middle part of the aim layer sequence becomes "shoot" until that animation is complete. |
|
m_bFiring = true; |
|
m_flFireStartTime = gpGlobals->curtime; |
|
} |
|
else if ( event == PLAYERANIMEVENT_DIE ) |
|
{ |
|
m_bFiring = m_bJumping = false; |
|
m_bDying = true; |
|
|
|
Activity acts[] = |
|
{ |
|
ACT_DIESIMPLE, |
|
ACT_DIEBACKWARD, |
|
ACT_DIEFORWARD, |
|
ACT_DIE_HEADSHOT, |
|
ACT_DIE_GUTSHOT |
|
}; |
|
|
|
m_DeathActivity = acts[ RandomInt( 0, ARRAYSIZE( acts ) - 1 ) ]; |
|
RestartMainSequence(); // Play a death animation. |
|
} |
|
} |
|
|
|
|
|
float CTFCPlayerAnimState::SetOuterBodyYaw( float flValue ) |
|
{ |
|
m_pOuterTFC->SetBoneController( 0, flValue ); |
|
return flValue; |
|
} |
|
|
|
|
|
bool CTFCPlayerAnimState::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_pOuterTFC->GetFlags() & FL_ONGROUND ) |
|
{ |
|
m_bJumping = false; |
|
RestartMainSequence(); // Reset the animation. |
|
} |
|
} |
|
} |
|
|
|
// Are we still jumping? If so, keep playing the jump animation. |
|
return m_bJumping; |
|
} |
|
|
|
|
|
bool CTFCPlayerAnimState::HandleDeath( Activity *deathActivity ) |
|
{ |
|
if ( m_bDying ) |
|
{ |
|
if ( m_pOuterTFC->IsAlive() ) |
|
{ |
|
m_bDying = false; |
|
} |
|
else |
|
{ |
|
*deathActivity = m_DeathActivity; |
|
} |
|
} |
|
return m_bDying; |
|
} |
|
|
|
|
|
Activity CTFCPlayerAnimState::CalcMainActivity() |
|
{ |
|
Activity deathActivity = ACT_IDLE; |
|
if ( HandleDeath( &deathActivity ) ) |
|
{ |
|
return deathActivity; |
|
} |
|
else if ( HandleJumping() ) |
|
{ |
|
return ACT_HOP; |
|
} |
|
else |
|
{ |
|
Activity idealActivity = ACT_IDLE; |
|
float flOuterSpeed = GetOuterXYSpeed(); |
|
|
|
if ( m_pOuterTFC->GetFlags() & FL_DUCKING ) |
|
{ |
|
if ( flOuterSpeed > 0.1f ) |
|
idealActivity = ACT_RUN_CROUCH; |
|
else |
|
idealActivity = ACT_CROUCHIDLE; |
|
} |
|
else |
|
{ |
|
if ( flOuterSpeed > 0.1f ) |
|
{ |
|
if ( flOuterSpeed > ARBITRARY_RUN_SPEED ) |
|
idealActivity = ACT_RUN; |
|
else |
|
idealActivity = ACT_WALK; |
|
} |
|
else |
|
{ |
|
idealActivity = ACT_IDLE; |
|
} |
|
} |
|
|
|
return idealActivity; |
|
} |
|
} |
|
|
|
|
|
float CTFCPlayerAnimState::GetCurrentMaxGroundSpeed() |
|
{ |
|
Activity act = GetCurrentMainSequenceActivity(); |
|
if ( act == ACT_CROUCHIDLE || act == ACT_RUN_CROUCH ) |
|
return MAX_CROUCHED_RUN_SPEED; |
|
else |
|
return MAX_STANDING_RUN_SPEED; |
|
} |
|
|
|
|
|
void CTFCPlayerAnimState::ClearAnimationState() |
|
{ |
|
m_bJumping = false; |
|
m_bFiring = false; |
|
m_bDying = false; |
|
|
|
BaseClass::ClearAnimationState(); |
|
} |
|
|
|
|
|
bool CTFCPlayerAnimState::ShouldUpdateAnimState() |
|
{ |
|
return true; |
|
} |
|
|
|
|