|
|
//========= 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; }
|