374 lines
8.0 KiB
C++
374 lines
8.0 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//
|
|
//=============================================================================//
|
|
#include "cbase.h"
|
|
#include "tier0/vprof.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
#include "hl1_player_shared.h"
|
|
#include "hl1/c_hl1mp_player.h"
|
|
//#define CRecipientFilter C_RecipientFilter
|
|
#else
|
|
#include "hl1mp_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 CPlayerAnimState : public IHL1MPPlayerAnimState, public CBasePlayerAnimState
|
|
{
|
|
public:
|
|
|
|
DECLARE_CLASS( CPlayerAnimState, CBasePlayerAnimState );
|
|
|
|
CPlayerAnimState();
|
|
void Init( CHL1MP_Player *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, bool bForceIdle );
|
|
virtual float SetOuterBodyYaw( float flValue );
|
|
virtual Activity CalcMainActivity();
|
|
virtual float GetCurrentMaxGroundSpeed();
|
|
virtual void ClearAnimationState();
|
|
virtual bool ShouldUpdateAnimState();
|
|
virtual int SelectWeightedSequence( Activity activity ) ;
|
|
|
|
float CalcMovementPlaybackRate( bool *bIsMoving );
|
|
|
|
virtual void ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr );
|
|
|
|
|
|
private:
|
|
|
|
const char* GetWeaponSuffix();
|
|
bool HandleJumping();
|
|
bool HandleDeath( Activity *deathActivity );
|
|
|
|
|
|
private:
|
|
|
|
CHL1MP_Player *m_pOuter;
|
|
|
|
bool m_bJumping;
|
|
bool m_bFirstJumpFrame;
|
|
float m_flJumpStartTime;
|
|
|
|
bool m_bFiring;
|
|
float m_flFireStartTime;
|
|
|
|
bool m_bDying;
|
|
Activity m_DeathActivity;
|
|
};
|
|
|
|
|
|
IHL1MPPlayerAnimState* CreatePlayerAnimState( CHL1MP_Player *pPlayer )
|
|
{
|
|
CPlayerAnimState *pRet = new CPlayerAnimState;
|
|
pRet->Init( pPlayer );
|
|
return pRet;
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------- //
|
|
// CPlayerAnimState implementation.
|
|
// ----------------------------------------------------------------------------- //
|
|
|
|
CPlayerAnimState::CPlayerAnimState()
|
|
{
|
|
m_pOuter = NULL;
|
|
m_bJumping = false;
|
|
m_bFirstJumpFrame = false;
|
|
m_bFiring = false;
|
|
}
|
|
|
|
|
|
void CPlayerAnimState::Init( CHL1MP_Player *pPlayer )
|
|
{
|
|
m_pOuter = pPlayer;
|
|
|
|
CModAnimConfig config;
|
|
config.m_flMaxBodyYawDegrees = 90;
|
|
config.m_LegAnimType = LEGANIM_GOLDSRC;
|
|
config.m_bUseAimSequences = true;
|
|
|
|
BaseClass::Init( pPlayer, config );
|
|
}
|
|
|
|
|
|
const char* CPlayerAnimState::GetWeaponSuffix()
|
|
{
|
|
CBaseCombatWeapon *pWeapon = m_pOuter->GetActiveWeapon();
|
|
if ( pWeapon )
|
|
return pWeapon->GetWpnData().szAnimationPrefix;
|
|
else
|
|
return "shotgun";
|
|
}
|
|
|
|
|
|
int CPlayerAnimState::CalcAimLayerSequence( float *flCycle, float *flAimSequenceWeight, bool bForceIdle )
|
|
{
|
|
const char *pWeaponSuffix = GetWeaponSuffix();
|
|
if ( !pWeaponSuffix )
|
|
return 0;
|
|
|
|
if ( strcmp( pWeaponSuffix, "glock" ) == 0 )
|
|
pWeaponSuffix = "onehanded";
|
|
|
|
// 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_pOuter->SequenceDuration( iSequence );
|
|
*flCycle = (gpGlobals->curtime - m_flFireStartTime) / dur;
|
|
if ( *flCycle >= 1 )
|
|
{
|
|
*flCycle = 1;
|
|
m_bFiring = false;
|
|
}
|
|
}
|
|
|
|
return iSequence;
|
|
}
|
|
|
|
|
|
void CPlayerAnimState::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;
|
|
}
|
|
}
|
|
|
|
|
|
float CPlayerAnimState::SetOuterBodyYaw( float flValue )
|
|
{
|
|
// m_pOuter->SetBoneController( 0, flValue );
|
|
|
|
float fAcc = flValue / 4;
|
|
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
m_pOuter->SetBoneController( i, fAcc );
|
|
}
|
|
|
|
return flValue;
|
|
}
|
|
|
|
|
|
bool CPlayerAnimState::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;
|
|
}
|
|
|
|
int CPlayerAnimState::SelectWeightedSequence( Activity activity )
|
|
{
|
|
return m_pOuter->m_iRealSequence;
|
|
}
|
|
|
|
bool CPlayerAnimState::HandleDeath( Activity *deathActivity )
|
|
{
|
|
if ( m_bDying )
|
|
{
|
|
if ( m_pOuter->IsAlive() )
|
|
{
|
|
m_bDying = false;
|
|
}
|
|
else
|
|
{
|
|
*deathActivity = m_DeathActivity;
|
|
}
|
|
}
|
|
return m_bDying;
|
|
}
|
|
|
|
|
|
Activity CPlayerAnimState::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_pOuter->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 CPlayerAnimState::GetCurrentMaxGroundSpeed()
|
|
{
|
|
Activity act = GetCurrentMainSequenceActivity();
|
|
if ( act == ACT_CROUCHIDLE || act == ACT_RUN_CROUCH )
|
|
return MAX_CROUCHED_RUN_SPEED;
|
|
else
|
|
return MAX_STANDING_RUN_SPEED;
|
|
}
|
|
|
|
|
|
void CPlayerAnimState::ClearAnimationState()
|
|
{
|
|
m_bJumping = false;
|
|
m_bFiring = false;
|
|
m_bDying = false;
|
|
|
|
BaseClass::ClearAnimationState();
|
|
}
|
|
|
|
|
|
bool CPlayerAnimState::ShouldUpdateAnimState()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
float CPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
|
|
{
|
|
// Determine ideal playback rate
|
|
Vector vel;
|
|
GetOuterAbsVelocity( vel );
|
|
|
|
float flReturnValue = BaseClass::CalcMovementPlaybackRate( bIsMoving );
|
|
|
|
Activity eActivity = GetOuter()->GetSequenceActivity( GetOuter()->GetSequence() ) ;
|
|
|
|
if ( eActivity == ACT_RUN || eActivity == ACT_WALK || eActivity == ACT_CROUCH )
|
|
{
|
|
VectorNormalize( vel );
|
|
|
|
Vector vForward;
|
|
AngleVectors( GetOuter()->EyeAngles(), &vForward );
|
|
|
|
float flDot = DotProduct( vel, vForward );
|
|
|
|
if ( flDot < 0 )
|
|
{
|
|
flReturnValue *= -1;
|
|
}
|
|
}
|
|
|
|
return flReturnValue;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CPlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
|
|
{
|
|
VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyPitch" );
|
|
|
|
// Get pitch from v_angle
|
|
float flPitch = -m_flEyePitch;
|
|
if ( flPitch > 180.0f )
|
|
{
|
|
flPitch -= 360.0f;
|
|
}
|
|
flPitch = clamp( flPitch, -50, 45 );
|
|
|
|
// See if we have a blender for pitch
|
|
int pitch = GetOuter()->LookupPoseParameter( pStudioHdr, "XR" );
|
|
if ( pitch < 0 )
|
|
return;
|
|
|
|
GetOuter()->SetPoseParameter( pStudioHdr, pitch, flPitch );
|
|
g_flLastBodyPitch = flPitch;
|
|
}
|
|
|