aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/shared/animation.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/shared/animation.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/shared/animation.cpp')
-rw-r--r--mp/src/game/shared/animation.cpp1942
1 files changed, 971 insertions, 971 deletions
diff --git a/mp/src/game/shared/animation.cpp b/mp/src/game/shared/animation.cpp
index 9d5183c8..0f6dd754 100644
--- a/mp/src/game/shared/animation.cpp
+++ b/mp/src/game/shared/animation.cpp
@@ -1,971 +1,971 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//
-//=============================================================================//
-#include "cbase.h"
-#include "studio.h"
-#include "activitylist.h"
-#include "engine/IEngineSound.h"
-#include "ai_activity.h"
-#include "animation.h"
-#include "bone_setup.h"
-#include "scriptevent.h"
-#include "npcevent.h"
-#include "eventlist.h"
-#include "tier0/vprof.h"
-
-#if !defined( CLIENT_DLL ) && !defined( MAKEXVCD )
-#include "util.h"
-#include "enginecallback.h"
-#endif
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#pragma warning( disable : 4244 )
-#define iabs(i) (( (i) >= 0 ) ? (i) : -(i) )
-
-int ExtractBbox( CStudioHdr *pstudiohdr, int sequence, Vector& mins, Vector& maxs )
-{
- if (! pstudiohdr)
- return 0;
-
- if (!pstudiohdr->SequencesAvailable())
- return 0;
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
-
- mins = seqdesc.bbmin;
-
- maxs = seqdesc.bbmax;
-
- return 1;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//
-// Input : *pstudiohdr -
-// iSequence -
-//
-// Output : mstudioseqdesc_t
-//-----------------------------------------------------------------------------
-
-extern int g_nActivityListVersion;
-extern int g_nEventListVersion;
-
-void SetEventIndexForSequence( mstudioseqdesc_t &seqdesc )
-{
- if ( &seqdesc == NULL )
- return;
-
- seqdesc.flags |= STUDIO_EVENT;
-
- if ( seqdesc.numevents == 0 )
- return;
-
- for ( int index = 0; index < (int)seqdesc.numevents; index++ )
- {
- mstudioevent_t *pevent = seqdesc.pEvent( index );
-
- if ( !pevent )
- continue;
-
- if ( pevent->type & AE_TYPE_NEWEVENTSYSTEM )
- {
- const char *pEventName = pevent->pszEventName();
-
- int iEventIndex = EventList_IndexForName( pEventName );
-
- if ( iEventIndex == -1 )
- {
- pevent->event = EventList_RegisterPrivateEvent( pEventName );
- }
- else
- {
- pevent->event = iEventIndex;
- pevent->type |= EventList_GetEventType( iEventIndex );
- }
- }
- }
-}
-
-mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc )
-{
- if (!(seqdesc.flags & STUDIO_EVENT))
- {
- SetEventIndexForSequence( seqdesc );
- }
-
- return seqdesc.pEvent( 0 );
-}
-
-
-void BuildAllAnimationEventIndexes( CStudioHdr *pstudiohdr )
-{
- if ( !pstudiohdr )
- return;
-
- if( pstudiohdr->GetEventListVersion() != g_nEventListVersion )
- {
- for ( int i = 0 ; i < pstudiohdr->GetNumSeq() ; i++ )
- {
- SetEventIndexForSequence( pstudiohdr->pSeqdesc( i ) );
- }
-
- pstudiohdr->SetEventListVersion( g_nEventListVersion );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Ensures that activity / index relationship is recalculated
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-void ResetEventIndexes( CStudioHdr *pstudiohdr )
-{
- if (! pstudiohdr)
- return;
-
- pstudiohdr->SetEventListVersion( g_nEventListVersion - 1 );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-
-void SetActivityForSequence( CStudioHdr *pstudiohdr, int i )
-{
- int iActivityIndex;
- const char *pszActivityName;
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
-
- seqdesc.flags |= STUDIO_ACTIVITY;
-
- pszActivityName = GetSequenceActivityName( pstudiohdr, i );
- if ( pszActivityName[0] != '\0' )
- {
- iActivityIndex = ActivityList_IndexForName( pszActivityName );
-
- if ( iActivityIndex == -1 )
- {
- // Allow this now. Animators can create custom activities that are referenced only on the client or by scripts, etc.
- //Warning( "***\nModel %s tried to reference unregistered activity: %s \n***\n", pstudiohdr->name, pszActivityName );
- //Assert(0);
- // HACK: the client and server don't share the private activity list so registering it on the client would hose the server
-#ifdef CLIENT_DLL
- seqdesc.flags &= ~STUDIO_ACTIVITY;
-#else
- seqdesc.activity = ActivityList_RegisterPrivateActivity( pszActivityName );
-#endif
- }
- else
- {
- seqdesc.activity = iActivityIndex;
- }
- }
-}
-
-//=========================================================
-// IndexModelSequences - set activity and event indexes for all model
-// sequences that have them.
-//=========================================================
-
-void IndexModelSequences( CStudioHdr *pstudiohdr )
-{
- int i;
-
- if (! pstudiohdr)
- return;
-
- if (!pstudiohdr->SequencesAvailable())
- return;
-
- for ( i = 0 ; i < pstudiohdr->GetNumSeq() ; i++ )
- {
- SetActivityForSequence( pstudiohdr, i );
- SetEventIndexForSequence( pstudiohdr->pSeqdesc( i ) );
- }
-
- pstudiohdr->SetActivityListVersion( g_nActivityListVersion );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Ensures that activity / index relationship is recalculated
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-void ResetActivityIndexes( CStudioHdr *pstudiohdr )
-{
- if (! pstudiohdr)
- return;
-
- pstudiohdr->SetActivityListVersion( g_nActivityListVersion - 1 );
-}
-
-void VerifySequenceIndex( CStudioHdr *pstudiohdr )
-{
- if ( !pstudiohdr )
- {
- return;
- }
-
- if( pstudiohdr->GetActivityListVersion( ) != g_nActivityListVersion )
- {
- // this model's sequences have not yet been indexed by activity
- IndexModelSequences( pstudiohdr );
- }
-}
-
-#if !defined( MAKEXVCD )
-bool IsInPrediction()
-{
- return CBaseEntity::GetPredictionPlayer() != NULL;
-}
-
-int SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence )
-{
- VPROF( "SelectWeightedSequence" );
-
- if (! pstudiohdr)
- return 0;
-
- if (!pstudiohdr->SequencesAvailable())
- return 0;
-
- VerifySequenceIndex( pstudiohdr );
-
-#if STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW
- int weighttotal = 0;
- int seq = ACTIVITY_NOT_AVAILABLE;
- int weight = 0;
- for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
- {
- int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
- if (curActivity == activity)
- {
- if ( curSequence == i && weight < 0 )
- {
- seq = i;
- break;
- }
- weighttotal += iabs(weight);
-
- int randomValue;
-
- if ( IsInPrediction() )
- randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
- else
- randomValue = RandomInt( 0, weighttotal - 1 );
-
- if (!weighttotal || randomValue < iabs(weight))
- seq = i;
- }
- }
-
- return seq;
-#else
- return pstudiohdr->SelectWeightedSequence( activity, curSequence );
-#endif
-}
-
-
-// Pick a sequence for the given activity. If the current sequence is appropriate for the
-// current activity, and its stored weight is negative (whatever that means), always select
-// it. Otherwise perform a weighted selection -- imagine a large roulette wheel, with each
-// sequence having a number of spaces corresponding to its weight.
-int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence )
-{
- if (!ValidateAgainst(pstudiohdr))
- {
- AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName());
- ExecuteOnce(DebuggerBreakIfDebugging());
- Reinitialize(pstudiohdr);
- }
-
- // a null m_pSequenceTuples just means that this studio header has no activities.
- if (!m_pSequenceTuples)
- return ACTIVITY_NOT_AVAILABLE;
-
- // is the current sequence appropriate?
- if (curSequence >= 0)
- {
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( curSequence );
-
- if (seqdesc.activity == activity && seqdesc.actweight < 0)
- return curSequence;
- }
-
- // get the data for the given activity
- HashValueType dummy( activity, 0, 0, 0 );
- UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy);
- if (!m_ActToSeqHash.IsValidHandle(handle))
- {
- return ACTIVITY_NOT_AVAILABLE;
- }
- const HashValueType * __restrict actData = &m_ActToSeqHash[handle];
-
- int weighttotal = actData->totalWeight;
- // generate a random number from 0 to the total weight
- int randomValue;
- if ( IsInPrediction() )
- {
- randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1 );
- }
- else
- {
- randomValue = RandomInt( 0, weighttotal - 1 );
- }
-
- // chug through the entries in the list (they are sequential therefore cache-coherent)
- // until we run out of random juice
- SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx;
-
- const SequenceTuple *const stopHere = sequenceInfo + actData->count; // this is a backup
- // in case the weights are somehow miscalculated -- we don't read or write through
- // it (because it aliases the restricted pointer above); it's only here for
- // the comparison.
-
- while (randomValue >= sequenceInfo->weight && sequenceInfo < stopHere)
- {
- randomValue -= sequenceInfo->weight;
- ++sequenceInfo;
- }
-
- return sequenceInfo->seqnum;
-
-}
-
-
-#endif
-
-int SelectHeaviestSequence( CStudioHdr *pstudiohdr, int activity )
-{
- if ( !pstudiohdr )
- return 0;
-
- VerifySequenceIndex( pstudiohdr );
-
- int maxweight = 0;
- int seq = ACTIVITY_NOT_AVAILABLE;
- int weight = 0;
- for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
- {
- int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
- if (curActivity == activity)
- {
- if ( iabs(weight) > maxweight )
- {
- maxweight = iabs(weight);
- seq = i;
- }
- }
- }
-
- return seq;
-}
-
-void GetEyePosition ( CStudioHdr *pstudiohdr, Vector &vecEyePosition )
-{
- if ( !pstudiohdr )
- {
- Warning( "GetEyePosition() Can't get pstudiohdr ptr!\n" );
- return;
- }
-
- vecEyePosition = pstudiohdr->eyeposition();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Looks up an activity by name.
-// Input : label - Name of the activity to look up, ie "ACT_IDLE"
-// Output : Activity index or ACT_INVALID if not found.
-//-----------------------------------------------------------------------------
-int LookupActivity( CStudioHdr *pstudiohdr, const char *label )
-{
- VPROF( "LookupActivity" );
-
- if ( !pstudiohdr )
- {
- return 0;
- }
-
- for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
- {
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
- if ( stricmp( seqdesc.pszActivityName(), label ) == 0 )
- {
- return seqdesc.activity;
- }
- }
-
- return ACT_INVALID;
-}
-
-#if !defined( MAKEXVCD )
-//-----------------------------------------------------------------------------
-// Purpose: Looks up a sequence by sequence name first, then by activity name.
-// Input : label - The sequence name or activity name to look up.
-// Output : Returns the sequence index of the matching sequence, or ACT_INVALID.
-//-----------------------------------------------------------------------------
-int LookupSequence( CStudioHdr *pstudiohdr, const char *label )
-{
- VPROF( "LookupSequence" );
-
- if (! pstudiohdr)
- return 0;
-
- if (!pstudiohdr->SequencesAvailable())
- return 0;
-
- //
- // Look up by sequence name.
- //
- for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
- {
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
- if (stricmp( seqdesc.pszLabel(), label ) == 0)
- return i;
- }
-
- //
- // Not found, look up by activity name.
- //
- int nActivity = LookupActivity( pstudiohdr, label );
- if (nActivity != ACT_INVALID )
- {
- return SelectWeightedSequence( pstudiohdr, nActivity );
- }
-
- return ACT_INVALID;
-}
-
-void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec )
-{
- if (! pstudiohdr)
- {
- Msg( "Bad pstudiohdr in GetSequenceLinearMotion()!\n" );
- return;
- }
-
- if (!pstudiohdr->SequencesAvailable())
- return;
-
- if( iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
- {
- // Don't spam on bogus model
- if ( pstudiohdr->GetNumSeq() > 0 )
- {
- static int msgCount = 0;
- while ( ++msgCount <= 10 )
- {
- Msg( "Bad sequence (%i out of %i max) in GetSequenceLinearMotion() for model '%s'!\n", iSequence, pstudiohdr->GetNumSeq(), pstudiohdr->pszName() );
- }
- }
- pVec->Init();
- return;
- }
-
- QAngle vecAngles;
- Studio_SeqMovement( pstudiohdr, iSequence, 0, 1.0, poseParameter, (*pVec), vecAngles );
-}
-#endif
-
-const char *GetSequenceName( CStudioHdr *pstudiohdr, int iSequence )
-{
- if( !pstudiohdr || iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
- {
- if ( pstudiohdr )
- {
- Msg( "Bad sequence in GetSequenceName() for model '%s'!\n", pstudiohdr->pszName() );
- }
- return "Unknown";
- }
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
- return seqdesc.pszLabel();
-}
-
-const char *GetSequenceActivityName( CStudioHdr *pstudiohdr, int iSequence )
-{
- if( !pstudiohdr || iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
- {
- if ( pstudiohdr )
- {
- Msg( "Bad sequence in GetSequenceActivityName() for model '%s'!\n", pstudiohdr->pszName() );
- }
- return "Unknown";
- }
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
- return seqdesc.pszActivityName( );
-}
-
-int GetSequenceFlags( CStudioHdr *pstudiohdr, int sequence )
-{
- if ( !pstudiohdr ||
- !pstudiohdr->SequencesAvailable() ||
- sequence < 0 ||
- sequence >= pstudiohdr->GetNumSeq() )
- {
- return 0;
- }
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
-
- return seqdesc.flags;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pstudiohdr -
-// sequence -
-// type -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool HasAnimationEventOfType( CStudioHdr *pstudiohdr, int sequence, int type )
-{
- if ( !pstudiohdr || sequence >= pstudiohdr->GetNumSeq() )
- return false;
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
- if ( !&seqdesc )
- return false;
-
- mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
- if ( !pevent )
- return false;
-
- if (seqdesc.numevents == 0 )
- return false;
-
- int index;
- for ( index = 0; index < (int)seqdesc.numevents; index++ )
- {
- if ( pevent[ index ].event == type )
- {
- return true;
- }
- }
-
- return false;
-}
-
-int GetAnimationEvent( CStudioHdr *pstudiohdr, int sequence, animevent_t *pNPCEvent, float flStart, float flEnd, int index )
-{
- if ( !pstudiohdr || sequence >= pstudiohdr->GetNumSeq() || !pNPCEvent )
- return 0;
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
- if (seqdesc.numevents == 0 || index >= (int)seqdesc.numevents )
- return 0;
-
- // Msg( "flStart %f flEnd %f (%d) %s\n", flStart, flEnd, seqdesc.numevents, seqdesc.label );
- mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
- for (; index < (int)seqdesc.numevents; index++)
- {
- // Don't send client-side events to the server AI
- if ( pevent[index].type & AE_TYPE_NEWEVENTSYSTEM )
- {
- if ( !(pevent[index].type & AE_TYPE_SERVER) )
- continue;
- }
- else if ( pevent[index].event >= EVENT_CLIENT ) //Adrian - Support the old event system
- continue;
-
- bool bOverlapEvent = false;
-
- if (pevent[index].cycle >= flStart && pevent[index].cycle < flEnd)
- {
- bOverlapEvent = true;
- }
- // FIXME: doesn't work with animations being played in reverse
- else if ((seqdesc.flags & STUDIO_LOOPING) && flEnd < flStart)
- {
- if (pevent[index].cycle >= flStart || pevent[index].cycle < flEnd)
- {
- bOverlapEvent = true;
- }
- }
-
- if (bOverlapEvent)
- {
- pNPCEvent->pSource = NULL;
- pNPCEvent->cycle = pevent[index].cycle;
-#if !defined( MAKEXVCD )
- pNPCEvent->eventtime = gpGlobals->curtime;
-#else
- pNPCEvent->eventtime = 0.0f;
-#endif
- pNPCEvent->event = pevent[index].event;
- pNPCEvent->options = pevent[index].pszOptions();
- pNPCEvent->type = pevent[index].type;
- return index + 1;
- }
- }
- return 0;
-}
-
-
-
-int FindTransitionSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, int iGoalSequence, int *piDir )
-{
- if ( !pstudiohdr )
- return iGoalSequence;
-
- if ( !pstudiohdr->SequencesAvailable() )
- return iGoalSequence;
-
- if ( ( iCurrentSequence < 0 ) || ( iCurrentSequence >= pstudiohdr->GetNumSeq() ) )
- return iGoalSequence;
-
- if ( ( iGoalSequence < 0 ) || ( iGoalSequence >= pstudiohdr->GetNumSeq() ) )
- {
- // asking for a bogus sequence. Punt.
- Assert( 0 );
- return iGoalSequence;
- }
-
-
- // bail if we're going to or from a node 0
- if (pstudiohdr->EntryNode( iCurrentSequence ) == 0 || pstudiohdr->EntryNode( iGoalSequence ) == 0)
- {
- *piDir = 1;
- return iGoalSequence;
- }
-
- int iEndNode;
-
- // Msg( "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
-
- // check to see if we should be going forward or backward through the graph
- if (*piDir > 0)
- {
- iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
- }
- else
- {
- iEndNode = pstudiohdr->EntryNode( iCurrentSequence );
- }
-
- // if both sequences are on the same node, just go there
- if (iEndNode == pstudiohdr->EntryNode( iGoalSequence ))
- {
- *piDir = 1;
- return iGoalSequence;
- }
-
- int iInternNode = pstudiohdr->GetTransition( iEndNode, pstudiohdr->EntryNode( iGoalSequence ) );
-
- // if there is no transitionial node, just go to the goal sequence
- if (iInternNode == 0)
- return iGoalSequence;
-
- int i;
-
- // look for someone going from the entry node to next node it should hit
- // this may be the goal sequences node or an intermediate node
- for (i = 0; i < pstudiohdr->GetNumSeq(); i++)
- {
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc(i );
- if (pstudiohdr->EntryNode( i ) == iEndNode && pstudiohdr->ExitNode( i ) == iInternNode)
- {
- *piDir = 1;
- return i;
- }
- if (seqdesc.nodeflags)
- {
- if (pstudiohdr->ExitNode( i ) == iEndNode && pstudiohdr->EntryNode( i ) == iInternNode)
- {
- *piDir = -1;
- return i;
- }
- }
- }
-
- // this means that two parts of the node graph are not connected.
- DevMsg( 2, "error in transition graph: %s to %s\n", pstudiohdr->pszNodeName( iEndNode ), pstudiohdr->pszNodeName( pstudiohdr->EntryNode( iGoalSequence ) ));
- // Go ahead and jump to the goal sequence
- return iGoalSequence;
-}
-
-
-
-
-
-
-bool GotoSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &nNextSequence, float &flNextCycle, int &iNextDir )
-{
- if ( !pstudiohdr )
- return false;
-
- if ( !pstudiohdr->SequencesAvailable() )
- return false;
-
- if ( ( iCurrentSequence < 0 ) || ( iCurrentSequence >= pstudiohdr->GetNumSeq() ) )
- return false;
-
- if ( ( iGoalSequence < 0 ) || ( iGoalSequence >= pstudiohdr->GetNumSeq() ) )
- {
- // asking for a bogus sequence. Punt.
- Assert( 0 );
- return false;
- }
-
- // bail if we're going to or from a node 0
- if (pstudiohdr->EntryNode( iCurrentSequence ) == 0 || pstudiohdr->EntryNode( iGoalSequence ) == 0)
- {
- iNextDir = 1;
- flNextCycle = 0.0;
- nNextSequence = iGoalSequence;
- return true;
- }
-
- int iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
- // Msg( "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
-
- // if we're in a transition sequence
- if (pstudiohdr->EntryNode( iCurrentSequence ) != pstudiohdr->ExitNode( iCurrentSequence ))
- {
- // are we done with it?
- if (flCurrentRate > 0.0 && flCurrentCycle >= 0.999)
- {
- iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
- }
- else if (flCurrentRate < 0.0 && flCurrentCycle <= 0.001)
- {
- iEndNode = pstudiohdr->EntryNode( iCurrentSequence );
- }
- else
- {
- // nope, exit
- return false;
- }
- }
-
- // if both sequences are on the same node, just go there
- if (iEndNode == pstudiohdr->EntryNode( iGoalSequence ))
- {
- iNextDir = 1;
- flNextCycle = 0.0;
- nNextSequence = iGoalSequence;
- return true;
- }
-
- int iInternNode = pstudiohdr->GetTransition( iEndNode, pstudiohdr->EntryNode( iGoalSequence ) );
-
- // if there is no transitionial node, just go to the goal sequence
- if (iInternNode == 0)
- {
- iNextDir = 1;
- flNextCycle = 0.0;
- nNextSequence = iGoalSequence;
- return true;
- }
-
- int i;
-
- // look for someone going from the entry node to next node it should hit
- // this may be the goal sequences node or an intermediate node
- for (i = 0; i < pstudiohdr->GetNumSeq(); i++)
- {
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc(i );
- if (pstudiohdr->EntryNode( i ) == iEndNode && pstudiohdr->ExitNode( i ) == iInternNode)
- {
- iNextDir = 1;
- flNextCycle = 0.0;
- nNextSequence = i;
- return true;
- }
- if (seqdesc.nodeflags)
- {
- if (pstudiohdr->ExitNode( i ) == iEndNode && pstudiohdr->EntryNode( i ) == iInternNode)
- {
- iNextDir = -1;
- flNextCycle = 0.999;
- nNextSequence = i;
- return true;
- }
- }
- }
-
- // this means that two parts of the node graph are not connected.
- DevMsg( 2, "error in transition graph: %s to %s\n", pstudiohdr->pszNodeName( iEndNode ), pstudiohdr->pszNodeName( pstudiohdr->EntryNode( iGoalSequence ) ));
- return false;
-}
-
-void SetBodygroup( CStudioHdr *pstudiohdr, int& body, int iGroup, int iValue )
-{
- if (! pstudiohdr)
- return;
-
- if (iGroup >= pstudiohdr->numbodyparts())
- return;
-
- mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
-
- if (iValue >= pbodypart->nummodels)
- return;
-
- int iCurrent = (body / pbodypart->base) % pbodypart->nummodels;
-
- body = (body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base));
-}
-
-
-int GetBodygroup( CStudioHdr *pstudiohdr, int body, int iGroup )
-{
- if (! pstudiohdr)
- return 0;
-
- if (iGroup >= pstudiohdr->numbodyparts())
- return 0;
-
- mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
-
- if (pbodypart->nummodels <= 1)
- return 0;
-
- int iCurrent = (body / pbodypart->base) % pbodypart->nummodels;
-
- return iCurrent;
-}
-
-const char *GetBodygroupName( CStudioHdr *pstudiohdr, int iGroup )
-{
- if ( !pstudiohdr)
- return "";
-
- if (iGroup >= pstudiohdr->numbodyparts())
- return "";
-
- mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
- return pbodypart->pszName();
-}
-
-int FindBodygroupByName( CStudioHdr *pstudiohdr, const char *name )
-{
- if ( !pstudiohdr )
- return -1;
-
- int group;
- for ( group = 0; group < pstudiohdr->numbodyparts(); group++ )
- {
- mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( group );
- if ( !Q_strcasecmp( name, pbodypart->pszName() ) )
- {
- return group;
- }
- }
-
- return -1;
-}
-
-int GetBodygroupCount( CStudioHdr *pstudiohdr, int iGroup )
-{
- if ( !pstudiohdr )
- return 0;
-
- if (iGroup >= pstudiohdr->numbodyparts())
- return 0;
-
- mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
- return pbodypart->nummodels;
-}
-
-int GetNumBodyGroups( CStudioHdr *pstudiohdr )
-{
- if ( !pstudiohdr )
- return 0;
-
- return pstudiohdr->numbodyparts();
-}
-
-int GetSequenceActivity( CStudioHdr *pstudiohdr, int sequence, int *pweight )
-{
- if (!pstudiohdr || !pstudiohdr->SequencesAvailable() )
- {
- if (pweight)
- *pweight = 0;
- return 0;
- }
-
- mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
-
- if (!(seqdesc.flags & STUDIO_ACTIVITY))
- {
- SetActivityForSequence( pstudiohdr, sequence );
- }
- if (pweight)
- *pweight = seqdesc.actweight;
- return seqdesc.activity;
-}
-
-
-void GetAttachmentLocalSpace( CStudioHdr *pstudiohdr, int attachIndex, matrix3x4_t &pLocalToWorld )
-{
- if ( attachIndex >= 0 )
- {
- const mstudioattachment_t &pAttachment = pstudiohdr->pAttachment(attachIndex);
- MatrixCopy( pAttachment.local, pLocalToWorld );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pstudiohdr -
-// *name -
-// Output : int
-//-----------------------------------------------------------------------------
-int FindHitboxSetByName( CStudioHdr *pstudiohdr, const char *name )
-{
- if ( !pstudiohdr )
- return -1;
-
- for ( int i = 0; i < pstudiohdr->numhitboxsets(); i++ )
- {
- mstudiohitboxset_t *set = pstudiohdr->pHitboxSet( i );
- if ( !set )
- continue;
-
- if ( !stricmp( set->pszName(), name ) )
- return i;
- }
-
- return -1;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pstudiohdr -
-// setnumber -
-// Output : char const
-//-----------------------------------------------------------------------------
-const char *GetHitboxSetName( CStudioHdr *pstudiohdr, int setnumber )
-{
- if ( !pstudiohdr )
- return "";
-
- mstudiohitboxset_t *set = pstudiohdr->pHitboxSet( setnumber );
- if ( !set )
- return "";
-
- return set->pszName();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pstudiohdr -
-// Output : int
-//-----------------------------------------------------------------------------
-int GetHitboxSetCount( CStudioHdr *pstudiohdr )
-{
- if ( !pstudiohdr )
- return 0;
-
- return pstudiohdr->numhitboxsets();
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "studio.h"
+#include "activitylist.h"
+#include "engine/IEngineSound.h"
+#include "ai_activity.h"
+#include "animation.h"
+#include "bone_setup.h"
+#include "scriptevent.h"
+#include "npcevent.h"
+#include "eventlist.h"
+#include "tier0/vprof.h"
+
+#if !defined( CLIENT_DLL ) && !defined( MAKEXVCD )
+#include "util.h"
+#include "enginecallback.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#pragma warning( disable : 4244 )
+#define iabs(i) (( (i) >= 0 ) ? (i) : -(i) )
+
+int ExtractBbox( CStudioHdr *pstudiohdr, int sequence, Vector& mins, Vector& maxs )
+{
+ if (! pstudiohdr)
+ return 0;
+
+ if (!pstudiohdr->SequencesAvailable())
+ return 0;
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+
+ mins = seqdesc.bbmin;
+
+ maxs = seqdesc.bbmax;
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+// Input : *pstudiohdr -
+// iSequence -
+//
+// Output : mstudioseqdesc_t
+//-----------------------------------------------------------------------------
+
+extern int g_nActivityListVersion;
+extern int g_nEventListVersion;
+
+void SetEventIndexForSequence( mstudioseqdesc_t &seqdesc )
+{
+ if ( &seqdesc == NULL )
+ return;
+
+ seqdesc.flags |= STUDIO_EVENT;
+
+ if ( seqdesc.numevents == 0 )
+ return;
+
+ for ( int index = 0; index < (int)seqdesc.numevents; index++ )
+ {
+ mstudioevent_t *pevent = seqdesc.pEvent( index );
+
+ if ( !pevent )
+ continue;
+
+ if ( pevent->type & AE_TYPE_NEWEVENTSYSTEM )
+ {
+ const char *pEventName = pevent->pszEventName();
+
+ int iEventIndex = EventList_IndexForName( pEventName );
+
+ if ( iEventIndex == -1 )
+ {
+ pevent->event = EventList_RegisterPrivateEvent( pEventName );
+ }
+ else
+ {
+ pevent->event = iEventIndex;
+ pevent->type |= EventList_GetEventType( iEventIndex );
+ }
+ }
+ }
+}
+
+mstudioevent_t *GetEventIndexForSequence( mstudioseqdesc_t &seqdesc )
+{
+ if (!(seqdesc.flags & STUDIO_EVENT))
+ {
+ SetEventIndexForSequence( seqdesc );
+ }
+
+ return seqdesc.pEvent( 0 );
+}
+
+
+void BuildAllAnimationEventIndexes( CStudioHdr *pstudiohdr )
+{
+ if ( !pstudiohdr )
+ return;
+
+ if( pstudiohdr->GetEventListVersion() != g_nEventListVersion )
+ {
+ for ( int i = 0 ; i < pstudiohdr->GetNumSeq() ; i++ )
+ {
+ SetEventIndexForSequence( pstudiohdr->pSeqdesc( i ) );
+ }
+
+ pstudiohdr->SetEventListVersion( g_nEventListVersion );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Ensures that activity / index relationship is recalculated
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void ResetEventIndexes( CStudioHdr *pstudiohdr )
+{
+ if (! pstudiohdr)
+ return;
+
+ pstudiohdr->SetEventListVersion( g_nEventListVersion - 1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void SetActivityForSequence( CStudioHdr *pstudiohdr, int i )
+{
+ int iActivityIndex;
+ const char *pszActivityName;
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
+
+ seqdesc.flags |= STUDIO_ACTIVITY;
+
+ pszActivityName = GetSequenceActivityName( pstudiohdr, i );
+ if ( pszActivityName[0] != '\0' )
+ {
+ iActivityIndex = ActivityList_IndexForName( pszActivityName );
+
+ if ( iActivityIndex == -1 )
+ {
+ // Allow this now. Animators can create custom activities that are referenced only on the client or by scripts, etc.
+ //Warning( "***\nModel %s tried to reference unregistered activity: %s \n***\n", pstudiohdr->name, pszActivityName );
+ //Assert(0);
+ // HACK: the client and server don't share the private activity list so registering it on the client would hose the server
+#ifdef CLIENT_DLL
+ seqdesc.flags &= ~STUDIO_ACTIVITY;
+#else
+ seqdesc.activity = ActivityList_RegisterPrivateActivity( pszActivityName );
+#endif
+ }
+ else
+ {
+ seqdesc.activity = iActivityIndex;
+ }
+ }
+}
+
+//=========================================================
+// IndexModelSequences - set activity and event indexes for all model
+// sequences that have them.
+//=========================================================
+
+void IndexModelSequences( CStudioHdr *pstudiohdr )
+{
+ int i;
+
+ if (! pstudiohdr)
+ return;
+
+ if (!pstudiohdr->SequencesAvailable())
+ return;
+
+ for ( i = 0 ; i < pstudiohdr->GetNumSeq() ; i++ )
+ {
+ SetActivityForSequence( pstudiohdr, i );
+ SetEventIndexForSequence( pstudiohdr->pSeqdesc( i ) );
+ }
+
+ pstudiohdr->SetActivityListVersion( g_nActivityListVersion );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Ensures that activity / index relationship is recalculated
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void ResetActivityIndexes( CStudioHdr *pstudiohdr )
+{
+ if (! pstudiohdr)
+ return;
+
+ pstudiohdr->SetActivityListVersion( g_nActivityListVersion - 1 );
+}
+
+void VerifySequenceIndex( CStudioHdr *pstudiohdr )
+{
+ if ( !pstudiohdr )
+ {
+ return;
+ }
+
+ if( pstudiohdr->GetActivityListVersion( ) != g_nActivityListVersion )
+ {
+ // this model's sequences have not yet been indexed by activity
+ IndexModelSequences( pstudiohdr );
+ }
+}
+
+#if !defined( MAKEXVCD )
+bool IsInPrediction()
+{
+ return CBaseEntity::GetPredictionPlayer() != NULL;
+}
+
+int SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence )
+{
+ VPROF( "SelectWeightedSequence" );
+
+ if (! pstudiohdr)
+ return 0;
+
+ if (!pstudiohdr->SequencesAvailable())
+ return 0;
+
+ VerifySequenceIndex( pstudiohdr );
+
+#if STUDIO_SEQUENCE_ACTIVITY_LOOKUPS_ARE_SLOW
+ int weighttotal = 0;
+ int seq = ACTIVITY_NOT_AVAILABLE;
+ int weight = 0;
+ for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
+ {
+ int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
+ if (curActivity == activity)
+ {
+ if ( curSequence == i && weight < 0 )
+ {
+ seq = i;
+ break;
+ }
+ weighttotal += iabs(weight);
+
+ int randomValue;
+
+ if ( IsInPrediction() )
+ randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1, i );
+ else
+ randomValue = RandomInt( 0, weighttotal - 1 );
+
+ if (!weighttotal || randomValue < iabs(weight))
+ seq = i;
+ }
+ }
+
+ return seq;
+#else
+ return pstudiohdr->SelectWeightedSequence( activity, curSequence );
+#endif
+}
+
+
+// Pick a sequence for the given activity. If the current sequence is appropriate for the
+// current activity, and its stored weight is negative (whatever that means), always select
+// it. Otherwise perform a weighted selection -- imagine a large roulette wheel, with each
+// sequence having a number of spaces corresponding to its weight.
+int CStudioHdr::CActivityToSequenceMapping::SelectWeightedSequence( CStudioHdr *pstudiohdr, int activity, int curSequence )
+{
+ if (!ValidateAgainst(pstudiohdr))
+ {
+ AssertMsg1(false, "CStudioHdr %s has changed its vmodel pointer without reinitializing its activity mapping! Now performing emergency reinitialization.", pstudiohdr->pszName());
+ ExecuteOnce(DebuggerBreakIfDebugging());
+ Reinitialize(pstudiohdr);
+ }
+
+ // a null m_pSequenceTuples just means that this studio header has no activities.
+ if (!m_pSequenceTuples)
+ return ACTIVITY_NOT_AVAILABLE;
+
+ // is the current sequence appropriate?
+ if (curSequence >= 0)
+ {
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( curSequence );
+
+ if (seqdesc.activity == activity && seqdesc.actweight < 0)
+ return curSequence;
+ }
+
+ // get the data for the given activity
+ HashValueType dummy( activity, 0, 0, 0 );
+ UtlHashHandle_t handle = m_ActToSeqHash.Find(dummy);
+ if (!m_ActToSeqHash.IsValidHandle(handle))
+ {
+ return ACTIVITY_NOT_AVAILABLE;
+ }
+ const HashValueType * __restrict actData = &m_ActToSeqHash[handle];
+
+ int weighttotal = actData->totalWeight;
+ // generate a random number from 0 to the total weight
+ int randomValue;
+ if ( IsInPrediction() )
+ {
+ randomValue = SharedRandomInt( "SelectWeightedSequence", 0, weighttotal - 1 );
+ }
+ else
+ {
+ randomValue = RandomInt( 0, weighttotal - 1 );
+ }
+
+ // chug through the entries in the list (they are sequential therefore cache-coherent)
+ // until we run out of random juice
+ SequenceTuple * __restrict sequenceInfo = m_pSequenceTuples + actData->startingIdx;
+
+ const SequenceTuple *const stopHere = sequenceInfo + actData->count; // this is a backup
+ // in case the weights are somehow miscalculated -- we don't read or write through
+ // it (because it aliases the restricted pointer above); it's only here for
+ // the comparison.
+
+ while (randomValue >= sequenceInfo->weight && sequenceInfo < stopHere)
+ {
+ randomValue -= sequenceInfo->weight;
+ ++sequenceInfo;
+ }
+
+ return sequenceInfo->seqnum;
+
+}
+
+
+#endif
+
+int SelectHeaviestSequence( CStudioHdr *pstudiohdr, int activity )
+{
+ if ( !pstudiohdr )
+ return 0;
+
+ VerifySequenceIndex( pstudiohdr );
+
+ int maxweight = 0;
+ int seq = ACTIVITY_NOT_AVAILABLE;
+ int weight = 0;
+ for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
+ {
+ int curActivity = GetSequenceActivity( pstudiohdr, i, &weight );
+ if (curActivity == activity)
+ {
+ if ( iabs(weight) > maxweight )
+ {
+ maxweight = iabs(weight);
+ seq = i;
+ }
+ }
+ }
+
+ return seq;
+}
+
+void GetEyePosition ( CStudioHdr *pstudiohdr, Vector &vecEyePosition )
+{
+ if ( !pstudiohdr )
+ {
+ Warning( "GetEyePosition() Can't get pstudiohdr ptr!\n" );
+ return;
+ }
+
+ vecEyePosition = pstudiohdr->eyeposition();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Looks up an activity by name.
+// Input : label - Name of the activity to look up, ie "ACT_IDLE"
+// Output : Activity index or ACT_INVALID if not found.
+//-----------------------------------------------------------------------------
+int LookupActivity( CStudioHdr *pstudiohdr, const char *label )
+{
+ VPROF( "LookupActivity" );
+
+ if ( !pstudiohdr )
+ {
+ return 0;
+ }
+
+ for ( int i = 0; i < pstudiohdr->GetNumSeq(); i++ )
+ {
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
+ if ( stricmp( seqdesc.pszActivityName(), label ) == 0 )
+ {
+ return seqdesc.activity;
+ }
+ }
+
+ return ACT_INVALID;
+}
+
+#if !defined( MAKEXVCD )
+//-----------------------------------------------------------------------------
+// Purpose: Looks up a sequence by sequence name first, then by activity name.
+// Input : label - The sequence name or activity name to look up.
+// Output : Returns the sequence index of the matching sequence, or ACT_INVALID.
+//-----------------------------------------------------------------------------
+int LookupSequence( CStudioHdr *pstudiohdr, const char *label )
+{
+ VPROF( "LookupSequence" );
+
+ if (! pstudiohdr)
+ return 0;
+
+ if (!pstudiohdr->SequencesAvailable())
+ return 0;
+
+ //
+ // Look up by sequence name.
+ //
+ for (int i = 0; i < pstudiohdr->GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( i );
+ if (stricmp( seqdesc.pszLabel(), label ) == 0)
+ return i;
+ }
+
+ //
+ // Not found, look up by activity name.
+ //
+ int nActivity = LookupActivity( pstudiohdr, label );
+ if (nActivity != ACT_INVALID )
+ {
+ return SelectWeightedSequence( pstudiohdr, nActivity );
+ }
+
+ return ACT_INVALID;
+}
+
+void GetSequenceLinearMotion( CStudioHdr *pstudiohdr, int iSequence, const float poseParameter[], Vector *pVec )
+{
+ if (! pstudiohdr)
+ {
+ Msg( "Bad pstudiohdr in GetSequenceLinearMotion()!\n" );
+ return;
+ }
+
+ if (!pstudiohdr->SequencesAvailable())
+ return;
+
+ if( iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
+ {
+ // Don't spam on bogus model
+ if ( pstudiohdr->GetNumSeq() > 0 )
+ {
+ static int msgCount = 0;
+ while ( ++msgCount <= 10 )
+ {
+ Msg( "Bad sequence (%i out of %i max) in GetSequenceLinearMotion() for model '%s'!\n", iSequence, pstudiohdr->GetNumSeq(), pstudiohdr->pszName() );
+ }
+ }
+ pVec->Init();
+ return;
+ }
+
+ QAngle vecAngles;
+ Studio_SeqMovement( pstudiohdr, iSequence, 0, 1.0, poseParameter, (*pVec), vecAngles );
+}
+#endif
+
+const char *GetSequenceName( CStudioHdr *pstudiohdr, int iSequence )
+{
+ if( !pstudiohdr || iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
+ {
+ if ( pstudiohdr )
+ {
+ Msg( "Bad sequence in GetSequenceName() for model '%s'!\n", pstudiohdr->pszName() );
+ }
+ return "Unknown";
+ }
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
+ return seqdesc.pszLabel();
+}
+
+const char *GetSequenceActivityName( CStudioHdr *pstudiohdr, int iSequence )
+{
+ if( !pstudiohdr || iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq() )
+ {
+ if ( pstudiohdr )
+ {
+ Msg( "Bad sequence in GetSequenceActivityName() for model '%s'!\n", pstudiohdr->pszName() );
+ }
+ return "Unknown";
+ }
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
+ return seqdesc.pszActivityName( );
+}
+
+int GetSequenceFlags( CStudioHdr *pstudiohdr, int sequence )
+{
+ if ( !pstudiohdr ||
+ !pstudiohdr->SequencesAvailable() ||
+ sequence < 0 ||
+ sequence >= pstudiohdr->GetNumSeq() )
+ {
+ return 0;
+ }
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+
+ return seqdesc.flags;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pstudiohdr -
+// sequence -
+// type -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool HasAnimationEventOfType( CStudioHdr *pstudiohdr, int sequence, int type )
+{
+ if ( !pstudiohdr || sequence >= pstudiohdr->GetNumSeq() )
+ return false;
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+ if ( !&seqdesc )
+ return false;
+
+ mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
+ if ( !pevent )
+ return false;
+
+ if (seqdesc.numevents == 0 )
+ return false;
+
+ int index;
+ for ( index = 0; index < (int)seqdesc.numevents; index++ )
+ {
+ if ( pevent[ index ].event == type )
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+int GetAnimationEvent( CStudioHdr *pstudiohdr, int sequence, animevent_t *pNPCEvent, float flStart, float flEnd, int index )
+{
+ if ( !pstudiohdr || sequence >= pstudiohdr->GetNumSeq() || !pNPCEvent )
+ return 0;
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+ if (seqdesc.numevents == 0 || index >= (int)seqdesc.numevents )
+ return 0;
+
+ // Msg( "flStart %f flEnd %f (%d) %s\n", flStart, flEnd, seqdesc.numevents, seqdesc.label );
+ mstudioevent_t *pevent = GetEventIndexForSequence( seqdesc );
+ for (; index < (int)seqdesc.numevents; index++)
+ {
+ // Don't send client-side events to the server AI
+ if ( pevent[index].type & AE_TYPE_NEWEVENTSYSTEM )
+ {
+ if ( !(pevent[index].type & AE_TYPE_SERVER) )
+ continue;
+ }
+ else if ( pevent[index].event >= EVENT_CLIENT ) //Adrian - Support the old event system
+ continue;
+
+ bool bOverlapEvent = false;
+
+ if (pevent[index].cycle >= flStart && pevent[index].cycle < flEnd)
+ {
+ bOverlapEvent = true;
+ }
+ // FIXME: doesn't work with animations being played in reverse
+ else if ((seqdesc.flags & STUDIO_LOOPING) && flEnd < flStart)
+ {
+ if (pevent[index].cycle >= flStart || pevent[index].cycle < flEnd)
+ {
+ bOverlapEvent = true;
+ }
+ }
+
+ if (bOverlapEvent)
+ {
+ pNPCEvent->pSource = NULL;
+ pNPCEvent->cycle = pevent[index].cycle;
+#if !defined( MAKEXVCD )
+ pNPCEvent->eventtime = gpGlobals->curtime;
+#else
+ pNPCEvent->eventtime = 0.0f;
+#endif
+ pNPCEvent->event = pevent[index].event;
+ pNPCEvent->options = pevent[index].pszOptions();
+ pNPCEvent->type = pevent[index].type;
+ return index + 1;
+ }
+ }
+ return 0;
+}
+
+
+
+int FindTransitionSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, int iGoalSequence, int *piDir )
+{
+ if ( !pstudiohdr )
+ return iGoalSequence;
+
+ if ( !pstudiohdr->SequencesAvailable() )
+ return iGoalSequence;
+
+ if ( ( iCurrentSequence < 0 ) || ( iCurrentSequence >= pstudiohdr->GetNumSeq() ) )
+ return iGoalSequence;
+
+ if ( ( iGoalSequence < 0 ) || ( iGoalSequence >= pstudiohdr->GetNumSeq() ) )
+ {
+ // asking for a bogus sequence. Punt.
+ Assert( 0 );
+ return iGoalSequence;
+ }
+
+
+ // bail if we're going to or from a node 0
+ if (pstudiohdr->EntryNode( iCurrentSequence ) == 0 || pstudiohdr->EntryNode( iGoalSequence ) == 0)
+ {
+ *piDir = 1;
+ return iGoalSequence;
+ }
+
+ int iEndNode;
+
+ // Msg( "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
+
+ // check to see if we should be going forward or backward through the graph
+ if (*piDir > 0)
+ {
+ iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
+ }
+ else
+ {
+ iEndNode = pstudiohdr->EntryNode( iCurrentSequence );
+ }
+
+ // if both sequences are on the same node, just go there
+ if (iEndNode == pstudiohdr->EntryNode( iGoalSequence ))
+ {
+ *piDir = 1;
+ return iGoalSequence;
+ }
+
+ int iInternNode = pstudiohdr->GetTransition( iEndNode, pstudiohdr->EntryNode( iGoalSequence ) );
+
+ // if there is no transitionial node, just go to the goal sequence
+ if (iInternNode == 0)
+ return iGoalSequence;
+
+ int i;
+
+ // look for someone going from the entry node to next node it should hit
+ // this may be the goal sequences node or an intermediate node
+ for (i = 0; i < pstudiohdr->GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc(i );
+ if (pstudiohdr->EntryNode( i ) == iEndNode && pstudiohdr->ExitNode( i ) == iInternNode)
+ {
+ *piDir = 1;
+ return i;
+ }
+ if (seqdesc.nodeflags)
+ {
+ if (pstudiohdr->ExitNode( i ) == iEndNode && pstudiohdr->EntryNode( i ) == iInternNode)
+ {
+ *piDir = -1;
+ return i;
+ }
+ }
+ }
+
+ // this means that two parts of the node graph are not connected.
+ DevMsg( 2, "error in transition graph: %s to %s\n", pstudiohdr->pszNodeName( iEndNode ), pstudiohdr->pszNodeName( pstudiohdr->EntryNode( iGoalSequence ) ));
+ // Go ahead and jump to the goal sequence
+ return iGoalSequence;
+}
+
+
+
+
+
+
+bool GotoSequence( CStudioHdr *pstudiohdr, int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &nNextSequence, float &flNextCycle, int &iNextDir )
+{
+ if ( !pstudiohdr )
+ return false;
+
+ if ( !pstudiohdr->SequencesAvailable() )
+ return false;
+
+ if ( ( iCurrentSequence < 0 ) || ( iCurrentSequence >= pstudiohdr->GetNumSeq() ) )
+ return false;
+
+ if ( ( iGoalSequence < 0 ) || ( iGoalSequence >= pstudiohdr->GetNumSeq() ) )
+ {
+ // asking for a bogus sequence. Punt.
+ Assert( 0 );
+ return false;
+ }
+
+ // bail if we're going to or from a node 0
+ if (pstudiohdr->EntryNode( iCurrentSequence ) == 0 || pstudiohdr->EntryNode( iGoalSequence ) == 0)
+ {
+ iNextDir = 1;
+ flNextCycle = 0.0;
+ nNextSequence = iGoalSequence;
+ return true;
+ }
+
+ int iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
+ // Msg( "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
+
+ // if we're in a transition sequence
+ if (pstudiohdr->EntryNode( iCurrentSequence ) != pstudiohdr->ExitNode( iCurrentSequence ))
+ {
+ // are we done with it?
+ if (flCurrentRate > 0.0 && flCurrentCycle >= 0.999)
+ {
+ iEndNode = pstudiohdr->ExitNode( iCurrentSequence );
+ }
+ else if (flCurrentRate < 0.0 && flCurrentCycle <= 0.001)
+ {
+ iEndNode = pstudiohdr->EntryNode( iCurrentSequence );
+ }
+ else
+ {
+ // nope, exit
+ return false;
+ }
+ }
+
+ // if both sequences are on the same node, just go there
+ if (iEndNode == pstudiohdr->EntryNode( iGoalSequence ))
+ {
+ iNextDir = 1;
+ flNextCycle = 0.0;
+ nNextSequence = iGoalSequence;
+ return true;
+ }
+
+ int iInternNode = pstudiohdr->GetTransition( iEndNode, pstudiohdr->EntryNode( iGoalSequence ) );
+
+ // if there is no transitionial node, just go to the goal sequence
+ if (iInternNode == 0)
+ {
+ iNextDir = 1;
+ flNextCycle = 0.0;
+ nNextSequence = iGoalSequence;
+ return true;
+ }
+
+ int i;
+
+ // look for someone going from the entry node to next node it should hit
+ // this may be the goal sequences node or an intermediate node
+ for (i = 0; i < pstudiohdr->GetNumSeq(); i++)
+ {
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc(i );
+ if (pstudiohdr->EntryNode( i ) == iEndNode && pstudiohdr->ExitNode( i ) == iInternNode)
+ {
+ iNextDir = 1;
+ flNextCycle = 0.0;
+ nNextSequence = i;
+ return true;
+ }
+ if (seqdesc.nodeflags)
+ {
+ if (pstudiohdr->ExitNode( i ) == iEndNode && pstudiohdr->EntryNode( i ) == iInternNode)
+ {
+ iNextDir = -1;
+ flNextCycle = 0.999;
+ nNextSequence = i;
+ return true;
+ }
+ }
+ }
+
+ // this means that two parts of the node graph are not connected.
+ DevMsg( 2, "error in transition graph: %s to %s\n", pstudiohdr->pszNodeName( iEndNode ), pstudiohdr->pszNodeName( pstudiohdr->EntryNode( iGoalSequence ) ));
+ return false;
+}
+
+void SetBodygroup( CStudioHdr *pstudiohdr, int& body, int iGroup, int iValue )
+{
+ if (! pstudiohdr)
+ return;
+
+ if (iGroup >= pstudiohdr->numbodyparts())
+ return;
+
+ mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
+
+ if (iValue >= pbodypart->nummodels)
+ return;
+
+ int iCurrent = (body / pbodypart->base) % pbodypart->nummodels;
+
+ body = (body - (iCurrent * pbodypart->base) + (iValue * pbodypart->base));
+}
+
+
+int GetBodygroup( CStudioHdr *pstudiohdr, int body, int iGroup )
+{
+ if (! pstudiohdr)
+ return 0;
+
+ if (iGroup >= pstudiohdr->numbodyparts())
+ return 0;
+
+ mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
+
+ if (pbodypart->nummodels <= 1)
+ return 0;
+
+ int iCurrent = (body / pbodypart->base) % pbodypart->nummodels;
+
+ return iCurrent;
+}
+
+const char *GetBodygroupName( CStudioHdr *pstudiohdr, int iGroup )
+{
+ if ( !pstudiohdr)
+ return "";
+
+ if (iGroup >= pstudiohdr->numbodyparts())
+ return "";
+
+ mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
+ return pbodypart->pszName();
+}
+
+int FindBodygroupByName( CStudioHdr *pstudiohdr, const char *name )
+{
+ if ( !pstudiohdr )
+ return -1;
+
+ int group;
+ for ( group = 0; group < pstudiohdr->numbodyparts(); group++ )
+ {
+ mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( group );
+ if ( !Q_strcasecmp( name, pbodypart->pszName() ) )
+ {
+ return group;
+ }
+ }
+
+ return -1;
+}
+
+int GetBodygroupCount( CStudioHdr *pstudiohdr, int iGroup )
+{
+ if ( !pstudiohdr )
+ return 0;
+
+ if (iGroup >= pstudiohdr->numbodyparts())
+ return 0;
+
+ mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
+ return pbodypart->nummodels;
+}
+
+int GetNumBodyGroups( CStudioHdr *pstudiohdr )
+{
+ if ( !pstudiohdr )
+ return 0;
+
+ return pstudiohdr->numbodyparts();
+}
+
+int GetSequenceActivity( CStudioHdr *pstudiohdr, int sequence, int *pweight )
+{
+ if (!pstudiohdr || !pstudiohdr->SequencesAvailable() )
+ {
+ if (pweight)
+ *pweight = 0;
+ return 0;
+ }
+
+ mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( sequence );
+
+ if (!(seqdesc.flags & STUDIO_ACTIVITY))
+ {
+ SetActivityForSequence( pstudiohdr, sequence );
+ }
+ if (pweight)
+ *pweight = seqdesc.actweight;
+ return seqdesc.activity;
+}
+
+
+void GetAttachmentLocalSpace( CStudioHdr *pstudiohdr, int attachIndex, matrix3x4_t &pLocalToWorld )
+{
+ if ( attachIndex >= 0 )
+ {
+ const mstudioattachment_t &pAttachment = pstudiohdr->pAttachment(attachIndex);
+ MatrixCopy( pAttachment.local, pLocalToWorld );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pstudiohdr -
+// *name -
+// Output : int
+//-----------------------------------------------------------------------------
+int FindHitboxSetByName( CStudioHdr *pstudiohdr, const char *name )
+{
+ if ( !pstudiohdr )
+ return -1;
+
+ for ( int i = 0; i < pstudiohdr->numhitboxsets(); i++ )
+ {
+ mstudiohitboxset_t *set = pstudiohdr->pHitboxSet( i );
+ if ( !set )
+ continue;
+
+ if ( !stricmp( set->pszName(), name ) )
+ return i;
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pstudiohdr -
+// setnumber -
+// Output : char const
+//-----------------------------------------------------------------------------
+const char *GetHitboxSetName( CStudioHdr *pstudiohdr, int setnumber )
+{
+ if ( !pstudiohdr )
+ return "";
+
+ mstudiohitboxset_t *set = pstudiohdr->pHitboxSet( setnumber );
+ if ( !set )
+ return "";
+
+ return set->pszName();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pstudiohdr -
+// Output : int
+//-----------------------------------------------------------------------------
+int GetHitboxSetCount( CStudioHdr *pstudiohdr )
+{
+ if ( !pstudiohdr )
+ return 0;
+
+ return pstudiohdr->numhitboxsets();
+}