You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1872 lines
58 KiB
1872 lines
58 KiB
//====== Copyright © 1996-2005, 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"
|
|
#include "basecombatweapon_shared.h"
|
|
#include "datacache/imdlcache.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
#include "c_baseplayer.h"
|
|
#include "engine/ivdebugoverlay.h"
|
|
#include "filesystem.h"
|
|
#include "eventlist.h"
|
|
#ifdef DEMOPOLISH_ENABLED
|
|
#include "demo_polish/demo_polish.h"
|
|
#endif
|
|
ConVar anim_showmainactivity( "anim_showmainactivity", "0", FCVAR_CHEAT, "Show the idle, walk, run, and/or sprint activities." );
|
|
#else
|
|
#include "player.h"
|
|
#endif
|
|
|
|
#if defined( PORTAL ) && defined( CLIENT_DLL )
|
|
#include "c_portal_player.h"
|
|
#endif
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
|
|
#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." );
|
|
|
|
|
|
mstudioevent_for_client_server_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc );
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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 );
|
|
|
|
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;
|
|
|
|
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 );
|
|
}
|
|
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 );
|
|
}
|
|
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 );
|
|
}
|
|
break;
|
|
}
|
|
case PLAYERANIMEVENT_JUMP:
|
|
{
|
|
// Jump.
|
|
m_bJumping = true;
|
|
m_bFirstJumpFrame = true;
|
|
m_flJumpStartTime = gpGlobals->curtime;
|
|
|
|
RestartMainSequence();
|
|
|
|
#if defined( CLIENT_DLL ) && defined( DEMO_POLISH )
|
|
// Notify demo polish recorder
|
|
if ( IsDemoPolishEnabled() && IsDemoPolishRecording() )
|
|
{
|
|
DemoPolish_GetRecorder().RecordJumpEvent( GetBasePlayer()->entindex() );
|
|
}
|
|
#endif
|
|
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 );
|
|
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
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->SetCycle( 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->GetSequence() );
|
|
if ( seqdesc.numevents > 0 )
|
|
{
|
|
mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
|
|
|
|
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_OldSystem() < EVENT_CLIENT ) //Adrian - Support the old event system
|
|
continue;
|
|
|
|
if ( pevent[i].cycle > pGesture->m_pAnimLayer->GetPrevCycle() &&
|
|
pevent[i].cycle <= pGesture->m_pAnimLayer->GetCycle() )
|
|
{
|
|
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->SetCycle( 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->SetCycle( 0.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetPrevCycle( 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->SetSequence( iGestureSequence );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetOrder( iGestureSlot );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetWeight( 1.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetPlaybackRate( 1.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetCycle( 0.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetPrevCycle( 0.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
|
|
|
|
pPlayer->SetOverlayPrevEventCycle(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, 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->SetSequence( iGestureSequence );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetOrder( iGestureSlot );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetWeight( 1.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetPlaybackRate( 1.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetCycle( 0.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->SetPrevCycle( 0.0f );
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerAnimtime = 0.0f;
|
|
m_aGestureSlots[iGestureSlot].m_pAnimLayer->m_flLayerFadeOuttime = 0.0f;
|
|
|
|
pPlayer->SetOverlayPrevEventCycle(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::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 = sqrt( prevX * prevX + prevY * 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
|
|
//-----------------------------------------------------------------------------
|
|
ConVar movement_anim_playback_minrate( "movement_anim_playback_minrate", "0.25" );
|
|
float CMultiPlayerAnimState::CalcMovementPlaybackRate( bool *bIsMoving )
|
|
{
|
|
// Get the player's current velocity and speed.
|
|
Vector vecVelocity;
|
|
GetOuterAbsVelocity( vecVelocity );
|
|
float flSpeed = vecVelocity.Length2D();
|
|
|
|
// Determine if the player is considered moving or not.
|
|
bool bMoving = ( flSpeed > MOVING_MINIMUM_SPEED );
|
|
|
|
// Initialize the return data.
|
|
*bIsMoving = false;
|
|
float flReturn = 1.0f;
|
|
|
|
// If we are moving.
|
|
if ( bMoving )
|
|
{
|
|
// float flGroundSpeed = GetInterpolatedGroundSpeed();
|
|
float flGroundSpeed = GetCurrentMaxGroundSpeed();
|
|
if ( flGroundSpeed < 0.001f )
|
|
{
|
|
flReturn = 0.01;
|
|
}
|
|
else
|
|
{
|
|
// Note this gets set back to 1.0 if sequence changes due to ResetSequenceInfo below
|
|
flReturn = flSpeed / flGroundSpeed;
|
|
flReturn = clamp( flReturn, movement_anim_playback_minrate.GetFloat(), 10.0f );
|
|
}
|
|
|
|
*bIsMoving = true;
|
|
}
|
|
|
|
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_STAND_SECONDARY || 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( gpGlobals->curtime );
|
|
m_iv_flMaxGroundSpeed.NoteChanged( gpGlobals->curtime, 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;
|
|
|
|
// Get the current cycle.
|
|
float flCycle = pGesture->m_pAnimLayer->GetCycle();
|
|
flCycle += pPlayer->GetSequenceCycleRate( pStudioHdr, pGesture->m_pAnimLayer->GetSequence() ) * gpGlobals->frametime;
|
|
|
|
pGesture->m_pAnimLayer->SetPrevCycle( pGesture->m_pAnimLayer->GetCycle() );
|
|
pGesture->m_pAnimLayer->SetCycle( flCycle );
|
|
|
|
if( flCycle > 1.0f )
|
|
{
|
|
#ifdef CLIENT_DLL
|
|
RunGestureSlotAnimEventsToCompletion( pGesture );
|
|
#endif
|
|
|
|
if ( pGesture->m_bAutoKill )
|
|
{
|
|
ResetGestureSlot( pGesture->m_iGestureSlot );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
pGesture->m_pAnimLayer->SetCycle( 1.0f );
|
|
}
|
|
}
|
|
|
|
#ifndef CLIENT_DLL
|
|
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::IsLocalPlayer( GetBasePlayer() ) &&
|
|
GetBasePlayer()->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;
|
|
|
|
// 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_bPoseParameterInit = true;
|
|
|
|
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:
|
|
// 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 flPlaybackRate = CalcMovementPlaybackRate( &bIsMoving );
|
|
|
|
// Setup the 9-way blend parameters based on our speed and direction.
|
|
Vector2D vecCurrentMoveYaw( 0.0f, 0.0f );
|
|
if ( bIsMoving )
|
|
{
|
|
if ( mp_slammoveyaw.GetBool() )
|
|
{
|
|
flYaw = SnapYawTo( flYaw );
|
|
}
|
|
vecCurrentMoveYaw.x = cos( DEG2RAD( flYaw ) ) * flPlaybackRate;
|
|
vecCurrentMoveYaw.y = -sin( DEG2RAD( flYaw ) ) * flPlaybackRate;
|
|
}
|
|
|
|
// 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 );
|
|
|
|
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*/ )
|
|
{
|
|
#if defined( CLIENT_DLL ) && defined( DEMO_POLISH )
|
|
float const flCurrentFootYaw = m_flGoalFeetYaw;
|
|
#endif
|
|
|
|
float flSide = ( flYawDelta > 0.0f ) ? -1.0f : 1.0f;
|
|
m_flGoalFeetYaw += ( 45.0f/*m_AnimConfig.m_flMaxBodyYawDegrees*/ * flSide );
|
|
|
|
#if defined( CLIENT_DLL ) && defined( DEMO_POLISH )
|
|
if ( IsDemoPolishRecording() )
|
|
{
|
|
CDemoPolishRecorder::Instance().RecordStandingHeadingChange( GetBasePlayer()->entindex(), flCurrentFootYaw, m_flGoalFeetYaw );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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()
|
|
{
|
|
#if defined( PORTAL ) && defined( CLIENT_DLL )
|
|
C_Portal_Player *pPlayer = (C_Portal_Player *)GetBasePlayer();
|
|
|
|
if( pPlayer )
|
|
{
|
|
if( pPlayer->GetOriginInterpolator().GetInterpolatedTime( pPlayer->GetEffectiveInterpolationCurTime( gpGlobals->curtime ) ) < pPlayer->m_fLatestServerTeleport )
|
|
{
|
|
m_angRender_InterpHistory = TransformAnglesToWorldSpace( m_angRender, pPlayer->m_matLatestServerTeleportationInverseMatrix.As3x4() );
|
|
return m_angRender_InterpHistory;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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->GetOrder() != CBaseAnimatingOverlay::MAX_OVERLAYS ) )
|
|
{
|
|
Anim_StatePrintf( iLine++, "Layer %s: Weight: %.2f, Cycle: %.2f", GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->GetSequence() ), pLayer->GetWeight(), pLayer->GetCycle() );
|
|
}
|
|
#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->GetSequence() ), pLayer->GetWeight(), pLayer->GetCycle() );
|
|
}
|
|
#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->GetOrder() == CBaseAnimatingOverlay::MAX_OVERLAYS ? "--" : GetSequenceName( GetBasePlayer()->GetModelPtr(), pLayer->GetSequence() ),
|
|
pLayer->GetOrder() == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->GetWeight(),
|
|
pLayer->GetOrder() == CBaseAnimatingOverlay::MAX_OVERLAYS ? -1 :(float)pLayer->GetCycle(),
|
|
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->GetSequence() ),
|
|
( pGesture->m_bAutoKill ? "true" : "false" ),
|
|
pGesture->m_pAnimLayer->GetCycle(), pGesture->m_pAnimLayer->GetPlaybackRate() );
|
|
}
|
|
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;
|
|
ClearAnimationState();
|
|
}
|
|
|