diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/shared/base_playeranimstate.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/shared/base_playeranimstate.cpp')
| -rw-r--r-- | mp/src/game/shared/base_playeranimstate.cpp | 2158 |
1 files changed, 1079 insertions, 1079 deletions
diff --git a/mp/src/game/shared/base_playeranimstate.cpp b/mp/src/game/shared/base_playeranimstate.cpp index 411d764f..a25d773c 100644 --- a/mp/src/game/shared/base_playeranimstate.cpp +++ b/mp/src/game/shared/base_playeranimstate.cpp @@ -1,1079 +1,1079 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "cbase.h"
-#include "base_playeranimstate.h"
-#include "tier0/vprof.h"
-#include "animation.h"
-#include "studio.h"
-#include "apparent_velocity_helper.h"
-#include "utldict.h"
-#include "filesystem.h"
-
-
-#ifdef CLIENT_DLL
- #include "c_baseplayer.h"
- #include "engine/ivdebugoverlay.h"
-
- ConVar cl_showanimstate( "cl_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (client) animation state for the specified entity (-1 for none)." );
- ConVar showanimstate_log( "cl_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output cl_showanimstate to Msg(). 2 to store in AnimStateClient.log. 3 for both." );
-#else
- #include "player.h"
- ConVar sv_showanimstate( "sv_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (server) animation state for the specified entity (-1 for none)." );
- ConVar showanimstate_log( "sv_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output sv_showanimstate to Msg(). 2 to store in AnimStateServer.log. 3 for both." );
-#endif
-
-
-// Below this many degrees, slow down turning rate linearly
-#define FADE_TURN_DEGREES 45.0f
-
-// After this, need to start turning feet
-#define MAX_TORSO_ANGLE 70.0f
-
-// Below this amount, don't play a turning animation/perform IK
-#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f
-
-
-ConVar mp_feetyawrate(
- "mp_feetyawrate",
- "720",
- FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY,
- "How many degrees per second that we can turn our feet or upper body." );
-
-ConVar mp_facefronttime(
- "mp_facefronttime",
- "3",
- FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY,
- "After this amount of time of standing in place but aiming to one side, go ahead and move feet to face upper body." );
-
-ConVar mp_ik( "mp_ik", "1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Use IK on in-place turns." );
-
-// Pose parameters stored for debugging.
-float g_flLastBodyPitch, g_flLastBodyYaw, m_flLastMoveYaw;
-
-
-// ------------------------------------------------------------------------------------------------ //
-// CBasePlayerAnimState implementation.
-// ------------------------------------------------------------------------------------------------ //
-
-CBasePlayerAnimState::CBasePlayerAnimState()
-{
- m_flEyeYaw = 0.0f;
- m_flEyePitch = 0.0f;
- m_bCurrentFeetYawInitialized = false;
- m_flCurrentTorsoYaw = 0.0f;
- m_flCurrentTorsoYaw = TURN_NONE;
- m_flMaxGroundSpeed = 0.0f;
- m_flStoredCycle = 0.0f;
-
- m_flGaitYaw = 0.0f;
- m_flGoalFeetYaw = 0.0f;
- m_flCurrentFeetYaw = 0.0f;
- m_flLastYaw = 0.0f;
- m_flLastTurnTime = 0.0f;
- m_angRender.Init();
- m_vLastMovePose.Init();
- m_iCurrent8WayIdleSequence = -1;
- m_iCurrent8WayCrouchIdleSequence = -1;
-
- m_pOuter = NULL;
- m_eCurrentMainSequenceActivity = ACT_IDLE;
- m_flLastAnimationStateClearTime = 0.0f;
-}
-
-
-CBasePlayerAnimState::~CBasePlayerAnimState()
-{
-}
-
-
-void CBasePlayerAnimState::Init( CBaseAnimatingOverlay *pPlayer, const CModAnimConfig &config )
-{
- m_pOuter = pPlayer;
- m_AnimConfig = config;
- ClearAnimationState();
-}
-
-
-void CBasePlayerAnimState::Release()
-{
- delete this;
-}
-
-
-void CBasePlayerAnimState::ClearAnimationState()
-{
- ClearAnimationLayers();
- m_bCurrentFeetYawInitialized = false;
- m_flLastAnimationStateClearTime = gpGlobals->curtime;
-}
-
-
-float CBasePlayerAnimState::TimeSinceLastAnimationStateClear() const
-{
- return gpGlobals->curtime - m_flLastAnimationStateClearTime;
-}
-
-
-void CBasePlayerAnimState::Update( float eyeYaw, float eyePitch )
-{
- VPROF( "CBasePlayerAnimState::Update" );
-
- // Clear animation overlays because we're about to completely reconstruct them.
- ClearAnimationLayers();
-
- // Some mods don't want to update the player's animation state if they're dead and ragdolled.
- if ( !ShouldUpdateAnimState() )
- {
- ClearAnimationState();
- return;
- }
-
-
- CStudioHdr *pStudioHdr = GetOuter()->GetModelPtr();
- // Store these. All the calculations are based on them.
- m_flEyeYaw = AngleNormalize( eyeYaw );
- m_flEyePitch = AngleNormalize( eyePitch );
-
- // Compute sequences for all the layers.
- ComputeSequences( pStudioHdr );
-
-
- // Compute all the pose params.
- ComputePoseParam_BodyPitch( pStudioHdr ); // Look up/down.
- ComputePoseParam_BodyYaw(); // Torso rotation.
- ComputePoseParam_MoveYaw( pStudioHdr ); // What direction his legs are running in.
-
-
- ComputePlaybackRate();
-
-
-#ifdef CLIENT_DLL
- if ( cl_showanimstate.GetInt() == m_pOuter->entindex() )
- {
- DebugShowAnimStateFull( 5 );
- }
- else if ( cl_showanimstate.GetInt() == -2 )
- {
- C_BasePlayer *targetPlayer = C_BasePlayer::GetLocalPlayer();
-
- if( targetPlayer && ( targetPlayer->GetObserverMode() == OBS_MODE_IN_EYE || targetPlayer->GetObserverMode() == OBS_MODE_CHASE ) )
- {
- C_BaseEntity *target = targetPlayer->GetObserverTarget();
-
- if( target && target->IsPlayer() )
- {
- targetPlayer = ToBasePlayer( target );
- }
- }
-
- if ( m_pOuter == targetPlayer )
- {
- DebugShowAnimStateFull( 6 );
- }
- }
-#else
- if ( sv_showanimstate.GetInt() == m_pOuter->entindex() )
- {
- DebugShowAnimState( 20 );
- }
-#endif
-}
-
-
-bool CBasePlayerAnimState::ShouldUpdateAnimState()
-{
- // By default, don't update their animation state when they're dead because they're
- // either a ragdoll or they're not drawn.
- return GetOuter()->IsAlive();
-}
-
-
-bool CBasePlayerAnimState::ShouldChangeSequences( void ) const
-{
- return true;
-}
-
-
-void CBasePlayerAnimState::SetOuterPoseParameter( int iParam, float flValue )
-{
- // Make sure to set all the history values too, otherwise the server can overwrite them.
- GetOuter()->SetPoseParameter( iParam, flValue );
-}
-
-
-void CBasePlayerAnimState::ClearAnimationLayers()
-{
- VPROF( "CBasePlayerAnimState::ClearAnimationLayers" );
- if ( !m_pOuter )
- return;
-
- m_pOuter->SetNumAnimOverlays( AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS );
- for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ )
- {
- m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS );
-#ifndef CLIENT_DLL
- m_pOuter->GetAnimOverlay( i )->m_fFlags = 0;
-#endif
- }
-}
-
-
-void CBasePlayerAnimState::RestartMainSequence()
-{
- CBaseAnimatingOverlay *pPlayer = GetOuter();
-
- pPlayer->m_flAnimTime = gpGlobals->curtime;
- pPlayer->SetCycle( 0 );
-}
-
-
-void CBasePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr )
-{
- VPROF( "CBasePlayerAnimState::ComputeSequences" );
-
- ComputeMainSequence(); // Lower body (walk/run/idle).
- UpdateInterpolators(); // The groundspeed interpolator uses the main sequence info.
-
- if ( m_AnimConfig.m_bUseAimSequences )
- {
- ComputeAimSequence(); // Upper body, based on weapon type.
- }
-}
-
-void CBasePlayerAnimState::ResetGroundSpeed( void )
-{
- m_flMaxGroundSpeed = GetCurrentMaxGroundSpeed();
-}
-
-void CBasePlayerAnimState::ComputeMainSequence()
-{
- VPROF( "CBasePlayerAnimState::ComputeMainSequence" );
-
- CBaseAnimatingOverlay *pPlayer = GetOuter();
-
- // 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;
-
- // Export to our outer class..
- int animDesired = SelectWeightedSequence( TranslateActivity(idealActivity) );
-
-#if !defined( HL1_CLIENT_DLL ) && !defined ( HL1_DLL )
- if ( pPlayer->GetSequenceActivity( pPlayer->GetSequence() ) == pPlayer->GetSequenceActivity( animDesired ) )
- return;
-#endif
-
- 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_CROUCHIDLE || oldActivity == ACT_IDLE) &&
- (idealActivity == ACT_WALK || idealActivity == ACT_RUN_CROUCH) )
- {
- ResetGroundSpeed();
- }
-#endif
-}
-
-
-
-
-
-void CBasePlayerAnimState::UpdateAimSequenceLayers(
- float flCycle,
- int iFirstLayer,
- bool bForceIdle,
- CSequenceTransitioner *pTransitioner,
- float flWeightScale
- )
-{
- float flAimSequenceWeight = 1;
- int iAimSequence = CalcAimLayerSequence( &flCycle, &flAimSequenceWeight, bForceIdle );
- if ( iAimSequence == -1 )
- iAimSequence = 0;
-
- // Feed the current state of the animation parameters to the sequence transitioner.
- // It will hand back either 1 or 2 animations in the queue to set, depending on whether
- // it's transitioning or not. We just dump those into the animation layers.
- pTransitioner->CheckForSequenceChange(
- m_pOuter->GetModelPtr(),
- iAimSequence,
- false, // don't force transitions on the same anim
- true // yes, interpolate when transitioning
- );
-
- pTransitioner->UpdateCurrent(
- m_pOuter->GetModelPtr(),
- iAimSequence,
- flCycle,
- GetOuter()->GetPlaybackRate(),
- gpGlobals->curtime
- );
-
- CAnimationLayer *pDest0 = m_pOuter->GetAnimOverlay( iFirstLayer );
- CAnimationLayer *pDest1 = m_pOuter->GetAnimOverlay( iFirstLayer+1 );
-
- if ( pTransitioner->m_animationQueue.Count() == 1 )
- {
- // If only 1 animation, then blend it in fully.
- CAnimationLayer *pSource0 = &pTransitioner->m_animationQueue[0];
- *pDest0 = *pSource0;
-
- pDest0->m_flWeight = 1;
- pDest1->m_flWeight = 0;
- pDest0->m_nOrder = iFirstLayer;
-
-#ifndef CLIENT_DLL
- pDest0->m_fFlags |= ANIM_LAYER_ACTIVE;
-#endif
- }
- else if ( pTransitioner->m_animationQueue.Count() >= 2 )
- {
- // The first one should be fading out. Fade in the new one inversely.
- CAnimationLayer *pSource0 = &pTransitioner->m_animationQueue[0];
- CAnimationLayer *pSource1 = &pTransitioner->m_animationQueue[1];
-
- *pDest0 = *pSource0;
- *pDest1 = *pSource1;
- Assert( pDest0->m_flWeight >= 0.0f && pDest0->m_flWeight <= 1.0f );
- pDest1->m_flWeight = 1 - pDest0->m_flWeight; // This layer just mirrors the other layer's weight (one fades in while the other fades out).
-
- pDest0->m_nOrder = iFirstLayer;
- pDest1->m_nOrder = iFirstLayer+1;
-
-#ifndef CLIENT_DLL
- pDest0->m_fFlags |= ANIM_LAYER_ACTIVE;
- pDest1->m_fFlags |= ANIM_LAYER_ACTIVE;
-#endif
- }
-
- pDest0->m_flWeight *= flWeightScale * flAimSequenceWeight;
- pDest0->m_flWeight = clamp( (float)pDest0->m_flWeight, 0.0f, 1.0f );
-
- pDest1->m_flWeight *= flWeightScale * flAimSequenceWeight;
- pDest1->m_flWeight = clamp( (float)pDest1->m_flWeight, 0.0f, 1.0f );
-
- pDest0->m_flCycle = pDest1->m_flCycle = flCycle;
-}
-
-
-void CBasePlayerAnimState::OptimizeLayerWeights( int iFirstLayer, int nLayers )
-{
- int i;
-
- // Find the total weight of the blended layers, not including the idle layer (iFirstLayer)
- float totalWeight = 0.0f;
- for ( i=1; i < nLayers; i++ )
- {
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i );
- if ( pLayer->IsActive() && pLayer->m_flWeight > 0.0f )
- {
- totalWeight += pLayer->m_flWeight;
- }
- }
-
- // Set the idle layer's weight to be 1 minus the sum of other layer weights
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer );
- if ( pLayer->IsActive() && pLayer->m_flWeight > 0.0f )
- {
- pLayer->m_flWeight = 1.0f - totalWeight;
- pLayer->m_flWeight = MAX( (float)pLayer->m_flWeight, 0.0f);
- }
-
- // This part is just an optimization. Since we have the walk/run animations weighted on top of
- // the idle animations, all this does is disable the idle animations if the walk/runs are at
- // full weighting, which is whenever a guy is at full speed.
- //
- // So it saves us blending a couple animation layers whenever a guy is walking or running full speed.
- int iLastOne = -1;
- for ( i=0; i < nLayers; i++ )
- {
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i );
- if ( pLayer->IsActive() && pLayer->m_flWeight > 0.99 )
- iLastOne = i;
- }
-
- if ( iLastOne != -1 )
- {
- for ( int i=iLastOne-1; i >= 0; i-- )
- {
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i );
-#ifdef CLIENT_DLL
- pLayer->m_nOrder = CBaseAnimatingOverlay::MAX_OVERLAYS;
-#else
- pLayer->m_nOrder.Set( CBaseAnimatingOverlay::MAX_OVERLAYS );
- pLayer->m_fFlags = 0;
-#endif
- }
- }
-}
-
-bool CBasePlayerAnimState::ShouldBlendAimSequenceToIdle()
-{
- Activity act = GetCurrentMainSequenceActivity();
-
- return (act == ACT_RUN || act == ACT_WALK || act == ACT_RUNTOIDLE || act == ACT_RUN_CROUCH);
-}
-
-void CBasePlayerAnimState::ComputeAimSequence()
-{
- VPROF( "CBasePlayerAnimState::ComputeAimSequence" );
-
- // Synchronize the lower and upper body cycles.
- float flCycle = m_pOuter->GetCycle();
-
- // Figure out the new cycle time.
- UpdateAimSequenceLayers( flCycle, AIMSEQUENCE_LAYER, true, &m_IdleSequenceTransitioner, 1 );
-
- if ( ShouldBlendAimSequenceToIdle() )
- {
- // What we do here is blend between the idle upper body animation (like where he's got the dual elites
- // held out in front of him but he's not moving) and his walk/run/crouchrun upper body animation,
- // weighting it based on how fast he's moving. That way, when he's moving slowly, his upper
- // body doesn't jiggle all around.
- bool bIsMoving;
- float flPlaybackRate = CalcMovementPlaybackRate( &bIsMoving );
- if ( bIsMoving )
- UpdateAimSequenceLayers( flCycle, AIMSEQUENCE_LAYER+2, false, &m_SequenceTransitioner, flPlaybackRate );
- }
-
- OptimizeLayerWeights( AIMSEQUENCE_LAYER, NUM_AIMSEQUENCE_LAYERS );
-}
-
-
-int CBasePlayerAnimState::CalcSequenceIndex( const char *pBaseName, ... )
-{
- char szFullName[512];
- va_list marker;
- va_start( marker, pBaseName );
- Q_vsnprintf( szFullName, sizeof( szFullName ), pBaseName, marker );
- va_end( marker );
- int iSequence = GetOuter()->LookupSequence( szFullName );
-
- // Show warnings if we can't find anything here.
- if ( iSequence == -1 )
- {
- static CUtlDict<int,int> dict;
- if ( dict.Find( szFullName ) == -1 )
- {
- dict.Insert( szFullName, 0 );
- Warning( "CalcSequenceIndex: can't find '%s'.\n", szFullName );
- }
-
- iSequence = 0;
- }
-
- return iSequence;
-}
-
-
-
-void CBasePlayerAnimState::UpdateInterpolators()
-{
- VPROF( "CBasePlayerAnimState::UpdateInterpolators" );
-
- // First, figure out their current max speed based on their current activity.
- float flCurMaxSpeed = GetCurrentMaxGroundSpeed();
- m_flMaxGroundSpeed = flCurMaxSpeed;
-}
-
-
-float CBasePlayerAnimState::GetInterpolatedGroundSpeed()
-{
- return m_flMaxGroundSpeed;
-}
-
-
-float CBasePlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
-{
- // Determine ideal playback rate
- Vector vel;
- GetOuterAbsVelocity( vel );
-
- float speed = vel.Length2D();
- bool isMoving = ( speed > MOVING_MINIMUM_SPEED );
-
- *bIsMoving = false;
- float flReturnValue = 1;
-
- if ( isMoving && CanThePlayerMove() )
- {
- float flGroundSpeed = GetInterpolatedGroundSpeed();
- if ( flGroundSpeed < 0.001f )
- {
- flReturnValue = 0.01;
- }
- else
- {
- // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
- flReturnValue = speed / flGroundSpeed;
- flReturnValue = clamp( flReturnValue, 0.01f, 10.f ); // don't go nuts here.
- }
- *bIsMoving = true;
- }
-
- return flReturnValue;
-}
-
-
-bool CBasePlayerAnimState::CanThePlayerMove()
-{
- return true;
-}
-
-
-void CBasePlayerAnimState::ComputePlaybackRate()
-{
- VPROF( "CBasePlayerAnimState::ComputePlaybackRate" );
- if ( m_AnimConfig.m_LegAnimType != LEGANIM_9WAY && m_AnimConfig.m_LegAnimType != LEGANIM_8WAY )
- {
- // When using a 9-way blend, playback rate is always 1 and we just scale the pose params
- // to speed up or slow down the animation.
- bool bIsMoving;
- float flRate = CalcMovementPlaybackRate( &bIsMoving );
- if ( bIsMoving )
- GetOuter()->SetPlaybackRate( flRate );
- else
- GetOuter()->SetPlaybackRate( 1 );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : CBasePlayer
-//-----------------------------------------------------------------------------
-CBaseAnimatingOverlay *CBasePlayerAnimState::GetOuter() const
-{
- return m_pOuter;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : dt -
-//-----------------------------------------------------------------------------
-void CBasePlayerAnimState::EstimateYaw()
-{
- Vector est_velocity;
- GetOuterAbsVelocity( est_velocity );
-
- float flLength = est_velocity.Length2D();
- if ( flLength > MOVING_MINIMUM_SPEED )
- {
- m_flGaitYaw = atan2( est_velocity[1], est_velocity[0] );
- m_flGaitYaw = RAD2DEG( m_flGaitYaw );
- m_flGaitYaw = AngleNormalize( m_flGaitYaw );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Override for backpeddling
-// Input : dt -
-//-----------------------------------------------------------------------------
-void CBasePlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr )
-{
- VPROF( "CBasePlayerAnimState::ComputePoseParam_MoveYaw" );
-
- //Matt: Goldsrc style animations need to not rotate the model
- if ( m_AnimConfig.m_LegAnimType == LEGANIM_GOLDSRC )
- {
-#ifndef CLIENT_DLL
- //Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
- GetOuter()->SetLocalAngles( QAngle( 0, m_flCurrentFeetYaw, 0 ) );
-#endif
- }
-
- // If using goldsrc-style animations where he's moving in the direction that his feet are facing,
- // we don't use move yaw.
- if ( m_AnimConfig.m_LegAnimType != LEGANIM_9WAY && m_AnimConfig.m_LegAnimType != LEGANIM_8WAY )
- return;
-
- // view direction relative to movement
- float flYaw;
-
- EstimateYaw();
-
- float ang = m_flEyeYaw;
- if ( ang > 180.0f )
- {
- ang -= 360.0f;
- }
- else if ( ang < -180.0f )
- {
- ang += 360.0f;
- }
-
- // calc side to side turning
- flYaw = ang - m_flGaitYaw;
- // Invert for mapping into 8way blend
- flYaw = -flYaw;
- flYaw = flYaw - (int)(flYaw / 360) * 360;
-
- if (flYaw < -180)
- {
- flYaw = flYaw + 360;
- }
- else if (flYaw > 180)
- {
- flYaw = flYaw - 360;
- }
-
-
- if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY )
- {
-#ifndef CLIENT_DLL
- //Adrian: Make the model's angle match the legs so the hitboxes match on both sides.
- GetOuter()->SetLocalAngles( QAngle( 0, m_flCurrentFeetYaw, 0 ) );
-#endif
-
- int iMoveX = GetOuter()->LookupPoseParameter( pStudioHdr, "move_x" );
- int iMoveY = GetOuter()->LookupPoseParameter( pStudioHdr, "move_y" );
- if ( iMoveX < 0 || iMoveY < 0 )
- return;
-
- bool bIsMoving;
- float flPlaybackRate = CalcMovementPlaybackRate( &bIsMoving );
-
- // Setup the 9-way blend parameters based on our speed and direction.
- Vector2D vCurMovePose( 0, 0 );
-
- if ( bIsMoving )
- {
- vCurMovePose.x = cos( DEG2RAD( flYaw ) ) * flPlaybackRate;
- vCurMovePose.y = -sin( DEG2RAD( flYaw ) ) * flPlaybackRate;
- }
-
- GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, vCurMovePose.x );
- GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, vCurMovePose.y );
-
- m_vLastMovePose = vCurMovePose;
- }
- else
- {
- int iMoveYaw = GetOuter()->LookupPoseParameter( pStudioHdr, "move_yaw" );
- if ( iMoveYaw >= 0 )
- {
- GetOuter()->SetPoseParameter( pStudioHdr, iMoveYaw, flYaw );
- m_flLastMoveYaw = flYaw;
-
- // Now blend in his idle animation.
- // This makes the 8-way blend act like a 9-way blend by blending to
- // an idle sequence as he slows down.
-#if defined(CLIENT_DLL)
- bool bIsMoving;
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER );
-
- pLayer->m_flWeight = 1 - CalcMovementPlaybackRate( &bIsMoving );
- if ( !bIsMoving )
- {
- pLayer->m_flWeight = 1;
- }
-
- if ( ShouldChangeSequences() )
- {
- // Whenever this layer stops blending, we can choose a new idle sequence to blend to, so he
- // doesn't always use the same idle.
- if ( pLayer->m_flWeight < 0.02f || m_iCurrent8WayIdleSequence == -1 )
- {
- m_iCurrent8WayIdleSequence = m_pOuter->SelectWeightedSequence( ACT_IDLE );
- m_iCurrent8WayCrouchIdleSequence = m_pOuter->SelectWeightedSequence( ACT_CROUCHIDLE );
- }
-
- if ( m_eCurrentMainSequenceActivity == ACT_CROUCHIDLE || m_eCurrentMainSequenceActivity == ACT_RUN_CROUCH )
- pLayer->m_nSequence = m_iCurrent8WayCrouchIdleSequence;
- else
- pLayer->m_nSequence = m_iCurrent8WayIdleSequence;
- }
-
- pLayer->m_flPlaybackRate = 1;
- pLayer->m_flCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, pLayer->m_nSequence ) * gpGlobals->frametime;
- pLayer->m_flCycle = fmod( pLayer->m_flCycle, 1 );
- pLayer->m_nOrder = MAIN_IDLE_SEQUENCE_LAYER;
-#endif
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CBasePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr )
-{
- VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyPitch" );
-
- // Get pitch from v_angle
- float flPitch = m_flEyePitch;
- if ( flPitch > 180.0f )
- {
- flPitch -= 360.0f;
- }
- flPitch = clamp( flPitch, -90.f, 90.f );
-
- // See if we have a blender for pitch
- int pitch = GetOuter()->LookupPoseParameter( pStudioHdr, "body_pitch" );
- if ( pitch < 0 )
- return;
-
- GetOuter()->SetPoseParameter( pStudioHdr, pitch, flPitch );
- g_flLastBodyPitch = flPitch;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : goal -
-// maxrate -
-// dt -
-// current -
-// Output : int
-//-----------------------------------------------------------------------------
-int CBasePlayerAnimState::ConvergeAngles( float goal,float maxrate, float maxgap, float dt, float& current )
-{
- int direction = TURN_NONE;
-
- float anglediff = goal - current;
- anglediff = AngleNormalize( anglediff );
-
- float anglediffabs = fabs( anglediff );
-
- float scale = 1.0f;
- if ( anglediffabs <= FADE_TURN_DEGREES )
- {
- scale = anglediffabs / FADE_TURN_DEGREES;
- // Always do at least a bit of the turn ( 1% )
- scale = clamp( scale, 0.01f, 1.0f );
- }
-
- float maxmove = maxrate * dt * scale;
-
- if ( anglediffabs > maxgap )
- {
- // gap is too big, jump
- maxmove = (anglediffabs - maxgap);
- }
-
- if ( anglediffabs < maxmove )
- {
- // we are close enought, just set the final value
- current = goal;
- }
- else
- {
- // adjust value up or down
- if ( anglediff > 0 )
- {
- current += maxmove;
- direction = TURN_LEFT;
- }
- else
- {
- current -= maxmove;
- direction = TURN_RIGHT;
- }
- }
-
- current = AngleNormalize( current );
-
- return direction;
-}
-
-void CBasePlayerAnimState::ComputePoseParam_BodyYaw()
-{
- VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyYaw" );
-
- // Find out which way he's running (m_flEyeYaw is the way he's looking).
- Vector vel;
- GetOuterAbsVelocity( vel );
- bool bIsMoving = vel.Length2D() > MOVING_MINIMUM_SPEED;
-
- // If we just initialized this guy (maybe he just came into the PVS), then immediately
- // set his feet in the right direction, otherwise they'll spin around from 0 to the
- // right direction every time someone switches spectator targets.
- if ( !m_bCurrentFeetYawInitialized )
- {
- m_bCurrentFeetYawInitialized = true;
- m_flGoalFeetYaw = m_flCurrentFeetYaw = m_flEyeYaw;
- m_flLastTurnTime = 0.0f;
- }
- else if ( bIsMoving )
- {
- // player is moving, feet yaw = aiming yaw
- if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY || m_AnimConfig.m_LegAnimType == LEGANIM_8WAY )
- {
- // His feet point in the direction his eyes are, but they can run in any direction.
- m_flGoalFeetYaw = m_flEyeYaw;
- }
- else
- {
- m_flGoalFeetYaw = RAD2DEG( atan2( vel.y, vel.x ) );
-
- // If he's running backwards, flip his feet backwards.
- Vector vEyeYaw( cos( DEG2RAD( m_flEyeYaw ) ), sin( DEG2RAD( m_flEyeYaw ) ), 0 );
- Vector vFeetYaw( cos( DEG2RAD( m_flGoalFeetYaw ) ), sin( DEG2RAD( m_flGoalFeetYaw ) ), 0 );
- if ( vEyeYaw.Dot( vFeetYaw ) < -0.01 )
- {
- m_flGoalFeetYaw += 180;
- }
- }
-
- }
- else if ( (gpGlobals->curtime - m_flLastTurnTime) > mp_facefronttime.GetFloat() )
- {
- // player didn't move & turn for quite some time
- m_flGoalFeetYaw = m_flEyeYaw;
- }
- else
- {
- // If he's rotated his view further than the model can turn, make him face forward.
- float flDiff = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw );
-
- if ( fabs(flDiff) > m_AnimConfig.m_flMaxBodyYawDegrees )
- {
- if ( flDiff > 0 )
- m_flGoalFeetYaw -= m_AnimConfig.m_flMaxBodyYawDegrees;
- else
- m_flGoalFeetYaw += m_AnimConfig.m_flMaxBodyYawDegrees;
- }
- }
-
- m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw );
-
- if ( m_flCurrentFeetYaw != m_flGoalFeetYaw )
- {
- ConvergeAngles( m_flGoalFeetYaw, mp_feetyawrate.GetFloat(), m_AnimConfig.m_flMaxBodyYawDegrees,
- gpGlobals->frametime, m_flCurrentFeetYaw );
-
- m_flLastTurnTime = gpGlobals->curtime;
- }
-
- float flCurrentTorsoYaw = AngleNormalize( m_flEyeYaw - m_flCurrentFeetYaw );
-
- // Rotate entire body into position
- m_angRender[YAW] = m_flCurrentFeetYaw;
- m_angRender[PITCH] = m_angRender[ROLL] = 0;
-
- SetOuterBodyYaw( flCurrentTorsoYaw );
- g_flLastBodyYaw = flCurrentTorsoYaw;
-}
-
-
-
-float CBasePlayerAnimState::SetOuterBodyYaw( float flValue )
-{
- int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" );
- if ( body_yaw < 0 )
- {
- return 0;
- }
-
- SetOuterPoseParameter( body_yaw, flValue );
- return flValue;
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : activity -
-// Output : Activity
-//-----------------------------------------------------------------------------
-Activity CBasePlayerAnimState::BodyYawTranslateActivity( Activity activity )
-{
- // Not even standing still, sigh
- if ( activity != ACT_IDLE )
- return activity;
-
- // Not turning
- switch ( m_nTurningInPlace )
- {
- default:
- case TURN_NONE:
- return activity;
- case TURN_RIGHT:
- case TURN_LEFT:
- return mp_ik.GetBool() ? ACT_TURN : activity;
- }
-
- Assert( 0 );
- return activity;
-}
-
-const QAngle& CBasePlayerAnimState::GetRenderAngles()
-{
- return m_angRender;
-}
-
-
-void CBasePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) const
-{
-#if defined( CLIENT_DLL )
- GetOuter()->EstimateAbsVelocity( vel );
-#else
- vel = GetOuter()->GetAbsVelocity();
-#endif
-}
-
-
-float CBasePlayerAnimState::GetOuterXYSpeed() const
-{
- Vector vel;
- GetOuterAbsVelocity( vel );
- return vel.Length2D();
-}
-
-// -----------------------------------------------------------------------------
-void CBasePlayerAnimState::AnimStateLog( 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 ( showanimstate_log.GetInt() == 1 || showanimstate_log.GetInt() == 3 )
- {
- Msg( "%s", str );
- }
-
- if ( showanimstate_log.GetInt() > 1 )
- {
-#ifdef CLIENT_DLL
- const char *fname = "AnimStateClient.log";
-#else
- const char *fname = "AnimStateServer.log";
-#endif
- static FileHandle_t hFile = filesystem->Open( fname, "wt" );
- filesystem->FPrintf( hFile, "%s", str );
- filesystem->Flush( hFile );
- }
-}
-
-
-// -----------------------------------------------------------------------------
-void CBasePlayerAnimState::AnimStatePrintf( 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.
- AnimStateLog( "%s\n", str );
-}
-
-
-// -----------------------------------------------------------------------------
-void CBasePlayerAnimState::DebugShowAnimState( int iStartLine )
-{
- Vector vOuterVel;
- GetOuterAbsVelocity( vOuterVel );
-
- int iLine = iStartLine;
- AnimStatePrintf( iLine++, "main: %s(%d), cycle: %.2f cyclerate: %.2f playbackrate: %.2f\n",
- GetSequenceName( m_pOuter->GetModelPtr(), m_pOuter->GetSequence() ),
- m_pOuter->GetSequence(),
- m_pOuter->GetCycle(),
- m_pOuter->GetSequenceCycleRate(m_pOuter->GetModelPtr(), m_pOuter->GetSequence()),
- m_pOuter->GetPlaybackRate()
- );
-
- if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY )
- {
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER );
-
- AnimStatePrintf( iLine++, "idle: %s, weight: %.2f\n",
- GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ),
- (float)pLayer->m_flWeight );
- }
-
- for ( int i=0; i < m_pOuter->GetNumAnimOverlays()-1; i++ )
- {
- CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( AIMSEQUENCE_LAYER + i );
-#ifdef CLIENT_DLL
- AnimStatePrintf( iLine++, "%s(%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)",
- !pLayer->IsActive() ? "-- ": (pLayer->m_nSequence == 0 ? "-- " : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ) ),
- !pLayer->IsActive() ? 0 : (int)pLayer->m_nSequence,
- !pLayer->IsActive() ? 0 : (float)pLayer->m_flWeight,
- !pLayer->IsActive() ? 0 : (float)pLayer->m_flCycle,
- !pLayer->IsActive() ? 0 : (int)pLayer->m_nOrder,
- i
- );
-#else
- AnimStatePrintf( iLine++, "%s(%d), flags (%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)",
- !pLayer->IsActive() ? "-- " : ( pLayer->m_nSequence == 0 ? "-- " : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ) ),
- !pLayer->IsActive() ? 0 : (int)pLayer->m_nSequence,
- !pLayer->IsActive() ? 0 : (int)pLayer->m_fFlags,// Doesn't exist on client
- !pLayer->IsActive() ? 0 : (float)pLayer->m_flWeight,
- !pLayer->IsActive() ? 0 : (float)pLayer->m_flCycle,
- !pLayer->IsActive() ? 0 : (int)pLayer->m_nOrder,
- i
- );
-#endif
- }
-
- AnimStatePrintf( iLine++, "vel: %.2f, time: %.2f, max: %.2f, animspeed: %.2f",
- vOuterVel.Length2D(), gpGlobals->curtime, GetInterpolatedGroundSpeed(), m_pOuter->GetSequenceGroundSpeed(m_pOuter->GetSequence()) );
-
- if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY )
- {
- AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, move_yaw: %.2f, gait_yaw: %.2f, body_pitch: %.2f",
- m_angRender[YAW], g_flLastBodyYaw, m_flLastMoveYaw, m_flGaitYaw, g_flLastBodyPitch );
- }
- else
- {
- 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 );
- }
-
- // Draw a red triangle on the ground for the eye yaw.
- float flBaseSize = 10;
- float flHeight = 80;
- Vector vBasePos = GetOuter()->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 );
-
-}
-
-// -----------------------------------------------------------------------------
-void CBasePlayerAnimState::DebugShowAnimStateFull( int iStartLine )
-{
- AnimStateLog( "----------------- frame %d -----------------\n", gpGlobals->framecount );
-
- DebugShowAnimState( iStartLine );
-
- AnimStateLog( "--------------------------------------------\n\n" );
-}
-
-// -----------------------------------------------------------------------------
-int CBasePlayerAnimState::SelectWeightedSequence( Activity activity )
-{
- return GetOuter()->SelectWeightedSequence( activity );
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "base_playeranimstate.h" +#include "tier0/vprof.h" +#include "animation.h" +#include "studio.h" +#include "apparent_velocity_helper.h" +#include "utldict.h" +#include "filesystem.h" + + +#ifdef CLIENT_DLL + #include "c_baseplayer.h" + #include "engine/ivdebugoverlay.h" + + ConVar cl_showanimstate( "cl_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (client) animation state for the specified entity (-1 for none)." ); + ConVar showanimstate_log( "cl_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output cl_showanimstate to Msg(). 2 to store in AnimStateClient.log. 3 for both." ); +#else + #include "player.h" + ConVar sv_showanimstate( "sv_showanimstate", "-1", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "Show the (server) animation state for the specified entity (-1 for none)." ); + ConVar showanimstate_log( "sv_showanimstate_log", "0", FCVAR_CHEAT | FCVAR_DEVELOPMENTONLY, "1 to output sv_showanimstate to Msg(). 2 to store in AnimStateServer.log. 3 for both." ); +#endif + + +// Below this many degrees, slow down turning rate linearly +#define FADE_TURN_DEGREES 45.0f + +// After this, need to start turning feet +#define MAX_TORSO_ANGLE 70.0f + +// Below this amount, don't play a turning animation/perform IK +#define MIN_TURN_ANGLE_REQUIRING_TURN_ANIMATION 15.0f + + +ConVar mp_feetyawrate( + "mp_feetyawrate", + "720", + FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, + "How many degrees per second that we can turn our feet or upper body." ); + +ConVar mp_facefronttime( + "mp_facefronttime", + "3", + FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, + "After this amount of time of standing in place but aiming to one side, go ahead and move feet to face upper body." ); + +ConVar mp_ik( "mp_ik", "1", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY, "Use IK on in-place turns." ); + +// Pose parameters stored for debugging. +float g_flLastBodyPitch, g_flLastBodyYaw, m_flLastMoveYaw; + + +// ------------------------------------------------------------------------------------------------ // +// CBasePlayerAnimState implementation. +// ------------------------------------------------------------------------------------------------ // + +CBasePlayerAnimState::CBasePlayerAnimState() +{ + m_flEyeYaw = 0.0f; + m_flEyePitch = 0.0f; + m_bCurrentFeetYawInitialized = false; + m_flCurrentTorsoYaw = 0.0f; + m_flCurrentTorsoYaw = TURN_NONE; + m_flMaxGroundSpeed = 0.0f; + m_flStoredCycle = 0.0f; + + m_flGaitYaw = 0.0f; + m_flGoalFeetYaw = 0.0f; + m_flCurrentFeetYaw = 0.0f; + m_flLastYaw = 0.0f; + m_flLastTurnTime = 0.0f; + m_angRender.Init(); + m_vLastMovePose.Init(); + m_iCurrent8WayIdleSequence = -1; + m_iCurrent8WayCrouchIdleSequence = -1; + + m_pOuter = NULL; + m_eCurrentMainSequenceActivity = ACT_IDLE; + m_flLastAnimationStateClearTime = 0.0f; +} + + +CBasePlayerAnimState::~CBasePlayerAnimState() +{ +} + + +void CBasePlayerAnimState::Init( CBaseAnimatingOverlay *pPlayer, const CModAnimConfig &config ) +{ + m_pOuter = pPlayer; + m_AnimConfig = config; + ClearAnimationState(); +} + + +void CBasePlayerAnimState::Release() +{ + delete this; +} + + +void CBasePlayerAnimState::ClearAnimationState() +{ + ClearAnimationLayers(); + m_bCurrentFeetYawInitialized = false; + m_flLastAnimationStateClearTime = gpGlobals->curtime; +} + + +float CBasePlayerAnimState::TimeSinceLastAnimationStateClear() const +{ + return gpGlobals->curtime - m_flLastAnimationStateClearTime; +} + + +void CBasePlayerAnimState::Update( float eyeYaw, float eyePitch ) +{ + VPROF( "CBasePlayerAnimState::Update" ); + + // Clear animation overlays because we're about to completely reconstruct them. + ClearAnimationLayers(); + + // Some mods don't want to update the player's animation state if they're dead and ragdolled. + if ( !ShouldUpdateAnimState() ) + { + ClearAnimationState(); + return; + } + + + CStudioHdr *pStudioHdr = GetOuter()->GetModelPtr(); + // Store these. All the calculations are based on them. + m_flEyeYaw = AngleNormalize( eyeYaw ); + m_flEyePitch = AngleNormalize( eyePitch ); + + // Compute sequences for all the layers. + ComputeSequences( pStudioHdr ); + + + // Compute all the pose params. + ComputePoseParam_BodyPitch( pStudioHdr ); // Look up/down. + ComputePoseParam_BodyYaw(); // Torso rotation. + ComputePoseParam_MoveYaw( pStudioHdr ); // What direction his legs are running in. + + + ComputePlaybackRate(); + + +#ifdef CLIENT_DLL + if ( cl_showanimstate.GetInt() == m_pOuter->entindex() ) + { + DebugShowAnimStateFull( 5 ); + } + else if ( cl_showanimstate.GetInt() == -2 ) + { + C_BasePlayer *targetPlayer = C_BasePlayer::GetLocalPlayer(); + + if( targetPlayer && ( targetPlayer->GetObserverMode() == OBS_MODE_IN_EYE || targetPlayer->GetObserverMode() == OBS_MODE_CHASE ) ) + { + C_BaseEntity *target = targetPlayer->GetObserverTarget(); + + if( target && target->IsPlayer() ) + { + targetPlayer = ToBasePlayer( target ); + } + } + + if ( m_pOuter == targetPlayer ) + { + DebugShowAnimStateFull( 6 ); + } + } +#else + if ( sv_showanimstate.GetInt() == m_pOuter->entindex() ) + { + DebugShowAnimState( 20 ); + } +#endif +} + + +bool CBasePlayerAnimState::ShouldUpdateAnimState() +{ + // By default, don't update their animation state when they're dead because they're + // either a ragdoll or they're not drawn. + return GetOuter()->IsAlive(); +} + + +bool CBasePlayerAnimState::ShouldChangeSequences( void ) const +{ + return true; +} + + +void CBasePlayerAnimState::SetOuterPoseParameter( int iParam, float flValue ) +{ + // Make sure to set all the history values too, otherwise the server can overwrite them. + GetOuter()->SetPoseParameter( iParam, flValue ); +} + + +void CBasePlayerAnimState::ClearAnimationLayers() +{ + VPROF( "CBasePlayerAnimState::ClearAnimationLayers" ); + if ( !m_pOuter ) + return; + + m_pOuter->SetNumAnimOverlays( AIMSEQUENCE_LAYER+NUM_AIMSEQUENCE_LAYERS ); + for ( int i=0; i < m_pOuter->GetNumAnimOverlays(); i++ ) + { + m_pOuter->GetAnimOverlay( i )->SetOrder( CBaseAnimatingOverlay::MAX_OVERLAYS ); +#ifndef CLIENT_DLL + m_pOuter->GetAnimOverlay( i )->m_fFlags = 0; +#endif + } +} + + +void CBasePlayerAnimState::RestartMainSequence() +{ + CBaseAnimatingOverlay *pPlayer = GetOuter(); + + pPlayer->m_flAnimTime = gpGlobals->curtime; + pPlayer->SetCycle( 0 ); +} + + +void CBasePlayerAnimState::ComputeSequences( CStudioHdr *pStudioHdr ) +{ + VPROF( "CBasePlayerAnimState::ComputeSequences" ); + + ComputeMainSequence(); // Lower body (walk/run/idle). + UpdateInterpolators(); // The groundspeed interpolator uses the main sequence info. + + if ( m_AnimConfig.m_bUseAimSequences ) + { + ComputeAimSequence(); // Upper body, based on weapon type. + } +} + +void CBasePlayerAnimState::ResetGroundSpeed( void ) +{ + m_flMaxGroundSpeed = GetCurrentMaxGroundSpeed(); +} + +void CBasePlayerAnimState::ComputeMainSequence() +{ + VPROF( "CBasePlayerAnimState::ComputeMainSequence" ); + + CBaseAnimatingOverlay *pPlayer = GetOuter(); + + // 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; + + // Export to our outer class.. + int animDesired = SelectWeightedSequence( TranslateActivity(idealActivity) ); + +#if !defined( HL1_CLIENT_DLL ) && !defined ( HL1_DLL ) + if ( pPlayer->GetSequenceActivity( pPlayer->GetSequence() ) == pPlayer->GetSequenceActivity( animDesired ) ) + return; +#endif + + 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_CROUCHIDLE || oldActivity == ACT_IDLE) && + (idealActivity == ACT_WALK || idealActivity == ACT_RUN_CROUCH) ) + { + ResetGroundSpeed(); + } +#endif +} + + + + + +void CBasePlayerAnimState::UpdateAimSequenceLayers( + float flCycle, + int iFirstLayer, + bool bForceIdle, + CSequenceTransitioner *pTransitioner, + float flWeightScale + ) +{ + float flAimSequenceWeight = 1; + int iAimSequence = CalcAimLayerSequence( &flCycle, &flAimSequenceWeight, bForceIdle ); + if ( iAimSequence == -1 ) + iAimSequence = 0; + + // Feed the current state of the animation parameters to the sequence transitioner. + // It will hand back either 1 or 2 animations in the queue to set, depending on whether + // it's transitioning or not. We just dump those into the animation layers. + pTransitioner->CheckForSequenceChange( + m_pOuter->GetModelPtr(), + iAimSequence, + false, // don't force transitions on the same anim + true // yes, interpolate when transitioning + ); + + pTransitioner->UpdateCurrent( + m_pOuter->GetModelPtr(), + iAimSequence, + flCycle, + GetOuter()->GetPlaybackRate(), + gpGlobals->curtime + ); + + CAnimationLayer *pDest0 = m_pOuter->GetAnimOverlay( iFirstLayer ); + CAnimationLayer *pDest1 = m_pOuter->GetAnimOverlay( iFirstLayer+1 ); + + if ( pTransitioner->m_animationQueue.Count() == 1 ) + { + // If only 1 animation, then blend it in fully. + CAnimationLayer *pSource0 = &pTransitioner->m_animationQueue[0]; + *pDest0 = *pSource0; + + pDest0->m_flWeight = 1; + pDest1->m_flWeight = 0; + pDest0->m_nOrder = iFirstLayer; + +#ifndef CLIENT_DLL + pDest0->m_fFlags |= ANIM_LAYER_ACTIVE; +#endif + } + else if ( pTransitioner->m_animationQueue.Count() >= 2 ) + { + // The first one should be fading out. Fade in the new one inversely. + CAnimationLayer *pSource0 = &pTransitioner->m_animationQueue[0]; + CAnimationLayer *pSource1 = &pTransitioner->m_animationQueue[1]; + + *pDest0 = *pSource0; + *pDest1 = *pSource1; + Assert( pDest0->m_flWeight >= 0.0f && pDest0->m_flWeight <= 1.0f ); + pDest1->m_flWeight = 1 - pDest0->m_flWeight; // This layer just mirrors the other layer's weight (one fades in while the other fades out). + + pDest0->m_nOrder = iFirstLayer; + pDest1->m_nOrder = iFirstLayer+1; + +#ifndef CLIENT_DLL + pDest0->m_fFlags |= ANIM_LAYER_ACTIVE; + pDest1->m_fFlags |= ANIM_LAYER_ACTIVE; +#endif + } + + pDest0->m_flWeight *= flWeightScale * flAimSequenceWeight; + pDest0->m_flWeight = clamp( (float)pDest0->m_flWeight, 0.0f, 1.0f ); + + pDest1->m_flWeight *= flWeightScale * flAimSequenceWeight; + pDest1->m_flWeight = clamp( (float)pDest1->m_flWeight, 0.0f, 1.0f ); + + pDest0->m_flCycle = pDest1->m_flCycle = flCycle; +} + + +void CBasePlayerAnimState::OptimizeLayerWeights( int iFirstLayer, int nLayers ) +{ + int i; + + // Find the total weight of the blended layers, not including the idle layer (iFirstLayer) + float totalWeight = 0.0f; + for ( i=1; i < nLayers; i++ ) + { + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i ); + if ( pLayer->IsActive() && pLayer->m_flWeight > 0.0f ) + { + totalWeight += pLayer->m_flWeight; + } + } + + // Set the idle layer's weight to be 1 minus the sum of other layer weights + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer ); + if ( pLayer->IsActive() && pLayer->m_flWeight > 0.0f ) + { + pLayer->m_flWeight = 1.0f - totalWeight; + pLayer->m_flWeight = MAX( (float)pLayer->m_flWeight, 0.0f); + } + + // This part is just an optimization. Since we have the walk/run animations weighted on top of + // the idle animations, all this does is disable the idle animations if the walk/runs are at + // full weighting, which is whenever a guy is at full speed. + // + // So it saves us blending a couple animation layers whenever a guy is walking or running full speed. + int iLastOne = -1; + for ( i=0; i < nLayers; i++ ) + { + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i ); + if ( pLayer->IsActive() && pLayer->m_flWeight > 0.99 ) + iLastOne = i; + } + + if ( iLastOne != -1 ) + { + for ( int i=iLastOne-1; i >= 0; i-- ) + { + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( iFirstLayer+i ); +#ifdef CLIENT_DLL + pLayer->m_nOrder = CBaseAnimatingOverlay::MAX_OVERLAYS; +#else + pLayer->m_nOrder.Set( CBaseAnimatingOverlay::MAX_OVERLAYS ); + pLayer->m_fFlags = 0; +#endif + } + } +} + +bool CBasePlayerAnimState::ShouldBlendAimSequenceToIdle() +{ + Activity act = GetCurrentMainSequenceActivity(); + + return (act == ACT_RUN || act == ACT_WALK || act == ACT_RUNTOIDLE || act == ACT_RUN_CROUCH); +} + +void CBasePlayerAnimState::ComputeAimSequence() +{ + VPROF( "CBasePlayerAnimState::ComputeAimSequence" ); + + // Synchronize the lower and upper body cycles. + float flCycle = m_pOuter->GetCycle(); + + // Figure out the new cycle time. + UpdateAimSequenceLayers( flCycle, AIMSEQUENCE_LAYER, true, &m_IdleSequenceTransitioner, 1 ); + + if ( ShouldBlendAimSequenceToIdle() ) + { + // What we do here is blend between the idle upper body animation (like where he's got the dual elites + // held out in front of him but he's not moving) and his walk/run/crouchrun upper body animation, + // weighting it based on how fast he's moving. That way, when he's moving slowly, his upper + // body doesn't jiggle all around. + bool bIsMoving; + float flPlaybackRate = CalcMovementPlaybackRate( &bIsMoving ); + if ( bIsMoving ) + UpdateAimSequenceLayers( flCycle, AIMSEQUENCE_LAYER+2, false, &m_SequenceTransitioner, flPlaybackRate ); + } + + OptimizeLayerWeights( AIMSEQUENCE_LAYER, NUM_AIMSEQUENCE_LAYERS ); +} + + +int CBasePlayerAnimState::CalcSequenceIndex( const char *pBaseName, ... ) +{ + char szFullName[512]; + va_list marker; + va_start( marker, pBaseName ); + Q_vsnprintf( szFullName, sizeof( szFullName ), pBaseName, marker ); + va_end( marker ); + int iSequence = GetOuter()->LookupSequence( szFullName ); + + // Show warnings if we can't find anything here. + if ( iSequence == -1 ) + { + static CUtlDict<int,int> dict; + if ( dict.Find( szFullName ) == -1 ) + { + dict.Insert( szFullName, 0 ); + Warning( "CalcSequenceIndex: can't find '%s'.\n", szFullName ); + } + + iSequence = 0; + } + + return iSequence; +} + + + +void CBasePlayerAnimState::UpdateInterpolators() +{ + VPROF( "CBasePlayerAnimState::UpdateInterpolators" ); + + // First, figure out their current max speed based on their current activity. + float flCurMaxSpeed = GetCurrentMaxGroundSpeed(); + m_flMaxGroundSpeed = flCurMaxSpeed; +} + + +float CBasePlayerAnimState::GetInterpolatedGroundSpeed() +{ + return m_flMaxGroundSpeed; +} + + +float CBasePlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving ) +{ + // Determine ideal playback rate + Vector vel; + GetOuterAbsVelocity( vel ); + + float speed = vel.Length2D(); + bool isMoving = ( speed > MOVING_MINIMUM_SPEED ); + + *bIsMoving = false; + float flReturnValue = 1; + + if ( isMoving && CanThePlayerMove() ) + { + float flGroundSpeed = GetInterpolatedGroundSpeed(); + if ( flGroundSpeed < 0.001f ) + { + flReturnValue = 0.01; + } + else + { + // Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below + flReturnValue = speed / flGroundSpeed; + flReturnValue = clamp( flReturnValue, 0.01f, 10.f ); // don't go nuts here. + } + *bIsMoving = true; + } + + return flReturnValue; +} + + +bool CBasePlayerAnimState::CanThePlayerMove() +{ + return true; +} + + +void CBasePlayerAnimState::ComputePlaybackRate() +{ + VPROF( "CBasePlayerAnimState::ComputePlaybackRate" ); + if ( m_AnimConfig.m_LegAnimType != LEGANIM_9WAY && m_AnimConfig.m_LegAnimType != LEGANIM_8WAY ) + { + // When using a 9-way blend, playback rate is always 1 and we just scale the pose params + // to speed up or slow down the animation. + bool bIsMoving; + float flRate = CalcMovementPlaybackRate( &bIsMoving ); + if ( bIsMoving ) + GetOuter()->SetPlaybackRate( flRate ); + else + GetOuter()->SetPlaybackRate( 1 ); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : CBasePlayer +//----------------------------------------------------------------------------- +CBaseAnimatingOverlay *CBasePlayerAnimState::GetOuter() const +{ + return m_pOuter; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : dt - +//----------------------------------------------------------------------------- +void CBasePlayerAnimState::EstimateYaw() +{ + Vector est_velocity; + GetOuterAbsVelocity( est_velocity ); + + float flLength = est_velocity.Length2D(); + if ( flLength > MOVING_MINIMUM_SPEED ) + { + m_flGaitYaw = atan2( est_velocity[1], est_velocity[0] ); + m_flGaitYaw = RAD2DEG( m_flGaitYaw ); + m_flGaitYaw = AngleNormalize( m_flGaitYaw ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Override for backpeddling +// Input : dt - +//----------------------------------------------------------------------------- +void CBasePlayerAnimState::ComputePoseParam_MoveYaw( CStudioHdr *pStudioHdr ) +{ + VPROF( "CBasePlayerAnimState::ComputePoseParam_MoveYaw" ); + + //Matt: Goldsrc style animations need to not rotate the model + if ( m_AnimConfig.m_LegAnimType == LEGANIM_GOLDSRC ) + { +#ifndef CLIENT_DLL + //Adrian: Make the model's angle match the legs so the hitboxes match on both sides. + GetOuter()->SetLocalAngles( QAngle( 0, m_flCurrentFeetYaw, 0 ) ); +#endif + } + + // If using goldsrc-style animations where he's moving in the direction that his feet are facing, + // we don't use move yaw. + if ( m_AnimConfig.m_LegAnimType != LEGANIM_9WAY && m_AnimConfig.m_LegAnimType != LEGANIM_8WAY ) + return; + + // view direction relative to movement + float flYaw; + + EstimateYaw(); + + float ang = m_flEyeYaw; + if ( ang > 180.0f ) + { + ang -= 360.0f; + } + else if ( ang < -180.0f ) + { + ang += 360.0f; + } + + // calc side to side turning + flYaw = ang - m_flGaitYaw; + // Invert for mapping into 8way blend + flYaw = -flYaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + + if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY ) + { +#ifndef CLIENT_DLL + //Adrian: Make the model's angle match the legs so the hitboxes match on both sides. + GetOuter()->SetLocalAngles( QAngle( 0, m_flCurrentFeetYaw, 0 ) ); +#endif + + int iMoveX = GetOuter()->LookupPoseParameter( pStudioHdr, "move_x" ); + int iMoveY = GetOuter()->LookupPoseParameter( pStudioHdr, "move_y" ); + if ( iMoveX < 0 || iMoveY < 0 ) + return; + + bool bIsMoving; + float flPlaybackRate = CalcMovementPlaybackRate( &bIsMoving ); + + // Setup the 9-way blend parameters based on our speed and direction. + Vector2D vCurMovePose( 0, 0 ); + + if ( bIsMoving ) + { + vCurMovePose.x = cos( DEG2RAD( flYaw ) ) * flPlaybackRate; + vCurMovePose.y = -sin( DEG2RAD( flYaw ) ) * flPlaybackRate; + } + + GetOuter()->SetPoseParameter( pStudioHdr, iMoveX, vCurMovePose.x ); + GetOuter()->SetPoseParameter( pStudioHdr, iMoveY, vCurMovePose.y ); + + m_vLastMovePose = vCurMovePose; + } + else + { + int iMoveYaw = GetOuter()->LookupPoseParameter( pStudioHdr, "move_yaw" ); + if ( iMoveYaw >= 0 ) + { + GetOuter()->SetPoseParameter( pStudioHdr, iMoveYaw, flYaw ); + m_flLastMoveYaw = flYaw; + + // Now blend in his idle animation. + // This makes the 8-way blend act like a 9-way blend by blending to + // an idle sequence as he slows down. +#if defined(CLIENT_DLL) + bool bIsMoving; + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER ); + + pLayer->m_flWeight = 1 - CalcMovementPlaybackRate( &bIsMoving ); + if ( !bIsMoving ) + { + pLayer->m_flWeight = 1; + } + + if ( ShouldChangeSequences() ) + { + // Whenever this layer stops blending, we can choose a new idle sequence to blend to, so he + // doesn't always use the same idle. + if ( pLayer->m_flWeight < 0.02f || m_iCurrent8WayIdleSequence == -1 ) + { + m_iCurrent8WayIdleSequence = m_pOuter->SelectWeightedSequence( ACT_IDLE ); + m_iCurrent8WayCrouchIdleSequence = m_pOuter->SelectWeightedSequence( ACT_CROUCHIDLE ); + } + + if ( m_eCurrentMainSequenceActivity == ACT_CROUCHIDLE || m_eCurrentMainSequenceActivity == ACT_RUN_CROUCH ) + pLayer->m_nSequence = m_iCurrent8WayCrouchIdleSequence; + else + pLayer->m_nSequence = m_iCurrent8WayIdleSequence; + } + + pLayer->m_flPlaybackRate = 1; + pLayer->m_flCycle += m_pOuter->GetSequenceCycleRate( pStudioHdr, pLayer->m_nSequence ) * gpGlobals->frametime; + pLayer->m_flCycle = fmod( pLayer->m_flCycle, 1 ); + pLayer->m_nOrder = MAIN_IDLE_SEQUENCE_LAYER; +#endif + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CBasePlayerAnimState::ComputePoseParam_BodyPitch( CStudioHdr *pStudioHdr ) +{ + VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyPitch" ); + + // Get pitch from v_angle + float flPitch = m_flEyePitch; + if ( flPitch > 180.0f ) + { + flPitch -= 360.0f; + } + flPitch = clamp( flPitch, -90.f, 90.f ); + + // See if we have a blender for pitch + int pitch = GetOuter()->LookupPoseParameter( pStudioHdr, "body_pitch" ); + if ( pitch < 0 ) + return; + + GetOuter()->SetPoseParameter( pStudioHdr, pitch, flPitch ); + g_flLastBodyPitch = flPitch; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : goal - +// maxrate - +// dt - +// current - +// Output : int +//----------------------------------------------------------------------------- +int CBasePlayerAnimState::ConvergeAngles( float goal,float maxrate, float maxgap, float dt, float& current ) +{ + int direction = TURN_NONE; + + float anglediff = goal - current; + anglediff = AngleNormalize( anglediff ); + + float anglediffabs = fabs( anglediff ); + + float scale = 1.0f; + if ( anglediffabs <= FADE_TURN_DEGREES ) + { + scale = anglediffabs / FADE_TURN_DEGREES; + // Always do at least a bit of the turn ( 1% ) + scale = clamp( scale, 0.01f, 1.0f ); + } + + float maxmove = maxrate * dt * scale; + + if ( anglediffabs > maxgap ) + { + // gap is too big, jump + maxmove = (anglediffabs - maxgap); + } + + if ( anglediffabs < maxmove ) + { + // we are close enought, just set the final value + current = goal; + } + else + { + // adjust value up or down + if ( anglediff > 0 ) + { + current += maxmove; + direction = TURN_LEFT; + } + else + { + current -= maxmove; + direction = TURN_RIGHT; + } + } + + current = AngleNormalize( current ); + + return direction; +} + +void CBasePlayerAnimState::ComputePoseParam_BodyYaw() +{ + VPROF( "CBasePlayerAnimState::ComputePoseParam_BodyYaw" ); + + // Find out which way he's running (m_flEyeYaw is the way he's looking). + Vector vel; + GetOuterAbsVelocity( vel ); + bool bIsMoving = vel.Length2D() > MOVING_MINIMUM_SPEED; + + // If we just initialized this guy (maybe he just came into the PVS), then immediately + // set his feet in the right direction, otherwise they'll spin around from 0 to the + // right direction every time someone switches spectator targets. + if ( !m_bCurrentFeetYawInitialized ) + { + m_bCurrentFeetYawInitialized = true; + m_flGoalFeetYaw = m_flCurrentFeetYaw = m_flEyeYaw; + m_flLastTurnTime = 0.0f; + } + else if ( bIsMoving ) + { + // player is moving, feet yaw = aiming yaw + if ( m_AnimConfig.m_LegAnimType == LEGANIM_9WAY || m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) + { + // His feet point in the direction his eyes are, but they can run in any direction. + m_flGoalFeetYaw = m_flEyeYaw; + } + else + { + m_flGoalFeetYaw = RAD2DEG( atan2( vel.y, vel.x ) ); + + // If he's running backwards, flip his feet backwards. + Vector vEyeYaw( cos( DEG2RAD( m_flEyeYaw ) ), sin( DEG2RAD( m_flEyeYaw ) ), 0 ); + Vector vFeetYaw( cos( DEG2RAD( m_flGoalFeetYaw ) ), sin( DEG2RAD( m_flGoalFeetYaw ) ), 0 ); + if ( vEyeYaw.Dot( vFeetYaw ) < -0.01 ) + { + m_flGoalFeetYaw += 180; + } + } + + } + else if ( (gpGlobals->curtime - m_flLastTurnTime) > mp_facefronttime.GetFloat() ) + { + // player didn't move & turn for quite some time + m_flGoalFeetYaw = m_flEyeYaw; + } + else + { + // If he's rotated his view further than the model can turn, make him face forward. + float flDiff = AngleNormalize( m_flGoalFeetYaw - m_flEyeYaw ); + + if ( fabs(flDiff) > m_AnimConfig.m_flMaxBodyYawDegrees ) + { + if ( flDiff > 0 ) + m_flGoalFeetYaw -= m_AnimConfig.m_flMaxBodyYawDegrees; + else + m_flGoalFeetYaw += m_AnimConfig.m_flMaxBodyYawDegrees; + } + } + + m_flGoalFeetYaw = AngleNormalize( m_flGoalFeetYaw ); + + if ( m_flCurrentFeetYaw != m_flGoalFeetYaw ) + { + ConvergeAngles( m_flGoalFeetYaw, mp_feetyawrate.GetFloat(), m_AnimConfig.m_flMaxBodyYawDegrees, + gpGlobals->frametime, m_flCurrentFeetYaw ); + + m_flLastTurnTime = gpGlobals->curtime; + } + + float flCurrentTorsoYaw = AngleNormalize( m_flEyeYaw - m_flCurrentFeetYaw ); + + // Rotate entire body into position + m_angRender[YAW] = m_flCurrentFeetYaw; + m_angRender[PITCH] = m_angRender[ROLL] = 0; + + SetOuterBodyYaw( flCurrentTorsoYaw ); + g_flLastBodyYaw = flCurrentTorsoYaw; +} + + + +float CBasePlayerAnimState::SetOuterBodyYaw( float flValue ) +{ + int body_yaw = GetOuter()->LookupPoseParameter( "body_yaw" ); + if ( body_yaw < 0 ) + { + return 0; + } + + SetOuterPoseParameter( body_yaw, flValue ); + return flValue; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : activity - +// Output : Activity +//----------------------------------------------------------------------------- +Activity CBasePlayerAnimState::BodyYawTranslateActivity( Activity activity ) +{ + // Not even standing still, sigh + if ( activity != ACT_IDLE ) + return activity; + + // Not turning + switch ( m_nTurningInPlace ) + { + default: + case TURN_NONE: + return activity; + case TURN_RIGHT: + case TURN_LEFT: + return mp_ik.GetBool() ? ACT_TURN : activity; + } + + Assert( 0 ); + return activity; +} + +const QAngle& CBasePlayerAnimState::GetRenderAngles() +{ + return m_angRender; +} + + +void CBasePlayerAnimState::GetOuterAbsVelocity( Vector& vel ) const +{ +#if defined( CLIENT_DLL ) + GetOuter()->EstimateAbsVelocity( vel ); +#else + vel = GetOuter()->GetAbsVelocity(); +#endif +} + + +float CBasePlayerAnimState::GetOuterXYSpeed() const +{ + Vector vel; + GetOuterAbsVelocity( vel ); + return vel.Length2D(); +} + +// ----------------------------------------------------------------------------- +void CBasePlayerAnimState::AnimStateLog( 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 ( showanimstate_log.GetInt() == 1 || showanimstate_log.GetInt() == 3 ) + { + Msg( "%s", str ); + } + + if ( showanimstate_log.GetInt() > 1 ) + { +#ifdef CLIENT_DLL + const char *fname = "AnimStateClient.log"; +#else + const char *fname = "AnimStateServer.log"; +#endif + static FileHandle_t hFile = filesystem->Open( fname, "wt" ); + filesystem->FPrintf( hFile, "%s", str ); + filesystem->Flush( hFile ); + } +} + + +// ----------------------------------------------------------------------------- +void CBasePlayerAnimState::AnimStatePrintf( 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. + AnimStateLog( "%s\n", str ); +} + + +// ----------------------------------------------------------------------------- +void CBasePlayerAnimState::DebugShowAnimState( int iStartLine ) +{ + Vector vOuterVel; + GetOuterAbsVelocity( vOuterVel ); + + int iLine = iStartLine; + AnimStatePrintf( iLine++, "main: %s(%d), cycle: %.2f cyclerate: %.2f playbackrate: %.2f\n", + GetSequenceName( m_pOuter->GetModelPtr(), m_pOuter->GetSequence() ), + m_pOuter->GetSequence(), + m_pOuter->GetCycle(), + m_pOuter->GetSequenceCycleRate(m_pOuter->GetModelPtr(), m_pOuter->GetSequence()), + m_pOuter->GetPlaybackRate() + ); + + if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) + { + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( MAIN_IDLE_SEQUENCE_LAYER ); + + AnimStatePrintf( iLine++, "idle: %s, weight: %.2f\n", + GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ), + (float)pLayer->m_flWeight ); + } + + for ( int i=0; i < m_pOuter->GetNumAnimOverlays()-1; i++ ) + { + CAnimationLayer *pLayer = m_pOuter->GetAnimOverlay( AIMSEQUENCE_LAYER + i ); +#ifdef CLIENT_DLL + AnimStatePrintf( iLine++, "%s(%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)", + !pLayer->IsActive() ? "-- ": (pLayer->m_nSequence == 0 ? "-- " : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ) ), + !pLayer->IsActive() ? 0 : (int)pLayer->m_nSequence, + !pLayer->IsActive() ? 0 : (float)pLayer->m_flWeight, + !pLayer->IsActive() ? 0 : (float)pLayer->m_flCycle, + !pLayer->IsActive() ? 0 : (int)pLayer->m_nOrder, + i + ); +#else + AnimStatePrintf( iLine++, "%s(%d), flags (%d), weight: %.2f, cycle: %.2f, order (%d), aim (%d)", + !pLayer->IsActive() ? "-- " : ( pLayer->m_nSequence == 0 ? "-- " : GetSequenceName( m_pOuter->GetModelPtr(), pLayer->m_nSequence ) ), + !pLayer->IsActive() ? 0 : (int)pLayer->m_nSequence, + !pLayer->IsActive() ? 0 : (int)pLayer->m_fFlags,// Doesn't exist on client + !pLayer->IsActive() ? 0 : (float)pLayer->m_flWeight, + !pLayer->IsActive() ? 0 : (float)pLayer->m_flCycle, + !pLayer->IsActive() ? 0 : (int)pLayer->m_nOrder, + i + ); +#endif + } + + AnimStatePrintf( iLine++, "vel: %.2f, time: %.2f, max: %.2f, animspeed: %.2f", + vOuterVel.Length2D(), gpGlobals->curtime, GetInterpolatedGroundSpeed(), m_pOuter->GetSequenceGroundSpeed(m_pOuter->GetSequence()) ); + + if ( m_AnimConfig.m_LegAnimType == LEGANIM_8WAY ) + { + AnimStatePrintf( iLine++, "ent yaw: %.2f, body_yaw: %.2f, move_yaw: %.2f, gait_yaw: %.2f, body_pitch: %.2f", + m_angRender[YAW], g_flLastBodyYaw, m_flLastMoveYaw, m_flGaitYaw, g_flLastBodyPitch ); + } + else + { + 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 ); + } + + // Draw a red triangle on the ground for the eye yaw. + float flBaseSize = 10; + float flHeight = 80; + Vector vBasePos = GetOuter()->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 ); + +} + +// ----------------------------------------------------------------------------- +void CBasePlayerAnimState::DebugShowAnimStateFull( int iStartLine ) +{ + AnimStateLog( "----------------- frame %d -----------------\n", gpGlobals->framecount ); + + DebugShowAnimState( iStartLine ); + + AnimStateLog( "--------------------------------------------\n\n" ); +} + +// ----------------------------------------------------------------------------- +int CBasePlayerAnimState::SelectWeightedSequence( Activity activity ) +{ + return GetOuter()->SelectWeightedSequence( activity ); +} + |