diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp')
| -rw-r--r-- | mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp | 2033 |
1 files changed, 2033 insertions, 0 deletions
diff --git a/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp new file mode 100644 index 00000000..135234d7 --- /dev/null +++ b/mp/src/game/shared/Multiplayer/multiplayer_animstate.cpp @@ -0,0 +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();
+}
|