//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Base class for all animating characters and objects.
//
//=============================================================================//
# include "cbase.h"
# include "baseanimating.h"
# include "animation.h"
# include "activitylist.h"
# include "studio.h"
# include "bone_setup.h"
# include "mathlib/mathlib.h"
# include "model_types.h"
# include "datacache/imdlcache.h"
# include "physics.h"
# include "ndebugoverlay.h"
# include "tier1/strtools.h"
# include "npcevent.h"
# include "isaverestore.h"
# include "KeyValues.h"
# include "tier0/vprof.h"
# include "EntityFlame.h"
# include "EntityDissolve.h"
# include "ai_basenpc.h"
# include "physics_prop_ragdoll.h"
# include "datacache/idatacache.h"
# include "smoke_trail.h"
# include "props.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
ConVar ai_sequence_debug ( " ai_sequence_debug " , " 0 " ) ;
class CIKSaveRestoreOps : public CClassPtrSaveRestoreOps
{
// save data type interface
void Save ( const SaveRestoreFieldInfo_t & fieldInfo , ISave * pSave )
{
Assert ( fieldInfo . pTypeDesc - > fieldSize = = 1 ) ;
CIKContext * * pIK = ( CIKContext * * ) fieldInfo . pField ;
bool bHasIK = ( * pIK ) ! = 0 ;
pSave - > WriteBool ( & bHasIK ) ;
}
void Restore ( const SaveRestoreFieldInfo_t & fieldInfo , IRestore * pRestore )
{
Assert ( fieldInfo . pTypeDesc - > fieldSize = = 1 ) ;
CIKContext * * pIK = ( CIKContext * * ) fieldInfo . pField ;
bool bHasIK ;
pRestore - > ReadBool ( & bHasIK ) ;
* pIK = ( bHasIK ) ? new CIKContext : NULL ;
}
} ;
//-----------------------------------------------------------------------------
// Relative lighting entity
//-----------------------------------------------------------------------------
class CInfoLightingRelative : public CBaseEntity
{
public :
DECLARE_CLASS ( CInfoLightingRelative , CBaseEntity ) ;
DECLARE_DATADESC ( ) ;
DECLARE_SERVERCLASS ( ) ;
virtual void Activate ( ) ;
virtual void SetTransmit ( CCheckTransmitInfo * pInfo , bool bAlways ) ;
virtual int UpdateTransmitState ( void ) ;
private :
CNetworkHandle ( CBaseEntity , m_hLightingLandmark ) ;
string_t m_strLightingLandmark ;
} ;
LINK_ENTITY_TO_CLASS ( info_lighting_relative , CInfoLightingRelative ) ;
BEGIN_DATADESC ( CInfoLightingRelative )
DEFINE_KEYFIELD ( m_strLightingLandmark , FIELD_STRING , " LightingLandmark " ) ,
DEFINE_FIELD ( m_hLightingLandmark , FIELD_EHANDLE ) ,
END_DATADESC ( )
IMPLEMENT_SERVERCLASS_ST ( CInfoLightingRelative , DT_InfoLightingRelative )
SendPropEHandle ( SENDINFO ( m_hLightingLandmark ) ) ,
END_SEND_TABLE ( )
//-----------------------------------------------------------------------------
// Activate!
//-----------------------------------------------------------------------------
void CInfoLightingRelative : : Activate ( )
{
BaseClass : : Activate ( ) ;
if ( m_strLightingLandmark = = NULL_STRING )
{
m_hLightingLandmark = NULL ;
}
else
{
m_hLightingLandmark = gEntList . FindEntityByName ( NULL , m_strLightingLandmark ) ;
if ( ! m_hLightingLandmark )
{
DevWarning ( " %s: Could not find lighting landmark '%s'! \n " , GetClassname ( ) , STRING ( m_strLightingLandmark ) ) ;
}
else
{
// Set a force transmit because we do not have a model.
m_hLightingLandmark - > AddEFlags ( EFL_FORCE_CHECK_TRANSMIT ) ;
}
}
}
//-----------------------------------------------------------------------------
// Force our lighting landmark to be transmitted
//-----------------------------------------------------------------------------
void CInfoLightingRelative : : SetTransmit ( CCheckTransmitInfo * pInfo , bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo - > m_pTransmitEdict - > Get ( entindex ( ) ) )
return ;
BaseClass : : SetTransmit ( pInfo , bAlways ) ;
// Force our constraint entity to be sent too.
if ( m_hLightingLandmark )
{
if ( m_hLightingLandmark - > GetMoveParent ( ) )
{
// Set a full check because we have a move parent.
m_hLightingLandmark - > SetTransmitState ( FL_EDICT_FULLCHECK ) ;
}
else
{
m_hLightingLandmark - > SetTransmitState ( FL_EDICT_ALWAYS ) ;
}
m_hLightingLandmark - > SetTransmit ( pInfo , bAlways ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose Force our lighting landmark to be transmitted
//-----------------------------------------------------------------------------
int CInfoLightingRelative : : UpdateTransmitState ( void )
{
return SetTransmitState ( FL_EDICT_ALWAYS ) ;
}
static CIKSaveRestoreOps s_IKSaveRestoreOp ;
BEGIN_DATADESC ( CBaseAnimating )
DEFINE_FIELD ( m_flGroundSpeed , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flLastEventCheck , FIELD_TIME ) ,
DEFINE_FIELD ( m_bSequenceFinished , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_bSequenceLoops , FIELD_BOOLEAN ) ,
// DEFINE_FIELD( m_nForceBone, FIELD_INTEGER ),
// DEFINE_FIELD( m_vecForce, FIELD_VECTOR ),
DEFINE_INPUT ( m_nSkin , FIELD_INTEGER , " skin " ) ,
DEFINE_KEYFIELD ( m_nBody , FIELD_INTEGER , " body " ) ,
DEFINE_INPUT ( m_nBody , FIELD_INTEGER , " SetBodyGroup " ) ,
DEFINE_KEYFIELD ( m_nHitboxSet , FIELD_INTEGER , " hitboxset " ) ,
DEFINE_KEYFIELD ( m_nSequence , FIELD_INTEGER , " sequence " ) ,
DEFINE_ARRAY ( m_flPoseParameter , FIELD_FLOAT , CBaseAnimating : : NUM_POSEPAREMETERS ) ,
DEFINE_ARRAY ( m_flEncodedController , FIELD_FLOAT , CBaseAnimating : : NUM_BONECTRLS ) ,
DEFINE_KEYFIELD ( m_flPlaybackRate , FIELD_FLOAT , " playbackrate " ) ,
DEFINE_KEYFIELD ( m_flCycle , FIELD_FLOAT , " cycle " ) ,
// DEFINE_FIELD( m_flIKGroundContactTime, FIELD_TIME ),
// DEFINE_FIELD( m_flIKGroundMinHeight, FIELD_FLOAT ),
// DEFINE_FIELD( m_flIKGroundMaxHeight, FIELD_FLOAT ),
// DEFINE_FIELD( m_flEstIkFloor, FIELD_FLOAT ),
// DEFINE_FIELD( m_flEstIkOffset, FIELD_FLOAT ),
// DEFINE_FIELD( m_pStudioHdr, CStudioHdr ),
// DEFINE_FIELD( m_StudioHdrInitLock, CThreadFastMutex ),
// DEFINE_FIELD( m_BoneSetupMutex, CThreadFastMutex ),
DEFINE_CUSTOM_FIELD ( m_pIk , & s_IKSaveRestoreOp ) ,
DEFINE_FIELD ( m_iIKCounter , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_bClientSideAnimation , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_bClientSideFrameReset , FIELD_BOOLEAN ) ,
DEFINE_FIELD ( m_nNewSequenceParity , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_nResetEventsParity , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_nMuzzleFlashParity , FIELD_CHARACTER ) ,
DEFINE_KEYFIELD ( m_iszLightingOriginRelative , FIELD_STRING , " LightingOriginHack " ) ,
DEFINE_KEYFIELD ( m_iszLightingOrigin , FIELD_STRING , " LightingOrigin " ) ,
DEFINE_FIELD ( m_hLightingOrigin , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_hLightingOriginRelative , FIELD_EHANDLE ) ,
DEFINE_FIELD ( m_flModelScale , FIELD_FLOAT ) ,
DEFINE_FIELD ( m_flDissolveStartTime , FIELD_TIME ) ,
// DEFINE_FIELD( m_boneCacheHandle, memhandle_t ),
DEFINE_INPUTFUNC ( FIELD_VOID , " Ignite " , InputIgnite ) ,
DEFINE_INPUTFUNC ( FIELD_FLOAT , " IgniteLifetime " , InputIgniteLifetime ) ,
DEFINE_INPUTFUNC ( FIELD_INTEGER , " IgniteNumHitboxFires " , InputIgniteNumHitboxFires ) ,
DEFINE_INPUTFUNC ( FIELD_FLOAT , " IgniteHitboxFireScale " , InputIgniteHitboxFireScale ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " BecomeRagdoll " , InputBecomeRagdoll ) ,
DEFINE_INPUTFUNC ( FIELD_STRING , " SetLightingOriginHack " , InputSetLightingOriginRelative ) ,
DEFINE_INPUTFUNC ( FIELD_STRING , " SetLightingOrigin " , InputSetLightingOrigin ) ,
DEFINE_OUTPUT ( m_OnIgnite , " OnIgnite " ) ,
DEFINE_INPUT ( m_fadeMinDist , FIELD_FLOAT , " fademindist " ) ,
DEFINE_INPUT ( m_fadeMaxDist , FIELD_FLOAT , " fademaxdist " ) ,
DEFINE_KEYFIELD ( m_flFadeScale , FIELD_FLOAT , " fadescale " ) ,
DEFINE_KEYFIELD ( m_flModelScale , FIELD_FLOAT , " modelscale " ) ,
DEFINE_INPUTFUNC ( FIELD_VECTOR , " SetModelScale " , InputSetModelScale ) ,
DEFINE_FIELD ( m_fBoneCacheFlags , FIELD_SHORT ) ,
END_DATADESC ( )
// Sendtable for fields we don't want to send to clientside animating entities
BEGIN_SEND_TABLE_NOBASE ( CBaseAnimating , DT_ServerAnimationData )
// ANIMATION_CYCLE_BITS is defined in shareddefs.h
SendPropFloat ( SENDINFO ( m_flCycle ) , ANIMATION_CYCLE_BITS , SPROP_CHANGES_OFTEN | SPROP_ROUNDDOWN , 0.0f , 1.0f )
END_SEND_TABLE ( )
void * SendProxy_ClientSideAnimation ( const SendProp * pProp , const void * pStruct , const void * pVarData , CSendProxyRecipients * pRecipients , int objectID ) ;
// SendTable stuff.
IMPLEMENT_SERVERCLASS_ST ( CBaseAnimating , DT_BaseAnimating )
SendPropInt ( SENDINFO ( m_nForceBone ) , 8 , 0 ) ,
SendPropVector ( SENDINFO ( m_vecForce ) , - 1 , SPROP_NOSCALE ) ,
SendPropInt ( SENDINFO ( m_nSkin ) , ANIMATION_SKIN_BITS ) ,
SendPropInt ( SENDINFO ( m_nBody ) , ANIMATION_BODY_BITS ) ,
SendPropInt ( SENDINFO ( m_nHitboxSet ) , ANIMATION_HITBOXSET_BITS , SPROP_UNSIGNED ) ,
SendPropFloat ( SENDINFO ( m_flModelScale ) ) ,
SendPropArray3 ( SENDINFO_ARRAY3 ( m_flPoseParameter ) , SendPropFloat ( SENDINFO_ARRAY ( m_flPoseParameter ) , ANIMATION_POSEPARAMETER_BITS , 0 , 0.0f , 1.0f ) ) ,
SendPropInt ( SENDINFO ( m_nSequence ) , ANIMATION_SEQUENCE_BITS , SPROP_UNSIGNED ) ,
SendPropFloat ( SENDINFO ( m_flPlaybackRate ) , ANIMATION_PLAYBACKRATE_BITS , SPROP_ROUNDUP , - 4.0 , 12.0f ) , // NOTE: if this isn't a power of 2 than "1.0" can't be encoded correctly
SendPropArray3 ( SENDINFO_ARRAY3 ( m_flEncodedController ) , SendPropFloat ( SENDINFO_ARRAY ( m_flEncodedController ) , 11 , SPROP_ROUNDDOWN , 0.0f , 1.0f ) ) ,
SendPropInt ( SENDINFO ( m_bClientSideAnimation ) , 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_bClientSideFrameReset ) , 1 , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_nNewSequenceParity ) , EF_PARITY_BITS , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_nResetEventsParity ) , EF_PARITY_BITS , SPROP_UNSIGNED ) ,
SendPropInt ( SENDINFO ( m_nMuzzleFlashParity ) , EF_MUZZLEFLASH_BITS , SPROP_UNSIGNED ) ,
SendPropEHandle ( SENDINFO ( m_hLightingOrigin ) ) ,
SendPropEHandle ( SENDINFO ( m_hLightingOriginRelative ) ) ,
SendPropDataTable ( " serveranimdata " , 0 , & REFERENCE_SEND_TABLE ( DT_ServerAnimationData ) , SendProxy_ClientSideAnimation ) ,
// Fading
SendPropFloat ( SENDINFO ( m_fadeMinDist ) , 0 , SPROP_NOSCALE ) ,
SendPropFloat ( SENDINFO ( m_fadeMaxDist ) , 0 , SPROP_NOSCALE ) ,
SendPropFloat ( SENDINFO ( m_flFadeScale ) , 0 , SPROP_NOSCALE ) ,
END_SEND_TABLE ( )
CBaseAnimating : : CBaseAnimating ( )
{
m_vecForce . GetForModify ( ) . Init ( ) ;
m_nForceBone = 0 ;
m_bResetSequenceInfoOnLoad = false ;
m_bClientSideAnimation = false ;
m_pIk = NULL ;
m_iIKCounter = 0 ;
InitStepHeightAdjust ( ) ;
m_flModelScale = 1.0f ;
// initialize anim clock
m_flAnimTime = gpGlobals - > curtime ;
m_flPrevAnimTime = gpGlobals - > curtime ;
m_nNewSequenceParity = 0 ;
m_nResetEventsParity = 0 ;
m_boneCacheHandle = 0 ;
m_pStudioHdr = NULL ;
m_fadeMinDist = 0 ;
m_fadeMaxDist = 0 ;
m_flFadeScale = 0.0f ;
m_fBoneCacheFlags = 0 ;
}
CBaseAnimating : : ~ CBaseAnimating ( )
{
Studio_DestroyBoneCache ( m_boneCacheHandle ) ;
delete m_pIk ;
UnlockStudioHdr ( ) ;
delete m_pStudioHdr ;
}
void CBaseAnimating : : Precache ( )
{
# if !defined( TF_DLL )
// Anything derived from this class can potentially burn - true, but do we want it to!
PrecacheParticleSystem ( " burning_character " ) ;
# endif
BaseClass : : Precache ( ) ;
}
//-----------------------------------------------------------------------------
// Activate!
//-----------------------------------------------------------------------------
void CBaseAnimating : : Activate ( )
{
BaseClass : : Activate ( ) ;
SetLightingOrigin ( m_iszLightingOrigin ) ;
SetLightingOriginRelative ( m_iszLightingOriginRelative ) ;
// Scaled physics objects (re)create their physics here
if ( m_flModelScale ! = 1.0f & & VPhysicsGetObject ( ) )
{
// sanity check to make sure 'm_flModelScale' is in sync with the
Assert ( m_flModelScale > 0.0f ) ;
UTIL_CreateScaledPhysObject ( this , m_flModelScale ) ;
}
}
//-----------------------------------------------------------------------------
// Force our lighting origin to be trasmitted
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetTransmit ( CCheckTransmitInfo * pInfo , bool bAlways )
{
// Are we already marked for transmission?
if ( pInfo - > m_pTransmitEdict - > Get ( entindex ( ) ) )
return ;
BaseClass : : SetTransmit ( pInfo , bAlways ) ;
// Force our lighting entities to be sent too.
if ( m_hLightingOrigin )
{
m_hLightingOrigin - > SetTransmit ( pInfo , bAlways ) ;
}
if ( m_hLightingOriginRelative )
{
m_hLightingOriginRelative - > SetTransmit ( pInfo , bAlways ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int CBaseAnimating : : Restore ( IRestore & restore )
{
int result = BaseClass : : Restore ( restore ) ;
if ( m_flModelScale < = 0.0f )
m_flModelScale = 1.0f ;
LockStudioHdr ( ) ;
return result ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseAnimating : : OnRestore ( )
{
BaseClass : : OnRestore ( ) ;
if ( m_nSequence ! = - 1 & & GetModelPtr ( ) & & ! IsValidSequence ( m_nSequence ) )
m_nSequence = 0 ;
m_flEstIkFloor = GetLocalOrigin ( ) . z ;
PopulatePoseParameters ( ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseAnimating : : Spawn ( )
{
BaseClass : : Spawn ( ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseAnimating : : UseClientSideAnimation ( )
{
m_bClientSideAnimation = true ;
}
# define MAX_ANIMTIME_INTERVAL 0.2f
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetAnimTimeInterval ( void ) const
{
float flInterval ;
if ( m_flAnimTime < gpGlobals - > curtime )
{
// estimate what it'll be this frame
flInterval = clamp ( gpGlobals - > curtime - m_flAnimTime , 0.f , MAX_ANIMTIME_INTERVAL ) ;
}
else
{
// report actual
flInterval = clamp ( m_flAnimTime - m_flPrevAnimTime , 0.f , MAX_ANIMTIME_INTERVAL ) ;
}
return flInterval ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimating : : StudioFrameAdvanceInternal ( CStudioHdr * pStudioHdr , float flCycleDelta )
{
float flNewCycle = GetCycle ( ) + flCycleDelta ;
if ( flNewCycle < 0.0 | | flNewCycle > = 1.0 )
{
if ( m_bSequenceLoops )
{
flNewCycle - = ( int ) ( flNewCycle ) ;
}
else
{
flNewCycle = ( flNewCycle < 0.0f ) ? 0.0f : 1.0f ;
}
m_bSequenceFinished = true ; // just in case it wasn't caught in GetEvents
}
else if ( flNewCycle > GetLastVisibleCycle ( pStudioHdr , GetSequence ( ) ) )
{
m_bSequenceFinished = true ;
}
SetCycle ( flNewCycle ) ;
/*
if ( ! IsPlayer ( ) )
Msg ( " %s %6.3f : %6.3f %6.3f (%.3f) %.3f \n " ,
GetClassname ( ) , gpGlobals - > curtime ,
m_flAnimTime . Get ( ) , m_flPrevAnimTime , flInterval , GetCycle ( ) ) ;
*/
m_flGroundSpeed = GetSequenceGroundSpeed ( pStudioHdr , GetSequence ( ) ) * GetModelScale ( ) ;
// Msg("%s : %s : %5.1f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
InvalidatePhysicsRecursive ( ANIMATION_CHANGED ) ;
InvalidateBoneCacheIfOlderThan ( 0 ) ;
}
void CBaseAnimating : : InvalidateBoneCacheIfOlderThan ( float deltaTime )
{
CBoneCache * pcache = Studio_GetBoneCache ( m_boneCacheHandle ) ;
if ( ! pcache | | ! pcache - > IsValid ( gpGlobals - > curtime , deltaTime ) )
{
InvalidateBoneCache ( ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimating : : StudioFrameAdvanceManual ( float flInterval )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return ;
UpdateModelScale ( ) ;
m_flAnimTime = gpGlobals - > curtime ;
m_flPrevAnimTime = m_flAnimTime - flInterval ;
float flCycleRate = GetSequenceCycleRate ( pStudioHdr , GetSequence ( ) ) * m_flPlaybackRate ;
StudioFrameAdvanceInternal ( GetModelPtr ( ) , flInterval * flCycleRate ) ;
}
//=========================================================
// StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future
//=========================================================
void CBaseAnimating : : StudioFrameAdvance ( )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr | | ! pStudioHdr - > SequencesAvailable ( ) )
{
return ;
}
UpdateModelScale ( ) ;
if ( ! m_flPrevAnimTime )
{
m_flPrevAnimTime = m_flAnimTime ;
}
// Time since last animation
float flInterval = gpGlobals - > curtime - m_flAnimTime ;
flInterval = clamp ( flInterval , 0.f , MAX_ANIMTIME_INTERVAL ) ;
//Msg( "%i %s interval %f\n", entindex(), GetClassname(), flInterval );
if ( flInterval < = 0.001f )
{
// Msg("%s : %s : %5.3f (skip)\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
return ;
}
// Latch prev
m_flPrevAnimTime = m_flAnimTime ;
// Set current
m_flAnimTime = gpGlobals - > curtime ;
// Drive cycle
float flCycleRate = GetSequenceCycleRate ( pStudioHdr , GetSequence ( ) ) * m_flPlaybackRate ;
StudioFrameAdvanceInternal ( pStudioHdr , flInterval * flCycleRate ) ;
if ( ai_sequence_debug . GetBool ( ) = = true & & m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " %5.2f : %s : %s : %5.3f \n " , gpGlobals - > curtime , GetClassname ( ) , GetSequenceName ( GetSequence ( ) ) , GetCycle ( ) ) ;
}
}
//-----------------------------------------------------------------------------
// Set the relative lighting origin
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetLightingOriginRelative ( string_t strLightingOriginRelative )
{
if ( strLightingOriginRelative = = NULL_STRING )
{
SetLightingOriginRelative ( NULL ) ;
}
else
{
CBaseEntity * pLightingOrigin = gEntList . FindEntityByName ( NULL , strLightingOriginRelative ) ;
if ( ! pLightingOrigin )
{
DevWarning ( " %s: Could not find info_lighting_relative '%s'! \n " , GetClassname ( ) , STRING ( strLightingOriginRelative ) ) ;
return ;
}
else if ( ! dynamic_cast < CInfoLightingRelative * > ( pLightingOrigin ) )
{
if ( ! pLightingOrigin )
{
DevWarning ( " %s: Cannot find Lighting Origin named: %s \n " , GetEntityName ( ) . ToCStr ( ) , STRING ( strLightingOriginRelative ) ) ;
}
else
{
DevWarning ( " %s: Specified entity '%s' must be a info_lighting_relative! \n " ,
pLightingOrigin - > GetClassname ( ) , pLightingOrigin - > GetEntityName ( ) . ToCStr ( ) ) ;
}
return ;
}
SetLightingOriginRelative ( pLightingOrigin ) ;
}
// Save the name so that save/load will correctly restore it in Activate()
m_iszLightingOriginRelative = strLightingOriginRelative ;
}
//-----------------------------------------------------------------------------
// Set the lighting origin
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetLightingOrigin ( string_t strLightingOrigin )
{
if ( strLightingOrigin = = NULL_STRING )
{
SetLightingOrigin ( NULL ) ;
}
else
{
CBaseEntity * pLightingOrigin = gEntList . FindEntityByName ( NULL , strLightingOrigin ) ;
if ( ! pLightingOrigin )
{
DevWarning ( " %s: Could not find lighting origin entity named '%s'! \n " , GetClassname ( ) , STRING ( strLightingOrigin ) ) ;
return ;
}
else
{
SetLightingOrigin ( pLightingOrigin ) ;
}
}
// Save the name so that save/load will correctly restore it in Activate()
m_iszLightingOrigin = strLightingOrigin ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CBaseAnimating : : InputSetLightingOriginRelative ( inputdata_t & inputdata )
{
// Find our specified target
string_t strLightingOriginRelative = MAKE_STRING ( inputdata . value . String ( ) ) ;
SetLightingOriginRelative ( strLightingOriginRelative ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &inputdata -
//-----------------------------------------------------------------------------
void CBaseAnimating : : InputSetLightingOrigin ( inputdata_t & inputdata )
{
// Find our specified target
string_t strLightingOrigin = MAKE_STRING ( inputdata . value . String ( ) ) ;
SetLightingOrigin ( strLightingOrigin ) ;
}
//-----------------------------------------------------------------------------
// Purpose: SetModelScale input handler
//-----------------------------------------------------------------------------
void CBaseAnimating : : InputSetModelScale ( inputdata_t & inputdata )
{
Vector vecScale ;
inputdata . value . Vector3D ( vecScale ) ;
SetModelScale ( vecScale . x , vecScale . y ) ;
}
//=========================================================
// SelectWeightedSequence
//=========================================================
int CBaseAnimating : : SelectWeightedSequence ( Activity activity )
{
Assert ( activity ! = ACT_INVALID ) ;
Assert ( GetModelPtr ( ) ) ;
return : : SelectWeightedSequence ( GetModelPtr ( ) , activity , GetSequence ( ) ) ;
}
int CBaseAnimating : : SelectWeightedSequence ( Activity activity , int curSequence )
{
Assert ( activity ! = ACT_INVALID ) ;
Assert ( GetModelPtr ( ) ) ;
return : : SelectWeightedSequence ( GetModelPtr ( ) , activity , curSequence ) ;
}
//=========================================================
// ResetActivityIndexes
//=========================================================
void CBaseAnimating : : ResetActivityIndexes ( void )
{
Assert ( GetModelPtr ( ) ) ;
: : ResetActivityIndexes ( GetModelPtr ( ) ) ;
}
//=========================================================
// ResetEventIndexes
//=========================================================
void CBaseAnimating : : ResetEventIndexes ( void )
{
Assert ( GetModelPtr ( ) ) ;
: : ResetEventIndexes ( GetModelPtr ( ) ) ;
}
//=========================================================
// LookupHeaviestSequence
//
// Get sequence with highest 'weight' for this activity
//
//=========================================================
int CBaseAnimating : : SelectHeaviestSequence ( Activity activity )
{
Assert ( GetModelPtr ( ) ) ;
return : : SelectHeaviestSequence ( GetModelPtr ( ) , activity ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Looks up an activity by name.
// Input : label - Name of the activity, ie "ACT_IDLE".
// Output : Returns the activity ID or ACT_INVALID.
//-----------------------------------------------------------------------------
int CBaseAnimating : : LookupActivity ( const char * label )
{
Assert ( GetModelPtr ( ) ) ;
return : : LookupActivity ( GetModelPtr ( ) , label ) ;
}
//=========================================================
//=========================================================
int CBaseAnimating : : LookupSequence ( const char * label )
{
Assert ( GetModelPtr ( ) ) ;
return : : LookupSequence ( GetModelPtr ( ) , label ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
KeyValues * CBaseAnimating : : GetSequenceKeyValues ( int iSequence )
{
const char * szText = Studio_GetKeyValueText ( GetModelPtr ( ) , iSequence ) ;
if ( szText )
{
KeyValues * seqKeyValues = new KeyValues ( " " ) ;
if ( seqKeyValues - > LoadFromBuffer ( modelinfo - > GetModelName ( GetModel ( ) ) , szText ) )
{
return seqKeyValues ;
}
seqKeyValues - > deleteThis ( ) ;
}
return NULL ;
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : iSequence -
//
// Output : float -
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetSequenceMoveYaw ( int iSequence )
{
Vector vecReturn ;
Assert ( GetModelPtr ( ) ) ;
: : GetSequenceLinearMotion ( GetModelPtr ( ) , iSequence , GetPoseParameterArray ( ) , & vecReturn ) ;
if ( vecReturn . Length ( ) > 0 )
{
return UTIL_VecToYaw ( vecReturn ) ;
}
return NOMOTION ;
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : iSequence -
//
// Output : float
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetSequenceMoveDist ( CStudioHdr * pStudioHdr , int iSequence )
{
Vector vecReturn ;
: : GetSequenceLinearMotion ( pStudioHdr , iSequence , GetPoseParameterArray ( ) , & vecReturn ) ;
return vecReturn . Length ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : iSequence -
// *pVec -
//
//-----------------------------------------------------------------------------
void CBaseAnimating : : GetSequenceLinearMotion ( int iSequence , Vector * pVec )
{
Assert ( GetModelPtr ( ) ) ;
: : GetSequenceLinearMotion ( GetModelPtr ( ) , iSequence , GetPoseParameterArray ( ) , pVec ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : iSequence -
//
// Output : char
//-----------------------------------------------------------------------------
const char * CBaseAnimating : : GetSequenceName ( int iSequence )
{
if ( iSequence = = - 1 )
{
return " Not Found! " ;
}
if ( ! GetModelPtr ( ) )
return " No model! " ;
return : : GetSequenceName ( GetModelPtr ( ) , iSequence ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//
// Input : iSequence -
//
// Output : char
//-----------------------------------------------------------------------------
const char * CBaseAnimating : : GetSequenceActivityName ( int iSequence )
{
if ( iSequence = = - 1 )
{
return " Not Found! " ;
}
if ( ! GetModelPtr ( ) )
return " No model! " ;
return : : GetSequenceActivityName ( GetModelPtr ( ) , iSequence ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Make this a client-side simulated entity
// Input : force - vector of force to be exerted in the physics simulation
// forceBone - bone to exert force upon
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseAnimating : : BecomeRagdollOnClient ( const Vector & force )
{
// If this character has a ragdoll animation, turn it over to the physics system
if ( CanBecomeRagdoll ( ) )
{
VPhysicsDestroyObject ( ) ;
AddSolidFlags ( FSOLID_NOT_SOLID ) ;
m_nRenderFX = kRenderFxRagdoll ;
// Have to do this dance because m_vecForce is a network vector
// and can't be sent to ClampRagdollForce as a Vector *
Vector vecClampedForce ;
ClampRagdollForce ( force , & vecClampedForce ) ;
m_vecForce = vecClampedForce ;
SetParent ( NULL ) ;
AddFlag ( FL_TRANSRAGDOLL ) ;
SetMoveType ( MOVETYPE_NONE ) ;
//UTIL_SetSize( this, vec3_origin, vec3_origin );
SetThink ( NULL ) ;
SetNextThink ( gpGlobals - > curtime + 2.0f ) ;
//If we're here, then we can vanish safely
SetThink ( & CBaseEntity : : SUB_Remove ) ;
// Remove our flame entity if it's attached to us
CEntityFlame * pFireChild = dynamic_cast < CEntityFlame * > ( GetEffectEntity ( ) ) ;
if ( pFireChild )
{
pFireChild - > SetThink ( & CBaseEntity : : SUB_Remove ) ;
pFireChild - > SetNextThink ( gpGlobals - > curtime + 0.1f ) ;
}
return true ;
}
return false ;
}
bool CBaseAnimating : : IsRagdoll ( )
{
return ( m_nRenderFX = = kRenderFxRagdoll ) ? true : false ;
}
bool CBaseAnimating : : CanBecomeRagdoll ( void )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
int ragdollSequence = SelectWeightedSequence ( ACT_DIERAGDOLL ) ;
//Can't cause we don't have a ragdoll sequence.
if ( ragdollSequence = = ACTIVITY_NOT_AVAILABLE )
return false ;
if ( GetFlags ( ) & FL_TRANSRAGDOLL )
return false ;
return true ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : ResetSequenceInfo ( )
{
if ( GetSequence ( ) = = - 1 )
{
// This shouldn't happen. Setting m_nSequence blindly is a horrible coding practice.
SetSequence ( 0 ) ;
}
if ( IsDynamicModelLoading ( ) )
{
m_bResetSequenceInfoOnLoad = true ;
return ;
}
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
m_flGroundSpeed = GetSequenceGroundSpeed ( pStudioHdr , GetSequence ( ) ) * GetModelScale ( ) ;
m_bSequenceLoops = ( ( GetSequenceFlags ( pStudioHdr , GetSequence ( ) ) & STUDIO_LOOPING ) ! = 0 ) ;
// m_flAnimTime = gpGlobals->time;
m_flPlaybackRate = 1.0 ;
m_bSequenceFinished = false ;
m_flLastEventCheck = 0 ;
m_nNewSequenceParity = ( m_nNewSequenceParity + 1 ) & EF_PARITY_MASK ;
m_nResetEventsParity = ( m_nResetEventsParity + 1 ) & EF_PARITY_MASK ;
// FIXME: why is this called here? Nothing should have changed to make this nessesary
if ( pStudioHdr )
{
SetEventIndexForSequence ( pStudioHdr - > pSeqdesc ( GetSequence ( ) ) ) ;
}
}
//=========================================================
//=========================================================
bool CBaseAnimating : : IsValidSequence ( int iSequence )
{
Assert ( GetModelPtr ( ) ) ;
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( iSequence < 0 | | iSequence > = pstudiohdr - > GetNumSeq ( ) )
{
return false ;
}
return true ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : SetSequence ( int nSequence )
{
Assert ( nSequence = = 0 | | IsDynamicModelLoading ( ) | | ( GetModelPtr ( ) & & ( nSequence < GetModelPtr ( ) - > GetNumSeq ( ) ) & & ( GetModelPtr ( ) - > GetNumSeq ( ) < ( 1 < < ANIMATION_SEQUENCE_BITS ) ) ) ) ;
m_nSequence = nSequence ;
}
//=========================================================
//=========================================================
float CBaseAnimating : : SequenceDuration ( CStudioHdr * pStudioHdr , int iSequence )
{
if ( ! pStudioHdr )
{
DevWarning ( 2 , " CBaseAnimating::SequenceDuration( %d ) NULL pstudiohdr on %s! \n " , iSequence , GetClassname ( ) ) ;
return 0.1 ;
}
if ( ! pStudioHdr - > SequencesAvailable ( ) )
{
return 0.1 ;
}
if ( iSequence > = pStudioHdr - > GetNumSeq ( ) | | iSequence < 0 )
{
DevWarning ( 2 , " CBaseAnimating::SequenceDuration( %d ) out of range \n " , iSequence ) ;
return 0.1 ;
}
return Studio_Duration ( pStudioHdr , iSequence , GetPoseParameterArray ( ) ) ;
}
float CBaseAnimating : : GetSequenceCycleRate ( CStudioHdr * pStudioHdr , int iSequence )
{
float t = SequenceDuration ( pStudioHdr , iSequence ) ;
if ( t > 0.0f )
{
return 1.0f / t ;
}
else
{
return 1.0f / 0.1f ;
}
}
float CBaseAnimating : : GetLastVisibleCycle ( CStudioHdr * pStudioHdr , int iSequence )
{
if ( ! pStudioHdr )
{
DevWarning ( 2 , " CBaseAnimating::LastVisibleCycle( %d ) NULL pstudiohdr on %s! \n " , iSequence , GetClassname ( ) ) ;
return 1.0 ;
}
if ( ! ( GetSequenceFlags ( pStudioHdr , iSequence ) & STUDIO_LOOPING ) )
{
return 1.0f - ( pStudioHdr - > pSeqdesc ( iSequence ) . fadeouttime ) * GetSequenceCycleRate ( iSequence ) * m_flPlaybackRate ;
}
else
{
return 1.0 ;
}
}
float CBaseAnimating : : GetSequenceGroundSpeed ( CStudioHdr * pStudioHdr , int iSequence )
{
float t = SequenceDuration ( pStudioHdr , iSequence ) ;
if ( t > 0 )
{
return ( GetSequenceMoveDist ( pStudioHdr , iSequence ) / t ) ;
}
else
{
return 0 ;
}
}
float CBaseAnimating : : GetIdealSpeed ( ) const
{
return m_flGroundSpeed ;
}
float CBaseAnimating : : GetIdealAccel ( ) const
{
// return ideal max velocity change over 1 second.
// tuned for run-walk range of humans
return GetIdealSpeed ( ) + 50 ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if the given sequence has the anim event, false if not.
// Input : nSequence - sequence number to check
// nEvent - anim event number to look for
//-----------------------------------------------------------------------------
bool CBaseAnimating : : HasAnimEvent ( int nSequence , int nEvent )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
return false ;
}
animevent_t event ;
int index = 0 ;
while ( ( index = GetAnimationEvent ( pstudiohdr , nSequence , & event , 0.0f , 1.0f , index ) ) ! = 0 )
{
if ( event . event = = nEvent )
{
return true ;
}
}
return false ;
}
//=========================================================
// DispatchAnimEvents
//=========================================================
void CBaseAnimating : : DispatchAnimEvents ( CBaseAnimating * eventHandler )
{
// don't fire events if the framerate is 0
if ( m_flPlaybackRate = = 0.0 )
return ;
animevent_t event ;
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
Assert ( ! " CBaseAnimating::DispatchAnimEvents: model missing " ) ;
return ;
}
if ( ! pstudiohdr - > SequencesAvailable ( ) )
{
return ;
}
// skip this altogether if there are no events
if ( pstudiohdr - > pSeqdesc ( GetSequence ( ) ) . numevents = = 0 )
{
return ;
}
// look from when it last checked to some short time in the future
float flCycleRate = GetSequenceCycleRate ( GetSequence ( ) ) * m_flPlaybackRate ;
float flStart = m_flLastEventCheck ;
float flEnd = GetCycle ( ) ;
if ( ! m_bSequenceLoops & & m_bSequenceFinished )
{
flEnd = 1.01f ;
}
m_flLastEventCheck = flEnd ;
/*
if ( m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " %s:%s : checking %.2f %.2f (%d) \n " , STRING ( GetModelName ( ) ) , pstudiohdr - > pSeqdesc ( GetSequence ( ) ) . pszLabel ( ) , flStart , flEnd , m_bSequenceFinished ) ;
}
*/
// FIXME: does not handle negative framerates!
int index = 0 ;
while ( ( index = GetAnimationEvent ( pstudiohdr , GetSequence ( ) , & event , flStart , flEnd , index ) ) ! = 0 )
{
event . pSource = this ;
// calc when this event should happen
if ( flCycleRate > 0.0 )
{
float flCycle = event . cycle ;
if ( flCycle > GetCycle ( ) )
{
flCycle = flCycle - 1.0 ;
}
event . eventtime = m_flAnimTime + ( flCycle - GetCycle ( ) ) / flCycleRate + GetAnimTimeInterval ( ) ;
}
/*
if ( m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " dispatch %i (%i) cycle %f event cycle %f cyclerate %f \n " ,
( int ) ( index - 1 ) ,
( int ) event . event ,
( float ) GetCycle ( ) ,
( float ) event . cycle ,
( float ) flCycleRate ) ;
}
*/
eventHandler - > HandleAnimEvent ( & event ) ;
// FAILSAFE:
// If HandleAnimEvent has somehow reset my internal pointer
// to CStudioHdr to something other than it was when we entered
// this function, we will crash on the next call to GetAnimationEvent
// because pstudiohdr no longer points at something valid.
// So, catch this case, complain vigorously, and bail out of
// the loop.
CStudioHdr * pNowStudioHdr = GetModelPtr ( ) ;
if ( pNowStudioHdr ! = pstudiohdr )
{
AssertMsg2 ( false , " %s has changed its model while processing AnimEvents on sequence %d. Aborting dispatch. \n " , GetDebugName ( ) , GetSequence ( ) ) ;
Warning ( " %s has changed its model while processing AnimEvents on sequence %d. Aborting dispatch. \n " , GetDebugName ( ) , GetSequence ( ) ) ;
break ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimating : : HandleAnimEvent ( animevent_t * pEvent )
{
if ( ( pEvent - > type & AE_TYPE_NEWEVENTSYSTEM ) & & ( pEvent - > type & AE_TYPE_SERVER ) )
{
if ( pEvent - > event = = AE_SV_PLAYSOUND )
{
EmitSound ( pEvent - > options ) ;
return ;
}
else if ( pEvent - > event = = AE_RAGDOLL )
{
// Convert to ragdoll immediately
BecomeRagdollOnClient ( vec3_origin ) ;
return ;
}
# ifdef HL2_EPISODIC
else if ( pEvent - > event = = AE_SV_DUSTTRAIL )
{
char szAttachment [ 128 ] ;
float flDuration ;
float flSize ;
if ( sscanf ( pEvent - > options , " %s %f %f " , szAttachment , & flDuration , & flSize ) = = 3 )
{
CHandle < DustTrail > hDustTrail ;
hDustTrail = DustTrail : : CreateDustTrail ( ) ;
if ( hDustTrail )
{
hDustTrail - > m_SpawnRate = 4 ; // Particles per second
hDustTrail - > m_ParticleLifetime = 1.5 ; // Lifetime of each particle, In seconds
hDustTrail - > m_Color . Init ( 0.5f , 0.46f , 0.44f ) ;
hDustTrail - > m_StartSize = flSize ;
hDustTrail - > m_EndSize = hDustTrail - > m_StartSize * 8 ;
hDustTrail - > m_SpawnRadius = 3 ; // Each particle randomly offset from the center up to this many units
hDustTrail - > m_MinSpeed = 4 ; // u/sec
hDustTrail - > m_MaxSpeed = 10 ; // u/sec
hDustTrail - > m_Opacity = 0.5f ;
hDustTrail - > SetLifetime ( flDuration ) ; // Lifetime of the spawner, in seconds
hDustTrail - > m_StopEmitTime = gpGlobals - > curtime + flDuration ;
hDustTrail - > SetParent ( this , LookupAttachment ( szAttachment ) ) ;
hDustTrail - > SetLocalOrigin ( vec3_origin ) ;
}
}
else
{
DevWarning ( 1 , " %s unable to parse AE_SV_DUSTTRAIL event \" %s \" \n " , STRING ( GetModelName ( ) ) , pEvent - > options ) ;
}
return ;
}
# endif
}
// Failed to find a handler
const char * pName = EventList_NameForIndex ( pEvent - > event ) ;
if ( pName )
{
DevWarning ( 1 , " Unhandled animation event %s for %s \n " , pName , GetClassname ( ) ) ;
}
else
{
DevWarning ( 1 , " Unhandled animation event %d for %s \n " , pEvent - > event , GetClassname ( ) ) ;
}
}
// SetPoseParamater()
//=========================================================
//=========================================================
float CBaseAnimating : : SetPoseParameter ( CStudioHdr * pStudioHdr , const char * szName , float flValue )
{
int poseParam = LookupPoseParameter ( pStudioHdr , szName ) ;
AssertMsg2 ( poseParam > = 0 , " SetPoseParameter called with invalid argument %s by %s " , szName , GetDebugName ( ) ) ;
return SetPoseParameter ( pStudioHdr , poseParam , flValue ) ;
}
float CBaseAnimating : : SetPoseParameter ( CStudioHdr * pStudioHdr , int iParameter , float flValue )
{
if ( ! pStudioHdr )
{
return flValue ;
}
if ( iParameter > = 0 )
{
float flNewValue ;
flValue = Studio_SetPoseParameter ( pStudioHdr , iParameter , flValue , flNewValue ) ;
m_flPoseParameter . Set ( iParameter , flNewValue ) ;
}
return flValue ;
}
//=========================================================
//=========================================================
float CBaseAnimating : : GetPoseParameter ( const char * szName )
{
return GetPoseParameter ( LookupPoseParameter ( szName ) ) ;
}
float CBaseAnimating : : GetPoseParameter ( int iParameter )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
Assert ( ! " CBaseAnimating::GetPoseParameter: model missing " ) ;
return 0.0 ;
}
if ( ! pstudiohdr - > SequencesAvailable ( ) )
{
return 0 ;
}
if ( iParameter > = 0 )
{
return Studio_GetPoseParameter ( pstudiohdr , iParameter , m_flPoseParameter [ iParameter ] ) ;
}
return 0.0 ;
}
bool CBaseAnimating : : GetPoseParameterRange ( int index , float & minValue , float & maxValue )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
if ( index > = 0 & & index < pStudioHdr - > GetNumPoseParameters ( ) )
{
const mstudioposeparamdesc_t & pose = pStudioHdr - > pPoseParameter ( index ) ;
minValue = pose . start ;
maxValue = pose . end ;
return true ;
}
}
minValue = 0.0f ;
maxValue = 1.0f ;
return false ;
}
//=========================================================
//=========================================================
int CBaseAnimating : : LookupPoseParameter ( CStudioHdr * pStudioHdr , const char * szName )
{
if ( ! pStudioHdr )
return 0 ;
if ( ! pStudioHdr - > SequencesAvailable ( ) )
{
return 0 ;
}
for ( int i = 0 ; i < pStudioHdr - > GetNumPoseParameters ( ) ; i + + )
{
if ( Q_stricmp ( pStudioHdr - > pPoseParameter ( i ) . pszName ( ) , szName ) = = 0 )
{
return i ;
}
}
// AssertMsg( 0, UTIL_VarArgs( "poseparameter %s couldn't be mapped!!!\n", szName ) );
return - 1 ; // Error
}
//=========================================================
//=========================================================
bool CBaseAnimating : : HasPoseParameter ( int iSequence , const char * szName )
{
int iParameter = LookupPoseParameter ( szName ) ;
if ( iParameter = = - 1 )
{
return false ;
}
return HasPoseParameter ( iSequence , iParameter ) ;
}
//=========================================================
//=========================================================
bool CBaseAnimating : : HasPoseParameter ( int iSequence , int iParameter )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
return false ;
}
if ( ! pstudiohdr - > SequencesAvailable ( ) )
{
return false ;
}
if ( iSequence < 0 | | iSequence > = pstudiohdr - > GetNumSeq ( ) )
{
return false ;
}
mstudioseqdesc_t & seqdesc = pstudiohdr - > pSeqdesc ( iSequence ) ;
if ( pstudiohdr - > GetSharedPoseParameter ( iSequence , seqdesc . paramindex [ 0 ] ) = = iParameter | |
pstudiohdr - > GetSharedPoseParameter ( iSequence , seqdesc . paramindex [ 1 ] ) = = iParameter )
{
return true ;
}
return false ;
}
//=========================================================
// Each class that wants to use pose parameters should populate
// static variables in this entry point, rather than calling
// GetPoseParameter(const char*) every time you want to adjust
// an animation.
//
// Make sure to call BaseClass::PopulatePoseParameters() at
// the *bottom* of your function.
//=========================================================
void CBaseAnimating : : PopulatePoseParameters ( void )
{
}
//=========================================================
// Purpose: from input of 75% to 200% of maximum range, rescale smoothly from 75% to 100%
//=========================================================
float CBaseAnimating : : EdgeLimitPoseParameter ( int iParameter , float flValue , float flBase )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
{
return flValue ;
}
if ( iParameter < 0 | | iParameter > = pstudiohdr - > GetNumPoseParameters ( ) )
{
return flValue ;
}
const mstudioposeparamdesc_t & Pose = pstudiohdr - > pPoseParameter ( iParameter ) ;
if ( Pose . loop | | Pose . start = = Pose . end )
{
return flValue ;
}
return RangeCompressor ( flValue , Pose . start , Pose . end , flBase ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns index number of a given named bone
// Input : name of a bone
// Output : Bone index number or -1 if bone not found
//-----------------------------------------------------------------------------
int CBaseAnimating : : LookupBone ( const char * szName )
{
const CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
Assert ( pStudioHdr ) ;
if ( ! pStudioHdr )
return - 1 ;
return Studio_BoneIndexByName ( pStudioHdr , szName ) ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : GetBonePosition ( int iBone , Vector & origin , QAngle & angles )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetBonePosition: model missing " ) ;
return ;
}
if ( iBone < 0 | | iBone > = pStudioHdr - > numbones ( ) )
{
Assert ( ! " CBaseAnimating::GetBonePosition: invalid bone index " ) ;
return ;
}
matrix3x4_t bonetoworld ;
GetBoneTransform ( iBone , bonetoworld ) ;
MatrixAngles ( bonetoworld , angles , origin ) ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : GetBoneTransform ( int iBone , matrix3x4_t & pBoneToWorld )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetBoneTransform: model missing " ) ;
return ;
}
if ( iBone < 0 | | iBone > = pStudioHdr - > numbones ( ) )
{
Assert ( ! " CBaseAnimating::GetBoneTransform: invalid bone index " ) ;
return ;
}
CBoneCache * pcache = GetBoneCache ( ) ;
matrix3x4_t * pmatrix = pcache - > GetCachedBone ( iBone ) ;
if ( ! pmatrix )
{
MatrixCopy ( EntityToWorldTransform ( ) , pBoneToWorld ) ;
return ;
}
Assert ( pmatrix ) ;
// FIXME
MatrixCopy ( * pmatrix , pBoneToWorld ) ;
}
class CTraceFilterSkipNPCs : public CTraceFilterSimple
{
public :
CTraceFilterSkipNPCs ( const IHandleEntity * passentity , int collisionGroup )
: CTraceFilterSimple ( passentity , collisionGroup )
{
}
virtual bool ShouldHitEntity ( IHandleEntity * pServerEntity , int contentsMask )
{
if ( CTraceFilterSimple : : ShouldHitEntity ( pServerEntity , contentsMask ) )
{
CBaseEntity * pEntity = EntityFromEntityHandle ( pServerEntity ) ;
if ( pEntity - > IsNPC ( ) )
return false ;
return true ;
}
return false ;
}
} ;
//-----------------------------------------------------------------------------
// Purpose: Receives the clients IK floor position
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetIKGroundContactInfo ( float minHeight , float maxHeight )
{
m_flIKGroundContactTime = gpGlobals - > curtime ;
m_flIKGroundMinHeight = minHeight ;
m_flIKGroundMaxHeight = maxHeight ;
}
//-----------------------------------------------------------------------------
// Purpose: Initializes IK floor position
//-----------------------------------------------------------------------------
void CBaseAnimating : : InitStepHeightAdjust ( void )
{
m_flIKGroundContactTime = 0 ;
m_flIKGroundMinHeight = 0 ;
m_flIKGroundMaxHeight = 0 ;
// FIXME: not safe to call GetAbsOrigin here. Hierarchy might not be set up!
m_flEstIkFloor = GetAbsOrigin ( ) . z ;
m_flEstIkOffset = 0 ;
}
//-----------------------------------------------------------------------------
// Purpose: Interpolates client IK floor position and drops entity down so that the feet will reach
//-----------------------------------------------------------------------------
ConVar npc_height_adjust ( " npc_height_adjust " , " 1 " , FCVAR_ARCHIVE , " Enable test mode for ik height adjustment " ) ;
void CBaseAnimating : : UpdateStepOrigin ( )
{
if ( ! npc_height_adjust . GetBool ( ) )
{
m_flEstIkOffset = 0 ;
m_flEstIkFloor = GetLocalOrigin ( ) . z ;
return ;
}
/*
if ( m_debugOverlays & OVERLAY_NPC_SELECTED_BIT )
{
Msg ( " %x : %x \n " , GetMoveParent ( ) , GetGroundEntity ( ) ) ;
}
*/
if ( m_flIKGroundContactTime > 0.2 & & m_flIKGroundContactTime > gpGlobals - > curtime - 0.2 )
{
if ( ( GetFlags ( ) & ( FL_FLY | FL_SWIM ) ) = = 0 & & GetMoveParent ( ) = = NULL & & GetGroundEntity ( ) ! = NULL & & ! GetGroundEntity ( ) - > IsMoving ( ) )
{
Vector toAbs = GetAbsOrigin ( ) - GetLocalOrigin ( ) ;
if ( toAbs . z = = 0.0 )
{
CAI_BaseNPC * pNPC = MyNPCPointer ( ) ;
// FIXME: There needs to be a default step height somewhere
float height = 18.0f ;
if ( pNPC )
{
height = pNPC - > StepHeight ( ) ;
}
// debounce floor location
m_flEstIkFloor = m_flEstIkFloor * 0.2 + m_flIKGroundMinHeight * 0.8 ;
// don't let heigth difference between min and max exceed step height
float bias = clamp ( ( m_flIKGroundMaxHeight - m_flIKGroundMinHeight ) - height , 0.f , height ) ;
// save off reasonable offset
m_flEstIkOffset = clamp ( m_flEstIkFloor - GetAbsOrigin ( ) . z , - height + bias , 0.0f ) ;
return ;
}
}
}
// don't use floor offset, decay the value
m_flEstIkOffset * = 0.5 ;
m_flEstIkFloor = GetLocalOrigin ( ) . z ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the origin to use for model rendering
//-----------------------------------------------------------------------------
Vector CBaseAnimating : : GetStepOrigin ( void ) const
{
Vector tmp = GetLocalOrigin ( ) ;
tmp . z + = m_flEstIkOffset ;
return tmp ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the origin to use for model rendering
//-----------------------------------------------------------------------------
QAngle CBaseAnimating : : GetStepAngles ( void ) const
{
// TODO: Add in body lean
return GetLocalAngles ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Find IK collisions with world
// Input :
// Output : fills out m_pIk targets, calcs floor offset for rendering
//-----------------------------------------------------------------------------
void CBaseAnimating : : CalculateIKLocks ( float currentTime )
{
if ( m_pIk )
{
Ray_t ray ;
CTraceFilterSkipNPCs traceFilter ( this , GetCollisionGroup ( ) ) ;
Vector up ;
GetVectors ( NULL , NULL , & up ) ;
// FIXME: check number of slots?
for ( int i = 0 ; i < m_pIk - > m_target . Count ( ) ; i + + )
{
trace_t trace ;
CIKTarget * pTarget = & m_pIk - > m_target [ i ] ;
if ( ! pTarget - > IsActive ( ) )
continue ;
switch ( pTarget - > type )
{
case IK_GROUND :
{
Vector estGround ;
estGround = ( pTarget - > est . pos - GetAbsOrigin ( ) ) ;
estGround = estGround - ( estGround * up ) * up ;
estGround = GetAbsOrigin ( ) + estGround + pTarget - > est . floor * up ;
Vector p1 , p2 ;
VectorMA ( estGround , pTarget - > est . height , up , p1 ) ;
VectorMA ( estGround , - pTarget - > est . height , up , p2 ) ;
float r = MAX ( pTarget - > est . radius , 1 ) ;
// don't IK to other characters
ray . Init ( p1 , p2 , Vector ( - r , - r , 0 ) , Vector ( r , r , 1 ) ) ;
enginetrace - > TraceRay ( ray , MASK_SOLID , & traceFilter , & trace ) ;
/*
debugoverlay - > AddBoxOverlay ( p1 , Vector ( - r , - r , 0 ) , Vector ( r , r , 1 ) , QAngle ( 0 , 0 , 0 ) , 255 , 0 , 0 , 0 , 1.0f ) ;
debugoverlay - > AddBoxOverlay ( trace . endpos , Vector ( - r , - r , 0 ) , Vector ( r , r , 1 ) , QAngle ( 0 , 0 , 0 ) , 255 , 0 , 0 , 0 , 1.0f ) ;
debugoverlay - > AddLineOverlay ( p1 , trace . endpos , 255 , 0 , 0 , 0 , 1.0f ) ;
*/
if ( trace . startsolid )
{
ray . Init ( pTarget - > trace . hip , pTarget - > est . pos , Vector ( - r , - r , 0 ) , Vector ( r , r , 1 ) ) ;
enginetrace - > TraceRay ( ray , MASK_SOLID , & traceFilter , & trace ) ;
p1 = trace . endpos ;
VectorMA ( p1 , - pTarget - > est . height , up , p2 ) ;
ray . Init ( p1 , p2 , Vector ( - r , - r , 0 ) , Vector ( r , r , 1 ) ) ;
enginetrace - > TraceRay ( ray , MASK_SOLID , & traceFilter , & trace ) ;
}
if ( ! trace . startsolid )
{
if ( trace . DidHitWorld ( ) )
{
pTarget - > SetPosWithNormalOffset ( trace . endpos , trace . plane . normal ) ;
pTarget - > SetNormal ( trace . plane . normal ) ;
}
else
{
pTarget - > SetPos ( trace . endpos ) ;
pTarget - > SetAngles ( GetAbsAngles ( ) ) ;
}
}
}
break ;
case IK_ATTACHMENT :
{
// anything on the server?
}
break ;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Clear out animation states that are invalidated with Teleport
//-----------------------------------------------------------------------------
void CBaseAnimating : : Teleport ( const Vector * newPosition , const QAngle * newAngles , const Vector * newVelocity )
{
BaseClass : : Teleport ( newPosition , newAngles , newVelocity ) ;
if ( m_pIk )
{
m_pIk - > ClearTargets ( ) ;
}
InitStepHeightAdjust ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: build matrices first from the parent, then from the passed in arrays if the bone doesn't exist on the parent
//-----------------------------------------------------------------------------
void CBaseAnimating : : BuildMatricesWithBoneMerge (
const CStudioHdr * pStudioHdr ,
const QAngle & angles ,
const Vector & origin ,
const Vector pos [ MAXSTUDIOBONES ] ,
const Quaternion q [ MAXSTUDIOBONES ] ,
matrix3x4_t bonetoworld [ MAXSTUDIOBONES ] ,
CBaseAnimating * pParent ,
CBoneCache * pParentCache
)
{
CStudioHdr * fhdr = pParent - > GetModelPtr ( ) ;
mstudiobone_t * pbones = pStudioHdr - > pBone ( 0 ) ;
matrix3x4_t rotationmatrix ; // model to world transformation
AngleMatrix ( angles , origin , rotationmatrix ) ;
for ( int i = 0 ; i < pStudioHdr - > numbones ( ) ; i + + )
{
// Now find the bone in the parent entity.
bool merged = false ;
int parentBoneIndex = Studio_BoneIndexByName ( fhdr , pbones [ i ] . pszName ( ) ) ;
if ( parentBoneIndex > = 0 )
{
matrix3x4_t * pMat = pParentCache - > GetCachedBone ( parentBoneIndex ) ;
if ( pMat )
{
MatrixCopy ( * pMat , bonetoworld [ i ] ) ;
merged = true ;
}
}
if ( ! merged )
{
// If we get down here, then the bone wasn't merged.
matrix3x4_t bonematrix ;
QuaternionMatrix ( q [ i ] , pos [ i ] , bonematrix ) ;
if ( pbones [ i ] . parent = = - 1 )
{
ConcatTransforms ( rotationmatrix , bonematrix , bonetoworld [ i ] ) ;
}
else
{
ConcatTransforms ( bonetoworld [ pbones [ i ] . parent ] , bonematrix , bonetoworld [ i ] ) ;
}
}
}
}
ConVar sv_pvsskipanimation ( " sv_pvsskipanimation " , " 1 " , FCVAR_ARCHIVE , " Skips SetupBones when npc's are outside the PVS " ) ;
ConVar ai_setupbones_debug ( " ai_setupbones_debug " , " 0 " , 0 , " Shows that bones that are setup every think " ) ;
inline bool CBaseAnimating : : CanSkipAnimation ( void )
{
if ( ! sv_pvsskipanimation . GetBool ( ) )
return false ;
CAI_BaseNPC * pNPC = MyNPCPointer ( ) ;
if ( pNPC & & ! pNPC - > HasCondition ( COND_IN_PVS ) & & ( m_fBoneCacheFlags & ( BCF_NO_ANIMATION_SKIP | BCF_IS_IN_SPAWN ) ) = = false )
{
// If we have a player as a child, then we better setup our bones. If we don't,
// the PVS will be screwy.
return ! DoesHavePlayerChild ( ) ;
}
else
{
return false ;
}
}
void CBaseAnimating : : SetupBones ( matrix3x4_t * pBoneToWorld , int boneMask )
{
AUTO_LOCK ( m_BoneSetupMutex ) ;
VPROF_BUDGET ( " CBaseAnimating::SetupBones " , VPROF_BUDGETGROUP_SERVER_ANIM ) ;
MDLCACHE_CRITICAL_SECTION ( ) ;
Assert ( GetModelPtr ( ) ) ;
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetSkeleton() without a model " ) ;
return ;
}
Assert ( ! IsEFlagSet ( EFL_SETTING_UP_BONES ) ) ;
AddEFlags ( EFL_SETTING_UP_BONES ) ;
Vector pos [ MAXSTUDIOBONES ] ;
Quaternion q [ MAXSTUDIOBONES ] ;
// adjust hit boxes based on IK driven offset
Vector adjOrigin = GetAbsOrigin ( ) + Vector ( 0 , 0 , m_flEstIkOffset ) ;
if ( CanSkipAnimation ( ) )
{
IBoneSetup boneSetup ( pStudioHdr , boneMask , GetPoseParameterArray ( ) ) ;
boneSetup . InitPose ( pos , q ) ;
// Msg( "%.03f : %s:%s not in pvs\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
}
else
{
if ( m_pIk )
{
// FIXME: pass this into Studio_BuildMatrices to skip transforms
CBoneBitList boneComputed ;
m_iIKCounter + + ;
m_pIk - > Init ( pStudioHdr , GetAbsAngles ( ) , adjOrigin , gpGlobals - > curtime , m_iIKCounter , boneMask ) ;
GetSkeleton ( pStudioHdr , pos , q , boneMask ) ;
m_pIk - > UpdateTargets ( pos , q , pBoneToWorld , boneComputed ) ;
CalculateIKLocks ( gpGlobals - > curtime ) ;
m_pIk - > SolveDependencies ( pos , q , pBoneToWorld , boneComputed ) ;
}
else
{
// Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
GetSkeleton ( pStudioHdr , pos , q , boneMask ) ;
}
}
CBaseAnimating * pParent = dynamic_cast < CBaseAnimating * > ( GetMoveParent ( ) ) ;
if ( pParent )
{
// We're doing bone merging, so do special stuff here.
CBoneCache * pParentCache = pParent - > GetBoneCache ( ) ;
if ( pParentCache )
{
BuildMatricesWithBoneMerge (
pStudioHdr ,
GetAbsAngles ( ) ,
adjOrigin ,
pos ,
q ,
pBoneToWorld ,
pParent ,
pParentCache ) ;
RemoveEFlags ( EFL_SETTING_UP_BONES ) ;
if ( ai_setupbones_debug . GetBool ( ) )
{
DrawRawSkeleton ( pBoneToWorld , boneMask , true , 0.11 ) ;
}
return ;
}
}
Studio_BuildMatrices (
pStudioHdr ,
GetAbsAngles ( ) ,
adjOrigin ,
pos ,
q ,
- 1 ,
GetModelScale ( ) , // Scaling
pBoneToWorld ,
boneMask ) ;
if ( ai_setupbones_debug . GetBool ( ) )
{
// Msg("%s:%s:%s (%x)\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask );
DrawRawSkeleton ( pBoneToWorld , boneMask , true , 0.11 ) ;
}
RemoveEFlags ( EFL_SETTING_UP_BONES ) ;
}
//=========================================================
//=========================================================
int CBaseAnimating : : GetNumBones ( void )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
return pStudioHdr - > numbones ( ) ;
}
else
{
Assert ( ! " CBaseAnimating::GetNumBones: model missing " ) ;
return 0 ;
}
}
//=========================================================
//=========================================================
//-----------------------------------------------------------------------------
// Purpose: Returns index number of a given named attachment
// Input : name of attachment
// Output : attachment index number or -1 if attachment not found
//-----------------------------------------------------------------------------
int CBaseAnimating : : LookupAttachment ( const char * szName )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::LookupAttachment: model missing " ) ;
return 0 ;
}
// The +1 is to make attachment indices be 1-based (namely 0 == invalid or unused attachment)
return Studio_FindAttachment ( pStudioHdr , szName ) + 1 ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment
// Input : attachment name
// Output : location and angles
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetAttachment ( const char * szName , Vector & absOrigin , QAngle & absAngles )
{
return GetAttachment ( LookupAttachment ( szName ) , absOrigin , absAngles ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment
// Input : attachment index
// Output : location and angles
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetAttachment ( int iAttachment , Vector & absOrigin , QAngle & absAngles )
{
matrix3x4_t attachmentToWorld ;
bool bRet = GetAttachment ( iAttachment , attachmentToWorld ) ;
MatrixAngles ( attachmentToWorld , absAngles , absOrigin ) ;
return bRet ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location and world angles of an attachment
// Input : attachment index
// Output : location and angles
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetAttachment ( int iAttachment , matrix3x4_t & attachmentToWorld )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
MatrixCopy ( EntityToWorldTransform ( ) , attachmentToWorld ) ;
AssertOnce ( ! " CBaseAnimating::GetAttachment: model missing " ) ;
return false ;
}
if ( iAttachment < 1 | | iAttachment > pStudioHdr - > GetNumAttachments ( ) )
{
MatrixCopy ( EntityToWorldTransform ( ) , attachmentToWorld ) ;
// Assert(!"CBaseAnimating::GetAttachment: invalid attachment index");
return false ;
}
const mstudioattachment_t & pattachment = pStudioHdr - > pAttachment ( iAttachment - 1 ) ;
int iBone = pStudioHdr - > GetAttachmentBone ( iAttachment - 1 ) ;
matrix3x4_t bonetoworld ;
GetBoneTransform ( iBone , bonetoworld ) ;
if ( ( pattachment . flags & ATTACHMENT_FLAG_WORLD_ALIGN ) = = 0 )
{
ConcatTransforms ( bonetoworld , pattachment . local , attachmentToWorld ) ;
}
else
{
Vector vecLocalBonePos , vecWorldBonePos ;
MatrixGetColumn ( pattachment . local , 3 , vecLocalBonePos ) ;
VectorTransform ( vecLocalBonePos , bonetoworld , vecWorldBonePos ) ;
SetIdentityMatrix ( attachmentToWorld ) ;
MatrixSetColumn ( vecWorldBonePos , 3 , attachmentToWorld ) ;
}
return true ;
}
// gets the bone for an attachment
int CBaseAnimating : : GetAttachmentBone ( int iAttachment )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr | | iAttachment < 1 | | iAttachment > pStudioHdr - > GetNumAttachments ( ) )
{
AssertOnce ( pStudioHdr & & " CBaseAnimating::GetAttachment: model missing " ) ;
return 0 ;
}
return pStudioHdr - > GetAttachmentBone ( iAttachment - 1 ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the world location of an attachment
// Input : attachment index
// Output : location and angles
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetAttachment ( const char * szName , Vector & absOrigin , Vector * forward , Vector * right , Vector * up )
{
return GetAttachment ( LookupAttachment ( szName ) , absOrigin , forward , right , up ) ;
}
bool CBaseAnimating : : GetAttachment ( int iAttachment , Vector & absOrigin , Vector * forward , Vector * right , Vector * up )
{
matrix3x4_t attachmentToWorld ;
bool bRet = GetAttachment ( iAttachment , attachmentToWorld ) ;
MatrixPosition ( attachmentToWorld , absOrigin ) ;
if ( forward )
{
MatrixGetColumn ( attachmentToWorld , 0 , forward ) ;
}
if ( right )
{
MatrixGetColumn ( attachmentToWorld , 1 , right ) ;
}
if ( up )
{
MatrixGetColumn ( attachmentToWorld , 2 , up ) ;
}
return bRet ;
}
//-----------------------------------------------------------------------------
// Returns the attachment in local space
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetAttachmentLocal ( const char * szName , Vector & origin , QAngle & angles )
{
return GetAttachmentLocal ( LookupAttachment ( szName ) , origin , angles ) ;
}
bool CBaseAnimating : : GetAttachmentLocal ( int iAttachment , Vector & origin , QAngle & angles )
{
matrix3x4_t attachmentToEntity ;
bool bRet = GetAttachmentLocal ( iAttachment , attachmentToEntity ) ;
MatrixAngles ( attachmentToEntity , angles , origin ) ;
return bRet ;
}
bool CBaseAnimating : : GetAttachmentLocal ( int iAttachment , matrix3x4_t & attachmentToLocal )
{
matrix3x4_t attachmentToWorld ;
bool bRet = GetAttachment ( iAttachment , attachmentToWorld ) ;
matrix3x4_t worldToEntity ;
MatrixInvert ( EntityToWorldTransform ( ) , worldToEntity ) ;
ConcatTransforms ( worldToEntity , attachmentToWorld , attachmentToLocal ) ;
return bRet ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : GetEyeballs ( Vector & origin , QAngle & angles )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetAttachment: model missing " ) ;
return ;
}
for ( int iBodypart = 0 ; iBodypart < pStudioHdr - > numbodyparts ( ) ; iBodypart + + )
{
mstudiobodyparts_t * pBodypart = pStudioHdr - > pBodypart ( iBodypart ) ;
for ( int iModel = 0 ; iModel < pBodypart - > nummodels ; iModel + + )
{
mstudiomodel_t * pModel = pBodypart - > pModel ( iModel ) ;
for ( int iEyeball = 0 ; iEyeball < pModel - > numeyeballs ; iEyeball + + )
{
mstudioeyeball_t * pEyeball = pModel - > pEyeball ( iEyeball ) ;
matrix3x4_t bonetoworld ;
GetBoneTransform ( pEyeball - > bone , bonetoworld ) ;
VectorTransform ( pEyeball - > org , bonetoworld , origin ) ;
MatrixAngles ( bonetoworld , angles ) ; // ???
}
}
}
}
//=========================================================
//=========================================================
int CBaseAnimating : : FindTransitionSequence ( int iCurrentSequence , int iGoalSequence , int * piDir )
{
Assert ( GetModelPtr ( ) ) ;
if ( piDir = = NULL )
{
int iDir = 1 ;
int sequence = : : FindTransitionSequence ( GetModelPtr ( ) , iCurrentSequence , iGoalSequence , & iDir ) ;
if ( iDir ! = 1 )
return - 1 ;
else
return sequence ;
}
return : : FindTransitionSequence ( GetModelPtr ( ) , iCurrentSequence , iGoalSequence , piDir ) ;
}
bool CBaseAnimating : : GotoSequence ( int iCurrentSequence , float flCurrentCycle , float flCurrentRate , int iGoalSequence , int & nNextSequence , float & flNextCycle , int & iNextDir )
{
return : : GotoSequence ( GetModelPtr ( ) , iCurrentSequence , flCurrentCycle , flCurrentRate , iGoalSequence , nNextSequence , flNextCycle , iNextDir ) ;
}
int CBaseAnimating : : GetEntryNode ( int iSequence )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
return pstudiohdr - > EntryNode ( iSequence ) ;
}
int CBaseAnimating : : GetExitNode ( int iSequence )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
return pstudiohdr - > ExitNode ( iSequence ) ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : SetBodygroup ( int iGroup , int iValue )
{
// SetBodygroup is not supported on pending dynamic models. Wait for it to load!
// XXX TODO we could buffer up the group and value if we really needed to. -henryg
Assert ( GetModelPtr ( ) ) ;
int newBody = m_nBody ;
: : SetBodygroup ( GetModelPtr ( ) , newBody , iGroup , iValue ) ;
m_nBody = newBody ;
}
int CBaseAnimating : : GetBodygroup ( int iGroup )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? 0 : : : GetBodygroup ( GetModelPtr ( ) , m_nBody , iGroup ) ;
}
const char * CBaseAnimating : : GetBodygroupName ( int iGroup )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? " " : : : GetBodygroupName ( GetModelPtr ( ) , iGroup ) ;
}
int CBaseAnimating : : FindBodygroupByName ( const char * name )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? - 1 : : : FindBodygroupByName ( GetModelPtr ( ) , name ) ;
}
int CBaseAnimating : : GetBodygroupCount ( int iGroup )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? 0 : : : GetBodygroupCount ( GetModelPtr ( ) , iGroup ) ;
}
int CBaseAnimating : : GetNumBodyGroups ( void )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? 0 : : : GetNumBodyGroups ( GetModelPtr ( ) ) ;
}
int CBaseAnimating : : ExtractBbox ( int sequence , Vector & mins , Vector & maxs )
{
Assert ( IsDynamicModelLoading ( ) | | GetModelPtr ( ) ) ;
return IsDynamicModelLoading ( ) ? 0 : : : ExtractBbox ( GetModelPtr ( ) , sequence , mins , maxs ) ;
}
//=========================================================
//=========================================================
void CBaseAnimating : : SetSequenceBox ( void )
{
Vector mins , maxs ;
// Get sequence bbox
if ( ExtractBbox ( GetSequence ( ) , mins , maxs ) )
{
// expand box for rotation
// find min / max for rotations
float yaw = GetLocalAngles ( ) . y * ( M_PI / 180.0 ) ;
Vector xvector , yvector ;
xvector . x = cos ( yaw ) ;
xvector . y = sin ( yaw ) ;
yvector . x = - sin ( yaw ) ;
yvector . y = cos ( yaw ) ;
Vector bounds [ 2 ] ;
bounds [ 0 ] = mins ;
bounds [ 1 ] = maxs ;
Vector rmin ( 9999 , 9999 , 9999 ) ;
Vector rmax ( - 9999 , - 9999 , - 9999 ) ;
Vector base , transformed ;
for ( int i = 0 ; i < = 1 ; i + + )
{
base . x = bounds [ i ] . x ;
for ( int j = 0 ; j < = 1 ; j + + )
{
base . y = bounds [ j ] . y ;
for ( int k = 0 ; k < = 1 ; k + + )
{
base . z = bounds [ k ] . z ;
// transform the point
transformed . x = xvector . x * base . x + yvector . x * base . y ;
transformed . y = xvector . y * base . x + yvector . y * base . y ;
transformed . z = base . z ;
for ( int l = 0 ; l < 3 ; l + + )
{
if ( transformed [ l ] < rmin [ l ] )
rmin [ l ] = transformed [ l ] ;
if ( transformed [ l ] > rmax [ l ] )
rmax [ l ] = transformed [ l ] ;
}
}
}
}
rmin . z = 0 ;
rmax . z = rmin . z + 1 ;
UTIL_SetSize ( this , rmin , rmax ) ;
}
}
//=========================================================
//=========================================================
int CBaseAnimating : : RegisterPrivateActivity ( const char * pszActivityName )
{
return ActivityList_RegisterPrivateActivity ( pszActivityName ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Notifies the console that this entity could not retrieve an
// animation sequence for the specified activity. This probably means
// there's a typo in the model QC file, or the sequence is missing
// entirely.
//
//
// Input : iActivity - The activity that failed to resolve to a sequence.
//
//
// NOTE : IMPORTANT - Something needs to be done so that private activities
// (which are allowed to collide in the activity list) remember each
// entity that registered an activity there, and the activity name
// each character registered.
//-----------------------------------------------------------------------------
void CBaseAnimating : : ReportMissingActivity ( int iActivity )
{
Msg ( " %s has no sequence for act:%s \n " , GetClassname ( ) , ActivityList_NameForIndex ( iActivity ) ) ;
}
LocalFlexController_t CBaseAnimating : : GetNumFlexControllers ( void )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return LocalFlexController_t ( 0 ) ;
return pstudiohdr - > numflexcontrollers ( ) ;
}
const char * CBaseAnimating : : GetFlexDescFacs ( int iFlexDesc )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
mstudioflexdesc_t * pflexdesc = pstudiohdr - > pFlexdesc ( iFlexDesc ) ;
return pflexdesc - > pszFACS ( ) ;
}
const char * CBaseAnimating : : GetFlexControllerName ( LocalFlexController_t iFlexController )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
mstudioflexcontroller_t * pflexcontroller = pstudiohdr - > pFlexcontroller ( iFlexController ) ;
return pflexcontroller - > pszName ( ) ;
}
const char * CBaseAnimating : : GetFlexControllerType ( LocalFlexController_t iFlexController )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
mstudioflexcontroller_t * pflexcontroller = pstudiohdr - > pFlexcontroller ( iFlexController ) ;
return pflexcontroller - > pszType ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Converts the ground speed of the animating entity into a true velocity
// Output : Vector - velocity of the character at its current m_flGroundSpeed
//-----------------------------------------------------------------------------
Vector CBaseAnimating : : GetGroundSpeedVelocity ( void )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return vec3_origin ;
QAngle vecAngles ;
Vector vecVelocity ;
vecAngles . y = GetSequenceMoveYaw ( GetSequence ( ) ) ;
vecAngles . x = 0 ;
vecAngles . z = 0 ;
vecAngles . y + = GetLocalAngles ( ) . y ;
AngleVectors ( vecAngles , & vecVelocity ) ;
vecVelocity = vecVelocity * m_flGroundSpeed ;
return vecVelocity ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetInstantaneousVelocity ( float flInterval )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
// FIXME: someone needs to check for last frame, etc.
float flNextCycle = GetCycle ( ) + flInterval * GetSequenceCycleRate ( GetSequence ( ) ) * m_flPlaybackRate ;
Vector vecVelocity ;
Studio_SeqVelocity ( pstudiohdr , GetSequence ( ) , flNextCycle , GetPoseParameterArray ( ) , vecVelocity ) ;
vecVelocity * = m_flPlaybackRate ;
return vecVelocity . Length ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetEntryVelocity ( int iSequence )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
Vector vecVelocity ;
Studio_SeqVelocity ( pstudiohdr , iSequence , 0.0 , GetPoseParameterArray ( ) , vecVelocity ) ;
return vecVelocity . Length ( ) ;
}
float CBaseAnimating : : GetExitVelocity ( int iSequence )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
Vector vecVelocity ;
Studio_SeqVelocity ( pstudiohdr , iSequence , 1.0 , GetPoseParameterArray ( ) , vecVelocity ) ;
return vecVelocity . Length ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetIntervalMovement ( float flIntervalUsed , bool & bMoveSeqFinished , Vector & newPosition , QAngle & newAngles )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr | | ! pstudiohdr - > SequencesAvailable ( ) )
return false ;
float flComputedCycleRate = GetSequenceCycleRate ( GetSequence ( ) ) ;
float flNextCycle = GetCycle ( ) + flIntervalUsed * flComputedCycleRate * m_flPlaybackRate ;
if ( ( ! m_bSequenceLoops ) & & flNextCycle > 1.0 )
{
flIntervalUsed = GetCycle ( ) / ( flComputedCycleRate * m_flPlaybackRate ) ;
flNextCycle = 1.0 ;
bMoveSeqFinished = true ;
}
else
{
bMoveSeqFinished = false ;
}
Vector deltaPos ;
QAngle deltaAngles ;
if ( Studio_SeqMovement ( pstudiohdr , GetSequence ( ) , GetCycle ( ) , flNextCycle , GetPoseParameterArray ( ) , deltaPos , deltaAngles ) )
{
VectorYawRotate ( deltaPos , GetLocalAngles ( ) . y , deltaPos ) ;
newPosition = GetLocalOrigin ( ) + deltaPos ;
newAngles . Init ( ) ;
newAngles . y = GetLocalAngles ( ) . y + deltaAngles . y ;
return true ;
}
else
{
newPosition = GetLocalOrigin ( ) ;
newAngles = GetLocalAngles ( ) ;
return false ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output :
//-----------------------------------------------------------------------------
bool CBaseAnimating : : GetSequenceMovement ( int nSequence , float fromCycle , float toCycle , Vector & deltaPosition , QAngle & deltaAngles )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return false ;
return Studio_SeqMovement ( pstudiohdr , nSequence , fromCycle , toCycle , GetPoseParameterArray ( ) , deltaPosition , deltaAngles ) ;
}
//-----------------------------------------------------------------------------
// Purpose: find frame where they animation has moved a given distance.
// Output :
//-----------------------------------------------------------------------------
float CBaseAnimating : : GetMovementFrame ( float flDist )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return 0 ;
float t = Studio_FindSeqDistance ( pstudiohdr , GetSequence ( ) , GetPoseParameterArray ( ) , flDist ) ;
return t ;
}
//-----------------------------------------------------------------------------
// Purpose: does a specific sequence have movement?
// Output :
//-----------------------------------------------------------------------------
bool CBaseAnimating : : HasMovement ( int iSequence )
{
CStudioHdr * pstudiohdr = GetModelPtr ( ) ;
if ( ! pstudiohdr )
return false ;
// FIXME: this needs to check to see if there are keys, and the object is walking
Vector deltaPos ;
QAngle deltaAngles ;
if ( Studio_SeqMovement ( pstudiohdr , iSequence , 0.0f , 1.0f , GetPoseParameterArray ( ) , deltaPos , deltaAngles ) )
{
return true ;
}
return false ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *szModelName -
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetModel ( const char * szModelName )
{
MDLCACHE_CRITICAL_SECTION ( ) ;
// delete exiting studio model container
UnlockStudioHdr ( ) ;
delete m_pStudioHdr ;
m_pStudioHdr = NULL ;
if ( szModelName [ 0 ] )
{
int modelIndex = modelinfo - > GetModelIndex ( szModelName ) ;
const model_t * model = modelinfo - > GetModel ( modelIndex ) ;
if ( model & & ( modelinfo - > GetModelType ( model ) ! = mod_studio ) )
{
Msg ( " Setting CBaseAnimating to non-studio model %s (type:%i) \n " , szModelName , modelinfo - > GetModelType ( model ) ) ;
}
}
if ( m_boneCacheHandle )
{
Studio_DestroyBoneCache ( m_boneCacheHandle ) ;
m_boneCacheHandle = 0 ;
}
UTIL_SetModel ( this , szModelName ) ;
InitBoneControllers ( ) ;
SetSequence ( 0 ) ;
PopulatePoseParameters ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
//-----------------------------------------------------------------------------
void CBaseAnimating : : LockStudioHdr ( )
{
AUTO_LOCK ( m_StudioHdrInitLock ) ;
const model_t * mdl = GetModel ( ) ;
if ( mdl )
{
MDLHandle_t hStudioHdr = modelinfo - > GetCacheHandle ( mdl ) ;
if ( hStudioHdr ! = MDLHANDLE_INVALID )
{
const studiohdr_t * pStudioHdr = mdlcache - > LockStudioHdr ( hStudioHdr ) ;
CStudioHdr * pStudioHdrContainer = NULL ;
if ( ! m_pStudioHdr )
{
if ( pStudioHdr )
{
pStudioHdrContainer = new CStudioHdr ;
pStudioHdrContainer - > Init ( pStudioHdr , mdlcache ) ;
}
}
else
{
pStudioHdrContainer = m_pStudioHdr ;
}
Assert ( ( pStudioHdr = = NULL & & pStudioHdrContainer = = NULL ) | | pStudioHdrContainer - > GetRenderHdr ( ) = = pStudioHdr ) ;
if ( pStudioHdrContainer & & pStudioHdrContainer - > GetVirtualModel ( ) )
{
MDLHandle_t hVirtualModel = VoidPtrToMDLHandle ( pStudioHdrContainer - > GetRenderHdr ( ) - > VirtualModel ( ) ) ;
mdlcache - > LockStudioHdr ( hVirtualModel ) ;
}
m_pStudioHdr = pStudioHdrContainer ; // must be last to ensure virtual model correctly set up
}
}
}
void CBaseAnimating : : UnlockStudioHdr ( )
{
if ( m_pStudioHdr )
{
const model_t * mdl = GetModel ( ) ;
if ( mdl )
{
mdlcache - > UnlockStudioHdr ( modelinfo - > GetCacheHandle ( mdl ) ) ;
if ( m_pStudioHdr - > GetVirtualModel ( ) )
{
MDLHandle_t hVirtualModel = VoidPtrToMDLHandle ( m_pStudioHdr - > GetRenderHdr ( ) - > VirtualModel ( ) ) ;
mdlcache - > UnlockStudioHdr ( hVirtualModel ) ;
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: return the index to the shared bone cache
// Output :
//-----------------------------------------------------------------------------
CBoneCache * CBaseAnimating : : GetBoneCache ( void )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
Assert ( pStudioHdr ) ;
CBoneCache * pcache = Studio_GetBoneCache ( m_boneCacheHandle ) ;
int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT ;
// TF queries these bones to position weapons when players are killed
# if defined( TF_DLL )
boneMask | = BONE_USED_BY_BONE_MERGE ;
# endif
if ( pcache )
{
if ( pcache - > IsValid ( gpGlobals - > curtime ) & & ( pcache - > m_boneMask & boneMask ) = = boneMask & & pcache - > m_timeValid < = gpGlobals - > curtime )
{
// Msg("%s:%s:%s (%x:%x:%8.4f) cache\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask, pcache->m_boneMask, pcache->m_timeValid );
// in memory and still valid, use it!
return pcache ;
}
// in memory, but missing some of the bone masks
if ( ( pcache - > m_boneMask & boneMask ) ! = boneMask )
{
Studio_DestroyBoneCache ( m_boneCacheHandle ) ;
m_boneCacheHandle = 0 ;
pcache = NULL ;
}
}
matrix3x4_t bonetoworld [ MAXSTUDIOBONES ] ;
SetupBones ( bonetoworld , boneMask ) ;
if ( pcache )
{
// still in memory but out of date, refresh the bones.
pcache - > UpdateBones ( bonetoworld , pStudioHdr - > numbones ( ) , gpGlobals - > curtime ) ;
}
else
{
bonecacheparams_t params ;
params . pStudioHdr = pStudioHdr ;
params . pBoneToWorld = bonetoworld ;
params . curtime = gpGlobals - > curtime ;
params . boneMask = boneMask ;
m_boneCacheHandle = Studio_CreateBoneCache ( params ) ;
pcache = Studio_GetBoneCache ( m_boneCacheHandle ) ;
}
Assert ( pcache ) ;
return pcache ;
}
void CBaseAnimating : : InvalidateBoneCache ( void )
{
Studio_InvalidateBoneCache ( m_boneCacheHandle ) ;
}
bool CBaseAnimating : : TestCollision ( const Ray_t & ray , unsigned int fContentsMask , trace_t & tr )
{
// Return a special case for scaled physics objects
if ( GetModelScale ( ) ! = 1.0f )
{
IPhysicsObject * pPhysObject = VPhysicsGetObject ( ) ;
Vector vecPosition ;
QAngle vecAngles ;
pPhysObject - > GetPosition ( & vecPosition , & vecAngles ) ;
const CPhysCollide * pScaledCollide = pPhysObject - > GetCollide ( ) ;
physcollision - > TraceBox ( ray , pScaledCollide , vecPosition , vecAngles , & tr ) ;
return tr . DidHit ( ) ;
}
if ( IsSolidFlagSet ( FSOLID_CUSTOMRAYTEST ) )
{
if ( ! TestHitboxes ( ray , fContentsMask , tr ) )
return true ;
return tr . DidHit ( ) ;
}
// We shouldn't get here.
Assert ( 0 ) ;
return false ;
}
bool CBaseAnimating : : TestHitboxes ( const Ray_t & ray , unsigned int fContentsMask , trace_t & tr )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetBonePosition: model missing " ) ;
return false ;
}
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( ! set | | ! set - > numhitboxes )
return false ;
CBoneCache * pcache = GetBoneCache ( ) ;
matrix3x4_t * hitboxbones [ MAXSTUDIOBONES ] ;
pcache - > ReadCachedBonePointers ( hitboxbones , pStudioHdr - > numbones ( ) ) ;
if ( TraceToStudio ( physprops , ray , pStudioHdr , set , hitboxbones , fContentsMask , GetAbsOrigin ( ) , GetModelScale ( ) , tr ) )
{
mstudiobbox_t * pbox = set - > pHitbox ( tr . hitbox ) ;
mstudiobone_t * pBone = pStudioHdr - > pBone ( pbox - > bone ) ;
tr . surface . name = " **studio** " ;
tr . surface . flags = SURF_HITBOX ;
tr . surface . surfaceProps = physprops - > GetSurfaceIndex ( pBone - > pszSurfaceProp ( ) ) ;
}
return true ;
}
void CBaseAnimating : : InitBoneControllers ( void ) // FIXME: rename
{
int i ;
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return ;
int nBoneControllerCount = pStudioHdr - > numbonecontrollers ( ) ;
if ( nBoneControllerCount > NUM_BONECTRLS )
{
nBoneControllerCount = NUM_BONECTRLS ;
# ifdef _DEBUG
Warning ( " Model %s has too many bone controllers! (Max %d allowed) \n " , pStudioHdr - > pszName ( ) , NUM_BONECTRLS ) ;
# endif
}
for ( i = 0 ; i < nBoneControllerCount ; i + + )
{
SetBoneController ( i , 0.0 ) ;
}
Assert ( pStudioHdr - > SequencesAvailable ( ) ) ;
if ( pStudioHdr - > SequencesAvailable ( ) )
{
for ( i = 0 ; i < pStudioHdr - > GetNumPoseParameters ( ) ; i + + )
{
SetPoseParameter ( i , 0.0 ) ;
}
}
}
//=========================================================
//=========================================================
float CBaseAnimating : : SetBoneController ( int iController , float flValue )
{
Assert ( GetModelPtr ( ) ) ;
CStudioHdr * pmodel = ( CStudioHdr * ) GetModelPtr ( ) ;
Assert ( iController > = 0 & & iController < NUM_BONECTRLS ) ;
float newValue ;
float retVal = Studio_SetController ( pmodel , iController , flValue , newValue ) ;
float & val = m_flEncodedController . GetForModify ( iController ) ;
val = newValue ;
return retVal ;
}
//=========================================================
//=========================================================
float CBaseAnimating : : GetBoneController ( int iController )
{
Assert ( GetModelPtr ( ) ) ;
CStudioHdr * pmodel = ( CStudioHdr * ) GetModelPtr ( ) ;
return Studio_GetController ( pmodel , iController , m_flEncodedController [ iController ] ) ;
}
//------------------------------------------------------------------------------
// Purpose : Returns velcocity of the NPC from it's animation.
// If physically simulated gets velocity from physics object
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseAnimating : : GetVelocity ( Vector * vVelocity , AngularImpulse * vAngVelocity )
{
if ( GetMoveType ( ) = = MOVETYPE_VPHYSICS )
{
BaseClass : : GetVelocity ( vVelocity , vAngVelocity ) ;
}
else if ( ! ( GetFlags ( ) & FL_ONGROUND ) )
{
BaseClass : : GetVelocity ( vVelocity , vAngVelocity ) ;
}
else
{
if ( vVelocity ! = NULL )
{
Vector vRawVel ;
GetSequenceLinearMotion ( GetSequence ( ) , & vRawVel ) ;
// Build a rotation matrix from NPC orientation
matrix3x4_t fRotateMatrix ;
AngleMatrix ( GetLocalAngles ( ) , fRotateMatrix ) ;
VectorRotate ( vRawVel , fRotateMatrix , * vVelocity ) ;
}
if ( vAngVelocity ! = NULL )
{
QAngle tmp = GetLocalAngularVelocity ( ) ;
QAngleToAngularImpulse ( tmp , * vAngVelocity ) ;
}
}
}
//=========================================================
//=========================================================
void CBaseAnimating : : GetSkeleton ( CStudioHdr * pStudioHdr , Vector pos [ ] , Quaternion q [ ] , int boneMask )
{
if ( ! pStudioHdr )
{
Assert ( ! " CBaseAnimating::GetSkeleton() without a model " ) ;
return ;
}
IBoneSetup boneSetup ( pStudioHdr , boneMask , GetPoseParameterArray ( ) ) ;
boneSetup . InitPose ( pos , q ) ;
boneSetup . AccumulatePose ( pos , q , GetSequence ( ) , GetCycle ( ) , 1.0 , 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 ( ) ) ;
}
int CBaseAnimating : : DrawDebugTextOverlays ( void )
{
int text_offset = BaseClass : : DrawDebugTextOverlays ( ) ;
if ( m_debugOverlays & OVERLAY_TEXT_BIT )
{
// ----------------
// Print Look time
// ----------------
char tempstr [ 1024 ] ;
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Sequence: (%3d) %s " , GetSequence ( ) , GetSequenceName ( GetSequence ( ) ) ) ;
EntityText ( text_offset , tempstr , 0 ) ;
text_offset + + ;
const char * pActname = GetSequenceActivityName ( GetSequence ( ) ) ;
if ( pActname & & strlen ( pActname ) )
{
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Activity %s " , pActname ) ;
EntityText ( text_offset , tempstr , 0 ) ;
text_offset + + ;
}
Q_snprintf ( tempstr , sizeof ( tempstr ) , " Cycle: %.5f (%.5f) " , ( float ) GetCycle ( ) , m_flAnimTime . Get ( ) ) ;
EntityText ( text_offset , tempstr , 0 ) ;
text_offset + + ;
}
// Visualize attachment points
if ( m_debugOverlays & OVERLAY_ATTACHMENTS_BIT )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
Vector vecPos , vecForward , vecRight , vecUp ;
char tempstr [ 256 ] ;
// Iterate all the stored attachments
for ( int i = 1 ; i < = pStudioHdr - > GetNumAttachments ( ) ; i + + )
{
GetAttachment ( i , vecPos , & vecForward , & vecRight , & vecUp ) ;
// Red - forward, green - right, blue - up
NDebugOverlay : : Line ( vecPos , vecPos + ( vecForward * 4.0f ) , 255 , 0 , 0 , true , 0.05f ) ;
NDebugOverlay : : Line ( vecPos , vecPos + ( vecRight * 4.0f ) , 0 , 255 , 0 , true , 0.05f ) ;
NDebugOverlay : : Line ( vecPos , vecPos + ( vecUp * 4.0f ) , 0 , 0 , 255 , true , 0.05f ) ;
Q_snprintf ( tempstr , sizeof ( tempstr ) , " < %s (%d) " , pStudioHdr - > pAttachment ( i - 1 ) . pszName ( ) , i ) ;
NDebugOverlay : : Text ( vecPos , tempstr , true , 0.05f ) ;
}
}
}
return text_offset ;
}
//-----------------------------------------------------------------------------
// Purpose: Force a clientside-animating entity to reset it's frame
//-----------------------------------------------------------------------------
void CBaseAnimating : : ResetClientsideFrame ( void )
{
// TODO: Once we can chain MSG_ENTITY messages, use one of them
m_bClientSideFrameReset = ! ( bool ) m_bClientSideFrameReset ;
}
//-----------------------------------------------------------------------------
// Purpose: Returns the origin at which to play an inputted dispatcheffect
//-----------------------------------------------------------------------------
void CBaseAnimating : : GetInputDispatchEffectPosition ( const char * sInputString , Vector & pOrigin , QAngle & pAngles )
{
// See if there's a specified attachment point
int iAttachment ;
if ( GetModelPtr ( ) & & sscanf ( sInputString , " %d " , & iAttachment ) )
{
if ( ! GetAttachment ( iAttachment , pOrigin , pAngles ) )
{
Msg ( " ERROR: Mapmaker tried to spawn DispatchEffect %s, but %s has no attachment %d \n " ,
sInputString , STRING ( GetModelName ( ) ) , iAttachment ) ;
}
return ;
}
BaseClass : : GetInputDispatchEffectPosition ( sInputString , pOrigin , pAngles ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : setnum -
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetHitboxSet ( int setnum )
{
# ifdef _DEBUG
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return ;
if ( setnum > pStudioHdr - > numhitboxsets ( ) )
{
// Warn if an bogus hitbox set is being used....
static bool s_bWarned = false ;
if ( ! s_bWarned )
{
Warning ( " Using bogus hitbox set in entity %s! \n " , GetClassname ( ) ) ;
s_bWarned = true ;
}
setnum = 0 ;
}
# endif
m_nHitboxSet = setnum ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *setname -
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetHitboxSetByName ( const char * setname )
{
Assert ( GetModelPtr ( ) ) ;
m_nHitboxSet = FindHitboxSetByName ( GetModelPtr ( ) , setname ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimating : : GetHitboxSet ( void )
{
return m_nHitboxSet ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : char const
//-----------------------------------------------------------------------------
const char * CBaseAnimating : : GetHitboxSetName ( void )
{
Assert ( GetModelPtr ( ) ) ;
return : : GetHitboxSetName ( GetModelPtr ( ) , m_nHitboxSet ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int CBaseAnimating : : GetHitboxSetCount ( void )
{
Assert ( GetModelPtr ( ) ) ;
return : : GetHitboxSetCount ( GetModelPtr ( ) ) ;
}
static Vector hullcolor [ 8 ] =
{
Vector ( 1.0 , 1.0 , 1.0 ) ,
Vector ( 1.0 , 0.5 , 0.5 ) ,
Vector ( 0.5 , 1.0 , 0.5 ) ,
Vector ( 1.0 , 1.0 , 0.5 ) ,
Vector ( 0.5 , 0.5 , 1.0 ) ,
Vector ( 1.0 , 0.5 , 1.0 ) ,
Vector ( 0.5 , 1.0 , 1.0 ) ,
Vector ( 1.0 , 1.0 , 1.0 )
} ;
//-----------------------------------------------------------------------------
// Purpose: Send the current hitboxes for this model to the client ( to compare with
// r_drawentities 3 client side boxes ).
// WARNING: This uses a ton of bandwidth, only use on a listen server
//-----------------------------------------------------------------------------
void CBaseAnimating : : DrawServerHitboxes ( float duration /*= 0.0f*/ , bool monocolor /*= false*/ )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return ;
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( ! set )
return ;
Vector position ;
QAngle angles ;
int r = 0 ;
int g = 0 ;
int b = 255 ;
for ( int i = 0 ; i < set - > numhitboxes ; i + + )
{
mstudiobbox_t * pbox = set - > pHitbox ( i ) ;
GetBonePosition ( pbox - > bone , position , angles ) ;
if ( ! monocolor )
{
int j = ( pbox - > group % 8 ) ;
r = ( int ) ( 255.0f * hullcolor [ j ] [ 0 ] ) ;
g = ( int ) ( 255.0f * hullcolor [ j ] [ 1 ] ) ;
b = ( int ) ( 255.0f * hullcolor [ j ] [ 2 ] ) ;
}
NDebugOverlay : : BoxAngles ( position , pbox - > bbmin * GetModelScale ( ) , pbox - > bbmax * GetModelScale ( ) , angles , r , g , b , 0 , duration ) ;
}
}
void CBaseAnimating : : DrawRawSkeleton ( matrix3x4_t boneToWorld [ ] , int boneMask , bool noDepthTest , float duration , bool monocolor )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return ;
int i ;
int r = 255 ;
int g = 255 ;
int b = monocolor ? 255 : 0 ;
for ( i = 0 ; i < pStudioHdr - > numbones ( ) ; i + + )
{
if ( pStudioHdr - > pBone ( i ) - > flags & boneMask )
{
Vector p1 ;
MatrixPosition ( boneToWorld [ i ] , p1 ) ;
if ( pStudioHdr - > pBone ( i ) - > parent ! = - 1 )
{
Vector p2 ;
MatrixPosition ( boneToWorld [ pStudioHdr - > pBone ( i ) - > parent ] , p2 ) ;
NDebugOverlay : : Line ( p1 , p2 , r , g , b , noDepthTest , duration ) ;
}
}
}
}
int CBaseAnimating : : GetHitboxBone ( int hitboxIndex )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( set & & hitboxIndex < set - > numhitboxes )
{
return set - > pHitbox ( hitboxIndex ) - > bone ;
}
}
return 0 ;
}
//-----------------------------------------------------------------------------
// Computes a box that surrounds all hitboxes
//-----------------------------------------------------------------------------
bool CBaseAnimating : : ComputeHitboxSurroundingBox ( Vector * pVecWorldMins , Vector * pVecWorldMaxs )
{
// Note that this currently should not be called during Relink because of IK.
// The code below recomputes bones so as to get at the hitboxes,
// which causes IK to trigger, which causes raycasts against the other entities to occur,
// which is illegal to do while in the Relink phase.
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return false ;
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( ! set | | ! set - > numhitboxes )
return false ;
CBoneCache * pCache = GetBoneCache ( ) ;
// Compute a box in world space that surrounds this entity
pVecWorldMins - > Init ( FLT_MAX , FLT_MAX , FLT_MAX ) ;
pVecWorldMaxs - > Init ( - FLT_MAX , - FLT_MAX , - FLT_MAX ) ;
Vector vecBoxAbsMins , vecBoxAbsMaxs ;
for ( int i = 0 ; i < set - > numhitboxes ; i + + )
{
mstudiobbox_t * pbox = set - > pHitbox ( i ) ;
matrix3x4_t * pMatrix = pCache - > GetCachedBone ( pbox - > bone ) ;
if ( pMatrix )
{
TransformAABB ( * pMatrix , pbox - > bbmin * GetModelScale ( ) , pbox - > bbmax * GetModelScale ( ) , vecBoxAbsMins , vecBoxAbsMaxs ) ;
VectorMin ( * pVecWorldMins , vecBoxAbsMins , * pVecWorldMins ) ;
VectorMax ( * pVecWorldMaxs , vecBoxAbsMaxs , * pVecWorldMaxs ) ;
}
}
return true ;
}
//-----------------------------------------------------------------------------
// Computes a box that surrounds all hitboxes, in entity space
//-----------------------------------------------------------------------------
bool CBaseAnimating : : ComputeEntitySpaceHitboxSurroundingBox ( Vector * pVecWorldMins , Vector * pVecWorldMaxs )
{
// Note that this currently should not be called during position recomputation because of IK.
// The code below recomputes bones so as to get at the hitboxes,
// which causes IK to trigger, which causes raycasts against the other entities to occur,
// which is illegal to do while in the computeabsposition phase.
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return false ;
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( ! set | | ! set - > numhitboxes )
return false ;
CBoneCache * pCache = GetBoneCache ( ) ;
matrix3x4_t * hitboxbones [ MAXSTUDIOBONES ] ;
pCache - > ReadCachedBonePointers ( hitboxbones , pStudioHdr - > numbones ( ) ) ;
// Compute a box in world space that surrounds this entity
pVecWorldMins - > Init ( FLT_MAX , FLT_MAX , FLT_MAX ) ;
pVecWorldMaxs - > Init ( - FLT_MAX , - FLT_MAX , - FLT_MAX ) ;
matrix3x4_t worldToEntity , boneToEntity ;
MatrixInvert ( EntityToWorldTransform ( ) , worldToEntity ) ;
Vector vecBoxAbsMins , vecBoxAbsMaxs ;
for ( int i = 0 ; i < set - > numhitboxes ; i + + )
{
mstudiobbox_t * pbox = set - > pHitbox ( i ) ;
ConcatTransforms ( worldToEntity , * hitboxbones [ pbox - > bone ] , boneToEntity ) ;
TransformAABB ( boneToEntity , pbox - > bbmin , pbox - > bbmax , vecBoxAbsMins , vecBoxAbsMaxs ) ;
VectorMin ( * pVecWorldMins , vecBoxAbsMins , * pVecWorldMins ) ;
VectorMax ( * pVecWorldMaxs , vecBoxAbsMaxs , * pVecWorldMaxs ) ;
}
return true ;
}
int CBaseAnimating : : GetPhysicsBone ( int boneIndex )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
if ( boneIndex > = 0 & & boneIndex < pStudioHdr - > numbones ( ) )
return pStudioHdr - > pBone ( boneIndex ) - > physicsbone ;
}
return 0 ;
}
bool CBaseAnimating : : LookupHitbox ( const char * szName , int & outSet , int & outBox )
{
CStudioHdr * pHdr = GetModelPtr ( ) ;
outSet = - 1 ;
outBox = - 1 ;
if ( ! pHdr )
return false ;
for ( int set = 0 ; set < pHdr - > numhitboxsets ( ) ; set + + )
{
for ( int i = 0 ; i < pHdr - > iHitboxCount ( set ) ; i + + )
{
mstudiobbox_t * pBox = pHdr - > pHitbox ( i , set ) ;
if ( ! pBox )
continue ;
const char * szBoxName = pBox - > pszHitboxName ( ) ;
if ( Q_stricmp ( szBoxName , szName ) = = 0 )
{
outSet = set ;
outBox = i ;
return true ;
}
}
}
return false ;
}
void CBaseAnimating : : CopyAnimationDataFrom ( CBaseAnimating * pSource )
{
this - > SetModelName ( pSource - > GetModelName ( ) ) ;
this - > SetModelIndex ( pSource - > GetModelIndex ( ) ) ;
this - > SetCycle ( pSource - > GetCycle ( ) ) ;
this - > SetEffects ( pSource - > GetEffects ( ) ) ;
this - > IncrementInterpolationFrame ( ) ;
this - > SetSequence ( pSource - > GetSequence ( ) ) ;
this - > m_flAnimTime = pSource - > m_flAnimTime ;
this - > m_nBody = pSource - > m_nBody ;
this - > m_nSkin = pSource - > m_nSkin ;
this - > LockStudioHdr ( ) ;
}
int CBaseAnimating : : GetHitboxesFrontside ( int * boxList , int boxMax , const Vector & normal , float dist )
{
int count = 0 ;
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( pStudioHdr )
{
mstudiohitboxset_t * set = pStudioHdr - > pHitboxSet ( m_nHitboxSet ) ;
if ( set )
{
matrix3x4_t matrix ;
for ( int b = 0 ; b < set - > numhitboxes ; b + + )
{
mstudiobbox_t * pbox = set - > pHitbox ( b ) ;
GetBoneTransform ( pbox - > bone , matrix ) ;
Vector center = ( pbox - > bbmax + pbox - > bbmin ) * 0.5 ;
Vector centerWs ;
VectorTransform ( center , matrix , centerWs ) ;
if ( DotProduct ( centerWs , normal ) > = dist )
{
if ( count < boxMax )
{
boxList [ count ] = b ;
count + + ;
}
}
}
}
}
return count ;
}
void CBaseAnimating : : EnableServerIK ( )
{
if ( ! m_pIk )
{
m_pIk = new CIKContext ;
m_iIKCounter = 0 ;
}
}
void CBaseAnimating : : DisableServerIK ( )
{
delete m_pIk ;
m_pIk = NULL ;
}
Activity CBaseAnimating : : GetSequenceActivity ( int iSequence )
{
if ( iSequence = = - 1 )
{
return ACT_INVALID ;
}
if ( ! GetModelPtr ( ) )
return ACT_INVALID ;
return ( Activity ) : : GetSequenceActivity ( GetModelPtr ( ) , iSequence ) ;
}
void CBaseAnimating : : ModifyOrAppendCriteria ( AI_CriteriaSet & set )
{
BaseClass : : ModifyOrAppendCriteria ( set ) ;
// TODO
// Append any animation state parameters here
}
void CBaseAnimating : : DoMuzzleFlash ( )
{
m_nMuzzleFlashParity = ( m_nMuzzleFlashParity + 1 ) & ( ( 1 < < EF_MUZZLEFLASH_BITS ) - 1 ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : scale -
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetModelScale ( float scale , float change_duration /*= 0.0f*/ )
{
if ( change_duration > 0.0f )
{
ModelScale * mvs = ( ModelScale * ) CreateDataObject ( MODELSCALE ) ;
mvs - > m_flModelScaleStart = m_flModelScale ;
mvs - > m_flModelScaleGoal = scale ;
mvs - > m_flModelScaleStartTime = gpGlobals - > curtime ;
mvs - > m_flModelScaleFinishTime = mvs - > m_flModelScaleStartTime + change_duration ;
}
else
{
m_flModelScale = scale ;
RefreshCollisionBounds ( ) ;
if ( HasDataObjectType ( MODELSCALE ) )
{
DestroyDataObject ( MODELSCALE ) ;
}
}
}
void CBaseAnimating : : UpdateModelScale ( )
{
ModelScale * mvs = ( ModelScale * ) GetDataObject ( MODELSCALE ) ;
if ( ! mvs )
{
return ;
}
float dt = mvs - > m_flModelScaleFinishTime - mvs - > m_flModelScaleStartTime ;
Assert ( dt > 0.0f ) ;
float frac = ( gpGlobals - > curtime - mvs - > m_flModelScaleStartTime ) / dt ;
frac = clamp ( frac , 0.0f , 1.0f ) ;
if ( gpGlobals - > curtime > = mvs - > m_flModelScaleFinishTime )
{
m_flModelScale = mvs - > m_flModelScaleGoal ;
DestroyDataObject ( MODELSCALE ) ;
}
else
{
m_flModelScale = Lerp ( frac , mvs - > m_flModelScaleStart , mvs - > m_flModelScaleGoal ) ;
}
RefreshCollisionBounds ( ) ;
}
void CBaseAnimating : : RefreshCollisionBounds ( void )
{
CollisionProp ( ) - > RefreshScaledCollisionBounds ( ) ;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseAnimating : : Ignite ( float flFlameLifetime , bool bNPCOnly , float flSize , bool bCalledByLevelDesigner )
{
if ( IsOnFire ( ) )
return ;
bool bIsNPC = IsNPC ( ) ;
// Right now this prevents stuff we don't want to catch on fire from catching on fire.
if ( bNPCOnly & & bIsNPC = = false )
{
return ;
}
if ( bIsNPC = = true & & bCalledByLevelDesigner = = false )
{
CAI_BaseNPC * pNPC = MyNPCPointer ( ) ;
if ( pNPC & & pNPC - > AllowedToIgnite ( ) = = false )
return ;
}
CEntityFlame * pFlame = CEntityFlame : : Create ( this ) ;
if ( pFlame )
{
pFlame - > SetLifetime ( flFlameLifetime ) ;
AddFlag ( FL_ONFIRE ) ;
SetEffectEntity ( pFlame ) ;
if ( flSize > 0.0f )
{
pFlame - > SetSize ( flSize ) ;
}
}
m_OnIgnite . FireOutput ( this , this ) ;
}
void CBaseAnimating : : IgniteLifetime ( float flFlameLifetime )
{
if ( ! IsOnFire ( ) )
Ignite ( 30 , false , 0.0f , true ) ;
CEntityFlame * pFlame = dynamic_cast < CEntityFlame * > ( GetEffectEntity ( ) ) ;
if ( ! pFlame )
return ;
pFlame - > SetLifetime ( flFlameLifetime ) ;
}
void CBaseAnimating : : IgniteNumHitboxFires ( int iNumHitBoxFires )
{
if ( ! IsOnFire ( ) )
Ignite ( 30 , false , 0.0f , true ) ;
CEntityFlame * pFlame = dynamic_cast < CEntityFlame * > ( GetEffectEntity ( ) ) ;
if ( ! pFlame )
return ;
pFlame - > SetNumHitboxFires ( iNumHitBoxFires ) ;
}
void CBaseAnimating : : IgniteHitboxFireScale ( float flHitboxFireScale )
{
if ( ! IsOnFire ( ) )
Ignite ( 30 , false , 0.0f , true ) ;
CEntityFlame * pFlame = dynamic_cast < CEntityFlame * > ( GetEffectEntity ( ) ) ;
if ( ! pFlame )
return ;
pFlame - > SetHitboxFireScale ( flHitboxFireScale ) ;
}
//-----------------------------------------------------------------------------
// Fades out!
//-----------------------------------------------------------------------------
bool CBaseAnimating : : Dissolve ( const char * pMaterialName , float flStartTime , bool bNPCOnly , int nDissolveType , Vector vDissolverOrigin , int iMagnitude )
{
// Right now this prevents stuff we don't want to catch on fire from catching on fire.
if ( bNPCOnly & & ! ( GetFlags ( ) & FL_NPC ) )
return false ;
// Can't dissolve twice
if ( IsDissolving ( ) )
return false ;
bool bRagdollCreated = false ;
CEntityDissolve * pDissolve = CEntityDissolve : : Create ( this , pMaterialName , flStartTime , nDissolveType , & bRagdollCreated ) ;
if ( pDissolve )
{
SetEffectEntity ( pDissolve ) ;
AddFlag ( FL_DISSOLVING ) ;
m_flDissolveStartTime = flStartTime ;
pDissolve - > SetDissolverOrigin ( vDissolverOrigin ) ;
pDissolve - > SetMagnitude ( iMagnitude ) ;
}
// if this is a ragdoll dissolving, fire an event
if ( ( CLASS_NONE = = Classify ( ) ) & & ( ClassMatches ( " prop_ragdoll " ) ) )
{
IGameEvent * event = gameeventmanager - > CreateEvent ( " ragdoll_dissolved " ) ;
if ( event )
{
event - > SetInt ( " entindex " , entindex ( ) ) ;
gameeventmanager - > FireEvent ( event ) ;
}
}
return bRagdollCreated ;
}
//-----------------------------------------------------------------------------
// Make a model look as though it's burning.
//-----------------------------------------------------------------------------
void CBaseAnimating : : Scorch ( int rate , int floor )
{
color32 color = GetRenderColor ( ) ;
if ( color . r > floor )
color . r - = rate ;
if ( color . g > floor )
color . g - = rate ;
if ( color . b > floor )
color . b - = rate ;
SetRenderColor ( color . r , color . g , color . b ) ;
}
void CBaseAnimating : : ResetSequence ( int nSequence )
{
if ( ai_sequence_debug . GetBool ( ) = = true & & ( m_debugOverlays & OVERLAY_NPC_SELECTED_BIT ) )
{
DevMsg ( " ResetSequence : %s: %s -> %s \n " , GetClassname ( ) , GetSequenceName ( GetSequence ( ) ) , GetSequenceName ( nSequence ) ) ;
}
if ( ! SequenceLoops ( ) )
{
SetCycle ( 0 ) ;
}
// Tracker 17868: If the sequence number didn't actually change, but you call resetsequence info, it changes
// the newsequenceparity bit which causes the client to call m_flCycle.Reset() which causes a very slight
// discontinuity in looping animations as they reset around to cycle 0.0. This was causing the parentattached
// helmet on barney to hitch every time barney's idle cycled back around to its start.
bool changed = nSequence ! = GetSequence ( ) ? true : false ;
SetSequence ( nSequence ) ;
if ( changed | | ! SequenceLoops ( ) )
{
ResetSequenceInfo ( ) ;
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CBaseAnimating : : InputIgnite ( inputdata_t & inputdata )
{
Ignite ( 30 , false , 0.0f , true ) ;
}
void CBaseAnimating : : InputIgniteLifetime ( inputdata_t & inputdata )
{
IgniteLifetime ( inputdata . value . Float ( ) ) ;
}
void CBaseAnimating : : InputIgniteNumHitboxFires ( inputdata_t & inputdata )
{
IgniteNumHitboxFires ( inputdata . value . Int ( ) ) ;
}
void CBaseAnimating : : InputIgniteHitboxFireScale ( inputdata_t & inputdata )
{
IgniteHitboxFireScale ( inputdata . value . Float ( ) ) ;
}
void CBaseAnimating : : InputBecomeRagdoll ( inputdata_t & inputdata )
{
BecomeRagdollOnClient ( vec3_origin ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAnimating : : SetFadeDistance ( float minFadeDist , float maxFadeDist )
{
m_fadeMinDist = minFadeDist ;
m_fadeMaxDist = maxFadeDist ;
}
//-----------------------------------------------------------------------------
// Purpose: Async prefetches all anim data used by a particular sequence. Returns true if all of the required data is memory resident
// Input : iSequence -
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseAnimating : : PrefetchSequence ( int iSequence )
{
CStudioHdr * pStudioHdr = GetModelPtr ( ) ;
if ( ! pStudioHdr )
return true ;
return Studio_PrefetchSequence ( pStudioHdr , iSequence ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseAnimating : : IsSequenceLooping ( CStudioHdr * pStudioHdr , int iSequence )
{
return ( : : GetSequenceFlags ( pStudioHdr , iSequence ) & STUDIO_LOOPING ) ! = 0 ;
}
//-----------------------------------------------------------------------------
// Purpose: model-change notification. Fires on dynamic load completion as well
//-----------------------------------------------------------------------------
CStudioHdr * CBaseAnimating : : OnNewModel ( )
{
( void ) BaseClass : : OnNewModel ( ) ;
// TODO: if dynamic, validate m_Sequence and apply queued body group settings?
if ( IsDynamicModelLoading ( ) )
{
// Called while dynamic model still loading -> new model, clear deferred state
m_bResetSequenceInfoOnLoad = false ;
return NULL ;
}
CStudioHdr * hdr = GetModelPtr ( ) ;
if ( m_bResetSequenceInfoOnLoad )
{
m_bResetSequenceInfoOnLoad = false ;
ResetSequenceInfo ( ) ;
}
return hdr ;
}