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.
1454 lines
39 KiB
1454 lines
39 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "dod_playeranimstate.h" |
|
#include "base_playeranimstate.h" |
|
#include "tier0/vprof.h" |
|
#include "animation.h" |
|
#include "studio.h" |
|
#include "apparent_velocity_helper.h" |
|
#include "utldict.h" |
|
#include "weapon_dodbase.h" |
|
#include "dod_shareddefs.h" |
|
|
|
#ifdef CLIENT_DLL |
|
#include "c_dod_player.h" |
|
#include "engine/ivdebugoverlay.h" |
|
#include "filesystem.h" |
|
|
|
ConVar anim_showmainactivity( "anim_showmainactivity", "0", FCVAR_CHEAT, "Show the idle, walk, run, and/or sprint activities." ); |
|
#else |
|
#include "dod_player.h" |
|
#endif |
|
|
|
ConVar anim_showstate( "anim_showstate", "-1", FCVAR_CHEAT | FCVAR_REPLICATED, "Show the (client) animation state for the specified entity (-1 for none)." ); |
|
ConVar anim_showstatelog( "anim_showstatelog", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "1 to output anim_showstate to Msg(). 2 to store in AnimState.log. 3 for both." ); |
|
ConVar dod_bodyheightoffset( "dod_bodyheightoffset", "4", FCVAR_CHEAT | FCVAR_REPLICATED, "Deploy height offset." ); |
|
|
|
#define ANIMPART_STAND "stand" |
|
#define ANIMPART_PRONE "prone" |
|
#define ANIMPART_CROUCH "crouch" |
|
#define ANIMPART_SPRINT "sprint" |
|
#define ANIMPART_SANDBAG "sandbag" |
|
#define ANIMPART_BIPOD "bipod" |
|
|
|
// When moving this fast, he plays run anim. |
|
#define ARBITRARY_RUN_SPEED 300.0f |
|
#define DOD_BODYYAW_RATE 720.0f |
|
|
|
#define DOD_WALK_SPEED 60.0f |
|
#define DOD_RUN_SPEED 120.0f |
|
#define DOD_SPRINT_SPEED 260.0f |
|
|
|
class CDODPlayerAnimState : public CBasePlayerAnimState, public IDODPlayerAnimState |
|
{ |
|
public: |
|
|
|
DECLARE_CLASS( CDODPlayerAnimState, CBasePlayerAnimState ); |
|
friend IDODPlayerAnimState* CreatePlayerAnimState( CDODPlayer *pPlayer ); |
|
|
|
CDODPlayerAnimState(); |
|
|
|
virtual void ShowDebugInfo( void ); |
|
|
|
// 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 void ClearAnimationState(); |
|
virtual Activity CalcMainActivity(); |
|
virtual void Update( float eyeYaw, float eyePitch ); |
|
|
|
virtual void DebugShowAnimState( int iStartLine ); |
|
|
|
virtual int CalcAimLayerSequence( float *flCyle, float *flAimSequenceWeight, bool bForceIdle ) { return 0; } |
|
|
|
virtual float GetCurrentMaxGroundSpeed(); |
|
virtual void ComputeSequences( CStudioHdr *pStudioHdr ); |
|
virtual void ClearAnimationLayers(); |
|
|
|
virtual void RestartMainSequence(); |
|
virtual float CalcMovementPlaybackRate( bool *bIsMoving ); |
|
|
|
Activity TranslateActivity( Activity actDesired ); |
|
void CancelGestures( void ); |
|
|
|
protected: |
|
|
|
// Pose paramters. |
|
bool SetupPoseParameters( CStudioHdr *pStudioHdr ); |
|
virtual void ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr ); |
|
virtual void ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr ); |
|
virtual void ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr ); |
|
void ComputePoseParam_BodyHeight( CStudioHdr *pStudioHdr ); |
|
virtual void EstimateYaw( void ); |
|
void ConvergeYawAngles( float flGoalYaw, float flYawRate, float flDeltaTime, float &flCurrentYaw ); |
|
|
|
void ComputeFireSequence(); |
|
void ComputeDeployedSequence(); |
|
|
|
void ComputeGestureSequence( CStudioHdr *pStudioHdr ); |
|
|
|
void RestartGesture( int iGestureType, Activity act, bool bAutoKill = true ); |
|
|
|
void UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd, float flWeight = 1.0 ); |
|
|
|
void DebugShowAnimStateForPlayer( bool bIsServer ); |
|
void DebugShowEyeYaw( void ); |
|
|
|
// Client specific. |
|
#ifdef CLIENT_DLL |
|
|
|
// Debug. |
|
void DebugShowActivity( Activity activity ); |
|
|
|
#endif |
|
|
|
private: |
|
|
|
void InitDOD( CDODPlayer *pPlayer ); |
|
|
|
bool HandleJumping( Activity *idealActivity ); |
|
bool HandleProne( Activity *idealActivity ); |
|
bool HandleProneDown( CDODPlayer *pPlayer, Activity *idealActivity ); |
|
bool HandleProneUp( CDODPlayer *pPlayer, Activity *idealActivity ); |
|
bool HandleDucked( Activity *idealActivity ); |
|
|
|
bool IsGettingDown( CDODPlayer *pPlayer ); |
|
bool IsGettingUp( CDODPlayer *pPlayer ); |
|
|
|
CDODPlayer* GetOuterDOD() const; |
|
|
|
bool IsPlayingGesture( int type ) |
|
{ |
|
return ( m_bPlayingGesture && m_iGestureType == type ); |
|
} |
|
|
|
private: |
|
// Current state variables. |
|
bool m_bJumping; // Set on a jump event. |
|
float m_flJumpStartTime; |
|
bool m_bFirstJumpFrame; |
|
|
|
// These control the prone state _achine. |
|
bool m_bGettingDown; |
|
bool m_bGettingUp; |
|
bool m_bWasGoingProne; |
|
bool m_bWasGettingUp; |
|
|
|
// The single Gesture layer |
|
bool m_bPlayingGesture; |
|
bool m_bAutokillGesture; |
|
int m_iGestureSequence; |
|
float m_flGestureCycle; |
|
|
|
int m_iGestureType; |
|
|
|
enum |
|
{ |
|
GESTURE_NONE = -1, |
|
GESTURE_ATTACK1 = 0, |
|
GESTURE_ATTACK2, |
|
GESTURE_RELOAD, |
|
GESTURE_HAND_SIGNAL, |
|
GESTURE_FIDGET, |
|
GESTURE_PLANT, |
|
GESTURE_DEFUSE, |
|
}; |
|
|
|
// Pose parameters. |
|
bool m_bPoseParameterInit; |
|
float m_flEstimateYaw; |
|
float m_flEstimateVelocity; |
|
float m_flLastAimPitch; |
|
float m_flLastAimYaw; |
|
float m_flLastBodyHeight; |
|
float m_flLastAimTurnTime; |
|
Vector2D m_vecLastMoveYaw; |
|
int m_iMoveX; |
|
int m_iMoveY; |
|
int m_iAimYaw; |
|
int m_iAimPitch; |
|
int m_iBodyHeight; |
|
|
|
float m_flFireIdleTime; // Time that we drop our gun |
|
|
|
bool m_bLastDeployState; // true = last was deployed, false = last was not deployed |
|
|
|
DODWeaponID m_iLastWeaponID; // remember the weapon we were last using |
|
|
|
// Our DOD player pointer. |
|
CDODPlayer *m_pOuterDOD; |
|
}; |
|
|
|
|
|
IDODPlayerAnimState* CreatePlayerAnimState( CDODPlayer *pPlayer ) |
|
{ |
|
CDODPlayerAnimState *pState = new CDODPlayerAnimState; |
|
pState->InitDOD( pPlayer ); |
|
return pState; |
|
} |
|
|
|
|
|
// -------------------------------------------------------------------------------- // |
|
// CDODPlayerAnimState implementation. |
|
// -------------------------------------------------------------------------------- // |
|
|
|
CDODPlayerAnimState::CDODPlayerAnimState() |
|
{ |
|
m_bGettingDown = false; |
|
m_bGettingUp = false; |
|
m_bWasGoingProne = false; |
|
m_bWasGettingUp = false; |
|
|
|
m_pOuterDOD = NULL; |
|
|
|
m_bPoseParameterInit = false; |
|
m_flEstimateYaw = 0.0f; |
|
m_flLastAimPitch = 0.0f; |
|
m_flLastAimYaw = 0.0f; |
|
m_flLastBodyHeight = 0.0f; |
|
m_flLastAimTurnTime = 0.0f; |
|
m_vecLastMoveYaw.Init(); |
|
m_iMoveX = -1; |
|
m_iMoveY = -1; |
|
m_iAimYaw = -1; |
|
m_iAimPitch = -1; |
|
m_iBodyHeight = -1; |
|
} |
|
|
|
void CDODPlayerAnimState::InitDOD( CDODPlayer *pPlayer ) |
|
{ |
|
m_pOuterDOD = pPlayer; |
|
|
|
CModAnimConfig config; |
|
config.m_flMaxBodyYawDegrees = 45; |
|
config.m_LegAnimType = LEGANIM_GOLDSRC; |
|
config.m_bUseAimSequences = false; |
|
|
|
BaseClass::Init( pPlayer, config ); |
|
} |
|
|
|
|
|
void CDODPlayerAnimState::ClearAnimationState() |
|
{ |
|
m_bJumping = false; |
|
m_flFireIdleTime = 0; |
|
m_bLastDeployState = false; |
|
m_iLastWeaponID = WEAPON_NONE; |
|
CancelGestures(); |
|
BaseClass::ClearAnimationState(); |
|
} |
|
|
|
void CDODPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData ) |
|
{ |
|
if ( event == PLAYERANIMEVENT_FIRE_GUN ) |
|
{ |
|
RestartGesture( GESTURE_ATTACK1, ACT_RANGE_ATTACK1, false ); |
|
|
|
if( GetOuterDOD()->m_Shared.IsBazookaDeployed() ) |
|
{ |
|
m_flFireIdleTime = gpGlobals->curtime + 0.1; // don't hold this pose after firing |
|
} |
|
else |
|
{ |
|
// hold last frame of fire pose for 2 seconds ( if we are moving ) |
|
m_flFireIdleTime = gpGlobals->curtime + 2; |
|
} |
|
} |
|
if ( event == PLAYERANIMEVENT_SECONDARY_ATTACK ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_ATTACK2, ACT_RANGE_ATTACK2 ); |
|
} |
|
else if ( event == PLAYERANIMEVENT_RELOAD ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_RELOAD, ACT_RELOAD ); |
|
} |
|
else if ( event == PLAYERANIMEVENT_THROW_GRENADE ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_ATTACK1, ACT_RANGE_ATTACK1 ); |
|
} |
|
else if ( event == PLAYERANIMEVENT_ROLL_GRENADE ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_ATTACK2, ACT_RANGE_ATTACK2 ); |
|
} |
|
else if ( event == PLAYERANIMEVENT_JUMP ) |
|
{ |
|
// Play the jump animation. |
|
m_bJumping = true; |
|
m_bFirstJumpFrame = true; |
|
RestartMainSequence(); |
|
m_flJumpStartTime = gpGlobals->curtime; |
|
} |
|
else if ( event == PLAYERANIMEVENT_HANDSIGNAL ) |
|
{ |
|
CDODPlayer *pPlayer = GetOuterDOD(); |
|
if ( pPlayer && !( pPlayer->m_Shared.IsBazookaDeployed() || pPlayer->m_Shared.IsProne() || pPlayer->m_Shared.IsProneDeployed() || pPlayer->m_Shared.IsSniperZoomed() || pPlayer->m_Shared.IsSandbagDeployed() ) ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_HAND_SIGNAL, ACT_DOD_HS_IDLE ); |
|
} |
|
} |
|
else if ( event == PLAYERANIMEVENT_PLANT_TNT ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_PLANT, ACT_DOD_PLANT_TNT ); |
|
} |
|
else if ( event == PLAYERANIMEVENT_DEFUSE_TNT ) |
|
{ |
|
CancelGestures(); |
|
RestartGesture( GESTURE_DEFUSE, ACT_DOD_DEFUSE_TNT ); |
|
} |
|
} |
|
|
|
void CDODPlayerAnimState::ShowDebugInfo( void ) |
|
{ |
|
if ( anim_showstate.GetInt() == m_pOuter->entindex() ) |
|
{ |
|
DebugShowAnimStateForPlayer( m_pOuter->IsServer() ); |
|
} |
|
} |
|
|
|
|
|
void CDODPlayerAnimState::RestartMainSequence() |
|
{ |
|
CancelGestures(); |
|
|
|
BaseClass::RestartMainSequence(); |
|
} |
|
|
|
bool CDODPlayerAnimState::HandleJumping( Activity *idealActivity ) |
|
{ |
|
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(); |
|
} |
|
} |
|
} |
|
if ( m_bJumping ) |
|
{ |
|
*idealActivity = ACT_HOP; |
|
return true; |
|
} |
|
else |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle the prone up animation. |
|
//----------------------------------------------------------------------------- |
|
bool CDODPlayerAnimState::HandleProneDown( CDODPlayer *pPlayer, Activity *idealActivity ) |
|
{ |
|
if ( ( pPlayer->GetCycle() > 0.99f ) || ( pPlayer->m_Shared.IsProne() ) ) |
|
{ |
|
*idealActivity = ACT_PRONE_IDLE; |
|
if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED ) |
|
{ |
|
*idealActivity = ACT_PRONE_FORWARD; |
|
} |
|
RestartMainSequence(); |
|
|
|
m_bGettingDown = false; |
|
} |
|
else |
|
{ |
|
*idealActivity = ACT_GET_DOWN_STAND; |
|
if ( pPlayer->GetFlags() & FL_DUCKING ) |
|
{ |
|
*idealActivity = ACT_GET_DOWN_CROUCH; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle the prone up animation. |
|
//----------------------------------------------------------------------------- |
|
bool CDODPlayerAnimState::HandleProneUp( CDODPlayer *pPlayer, Activity *idealActivity ) |
|
{ |
|
if ( ( m_pOuter->GetCycle() > 0.99f ) || ( !pPlayer->m_Shared.IsGettingUpFromProne() ) ) |
|
{ |
|
m_bGettingUp = false; |
|
RestartMainSequence(); |
|
|
|
return false; |
|
} |
|
|
|
*idealActivity = ACT_GET_UP_STAND; |
|
if ( pPlayer->GetFlags() & FL_DUCKING ) |
|
{ |
|
*idealActivity = ACT_GET_UP_CROUCH; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle the prone animations. |
|
//----------------------------------------------------------------------------- |
|
bool CDODPlayerAnimState::HandleProne( Activity *idealActivity ) |
|
{ |
|
// Get the player. |
|
CDODPlayer *pPlayer = GetOuterDOD(); |
|
if ( !pPlayer ) |
|
return false; |
|
|
|
// Find the leading edge on going prone. |
|
bool bChange = pPlayer->m_Shared.IsGoingProne() && !m_bWasGoingProne; |
|
m_bWasGoingProne = pPlayer->m_Shared.IsGoingProne(); |
|
if ( bChange ) |
|
{ |
|
m_bGettingDown = true; |
|
RestartMainSequence(); |
|
} |
|
|
|
// Find the leading edge on getting up. |
|
bChange = pPlayer->m_Shared.IsGettingUpFromProne() && !m_bWasGettingUp; |
|
m_bWasGettingUp = pPlayer->m_Shared.IsGettingUpFromProne(); |
|
if ( bChange ) |
|
{ |
|
m_bGettingUp = true; |
|
RestartMainSequence(); |
|
} |
|
|
|
// Handle the transitions. |
|
if ( m_bGettingDown ) |
|
{ |
|
return HandleProneDown( pPlayer, idealActivity ); |
|
} |
|
else if ( m_bGettingUp ) |
|
{ |
|
return HandleProneUp( pPlayer, idealActivity ); |
|
} |
|
|
|
// Handle the prone state. |
|
if ( pPlayer->m_Shared.IsProne() ) |
|
{ |
|
*idealActivity = ACT_PRONE_IDLE; |
|
if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED ) |
|
{ |
|
*idealActivity = ACT_PRONE_FORWARD; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
bool CDODPlayerAnimState::HandleDucked( Activity *idealActivity ) |
|
{ |
|
if ( m_pOuter->GetFlags() & FL_DUCKING ) |
|
{ |
|
if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED ) |
|
*idealActivity = ACT_RUN_CROUCH; |
|
else |
|
*idealActivity = ACT_CROUCHIDLE; |
|
|
|
return true; |
|
} |
|
else |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
Activity CDODPlayerAnimState::CalcMainActivity() |
|
{ |
|
Activity idealActivity = ACT_IDLE; |
|
|
|
float flSpeed = GetOuterXYSpeed(); |
|
|
|
if ( HandleJumping( &idealActivity ) || |
|
HandleProne( &idealActivity ) || |
|
HandleDucked( &idealActivity ) ) |
|
{ |
|
// intentionally blank |
|
} |
|
else |
|
{ |
|
if ( flSpeed > MOVING_MINIMUM_SPEED ) |
|
{ |
|
if( flSpeed >= DOD_SPRINT_SPEED ) |
|
{ |
|
idealActivity = ACT_SPRINT; |
|
|
|
// If we sprint, cancel the fire idle time |
|
CancelGestures(); |
|
} |
|
else if( flSpeed >= DOD_WALK_SPEED ) |
|
idealActivity = ACT_RUN; |
|
else |
|
idealActivity = ACT_WALK; |
|
} |
|
} |
|
|
|
// Shouldn't be here but we need to ship - bazooka deployed reload/running check. |
|
if ( IsPlayingGesture( GESTURE_RELOAD ) ) |
|
{ |
|
if ( flSpeed >= DOD_RUN_SPEED && m_pOuterDOD->m_Shared.IsBazookaOnlyDeployed() ) |
|
{ |
|
CancelGestures(); |
|
} |
|
} |
|
|
|
ShowDebugInfo(); |
|
|
|
// Client specific. |
|
#ifdef CLIENT_DLL |
|
|
|
if ( anim_showmainactivity.GetBool() ) |
|
{ |
|
DebugShowActivity( idealActivity ); |
|
} |
|
|
|
#endif |
|
|
|
return idealActivity; |
|
} |
|
|
|
void CDODPlayerAnimState::CancelGestures( void ) |
|
{ |
|
m_bPlayingGesture = false; |
|
m_iGestureType = GESTURE_NONE; |
|
|
|
#ifdef CLIENT_DLL |
|
m_iGestureSequence = -1; |
|
#else |
|
m_pOuter->RemoveAllGestures(); |
|
#endif |
|
} |
|
|
|
void CDODPlayerAnimState::RestartGesture( int iGestureType, Activity act, bool bAutoKill /* = true */ ) |
|
{ |
|
Activity idealActivity = TranslateActivity( act ); |
|
m_bPlayingGesture = true; |
|
m_iGestureType = iGestureType; |
|
|
|
#ifdef CLIENT_DLL |
|
m_iGestureSequence = m_pOuter->SelectWeightedSequence( idealActivity ); |
|
|
|
if( m_iGestureSequence == -1 ) |
|
{ |
|
m_bPlayingGesture = false; |
|
} |
|
|
|
m_flGestureCycle = 0.0f; |
|
m_bAutokillGesture = bAutoKill; |
|
#else |
|
m_pOuterDOD->RestartGesture( idealActivity, true, bAutoKill ); |
|
#endif |
|
} |
|
|
|
Activity CDODPlayerAnimState::TranslateActivity( Activity actDesired ) |
|
{ |
|
Activity idealActivity = actDesired; |
|
|
|
if ( m_pOuterDOD->m_Shared.IsSandbagDeployed() ) |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_IDLE: |
|
idealActivity = ACT_DOD_DEPLOYED; |
|
break; |
|
case ACT_RANGE_ATTACK1: |
|
idealActivity = ACT_DOD_PRIMARYATTACK_DEPLOYED; |
|
break; |
|
case ACT_RELOAD: |
|
idealActivity = ACT_DOD_RELOAD_DEPLOYED; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
else if ( m_pOuterDOD->m_Shared.IsProneDeployed() ) |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_PRONE_IDLE: |
|
idealActivity = ACT_DOD_PRONE_DEPLOYED; |
|
break; |
|
case ACT_RANGE_ATTACK1: |
|
idealActivity = ACT_DOD_PRIMARYATTACK_PRONE_DEPLOYED; |
|
break; |
|
case ACT_RELOAD: |
|
idealActivity = ACT_DOD_RELOAD_PRONE_DEPLOYED; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
else if ( m_pOuterDOD->m_Shared.IsSniperZoomed() || m_pOuterDOD->m_Shared.IsBazookaDeployed() ) |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_IDLE: |
|
idealActivity = ACT_DOD_IDLE_ZOOMED; |
|
break; |
|
case ACT_WALK: |
|
idealActivity = ACT_DOD_WALK_ZOOMED; |
|
break; |
|
case ACT_CROUCHIDLE: |
|
idealActivity = ACT_DOD_CROUCH_ZOOMED; |
|
break; |
|
case ACT_RUN_CROUCH: |
|
idealActivity = ACT_DOD_CROUCHWALK_ZOOMED; |
|
break; |
|
case ACT_PRONE_IDLE: |
|
idealActivity = ACT_DOD_PRONE_ZOOMED; |
|
break; |
|
case ACT_PRONE_FORWARD: |
|
idealActivity = ACT_DOD_PRONE_FORWARD_ZOOMED; |
|
break; |
|
case ACT_RANGE_ATTACK1: |
|
if ( m_pOuterDOD->m_Shared.IsSniperZoomed() ) |
|
{ |
|
if( m_pOuterDOD->m_Shared.IsProne() ) |
|
idealActivity = ACT_DOD_PRIMARYATTACK_PRONE; |
|
} |
|
break; |
|
case ACT_RELOAD: |
|
if ( m_pOuterDOD->m_Shared.IsBazookaDeployed() ) |
|
{ |
|
if( m_pOuterDOD->m_Shared.IsProne() ) |
|
{ |
|
idealActivity = ACT_DOD_RELOAD_PRONE_DEPLOYED; |
|
} |
|
else |
|
{ |
|
idealActivity = ACT_DOD_RELOAD_DEPLOYED; |
|
} |
|
} |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
else if ( m_pOuterDOD->m_Shared.IsProne() ) |
|
{ |
|
// translate prone shooting, reload, handsignal |
|
|
|
switch( idealActivity ) |
|
{ |
|
case ACT_RANGE_ATTACK1: |
|
idealActivity = ACT_DOD_PRIMARYATTACK_PRONE; |
|
break; |
|
case ACT_RANGE_ATTACK2: |
|
idealActivity = ACT_DOD_SECONDARYATTACK_PRONE; |
|
break; |
|
case ACT_RELOAD: |
|
idealActivity = ACT_DOD_RELOAD_PRONE; |
|
break; |
|
default: |
|
break; |
|
} |
|
} |
|
else if ( m_pOuter->GetFlags() & FL_DUCKING ) |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_RANGE_ATTACK1: |
|
idealActivity = ACT_DOD_PRIMARYATTACK_CROUCH; |
|
break; |
|
case ACT_RANGE_ATTACK2: |
|
idealActivity = ACT_DOD_SECONDARYATTACK_CROUCH; |
|
break; |
|
case ACT_DOD_HS_IDLE: |
|
idealActivity = ACT_DOD_HS_CROUCH; |
|
break; |
|
} |
|
} |
|
|
|
// Are our guns at fire or rest? |
|
if ( m_flFireIdleTime > gpGlobals->curtime ) |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_IDLE: idealActivity = ACT_DOD_STAND_AIM; break; |
|
case ACT_CROUCHIDLE: idealActivity = ACT_DOD_CROUCH_AIM; break; |
|
case ACT_RUN_CROUCH: idealActivity = ACT_DOD_CROUCHWALK_AIM; break; |
|
case ACT_WALK: idealActivity = ACT_DOD_WALK_AIM; break; |
|
case ACT_RUN: idealActivity = ACT_DOD_RUN_AIM; break; |
|
default: break; |
|
} |
|
} |
|
else |
|
{ |
|
switch( idealActivity ) |
|
{ |
|
case ACT_IDLE: idealActivity = ACT_DOD_STAND_IDLE; break; |
|
case ACT_CROUCHIDLE: idealActivity = ACT_DOD_CROUCH_IDLE; break; |
|
case ACT_RUN_CROUCH: idealActivity = ACT_DOD_CROUCHWALK_IDLE; break; |
|
case ACT_WALK: idealActivity = ACT_DOD_WALK_IDLE; break; |
|
case ACT_RUN: idealActivity = ACT_DOD_RUN_IDLE; break; |
|
default: break; |
|
} |
|
} |
|
|
|
return m_pOuterDOD->TranslateActivity( idealActivity ); |
|
} |
|
|
|
CDODPlayer* CDODPlayerAnimState::GetOuterDOD() const |
|
{ |
|
return m_pOuterDOD; |
|
} |
|
|
|
float CDODPlayerAnimState::GetCurrentMaxGroundSpeed() |
|
{ |
|
return PLAYER_SPEED_SPRINT; |
|
} |
|
|
|
float CDODPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving ) |
|
{ |
|
if( ( GetCurrentMainSequenceActivity() == ACT_GET_UP_STAND ) || ( GetCurrentMainSequenceActivity() == ACT_GET_DOWN_STAND ) || |
|
( GetCurrentMainSequenceActivity() == ACT_GET_UP_CROUCH ) || ( GetCurrentMainSequenceActivity() == ACT_GET_DOWN_CROUCH ) ) |
|
{ |
|
// We don't want to change the playback speed of these, even if we move. |
|
*bIsMoving = false; |
|
return 1.0; |
|
} |
|
|
|
// it would be a good idea to ramp up from 0.5 to 1.0 as they go from stop to moveing, it looks more natural. |
|
*bIsMoving = true; |
|
return 1.0; |
|
} |
|
|
|
void CDODPlayerAnimState::DebugShowAnimState( int iStartLine ) |
|
{ |
|
#ifdef CLIENT_DLL |
|
engine->Con_NPrintf( iStartLine++, "getting down: %s\n", m_bGettingDown ? "yes" : "no" ); |
|
engine->Con_NPrintf( iStartLine++, "getting up: %s\n", m_bGettingUp ? "yes" : "no" ); |
|
#endif |
|
|
|
BaseClass::DebugShowAnimState( iStartLine ); |
|
} |
|
|
|
void CDODPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) |
|
{ |
|
// Reset some things if we're changed weapons |
|
// do this before ComputeSequences |
|
CWeaponDODBase *pWeapon = GetOuterDOD()->m_Shared.GetActiveDODWeapon(); |
|
if ( pWeapon ) |
|
{ |
|
if( pWeapon->GetWeaponID() != m_iLastWeaponID ) |
|
{ |
|
CancelGestures(); |
|
m_iLastWeaponID = pWeapon->GetWeaponID(); |
|
m_flFireIdleTime = 0; |
|
} |
|
} |
|
|
|
BaseClass::ComputeSequences( pStudioHdr ); |
|
|
|
if( !m_bGettingDown && !m_bGettingUp ) |
|
{ |
|
ComputeFireSequence(); |
|
|
|
#ifdef CLIENT_DLL |
|
|
|
ComputeGestureSequence( pStudioHdr ); |
|
|
|
// get the weapon's swap criteria ( reload? attack? deployed? deployed reload? ) |
|
// and determine whether we should use alt model or not |
|
|
|
CWeaponDODBase *pWeapon = GetOuterDOD()->m_Shared.GetActiveDODWeapon(); |
|
if ( pWeapon ) |
|
{ |
|
int iCurrentState = ALTWPN_CRITERIA_NONE; |
|
|
|
if( m_bPlayingGesture && m_iGestureType == GESTURE_ATTACK1 ) |
|
iCurrentState |= ALTWPN_CRITERIA_FIRING; |
|
|
|
else if( m_bPlayingGesture && m_iGestureType == GESTURE_RELOAD ) |
|
iCurrentState |= ALTWPN_CRITERIA_RELOADING; |
|
|
|
if( m_pOuterDOD->m_Shared.IsProne() ) |
|
iCurrentState |= ALTWPN_CRITERIA_PRONE; |
|
|
|
// always use default model while proning or hand signal |
|
if( !IsPlayingGesture( GESTURE_HAND_SIGNAL ) && |
|
!IsPlayingGesture( GESTURE_FIDGET ) && |
|
!m_bGettingDown && |
|
!m_bGettingUp ) |
|
{ |
|
pWeapon->CheckForAltWeapon( iCurrentState ); |
|
} |
|
else |
|
{ |
|
pWeapon->SetUseAltModel( false ); |
|
} |
|
} |
|
#endif |
|
} |
|
} |
|
|
|
#define GESTURE_LAYER AIMSEQUENCE_LAYER |
|
#define NUM_LAYERS_WANTED (GESTURE_LAYER + 1) |
|
|
|
void CDODPlayerAnimState::ClearAnimationLayers() |
|
{ |
|
if ( !m_pOuter ) |
|
return; |
|
|
|
m_pOuter->SetNumAnimOverlays( NUM_LAYERS_WANTED ); |
|
for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ ) |
|
{ |
|
m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS ); |
|
} |
|
} |
|
|
|
void CDODPlayerAnimState::ComputeFireSequence( void ) |
|
{ |
|
// Hold the shoot pose for a time after firing, unless we stand still |
|
if( m_flFireIdleTime < gpGlobals->curtime && |
|
IsPlayingGesture( GESTURE_ATTACK1 ) && |
|
GetOuterXYSpeed() > MOVING_MINIMUM_SPEED ) |
|
{ |
|
CancelGestures(); |
|
} |
|
|
|
if( GetOuterDOD()->m_Shared.IsInMGDeploy() != m_bLastDeployState ) |
|
{ |
|
CancelGestures(); |
|
|
|
m_bLastDeployState = GetOuterDOD()->m_Shared.IsInMGDeploy(); |
|
} |
|
} |
|
|
|
void CDODPlayerAnimState::ComputeGestureSequence( CStudioHdr *pStudioHdr ) |
|
{ |
|
UpdateLayerSequenceGeneric( pStudioHdr, GESTURE_LAYER, m_bPlayingGesture, m_flGestureCycle, m_iGestureSequence, !m_bAutokillGesture ); |
|
} |
|
|
|
void CDODPlayerAnimState::UpdateLayerSequenceGeneric( CStudioHdr *pStudioHdr, int iLayer, bool &bEnabled, float &flCurCycle, int &iSequence, bool bWaitAtEnd, float flWeight /* = 1.0 */ ) |
|
{ |
|
if ( !bEnabled ) |
|
return; |
|
|
|
if( flCurCycle > 1.0 ) |
|
flCurCycle = 1.0; |
|
|
|
// Increment the fire sequence's cycle. |
|
flCurCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, iSequence ) * gpGlobals->frametime; |
|
if ( flCurCycle > 1 ) |
|
{ |
|
if ( bWaitAtEnd ) |
|
{ |
|
flCurCycle = 1; |
|
} |
|
else |
|
{ |
|
// Not firing anymore. |
|
bEnabled = false; |
|
iSequence = 0; |
|
return; |
|
} |
|
} |
|
|
|
CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iLayer ); |
|
|
|
pLayer->m_flCycle = flCurCycle; |
|
pLayer->m_nSequence = iSequence; |
|
|
|
pLayer->m_flPlaybackRate = 1.0; |
|
pLayer->m_flWeight = flWeight; |
|
pLayer->m_nOrder = iLayer; |
|
|
|
} |
|
|
|
extern ConVar mp_facefronttime; |
|
extern ConVar mp_feetyawrate; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::Update( float eyeYaw, float eyePitch ) |
|
{ |
|
// Profile the animation update. |
|
VPROF( "CDODPlayerAnimState::Update" ); |
|
|
|
// Get the studio header for the player. |
|
CStudioHdr *pStudioHdr = GetOuterDOD()->GetModelPtr(); |
|
if ( !pStudioHdr ) |
|
return; |
|
|
|
// Check to see if we should be updating the animation state - dead, ragdolled? |
|
if ( !ShouldUpdateAnimState() ) |
|
{ |
|
ClearAnimationState(); |
|
return; |
|
} |
|
|
|
// Store the eye angles. |
|
m_flEyeYaw = AngleNormalize( eyeYaw ); |
|
m_flEyePitch = AngleNormalize( eyePitch ); |
|
|
|
// Clear animation overlays because we're about to completely reconstruct them. |
|
ClearAnimationLayers(); |
|
|
|
// Compute the player sequences. |
|
ComputeSequences( pStudioHdr ); |
|
|
|
if ( SetupPoseParameters( pStudioHdr ) ) |
|
{ |
|
// Pose parameter - what direction are the player's legs running in. |
|
ComputePoseParam_MoveYaw( pStudioHdr ); |
|
|
|
// Pose parameter - Torso aiming (up/down). |
|
ComputePoseParam_AimPitch( pStudioHdr ); |
|
|
|
// Pose parameter - Torso aiming (rotation). |
|
ComputePoseParam_AimYaw( pStudioHdr ); |
|
|
|
// Pose parameter - Body Height (torso elevation). |
|
ComputePoseParam_BodyHeight( pStudioHdr ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CDODPlayerAnimState::SetupPoseParameters( CStudioHdr *pStudioHdr ) |
|
{ |
|
// Check to see if this has already been done. |
|
if ( m_bPoseParameterInit ) |
|
return true; |
|
|
|
// Save off the pose parameter indices. |
|
if ( !pStudioHdr ) |
|
return false; |
|
|
|
// Look for the movement blenders. |
|
m_iMoveX = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "move_x" ); |
|
m_iMoveY = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "move_y" ); |
|
if ( ( m_iMoveX < 0 ) || ( m_iMoveY < 0 ) ) |
|
return false; |
|
|
|
// Look for the aim pitch blender. |
|
m_iAimPitch = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_pitch" ); |
|
if ( m_iAimPitch < 0 ) |
|
return false; |
|
|
|
// Look for aim yaw blender. |
|
m_iAimYaw = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_yaw" ); |
|
if ( m_iAimYaw < 0 ) |
|
return false; |
|
|
|
// Look for the body height blender. |
|
m_iBodyHeight = GetOuterDOD()->LookupPoseParameter( pStudioHdr, "body_height" ); |
|
if ( m_iBodyHeight < 0 ) |
|
return false; |
|
|
|
m_bPoseParameterInit = true; |
|
|
|
return true; |
|
} |
|
|
|
#define DOD_MOVEMENT_ERROR_LIMIT 1.0 |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr ) |
|
{ |
|
// Check to see if we are deployed or prone. |
|
if( GetOuterDOD()->m_Shared.IsInMGDeploy() || GetOuterDOD()->m_Shared.IsProne() ) |
|
{ |
|
// Set the 9-way blend movement pose parameters. |
|
Vector2D vecCurrentMoveYaw( 0.0f, 0.0f ); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x ); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y ); |
|
|
|
m_vecLastMoveYaw = vecCurrentMoveYaw; |
|
|
|
#if 0 |
|
// Rotate the entire body instantly. |
|
m_flGoalFeetYaw = AngleNormalize( m_flEyeYaw ); |
|
m_flCurrentFeetYaw = m_flGoalFeetYaw; |
|
m_flLastTurnTime = gpGlobals->curtime; |
|
|
|
// Rotate entire body into position. |
|
m_angRender[YAW] = m_flCurrentFeetYaw; |
|
m_angRender[PITCH] = m_angRender[ROLL] = 0; |
|
|
|
SetOuterBodyYaw( m_flCurrentFeetYaw ); |
|
g_flLastBodyYaw = m_flCurrentFeetYaw; |
|
#endif |
|
} |
|
else |
|
{ |
|
// Get the estimated movement yaw. |
|
EstimateYaw(); |
|
|
|
// Get the view yaw. |
|
float flAngle = AngleNormalize( m_flEyeYaw ); |
|
|
|
// rotate movement into local reference frame |
|
float flYaw = flAngle - m_flEstimateYaw; |
|
flYaw = AngleNormalize( -flYaw ); |
|
|
|
// Get the current speed the character is running. |
|
Vector vecEstVelocity; |
|
vecEstVelocity.x = cos( DEG2RAD( flYaw ) ) * m_flEstimateVelocity; |
|
vecEstVelocity.y = sin( DEG2RAD( flYaw ) ) * m_flEstimateVelocity; |
|
|
|
Vector2D vecCurrentMoveYaw( 0.0f, 0.0f ); |
|
// set the pose parameters to the correct direction, but not value |
|
if ( vecEstVelocity.x != 0.0f && fabs( vecEstVelocity.x ) > fabs( vecEstVelocity.y ) ) |
|
{ |
|
vecCurrentMoveYaw.x = (vecEstVelocity.x < 0.0) ? -1.0 : 1.0; |
|
vecCurrentMoveYaw.y = vecEstVelocity.y / fabs( vecEstVelocity.x ); |
|
} |
|
else if (vecEstVelocity.y != 0.0f) |
|
{ |
|
vecCurrentMoveYaw.y = (vecEstVelocity.y < 0.0) ? -1.0 : 1.0; |
|
vecCurrentMoveYaw.x = vecEstVelocity.x / fabs( vecEstVelocity.y ); |
|
} |
|
|
|
#ifndef CLIENT_DLL |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x ); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y ); |
|
#else |
|
|
|
// refine pose parameters to be more accurate |
|
int i = 0; |
|
float dx, dy; |
|
Vector vecAnimVelocity; |
|
|
|
/* |
|
if ( m_pOuter->entindex() == 2 ) |
|
{ |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x ); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y ); |
|
GetOuterDOD()->GetBlendedLinearVelocity( &vecAnimVelocity ); |
|
DevMsgRT("(%.2f) %.3f : (%.2f) %.3f\n", vecAnimVelocity.x, vecCurrentMoveYaw.x, vecAnimVelocity.y, vecCurrentMoveYaw.y ); |
|
} |
|
*/ |
|
|
|
bool retry = true; |
|
do |
|
{ |
|
// Set the 9-way blend movement pose parameters. |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x ); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y ); |
|
|
|
GetOuterDOD()->GetBlendedLinearVelocity( &vecAnimVelocity ); |
|
|
|
// adjust X pose parameter based on movement error |
|
if (fabs( vecAnimVelocity.x ) > 0.001) |
|
{ |
|
vecCurrentMoveYaw.x *= vecEstVelocity.x / vecAnimVelocity.x; |
|
} |
|
else |
|
{ |
|
vecCurrentMoveYaw.x = 0; |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveX, vecCurrentMoveYaw.x ); |
|
} |
|
// adjust Y pose parameter based on movement error |
|
if (fabs( vecAnimVelocity.y ) > 0.001) |
|
{ |
|
vecCurrentMoveYaw.y *= vecEstVelocity.y / vecAnimVelocity.y; |
|
} |
|
else |
|
{ |
|
vecCurrentMoveYaw.y = 0; |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iMoveY, vecCurrentMoveYaw.y ); |
|
} |
|
|
|
dx = vecEstVelocity.x - vecAnimVelocity.x; |
|
dy = vecEstVelocity.y - vecAnimVelocity.y; |
|
|
|
retry = (vecCurrentMoveYaw.x < 1.0 && vecCurrentMoveYaw.x > -1.0) && (dx < -DOD_MOVEMENT_ERROR_LIMIT || dx > DOD_MOVEMENT_ERROR_LIMIT); |
|
retry = retry || ((vecCurrentMoveYaw.y < 1.0 && vecCurrentMoveYaw.y > -1.0) && (dy < -DOD_MOVEMENT_ERROR_LIMIT || dy > DOD_MOVEMENT_ERROR_LIMIT)); |
|
|
|
} while (i++ < 5 && retry); |
|
|
|
/* |
|
if ( m_pOuter->entindex() == 2 ) |
|
{ |
|
DevMsgRT("%d(%.2f : %.2f) %.3f : (%.2f : %.2f) %.3f\n", |
|
i, |
|
vecEstVelocity.x, vecAnimVelocity.x, vecCurrentMoveYaw.x, |
|
vecEstVelocity.y, vecAnimVelocity.y, vecCurrentMoveYaw.y ); |
|
} |
|
*/ |
|
#endif |
|
|
|
m_vecLastMoveYaw = vecCurrentMoveYaw; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::EstimateYaw( void ) |
|
{ |
|
// Get the frame time. |
|
float flDeltaTime = gpGlobals->frametime; |
|
if ( flDeltaTime == 0.0f ) |
|
{ |
|
// FIXME: why does this short circuit? |
|
m_flEstimateVelocity = 0.0; |
|
m_flEstimateYaw = 0.0; |
|
return; |
|
} |
|
|
|
// Get the player's velocity and angles. |
|
Vector vecEstVelocity; |
|
GetOuterAbsVelocity( vecEstVelocity ); |
|
QAngle angles = GetOuterDOD()->GetLocalAngles(); |
|
|
|
// If we are not moving, sync up the feet and eyes slowly. |
|
if ( vecEstVelocity.x == 0.0f && vecEstVelocity.y == 0.0f ) |
|
{ |
|
float flYawDelta = angles[YAW] - m_flEstimateYaw; |
|
flYawDelta = AngleNormalize( flYawDelta ); |
|
|
|
if ( flDeltaTime < 0.25f ) |
|
{ |
|
flYawDelta *= ( flDeltaTime * 4.0f ); |
|
} |
|
else |
|
{ |
|
flYawDelta *= flDeltaTime; |
|
} |
|
|
|
m_flEstimateVelocity = 0.0; |
|
m_flEstimateYaw += flYawDelta; |
|
AngleNormalize( m_flEstimateYaw ); |
|
} |
|
else |
|
{ |
|
m_flEstimateVelocity = vecEstVelocity.Length2D(); |
|
m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI ); |
|
m_flEstimateYaw = clamp( m_flEstimateYaw, -180.0f, 180.0f ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr ) |
|
{ |
|
// Get the view pitch. |
|
float flAimPitch = m_flEyePitch; |
|
|
|
// Lock pitch at 0 if a reload gesture is playing |
|
#ifdef CLIENT_DLL |
|
if ( IsPlayingGesture( GESTURE_RELOAD ) ) |
|
flAimPitch = 0; |
|
#else |
|
Activity idealActivity = TranslateActivity( ACT_RELOAD ); |
|
|
|
if ( m_pOuter->IsPlayingGesture( idealActivity ) ) |
|
flAimPitch = 0; |
|
#endif |
|
|
|
// Set the aim pitch pose parameter and save. |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iAimPitch, -flAimPitch ); |
|
m_flLastAimPitch = flAimPitch; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::ComputePoseParam_AimYaw( CStudioHdr *pStudioHdr ) |
|
{ |
|
// Get the movement velocity. |
|
Vector vecVelocity; |
|
GetOuterAbsVelocity( vecVelocity ); |
|
|
|
// Check to see if we are moving. |
|
bool bMoving = ( vecVelocity.Length() > 1.0f ) ? true : false; |
|
|
|
// Check our prone and deployed state. |
|
bool bDeployed = GetOuterDOD()->m_Shared.IsSandbagDeployed() || GetOuterDOD()->m_Shared.IsProneDeployed(); |
|
bool bProne = GetOuterDOD()->m_Shared.IsProne(); |
|
|
|
// If we are moving or are prone and undeployed. |
|
if ( bMoving || ( bProne && !bDeployed ) ) |
|
{ |
|
// The feet match the eye direction when moving - the move yaw takes care of the rest. |
|
m_flGoalFeetYaw = m_flEyeYaw; |
|
} |
|
// Else if we are not moving. |
|
else |
|
{ |
|
// Initialize the feet. |
|
if ( m_flLastAimTurnTime <= 0.0f ) |
|
{ |
|
m_flGoalFeetYaw = m_flEyeYaw; |
|
m_flCurrentFeetYaw = m_flEyeYaw; |
|
m_flLastAimTurnTime = gpGlobals->curtime; |
|
} |
|
// Make sure the feet yaw isn't too far out of sync with the eye yaw. |
|
// TODO: Do something better here! |
|
else |
|
{ |
|
float flYawDelta = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw ); |
|
|
|
if ( bDeployed ) |
|
{ |
|
if ( fabs( flYawDelta ) > 20.0f ) |
|
{ |
|
float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f; |
|
m_flGoalFeetYaw += ( 20.0f * flSide ); |
|
} |
|
} |
|
else |
|
{ |
|
if ( fabs( flYawDelta ) > m_AnimConfig.m_flMaxBodyYawDegrees ) |
|
{ |
|
float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f; |
|
m_flGoalFeetYaw += ( m_AnimConfig.m_flMaxBodyYawDegrees * flSide ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Fix up the feet yaw. |
|
m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); |
|
if ( m_flGoalFeetYaw != m_flCurrentFeetYaw ) |
|
{ |
|
ConvergeYawAngles( m_flGoalFeetYaw, DOD_BODYYAW_RATE, gpGlobals->frametime, m_flCurrentFeetYaw ); |
|
m_flLastAimTurnTime = gpGlobals->curtime; |
|
} |
|
|
|
// Rotate the body into position. |
|
m_angRender[YAW] = m_flCurrentFeetYaw; |
|
|
|
// Find the aim(torso) yaw base on the eye and feet yaws. |
|
float flAimYaw = m_flEyeYaw - m_flCurrentFeetYaw; |
|
flAimYaw = AngleNormalize( flAimYaw ); |
|
|
|
// Set the aim yaw and save. |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iAimYaw, -flAimYaw ); |
|
m_flLastAimYaw = flAimYaw; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::ConvergeYawAngles( float flGoalYaw, float flYawRate, float flDeltaTime, float &flCurrentYaw ) |
|
{ |
|
#define FADE_TURN_DEGREES 60.0f |
|
|
|
// Find the yaw delta. |
|
float flDeltaYaw = flGoalYaw - flCurrentYaw; |
|
float flDeltaYawAbs = fabs( flDeltaYaw ); |
|
flDeltaYaw = AngleNormalize( flDeltaYaw ); |
|
|
|
// Always do at least a bit of the turn (1%). |
|
float flScale = 1.0f; |
|
flScale = flDeltaYawAbs / FADE_TURN_DEGREES; |
|
flScale = clamp( flScale, 0.01f, 1.0f ); |
|
|
|
float flYaw = flYawRate * flDeltaTime * flScale; |
|
if ( flDeltaYawAbs < flYaw ) |
|
{ |
|
flCurrentYaw = flGoalYaw; |
|
} |
|
else |
|
{ |
|
float flSide = ( flDeltaYaw < 0.0f ) ? -1.0f : 1.0f; |
|
flCurrentYaw += ( flYaw * flSide ); |
|
} |
|
|
|
flCurrentYaw = AngleNormalize( flCurrentYaw ); |
|
|
|
#undef FADE_TURN_DEGREES |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::ComputePoseParam_BodyHeight( CStudioHdr *pStudioHdr ) |
|
{ |
|
if( m_pOuterDOD->m_Shared.IsSandbagDeployed() ) |
|
{ |
|
// float flHeight = m_pOuterDOD->m_Shared.GetDeployedHeight() - 4.0f; |
|
float flHeight = m_pOuterDOD->m_Shared.GetDeployedHeight() - dod_bodyheightoffset.GetFloat(); |
|
GetOuter()->SetPoseParameter( pStudioHdr, m_iBodyHeight, flHeight ); |
|
m_flLastBodyHeight = flHeight; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void Anim_StateLog( const char *pMsg, ... ) |
|
{ |
|
// Format the string. |
|
char str[4096]; |
|
va_list marker; |
|
va_start( marker, pMsg ); |
|
Q_vsnprintf( str, sizeof( str ), pMsg, marker ); |
|
va_end( marker ); |
|
|
|
// Log it? |
|
if ( anim_showstatelog.GetInt() == 1 || anim_showstatelog.GetInt() == 3 ) |
|
{ |
|
Msg( "%s", str ); |
|
} |
|
|
|
if ( anim_showstatelog.GetInt() > 1 ) |
|
{ |
|
// static FileHandle_t hFile = filesystem->Open( "AnimState.log", "wt" ); |
|
// filesystem->FPrintf( hFile, "%s", str ); |
|
// filesystem->Flush( hFile ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void Anim_StatePrintf( int iLine, const char *pMsg, ... ) |
|
{ |
|
// Format the string. |
|
char str[4096]; |
|
va_list marker; |
|
va_start( marker, pMsg ); |
|
Q_vsnprintf( str, sizeof( str ), pMsg, marker ); |
|
va_end( marker ); |
|
|
|
// Show it with Con_NPrintf. |
|
engine->Con_NPrintf( iLine, "%s", str ); |
|
|
|
// Log it. |
|
Anim_StateLog( "%s\n", str ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::DebugShowAnimStateForPlayer( bool bIsServer ) |
|
{ |
|
// Get the player's velocity. |
|
Vector vecVelocity; |
|
GetOuterAbsVelocity( vecVelocity ); |
|
|
|
// Start animation state logging. |
|
int iLine = 5; |
|
if ( bIsServer ) |
|
{ |
|
iLine = 12; |
|
} |
|
// Anim_StateLog( "-------------%s: frame %d -----------------\n", bIsServer ? "Server" : "Client", gpGlobals->framecount ); |
|
Anim_StatePrintf( iLine++, "-------------%s: frame %d -----------------\n", bIsServer ? "Server" : "Client", gpGlobals->framecount ); |
|
|
|
// Write out the main sequence and its data. |
|
Anim_StatePrintf( iLine++, "Main: %s, Cycle: %.2f\n", GetSequenceName( GetOuter()->GetModelPtr(), GetOuter()->GetSequence() ), GetOuter()->GetCycle() ); |
|
|
|
// Write out the layers and their data. |
|
for ( int iAnim = 0; iAnim < GetOuter()->GetNumAnimOverlays(); ++iAnim ) |
|
{ |
|
CAnimationLayer *pLayer = GetOuter()->GetAnimOverlay( iAnim ); |
|
if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) ) |
|
{ |
|
Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetOuter()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle ); |
|
} |
|
} |
|
|
|
// Write out the speed data. |
|
Anim_StatePrintf( iLine++, "Time: %.2f, Speed: %.2f, MaxSpeed: %.2f", gpGlobals->curtime, vecVelocity.Length2D(), GetCurrentMaxGroundSpeed() ); |
|
|
|
// Write out the 9-way blend data. |
|
Anim_StatePrintf( iLine++, "EntityYaw: %.2f, AimYaw: %.2f, AimPitch: %.2f, MoveX: %.2f, MoveY: %.2f Body: %.2f", m_angRender[YAW], m_flLastAimYaw, m_flLastAimPitch, m_vecLastMoveYaw.x, m_vecLastMoveYaw.y, m_flLastBodyHeight ); |
|
|
|
// Anim_StateLog( "--------------------------------------------\n\n" ); |
|
Anim_StatePrintf( iLine++, "--------------------------------------------\n\n" ); |
|
|
|
DebugShowEyeYaw(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::DebugShowEyeYaw( void ) |
|
{ |
|
#ifdef _NDEBUG |
|
|
|
float flBaseSize = 10; |
|
float flHeight = 80; |
|
|
|
Vector vecPos = GetOuter()->GetAbsOrigin() + Vector( 0.0f, 0.0f, 3.0f ); |
|
QAngle angles( 0.0f, 0.0f, 0.0f ); |
|
|
|
angles[YAW] = m_flEyeYaw; |
|
|
|
Vector vecForward, vecRight, vecUp; |
|
AngleVectors( angles, &vecForward, &vecRight, &vecUp ); |
|
|
|
// Draw a red triangle on the ground for the eye yaw. |
|
debugoverlay->AddTriangleOverlay( ( vecPos + vecRight * flBaseSize / 2.0f ), |
|
( vecPos - vecRight * flBaseSize / 2.0f ), |
|
( vecPos + vecForward * flHeight, 255, 0, 0, 255, false, 0.01f ); |
|
|
|
#endif |
|
} |
|
|
|
// Client specific debug functions. |
|
#ifdef CLIENT_DLL |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CDODPlayerAnimState::DebugShowActivity( Activity activity ) |
|
{ |
|
#ifdef _DEBUG |
|
|
|
const char *pszActivity = "other"; |
|
|
|
switch( activity ) |
|
{ |
|
case ACT_IDLE: |
|
{ |
|
pszActivity = "idle"; |
|
break; |
|
} |
|
case ACT_SPRINT: |
|
{ |
|
pszActivity = "sprint"; |
|
break; |
|
} |
|
case ACT_WALK: |
|
{ |
|
pszActivity = "walk"; |
|
break; |
|
} |
|
case ACT_RUN: |
|
{ |
|
pszActivity = "run"; |
|
break; |
|
} |
|
} |
|
|
|
Msg( "Activity: %s\n", pszActivity ); |
|
|
|
#endif |
|
} |
|
|
|
#endif
|
|
|