source-engine/game/shared/tfc/tfc_playeranimstate.cpp

324 lines
6.7 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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;
}