summaryrefslogtreecommitdiff
path: root/game/shared/tfc/tfc_playeranimstate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tfc/tfc_playeranimstate.cpp')
-rw-r--r--game/shared/tfc/tfc_playeranimstate.cpp323
1 files changed, 323 insertions, 0 deletions
diff --git a/game/shared/tfc/tfc_playeranimstate.cpp b/game/shared/tfc/tfc_playeranimstate.cpp
new file mode 100644
index 0000000..7c47748
--- /dev/null
+++ b/game/shared/tfc/tfc_playeranimstate.cpp
@@ -0,0 +1,323 @@
+//========= 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;
+}
+