2013-06-26 15:22:04 -07:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//===========================================================================//
# include "cbase.h"
# include "animation.h"
# include "studio.h"
# include "bone_setup.h"
# include "ai_basenpc.h"
# include "npcevent.h"
# include "saverestore_utlvector.h"
# include "dt_utlvector_send.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
extern ConVar ai_sequence_debug ;
BEGIN_SIMPLE_DATADESC ( CAnimationLayer )
// DEFINE_FIELD( m_pOwnerEntity, CBaseAnimatingOverlay ),
DEFINE_FIELD ( m_fFlags , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_bSequenceFinished , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_bLooping , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_nSequence , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flCycle , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flPrevCycle , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flPlaybackRate , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flWeight , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flBlendIn , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flBlendOut , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flKillRate , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flKillDelay , FIELD_FLOAT ) ,
DEFINE_CUSTOM_FIELD ( m_nActivity , ActivityDataOps ( ) ) ,
DEFINE_FIELD ( m_nPriority , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_nOrder , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_flLastEventCheck , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flLastAccess , FIELD_TIME ) ,
DEFINE_FIELD ( m_flLayerAnimtime , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flLayerFadeOuttime , FIELD_FLOAT ) ,
END_DATADESC ( )
BEGIN_DATADESC ( CBaseAnimatingOverlay )
DEFINE_UTLVECTOR ( m_AnimOverlay , FIELD_EMBEDDED ) ,
// DEFINE_FIELD( m_nActiveLayers, FIELD_INTEGER ),
// DEFINE_FIELD( m_nActiveBaseLayers, FIELD_INTEGER ),
END_DATADESC ( )
# define ORDER_BITS 4
# define WEIGHT_BITS 8
BEGIN_SEND_TABLE_NOBASE ( CAnimationLayer , DT_Animationlayer )
SendPropInt ( SENDINFO ( m_nSequence ) , ANIMATION_SEQUENCE_BITS , SPROP_UNSIGNED ) ,
SendPropFloat ( SENDINFO ( m_flCycle ) , ANIMATION_CYCLE_BITS , SPROP_ROUNDDOWN , 0.0f , 1.0f ) ,
SendPropFloat ( SENDINFO ( m_flPrevCycle ) , ANIMATION_CYCLE_BITS , SPROP_ROUNDDOWN , 0.0f , 1.0f ) ,
SendPropFloat ( SENDINFO ( m_flWeight ) , WEIGHT_BITS , 0 , 0.0f , 1.0f ) ,
SendPropInt ( SENDINFO ( m_nOrder ) , ORDER_BITS , SPROP_UNSIGNED ) ,
END_SEND_TABLE ( )
BEGIN_SEND_TABLE_NOBASE ( CBaseAnimatingOverlay , DT_OverlayVars )
SendPropUtlVector (
SENDINFO_UTLVECTOR ( m_AnimOverlay ) ,
CBaseAnimatingOverlay : : MAX_OVERLAYS , // max elements
SendPropDataTable ( NULL , 0 , & REFERENCE_SEND_TABLE ( DT_Animationlayer ) ) )
END_SEND_TABLE ( )
IMPLEMENT_SERVERCLASS_ST ( CBaseAnimatingOverlay , DT_BaseAnimatingOverlay )
// These are in their own separate data table so CCSPlayer can exclude all of these.
SendPropDataTable ( " overlay_vars " , 0 , & REFERENCE_SEND_TABLE ( DT_OverlayVars ) )
END_SEND_TABLE ( )
CAnimationLayer : : CAnimationLayer ( )
{
Init ( NULL ) ;
}
void CAnimationLayer : : Init ( CBaseAnimatingOverlay * pOverlay )
{
m_pOwnerEntity = pOverlay ;
m_fFlags = 0 ;
m_flWeight = 0 ;
m_flCycle = 0 ;
m_flPrevCycle = 0 ;
m_bSequenceFinished = false ;
m_nActivity = ACT_INVALID ;
m_nSequence = 0 ;
m_nPriority = 0 ;
m_nOrder . Set ( CBaseAnimatingOverlay : : MAX_OVERLAYS ) ;
2014-10-30 12:30:57 -04:00
m_flBlendIn = 0.0 ;
m_flBlendOut = 0.0 ;
2013-06-26 15:22:04 -07:00
m_flKillRate = 100.0 ;
m_flKillDelay = 0.0 ;
m_flPlaybackRate = 1.0 ;
2014-10-30 12:30:57 -04:00
m_flLastEventCheck = 0.0 ;
2013-06-26 15:22:04 -07:00
m_flLastAccess = gpGlobals - > curtime ;
m_flLayerAnimtime = 0 ;
m_flLayerFadeOuttime = 0 ;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CAnimationLayer : : StudioFrameAdvance ( float flInterval , CBaseAnimating * pOwner )
{
float flCycleRate = pOwner - > GetSequenceCycleRate ( m_nSequence ) ;
m_flPrevCycle = m_flCycle ;
m_flCycle + = flInterval * flCycleRate * m_flPlaybackRate ;
if ( m_flCycle < 0.0 )
{
if ( m_bLooping )
{
m_flCycle - = ( int ) ( m_flCycle ) ;
}
else
{
m_flCycle = 0 ;
}
}
else if ( m_flCycle > = 1.0 )
{
m_bSequenceFinished = true ;
if ( m_bLooping )
{
m_flCycle - = ( int ) ( m_flCycle ) ;
}
else
{
m_flCycle = 1.0 ;
}
}
if ( IsAutoramp ( ) )
{
m_flWeight = 1 ;
// blend in?
if ( m_flBlendIn ! = 0.0f )
{
if ( m_flCycle < m_flBlendIn )
{
m_flWeight = m_flCycle / m_flBlendIn ;
}
}
// blend out?
if ( m_flBlendOut ! = 0.0f )
{
if ( m_flCycle > 1.0 - m_flBlendOut )
{
m_flWeight = ( 1.0 - m_flCycle ) / m_flBlendOut ;
}
}
m_flWeight = 3.0 * m_flWeight * m_flWeight - 2.0 * m_flWeight * m_flWeight * m_flWeight ;
if ( m_nSequence = = 0 )
m_flWeight = 0 ;
}
}
//------------------------------------------------------------------------------
bool CAnimationLayer : : IsAbandoned ( void )
{
if ( IsActive ( ) & & ! IsAutokill ( ) & & ! IsKillMe ( ) & & m_flLastAccess > 0.0 & & ( gpGlobals - > curtime - m_flLastAccess > 0.2 ) )
return true ;
else
return false ;
}
void CAnimationLayer : : MarkActive ( void )
{
m_flLastAccess = gpGlobals - > curtime ;
}
//------------------------------------------------------------------------------
void CBaseAnimatingOverlay : : VerifyOrder ( void )
{
# ifdef _DEBUG
int i , j ;
// test sorting of the layers
int layer [ MAX_OVERLAYS ] ;
int maxOrder = - 1 ;
for ( i = 0 ; i < MAX_OVERLAYS ; i + + )
{
layer [ i ] = MAX_OVERLAYS ;
}
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . m_nOrder < MAX_OVERLAYS )
{
j = m_AnimOverlay [ i ] . m_nOrder ;
Assert ( layer [ j ] = = MAX_OVERLAYS ) ;
layer [ j ] = i ;
if ( j > maxOrder )
maxOrder = j ;
}
}
// make sure they're sequential
// Aim layers are allowed to have gaps, and we are moving aim blending to server
// for ( i = 0; i <= maxOrder; i++ )
// {
// Assert( layer[i] != MAX_OVERLAYS);
// }
/*
for ( i = 0 ; i < MAX_OVERLAYS ; i + + )
{
int j = layer [ i ] ;
if ( j ! = MAX_OVERLAYS )
{
char tempstr [ 512 ] ;
Q_snprintf ( tempstr , sizeof ( tempstr ) , " %d : %d :%.2f :%d:%d:%.1f " ,
j ,
m_AnimOverlay [ j ] . m_nSequence ,
m_AnimOverlay [ j ] . m_flWeight ,
m_AnimOverlay [ j ] . IsActive ( ) ,
m_AnimOverlay [ j ] . IsKillMe ( ) ,
m_AnimOverlay [ j ] . m_flKillDelay
) ;
EntityText ( i , tempstr , 0.1 ) ;
}
}
*/
# endif
}
//------------------------------------------------------------------------------
// Purpose : advance the animation frame up to the current time
// if an flInterval is passed in, only advance animation that number of seconds
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseAnimatingOverlay : : StudioFrameAdvance ( )
{
float flAdvance = GetAnimTimeInterval ( ) ;
VerifyOrder ( ) ;
BaseClass : : StudioFrameAdvance ( ) ;
for ( int i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
CAnimationLayer * pLayer = & m_AnimOverlay [ i ] ;
if ( pLayer - > IsActive ( ) )
{
// Assert( !m_AnimOverlay[ i ].IsAbandoned() );
if ( pLayer - > IsKillMe ( ) )
{
if ( pLayer - > m_flKillDelay > 0 )
{
pLayer - > m_flKillDelay - = flAdvance ;
pLayer - > m_flKillDelay = clamp ( pLayer - > m_flKillDelay , 0.0f , 1.0f ) ;
}
else if ( pLayer - > m_flWeight ! = 0.0f )
{
// give it at least one frame advance cycle to propagate 0.0 to client
pLayer - > m_flWeight - = pLayer - > m_flKillRate * flAdvance ;
pLayer - > m_flWeight = clamp ( ( float ) pLayer - > m_flWeight , 0.0f , 1.0f ) ;
}
else
{
// shift the other layers down in order
if ( ai_sequence_debug . GetBool ( ) = = true & & m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " removing %d (%d): %s : %5.3f (%.3f) \n " , i , pLayer - > m_nOrder . Get ( ) , GetSequenceName ( pLayer - > m_nSequence ) , pLayer - > m_flCycle . Get ( ) , pLayer - > m_flWeight . Get ( ) ) ;
}
FastRemoveLayer ( i ) ;
// needs at least one thing cycle dead to trigger sequence change
pLayer - > Dying ( ) ;
continue ;
}
}
pLayer - > StudioFrameAdvance ( flAdvance , this ) ;
if ( pLayer - > m_bSequenceFinished & & ( pLayer - > IsAutokill ( ) ) )
{
pLayer - > m_flWeight = 0.0f ;
pLayer - > KillMe ( ) ;
}
}
else if ( pLayer - > IsDying ( ) )
{
pLayer - > Dead ( ) ;
}
else if ( pLayer - > m_flWeight > 0.0 )
{
// Now that the server blends, it is turning off layers all the time. Having a weight left over
// when you're no longer marked as active is now harmless and commonplace. Just clean up.
pLayer - > Init ( this ) ;
pLayer - > Dying ( ) ;
}
}
if ( ai_sequence_debug . GetBool ( ) = = true & & m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
for ( int i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . IsActive ( ) )
{
/*
if ( m_AnimOverlay [ i ] . IsAbandoned ( ) )
{
Msg ( " %d abandoned %.2f (%.2f) \n " , i , gpGlobals - > curtime , m_AnimOverlay [ i ] . m_flLastAccess ) ;
}
*/
Msg ( " %d (%d): %s : %5.3f (%.3f) \n " , i , m_AnimOverlay [ i ] . m_nOrder . Get ( ) , GetSequenceName ( m_AnimOverlay [ i ] . m_nSequence ) , m_AnimOverlay [ i ] . m_flCycle . Get ( ) , m_AnimOverlay [ i ] . m_flWeight . Get ( ) ) ;
}
}
}
VerifyOrder ( ) ;
}
//=========================================================
// DispatchAnimEvents
//=========================================================
void CBaseAnimatingOverlay : : DispatchAnimEvents ( CBaseAnimating * eventHandler )
{
BaseClass : : DispatchAnimEvents ( eventHandler ) ;
for ( int i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . IsActive ( ) )
{
m_AnimOverlay [ i ] . DispatchAnimEvents ( eventHandler , this ) ;
}
}
}
void CAnimationLayer : : DispatchAnimEvents ( CBaseAnimating * eventHandler , CBaseAnimating * pOwner )
{
animevent_t event ;
CStudioHdr * pstudiohdr = pOwner - > GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
Assert ( ! " CBaseAnimating::DispatchAnimEvents: model missing " ) ;
return ;
}
if ( ! pstudiohdr - > SequencesAvailable ( ) )
{
return ;
}
if ( m_nSequence > = pstudiohdr - > GetNumSeq ( ) )
return ;
// don't fire if here are no events
if ( pstudiohdr - > pSeqdesc ( m_nSequence ) . numevents = = 0 )
{
return ;
}
// look from when it last checked to some short time in the future
float flCycleRate = pOwner - > GetSequenceCycleRate ( m_nSequence ) * m_flPlaybackRate ;
float flStart = m_flLastEventCheck ;
float flEnd = m_flCycle ;
if ( ! m_bLooping )
{
// fire off events early
float flLastVisibleCycle = 1.0f - ( pstudiohdr - > pSeqdesc ( m_nSequence ) . fadeouttime ) * flCycleRate ;
if ( flEnd > = flLastVisibleCycle | | flEnd < 0.0 )
{
m_bSequenceFinished = true ;
flEnd = 1.0f ;
}
}
m_flLastEventCheck = flEnd ;
/*
if ( pOwner - > m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " %s:%s : checking %.2f %.2f (%d) \n " , STRING ( pOwner - > GetModelName ( ) ) , pstudiohdr - > pSeqdesc ( m_nSequence ) . pszLabel ( ) , flStart , flEnd , m_bSequenceFinished ) ;
}
*/
// FIXME: does not handle negative framerates!
int index = 0 ;
while ( ( index = GetAnimationEvent ( pstudiohdr , m_nSequence , & event , flStart , flEnd , index ) ) ! = 0 )
{
event . pSource = pOwner ;
// calc when this event should happen
if ( flCycleRate > 0.0 )
{
float flCycle = event . cycle ;
if ( flCycle > m_flCycle )
{
flCycle = flCycle - 1.0 ;
}
event . eventtime = pOwner - > m_flAnimTime + ( flCycle - m_flCycle ) / flCycleRate + pOwner - > GetAnimTimeInterval ( ) ;
}
// Msg( "dispatch %d (%d : %.2f)\n", index - 1, event.event, event.eventtime );
eventHandler - > HandleAnimEvent ( & event ) ;
}
}
void CBaseAnimatingOverlay : : GetSkeleton ( CStudioHdr * pStudioHdr , Vector pos [ ] , Quaternion q [ ] , int boneMask )
{
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetSkeleton() without a model " ) ;
return ;
}
if ( ! pStudioHdr - > SequencesAvailable ( ) )
{
return ;
}
IBoneSetup boneSetup ( pStudioHdr , boneMask , GetPoseParameterArray ( ) ) ;
boneSetup . InitPose ( pos , q ) ;
boneSetup . AccumulatePose ( pos , q , GetSequence ( ) , GetCycle ( ) , 1.0 , gpGlobals - > curtime , m_pIk ) ;
// sort the layers
int layer [ MAX_OVERLAYS ] = { } ;
int i ;
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
layer [ i ] = MAX_OVERLAYS ;
}
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
CAnimationLayer & pLayer = m_AnimOverlay [ i ] ;
if ( ( pLayer . m_flWeight > 0 ) & & pLayer . IsActive ( ) & & pLayer . m_nOrder > = 0 & & pLayer . m_nOrder < m_AnimOverlay . Count ( ) )
{
layer [ pLayer . m_nOrder ] = i ;
}
}
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( layer [ i ] > = 0 & & layer [ i ] < m_AnimOverlay . Count ( ) )
{
CAnimationLayer & pLayer = m_AnimOverlay [ layer [ i ] ] ;
// UNDONE: Is it correct to use overlay weight for IK too?
boneSetup . AccumulatePose ( pos , q , pLayer . m_nSequence , pLayer . m_flCycle , pLayer . m_flWeight , gpGlobals - > curtime , m_pIk ) ;
}
}
if ( m_pIk )
{
CIKContext auto_ik ;
auto_ik . Init ( pStudioHdr , GetAbsAngles ( ) , GetAbsOrigin ( ) , gpGlobals - > curtime , 0 , boneMask ) ;
boneSetup . CalcAutoplaySequences ( pos , q , gpGlobals - > curtime , & auto_ik ) ;
}
else
{
boneSetup . CalcAutoplaySequences ( pos , q , gpGlobals - > curtime , NULL ) ;
}
boneSetup . CalcBoneAdj ( pos , q , GetEncodedControllerArray ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose: zero's out all non-restore safe fields
// Output :
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : OnRestore ( )
{
int i ;
// force order of unused layers to current MAX_OVERLAYS
// and Tracker 48843 (Alyx skating after restore) restore the owner entity ptr (otherwise the network layer won't get NetworkStateChanged signals until the layer is re-Init()'ed
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
m_AnimOverlay [ i ] . m_pOwnerEntity = this ;
if ( ! m_AnimOverlay [ i ] . IsActive ( ) )
{
m_AnimOverlay [ i ] . m_nOrder . Set ( MAX_OVERLAYS ) ;
}
}
// get rid of all layers that shouldn't be restored
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( ( m_AnimOverlay [ i ] . IsActive ( ) & & ( m_AnimOverlay [ i ] . m_fFlags & ANIM_LAYER_DONTRESTORE ) ) | |
( GetModelPtr ( ) & & ! IsValidSequence ( m_AnimOverlay [ i ] . m_nSequence ) ) )
{
FastRemoveLayer ( i ) ;
}
}
BaseClass : : OnRestore ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : AddGestureSequence ( int sequence , bool autokill /*= true*/ )
{
int i = AddLayeredSequence ( sequence , 0 ) ;
// No room?
if ( IsValidLayer ( i ) )
{
SetLayerAutokill ( i , autokill ) ;
}
return i ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : AddGestureSequence ( int nSequence , float flDuration , bool autokill /*= true*/ )
{
int iLayer = AddGestureSequence ( nSequence , autokill ) ;
Assert ( iLayer ! = - 1 ) ;
if ( iLayer > = 0 & & flDuration > 0 )
{
m_AnimOverlay [ iLayer ] . m_flPlaybackRate = SequenceDuration ( nSequence ) / flDuration ;
}
return iLayer ;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
int CBaseAnimatingOverlay : : AddGesture ( Activity activity , bool autokill /*= true*/ )
{
if ( IsPlayingGesture ( activity ) )
{
return FindGestureLayer ( activity ) ;
}
int seq = SelectWeightedSequence ( activity ) ;
if ( seq < = 0 )
{
const char * actname = CAI_BaseNPC : : GetActivityName ( activity ) ;
DevMsg ( " CBaseAnimatingOverlay::AddGesture: model %s missing activity %s \n " , STRING ( GetModelName ( ) ) , actname ) ;
return - 1 ;
}
int i = AddGestureSequence ( seq , autokill ) ;
Assert ( i ! = - 1 ) ;
if ( i ! = - 1 )
{
m_AnimOverlay [ i ] . m_nActivity = activity ;
}
return i ;
}
int CBaseAnimatingOverlay : : AddGesture ( Activity activity , float flDuration , bool autokill /*= true*/ )
{
int iLayer = AddGesture ( activity , autokill ) ;
SetLayerDuration ( iLayer , flDuration ) ;
return iLayer ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerDuration ( int iLayer , float flDuration )
{
if ( IsValidLayer ( iLayer ) & & flDuration > 0 )
{
m_AnimOverlay [ iLayer ] . m_flPlaybackRate = SequenceDuration ( m_AnimOverlay [ iLayer ] . m_nSequence ) / flDuration ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
float CBaseAnimatingOverlay : : GetLayerDuration ( int iLayer )
{
if ( IsValidLayer ( iLayer ) )
{
if ( m_AnimOverlay [ iLayer ] . m_flPlaybackRate ! = 0.0f )
{
return ( 1.0 - m_AnimOverlay [ iLayer ] . m_flCycle ) * SequenceDuration ( m_AnimOverlay [ iLayer ] . m_nSequence ) / m_AnimOverlay [ iLayer ] . m_flPlaybackRate ;
}
return SequenceDuration ( m_AnimOverlay [ iLayer ] . m_nSequence ) ;
}
return 0.0 ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : AddLayeredSequence ( int sequence , int iPriority )
{
int i = AllocateLayer ( iPriority ) ;
// No room?
if ( IsValidLayer ( i ) )
{
m_AnimOverlay [ i ] . m_flCycle = 0 ;
m_AnimOverlay [ i ] . m_flPrevCycle = 0 ;
m_AnimOverlay [ i ] . m_flPlaybackRate = 1.0 ;
m_AnimOverlay [ i ] . m_nActivity = ACT_INVALID ;
m_AnimOverlay [ i ] . m_nSequence = sequence ;
m_AnimOverlay [ i ] . m_flWeight = 1.0f ;
m_AnimOverlay [ i ] . m_flBlendIn = 0.0f ;
m_AnimOverlay [ i ] . m_flBlendOut = 0.0f ;
m_AnimOverlay [ i ] . m_bSequenceFinished = false ;
m_AnimOverlay [ i ] . m_flLastEventCheck = 0 ;
m_AnimOverlay [ i ] . m_bLooping = ( ( GetSequenceFlags ( GetModelPtr ( ) , sequence ) & STUDIO_LOOPING ) ! = 0 ) ;
if ( ai_sequence_debug . GetBool ( ) = = true & & m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " %5.3f : adding %d (%d): %s : %5.3f (%.3f) \n " , gpGlobals - > curtime , i , m_AnimOverlay [ i ] . m_nOrder . Get ( ) , GetSequenceName ( m_AnimOverlay [ i ] . m_nSequence ) , m_AnimOverlay [ i ] . m_flCycle . Get ( ) , m_AnimOverlay [ i ] . m_flWeight . Get ( ) ) ;
}
}
return i ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
bool CBaseAnimatingOverlay : : IsValidLayer ( int iLayer )
{
return ( iLayer > = 0 & & iLayer < m_AnimOverlay . Count ( ) & & m_AnimOverlay [ iLayer ] . IsActive ( ) ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : AllocateLayer ( int iPriority )
{
int i ;
// look for an open slot and for existing layers that are lower priority
int iNewOrder = 0 ;
int iOpenLayer = - 1 ;
int iNumOpen = 0 ;
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . IsActive ( ) )
{
if ( m_AnimOverlay [ i ] . m_nPriority < = iPriority )
{
iNewOrder = MAX ( iNewOrder , m_AnimOverlay [ i ] . m_nOrder + 1 ) ;
}
}
else if ( m_AnimOverlay [ i ] . IsDying ( ) )
{
// skip
}
else if ( iOpenLayer = = - 1 )
{
iOpenLayer = i ;
}
else
{
iNumOpen + + ;
}
}
if ( iOpenLayer = = - 1 )
{
if ( m_AnimOverlay . Count ( ) > = MAX_OVERLAYS )
{
return - 1 ;
}
iOpenLayer = m_AnimOverlay . AddToTail ( ) ;
m_AnimOverlay [ iOpenLayer ] . Init ( this ) ;
}
// make sure there's always an empty unused layer so that history slots will be available on the client when it is used
if ( iNumOpen = = 0 )
{
if ( m_AnimOverlay . Count ( ) < MAX_OVERLAYS )
{
i = m_AnimOverlay . AddToTail ( ) ;
m_AnimOverlay [ i ] . Init ( this ) ;
}
}
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . m_nOrder > = iNewOrder & & m_AnimOverlay [ i ] . m_nOrder < MAX_OVERLAYS )
{
m_AnimOverlay [ i ] . m_nOrder + + ;
}
}
m_AnimOverlay [ iOpenLayer ] . m_fFlags = ANIM_LAYER_ACTIVE ;
m_AnimOverlay [ iOpenLayer ] . m_nOrder = iNewOrder ;
m_AnimOverlay [ iOpenLayer ] . m_nPriority = iPriority ;
m_AnimOverlay [ iOpenLayer ] . MarkActive ( ) ;
VerifyOrder ( ) ;
return iOpenLayer ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerPriority ( int iLayer , int iPriority )
{
if ( ! IsValidLayer ( iLayer ) )
{
return ;
}
if ( m_AnimOverlay [ iLayer ] . m_nPriority = = iPriority )
{
return ;
}
// look for an open slot and for existing layers that are lower priority
int i ;
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( m_AnimOverlay [ i ] . IsActive ( ) )
{
if ( m_AnimOverlay [ i ] . m_nOrder > m_AnimOverlay [ iLayer ] . m_nOrder )
{
m_AnimOverlay [ i ] . m_nOrder - - ;
}
}
}
int iNewOrder = 0 ;
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( i ! = iLayer & & m_AnimOverlay [ i ] . IsActive ( ) )
{
if ( m_AnimOverlay [ i ] . m_nPriority < = iPriority )
{
iNewOrder = MAX ( iNewOrder , m_AnimOverlay [ i ] . m_nOrder + 1 ) ;
}
}
}
for ( i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( i ! = iLayer & & m_AnimOverlay [ i ] . IsActive ( ) )
{
if ( m_AnimOverlay [ i ] . m_nOrder > = iNewOrder )
{
m_AnimOverlay [ i ] . m_nOrder + + ;
}
}
}
m_AnimOverlay [ iLayer ] . m_nOrder = iNewOrder ;
m_AnimOverlay [ iLayer ] . m_nPriority = iPriority ;
m_AnimOverlay [ iLayer ] . MarkActive ( ) ;
VerifyOrder ( ) ;
return ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : FindGestureLayer ( Activity activity )
{
for ( int i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
if ( ! ( m_AnimOverlay [ i ] . IsActive ( ) ) )
continue ;
if ( m_AnimOverlay [ i ] . IsKillMe ( ) )
continue ;
if ( m_AnimOverlay [ i ] . m_nActivity = = ACT_INVALID )
continue ;
if ( m_AnimOverlay [ i ] . m_nActivity = = activity )
return i ;
}
return - 1 ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseAnimatingOverlay : : IsPlayingGesture ( Activity activity )
{
return FindGestureLayer ( activity ) ! = - 1 ? true : false ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : RestartGesture ( Activity activity , bool addifmissing /*=true*/ , bool autokill /*=true*/ )
{
int idx = FindGestureLayer ( activity ) ;
if ( idx = = - 1 )
{
if ( addifmissing )
{
AddGesture ( activity , autokill ) ;
}
return ;
}
m_AnimOverlay [ idx ] . m_flCycle = 0.0f ;
m_AnimOverlay [ idx ] . m_flPrevCycle = 0.0f ;
m_AnimOverlay [ idx ] . m_flLastEventCheck = 0.0f ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : activity -
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : RemoveGesture ( Activity activity )
{
int iLayer = FindGestureLayer ( activity ) ;
if ( iLayer = = - 1 )
return ;
RemoveLayer ( iLayer ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : RemoveAllGestures ( void )
{
for ( int i = 0 ; i < m_AnimOverlay . Count ( ) ; i + + )
{
RemoveLayer ( i ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerCycle ( int iLayer , float flCycle )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( ! m_AnimOverlay [ iLayer ] . m_bLooping )
{
flCycle = clamp ( flCycle , 0.0f , 1.0f ) ;
}
m_AnimOverlay [ iLayer ] . m_flCycle = flCycle ;
m_AnimOverlay [ iLayer ] . MarkActive ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerCycle ( int iLayer , float flCycle , float flPrevCycle )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( ! m_AnimOverlay [ iLayer ] . m_bLooping )
{
flCycle = clamp ( flCycle , 0.0f , 1.0f ) ;
flPrevCycle = clamp ( flPrevCycle , 0.0f , 1.0f ) ;
}
m_AnimOverlay [ iLayer ] . m_flCycle = flCycle ;
m_AnimOverlay [ iLayer ] . m_flPrevCycle = flPrevCycle ;
m_AnimOverlay [ iLayer ] . m_flLastEventCheck = flPrevCycle ;
m_AnimOverlay [ iLayer ] . MarkActive ( ) ;
}
2016-11-30 10:01:15 -05:00
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerCycle ( int iLayer , float flCycle , float flPrevCycle , float flLastEventCheck )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( ! m_AnimOverlay [ iLayer ] . m_bLooping )
{
flCycle = clamp ( flCycle , 0.0f , 1.0f ) ;
flPrevCycle = clamp ( flPrevCycle , 0.0f , 1.0f ) ;
}
m_AnimOverlay [ iLayer ] . m_flCycle = flCycle ;
m_AnimOverlay [ iLayer ] . m_flPrevCycle = flPrevCycle ;
m_AnimOverlay [ iLayer ] . m_flLastEventCheck = flLastEventCheck ;
m_AnimOverlay [ iLayer ] . MarkActive ( ) ;
}
2013-06-26 15:22:04 -07:00
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBaseAnimatingOverlay : : GetLayerCycle ( int iLayer )
{
if ( ! IsValidLayer ( iLayer ) )
return 0.0 ;
return m_AnimOverlay [ iLayer ] . m_flCycle ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerPlaybackRate ( int iLayer , float flPlaybackRate )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
Assert ( flPlaybackRate > - 1.0 & & flPlaybackRate < 40.0 ) ;
m_AnimOverlay [ iLayer ] . m_flPlaybackRate = flPlaybackRate ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerWeight ( int iLayer , float flWeight )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
flWeight = clamp ( flWeight , 0.0f , 1.0f ) ;
m_AnimOverlay [ iLayer ] . m_flWeight = flWeight ;
m_AnimOverlay [ iLayer ] . MarkActive ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CBaseAnimatingOverlay : : GetLayerWeight ( int iLayer )
{
if ( ! IsValidLayer ( iLayer ) )
return 0.0 ;
return m_AnimOverlay [ iLayer ] . m_flWeight ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerBlendIn ( int iLayer , float flBlendIn )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
m_AnimOverlay [ iLayer ] . m_flBlendIn = flBlendIn ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerBlendOut ( int iLayer , float flBlendOut )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
m_AnimOverlay [ iLayer ] . m_flBlendOut = flBlendOut ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerAutokill ( int iLayer , bool bAutokill )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( bAutokill )
{
m_AnimOverlay [ iLayer ] . m_fFlags | = ANIM_LAYER_AUTOKILL ;
}
else
{
m_AnimOverlay [ iLayer ] . m_fFlags & = ~ ANIM_LAYER_AUTOKILL ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerLooping ( int iLayer , bool bLooping )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
m_AnimOverlay [ iLayer ] . m_bLooping = bLooping ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : SetLayerNoRestore ( int iLayer , bool bNoRestore )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( bNoRestore )
{
m_AnimOverlay [ iLayer ] . m_fFlags | = ANIM_LAYER_DONTRESTORE ;
}
else
{
m_AnimOverlay [ iLayer ] . m_fFlags & = ~ ANIM_LAYER_DONTRESTORE ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
Activity CBaseAnimatingOverlay : : GetLayerActivity ( int iLayer )
{
if ( ! IsValidLayer ( iLayer ) )
{
return ACT_INVALID ;
}
return m_AnimOverlay [ iLayer ] . m_nActivity ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CBaseAnimatingOverlay : : GetLayerSequence ( int iLayer )
{
if ( ! IsValidLayer ( iLayer ) )
{
return ACT_INVALID ;
}
return m_AnimOverlay [ iLayer ] . m_nSequence ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimatingOverlay : : RemoveLayer ( int iLayer , float flKillRate , float flKillDelay )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
if ( flKillRate > 0 )
{
m_AnimOverlay [ iLayer ] . m_flKillRate = m_AnimOverlay [ iLayer ] . m_flWeight / flKillRate ;
}
else
{
m_AnimOverlay [ iLayer ] . m_flKillRate = 100 ;
}
m_AnimOverlay [ iLayer ] . m_flKillDelay = flKillDelay ;
m_AnimOverlay [ iLayer ] . KillMe ( ) ;
}
void CBaseAnimatingOverlay : : FastRemoveLayer ( int iLayer )
{
if ( ! IsValidLayer ( iLayer ) )
return ;
// shift the other layers down in order
for ( int j = 0 ; j < m_AnimOverlay . Count ( ) ; j + + )
{
if ( ( m_AnimOverlay [ j ] . IsActive ( ) ) & & m_AnimOverlay [ j ] . m_nOrder > m_AnimOverlay [ iLayer ] . m_nOrder )
{
m_AnimOverlay [ j ] . m_nOrder - - ;
}
}
m_AnimOverlay [ iLayer ] . Init ( this ) ;
VerifyOrder ( ) ;
}
CAnimationLayer * CBaseAnimatingOverlay : : GetAnimOverlay ( int iIndex )
{
iIndex = clamp ( iIndex , 0 , m_AnimOverlay . Count ( ) - 1 ) ;
return & m_AnimOverlay [ iIndex ] ;
}
void CBaseAnimatingOverlay : : SetNumAnimOverlays ( int num )
{
if ( m_AnimOverlay . Count ( ) < num )
{
m_AnimOverlay . AddMultipleToTail ( num - m_AnimOverlay . Count ( ) ) ;
}
else if ( m_AnimOverlay . Count ( ) > num )
{
m_AnimOverlay . RemoveMultiple ( num , m_AnimOverlay . Count ( ) - num ) ;
}
}
bool CBaseAnimatingOverlay : : HasActiveLayer ( void )
{
for ( int j = 0 ; j < m_AnimOverlay . Count ( ) ; j + + )
{
if ( m_AnimOverlay [ j ] . IsActive ( ) )
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------