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.
373 lines
8.0 KiB
373 lines
8.0 KiB
//========= 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; |
|
} |
|
|
|
|