aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp')
-rw-r--r--mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp4066
1 files changed, 2033 insertions, 2033 deletions
diff --git a/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
index 135234d7..975eec17 100644
--- a/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
+++ b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp
@@ -1,2033 +1,2033 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-#include "cbase.h"
-#include "tier0/vprof.h"
-#include "animation.h"
-#include "studio.h"
-#include "apparent_velocity_helper.h"
-#include "utldict.h"
-#include "multiplayer_animstate.h"
-#include "activitylist.h"
-
-#ifdef CLIENT_DLL
-#include "c_baseplayer.h"
-#include "engine/ivdebugoverlay.h"
-#include "filesystem.h"
-#include "eventlist.h"
-ConVar anim_showmainactivity( "anim_showmainactivity", "0", FCVAR_CHEAT, "Show the idle, walk, run, and/or sprint activities." );
-#else
-#include "player.h"
-#endif
-
-#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
-#include "tf_gamerules.h"
-#endif
-
-#ifndef CALL_ATTRIB_HOOK_FLOAT_ON_OTHER
-#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( o, r, n )
-#endif
-
-#define MOVING_MINIMUM_SPEED 0.5f
-
-ConVar anim_showstate( "anim_showstate", "-1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Show the (client) animation state for the specified entity (-1 for none)." );
-ConVar anim_showstatelog( "anim_showstatelog", "0", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "1 to output anim_showstate to Msg(). 2 to store in AnimState.log. 3 for both." );
-ConVar mp_showgestureslots( "mp_showgestureslots", "-1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Show multiplayer client/server gesture slot information for the specified player index (-1 for no one)." );
-ConVar mp_slammoveyaw( "mp_slammoveyaw", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Force movement yaw along an animation path." );
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pPlayer -
-// &movementData -
-//-----------------------------------------------------------------------------
-CMultiPlayerAnimState::CMultiPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData )
-#ifdef CLIENT_DLL
- : m_iv_flMaxGroundSpeed( "CMultiPlayerAnimState::m_iv_flMaxGroundSpeed" )
-#endif
-{
- // Pose parameters.
- m_bPoseParameterInit = false;
- m_PoseParameterData.Init();
- m_DebugAnimData.Init();
-
- m_pPlayer = NULL;
- m_angRender.Init();
-
- m_bCurrentFeetYawInitialized = false;
- m_flLastAnimationStateClearTime = 0.0f;
-
- m_flEyeYaw = 0.0f;
- m_flEyePitch = 0.0f;
- m_flGoalFeetYaw = 0.0f;
- m_flCurrentFeetYaw = 0.0f;
- m_flLastAimTurnTime = 0.0f;
-
- // Jumping.
- m_bJumping = false;
- m_flJumpStartTime = 0.0f;
- m_bFirstJumpFrame = false;
-
- // Swimming
- m_bInSwim = false;
- m_bFirstSwimFrame = true;
-
- // Dying
- m_bDying = false;
- m_bFirstDyingFrame = true;
-
- m_eCurrentMainSequenceActivity = ACT_INVALID;
- m_nSpecificMainSequence = -1;
-
- // Weapon data.
- m_hActiveWeapon = NULL;
-
- // Ground speed interpolators.
-#ifdef CLIENT_DLL
- m_iv_flMaxGroundSpeed.Setup( &m_flMaxGroundSpeed, LATCH_ANIMATION_VAR | INTERPOLATE_LINEAR_ONLY );
- m_flLastGroundSpeedUpdateTime = 0.0f;
-#endif
-
- m_flMaxGroundSpeed = 0.0f;
-
- m_bForceAimYaw = false;
-
- Init( pPlayer, movementData );
-
- // movement playback options
- m_nMovementSequence = -1;
- m_LegAnimType = LEGANIM_9WAY;
-
- InitGestureSlots();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-//-----------------------------------------------------------------------------
-CMultiPlayerAnimState::~CMultiPlayerAnimState()
-{
- ShutdownGestureSlots();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pPlayer -
-// &movementData -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::Init( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData )
-{
- // Get the player this animation data works on.
- m_pPlayer = pPlayer;
-
- // Copy the movement data.
- memcpy( &m_MovementData, &movementData, sizeof( MultiPlayerMovementData_t ) );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ClearAnimationState()
-{
- // Reset state.
- m_bJumping = false;
- m_bDying = false;
- m_bCurrentFeetYawInitialized = false;
- m_flLastAnimationStateClearTime = gpGlobals->curtime;
- m_nSpecificMainSequence = -1;
-
- ResetGestureSlots();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : event -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
-{
- switch( event )
- {
- case PLAYERANIMEVENT_ATTACK_PRIMARY:
- {
- // Weapon primary fire.
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_PRIMARYFIRE );
- break;
- }
- case PLAYERANIMEVENT_ATTACK_SECONDARY:
- {
- // Weapon secondary fire.
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_SECONDARYFIRE );
- break;
- }
- case PLAYERANIMEVENT_ATTACK_GRENADE:
- {
- // Grenade throw.
- RestartGesture( GESTURE_SLOT_GRENADE, ACT_MP_ATTACK_STAND_GRENADE );
- break;
- }
- case PLAYERANIMEVENT_RELOAD:
- {
- // Weapon reload.
- if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH );
- }
- else if ( m_bInSwim )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM );
- }
- else
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND );
- }
-
-
- // Set the modified reload playback rate
- float flPlaybackRate = 1.0f;
- #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
- #endif
- m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
-
- break;
- }
- case PLAYERANIMEVENT_RELOAD_LOOP:
- {
- // Weapon reload.
- if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH_LOOP );
- }
- else if ( m_bInSwim )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM_LOOP );
- }
- else
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND_LOOP );
- }
-
- // Set the modified reload playback rate
- float flPlaybackRate = 1.0f;
- #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
- #endif
- m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
-
- break;
- }
- case PLAYERANIMEVENT_RELOAD_END:
- {
- // Weapon reload.
- if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH_END );
- }
- else if ( m_bInSwim )
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM_END );
- }
- else
- {
- RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND_END );
- }
-
- // Set the modified reload playback rate
- float flPlaybackRate = 1.0f;
- #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
- CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
- #endif
- m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
-
- break;
- }
- case PLAYERANIMEVENT_JUMP:
- {
- // Jump.
- m_bJumping = true;
- m_bFirstJumpFrame = true;
- m_flJumpStartTime = gpGlobals->curtime;
-
- RestartMainSequence();
-
- break;
- }
- case PLAYERANIMEVENT_DIE:
- {
- // Should be here - not supporting this yet!
- Assert( 0 );
-
- // Start playing the death animation
- m_bDying = true;
-
- RestartMainSequence();
- break;
- }
- case PLAYERANIMEVENT_SPAWN:
- {
- // Player has respawned. Clear flags.
- ClearAnimationState();
- break;
- }
-
- case PLAYERANIMEVENT_SNAP_YAW:
- m_PoseParameterData.m_flLastAimTurnTime = 0.0f;
- break;
-
- case PLAYERANIMEVENT_CUSTOM:
- {
- Activity iIdealActivity = TranslateActivity( (Activity)nData );
- m_nSpecificMainSequence = GetBasePlayer()->SelectWeightedSequence( iIdealActivity );
- RestartMainSequence();
- }
- break;
-
- case PLAYERANIMEVENT_CUSTOM_GESTURE:
- // Weapon primary fire.
- RestartGesture( GESTURE_SLOT_CUSTOM, (Activity)nData );
- break;
-
- case PLAYERANIMEVENT_CUSTOM_SEQUENCE:
- m_nSpecificMainSequence = nData;
- RestartMainSequence();
- break;
-
- case PLAYERANIMEVENT_CUSTOM_GESTURE_SEQUENCE:
- // Weapon primary fire.
-// RestartGestureSequence( nData, false );
- break;
-
- case PLAYERANIMEVENT_FLINCH_CHEST:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_CHEST );
- break;
- case PLAYERANIMEVENT_FLINCH_HEAD:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_HEAD );
- break;
- case PLAYERANIMEVENT_FLINCH_LEFTARM:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_LEFTARM );
- break;
- case PLAYERANIMEVENT_FLINCH_RIGHTARM:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_RIGHTARM );
- break;
- case PLAYERANIMEVENT_FLINCH_LEFTLEG:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_LEFTLEG );
- break;
- case PLAYERANIMEVENT_FLINCH_RIGHTLEG:
- PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_RIGHTLEG );
- break;
-
- default:
- break;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::PlayFlinchGesture( Activity iActivity )
-{
- if ( !IsGestureSlotActive( GESTURE_SLOT_FLINCH ) )
- {
- // See if we have the custom flinch. If not, revert to chest
- if ( iActivity != ACT_MP_GESTURE_FLINCH_CHEST && GetBasePlayer()->SelectWeightedSequence( iActivity ) == -1 )
- {
- RestartGesture( GESTURE_SLOT_FLINCH, ACT_MP_GESTURE_FLINCH_CHEST );
- }
- else
- {
- RestartGesture( GESTURE_SLOT_FLINCH, iActivity );
- }
- }
-}
-
-//=============================================================================
-//
-// Multiplayer gesture code.
-//
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::InitGestureSlots( void )
-{
- // Get the base player.
- CBasePlayer *pPlayer = GetBasePlayer();
- if( pPlayer )
- {
- // Set the number of animation overlays we will use.
- pPlayer->SetNumAnimOverlays( GESTURE_SLOT_COUNT );
- }
-
- // Setup the number of gesture slots.
- m_aGestureSlots.AddMultipleToTail( GESTURE_SLOT_COUNT );
- for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
- {
- m_aGestureSlots[iGesture].m_pAnimLayer = pPlayer->GetAnimOverlay( iGesture );
- if ( !m_aGestureSlots[iGesture].m_pAnimLayer )
- return false;
-
- ResetGestureSlot( iGesture );
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ShutdownGestureSlots( void )
-{
- // Clean up the gesture slots.
- m_aGestureSlots.Purge();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ResetGestureSlots( void )
-{
- // Clear out all the gesture slots.
- for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
- {
- ResetGestureSlot( iGesture );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ResetGestureSlot( int iGestureSlot )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
-
- GestureSlot_t *pGestureSlot = &m_aGestureSlots[iGestureSlot];
- if ( pGestureSlot )
- {
-#ifdef CLIENT_DLL
- // briefly set to 1.0 so we catch the events, before we reset the slot
- pGestureSlot->m_pAnimLayer->m_flCycle = 1.0;
-
- RunGestureSlotAnimEventsToCompletion( pGestureSlot );
-#endif
-
- pGestureSlot->m_iGestureSlot = GESTURE_SLOT_INVALID;
- pGestureSlot->m_iActivity = ACT_INVALID;
- pGestureSlot->m_bAutoKill = false;
- pGestureSlot->m_bActive = false;
- if ( pGestureSlot->m_pAnimLayer )
- {
- pGestureSlot->m_pAnimLayer->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );
-#ifdef CLIENT_DLL
- pGestureSlot->m_pAnimLayer->Reset();
-#endif
- }
- }
-}
-
-#ifdef CLIENT_DLL
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::RunGestureSlotAnimEventsToCompletion( GestureSlot_t *pGesture )
-{
- CBasePlayer *pPlayer = GetBasePlayer();
- if( !pPlayer )
- return;
-
- // Get the studio header for the player.
- CStudioHdr *pStudioHdr = pPlayer->GetModelPtr();
- if ( !pStudioHdr )
- return;
-
- // Do all the anim events between previous cycle and 1.0, inclusive
- mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( pGesture->m_pAnimLayer->m_nSequence );
- if ( seqdesc.numevents > 0 )
- {
- mstudioevent_t *pevent = seqdesc.pEvent( 0 );
-
- for (int i = 0; i < (int)seqdesc.numevents; i++)
- {
- if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
- {
- if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
- continue;
- }
- else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system
- continue;
-
- if ( pevent[i].cycle > pGesture->m_pAnimLayer->m_flPrevCycle &&
- pevent[i].cycle <= pGesture->m_pAnimLayer->m_flCycle )
- {
- pPlayer->FireEvent( pPlayer->GetAbsOrigin(), pPlayer->GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() );
- }
- }
- }
-}
-
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::IsGestureSlotActive( int iGestureSlot )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
- return m_aGestureSlots[iGestureSlot].m_bActive;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::IsGestureSlotPlaying( int iGestureSlot, Activity iGestureActivity )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
-
- // Check to see if the slot is active.
- if ( !IsGestureSlotActive( iGestureSlot ) )
- return false;
-
- return ( m_aGestureSlots[iGestureSlot].m_iActivity == iGestureActivity );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::RestartGesture( int iGestureSlot, Activity iGestureActivity, bool bAutoKill )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
-
- if ( !IsGestureSlotPlaying( iGestureSlot, iGestureActivity ) )
- {
-#ifdef CLIENT_DLL
- if ( IsGestureSlotActive( iGestureSlot ) )
- {
- GestureSlot_t *pGesture = &m_aGestureSlots[iGestureSlot];
- if ( pGesture && pGesture->m_pAnimLayer )
- {
- pGesture->m_pAnimLayer->m_flCycle = 1.0; // run until the end
- RunGestureSlotAnimEventsToCompletion( &m_aGestureSlots[iGestureSlot] );
- }
- }
-#endif
-
- Activity iIdealGestureActivity = TranslateActivity( iGestureActivity );
- AddToGestureSlot( iGestureSlot, iIdealGestureActivity, bAutoKill );
- return;
- }
-
- // Reset the cycle = restart the gesture.
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::AddToGestureSlot( int iGestureSlot, Activity iGestureActivity, bool bAutoKill )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
-
- CBasePlayer *pPlayer = GetBasePlayer();
- if ( !pPlayer )
- return;
-
- // Make sure we have a valid animation layer to fill out.
- if ( !m_aGestureSlots[iGestureSlot].m_pAnimLayer )
- return;
-
- // Get the sequence.
- int iGestureSequence = pPlayer->SelectWeightedSequence( iGestureActivity );
- if ( iGestureSequence <= 0 )
- return;
-
-#ifdef CLIENT_DLL
-
- // Setup the gesture.
- m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
- m_aGestureSlots[iGestureSlot].m_bActive = true;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
-
- pPlayer->m_flOverlayPrevEventCycle[iGestureSlot] = -1.0;
-
-#else
-
- // Setup the gesture.
- m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
- m_aGestureSlots[iGestureSlot].m_bActive = true;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nPriority = 0;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendIn = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendOut = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bSequenceFinished = false;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = gpGlobals->curtime;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bLooping = false;//( ( GetSequenceFlags( GetModelPtr(), iGestureSequence ) & STUDIO_LOOPING ) != 0);
- if ( bAutoKill )
- {
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_AUTOKILL;
- }
- else
- {
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags &= ~ANIM_LAYER_AUTOKILL;
- }
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
-
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::AddVCDSequenceToGestureSlot( int iGestureSlot, int iGestureSequence, float flCycle, bool bAutoKill )
-{
- // Sanity Check
- Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
-
- CBasePlayer *pPlayer = GetBasePlayer();
- if ( !pPlayer )
- return;
-
- // Make sure we have a valid animation layer to fill out.
- if ( !m_aGestureSlots[iGestureSlot].m_pAnimLayer )
- return;
-
- // Set the activity.
- Activity iGestureActivity = ACT_MP_VCD;
-
-#ifdef CLIENT_DLL
-
- // Setup the gesture.
- m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
- m_aGestureSlots[iGestureSlot].m_bActive = true;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = flCycle;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
-
- pPlayer->m_flOverlayPrevEventCycle[iGestureSlot] = -1.0;
-
-#else
-
- // Setup the gesture.
- m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
- m_aGestureSlots[iGestureSlot].m_bActive = true;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nPriority = 0;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = flCycle;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendIn = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendOut = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bSequenceFinished = false;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = 0.0f;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = gpGlobals->curtime;
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bLooping = false;//( ( GetSequenceFlags( GetModelPtr(), iGestureSequence ) & STUDIO_LOOPING ) != 0);
- if ( bAutoKill )
- {
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_AUTOKILL;
- }
- else
- {
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags &= ~ANIM_LAYER_AUTOKILL;
- }
- m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
-
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-CAnimationLayer* CMultiPlayerAnimState::GetGestureSlotLayer( int iGestureSlot )
-{
- return m_aGestureSlots[iGestureSlot].m_pAnimLayer;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ShowDebugInfo( void )
-{
- if ( anim_showstate.GetInt() == GetBasePlayer()->entindex() )
- {
- DebugShowAnimStateForPlayer( GetBasePlayer()->IsServer() );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Cancel the current gesture and restart the main sequence.
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::RestartMainSequence( void )
-{
- CBaseAnimatingOverlay *pPlayer = GetBasePlayer();
- if ( pPlayer )
- {
- pPlayer->m_flAnimTime = gpGlobals->curtime;
- pPlayer->SetCycle( 0 );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *idealActivity -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::HandleJumping( Activity &idealActivity )
-{
- if ( m_bJumping )
- {
- if ( m_bFirstJumpFrame )
- {
- m_bFirstJumpFrame = false;
- RestartMainSequence(); // Reset the animation.
- }
-
- // Check to see if we hit water and stop jumping animation.
- if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist )
- {
- m_bJumping = false;
- RestartMainSequence();
- }
- // 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.
- else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f )
- {
- if ( GetBasePlayer()->GetFlags() & FL_ONGROUND )
- {
- m_bJumping = false;
- RestartMainSequence();
- }
- }
- }
- if ( m_bJumping )
- {
- idealActivity = ACT_MP_JUMP;
- return true;
- }
- else
- {
- return false;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *idealActivity -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::HandleDucking( Activity &idealActivity )
-{
- if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
- {
- if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
- {
- idealActivity = ACT_MP_CROUCHWALK;
- }
- else
- {
- idealActivity = ACT_MP_CROUCH_IDLE;
- }
-
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &idealActivity -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::HandleSwimming( Activity &idealActivity )
-{
- if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist )
- {
- if ( m_bFirstSwimFrame )
- {
- // Reset the animation.
- RestartMainSequence();
- m_bFirstSwimFrame = false;
- }
-
- idealActivity = ACT_MP_SWIM;
- m_bInSwim = true;
- return true;
- }
- else
- {
- m_bInSwim = false;
-
- if ( !m_bFirstSwimFrame )
- {
- m_bFirstSwimFrame = true;
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *idealActivity -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::HandleDying( Activity &idealActivity )
-{
- if ( m_bDying )
- {
- if ( m_bFirstDyingFrame )
- {
- // Reset the animation.
- RestartMainSequence();
- m_bFirstDyingFrame = false;
- }
-
- idealActivity = ACT_DIESIMPLE;
- return true;
- }
- else
- {
- if ( !m_bFirstDyingFrame )
- {
- m_bFirstDyingFrame = true;
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *idealActivity -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::HandleMoving( Activity &idealActivity )
-{
- // In TF we run all the time now.
- float flSpeed = GetOuterXYSpeed();
-
- if ( flSpeed > MOVING_MINIMUM_SPEED )
- {
- // Always assume a run.
- idealActivity = ACT_MP_RUN;
- }
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-// Output : Activity
-//-----------------------------------------------------------------------------
-Activity CMultiPlayerAnimState::CalcMainActivity()
-{
- Activity idealActivity = ACT_MP_STAND_IDLE;
-
- if ( HandleJumping( idealActivity ) ||
- HandleDucking( idealActivity ) ||
- HandleSwimming( idealActivity ) ||
- HandleDying( idealActivity ) )
- {
- // intentionally blank
- }
- else
- {
- HandleMoving( idealActivity );
- }
-
- ShowDebugInfo();
-
- // Client specific.
-#ifdef CLIENT_DLL
-
- if ( anim_showmainactivity.GetBool() )
- {
- DebugShowActivity( idealActivity );
- }
-
-#endif
-
- return idealActivity;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : actDesired -
-// Output : Activity
-//-----------------------------------------------------------------------------
-Activity CMultiPlayerAnimState::TranslateActivity( Activity actDesired )
-{
- // Translate activities for swimming.
- if ( m_bInSwim )
- {
- switch ( actDesired )
- {
- case ACT_MP_ATTACK_STAND_PRIMARYFIRE: { actDesired = ACT_MP_ATTACK_SWIM_PRIMARYFIRE; break; }
- case ACT_MP_ATTACK_STAND_SECONDARYFIRE: { actDesired = ACT_MP_ATTACK_SWIM_SECONDARYFIRE; break; }
- case ACT_MP_ATTACK_STAND_GRENADE: { actDesired = ACT_MP_ATTACK_SWIM_GRENADE; break; }
- case ACT_MP_RELOAD_STAND: { actDesired = ACT_MP_RELOAD_SWIM; break; }
- }
- }
-
- return actDesired;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-// Output : float
-//-----------------------------------------------------------------------------
-float CMultiPlayerAnimState::GetCurrentMaxGroundSpeed()
-{
- CStudioHdr *pStudioHdr = GetBasePlayer()->GetModelPtr();
-
- if ( pStudioHdr == NULL )
- return 1.0f;
-
- float prevX = GetBasePlayer()->GetPoseParameter( m_PoseParameterData.m_iMoveX );
- float prevY = GetBasePlayer()->GetPoseParameter( m_PoseParameterData.m_iMoveY );
-
- float d = MAX( fabs( prevX ), fabs( prevY ) );
- float newX, newY;
- if ( d == 0.0 )
- {
- newX = 1.0;
- newY = 0.0;
- }
- else
- {
- newX = prevX / d;
- newY = prevY / d;
- }
-
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, newX );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, newY );
-
- float speed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
-
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, prevX );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, prevY );
-
- return speed;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *bIsMoving -
-// Output : float
-//-----------------------------------------------------------------------------
-float CMultiPlayerAnimState::CalcMovementSpeed( bool *bIsMoving )
-{
- // Get the player's current velocity and speed.
- Vector vecVelocity;
- GetOuterAbsVelocity( vecVelocity );
- float flSpeed = vecVelocity.Length2D();
-
- if ( flSpeed > MOVING_MINIMUM_SPEED )
- {
- *bIsMoving = true;
- return flSpeed;
- }
-
- *bIsMoving = false;
- return 0.0f;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *bIsMoving -
-// Output : float
-//-----------------------------------------------------------------------------
-float CMultiPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
-{
- float flSpeed = CalcMovementSpeed( bIsMoving );
- float flReturn = 1.0f;
- // If we are moving.
- if ( *bIsMoving )
- {
- // float flGroundSpeed = GetInterpolatedGroundSpeed();
- float flGroundSpeed = GetCurrentMaxGroundSpeed();
- if ( flGroundSpeed < 0.001f )
- {
- flReturn = 0.01f;
- }
- else
- {
- // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
- flReturn = flSpeed / flGroundSpeed;
- flReturn = clamp( flReturn, 0.01f, 10.0f );
- }
- }
-
- return flReturn;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : float
-//-----------------------------------------------------------------------------
-float CMultiPlayerAnimState::GetInterpolatedGroundSpeed( void )
-{
- return m_flMaxGroundSpeed;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pStudioHdr -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
-{
- VPROF( "CBasePlayerAnimState::ComputeSequences" );
-
- // Lower body (walk/run/idle).
- ComputeMainSequence();
-
- // The groundspeed interpolator uses the main sequence info.
- UpdateInterpolators();
- ComputeGestureSequence( pStudioHdr );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputeMainSequence()
-{
- VPROF( "CBasePlayerAnimState::ComputeMainSequence" );
-
- CBaseAnimatingOverlay *pPlayer = GetBasePlayer();
-
- // Have our class or the mod-specific class determine what the current activity is.
- Activity idealActivity = CalcMainActivity();
-
-#ifdef CLIENT_DLL
- Activity oldActivity = m_eCurrentMainSequenceActivity;
-#endif
-
- // Store our current activity so the aim and fire layers know what to do.
- m_eCurrentMainSequenceActivity = idealActivity;
-
- // Hook to force playback of a specific requested full-body sequence
- if ( m_nSpecificMainSequence >= 0 )
- {
- if ( pPlayer->GetSequence() != m_nSpecificMainSequence )
- {
- pPlayer->ResetSequence( m_nSpecificMainSequence );
- ResetGroundSpeed();
- return;
- }
-
- if ( !pPlayer->IsSequenceFinished() )
- return;
-
- m_nSpecificMainSequence = -1;
- RestartMainSequence();
- ResetGroundSpeed();
- }
-
- // Export to our outer class..
- int animDesired = SelectWeightedSequence( TranslateActivity( idealActivity ) );
- if ( pPlayer->GetSequenceActivity( pPlayer->GetSequence() ) == pPlayer->GetSequenceActivity( animDesired ) )
- return;
-
- if ( animDesired < 0 )
- {
- animDesired = 0;
- }
-
- pPlayer->ResetSequence( animDesired );
-
-#ifdef CLIENT_DLL
- // If we went from idle to walk, reset the interpolation history.
- // Kind of hacky putting this here.. it might belong outside the base class.
- if ( (oldActivity == ACT_MP_CROUCH_IDLE || oldActivity == ACT_MP_STAND_IDLE || oldActivity == ACT_MP_DEPLOYED_IDLE || oldActivity == ACT_MP_CROUCH_DEPLOYED_IDLE ) &&
- (idealActivity == ACT_MP_WALK || idealActivity == ACT_MP_CROUCHWALK ) )
- {
- ResetGroundSpeed();
- }
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ResetGroundSpeed( void )
-{
-#ifdef CLIENT_DLL
- m_flMaxGroundSpeed = GetCurrentMaxGroundSpeed();
- m_iv_flMaxGroundSpeed.Reset();
- m_iv_flMaxGroundSpeed.NoteChanged( gpGlobals->curtime, 0, false );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::UpdateInterpolators()
-{
- VPROF( "CBasePlayerAnimState::UpdateInterpolators" );
-
- // First, figure out their current max speed based on their current activity.
- float flCurMaxSpeed = GetCurrentMaxGroundSpeed();
-
-#ifdef CLIENT_DLL
- float flGroundSpeedInterval = 0.1;
-
- // Only update this 10x/sec so it has an interval to interpolate over.
- if ( gpGlobals->curtime - m_flLastGroundSpeedUpdateTime >= flGroundSpeedInterval )
- {
- m_flLastGroundSpeedUpdateTime = gpGlobals->curtime;
-
- m_flMaxGroundSpeed = flCurMaxSpeed;
- m_iv_flMaxGroundSpeed.NoteChanged( gpGlobals->curtime, flGroundSpeedInterval, false );
- }
-
- m_iv_flMaxGroundSpeed.Interpolate( gpGlobals->curtime, flGroundSpeedInterval );
-#else
- m_flMaxGroundSpeed = flCurMaxSpeed;
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputeFireSequence( void )
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pStudioHdr -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputeGestureSequence( CStudioHdr *pStudioHdr )
-{
- // Update all active gesture layers.
- for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
- {
- if ( !m_aGestureSlots[iGesture].m_bActive )
- continue;
-
- UpdateGestureLayer( pStudioHdr, &m_aGestureSlots[iGesture] );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::UpdateGestureLayer( CStudioHdr *pStudioHdr, GestureSlot_t *pGesture )
-{
- // Sanity check.
- if ( !pStudioHdr || !pGesture )
- return;
-
- CBasePlayer *pPlayer = GetBasePlayer();
- if( !pPlayer )
- return;
-
-#ifdef CLIENT_DLL
-
- // Get the current cycle.
- float flCycle = pGesture->m_pAnimLayer->m_flCycle;
- flCycle += pPlayer->GetSequenceCycleRate( pStudioHdr, pGesture->m_pAnimLayer->m_nSequence ) * gpGlobals->frametime * GetGesturePlaybackRate() * pGesture->m_pAnimLayer->m_flPlaybackRate;
-
- pGesture->m_pAnimLayer->m_flPrevCycle = pGesture->m_pAnimLayer->m_flCycle;
- pGesture->m_pAnimLayer->m_flCycle = flCycle;
-
- if( flCycle > 1.0f )
- {
- RunGestureSlotAnimEventsToCompletion( pGesture );
-
- if ( pGesture->m_bAutoKill )
- {
- ResetGestureSlot( pGesture->m_iGestureSlot );
- return;
- }
- else
- {
- pGesture->m_pAnimLayer->m_flCycle = 1.0f;
- }
- }
-
-#else
-
- if ( pGesture->m_iActivity != ACT_INVALID && pGesture->m_pAnimLayer->m_nActivity == ACT_INVALID )
- {
- ResetGestureSlot( pGesture->m_iGestureSlot );
- }
-
-#endif
-}
-
-extern ConVar mp_facefronttime;
-extern ConVar mp_feetyawrate;
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : eyeYaw -
-// eyePitch -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::Update( float eyeYaw, float eyePitch )
-{
- // Profile the animation update.
- VPROF( "CMultiPlayerAnimState::Update" );
-
- // Get the studio header for the player.
- CStudioHdr *pStudioHdr = GetBasePlayer()->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 );
-
- // 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 );
- }
-
-#ifdef CLIENT_DLL
- if ( C_BasePlayer::ShouldDrawLocalPlayer() )
- {
- GetBasePlayer()->SetPlaybackRate( 1.0f );
- }
-#endif
-
- if( mp_showgestureslots.GetInt() == GetBasePlayer()->entindex() )
- {
- DebugGestureInfo();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::ShouldUpdateAnimState()
-{
- // Don't update anim state if we're not visible
- if ( GetBasePlayer()->IsEffectActive( EF_NODRAW ) )
- return false;
-
- // By default, don't update their animation state when they're dead because they're
- // either a ragdoll or they're not drawn.
-#ifdef CLIENT_DLL
- if ( GetBasePlayer()->IsDormant() )
- return false;
-#endif
-
- return (GetBasePlayer()->IsAlive() || m_bDying);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool CMultiPlayerAnimState::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;
-
- m_bPoseParameterInit = true;
-
- // Look for the movement blenders.
- m_PoseParameterData.m_iMoveX = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_x" );
- m_PoseParameterData.m_iMoveY = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_y" );
- /*
- if ( ( m_PoseParameterData.m_iMoveX < 0 ) || ( m_PoseParameterData.m_iMoveY < 0 ) )
- return false;
- */
-
- // Look for the aim pitch blender.
- m_PoseParameterData.m_iAimPitch = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "body_pitch" );
- /*
- if ( m_PoseParameterData.m_iAimPitch < 0 )
- return false;
- */
-
- // Look for aim yaw blender.
- m_PoseParameterData.m_iAimYaw = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "body_yaw" );
- /*
- if ( m_PoseParameterData.m_iAimYaw < 0 )
- return false;
- */
-
- m_PoseParameterData.m_iMoveYaw = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_yaw" );
- m_PoseParameterData.m_iMoveScale = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_scale" );
- /*
- if ( ( m_PoseParameterData.m_iMoveYaw < 0 ) || ( m_PoseParameterData.m_iMoveScale < 0 ) )
- return false;
- */
-
- return true;
-}
-
-float SnapYawTo( float flValue )
-{
- float flSign = 1.0f;
- if ( flValue < 0.0f )
- {
- flSign = -1.0f;
- flValue = -flValue;
- }
-
- if ( flValue < 23.0f )
- {
- flValue = 0.0f;
- }
- else if ( flValue < 67.0f )
- {
- flValue = 45.0f;
- }
- else if ( flValue < 113.0f )
- {
- flValue = 90.0f;
- }
- else if ( flValue < 157 )
- {
- flValue = 135.0f;
- }
- else
- {
- flValue = 180.0f;
- }
-
- return ( flValue * flSign );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: double check that the movement animations actually have movement
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::DoMovementTest( CStudioHdr *pStudioHdr, float flX, float flY )
-{
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, flX );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, flY );
-
-#ifdef STAGING_ONLY
- float flTestSpeed = GetBasePlayer()->GetSequenceGroundSpeed( m_nMovementSequence );
- if ( flTestSpeed < 10.0f )
- {
- Warning( "%s : %s (X %.0f Y %.0f) missing movement\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY );
- }
-#endif
-
- /*
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, flX );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, flY );
- float flDuration = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
-
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 1.0f );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
- float flForward = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
-
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 0.0f );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
- float flCenter = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
-
- if ( flDuration > flForward * 1.1f || flDuration < flForward * 0.9f )
- {
- Warning( "%s : %s (X %.0f Y %.0f) mismatched duration with forward %.1f vs %.1f\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY, flDuration, flForward );
- }
-
- if ( flDuration > flCenter * 1.1f || flDuration < flCenter * 0.9f )
- {
- Warning( "%s : %s (X %.0f Y %.0f) mismatched duration with center %.1f vs %.1f\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY, flDuration, flCenter );
- }
- */
-}
-
-
-void CMultiPlayerAnimState::DoMovementTest( CStudioHdr *pStudioHdr )
-{
- if ( m_LegAnimType == LEGANIM_9WAY )
- {
- DoMovementTest( pStudioHdr, -1.0f, -1.0f );
- DoMovementTest( pStudioHdr, -1.0f, 0.0f );
- DoMovementTest( pStudioHdr, -1.0f, 1.0f );
- DoMovementTest( pStudioHdr, 0.0f, -1.0f );
- DoMovementTest( pStudioHdr, 0.0f, 1.0f );
- DoMovementTest( pStudioHdr, 1.0f, -1.0f );
- DoMovementTest( pStudioHdr, 1.0f, 0.0f );
- DoMovementTest( pStudioHdr, 1.0f, 1.0f );
- }
-}
-
-void CMultiPlayerAnimState::GetMovementFlags( CStudioHdr *pStudioHdr )
-{
- if ( m_nMovementSequence == GetBasePlayer()->GetSequence() )
- {
- return;
- }
-
- m_nMovementSequence = GetBasePlayer()->GetSequence();
- m_LegAnimType = LEGANIM_9WAY;
-
- KeyValues *seqKeyValues = GetBasePlayer()->GetSequenceKeyValues( m_nMovementSequence );
- // Msg("sequence %d : %s (%d)\n", sequence, GetOuter()->GetSequenceName( sequence ), seqKeyValues != NULL );
- if (seqKeyValues)
- {
- KeyValues *pkvMovement = seqKeyValues->FindKey( "movement" );
- if (pkvMovement)
- {
- const char *szStyle = pkvMovement->GetString();
- if ( V_stricmp( szStyle, "robot2" ) == 0 )
- {
- m_LegAnimType = LEGANIM_8WAY;
- }
- }
- seqKeyValues->deleteThis();
- }
-
- // skip tests if it's not a movement animation
- if ( m_nMovementSequence < 0 || !( GetBasePlayer()->GetFlags() & FL_ONGROUND ) || pStudioHdr->pSeqdesc( m_nMovementSequence ).groupsize[0] == 1 )
- {
- return;
- }
-
- DoMovementTest( pStudioHdr );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pStudioHdr -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
-{
- // Get the estimated movement yaw.
- EstimateYaw();
-
- // Get the view yaw.
- float flAngle = AngleNormalize( m_flEyeYaw );
-
- // Calc side to side turning - the view vs. movement yaw.
- float flYaw = flAngle - m_PoseParameterData.m_flEstimateYaw;
- flYaw = AngleNormalize( -flYaw );
-
- // Get the current speed the character is running.
- bool bIsMoving;
- float flSpeed = CalcMovementSpeed( &bIsMoving );
-
- // Setup the 9-way blend parameters based on our speed and direction.
- Vector2D vecCurrentMoveYaw( 0.0f, 0.0f );
- if ( bIsMoving )
- {
- GetMovementFlags( pStudioHdr );
-
- if ( mp_slammoveyaw.GetBool() )
- {
- flYaw = SnapYawTo( flYaw );
- }
-
- if ( m_LegAnimType == LEGANIM_9WAY )
- {
- // convert YAW back into vector
- vecCurrentMoveYaw.x = cos( DEG2RAD( flYaw ) );
- vecCurrentMoveYaw.y = -sin( DEG2RAD( flYaw ) );
- // push edges out to -1 to 1 box
- float flInvScale = MAX( fabs( vecCurrentMoveYaw.x ), fabs( vecCurrentMoveYaw.y ) );
- if ( flInvScale != 0.0f )
- {
- vecCurrentMoveYaw.x /= flInvScale;
- vecCurrentMoveYaw.y /= flInvScale;
- }
-
- // find what speed was actually authored
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, vecCurrentMoveYaw.x );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, vecCurrentMoveYaw.y );
- float flMaxSpeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
-
- // scale playback
- if ( flMaxSpeed > flSpeed )
- {
- vecCurrentMoveYaw.x *= flSpeed / flMaxSpeed;
- vecCurrentMoveYaw.y *= flSpeed / flMaxSpeed;
- }
-
- // Set the 9-way blend movement pose parameters.
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, vecCurrentMoveYaw.x );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, vecCurrentMoveYaw.y );
- }
- else
- {
- // find what speed was actually authored
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveYaw, flYaw );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveScale, 1.0f );
- float flMaxSpeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
-
- // scale playback
- if ( flMaxSpeed > flSpeed )
- {
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveScale, flSpeed / flMaxSpeed );
- }
- }
- }
- else
- {
- // Set the 9-way blend movement pose parameters.
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 0.0f );
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
- }
-
- m_DebugAnimData.m_vecMoveYaw = vecCurrentMoveYaw;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::EstimateYaw( void )
-{
- // Get the frame time.
- float flDeltaTime = gpGlobals->frametime;
- if ( flDeltaTime == 0.0f )
- return;
-
- // Get the player's velocity and angles.
- Vector vecEstVelocity;
- GetOuterAbsVelocity( vecEstVelocity );
- QAngle angles = GetBasePlayer()->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_PoseParameterData.m_flEstimateYaw;
- flYawDelta = AngleNormalize( flYawDelta );
-
- if ( flDeltaTime < 0.25f )
- {
- flYawDelta *= ( flDeltaTime * 4.0f );
- }
- else
- {
- flYawDelta *= flDeltaTime;
- }
-
- m_PoseParameterData.m_flEstimateYaw += flYawDelta;
- AngleNormalize( m_PoseParameterData.m_flEstimateYaw );
- }
- else
- {
- m_PoseParameterData.m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI );
- m_PoseParameterData.m_flEstimateYaw = clamp( m_PoseParameterData.m_flEstimateYaw, -180.0f, 180.0f );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr )
-{
- // Get the view pitch.
- float flAimPitch = m_flEyePitch;
-
- // Set the aim pitch pose parameter and save.
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimPitch, -flAimPitch );
- m_DebugAnimData.m_flAimPitch = flAimPitch;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::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;
-
- // If we are moving or are prone and undeployed.
- if ( bMoving || m_bForceAimYaw )
- {
- // 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_PoseParameterData.m_flLastAimTurnTime <= 0.0f )
- {
- m_flGoalFeetYaw = m_flEyeYaw;
- m_flCurrentFeetYaw = m_flEyeYaw;
- m_PoseParameterData.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 ( fabs( flYawDelta ) > 45.0f/*m_AnimConfig.m_flMaxBodyYawDegrees*/ )
- {
- float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f;
- m_flGoalFeetYaw += ( 45.0f/*m_AnimConfig.m_flMaxBodyYawDegrees*/ * flSide );
- }
- }
- }
-
- // Fix up the feet yaw.
- m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw );
- if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
- {
- if ( m_bForceAimYaw )
- {
- m_flCurrentFeetYaw = m_flGoalFeetYaw;
- }
- else
- {
- ConvergeYawAngles( m_flGoalFeetYaw, /*DOD_BODYYAW_RATE*/720.0f, 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.
- GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimYaw, -flAimYaw );
- m_DebugAnimData.m_flAimYaw = flAimYaw;
-
- // Turn off a force aim yaw - either we have already updated or we don't need to.
- m_bForceAimYaw = false;
-
-#ifndef CLIENT_DLL
- QAngle angle = GetBasePlayer()->GetAbsAngles();
- angle[YAW] = m_flCurrentFeetYaw;
-
- GetBasePlayer()->SetAbsAngles( angle );
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : flGoalYaw -
-// flYawRate -
-// flDeltaTime -
-// &flCurrentYaw -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::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:
-// Input : -
-// Output : const QAngle&
-//-----------------------------------------------------------------------------
-const QAngle& CMultiPlayerAnimState::GetRenderAngles()
-{
- return m_angRender;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : vel -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
-{
-#if defined( CLIENT_DLL )
- GetBasePlayer()->EstimateAbsVelocity( vel );
-#else
- vel = GetBasePlayer()->GetAbsVelocity();
-#endif
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::Release( void )
-{
- delete this;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : -
-// Output : float
-//-----------------------------------------------------------------------------
-float CMultiPlayerAnimState::GetOuterXYSpeed()
-{
- Vector vel;
- GetOuterAbsVelocity( vel );
- return vel.Length2D();
-}
-
-//-----------------------------------------------------------------------------
-// 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 CMultiPlayerAnimState::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( GetBasePlayer()->GetModelPtr(), GetBasePlayer()->GetSequence() ), GetBasePlayer()->GetCycle() );
-
-#if 0
- if ( m_bPlayingGesture )
- {
- Anim_StatePrintf( iLine++, "Gesture: %s, Cycle: %.2f\n",
- GetSequenceName( GetBasePlayer()->GetModelPtr(), m_iGestureSequence ),
- m_flGestureCycle );
- }
-#endif
-
- // Write out the layers and their data.
- for ( int iAnim = 0; iAnim < GetBasePlayer()->GetNumAnimOverlays(); ++iAnim )
- {
-#ifdef CLIENT_DLL
- C_AnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( iAnim );
- if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
- {
- Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle );
- }
-#else
- CAnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( iAnim );
- if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
- {
- Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle );
- }
-#endif
- }
-
- // 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", m_angRender[YAW], m_DebugAnimData.m_flAimYaw, m_DebugAnimData.m_flAimPitch, m_DebugAnimData.m_vecMoveYaw.x, m_DebugAnimData.m_vecMoveYaw.y );
-
-// Anim_StateLog( "--------------------------------------------\n\n" );
- Anim_StatePrintf( iLine++, "--------------------------------------------\n\n" );
-
- DebugShowEyeYaw();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::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
-}
-
-#if defined( CLIENT_DLL )
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : activity -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::DebugShowActivity( Activity activity )
-{
-#ifdef _DEBUG
-
- const char *pszActivity = "other";
-
- switch( activity )
- {
- case ACT_MP_STAND_IDLE:
- {
- pszActivity = "idle";
- break;
- }
- case ACT_MP_SPRINT:
- {
- pszActivity = "sprint";
- break;
- }
- case ACT_MP_WALK:
- {
- pszActivity = "walk";
- break;
- }
- case ACT_MP_RUN:
- {
- pszActivity = "run";
- break;
- }
- }
-
- Msg( "Activity: %s\n", pszActivity );
-
-#endif
-}
-#endif
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : iStartLine -
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::DebugShowAnimState( int iStartLine )
-{
- Vector vOuterVel;
- GetOuterAbsVelocity( vOuterVel );
-
- Anim_StateLog( "----------------- frame %d -----------------\n", gpGlobals->framecount );
-
- int iLine = iStartLine;
- Anim_StatePrintf( iLine++, "main: %s, cycle: %.2f\n", GetSequenceName( GetBasePlayer()->GetModelPtr(), GetBasePlayer()->GetSequence() ), GetBasePlayer()->GetCycle() );
-
-#if defined( CLIENT_DLL )
- for ( int i=0; i < GetBasePlayer()->GetNumAnimOverlays()-1; i++ )
- {
- C_AnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( i /*i+1?*/ );
- Anim_StatePrintf( iLine++, "%s, weight: %.2f, cycle: %.2f, aim (%d)",
- pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? "--" : GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ),
- pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->m_flWeight,
- pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->m_flCycle,
- i
- );
- }
-#endif
-
- Anim_StatePrintf( iLine++, "vel: %.2f, time: %.2f, max: %.2f",
- vOuterVel.Length2D(), gpGlobals->curtime, GetInterpolatedGroundSpeed() );
-
-// AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, body_pitch: %.2f, move_x: %.2f, move_y: %.2f",
-// m_angRender[YAW], g_flLastBodyYaw, g_flLastBodyPitch, m_vLastMovePose.x, m_vLastMovePose.y );
-
- Anim_StateLog( "--------------------------------------------\n\n" );
-
- // Draw a red triangle on the ground for the eye yaw.
- float flBaseSize = 10;
- float flHeight = 80;
- Vector vBasePos = GetBasePlayer()->GetAbsOrigin() + Vector( 0, 0, 3 );
- QAngle angles( 0, 0, 0 );
- angles[YAW] = m_flEyeYaw;
- Vector vForward, vRight, vUp;
- AngleVectors( angles, &vForward, &vRight, &vUp );
- debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 255, 0, 0, 255, false, 0.01 );
-
- // Draw a blue triangle on the ground for the body yaw.
- angles[YAW] = m_angRender[YAW];
- AngleVectors( angles, &vForward, &vRight, &vUp );
- debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 0, 0, 255, 255, false, 0.01 );
-}
-
-// Debug!
-const char *s_aGestureSlotNames[GESTURE_SLOT_COUNT] =
-{
- "Attack and Reload",
- "Grenade",
- "Jump",
- "Swim",
- "Flinch",
- "VCD",
- "Custom"
-};
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::DebugGestureInfo( void )
-{
- CBasePlayer *pPlayer = GetBasePlayer();
- if ( !pPlayer )
- return;
-
- int iLine = ( pPlayer->IsServer() ? 12 : ( 14 + GESTURE_SLOT_COUNT ) );
-
- Anim_StatePrintf( iLine++, "%s\n", ( pPlayer->IsServer() ? "Server" : "Client" ) );
-
- for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
- {
- GestureSlot_t *pGesture = &m_aGestureSlots[iGesture];
- if ( pGesture )
- {
- if( pGesture->m_bActive )
- {
- Anim_StatePrintf( iLine++, "Gesture Slot %d(%s): %s %s(A:%s, C:%f P:%f)\n",
- iGesture,
- s_aGestureSlotNames[iGesture],
- ActivityList_NameForIndex( pGesture->m_iActivity ),
- GetSequenceName( pPlayer->GetModelPtr(), pGesture->m_pAnimLayer->m_nSequence ),
- ( pGesture->m_bAutoKill ? "true" : "false" ),
- (float)pGesture->m_pAnimLayer->m_flCycle, (float)pGesture->m_pAnimLayer->m_flPlaybackRate );
- }
- else
- {
- Anim_StatePrintf( iLine++, "Gesture Slot %d(%s): NOT ACTIVE!\n", iGesture, s_aGestureSlotNames[iGesture] );
- }
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: New Model, init the pose parameters
-//-----------------------------------------------------------------------------
-void CMultiPlayerAnimState::OnNewModel( void )
-{
- m_bPoseParameterInit = false;
- m_PoseParameterData.Init();
- ClearAnimationState();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "tier0/vprof.h"
+#include "animation.h"
+#include "studio.h"
+#include "apparent_velocity_helper.h"
+#include "utldict.h"
+#include "multiplayer_animstate.h"
+#include "activitylist.h"
+
+#ifdef CLIENT_DLL
+#include "c_baseplayer.h"
+#include "engine/ivdebugoverlay.h"
+#include "filesystem.h"
+#include "eventlist.h"
+ConVar anim_showmainactivity( "anim_showmainactivity", "0", FCVAR_CHEAT, "Show the idle, walk, run, and/or sprint activities." );
+#else
+#include "player.h"
+#endif
+
+#if defined(TF_CLIENT_DLL) || defined(TF_DLL)
+#include "tf_gamerules.h"
+#endif
+
+#ifndef CALL_ATTRIB_HOOK_FLOAT_ON_OTHER
+#define CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( o, r, n )
+#endif
+
+#define MOVING_MINIMUM_SPEED 0.5f
+
+ConVar anim_showstate( "anim_showstate", "-1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Show the (client) animation state for the specified entity (-1 for none)." );
+ConVar anim_showstatelog( "anim_showstatelog", "0", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "1 to output anim_showstate to Msg(). 2 to store in AnimState.log. 3 for both." );
+ConVar mp_showgestureslots( "mp_showgestureslots", "-1", FCVAR_CHEAT | FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Show multiplayer client/server gesture slot information for the specified player index (-1 for no one)." );
+ConVar mp_slammoveyaw( "mp_slammoveyaw", "0", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Force movement yaw along an animation path." );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPlayer -
+// &movementData -
+//-----------------------------------------------------------------------------
+CMultiPlayerAnimState::CMultiPlayerAnimState( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData )
+#ifdef CLIENT_DLL
+ : m_iv_flMaxGroundSpeed( "CMultiPlayerAnimState::m_iv_flMaxGroundSpeed" )
+#endif
+{
+ // Pose parameters.
+ m_bPoseParameterInit = false;
+ m_PoseParameterData.Init();
+ m_DebugAnimData.Init();
+
+ m_pPlayer = NULL;
+ m_angRender.Init();
+
+ m_bCurrentFeetYawInitialized = false;
+ m_flLastAnimationStateClearTime = 0.0f;
+
+ m_flEyeYaw = 0.0f;
+ m_flEyePitch = 0.0f;
+ m_flGoalFeetYaw = 0.0f;
+ m_flCurrentFeetYaw = 0.0f;
+ m_flLastAimTurnTime = 0.0f;
+
+ // Jumping.
+ m_bJumping = false;
+ m_flJumpStartTime = 0.0f;
+ m_bFirstJumpFrame = false;
+
+ // Swimming
+ m_bInSwim = false;
+ m_bFirstSwimFrame = true;
+
+ // Dying
+ m_bDying = false;
+ m_bFirstDyingFrame = true;
+
+ m_eCurrentMainSequenceActivity = ACT_INVALID;
+ m_nSpecificMainSequence = -1;
+
+ // Weapon data.
+ m_hActiveWeapon = NULL;
+
+ // Ground speed interpolators.
+#ifdef CLIENT_DLL
+ m_iv_flMaxGroundSpeed.Setup( &m_flMaxGroundSpeed, LATCH_ANIMATION_VAR | INTERPOLATE_LINEAR_ONLY );
+ m_flLastGroundSpeedUpdateTime = 0.0f;
+#endif
+
+ m_flMaxGroundSpeed = 0.0f;
+
+ m_bForceAimYaw = false;
+
+ Init( pPlayer, movementData );
+
+ // movement playback options
+ m_nMovementSequence = -1;
+ m_LegAnimType = LEGANIM_9WAY;
+
+ InitGestureSlots();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+CMultiPlayerAnimState::~CMultiPlayerAnimState()
+{
+ ShutdownGestureSlots();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pPlayer -
+// &movementData -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::Init( CBasePlayer *pPlayer, MultiPlayerMovementData_t &movementData )
+{
+ // Get the player this animation data works on.
+ m_pPlayer = pPlayer;
+
+ // Copy the movement data.
+ memcpy( &m_MovementData, &movementData, sizeof( MultiPlayerMovementData_t ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ClearAnimationState()
+{
+ // Reset state.
+ m_bJumping = false;
+ m_bDying = false;
+ m_bCurrentFeetYawInitialized = false;
+ m_flLastAnimationStateClearTime = gpGlobals->curtime;
+ m_nSpecificMainSequence = -1;
+
+ ResetGestureSlots();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : event -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::DoAnimationEvent( PlayerAnimEvent_t event, int nData )
+{
+ switch( event )
+ {
+ case PLAYERANIMEVENT_ATTACK_PRIMARY:
+ {
+ // Weapon primary fire.
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_PRIMARYFIRE );
+ break;
+ }
+ case PLAYERANIMEVENT_ATTACK_SECONDARY:
+ {
+ // Weapon secondary fire.
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_ATTACK_STAND_SECONDARYFIRE );
+ break;
+ }
+ case PLAYERANIMEVENT_ATTACK_GRENADE:
+ {
+ // Grenade throw.
+ RestartGesture( GESTURE_SLOT_GRENADE, ACT_MP_ATTACK_STAND_GRENADE );
+ break;
+ }
+ case PLAYERANIMEVENT_RELOAD:
+ {
+ // Weapon reload.
+ if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH );
+ }
+ else if ( m_bInSwim )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM );
+ }
+ else
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND );
+ }
+
+
+ // Set the modified reload playback rate
+ float flPlaybackRate = 1.0f;
+ #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
+ #endif
+ m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
+
+ break;
+ }
+ case PLAYERANIMEVENT_RELOAD_LOOP:
+ {
+ // Weapon reload.
+ if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH_LOOP );
+ }
+ else if ( m_bInSwim )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM_LOOP );
+ }
+ else
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND_LOOP );
+ }
+
+ // Set the modified reload playback rate
+ float flPlaybackRate = 1.0f;
+ #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
+ #endif
+ m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
+
+ break;
+ }
+ case PLAYERANIMEVENT_RELOAD_END:
+ {
+ // Weapon reload.
+ if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_CROUCH_END );
+ }
+ else if ( m_bInSwim )
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_SWIM_END );
+ }
+ else
+ {
+ RestartGesture( GESTURE_SLOT_ATTACK_AND_RELOAD, ACT_MP_RELOAD_STAND_END );
+ }
+
+ // Set the modified reload playback rate
+ float flPlaybackRate = 1.0f;
+ #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, mult_reload_time_hidden );
+ CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( GetBasePlayer(), flPlaybackRate, fast_reload );
+ #endif
+ m_aGestureSlots[ GESTURE_SLOT_ATTACK_AND_RELOAD ].m_pAnimLayer->m_flPlaybackRate = flPlaybackRate;
+
+ break;
+ }
+ case PLAYERANIMEVENT_JUMP:
+ {
+ // Jump.
+ m_bJumping = true;
+ m_bFirstJumpFrame = true;
+ m_flJumpStartTime = gpGlobals->curtime;
+
+ RestartMainSequence();
+
+ break;
+ }
+ case PLAYERANIMEVENT_DIE:
+ {
+ // Should be here - not supporting this yet!
+ Assert( 0 );
+
+ // Start playing the death animation
+ m_bDying = true;
+
+ RestartMainSequence();
+ break;
+ }
+ case PLAYERANIMEVENT_SPAWN:
+ {
+ // Player has respawned. Clear flags.
+ ClearAnimationState();
+ break;
+ }
+
+ case PLAYERANIMEVENT_SNAP_YAW:
+ m_PoseParameterData.m_flLastAimTurnTime = 0.0f;
+ break;
+
+ case PLAYERANIMEVENT_CUSTOM:
+ {
+ Activity iIdealActivity = TranslateActivity( (Activity)nData );
+ m_nSpecificMainSequence = GetBasePlayer()->SelectWeightedSequence( iIdealActivity );
+ RestartMainSequence();
+ }
+ break;
+
+ case PLAYERANIMEVENT_CUSTOM_GESTURE:
+ // Weapon primary fire.
+ RestartGesture( GESTURE_SLOT_CUSTOM, (Activity)nData );
+ break;
+
+ case PLAYERANIMEVENT_CUSTOM_SEQUENCE:
+ m_nSpecificMainSequence = nData;
+ RestartMainSequence();
+ break;
+
+ case PLAYERANIMEVENT_CUSTOM_GESTURE_SEQUENCE:
+ // Weapon primary fire.
+// RestartGestureSequence( nData, false );
+ break;
+
+ case PLAYERANIMEVENT_FLINCH_CHEST:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_CHEST );
+ break;
+ case PLAYERANIMEVENT_FLINCH_HEAD:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_HEAD );
+ break;
+ case PLAYERANIMEVENT_FLINCH_LEFTARM:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_LEFTARM );
+ break;
+ case PLAYERANIMEVENT_FLINCH_RIGHTARM:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_RIGHTARM );
+ break;
+ case PLAYERANIMEVENT_FLINCH_LEFTLEG:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_LEFTLEG );
+ break;
+ case PLAYERANIMEVENT_FLINCH_RIGHTLEG:
+ PlayFlinchGesture( ACT_MP_GESTURE_FLINCH_RIGHTLEG );
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::PlayFlinchGesture( Activity iActivity )
+{
+ if ( !IsGestureSlotActive( GESTURE_SLOT_FLINCH ) )
+ {
+ // See if we have the custom flinch. If not, revert to chest
+ if ( iActivity != ACT_MP_GESTURE_FLINCH_CHEST && GetBasePlayer()->SelectWeightedSequence( iActivity ) == -1 )
+ {
+ RestartGesture( GESTURE_SLOT_FLINCH, ACT_MP_GESTURE_FLINCH_CHEST );
+ }
+ else
+ {
+ RestartGesture( GESTURE_SLOT_FLINCH, iActivity );
+ }
+ }
+}
+
+//=============================================================================
+//
+// Multiplayer gesture code.
+//
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::InitGestureSlots( void )
+{
+ // Get the base player.
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if( pPlayer )
+ {
+ // Set the number of animation overlays we will use.
+ pPlayer->SetNumAnimOverlays( GESTURE_SLOT_COUNT );
+ }
+
+ // Setup the number of gesture slots.
+ m_aGestureSlots.AddMultipleToTail( GESTURE_SLOT_COUNT );
+ for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
+ {
+ m_aGestureSlots[iGesture].m_pAnimLayer = pPlayer->GetAnimOverlay( iGesture );
+ if ( !m_aGestureSlots[iGesture].m_pAnimLayer )
+ return false;
+
+ ResetGestureSlot( iGesture );
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ShutdownGestureSlots( void )
+{
+ // Clean up the gesture slots.
+ m_aGestureSlots.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ResetGestureSlots( void )
+{
+ // Clear out all the gesture slots.
+ for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
+ {
+ ResetGestureSlot( iGesture );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ResetGestureSlot( int iGestureSlot )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+
+ GestureSlot_t *pGestureSlot = &m_aGestureSlots[iGestureSlot];
+ if ( pGestureSlot )
+ {
+#ifdef CLIENT_DLL
+ // briefly set to 1.0 so we catch the events, before we reset the slot
+ pGestureSlot->m_pAnimLayer->m_flCycle = 1.0;
+
+ RunGestureSlotAnimEventsToCompletion( pGestureSlot );
+#endif
+
+ pGestureSlot->m_iGestureSlot = GESTURE_SLOT_INVALID;
+ pGestureSlot->m_iActivity = ACT_INVALID;
+ pGestureSlot->m_bAutoKill = false;
+ pGestureSlot->m_bActive = false;
+ if ( pGestureSlot->m_pAnimLayer )
+ {
+ pGestureSlot->m_pAnimLayer->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );
+#ifdef CLIENT_DLL
+ pGestureSlot->m_pAnimLayer->Reset();
+#endif
+ }
+ }
+}
+
+#ifdef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::RunGestureSlotAnimEventsToCompletion( GestureSlot_t *pGesture )
+{
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if( !pPlayer )
+ return;
+
+ // Get the studio header for the player.
+ CStudioHdr *pStudioHdr = pPlayer->GetModelPtr();
+ if ( !pStudioHdr )
+ return;
+
+ // Do all the anim events between previous cycle and 1.0, inclusive
+ mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( pGesture->m_pAnimLayer->m_nSequence );
+ if ( seqdesc.numevents > 0 )
+ {
+ mstudioevent_t *pevent = seqdesc.pEvent( 0 );
+
+ for (int i = 0; i < (int)seqdesc.numevents; i++)
+ {
+ if ( pevent[i].type & AE_TYPE_NEWEVENTSYSTEM )
+ {
+ if ( !( pevent[i].type & AE_TYPE_CLIENT ) )
+ continue;
+ }
+ else if ( pevent[i].event < 5000 ) //Adrian - Support the old event system
+ continue;
+
+ if ( pevent[i].cycle > pGesture->m_pAnimLayer->m_flPrevCycle &&
+ pevent[i].cycle <= pGesture->m_pAnimLayer->m_flCycle )
+ {
+ pPlayer->FireEvent( pPlayer->GetAbsOrigin(), pPlayer->GetAbsAngles(), pevent[ i ].event, pevent[ i ].pszOptions() );
+ }
+ }
+ }
+}
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::IsGestureSlotActive( int iGestureSlot )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+ return m_aGestureSlots[iGestureSlot].m_bActive;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::IsGestureSlotPlaying( int iGestureSlot, Activity iGestureActivity )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+
+ // Check to see if the slot is active.
+ if ( !IsGestureSlotActive( iGestureSlot ) )
+ return false;
+
+ return ( m_aGestureSlots[iGestureSlot].m_iActivity == iGestureActivity );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::RestartGesture( int iGestureSlot, Activity iGestureActivity, bool bAutoKill )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+
+ if ( !IsGestureSlotPlaying( iGestureSlot, iGestureActivity ) )
+ {
+#ifdef CLIENT_DLL
+ if ( IsGestureSlotActive( iGestureSlot ) )
+ {
+ GestureSlot_t *pGesture = &m_aGestureSlots[iGestureSlot];
+ if ( pGesture && pGesture->m_pAnimLayer )
+ {
+ pGesture->m_pAnimLayer->m_flCycle = 1.0; // run until the end
+ RunGestureSlotAnimEventsToCompletion( &m_aGestureSlots[iGestureSlot] );
+ }
+ }
+#endif
+
+ Activity iIdealGestureActivity = TranslateActivity( iGestureActivity );
+ AddToGestureSlot( iGestureSlot, iIdealGestureActivity, bAutoKill );
+ return;
+ }
+
+ // Reset the cycle = restart the gesture.
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::AddToGestureSlot( int iGestureSlot, Activity iGestureActivity, bool bAutoKill )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if ( !pPlayer )
+ return;
+
+ // Make sure we have a valid animation layer to fill out.
+ if ( !m_aGestureSlots[iGestureSlot].m_pAnimLayer )
+ return;
+
+ // Get the sequence.
+ int iGestureSequence = pPlayer->SelectWeightedSequence( iGestureActivity );
+ if ( iGestureSequence <= 0 )
+ return;
+
+#ifdef CLIENT_DLL
+
+ // Setup the gesture.
+ m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
+ m_aGestureSlots[iGestureSlot].m_bActive = true;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
+
+ pPlayer->m_flOverlayPrevEventCycle[iGestureSlot] = -1.0;
+
+#else
+
+ // Setup the gesture.
+ m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
+ m_aGestureSlots[iGestureSlot].m_bActive = true;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nPriority = 0;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendIn = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendOut = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bSequenceFinished = false;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = gpGlobals->curtime;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bLooping = false;//( ( GetSequenceFlags( GetModelPtr(), iGestureSequence ) & STUDIO_LOOPING ) != 0);
+ if ( bAutoKill )
+ {
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_AUTOKILL;
+ }
+ else
+ {
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags &= ~ANIM_LAYER_AUTOKILL;
+ }
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
+
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::AddVCDSequenceToGestureSlot( int iGestureSlot, int iGestureSequence, float flCycle, bool bAutoKill )
+{
+ // Sanity Check
+ Assert( iGestureSlot >= 0 && iGestureSlot < GESTURE_SLOT_COUNT );
+
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if ( !pPlayer )
+ return;
+
+ // Make sure we have a valid animation layer to fill out.
+ if ( !m_aGestureSlots[iGestureSlot].m_pAnimLayer )
+ return;
+
+ // Set the activity.
+ Activity iGestureActivity = ACT_MP_VCD;
+
+#ifdef CLIENT_DLL
+
+ // Setup the gesture.
+ m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
+ m_aGestureSlots[iGestureSlot].m_bActive = true;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = flCycle;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
+
+ pPlayer->m_flOverlayPrevEventCycle[iGestureSlot] = -1.0;
+
+#else
+
+ // Setup the gesture.
+ m_aGestureSlots[iGestureSlot].m_iGestureSlot = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_iActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_bAutoKill = bAutoKill;
+ m_aGestureSlots[iGestureSlot].m_bActive = true;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nOrder = iGestureSlot;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nPriority = 0;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flCycle = flCycle;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPrevCycle = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flPlaybackRate = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nActivity = iGestureActivity;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_nSequence = iGestureSequence;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flWeight = 1.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendIn = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flBlendOut = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bSequenceFinished = false;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = 0.0f;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLastEventCheck = gpGlobals->curtime;
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_bLooping = false;//( ( GetSequenceFlags( GetModelPtr(), iGestureSequence ) & STUDIO_LOOPING ) != 0);
+ if ( bAutoKill )
+ {
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_AUTOKILL;
+ }
+ else
+ {
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags &= ~ANIM_LAYER_AUTOKILL;
+ }
+ m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_fFlags |= ANIM_LAYER_ACTIVE;
+
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CAnimationLayer* CMultiPlayerAnimState::GetGestureSlotLayer( int iGestureSlot )
+{
+ return m_aGestureSlots[iGestureSlot].m_pAnimLayer;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ShowDebugInfo( void )
+{
+ if ( anim_showstate.GetInt() == GetBasePlayer()->entindex() )
+ {
+ DebugShowAnimStateForPlayer( GetBasePlayer()->IsServer() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Cancel the current gesture and restart the main sequence.
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::RestartMainSequence( void )
+{
+ CBaseAnimatingOverlay *pPlayer = GetBasePlayer();
+ if ( pPlayer )
+ {
+ pPlayer->m_flAnimTime = gpGlobals->curtime;
+ pPlayer->SetCycle( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *idealActivity -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::HandleJumping( Activity &idealActivity )
+{
+ if ( m_bJumping )
+ {
+ if ( m_bFirstJumpFrame )
+ {
+ m_bFirstJumpFrame = false;
+ RestartMainSequence(); // Reset the animation.
+ }
+
+ // Check to see if we hit water and stop jumping animation.
+ if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist )
+ {
+ m_bJumping = false;
+ RestartMainSequence();
+ }
+ // 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.
+ else if ( gpGlobals->curtime - m_flJumpStartTime > 0.2f )
+ {
+ if ( GetBasePlayer()->GetFlags() & FL_ONGROUND )
+ {
+ m_bJumping = false;
+ RestartMainSequence();
+ }
+ }
+ }
+ if ( m_bJumping )
+ {
+ idealActivity = ACT_MP_JUMP;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *idealActivity -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::HandleDucking( Activity &idealActivity )
+{
+ if ( GetBasePlayer()->GetFlags() & FL_DUCKING )
+ {
+ if ( GetOuterXYSpeed() > MOVING_MINIMUM_SPEED )
+ {
+ idealActivity = ACT_MP_CROUCHWALK;
+ }
+ else
+ {
+ idealActivity = ACT_MP_CROUCH_IDLE;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &idealActivity -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::HandleSwimming( Activity &idealActivity )
+{
+ if ( GetBasePlayer()->GetWaterLevel() >= WL_Waist )
+ {
+ if ( m_bFirstSwimFrame )
+ {
+ // Reset the animation.
+ RestartMainSequence();
+ m_bFirstSwimFrame = false;
+ }
+
+ idealActivity = ACT_MP_SWIM;
+ m_bInSwim = true;
+ return true;
+ }
+ else
+ {
+ m_bInSwim = false;
+
+ if ( !m_bFirstSwimFrame )
+ {
+ m_bFirstSwimFrame = true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *idealActivity -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::HandleDying( Activity &idealActivity )
+{
+ if ( m_bDying )
+ {
+ if ( m_bFirstDyingFrame )
+ {
+ // Reset the animation.
+ RestartMainSequence();
+ m_bFirstDyingFrame = false;
+ }
+
+ idealActivity = ACT_DIESIMPLE;
+ return true;
+ }
+ else
+ {
+ if ( !m_bFirstDyingFrame )
+ {
+ m_bFirstDyingFrame = true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *idealActivity -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::HandleMoving( Activity &idealActivity )
+{
+ // In TF we run all the time now.
+ float flSpeed = GetOuterXYSpeed();
+
+ if ( flSpeed > MOVING_MINIMUM_SPEED )
+ {
+ // Always assume a run.
+ idealActivity = ACT_MP_RUN;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : Activity
+//-----------------------------------------------------------------------------
+Activity CMultiPlayerAnimState::CalcMainActivity()
+{
+ Activity idealActivity = ACT_MP_STAND_IDLE;
+
+ if ( HandleJumping( idealActivity ) ||
+ HandleDucking( idealActivity ) ||
+ HandleSwimming( idealActivity ) ||
+ HandleDying( idealActivity ) )
+ {
+ // intentionally blank
+ }
+ else
+ {
+ HandleMoving( idealActivity );
+ }
+
+ ShowDebugInfo();
+
+ // Client specific.
+#ifdef CLIENT_DLL
+
+ if ( anim_showmainactivity.GetBool() )
+ {
+ DebugShowActivity( idealActivity );
+ }
+
+#endif
+
+ return idealActivity;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : actDesired -
+// Output : Activity
+//-----------------------------------------------------------------------------
+Activity CMultiPlayerAnimState::TranslateActivity( Activity actDesired )
+{
+ // Translate activities for swimming.
+ if ( m_bInSwim )
+ {
+ switch ( actDesired )
+ {
+ case ACT_MP_ATTACK_STAND_PRIMARYFIRE: { actDesired = ACT_MP_ATTACK_SWIM_PRIMARYFIRE; break; }
+ case ACT_MP_ATTACK_STAND_SECONDARYFIRE: { actDesired = ACT_MP_ATTACK_SWIM_SECONDARYFIRE; break; }
+ case ACT_MP_ATTACK_STAND_GRENADE: { actDesired = ACT_MP_ATTACK_SWIM_GRENADE; break; }
+ case ACT_MP_RELOAD_STAND: { actDesired = ACT_MP_RELOAD_SWIM; break; }
+ }
+ }
+
+ return actDesired;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : float
+//-----------------------------------------------------------------------------
+float CMultiPlayerAnimState::GetCurrentMaxGroundSpeed()
+{
+ CStudioHdr *pStudioHdr = GetBasePlayer()->GetModelPtr();
+
+ if ( pStudioHdr == NULL )
+ return 1.0f;
+
+ float prevX = GetBasePlayer()->GetPoseParameter( m_PoseParameterData.m_iMoveX );
+ float prevY = GetBasePlayer()->GetPoseParameter( m_PoseParameterData.m_iMoveY );
+
+ float d = MAX( fabs( prevX ), fabs( prevY ) );
+ float newX, newY;
+ if ( d == 0.0 )
+ {
+ newX = 1.0;
+ newY = 0.0;
+ }
+ else
+ {
+ newX = prevX / d;
+ newY = prevY / d;
+ }
+
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, newX );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, newY );
+
+ float speed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
+
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, prevX );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, prevY );
+
+ return speed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *bIsMoving -
+// Output : float
+//-----------------------------------------------------------------------------
+float CMultiPlayerAnimState::CalcMovementSpeed( bool *bIsMoving )
+{
+ // Get the player's current velocity and speed.
+ Vector vecVelocity;
+ GetOuterAbsVelocity( vecVelocity );
+ float flSpeed = vecVelocity.Length2D();
+
+ if ( flSpeed > MOVING_MINIMUM_SPEED )
+ {
+ *bIsMoving = true;
+ return flSpeed;
+ }
+
+ *bIsMoving = false;
+ return 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *bIsMoving -
+// Output : float
+//-----------------------------------------------------------------------------
+float CMultiPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
+{
+ float flSpeed = CalcMovementSpeed( bIsMoving );
+ float flReturn = 1.0f;
+ // If we are moving.
+ if ( *bIsMoving )
+ {
+ // float flGroundSpeed = GetInterpolatedGroundSpeed();
+ float flGroundSpeed = GetCurrentMaxGroundSpeed();
+ if ( flGroundSpeed < 0.001f )
+ {
+ flReturn = 0.01f;
+ }
+ else
+ {
+ // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
+ flReturn = flSpeed / flGroundSpeed;
+ flReturn = clamp( flReturn, 0.01f, 10.0f );
+ }
+ }
+
+ return flReturn;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CMultiPlayerAnimState::GetInterpolatedGroundSpeed( void )
+{
+ return m_flMaxGroundSpeed;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pStudioHdr -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
+{
+ VPROF( "CBasePlayerAnimState::ComputeSequences" );
+
+ // Lower body (walk/run/idle).
+ ComputeMainSequence();
+
+ // The groundspeed interpolator uses the main sequence info.
+ UpdateInterpolators();
+ ComputeGestureSequence( pStudioHdr );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputeMainSequence()
+{
+ VPROF( "CBasePlayerAnimState::ComputeMainSequence" );
+
+ CBaseAnimatingOverlay *pPlayer = GetBasePlayer();
+
+ // Have our class or the mod-specific class determine what the current activity is.
+ Activity idealActivity = CalcMainActivity();
+
+#ifdef CLIENT_DLL
+ Activity oldActivity = m_eCurrentMainSequenceActivity;
+#endif
+
+ // Store our current activity so the aim and fire layers know what to do.
+ m_eCurrentMainSequenceActivity = idealActivity;
+
+ // Hook to force playback of a specific requested full-body sequence
+ if ( m_nSpecificMainSequence >= 0 )
+ {
+ if ( pPlayer->GetSequence() != m_nSpecificMainSequence )
+ {
+ pPlayer->ResetSequence( m_nSpecificMainSequence );
+ ResetGroundSpeed();
+ return;
+ }
+
+ if ( !pPlayer->IsSequenceFinished() )
+ return;
+
+ m_nSpecificMainSequence = -1;
+ RestartMainSequence();
+ ResetGroundSpeed();
+ }
+
+ // Export to our outer class..
+ int animDesired = SelectWeightedSequence( TranslateActivity( idealActivity ) );
+ if ( pPlayer->GetSequenceActivity( pPlayer->GetSequence() ) == pPlayer->GetSequenceActivity( animDesired ) )
+ return;
+
+ if ( animDesired < 0 )
+ {
+ animDesired = 0;
+ }
+
+ pPlayer->ResetSequence( animDesired );
+
+#ifdef CLIENT_DLL
+ // If we went from idle to walk, reset the interpolation history.
+ // Kind of hacky putting this here.. it might belong outside the base class.
+ if ( (oldActivity == ACT_MP_CROUCH_IDLE || oldActivity == ACT_MP_STAND_IDLE || oldActivity == ACT_MP_DEPLOYED_IDLE || oldActivity == ACT_MP_CROUCH_DEPLOYED_IDLE ) &&
+ (idealActivity == ACT_MP_WALK || idealActivity == ACT_MP_CROUCHWALK ) )
+ {
+ ResetGroundSpeed();
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ResetGroundSpeed( void )
+{
+#ifdef CLIENT_DLL
+ m_flMaxGroundSpeed = GetCurrentMaxGroundSpeed();
+ m_iv_flMaxGroundSpeed.Reset();
+ m_iv_flMaxGroundSpeed.NoteChanged( gpGlobals->curtime, 0, false );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::UpdateInterpolators()
+{
+ VPROF( "CBasePlayerAnimState::UpdateInterpolators" );
+
+ // First, figure out their current max speed based on their current activity.
+ float flCurMaxSpeed = GetCurrentMaxGroundSpeed();
+
+#ifdef CLIENT_DLL
+ float flGroundSpeedInterval = 0.1;
+
+ // Only update this 10x/sec so it has an interval to interpolate over.
+ if ( gpGlobals->curtime - m_flLastGroundSpeedUpdateTime >= flGroundSpeedInterval )
+ {
+ m_flLastGroundSpeedUpdateTime = gpGlobals->curtime;
+
+ m_flMaxGroundSpeed = flCurMaxSpeed;
+ m_iv_flMaxGroundSpeed.NoteChanged( gpGlobals->curtime, flGroundSpeedInterval, false );
+ }
+
+ m_iv_flMaxGroundSpeed.Interpolate( gpGlobals->curtime, flGroundSpeedInterval );
+#else
+ m_flMaxGroundSpeed = flCurMaxSpeed;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputeFireSequence( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pStudioHdr -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputeGestureSequence( CStudioHdr *pStudioHdr )
+{
+ // Update all active gesture layers.
+ for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
+ {
+ if ( !m_aGestureSlots[iGesture].m_bActive )
+ continue;
+
+ UpdateGestureLayer( pStudioHdr, &m_aGestureSlots[iGesture] );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::UpdateGestureLayer( CStudioHdr *pStudioHdr, GestureSlot_t *pGesture )
+{
+ // Sanity check.
+ if ( !pStudioHdr || !pGesture )
+ return;
+
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if( !pPlayer )
+ return;
+
+#ifdef CLIENT_DLL
+
+ // Get the current cycle.
+ float flCycle = pGesture->m_pAnimLayer->m_flCycle;
+ flCycle += pPlayer->GetSequenceCycleRate( pStudioHdr, pGesture->m_pAnimLayer->m_nSequence ) * gpGlobals->frametime * GetGesturePlaybackRate() * pGesture->m_pAnimLayer->m_flPlaybackRate;
+
+ pGesture->m_pAnimLayer->m_flPrevCycle = pGesture->m_pAnimLayer->m_flCycle;
+ pGesture->m_pAnimLayer->m_flCycle = flCycle;
+
+ if( flCycle > 1.0f )
+ {
+ RunGestureSlotAnimEventsToCompletion( pGesture );
+
+ if ( pGesture->m_bAutoKill )
+ {
+ ResetGestureSlot( pGesture->m_iGestureSlot );
+ return;
+ }
+ else
+ {
+ pGesture->m_pAnimLayer->m_flCycle = 1.0f;
+ }
+ }
+
+#else
+
+ if ( pGesture->m_iActivity != ACT_INVALID && pGesture->m_pAnimLayer->m_nActivity == ACT_INVALID )
+ {
+ ResetGestureSlot( pGesture->m_iGestureSlot );
+ }
+
+#endif
+}
+
+extern ConVar mp_facefronttime;
+extern ConVar mp_feetyawrate;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : eyeYaw -
+// eyePitch -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::Update( float eyeYaw, float eyePitch )
+{
+ // Profile the animation update.
+ VPROF( "CMultiPlayerAnimState::Update" );
+
+ // Get the studio header for the player.
+ CStudioHdr *pStudioHdr = GetBasePlayer()->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 );
+
+ // 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 );
+ }
+
+#ifdef CLIENT_DLL
+ if ( C_BasePlayer::ShouldDrawLocalPlayer() )
+ {
+ GetBasePlayer()->SetPlaybackRate( 1.0f );
+ }
+#endif
+
+ if( mp_showgestureslots.GetInt() == GetBasePlayer()->entindex() )
+ {
+ DebugGestureInfo();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::ShouldUpdateAnimState()
+{
+ // Don't update anim state if we're not visible
+ if ( GetBasePlayer()->IsEffectActive( EF_NODRAW ) )
+ return false;
+
+ // By default, don't update their animation state when they're dead because they're
+ // either a ragdoll or they're not drawn.
+#ifdef CLIENT_DLL
+ if ( GetBasePlayer()->IsDormant() )
+ return false;
+#endif
+
+ return (GetBasePlayer()->IsAlive() || m_bDying);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CMultiPlayerAnimState::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;
+
+ m_bPoseParameterInit = true;
+
+ // Look for the movement blenders.
+ m_PoseParameterData.m_iMoveX = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_x" );
+ m_PoseParameterData.m_iMoveY = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_y" );
+ /*
+ if ( ( m_PoseParameterData.m_iMoveX < 0 ) || ( m_PoseParameterData.m_iMoveY < 0 ) )
+ return false;
+ */
+
+ // Look for the aim pitch blender.
+ m_PoseParameterData.m_iAimPitch = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "body_pitch" );
+ /*
+ if ( m_PoseParameterData.m_iAimPitch < 0 )
+ return false;
+ */
+
+ // Look for aim yaw blender.
+ m_PoseParameterData.m_iAimYaw = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "body_yaw" );
+ /*
+ if ( m_PoseParameterData.m_iAimYaw < 0 )
+ return false;
+ */
+
+ m_PoseParameterData.m_iMoveYaw = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_yaw" );
+ m_PoseParameterData.m_iMoveScale = GetBasePlayer()->LookupPoseParameter( pStudioHdr, "move_scale" );
+ /*
+ if ( ( m_PoseParameterData.m_iMoveYaw < 0 ) || ( m_PoseParameterData.m_iMoveScale < 0 ) )
+ return false;
+ */
+
+ return true;
+}
+
+float SnapYawTo( float flValue )
+{
+ float flSign = 1.0f;
+ if ( flValue < 0.0f )
+ {
+ flSign = -1.0f;
+ flValue = -flValue;
+ }
+
+ if ( flValue < 23.0f )
+ {
+ flValue = 0.0f;
+ }
+ else if ( flValue < 67.0f )
+ {
+ flValue = 45.0f;
+ }
+ else if ( flValue < 113.0f )
+ {
+ flValue = 90.0f;
+ }
+ else if ( flValue < 157 )
+ {
+ flValue = 135.0f;
+ }
+ else
+ {
+ flValue = 180.0f;
+ }
+
+ return ( flValue * flSign );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: double check that the movement animations actually have movement
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::DoMovementTest( CStudioHdr *pStudioHdr, float flX, float flY )
+{
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, flX );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, flY );
+
+#ifdef STAGING_ONLY
+ float flTestSpeed = GetBasePlayer()->GetSequenceGroundSpeed( m_nMovementSequence );
+ if ( flTestSpeed < 10.0f )
+ {
+ Warning( "%s : %s (X %.0f Y %.0f) missing movement\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY );
+ }
+#endif
+
+ /*
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, flX );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, flY );
+ float flDuration = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
+
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 1.0f );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
+ float flForward = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
+
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 0.0f );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
+ float flCenter = GetBasePlayer()->SequenceDuration( m_nMovementSequence );
+
+ if ( flDuration > flForward * 1.1f || flDuration < flForward * 0.9f )
+ {
+ Warning( "%s : %s (X %.0f Y %.0f) mismatched duration with forward %.1f vs %.1f\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY, flDuration, flForward );
+ }
+
+ if ( flDuration > flCenter * 1.1f || flDuration < flCenter * 0.9f )
+ {
+ Warning( "%s : %s (X %.0f Y %.0f) mismatched duration with center %.1f vs %.1f\n", pStudioHdr->pszName(), GetBasePlayer()->GetSequenceName( m_nMovementSequence ), flX, flY, flDuration, flCenter );
+ }
+ */
+}
+
+
+void CMultiPlayerAnimState::DoMovementTest( CStudioHdr *pStudioHdr )
+{
+ if ( m_LegAnimType == LEGANIM_9WAY )
+ {
+ DoMovementTest( pStudioHdr, -1.0f, -1.0f );
+ DoMovementTest( pStudioHdr, -1.0f, 0.0f );
+ DoMovementTest( pStudioHdr, -1.0f, 1.0f );
+ DoMovementTest( pStudioHdr, 0.0f, -1.0f );
+ DoMovementTest( pStudioHdr, 0.0f, 1.0f );
+ DoMovementTest( pStudioHdr, 1.0f, -1.0f );
+ DoMovementTest( pStudioHdr, 1.0f, 0.0f );
+ DoMovementTest( pStudioHdr, 1.0f, 1.0f );
+ }
+}
+
+void CMultiPlayerAnimState::GetMovementFlags( CStudioHdr *pStudioHdr )
+{
+ if ( m_nMovementSequence == GetBasePlayer()->GetSequence() )
+ {
+ return;
+ }
+
+ m_nMovementSequence = GetBasePlayer()->GetSequence();
+ m_LegAnimType = LEGANIM_9WAY;
+
+ KeyValues *seqKeyValues = GetBasePlayer()->GetSequenceKeyValues( m_nMovementSequence );
+ // Msg("sequence %d : %s (%d)\n", sequence, GetOuter()->GetSequenceName( sequence ), seqKeyValues != NULL );
+ if (seqKeyValues)
+ {
+ KeyValues *pkvMovement = seqKeyValues->FindKey( "movement" );
+ if (pkvMovement)
+ {
+ const char *szStyle = pkvMovement->GetString();
+ if ( V_stricmp( szStyle, "robot2" ) == 0 )
+ {
+ m_LegAnimType = LEGANIM_8WAY;
+ }
+ }
+ seqKeyValues->deleteThis();
+ }
+
+ // skip tests if it's not a movement animation
+ if ( m_nMovementSequence < 0 || !( GetBasePlayer()->GetFlags() & FL_ONGROUND ) || pStudioHdr->pSeqdesc( m_nMovementSequence ).groupsize[0] == 1 )
+ {
+ return;
+ }
+
+ DoMovementTest( pStudioHdr );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pStudioHdr -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
+{
+ // Get the estimated movement yaw.
+ EstimateYaw();
+
+ // Get the view yaw.
+ float flAngle = AngleNormalize( m_flEyeYaw );
+
+ // Calc side to side turning - the view vs. movement yaw.
+ float flYaw = flAngle - m_PoseParameterData.m_flEstimateYaw;
+ flYaw = AngleNormalize( -flYaw );
+
+ // Get the current speed the character is running.
+ bool bIsMoving;
+ float flSpeed = CalcMovementSpeed( &bIsMoving );
+
+ // Setup the 9-way blend parameters based on our speed and direction.
+ Vector2D vecCurrentMoveYaw( 0.0f, 0.0f );
+ if ( bIsMoving )
+ {
+ GetMovementFlags( pStudioHdr );
+
+ if ( mp_slammoveyaw.GetBool() )
+ {
+ flYaw = SnapYawTo( flYaw );
+ }
+
+ if ( m_LegAnimType == LEGANIM_9WAY )
+ {
+ // convert YAW back into vector
+ vecCurrentMoveYaw.x = cos( DEG2RAD( flYaw ) );
+ vecCurrentMoveYaw.y = -sin( DEG2RAD( flYaw ) );
+ // push edges out to -1 to 1 box
+ float flInvScale = MAX( fabs( vecCurrentMoveYaw.x ), fabs( vecCurrentMoveYaw.y ) );
+ if ( flInvScale != 0.0f )
+ {
+ vecCurrentMoveYaw.x /= flInvScale;
+ vecCurrentMoveYaw.y /= flInvScale;
+ }
+
+ // find what speed was actually authored
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, vecCurrentMoveYaw.x );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, vecCurrentMoveYaw.y );
+ float flMaxSpeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
+
+ // scale playback
+ if ( flMaxSpeed > flSpeed )
+ {
+ vecCurrentMoveYaw.x *= flSpeed / flMaxSpeed;
+ vecCurrentMoveYaw.y *= flSpeed / flMaxSpeed;
+ }
+
+ // Set the 9-way blend movement pose parameters.
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, vecCurrentMoveYaw.x );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, vecCurrentMoveYaw.y );
+ }
+ else
+ {
+ // find what speed was actually authored
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveYaw, flYaw );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveScale, 1.0f );
+ float flMaxSpeed = GetBasePlayer()->GetSequenceGroundSpeed( GetBasePlayer()->GetSequence() );
+
+ // scale playback
+ if ( flMaxSpeed > flSpeed )
+ {
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveScale, flSpeed / flMaxSpeed );
+ }
+ }
+ }
+ else
+ {
+ // Set the 9-way blend movement pose parameters.
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveX, 0.0f );
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iMoveY, 0.0f );
+ }
+
+ m_DebugAnimData.m_vecMoveYaw = vecCurrentMoveYaw;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::EstimateYaw( void )
+{
+ // Get the frame time.
+ float flDeltaTime = gpGlobals->frametime;
+ if ( flDeltaTime == 0.0f )
+ return;
+
+ // Get the player's velocity and angles.
+ Vector vecEstVelocity;
+ GetOuterAbsVelocity( vecEstVelocity );
+ QAngle angles = GetBasePlayer()->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_PoseParameterData.m_flEstimateYaw;
+ flYawDelta = AngleNormalize( flYawDelta );
+
+ if ( flDeltaTime < 0.25f )
+ {
+ flYawDelta *= ( flDeltaTime * 4.0f );
+ }
+ else
+ {
+ flYawDelta *= flDeltaTime;
+ }
+
+ m_PoseParameterData.m_flEstimateYaw += flYawDelta;
+ AngleNormalize( m_PoseParameterData.m_flEstimateYaw );
+ }
+ else
+ {
+ m_PoseParameterData.m_flEstimateYaw = ( atan2( vecEstVelocity.y, vecEstVelocity.x ) * 180.0f / M_PI );
+ m_PoseParameterData.m_flEstimateYaw = clamp( m_PoseParameterData.m_flEstimateYaw, -180.0f, 180.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::ComputePoseParam_AimPitch( CStudioHdr *pStudioHdr )
+{
+ // Get the view pitch.
+ float flAimPitch = m_flEyePitch;
+
+ // Set the aim pitch pose parameter and save.
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimPitch, -flAimPitch );
+ m_DebugAnimData.m_flAimPitch = flAimPitch;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::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;
+
+ // If we are moving or are prone and undeployed.
+ if ( bMoving || m_bForceAimYaw )
+ {
+ // 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_PoseParameterData.m_flLastAimTurnTime <= 0.0f )
+ {
+ m_flGoalFeetYaw = m_flEyeYaw;
+ m_flCurrentFeetYaw = m_flEyeYaw;
+ m_PoseParameterData.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 ( fabs( flYawDelta ) > 45.0f/*m_AnimConfig.m_flMaxBodyYawDegrees*/ )
+ {
+ float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f;
+ m_flGoalFeetYaw += ( 45.0f/*m_AnimConfig.m_flMaxBodyYawDegrees*/ * flSide );
+ }
+ }
+ }
+
+ // Fix up the feet yaw.
+ m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw );
+ if ( m_flGoalFeetYaw != m_flCurrentFeetYaw )
+ {
+ if ( m_bForceAimYaw )
+ {
+ m_flCurrentFeetYaw = m_flGoalFeetYaw;
+ }
+ else
+ {
+ ConvergeYawAngles( m_flGoalFeetYaw, /*DOD_BODYYAW_RATE*/720.0f, 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.
+ GetBasePlayer()->SetPoseParameter( pStudioHdr, m_PoseParameterData.m_iAimYaw, -flAimYaw );
+ m_DebugAnimData.m_flAimYaw = flAimYaw;
+
+ // Turn off a force aim yaw - either we have already updated or we don't need to.
+ m_bForceAimYaw = false;
+
+#ifndef CLIENT_DLL
+ QAngle angle = GetBasePlayer()->GetAbsAngles();
+ angle[YAW] = m_flCurrentFeetYaw;
+
+ GetBasePlayer()->SetAbsAngles( angle );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flGoalYaw -
+// flYawRate -
+// flDeltaTime -
+// &flCurrentYaw -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::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:
+// Input : -
+// Output : const QAngle&
+//-----------------------------------------------------------------------------
+const QAngle& CMultiPlayerAnimState::GetRenderAngles()
+{
+ return m_angRender;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : vel -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::GetOuterAbsVelocity( Vector& vel )
+{
+#if defined( CLIENT_DLL )
+ GetBasePlayer()->EstimateAbsVelocity( vel );
+#else
+ vel = GetBasePlayer()->GetAbsVelocity();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::Release( void )
+{
+ delete this;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : float
+//-----------------------------------------------------------------------------
+float CMultiPlayerAnimState::GetOuterXYSpeed()
+{
+ Vector vel;
+ GetOuterAbsVelocity( vel );
+ return vel.Length2D();
+}
+
+//-----------------------------------------------------------------------------
+// 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 CMultiPlayerAnimState::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( GetBasePlayer()->GetModelPtr(), GetBasePlayer()->GetSequence() ), GetBasePlayer()->GetCycle() );
+
+#if 0
+ if ( m_bPlayingGesture )
+ {
+ Anim_StatePrintf( iLine++, "Gesture: %s, Cycle: %.2f\n",
+ GetSequenceName( GetBasePlayer()->GetModelPtr(), m_iGestureSequence ),
+ m_flGestureCycle );
+ }
+#endif
+
+ // Write out the layers and their data.
+ for ( int iAnim = 0; iAnim < GetBasePlayer()->GetNumAnimOverlays(); ++iAnim )
+ {
+#ifdef CLIENT_DLL
+ C_AnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( iAnim );
+ if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
+ {
+ Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle );
+ }
+#else
+ CAnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( iAnim );
+ if ( pLayer && ( pLayer->m_nOrder != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
+ {
+ Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ), (float)pLayer->m_flWeight, (float)pLayer->m_flCycle );
+ }
+#endif
+ }
+
+ // 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", m_angRender[YAW], m_DebugAnimData.m_flAimYaw, m_DebugAnimData.m_flAimPitch, m_DebugAnimData.m_vecMoveYaw.x, m_DebugAnimData.m_vecMoveYaw.y );
+
+// Anim_StateLog( "--------------------------------------------\n\n" );
+ Anim_StatePrintf( iLine++, "--------------------------------------------\n\n" );
+
+ DebugShowEyeYaw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::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
+}
+
+#if defined( CLIENT_DLL )
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : activity -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::DebugShowActivity( Activity activity )
+{
+#ifdef _DEBUG
+
+ const char *pszActivity = "other";
+
+ switch( activity )
+ {
+ case ACT_MP_STAND_IDLE:
+ {
+ pszActivity = "idle";
+ break;
+ }
+ case ACT_MP_SPRINT:
+ {
+ pszActivity = "sprint";
+ break;
+ }
+ case ACT_MP_WALK:
+ {
+ pszActivity = "walk";
+ break;
+ }
+ case ACT_MP_RUN:
+ {
+ pszActivity = "run";
+ break;
+ }
+ }
+
+ Msg( "Activity: %s\n", pszActivity );
+
+#endif
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : iStartLine -
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::DebugShowAnimState( int iStartLine )
+{
+ Vector vOuterVel;
+ GetOuterAbsVelocity( vOuterVel );
+
+ Anim_StateLog( "----------------- frame %d -----------------\n", gpGlobals->framecount );
+
+ int iLine = iStartLine;
+ Anim_StatePrintf( iLine++, "main: %s, cycle: %.2f\n", GetSequenceName( GetBasePlayer()->GetModelPtr(), GetBasePlayer()->GetSequence() ), GetBasePlayer()->GetCycle() );
+
+#if defined( CLIENT_DLL )
+ for ( int i=0; i < GetBasePlayer()->GetNumAnimOverlays()-1; i++ )
+ {
+ C_AnimationLayer *pLayer = GetBasePlayer()->GetAnimOverlay( i /*i+1?*/ );
+ Anim_StatePrintf( iLine++, "%s, weight: %.2f, cycle: %.2f, aim (%d)",
+ pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? "--" : GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->m_nSequence ),
+ pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->m_flWeight,
+ pLayer->m_nOrder == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->m_flCycle,
+ i
+ );
+ }
+#endif
+
+ Anim_StatePrintf( iLine++, "vel: %.2f, time: %.2f, max: %.2f",
+ vOuterVel.Length2D(), gpGlobals->curtime, GetInterpolatedGroundSpeed() );
+
+// AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, body_pitch: %.2f, move_x: %.2f, move_y: %.2f",
+// m_angRender[YAW], g_flLastBodyYaw, g_flLastBodyPitch, m_vLastMovePose.x, m_vLastMovePose.y );
+
+ Anim_StateLog( "--------------------------------------------\n\n" );
+
+ // Draw a red triangle on the ground for the eye yaw.
+ float flBaseSize = 10;
+ float flHeight = 80;
+ Vector vBasePos = GetBasePlayer()->GetAbsOrigin() + Vector( 0, 0, 3 );
+ QAngle angles( 0, 0, 0 );
+ angles[YAW] = m_flEyeYaw;
+ Vector vForward, vRight, vUp;
+ AngleVectors( angles, &vForward, &vRight, &vUp );
+ debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 255, 0, 0, 255, false, 0.01 );
+
+ // Draw a blue triangle on the ground for the body yaw.
+ angles[YAW] = m_angRender[YAW];
+ AngleVectors( angles, &vForward, &vRight, &vUp );
+ debugoverlay->AddTriangleOverlay( vBasePos+vRight*flBaseSize/2, vBasePos-vRight*flBaseSize/2, vBasePos+vForward*flHeight, 0, 0, 255, 255, false, 0.01 );
+}
+
+// Debug!
+const char *s_aGestureSlotNames[GESTURE_SLOT_COUNT] =
+{
+ "Attack and Reload",
+ "Grenade",
+ "Jump",
+ "Swim",
+ "Flinch",
+ "VCD",
+ "Custom"
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::DebugGestureInfo( void )
+{
+ CBasePlayer *pPlayer = GetBasePlayer();
+ if ( !pPlayer )
+ return;
+
+ int iLine = ( pPlayer->IsServer() ? 12 : ( 14 + GESTURE_SLOT_COUNT ) );
+
+ Anim_StatePrintf( iLine++, "%s\n", ( pPlayer->IsServer() ? "Server" : "Client" ) );
+
+ for ( int iGesture = 0; iGesture < GESTURE_SLOT_COUNT; ++iGesture )
+ {
+ GestureSlot_t *pGesture = &m_aGestureSlots[iGesture];
+ if ( pGesture )
+ {
+ if( pGesture->m_bActive )
+ {
+ Anim_StatePrintf( iLine++, "Gesture Slot %d(%s): %s %s(A:%s, C:%f P:%f)\n",
+ iGesture,
+ s_aGestureSlotNames[iGesture],
+ ActivityList_NameForIndex( pGesture->m_iActivity ),
+ GetSequenceName( pPlayer->GetModelPtr(), pGesture->m_pAnimLayer->m_nSequence ),
+ ( pGesture->m_bAutoKill ? "true" : "false" ),
+ (float)pGesture->m_pAnimLayer->m_flCycle, (float)pGesture->m_pAnimLayer->m_flPlaybackRate );
+ }
+ else
+ {
+ Anim_StatePrintf( iLine++, "Gesture Slot %d(%s): NOT ACTIVE!\n", iGesture, s_aGestureSlotNames[iGesture] );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: New Model, init the pose parameters
+//-----------------------------------------------------------------------------
+void CMultiPlayerAnimState::OnNewModel( void )
+{
+ m_bPoseParameterInit = false;
+ m_PoseParameterData.Init();
+ ClearAnimationState();
+}