Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3607 lines
104 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Base class for all animating characters and objects.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "baseanimating.h"
  8. #include "animation.h"
  9. #include "activitylist.h"
  10. #include "studio.h"
  11. #include "bone_setup.h"
  12. #include "mathlib/mathlib.h"
  13. #include "model_types.h"
  14. #include "datacache/imdlcache.h"
  15. #include "physics.h"
  16. #include "ndebugoverlay.h"
  17. #include "tier1/strtools.h"
  18. #include "npcevent.h"
  19. #include "isaverestore.h"
  20. #include "KeyValues.h"
  21. #include "tier0/vprof.h"
  22. #include "EntityFlame.h"
  23. #include "EntityDissolve.h"
  24. #include "ai_basenpc.h"
  25. #include "physics_prop_ragdoll.h"
  26. #include "datacache/idatacache.h"
  27. #include "smoke_trail.h"
  28. #include "props.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. ConVar ai_sequence_debug( "ai_sequence_debug", "0" );
  32. class CIKSaveRestoreOps : public CClassPtrSaveRestoreOps
  33. {
  34. // save data type interface
  35. void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  36. {
  37. Assert( fieldInfo.pTypeDesc->fieldSize == 1 );
  38. CIKContext **pIK = (CIKContext **)fieldInfo.pField;
  39. bool bHasIK = (*pIK) != 0;
  40. pSave->WriteBool( &bHasIK );
  41. }
  42. void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  43. {
  44. Assert( fieldInfo.pTypeDesc->fieldSize == 1 );
  45. CIKContext **pIK = (CIKContext **)fieldInfo.pField;
  46. bool bHasIK;
  47. pRestore->ReadBool( &bHasIK );
  48. *pIK = (bHasIK) ? new CIKContext : NULL;
  49. }
  50. };
  51. //-----------------------------------------------------------------------------
  52. // Relative lighting entity
  53. //-----------------------------------------------------------------------------
  54. class CInfoLightingRelative : public CBaseEntity
  55. {
  56. public:
  57. DECLARE_CLASS( CInfoLightingRelative, CBaseEntity );
  58. DECLARE_DATADESC();
  59. DECLARE_SERVERCLASS();
  60. virtual void Activate();
  61. virtual void SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways );
  62. virtual int UpdateTransmitState( void );
  63. private:
  64. CNetworkHandle( CBaseEntity, m_hLightingLandmark );
  65. string_t m_strLightingLandmark;
  66. };
  67. LINK_ENTITY_TO_CLASS( info_lighting_relative, CInfoLightingRelative );
  68. BEGIN_DATADESC( CInfoLightingRelative )
  69. DEFINE_KEYFIELD( m_strLightingLandmark, FIELD_STRING, "LightingLandmark" ),
  70. DEFINE_FIELD( m_hLightingLandmark, FIELD_EHANDLE ),
  71. END_DATADESC()
  72. IMPLEMENT_SERVERCLASS_ST(CInfoLightingRelative, DT_InfoLightingRelative)
  73. SendPropEHandle( SENDINFO( m_hLightingLandmark ) ),
  74. END_SEND_TABLE()
  75. //-----------------------------------------------------------------------------
  76. // Activate!
  77. //-----------------------------------------------------------------------------
  78. void CInfoLightingRelative::Activate()
  79. {
  80. BaseClass::Activate();
  81. if ( m_strLightingLandmark == NULL_STRING )
  82. {
  83. m_hLightingLandmark = NULL;
  84. }
  85. else
  86. {
  87. m_hLightingLandmark = gEntList.FindEntityByName( NULL, m_strLightingLandmark );
  88. if ( !m_hLightingLandmark )
  89. {
  90. DevWarning( "%s: Could not find lighting landmark '%s'!\n", GetClassname(), STRING( m_strLightingLandmark ) );
  91. }
  92. else
  93. {
  94. // Set a force transmit because we do not have a model.
  95. m_hLightingLandmark->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  96. }
  97. }
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Force our lighting landmark to be transmitted
  101. //-----------------------------------------------------------------------------
  102. void CInfoLightingRelative::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
  103. {
  104. // Are we already marked for transmission?
  105. if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
  106. return;
  107. BaseClass::SetTransmit( pInfo, bAlways );
  108. // Force our constraint entity to be sent too.
  109. if ( m_hLightingLandmark )
  110. {
  111. if ( m_hLightingLandmark->GetMoveParent() )
  112. {
  113. // Set a full check because we have a move parent.
  114. m_hLightingLandmark->SetTransmitState( FL_EDICT_FULLCHECK );
  115. }
  116. else
  117. {
  118. m_hLightingLandmark->SetTransmitState( FL_EDICT_ALWAYS );
  119. }
  120. m_hLightingLandmark->SetTransmit( pInfo, bAlways );
  121. }
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose Force our lighting landmark to be transmitted
  125. //-----------------------------------------------------------------------------
  126. int CInfoLightingRelative::UpdateTransmitState( void )
  127. {
  128. return SetTransmitState( FL_EDICT_ALWAYS );
  129. }
  130. static CIKSaveRestoreOps s_IKSaveRestoreOp;
  131. BEGIN_DATADESC( CBaseAnimating )
  132. DEFINE_FIELD( m_flGroundSpeed, FIELD_FLOAT ),
  133. DEFINE_FIELD( m_flLastEventCheck, FIELD_TIME ),
  134. DEFINE_FIELD( m_bSequenceFinished, FIELD_BOOLEAN ),
  135. DEFINE_FIELD( m_bSequenceLoops, FIELD_BOOLEAN ),
  136. // DEFINE_FIELD( m_nForceBone, FIELD_INTEGER ),
  137. // DEFINE_FIELD( m_vecForce, FIELD_VECTOR ),
  138. DEFINE_INPUT( m_nSkin, FIELD_INTEGER, "skin" ),
  139. DEFINE_KEYFIELD( m_nBody, FIELD_INTEGER, "body" ),
  140. DEFINE_INPUT( m_nBody, FIELD_INTEGER, "SetBodyGroup" ),
  141. DEFINE_KEYFIELD( m_nHitboxSet, FIELD_INTEGER, "hitboxset" ),
  142. DEFINE_KEYFIELD( m_nSequence, FIELD_INTEGER, "sequence" ),
  143. DEFINE_ARRAY( m_flPoseParameter, FIELD_FLOAT, CBaseAnimating::NUM_POSEPAREMETERS ),
  144. DEFINE_ARRAY( m_flEncodedController, FIELD_FLOAT, CBaseAnimating::NUM_BONECTRLS ),
  145. DEFINE_KEYFIELD( m_flPlaybackRate, FIELD_FLOAT, "playbackrate" ),
  146. DEFINE_KEYFIELD( m_flCycle, FIELD_FLOAT, "cycle" ),
  147. // DEFINE_FIELD( m_flIKGroundContactTime, FIELD_TIME ),
  148. // DEFINE_FIELD( m_flIKGroundMinHeight, FIELD_FLOAT ),
  149. // DEFINE_FIELD( m_flIKGroundMaxHeight, FIELD_FLOAT ),
  150. // DEFINE_FIELD( m_flEstIkFloor, FIELD_FLOAT ),
  151. // DEFINE_FIELD( m_flEstIkOffset, FIELD_FLOAT ),
  152. // DEFINE_FIELD( m_pStudioHdr, CStudioHdr ),
  153. // DEFINE_FIELD( m_StudioHdrInitLock, CThreadFastMutex ),
  154. // DEFINE_FIELD( m_BoneSetupMutex, CThreadFastMutex ),
  155. DEFINE_CUSTOM_FIELD( m_pIk, &s_IKSaveRestoreOp ),
  156. DEFINE_FIELD( m_iIKCounter, FIELD_INTEGER ),
  157. DEFINE_FIELD( m_bClientSideAnimation, FIELD_BOOLEAN ),
  158. DEFINE_FIELD( m_bClientSideFrameReset, FIELD_BOOLEAN ),
  159. DEFINE_FIELD( m_nNewSequenceParity, FIELD_INTEGER ),
  160. DEFINE_FIELD( m_nResetEventsParity, FIELD_INTEGER ),
  161. DEFINE_FIELD( m_nMuzzleFlashParity, FIELD_CHARACTER ),
  162. DEFINE_KEYFIELD( m_iszLightingOriginRelative, FIELD_STRING, "LightingOriginHack" ),
  163. DEFINE_KEYFIELD( m_iszLightingOrigin, FIELD_STRING, "LightingOrigin" ),
  164. DEFINE_FIELD( m_hLightingOrigin, FIELD_EHANDLE ),
  165. DEFINE_FIELD( m_hLightingOriginRelative, FIELD_EHANDLE ),
  166. DEFINE_FIELD( m_flModelScale, FIELD_FLOAT ),
  167. DEFINE_FIELD( m_flDissolveStartTime, FIELD_TIME ),
  168. // DEFINE_FIELD( m_boneCacheHandle, memhandle_t ),
  169. DEFINE_INPUTFUNC( FIELD_VOID, "Ignite", InputIgnite ),
  170. DEFINE_INPUTFUNC( FIELD_FLOAT, "IgniteLifetime", InputIgniteLifetime ),
  171. DEFINE_INPUTFUNC( FIELD_INTEGER, "IgniteNumHitboxFires", InputIgniteNumHitboxFires ),
  172. DEFINE_INPUTFUNC( FIELD_FLOAT, "IgniteHitboxFireScale", InputIgniteHitboxFireScale ),
  173. DEFINE_INPUTFUNC( FIELD_VOID, "BecomeRagdoll", InputBecomeRagdoll ),
  174. DEFINE_INPUTFUNC( FIELD_STRING, "SetLightingOriginHack", InputSetLightingOriginRelative ),
  175. DEFINE_INPUTFUNC( FIELD_STRING, "SetLightingOrigin", InputSetLightingOrigin ),
  176. DEFINE_OUTPUT( m_OnIgnite, "OnIgnite" ),
  177. DEFINE_INPUT( m_fadeMinDist, FIELD_FLOAT, "fademindist" ),
  178. DEFINE_INPUT( m_fadeMaxDist, FIELD_FLOAT, "fademaxdist" ),
  179. DEFINE_KEYFIELD( m_flFadeScale, FIELD_FLOAT, "fadescale" ),
  180. DEFINE_KEYFIELD( m_flModelScale, FIELD_FLOAT, "modelscale" ),
  181. DEFINE_INPUTFUNC( FIELD_VECTOR, "SetModelScale", InputSetModelScale ),
  182. DEFINE_FIELD( m_fBoneCacheFlags, FIELD_SHORT ),
  183. END_DATADESC()
  184. // Sendtable for fields we don't want to send to clientside animating entities
  185. BEGIN_SEND_TABLE_NOBASE( CBaseAnimating, DT_ServerAnimationData )
  186. // ANIMATION_CYCLE_BITS is defined in shareddefs.h
  187. SendPropFloat (SENDINFO(m_flCycle), ANIMATION_CYCLE_BITS, SPROP_CHANGES_OFTEN|SPROP_ROUNDDOWN, 0.0f, 1.0f)
  188. END_SEND_TABLE()
  189. void *SendProxy_ClientSideAnimation( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID );
  190. // SendTable stuff.
  191. IMPLEMENT_SERVERCLASS_ST(CBaseAnimating, DT_BaseAnimating)
  192. SendPropInt ( SENDINFO(m_nForceBone), 8, 0 ),
  193. SendPropVector ( SENDINFO(m_vecForce), -1, SPROP_NOSCALE ),
  194. SendPropInt ( SENDINFO(m_nSkin), ANIMATION_SKIN_BITS),
  195. SendPropInt ( SENDINFO(m_nBody), ANIMATION_BODY_BITS),
  196. SendPropInt ( SENDINFO(m_nHitboxSet),ANIMATION_HITBOXSET_BITS, SPROP_UNSIGNED ),
  197. SendPropFloat ( SENDINFO(m_flModelScale) ),
  198. SendPropArray3 ( SENDINFO_ARRAY3(m_flPoseParameter), SendPropFloat(SENDINFO_ARRAY(m_flPoseParameter), ANIMATION_POSEPARAMETER_BITS, 0, 0.0f, 1.0f ) ),
  199. SendPropInt ( SENDINFO(m_nSequence), ANIMATION_SEQUENCE_BITS, SPROP_UNSIGNED ),
  200. 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
  201. SendPropArray3 (SENDINFO_ARRAY3(m_flEncodedController), SendPropFloat(SENDINFO_ARRAY(m_flEncodedController), 11, SPROP_ROUNDDOWN, 0.0f, 1.0f ) ),
  202. SendPropInt( SENDINFO( m_bClientSideAnimation ), 1, SPROP_UNSIGNED ),
  203. SendPropInt( SENDINFO( m_bClientSideFrameReset ), 1, SPROP_UNSIGNED ),
  204. SendPropInt( SENDINFO( m_nNewSequenceParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
  205. SendPropInt( SENDINFO( m_nResetEventsParity ), EF_PARITY_BITS, SPROP_UNSIGNED ),
  206. SendPropInt( SENDINFO( m_nMuzzleFlashParity ), EF_MUZZLEFLASH_BITS, SPROP_UNSIGNED ),
  207. SendPropEHandle( SENDINFO( m_hLightingOrigin ) ),
  208. SendPropEHandle( SENDINFO( m_hLightingOriginRelative ) ),
  209. SendPropDataTable( "serveranimdata", 0, &REFERENCE_SEND_TABLE( DT_ServerAnimationData ), SendProxy_ClientSideAnimation ),
  210. // Fading
  211. SendPropFloat( SENDINFO( m_fadeMinDist ), 0, SPROP_NOSCALE ),
  212. SendPropFloat( SENDINFO( m_fadeMaxDist ), 0, SPROP_NOSCALE ),
  213. SendPropFloat( SENDINFO( m_flFadeScale ), 0, SPROP_NOSCALE ),
  214. END_SEND_TABLE()
  215. CBaseAnimating::CBaseAnimating()
  216. {
  217. m_vecForce.GetForModify().Init();
  218. m_nForceBone = 0;
  219. m_bResetSequenceInfoOnLoad = false;
  220. m_bClientSideAnimation = false;
  221. m_pIk = NULL;
  222. m_iIKCounter = 0;
  223. InitStepHeightAdjust();
  224. m_flModelScale = 1.0f;
  225. // initialize anim clock
  226. m_flAnimTime = gpGlobals->curtime;
  227. m_flPrevAnimTime = gpGlobals->curtime;
  228. m_nNewSequenceParity = 0;
  229. m_nResetEventsParity = 0;
  230. m_boneCacheHandle = 0;
  231. m_pStudioHdr = NULL;
  232. m_fadeMinDist = 0;
  233. m_fadeMaxDist = 0;
  234. m_flFadeScale = 0.0f;
  235. m_fBoneCacheFlags = 0;
  236. }
  237. CBaseAnimating::~CBaseAnimating()
  238. {
  239. Studio_DestroyBoneCache( m_boneCacheHandle );
  240. delete m_pIk;
  241. UnlockStudioHdr();
  242. delete m_pStudioHdr;
  243. }
  244. void CBaseAnimating::Precache()
  245. {
  246. #if !defined( TF_DLL )
  247. // Anything derived from this class can potentially burn - true, but do we want it to!
  248. PrecacheParticleSystem( "burning_character" );
  249. #endif
  250. BaseClass::Precache();
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Activate!
  254. //-----------------------------------------------------------------------------
  255. void CBaseAnimating::Activate()
  256. {
  257. BaseClass::Activate();
  258. SetLightingOrigin( m_iszLightingOrigin );
  259. SetLightingOriginRelative( m_iszLightingOriginRelative );
  260. // Scaled physics objects (re)create their physics here
  261. if ( m_flModelScale != 1.0f && VPhysicsGetObject() )
  262. {
  263. // sanity check to make sure 'm_flModelScale' is in sync with the
  264. Assert( m_flModelScale > 0.0f );
  265. UTIL_CreateScaledPhysObject( this, m_flModelScale );
  266. }
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Force our lighting origin to be trasmitted
  270. //-----------------------------------------------------------------------------
  271. void CBaseAnimating::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
  272. {
  273. // Are we already marked for transmission?
  274. if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
  275. return;
  276. BaseClass::SetTransmit( pInfo, bAlways );
  277. // Force our lighting entities to be sent too.
  278. if ( m_hLightingOrigin )
  279. {
  280. m_hLightingOrigin->SetTransmit( pInfo, bAlways );
  281. }
  282. if ( m_hLightingOriginRelative )
  283. {
  284. m_hLightingOriginRelative->SetTransmit( pInfo, bAlways );
  285. }
  286. }
  287. //-----------------------------------------------------------------------------
  288. //-----------------------------------------------------------------------------
  289. int CBaseAnimating::Restore( IRestore &restore )
  290. {
  291. int result = BaseClass::Restore( restore );
  292. if ( m_flModelScale <= 0.0f )
  293. m_flModelScale = 1.0f;
  294. LockStudioHdr();
  295. return result;
  296. }
  297. //-----------------------------------------------------------------------------
  298. //-----------------------------------------------------------------------------
  299. void CBaseAnimating::OnRestore()
  300. {
  301. BaseClass::OnRestore();
  302. if ( m_nSequence != -1 && GetModelPtr() && !IsValidSequence( m_nSequence ) )
  303. m_nSequence = 0;
  304. m_flEstIkFloor = GetLocalOrigin().z;
  305. PopulatePoseParameters();
  306. }
  307. //-----------------------------------------------------------------------------
  308. //-----------------------------------------------------------------------------
  309. void CBaseAnimating::Spawn()
  310. {
  311. BaseClass::Spawn();
  312. }
  313. //-----------------------------------------------------------------------------
  314. //-----------------------------------------------------------------------------
  315. void CBaseAnimating::UseClientSideAnimation()
  316. {
  317. m_bClientSideAnimation = true;
  318. }
  319. #define MAX_ANIMTIME_INTERVAL 0.2f
  320. //-----------------------------------------------------------------------------
  321. // Purpose:
  322. // Output : float
  323. //-----------------------------------------------------------------------------
  324. float CBaseAnimating::GetAnimTimeInterval( void ) const
  325. {
  326. float flInterval;
  327. if (m_flAnimTime < gpGlobals->curtime)
  328. {
  329. // estimate what it'll be this frame
  330. flInterval = clamp( gpGlobals->curtime - m_flAnimTime, 0.f, MAX_ANIMTIME_INTERVAL );
  331. }
  332. else
  333. {
  334. // report actual
  335. flInterval = clamp( m_flAnimTime - m_flPrevAnimTime, 0.f, MAX_ANIMTIME_INTERVAL );
  336. }
  337. return flInterval;
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose:
  341. //-----------------------------------------------------------------------------
  342. void CBaseAnimating::StudioFrameAdvanceInternal( CStudioHdr *pStudioHdr, float flCycleDelta )
  343. {
  344. float flNewCycle = GetCycle() + flCycleDelta;
  345. if (flNewCycle < 0.0 || flNewCycle >= 1.0)
  346. {
  347. if (m_bSequenceLoops)
  348. {
  349. flNewCycle -= (int)(flNewCycle);
  350. }
  351. else
  352. {
  353. flNewCycle = (flNewCycle < 0.0f) ? 0.0f : 1.0f;
  354. }
  355. m_bSequenceFinished = true; // just in case it wasn't caught in GetEvents
  356. }
  357. else if (flNewCycle > GetLastVisibleCycle( pStudioHdr, GetSequence() ))
  358. {
  359. m_bSequenceFinished = true;
  360. }
  361. SetCycle( flNewCycle );
  362. /*
  363. if (!IsPlayer())
  364. Msg("%s %6.3f : %6.3f %6.3f (%.3f) %.3f\n",
  365. GetClassname(), gpGlobals->curtime,
  366. m_flAnimTime.Get(), m_flPrevAnimTime, flInterval, GetCycle() );
  367. */
  368. m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() ) * GetModelScale();
  369. // Msg("%s : %s : %5.1f\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
  370. InvalidatePhysicsRecursive( ANIMATION_CHANGED );
  371. InvalidateBoneCacheIfOlderThan( 0 );
  372. }
  373. void CBaseAnimating::InvalidateBoneCacheIfOlderThan( float deltaTime )
  374. {
  375. CBoneCache *pcache = Studio_GetBoneCache( m_boneCacheHandle );
  376. if ( !pcache || !pcache->IsValid( gpGlobals->curtime, deltaTime ) )
  377. {
  378. InvalidateBoneCache();
  379. }
  380. }
  381. //-----------------------------------------------------------------------------
  382. // Purpose:
  383. //-----------------------------------------------------------------------------
  384. void CBaseAnimating::StudioFrameAdvanceManual( float flInterval )
  385. {
  386. CStudioHdr *pStudioHdr = GetModelPtr();
  387. if ( !pStudioHdr )
  388. return;
  389. m_flAnimTime = gpGlobals->curtime;
  390. m_flPrevAnimTime = m_flAnimTime - flInterval;
  391. float flCycleRate = GetSequenceCycleRate( pStudioHdr, GetSequence() ) * m_flPlaybackRate;
  392. StudioFrameAdvanceInternal( GetModelPtr(), flInterval * flCycleRate );
  393. }
  394. //=========================================================
  395. // StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future
  396. //=========================================================
  397. void CBaseAnimating::StudioFrameAdvance()
  398. {
  399. CStudioHdr *pStudioHdr = GetModelPtr();
  400. if ( !pStudioHdr || !pStudioHdr->SequencesAvailable() )
  401. {
  402. return;
  403. }
  404. if ( !m_flPrevAnimTime )
  405. {
  406. m_flPrevAnimTime = m_flAnimTime;
  407. }
  408. // Time since last animation
  409. float flInterval = gpGlobals->curtime - m_flAnimTime;
  410. flInterval = clamp( flInterval, 0.f, MAX_ANIMTIME_INTERVAL );
  411. //Msg( "%i %s interval %f\n", entindex(), GetClassname(), flInterval );
  412. if (flInterval <= 0.001f)
  413. {
  414. // Msg("%s : %s : %5.3f (skip)\n", GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
  415. return;
  416. }
  417. // Latch prev
  418. m_flPrevAnimTime = m_flAnimTime;
  419. // Set current
  420. m_flAnimTime = gpGlobals->curtime;
  421. // Drive cycle
  422. float flCycleRate = GetSequenceCycleRate( pStudioHdr, GetSequence() ) * m_flPlaybackRate;
  423. StudioFrameAdvanceInternal( pStudioHdr, flInterval * flCycleRate );
  424. if (ai_sequence_debug.GetBool() == true && m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
  425. {
  426. Msg("%5.2f : %s : %s : %5.3f\n", gpGlobals->curtime, GetClassname(), GetSequenceName( GetSequence() ), GetCycle() );
  427. }
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Set the relative lighting origin
  431. //-----------------------------------------------------------------------------
  432. void CBaseAnimating::SetLightingOriginRelative( string_t strLightingOriginRelative )
  433. {
  434. if ( strLightingOriginRelative == NULL_STRING )
  435. {
  436. SetLightingOriginRelative( NULL );
  437. }
  438. else
  439. {
  440. CBaseEntity *pLightingOrigin = gEntList.FindEntityByName( NULL, strLightingOriginRelative );
  441. if ( !pLightingOrigin )
  442. {
  443. DevWarning( "%s: Could not find info_lighting_relative '%s'!\n", GetClassname(), STRING( strLightingOriginRelative ) );
  444. return;
  445. }
  446. else if ( !dynamic_cast<CInfoLightingRelative *>(pLightingOrigin) )
  447. {
  448. if( !pLightingOrigin )
  449. {
  450. DevWarning( "%s: Cannot find Lighting Origin named: %s\n", GetEntityName().ToCStr(), STRING(strLightingOriginRelative) );
  451. }
  452. else
  453. {
  454. DevWarning( "%s: Specified entity '%s' must be a info_lighting_relative!\n",
  455. pLightingOrigin->GetClassname(), pLightingOrigin->GetEntityName().ToCStr() );
  456. }
  457. return;
  458. }
  459. SetLightingOriginRelative( pLightingOrigin );
  460. }
  461. // Save the name so that save/load will correctly restore it in Activate()
  462. m_iszLightingOriginRelative = strLightingOriginRelative;
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Set the lighting origin
  466. //-----------------------------------------------------------------------------
  467. void CBaseAnimating::SetLightingOrigin( string_t strLightingOrigin )
  468. {
  469. if ( strLightingOrigin == NULL_STRING )
  470. {
  471. SetLightingOrigin( NULL );
  472. }
  473. else
  474. {
  475. CBaseEntity *pLightingOrigin = gEntList.FindEntityByName( NULL, strLightingOrigin );
  476. if ( !pLightingOrigin )
  477. {
  478. DevWarning( "%s: Could not find lighting origin entity named '%s'!\n", GetClassname(), STRING( strLightingOrigin ) );
  479. return;
  480. }
  481. else
  482. {
  483. SetLightingOrigin( pLightingOrigin );
  484. }
  485. }
  486. // Save the name so that save/load will correctly restore it in Activate()
  487. m_iszLightingOrigin = strLightingOrigin;
  488. }
  489. //-----------------------------------------------------------------------------
  490. // Purpose:
  491. // Input : &inputdata -
  492. //-----------------------------------------------------------------------------
  493. void CBaseAnimating::InputSetLightingOriginRelative( inputdata_t &inputdata )
  494. {
  495. // Find our specified target
  496. string_t strLightingOriginRelative = MAKE_STRING( inputdata.value.String() );
  497. SetLightingOriginRelative( strLightingOriginRelative );
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Purpose:
  501. // Input : &inputdata -
  502. //-----------------------------------------------------------------------------
  503. void CBaseAnimating::InputSetLightingOrigin( inputdata_t &inputdata )
  504. {
  505. // Find our specified target
  506. string_t strLightingOrigin = MAKE_STRING( inputdata.value.String() );
  507. SetLightingOrigin( strLightingOrigin );
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Purpose: SetModelScale input handler
  511. //-----------------------------------------------------------------------------
  512. void CBaseAnimating::InputSetModelScale( inputdata_t &inputdata )
  513. {
  514. Vector vecScale;
  515. inputdata.value.Vector3D( vecScale );
  516. SetModelScale( vecScale.x, vecScale.y );
  517. }
  518. //=========================================================
  519. // SelectWeightedSequence
  520. //=========================================================
  521. int CBaseAnimating::SelectWeightedSequence ( Activity activity )
  522. {
  523. Assert( activity != ACT_INVALID );
  524. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  525. return ::SelectWeightedSequence( GetModelPtr(), activity, GetSequence() );
  526. }
  527. int CBaseAnimating::SelectWeightedSequence ( Activity activity, int curSequence )
  528. {
  529. Assert( activity != ACT_INVALID );
  530. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  531. return ::SelectWeightedSequence( GetModelPtr(), activity, curSequence );
  532. }
  533. int CBaseAnimating::SelectWeightedSequenceFromModifiers( Activity activity, CUtlSymbol *pActivityModifiers, int iModifierCount )
  534. {
  535. Assert( activity != ACT_INVALID );
  536. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  537. return GetModelPtr()->SelectWeightedSequenceFromModifiers( activity, pActivityModifiers, iModifierCount );
  538. }
  539. //=========================================================
  540. // ResetActivityIndexes
  541. //=========================================================
  542. void CBaseAnimating::ResetActivityIndexes ( void )
  543. {
  544. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  545. ::ResetActivityIndexes( GetModelPtr() );
  546. }
  547. //=========================================================
  548. // ResetEventIndexes
  549. //=========================================================
  550. void CBaseAnimating::ResetEventIndexes ( void )
  551. {
  552. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  553. ::ResetEventIndexes( GetModelPtr() );
  554. }
  555. //=========================================================
  556. // LookupHeaviestSequence
  557. //
  558. // Get sequence with highest 'weight' for this activity
  559. //
  560. //=========================================================
  561. int CBaseAnimating::SelectHeaviestSequence ( Activity activity )
  562. {
  563. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  564. return ::SelectHeaviestSequence( GetModelPtr(), activity );
  565. }
  566. //-----------------------------------------------------------------------------
  567. // Purpose: Looks up an activity by name.
  568. // Input : label - Name of the activity, ie "ACT_IDLE".
  569. // Output : Returns the activity ID or ACT_INVALID.
  570. //-----------------------------------------------------------------------------
  571. int CBaseAnimating::LookupActivity( const char *label )
  572. {
  573. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  574. return ::LookupActivity( GetModelPtr(), label );
  575. }
  576. //=========================================================
  577. //=========================================================
  578. int CBaseAnimating::LookupSequence( const char *label )
  579. {
  580. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  581. return ::LookupSequence( GetModelPtr(), label );
  582. }
  583. //-----------------------------------------------------------------------------
  584. // Purpose:
  585. // Input :
  586. // Output :
  587. //-----------------------------------------------------------------------------
  588. KeyValues *CBaseAnimating::GetSequenceKeyValues( int iSequence )
  589. {
  590. const char *szText = Studio_GetKeyValueText( GetModelPtr(), iSequence );
  591. if (szText)
  592. {
  593. KeyValues *seqKeyValues = new KeyValues("");
  594. if ( seqKeyValues->LoadFromBuffer( modelinfo->GetModelName( GetModel() ), szText ) )
  595. {
  596. return seqKeyValues;
  597. }
  598. seqKeyValues->deleteThis();
  599. }
  600. return NULL;
  601. }
  602. //-----------------------------------------------------------------------------
  603. // Purpose:
  604. //
  605. // Input : iSequence -
  606. //
  607. // Output : float -
  608. //-----------------------------------------------------------------------------
  609. float CBaseAnimating::GetSequenceMoveYaw( int iSequence )
  610. {
  611. Vector vecReturn;
  612. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  613. ::GetSequenceLinearMotion( GetModelPtr(), iSequence, GetPoseParameterArray(), &vecReturn );
  614. if (vecReturn.Length() > 0)
  615. {
  616. return UTIL_VecToYaw( vecReturn );
  617. }
  618. return NOMOTION;
  619. }
  620. //-----------------------------------------------------------------------------
  621. // Purpose:
  622. //
  623. // Input : iSequence -
  624. //
  625. // Output : float
  626. //-----------------------------------------------------------------------------
  627. float CBaseAnimating::GetSequenceMoveDist( CStudioHdr *pStudioHdr, int iSequence )
  628. {
  629. Vector vecReturn;
  630. ::GetSequenceLinearMotion( pStudioHdr, iSequence, GetPoseParameterArray(), &vecReturn );
  631. return vecReturn.Length();
  632. }
  633. //-----------------------------------------------------------------------------
  634. // Purpose:
  635. //
  636. // Input : iSequence -
  637. // *pVec -
  638. //
  639. //-----------------------------------------------------------------------------
  640. void CBaseAnimating::GetSequenceLinearMotion( int iSequence, Vector *pVec )
  641. {
  642. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  643. ::GetSequenceLinearMotion( GetModelPtr(), iSequence, GetPoseParameterArray(), pVec );
  644. }
  645. //-----------------------------------------------------------------------------
  646. // Purpose:
  647. //
  648. // Input : iSequence -
  649. //
  650. // Output : char
  651. //-----------------------------------------------------------------------------
  652. const char *CBaseAnimating::GetSequenceName( int iSequence )
  653. {
  654. if( iSequence == -1 )
  655. {
  656. return "Not Found!";
  657. }
  658. if ( !GetModelPtr() )
  659. return "No model!";
  660. return ::GetSequenceName( GetModelPtr(), iSequence );
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Purpose:
  664. //
  665. // Input : iSequence -
  666. //
  667. // Output : char
  668. //-----------------------------------------------------------------------------
  669. const char *CBaseAnimating::GetSequenceActivityName( int iSequence )
  670. {
  671. if( iSequence == -1 )
  672. {
  673. return "Not Found!";
  674. }
  675. if ( !GetModelPtr() )
  676. return "No model!";
  677. return ::GetSequenceActivityName( GetModelPtr(), iSequence );
  678. }
  679. //-----------------------------------------------------------------------------
  680. // Purpose: Make this a client-side simulated entity
  681. // Input : force - vector of force to be exerted in the physics simulation
  682. // forceBone - bone to exert force upon
  683. // Output : Returns true on success, false on failure.
  684. //-----------------------------------------------------------------------------
  685. bool CBaseAnimating::BecomeRagdollOnClient( const Vector &force )
  686. {
  687. // If this character has a ragdoll animation, turn it over to the physics system
  688. if ( CanBecomeRagdoll() )
  689. {
  690. VPhysicsDestroyObject();
  691. AddSolidFlags( FSOLID_NOT_SOLID );
  692. m_nRenderFX = kRenderFxRagdoll;
  693. // Have to do this dance because m_vecForce is a network vector
  694. // and can't be sent to ClampRagdollForce as a Vector *
  695. Vector vecClampedForce;
  696. ClampRagdollForce( force, &vecClampedForce );
  697. m_vecForce = vecClampedForce;
  698. SetParent( NULL );
  699. AddFlag( FL_TRANSRAGDOLL );
  700. SetMoveType( MOVETYPE_NONE );
  701. //UTIL_SetSize( this, vec3_origin, vec3_origin );
  702. SetThink( NULL );
  703. SetNextThink( gpGlobals->curtime + 2.0f );
  704. //If we're here, then we can vanish safely
  705. SetThink( &CBaseEntity::SUB_Remove );
  706. // Remove our flame entity if it's attached to us
  707. CEntityFlame *pFireChild = dynamic_cast<CEntityFlame *>( GetEffectEntity() );
  708. if ( pFireChild )
  709. {
  710. pFireChild->SetThink( &CBaseEntity::SUB_Remove );
  711. pFireChild->SetNextThink( gpGlobals->curtime + 0.1f );
  712. }
  713. return true;
  714. }
  715. return false;
  716. }
  717. bool CBaseAnimating::IsRagdoll()
  718. {
  719. return ( m_nRenderFX == kRenderFxRagdoll ) ? true : false;
  720. }
  721. bool CBaseAnimating::CanBecomeRagdoll( void )
  722. {
  723. MDLCACHE_CRITICAL_SECTION();
  724. int ragdollSequence = SelectWeightedSequence( ACT_DIERAGDOLL );
  725. //Can't cause we don't have a ragdoll sequence.
  726. if ( ragdollSequence == ACTIVITY_NOT_AVAILABLE )
  727. return false;
  728. if ( GetFlags() & FL_TRANSRAGDOLL )
  729. return false;
  730. return true;
  731. }
  732. //=========================================================
  733. //=========================================================
  734. void CBaseAnimating::ResetSequenceInfo ( )
  735. {
  736. if (GetSequence() == -1)
  737. {
  738. // This shouldn't happen. Setting m_nSequence blindly is a horrible coding practice.
  739. SetSequence( 0 );
  740. }
  741. if ( IsDynamicModelLoading() )
  742. {
  743. m_bResetSequenceInfoOnLoad = true;
  744. return;
  745. }
  746. CStudioHdr *pStudioHdr = GetModelPtr();
  747. m_flGroundSpeed = GetSequenceGroundSpeed( pStudioHdr, GetSequence() ) * GetModelScale();
  748. m_bSequenceLoops = ((GetSequenceFlags( pStudioHdr, GetSequence() ) & STUDIO_LOOPING) != 0);
  749. // m_flAnimTime = gpGlobals->time;
  750. m_flPlaybackRate = 1.0;
  751. m_bSequenceFinished = false;
  752. m_flLastEventCheck = 0;
  753. m_nNewSequenceParity = ( m_nNewSequenceParity+1 ) & EF_PARITY_MASK;
  754. m_nResetEventsParity = ( m_nResetEventsParity+1 ) & EF_PARITY_MASK;
  755. // FIXME: why is this called here? Nothing should have changed to make this nessesary
  756. if ( pStudioHdr )
  757. {
  758. SetEventIndexForSequence( pStudioHdr->pSeqdesc( GetSequence() ) );
  759. }
  760. }
  761. //=========================================================
  762. //=========================================================
  763. bool CBaseAnimating::IsValidSequence( int iSequence )
  764. {
  765. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  766. CStudioHdr* pstudiohdr = GetModelPtr( );
  767. if (iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq())
  768. {
  769. return false;
  770. }
  771. return true;
  772. }
  773. //=========================================================
  774. //=========================================================
  775. void CBaseAnimating::SetSequence( int nSequence )
  776. {
  777. Assert( nSequence == 0 || IsDynamicModelLoading() || ( GetModelPtr( ) && ( nSequence < GetModelPtr( )->GetNumSeq() ) && ( GetModelPtr( )->GetNumSeq() < (1 << ANIMATION_SEQUENCE_BITS) ) ) );
  778. m_nSequence = nSequence;
  779. }
  780. //=========================================================
  781. //=========================================================
  782. float CBaseAnimating::SequenceDuration( CStudioHdr *pStudioHdr, int iSequence )
  783. {
  784. if ( !pStudioHdr )
  785. {
  786. DevWarning( 2, "CBaseAnimating::SequenceDuration( %d ) NULL pstudiohdr on %s!\n", iSequence, GetClassname() );
  787. return 0.1;
  788. }
  789. if ( !pStudioHdr->SequencesAvailable() )
  790. {
  791. return 0.1;
  792. }
  793. if (iSequence >= pStudioHdr->GetNumSeq() || iSequence < 0 )
  794. {
  795. DevWarning( 2, "CBaseAnimating::SequenceDuration( %d ) out of range\n", iSequence );
  796. return 0.1;
  797. }
  798. return Studio_Duration( pStudioHdr, iSequence, GetPoseParameterArray() );
  799. }
  800. float CBaseAnimating::GetSequenceCycleRate( CStudioHdr *pStudioHdr, int iSequence )
  801. {
  802. float t = SequenceDuration( pStudioHdr, iSequence );
  803. if ( t != 0.0f )
  804. {
  805. return 1.0f / t;
  806. }
  807. return t;
  808. }
  809. float CBaseAnimating::GetLastVisibleCycle( CStudioHdr *pStudioHdr, int iSequence )
  810. {
  811. if ( !pStudioHdr )
  812. {
  813. DevWarning( 2, "CBaseAnimating::LastVisibleCycle( %d ) NULL pstudiohdr on %s!\n", iSequence, GetClassname() );
  814. return 1.0;
  815. }
  816. if (!(GetSequenceFlags( pStudioHdr, iSequence ) & STUDIO_LOOPING))
  817. {
  818. return 1.0f - (pStudioHdr->pSeqdesc( iSequence ).fadeouttime) * GetSequenceCycleRate( iSequence ) * m_flPlaybackRate;
  819. }
  820. else
  821. {
  822. return 1.0;
  823. }
  824. }
  825. float CBaseAnimating::GetSequenceGroundSpeed( CStudioHdr *pStudioHdr, int iSequence )
  826. {
  827. float t = SequenceDuration( pStudioHdr, iSequence );
  828. if (t > 0)
  829. {
  830. return ( GetSequenceMoveDist( pStudioHdr, iSequence ) / t );
  831. }
  832. else
  833. {
  834. return 0;
  835. }
  836. }
  837. float CBaseAnimating::GetIdealSpeed( ) const
  838. {
  839. return m_flGroundSpeed;
  840. }
  841. float CBaseAnimating::GetIdealAccel( ) const
  842. {
  843. // return ideal max velocity change over 1 second.
  844. // tuned for run-walk range of humans
  845. return GetIdealSpeed() + 50;
  846. }
  847. //-----------------------------------------------------------------------------
  848. // Purpose: Returns true if the given sequence has the anim event, false if not.
  849. // Input : nSequence - sequence number to check
  850. // nEvent - anim event number to look for
  851. //-----------------------------------------------------------------------------
  852. bool CBaseAnimating::HasAnimEvent( int nSequence, int nEvent )
  853. {
  854. CStudioHdr *pstudiohdr = GetModelPtr();
  855. if ( !pstudiohdr )
  856. {
  857. return false;
  858. }
  859. animevent_t event;
  860. int index = 0;
  861. while ( ( index = GetAnimationEvent( pstudiohdr, nSequence, &event, 0.0f, 1.0f, index ) ) != 0 )
  862. {
  863. if ( event.event == nEvent )
  864. {
  865. return true;
  866. }
  867. }
  868. return false;
  869. }
  870. //=========================================================
  871. // DispatchAnimEvents
  872. //=========================================================
  873. void CBaseAnimating::DispatchAnimEvents ( CBaseAnimating *eventHandler )
  874. {
  875. // don't fire events if the framerate is 0
  876. if (m_flPlaybackRate == 0.0)
  877. return;
  878. animevent_t event;
  879. CStudioHdr *pstudiohdr = GetModelPtr( );
  880. if ( !pstudiohdr )
  881. {
  882. Assert(!"CBaseAnimating::DispatchAnimEvents: model missing");
  883. return;
  884. }
  885. if ( !pstudiohdr->SequencesAvailable() )
  886. {
  887. return;
  888. }
  889. // skip this altogether if there are no events
  890. if (pstudiohdr->pSeqdesc( GetSequence() ).numevents == 0)
  891. {
  892. return;
  893. }
  894. // look from when it last checked to some short time in the future
  895. float flCycleRate = GetSequenceCycleRate( GetSequence() ) * m_flPlaybackRate;
  896. float flStart = m_flLastEventCheck;
  897. float flEnd = GetCycle();
  898. if (!m_bSequenceLoops && m_bSequenceFinished)
  899. {
  900. flEnd = 1.01f;
  901. }
  902. m_flLastEventCheck = flEnd;
  903. /*
  904. if (m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
  905. {
  906. Msg( "%s:%s : checking %.2f %.2f (%d)\n", STRING(GetModelName()), pstudiohdr->pSeqdesc( GetSequence() ).pszLabel(), flStart, flEnd, m_bSequenceFinished );
  907. }
  908. */
  909. // FIXME: does not handle negative framerates!
  910. int index = 0;
  911. while ( (index = GetAnimationEvent( pstudiohdr, GetSequence(), &event, flStart, flEnd, index ) ) != 0 )
  912. {
  913. event.pSource = this;
  914. // calc when this event should happen
  915. if (flCycleRate > 0.0)
  916. {
  917. float flCycle = event.cycle;
  918. if (flCycle > GetCycle())
  919. {
  920. flCycle = flCycle - 1.0;
  921. }
  922. event.eventtime = m_flAnimTime + (flCycle - GetCycle()) / flCycleRate + GetAnimTimeInterval();
  923. }
  924. /*
  925. if (m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
  926. {
  927. Msg( "dispatch %i (%i) cycle %f event cycle %f cyclerate %f\n",
  928. (int)(index - 1),
  929. (int)event.event,
  930. (float)GetCycle(),
  931. (float)event.cycle,
  932. (float)flCycleRate );
  933. }
  934. */
  935. eventHandler->HandleAnimEvent( &event );
  936. // FAILSAFE:
  937. // If HandleAnimEvent has somehow reset my internal pointer
  938. // to CStudioHdr to something other than it was when we entered
  939. // this function, we will crash on the next call to GetAnimationEvent
  940. // because pstudiohdr no longer points at something valid.
  941. // So, catch this case, complain vigorously, and bail out of
  942. // the loop.
  943. CStudioHdr *pNowStudioHdr = GetModelPtr();
  944. if ( pNowStudioHdr != pstudiohdr )
  945. {
  946. AssertMsg2(false, "%s has changed its model while processing AnimEvents on sequence %d. Aborting dispatch.\n", GetDebugName(), GetSequence() );
  947. Warning( "%s has changed its model while processing AnimEvents on sequence %d. Aborting dispatch.\n", GetDebugName(), GetSequence() );
  948. break;
  949. }
  950. }
  951. }
  952. //-----------------------------------------------------------------------------
  953. // Purpose:
  954. //-----------------------------------------------------------------------------
  955. void CBaseAnimating::HandleAnimEvent( animevent_t *pEvent )
  956. {
  957. if ((pEvent->type & AE_TYPE_NEWEVENTSYSTEM) && (pEvent->type & AE_TYPE_SERVER))
  958. {
  959. if ( pEvent->event == AE_SV_PLAYSOUND )
  960. {
  961. EmitSound( pEvent->options );
  962. return;
  963. }
  964. else if ( pEvent->event == AE_RAGDOLL )
  965. {
  966. // Convert to ragdoll immediately
  967. BecomeRagdollOnClient( vec3_origin );
  968. return;
  969. }
  970. #ifdef HL2_EPISODIC
  971. else if ( pEvent->event == AE_SV_DUSTTRAIL )
  972. {
  973. char szAttachment[128];
  974. float flDuration;
  975. float flSize;
  976. if (sscanf( pEvent->options, "%s %f %f", szAttachment, &flDuration, &flSize ) == 3)
  977. {
  978. CHandle<DustTrail> hDustTrail;
  979. hDustTrail = DustTrail::CreateDustTrail();
  980. if( hDustTrail )
  981. {
  982. hDustTrail->m_SpawnRate = 4; // Particles per second
  983. hDustTrail->m_ParticleLifetime = 1.5; // Lifetime of each particle, In seconds
  984. hDustTrail->m_Color.Init(0.5f, 0.46f, 0.44f);
  985. hDustTrail->m_StartSize = flSize;
  986. hDustTrail->m_EndSize = hDustTrail->m_StartSize * 8;
  987. hDustTrail->m_SpawnRadius = 3; // Each particle randomly offset from the center up to this many units
  988. hDustTrail->m_MinSpeed = 4; // u/sec
  989. hDustTrail->m_MaxSpeed = 10; // u/sec
  990. hDustTrail->m_Opacity = 0.5f;
  991. hDustTrail->SetLifetime(flDuration); // Lifetime of the spawner, in seconds
  992. hDustTrail->m_StopEmitTime = gpGlobals->curtime + flDuration;
  993. hDustTrail->SetParent( this, LookupAttachment( szAttachment ) );
  994. hDustTrail->SetLocalOrigin( vec3_origin );
  995. }
  996. }
  997. else
  998. {
  999. DevWarning( 1, "%s unable to parse AE_SV_DUSTTRAIL event \"%s\"\n", STRING( GetModelName() ), pEvent->options );
  1000. }
  1001. return;
  1002. }
  1003. #endif
  1004. }
  1005. // Failed to find a handler
  1006. const char *pName = EventList_NameForIndex( pEvent->event );
  1007. if ( pName)
  1008. {
  1009. DevWarning( 1, "Unhandled animation event %s for %s\n", pName, GetClassname() );
  1010. }
  1011. else
  1012. {
  1013. DevWarning( 1, "Unhandled animation event %d for %s\n", pEvent->event, GetClassname() );
  1014. }
  1015. }
  1016. // SetPoseParamater()
  1017. //=========================================================
  1018. //=========================================================
  1019. float CBaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, const char *szName, float flValue )
  1020. {
  1021. int poseParam = LookupPoseParameter( pStudioHdr, szName );
  1022. AssertMsg2(poseParam >= 0, "SetPoseParameter called with invalid argument %s by %s", szName, GetDebugName());
  1023. return SetPoseParameter( pStudioHdr, poseParam, flValue );
  1024. }
  1025. float CBaseAnimating::SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue )
  1026. {
  1027. if ( !pStudioHdr )
  1028. {
  1029. return flValue;
  1030. }
  1031. if (iParameter >= 0)
  1032. {
  1033. float flNewValue;
  1034. flValue = Studio_SetPoseParameter( pStudioHdr, iParameter, flValue, flNewValue );
  1035. m_flPoseParameter.Set( iParameter, flNewValue );
  1036. }
  1037. return flValue;
  1038. }
  1039. //=========================================================
  1040. //=========================================================
  1041. float CBaseAnimating::GetPoseParameter( const char *szName )
  1042. {
  1043. return GetPoseParameter( LookupPoseParameter( szName ) );
  1044. }
  1045. float CBaseAnimating::GetPoseParameter( int iParameter )
  1046. {
  1047. CStudioHdr *pstudiohdr = GetModelPtr( );
  1048. if ( !pstudiohdr )
  1049. {
  1050. Assert(!"CBaseAnimating::GetPoseParameter: model missing");
  1051. return 0.0;
  1052. }
  1053. if ( !pstudiohdr->SequencesAvailable() )
  1054. {
  1055. return 0;
  1056. }
  1057. if (iParameter >= 0)
  1058. {
  1059. return Studio_GetPoseParameter( pstudiohdr, iParameter, m_flPoseParameter[ iParameter ] );
  1060. }
  1061. return 0.0;
  1062. }
  1063. bool CBaseAnimating::GetPoseParameterRange( int index, float &minValue, float &maxValue )
  1064. {
  1065. CStudioHdr *pStudioHdr = GetModelPtr();
  1066. if (pStudioHdr)
  1067. {
  1068. if (index >= 0 && index < pStudioHdr->GetNumPoseParameters())
  1069. {
  1070. const mstudioposeparamdesc_t &pose = pStudioHdr->pPoseParameter( index );
  1071. minValue = pose.start;
  1072. maxValue = pose.end;
  1073. return true;
  1074. }
  1075. }
  1076. minValue = 0.0f;
  1077. maxValue = 1.0f;
  1078. return false;
  1079. }
  1080. //=========================================================
  1081. //=========================================================
  1082. int CBaseAnimating::LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName )
  1083. {
  1084. if ( !pStudioHdr )
  1085. return 0;
  1086. if ( !pStudioHdr->SequencesAvailable() )
  1087. {
  1088. return 0;
  1089. }
  1090. for (int i = 0; i < pStudioHdr->GetNumPoseParameters(); i++)
  1091. {
  1092. if (Q_stricmp( pStudioHdr->pPoseParameter( i ).pszName(), szName ) == 0)
  1093. {
  1094. return i;
  1095. }
  1096. }
  1097. // AssertMsg( 0, UTIL_VarArgs( "poseparameter %s couldn't be mapped!!!\n", szName ) );
  1098. return -1; // Error
  1099. }
  1100. //=========================================================
  1101. //=========================================================
  1102. bool CBaseAnimating::HasPoseParameter( int iSequence, const char *szName )
  1103. {
  1104. int iParameter = LookupPoseParameter( szName );
  1105. if (iParameter == -1)
  1106. {
  1107. return false;
  1108. }
  1109. return HasPoseParameter( iSequence, iParameter );
  1110. }
  1111. //=========================================================
  1112. //=========================================================
  1113. bool CBaseAnimating::HasPoseParameter( int iSequence, int iParameter )
  1114. {
  1115. CStudioHdr *pstudiohdr = GetModelPtr( );
  1116. if ( !pstudiohdr )
  1117. {
  1118. return false;
  1119. }
  1120. if ( !pstudiohdr->SequencesAvailable() )
  1121. {
  1122. return false;
  1123. }
  1124. if (iSequence < 0 || iSequence >= pstudiohdr->GetNumSeq())
  1125. {
  1126. return false;
  1127. }
  1128. mstudioseqdesc_t &seqdesc = pstudiohdr->pSeqdesc( iSequence );
  1129. if (pstudiohdr->GetSharedPoseParameter( iSequence, seqdesc.paramindex[0] ) == iParameter ||
  1130. pstudiohdr->GetSharedPoseParameter( iSequence, seqdesc.paramindex[1] ) == iParameter)
  1131. {
  1132. return true;
  1133. }
  1134. return false;
  1135. }
  1136. //=========================================================
  1137. // Each class that wants to use pose parameters should populate
  1138. // static variables in this entry point, rather than calling
  1139. // GetPoseParameter(const char*) every time you want to adjust
  1140. // an animation.
  1141. //
  1142. // Make sure to call BaseClass::PopulatePoseParameters() at
  1143. // the *bottom* of your function.
  1144. //=========================================================
  1145. void CBaseAnimating::PopulatePoseParameters( void )
  1146. {
  1147. }
  1148. //=========================================================
  1149. // Purpose: from input of 75% to 200% of maximum range, rescale smoothly from 75% to 100%
  1150. //=========================================================
  1151. float CBaseAnimating::EdgeLimitPoseParameter( int iParameter, float flValue, float flBase )
  1152. {
  1153. CStudioHdr *pstudiohdr = GetModelPtr( );
  1154. if ( !pstudiohdr )
  1155. {
  1156. return flValue;
  1157. }
  1158. if (iParameter < 0 || iParameter >= pstudiohdr->GetNumPoseParameters())
  1159. {
  1160. return flValue;
  1161. }
  1162. const mstudioposeparamdesc_t &Pose = pstudiohdr->pPoseParameter( iParameter );
  1163. if (Pose.loop || Pose.start == Pose.end)
  1164. {
  1165. return flValue;
  1166. }
  1167. return RangeCompressor( flValue, Pose.start, Pose.end, flBase );
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose: Returns index number of a given named bone
  1171. // Input : name of a bone
  1172. // Output : Bone index number or -1 if bone not found
  1173. //-----------------------------------------------------------------------------
  1174. int CBaseAnimating::LookupBone( const char *szName )
  1175. {
  1176. const CStudioHdr *pStudioHdr = GetModelPtr();
  1177. Assert( pStudioHdr );
  1178. if ( !pStudioHdr )
  1179. return -1;
  1180. return Studio_BoneIndexByName( pStudioHdr, szName );
  1181. }
  1182. //=========================================================
  1183. //=========================================================
  1184. void CBaseAnimating::GetBonePosition ( int iBone, Vector &origin, QAngle &angles )
  1185. {
  1186. CStudioHdr *pStudioHdr = GetModelPtr( );
  1187. if (!pStudioHdr)
  1188. {
  1189. Assert(!"CBaseAnimating::GetBonePosition: model missing");
  1190. return;
  1191. }
  1192. if (iBone < 0 || iBone >= pStudioHdr->numbones())
  1193. {
  1194. Assert(!"CBaseAnimating::GetBonePosition: invalid bone index");
  1195. return;
  1196. }
  1197. matrix3x4_t bonetoworld;
  1198. GetBoneTransform( iBone, bonetoworld );
  1199. MatrixAngles( bonetoworld, angles, origin );
  1200. }
  1201. //=========================================================
  1202. //=========================================================
  1203. void CBaseAnimating::GetBoneTransform( int iBone, matrix3x4_t &pBoneToWorld )
  1204. {
  1205. CStudioHdr *pStudioHdr = GetModelPtr( );
  1206. if (!pStudioHdr)
  1207. {
  1208. Assert(!"CBaseAnimating::GetBoneTransform: model missing");
  1209. return;
  1210. }
  1211. if (iBone < 0 || iBone >= pStudioHdr->numbones())
  1212. {
  1213. Assert(!"CBaseAnimating::GetBoneTransform: invalid bone index");
  1214. return;
  1215. }
  1216. CBoneCache *pcache = GetBoneCache( );
  1217. matrix3x4_t *pmatrix = pcache->GetCachedBone( iBone );
  1218. if ( !pmatrix )
  1219. {
  1220. MatrixCopy( EntityToWorldTransform(), pBoneToWorld );
  1221. return;
  1222. }
  1223. Assert( pmatrix );
  1224. // FIXME
  1225. MatrixCopy( *pmatrix, pBoneToWorld );
  1226. }
  1227. class CTraceFilterSkipNPCs : public CTraceFilterSimple
  1228. {
  1229. public:
  1230. CTraceFilterSkipNPCs( const IHandleEntity *passentity, int collisionGroup )
  1231. : CTraceFilterSimple( passentity, collisionGroup )
  1232. {
  1233. }
  1234. virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
  1235. {
  1236. if ( CTraceFilterSimple::ShouldHitEntity(pServerEntity, contentsMask) )
  1237. {
  1238. CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity );
  1239. if ( pEntity->IsNPC() )
  1240. return false;
  1241. return true;
  1242. }
  1243. return false;
  1244. }
  1245. };
  1246. //-----------------------------------------------------------------------------
  1247. // Purpose: Receives the clients IK floor position
  1248. //-----------------------------------------------------------------------------
  1249. void CBaseAnimating::SetIKGroundContactInfo( float minHeight, float maxHeight )
  1250. {
  1251. m_flIKGroundContactTime = gpGlobals->curtime;
  1252. m_flIKGroundMinHeight = minHeight;
  1253. m_flIKGroundMaxHeight = maxHeight;
  1254. }
  1255. //-----------------------------------------------------------------------------
  1256. // Purpose: Initializes IK floor position
  1257. //-----------------------------------------------------------------------------
  1258. void CBaseAnimating::InitStepHeightAdjust( void )
  1259. {
  1260. m_flIKGroundContactTime = 0;
  1261. m_flIKGroundMinHeight = 0;
  1262. m_flIKGroundMaxHeight = 0;
  1263. // FIXME: not safe to call GetAbsOrigin here. Hierarchy might not be set up!
  1264. m_flEstIkFloor = GetAbsOrigin().z;
  1265. m_flEstIkOffset = 0;
  1266. }
  1267. //-----------------------------------------------------------------------------
  1268. // Purpose: Interpolates client IK floor position and drops entity down so that the feet will reach
  1269. //-----------------------------------------------------------------------------
  1270. ConVar npc_height_adjust( "npc_height_adjust", "1", FCVAR_ARCHIVE, "Enable test mode for ik height adjustment" );
  1271. void CBaseAnimating::UpdateStepOrigin()
  1272. {
  1273. if (!npc_height_adjust.GetBool())
  1274. {
  1275. m_flEstIkOffset = 0;
  1276. m_flEstIkFloor = GetLocalOrigin().z;
  1277. return;
  1278. }
  1279. /*
  1280. if (m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
  1281. {
  1282. Msg("%x : %x\n", GetMoveParent(), GetGroundEntity() );
  1283. }
  1284. */
  1285. if (m_flIKGroundContactTime > 0.2 && m_flIKGroundContactTime > gpGlobals->curtime - 0.2)
  1286. {
  1287. if ((GetFlags() & (FL_FLY | FL_SWIM)) == 0 && GetMoveParent() == NULL && GetGroundEntity() != NULL && !GetGroundEntity()->IsMoving())
  1288. {
  1289. Vector toAbs = GetAbsOrigin() - GetLocalOrigin();
  1290. if (toAbs.z == 0.0)
  1291. {
  1292. CAI_BaseNPC *pNPC = MyNPCPointer();
  1293. // FIXME: There needs to be a default step height somewhere
  1294. float height = 18.0f;
  1295. if (pNPC)
  1296. {
  1297. height = pNPC->StepHeight();
  1298. }
  1299. // debounce floor location
  1300. m_flEstIkFloor = m_flEstIkFloor * 0.2 + m_flIKGroundMinHeight * 0.8;
  1301. // don't let heigth difference between min and max exceed step height
  1302. float bias = clamp( (m_flIKGroundMaxHeight - m_flIKGroundMinHeight) - height, 0.f, height );
  1303. // save off reasonable offset
  1304. m_flEstIkOffset = clamp( m_flEstIkFloor - GetAbsOrigin().z, -height + bias, 0.0f );
  1305. return;
  1306. }
  1307. }
  1308. }
  1309. // don't use floor offset, decay the value
  1310. m_flEstIkOffset *= 0.5;
  1311. m_flEstIkFloor = GetLocalOrigin().z;
  1312. }
  1313. //-----------------------------------------------------------------------------
  1314. // Purpose: Returns the origin to use for model rendering
  1315. //-----------------------------------------------------------------------------
  1316. Vector CBaseAnimating::GetStepOrigin( void ) const
  1317. {
  1318. Vector tmp = GetLocalOrigin();
  1319. tmp.z += m_flEstIkOffset;
  1320. return tmp;
  1321. }
  1322. //-----------------------------------------------------------------------------
  1323. // Purpose: Returns the origin to use for model rendering
  1324. //-----------------------------------------------------------------------------
  1325. QAngle CBaseAnimating::GetStepAngles( void ) const
  1326. {
  1327. // TODO: Add in body lean
  1328. return GetLocalAngles();
  1329. }
  1330. //-----------------------------------------------------------------------------
  1331. // Purpose: Find IK collisions with world
  1332. // Input :
  1333. // Output : fills out m_pIk targets, calcs floor offset for rendering
  1334. //-----------------------------------------------------------------------------
  1335. void CBaseAnimating::CalculateIKLocks( float currentTime )
  1336. {
  1337. if ( m_pIk )
  1338. {
  1339. Ray_t ray;
  1340. CTraceFilterSkipNPCs traceFilter( this, GetCollisionGroup() );
  1341. Vector up;
  1342. GetVectors( NULL, NULL, &up );
  1343. // FIXME: check number of slots?
  1344. for (int i = 0; i < m_pIk->m_target.Count(); i++)
  1345. {
  1346. trace_t trace;
  1347. CIKTarget *pTarget = &m_pIk->m_target[i];
  1348. if (!pTarget->IsActive())
  1349. continue;
  1350. switch( pTarget->type )
  1351. {
  1352. case IK_GROUND:
  1353. {
  1354. Vector estGround;
  1355. estGround = (pTarget->est.pos - GetAbsOrigin());
  1356. estGround = estGround - (estGround * up) * up;
  1357. estGround = GetAbsOrigin() + estGround + pTarget->est.floor * up;
  1358. Vector p1, p2;
  1359. VectorMA( estGround, pTarget->est.height, up, p1 );
  1360. VectorMA( estGround, -pTarget->est.height, up, p2 );
  1361. float r = MAX(pTarget->est.radius,1);
  1362. // don't IK to other characters
  1363. ray.Init( p1, p2, Vector(-r,-r,0), Vector(r,r,1) );
  1364. enginetrace->TraceRay( ray, MASK_SOLID, &traceFilter, &trace );
  1365. /*
  1366. if ( debugoverlay )
  1367. {
  1368. debugoverlay->AddBoxOverlay( p1, Vector(-r,-r,0), Vector(r,r,1), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 1.0f );
  1369. debugoverlay->AddBoxOverlay( trace.endpos, Vector(-r,-r,0), Vector(r,r,1), QAngle( 0, 0, 0 ), 255, 0, 0, 0, 1.0f );
  1370. debugoverlay->AddLineOverlay( p1, trace.endpos, 255, 0, 0, 0, 1.0f );
  1371. }
  1372. */
  1373. if (trace.startsolid)
  1374. {
  1375. ray.Init( pTarget->trace.hip, pTarget->est.pos, Vector(-r,-r,0), Vector(r,r,1) );
  1376. enginetrace->TraceRay( ray, MASK_SOLID, &traceFilter, &trace );
  1377. p1 = trace.endpos;
  1378. VectorMA( p1, - pTarget->est.height, up, p2 );
  1379. ray.Init( p1, p2, Vector(-r,-r,0), Vector(r,r,1) );
  1380. enginetrace->TraceRay( ray, MASK_SOLID, &traceFilter, &trace );
  1381. }
  1382. if (!trace.startsolid)
  1383. {
  1384. if (trace.DidHitWorld())
  1385. {
  1386. pTarget->SetPosWithNormalOffset( trace.endpos, trace.plane.normal );
  1387. pTarget->SetNormal( trace.plane.normal );
  1388. }
  1389. else
  1390. {
  1391. pTarget->SetPos( trace.endpos );
  1392. pTarget->SetAngles( GetAbsAngles() );
  1393. }
  1394. }
  1395. }
  1396. break;
  1397. case IK_ATTACHMENT:
  1398. {
  1399. // anything on the server?
  1400. }
  1401. break;
  1402. }
  1403. }
  1404. }
  1405. }
  1406. //-----------------------------------------------------------------------------
  1407. // Purpose: Clear out animation states that are invalidated with Teleport
  1408. //-----------------------------------------------------------------------------
  1409. void CBaseAnimating::Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity )
  1410. {
  1411. BaseClass::Teleport( newPosition, newAngles, newVelocity );
  1412. if (m_pIk)
  1413. {
  1414. m_pIk->ClearTargets( );
  1415. }
  1416. InitStepHeightAdjust();
  1417. }
  1418. //-----------------------------------------------------------------------------
  1419. // Purpose: build matrices first from the parent, then from the passed in arrays if the bone doesn't exist on the parent
  1420. //-----------------------------------------------------------------------------
  1421. void CBaseAnimating::BuildMatricesWithBoneMerge(
  1422. const CStudioHdr *pStudioHdr,
  1423. const QAngle& angles,
  1424. const Vector& origin,
  1425. const Vector pos[MAXSTUDIOBONES],
  1426. const Quaternion q[MAXSTUDIOBONES],
  1427. matrix3x4_t bonetoworld[MAXSTUDIOBONES],
  1428. CBaseAnimating *pParent,
  1429. CBoneCache *pParentCache
  1430. )
  1431. {
  1432. CStudioHdr *fhdr = pParent->GetModelPtr();
  1433. mstudiobone_t *pbones = pStudioHdr->pBone( 0 );
  1434. matrix3x4_t rotationmatrix; // model to world transformation
  1435. AngleMatrix( angles, origin, rotationmatrix);
  1436. for ( int i=0; i < pStudioHdr->numbones(); i++ )
  1437. {
  1438. // Now find the bone in the parent entity.
  1439. bool merged = false;
  1440. int parentBoneIndex = Studio_BoneIndexByName( fhdr, pbones[i].pszName() );
  1441. if ( parentBoneIndex >= 0 )
  1442. {
  1443. matrix3x4_t *pMat = pParentCache->GetCachedBone( parentBoneIndex );
  1444. if ( pMat )
  1445. {
  1446. MatrixCopy( *pMat, bonetoworld[ i ] );
  1447. merged = true;
  1448. }
  1449. }
  1450. if ( !merged )
  1451. {
  1452. // If we get down here, then the bone wasn't merged.
  1453. matrix3x4_t bonematrix;
  1454. QuaternionMatrix( q[i], pos[i], bonematrix );
  1455. if (pbones[i].parent == -1)
  1456. {
  1457. ConcatTransforms (rotationmatrix, bonematrix, bonetoworld[i]);
  1458. }
  1459. else
  1460. {
  1461. ConcatTransforms (bonetoworld[pbones[i].parent], bonematrix, bonetoworld[i]);
  1462. }
  1463. }
  1464. }
  1465. }
  1466. ConVar sv_pvsskipanimation( "sv_pvsskipanimation", "1", FCVAR_ARCHIVE, "Skips SetupBones when npc's are outside the PVS" );
  1467. ConVar ai_setupbones_debug( "ai_setupbones_debug", "0", 0, "Shows that bones that are setup every think" );
  1468. inline bool CBaseAnimating::CanSkipAnimation( void )
  1469. {
  1470. if ( !sv_pvsskipanimation.GetBool() )
  1471. return false;
  1472. CAI_BaseNPC *pNPC = MyNPCPointer();
  1473. if ( pNPC && !pNPC->HasCondition( COND_IN_PVS ) && ( m_fBoneCacheFlags & (BCF_NO_ANIMATION_SKIP | BCF_IS_IN_SPAWN) ) == false )
  1474. {
  1475. // If we have a player as a child, then we better setup our bones. If we don't,
  1476. // the PVS will be screwy.
  1477. return !DoesHavePlayerChild();
  1478. }
  1479. else
  1480. {
  1481. return false;
  1482. }
  1483. }
  1484. void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
  1485. {
  1486. AUTO_LOCK( m_BoneSetupMutex );
  1487. VPROF_BUDGET( "CBaseAnimating::SetupBones", VPROF_BUDGETGROUP_SERVER_ANIM );
  1488. MDLCACHE_CRITICAL_SECTION();
  1489. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  1490. CStudioHdr *pStudioHdr = GetModelPtr( );
  1491. if(!pStudioHdr)
  1492. {
  1493. Assert(!"CBaseAnimating::GetSkeleton() without a model");
  1494. return;
  1495. }
  1496. Assert( !IsEFlagSet( EFL_SETTING_UP_BONES ) );
  1497. AddEFlags( EFL_SETTING_UP_BONES );
  1498. Vector pos[MAXSTUDIOBONES];
  1499. Quaternion q[MAXSTUDIOBONES];
  1500. // adjust hit boxes based on IK driven offset
  1501. Vector adjOrigin = GetAbsOrigin() + Vector( 0, 0, m_flEstIkOffset );
  1502. if ( CanSkipAnimation() )
  1503. {
  1504. IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() );
  1505. boneSetup.InitPose( pos, q );
  1506. // Msg( "%.03f : %s:%s not in pvs\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
  1507. }
  1508. else
  1509. {
  1510. if ( m_pIk )
  1511. {
  1512. // FIXME: pass this into Studio_BuildMatrices to skip transforms
  1513. CBoneBitList boneComputed;
  1514. m_iIKCounter++;
  1515. m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask );
  1516. GetSkeleton( pStudioHdr, pos, q, boneMask );
  1517. m_pIk->UpdateTargets( pos, q, pBoneToWorld, boneComputed );
  1518. CalculateIKLocks( gpGlobals->curtime );
  1519. m_pIk->SolveDependencies( pos, q, pBoneToWorld, boneComputed );
  1520. }
  1521. else
  1522. {
  1523. // Msg( "%.03f : %s:%s\n", gpGlobals->curtime, GetClassname(), GetEntityName().ToCStr() );
  1524. GetSkeleton( pStudioHdr, pos, q, boneMask );
  1525. }
  1526. }
  1527. CBaseAnimating *pParent = dynamic_cast< CBaseAnimating* >( GetMoveParent() );
  1528. if ( pParent )
  1529. {
  1530. // We're doing bone merging, so do special stuff here.
  1531. CBoneCache *pParentCache = pParent->GetBoneCache();
  1532. if ( pParentCache )
  1533. {
  1534. BuildMatricesWithBoneMerge(
  1535. pStudioHdr,
  1536. GetAbsAngles(),
  1537. adjOrigin,
  1538. pos,
  1539. q,
  1540. pBoneToWorld,
  1541. pParent,
  1542. pParentCache );
  1543. RemoveEFlags( EFL_SETTING_UP_BONES );
  1544. if (ai_setupbones_debug.GetBool())
  1545. {
  1546. DrawRawSkeleton( pBoneToWorld, boneMask, true, 0.11 );
  1547. }
  1548. return;
  1549. }
  1550. }
  1551. Studio_BuildMatrices(
  1552. pStudioHdr,
  1553. GetAbsAngles(),
  1554. adjOrigin,
  1555. pos,
  1556. q,
  1557. -1,
  1558. GetModelScale(), // Scaling
  1559. pBoneToWorld,
  1560. boneMask );
  1561. if (ai_setupbones_debug.GetBool())
  1562. {
  1563. // Msg("%s:%s:%s (%x)\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask );
  1564. DrawRawSkeleton( pBoneToWorld, boneMask, true, 0.11 );
  1565. }
  1566. RemoveEFlags( EFL_SETTING_UP_BONES );
  1567. }
  1568. //=========================================================
  1569. //=========================================================
  1570. int CBaseAnimating::GetNumBones ( void )
  1571. {
  1572. CStudioHdr *pStudioHdr = GetModelPtr( );
  1573. if(pStudioHdr)
  1574. {
  1575. return pStudioHdr->numbones();
  1576. }
  1577. else
  1578. {
  1579. Assert(!"CBaseAnimating::GetNumBones: model missing");
  1580. return 0;
  1581. }
  1582. }
  1583. //=========================================================
  1584. //=========================================================
  1585. //-----------------------------------------------------------------------------
  1586. // Purpose: Returns index number of a given named attachment
  1587. // Input : name of attachment
  1588. // Output : attachment index number or -1 if attachment not found
  1589. //-----------------------------------------------------------------------------
  1590. int CBaseAnimating::LookupAttachment( const char *szName )
  1591. {
  1592. CStudioHdr *pStudioHdr = GetModelPtr( );
  1593. if (!pStudioHdr)
  1594. {
  1595. Assert(!"CBaseAnimating::LookupAttachment: model missing");
  1596. return 0;
  1597. }
  1598. // The +1 is to make attachment indices be 1-based (namely 0 == invalid or unused attachment)
  1599. return Studio_FindAttachment( pStudioHdr, szName ) + 1;
  1600. }
  1601. //-----------------------------------------------------------------------------
  1602. // Purpose: Returns the world location and world angles of an attachment
  1603. // Input : attachment name
  1604. // Output : location and angles
  1605. //-----------------------------------------------------------------------------
  1606. bool CBaseAnimating::GetAttachment( const char *szName, Vector &absOrigin, QAngle &absAngles )
  1607. {
  1608. return GetAttachment( LookupAttachment( szName ), absOrigin, absAngles );
  1609. }
  1610. //-----------------------------------------------------------------------------
  1611. // Purpose: Returns the world location and world angles of an attachment
  1612. // Input : attachment index
  1613. // Output : location and angles
  1614. //-----------------------------------------------------------------------------
  1615. bool CBaseAnimating::GetAttachment ( int iAttachment, Vector &absOrigin, QAngle &absAngles )
  1616. {
  1617. matrix3x4_t attachmentToWorld;
  1618. bool bRet = GetAttachment( iAttachment, attachmentToWorld );
  1619. MatrixAngles( attachmentToWorld, absAngles, absOrigin );
  1620. return bRet;
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose: Returns the world location and world angles of an attachment
  1624. // Input : attachment index
  1625. // Output : location and angles
  1626. //-----------------------------------------------------------------------------
  1627. bool CBaseAnimating::GetAttachment( int iAttachment, matrix3x4_t &attachmentToWorld )
  1628. {
  1629. CStudioHdr *pStudioHdr = GetModelPtr( );
  1630. if (!pStudioHdr)
  1631. {
  1632. MatrixCopy(EntityToWorldTransform(), attachmentToWorld);
  1633. AssertOnce(!"CBaseAnimating::GetAttachment: model missing");
  1634. return false;
  1635. }
  1636. if (iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments())
  1637. {
  1638. MatrixCopy(EntityToWorldTransform(), attachmentToWorld);
  1639. // Assert(!"CBaseAnimating::GetAttachment: invalid attachment index");
  1640. return false;
  1641. }
  1642. const mstudioattachment_t &pattachment = pStudioHdr->pAttachment( iAttachment-1 );
  1643. int iBone = pStudioHdr->GetAttachmentBone( iAttachment-1 );
  1644. matrix3x4_t bonetoworld;
  1645. GetBoneTransform( iBone, bonetoworld );
  1646. if ( (pattachment.flags & ATTACHMENT_FLAG_WORLD_ALIGN) == 0 )
  1647. {
  1648. ConcatTransforms( bonetoworld, pattachment.local, attachmentToWorld );
  1649. }
  1650. else
  1651. {
  1652. Vector vecLocalBonePos, vecWorldBonePos;
  1653. MatrixGetColumn( pattachment.local, 3, vecLocalBonePos );
  1654. VectorTransform( vecLocalBonePos, bonetoworld, vecWorldBonePos );
  1655. SetIdentityMatrix( attachmentToWorld );
  1656. MatrixSetColumn( vecWorldBonePos, 3, attachmentToWorld );
  1657. }
  1658. return true;
  1659. }
  1660. // gets the bone for an attachment
  1661. int CBaseAnimating::GetAttachmentBone( int iAttachment )
  1662. {
  1663. CStudioHdr *pStudioHdr = GetModelPtr( );
  1664. if (!pStudioHdr || iAttachment < 1 || iAttachment > pStudioHdr->GetNumAttachments() )
  1665. {
  1666. AssertOnce(pStudioHdr && "CBaseAnimating::GetAttachment: model missing");
  1667. return 0;
  1668. }
  1669. return pStudioHdr->GetAttachmentBone( iAttachment-1 );
  1670. }
  1671. //-----------------------------------------------------------------------------
  1672. // Purpose: Returns the world location of an attachment
  1673. // Input : attachment index
  1674. // Output : location and angles
  1675. //-----------------------------------------------------------------------------
  1676. bool CBaseAnimating::GetAttachment( const char *szName, Vector &absOrigin, Vector *forward, Vector *right, Vector *up )
  1677. {
  1678. return GetAttachment( LookupAttachment( szName ), absOrigin, forward, right, up );
  1679. }
  1680. bool CBaseAnimating::GetAttachment( int iAttachment, Vector &absOrigin, Vector *forward, Vector *right, Vector *up )
  1681. {
  1682. matrix3x4_t attachmentToWorld;
  1683. bool bRet = GetAttachment( iAttachment, attachmentToWorld );
  1684. MatrixPosition( attachmentToWorld, absOrigin );
  1685. if (forward)
  1686. {
  1687. MatrixGetColumn( attachmentToWorld, 0, forward );
  1688. }
  1689. if (right)
  1690. {
  1691. MatrixGetColumn( attachmentToWorld, 1, right );
  1692. }
  1693. if (up)
  1694. {
  1695. MatrixGetColumn( attachmentToWorld, 2, up );
  1696. }
  1697. return bRet;
  1698. }
  1699. //-----------------------------------------------------------------------------
  1700. // Returns the attachment in local space
  1701. //-----------------------------------------------------------------------------
  1702. bool CBaseAnimating::GetAttachmentLocal( const char *szName, Vector &origin, QAngle &angles )
  1703. {
  1704. return GetAttachmentLocal( LookupAttachment( szName ), origin, angles );
  1705. }
  1706. bool CBaseAnimating::GetAttachmentLocal( int iAttachment, Vector &origin, QAngle &angles )
  1707. {
  1708. matrix3x4_t attachmentToEntity;
  1709. bool bRet = GetAttachmentLocal( iAttachment, attachmentToEntity );
  1710. MatrixAngles( attachmentToEntity, angles, origin );
  1711. return bRet;
  1712. }
  1713. bool CBaseAnimating::GetAttachmentLocal( int iAttachment, matrix3x4_t &attachmentToLocal )
  1714. {
  1715. matrix3x4_t attachmentToWorld;
  1716. bool bRet = GetAttachment(iAttachment, attachmentToWorld);
  1717. matrix3x4_t worldToEntity;
  1718. MatrixInvert( EntityToWorldTransform(), worldToEntity );
  1719. ConcatTransforms( worldToEntity, attachmentToWorld, attachmentToLocal );
  1720. return bRet;
  1721. }
  1722. //=========================================================
  1723. //=========================================================
  1724. void CBaseAnimating::GetEyeballs( Vector &origin, QAngle &angles )
  1725. {
  1726. CStudioHdr *pStudioHdr = GetModelPtr( );
  1727. if (!pStudioHdr)
  1728. {
  1729. Assert(!"CBaseAnimating::GetAttachment: model missing");
  1730. return;
  1731. }
  1732. for (int iBodypart = 0; iBodypart < pStudioHdr->numbodyparts(); iBodypart++)
  1733. {
  1734. mstudiobodyparts_t *pBodypart = pStudioHdr->pBodypart( iBodypart );
  1735. for (int iModel = 0; iModel < pBodypart->nummodels; iModel++)
  1736. {
  1737. mstudiomodel_t *pModel = pBodypart->pModel( iModel );
  1738. for (int iEyeball = 0; iEyeball < pModel->numeyeballs; iEyeball++)
  1739. {
  1740. mstudioeyeball_t *pEyeball = pModel->pEyeball( iEyeball );
  1741. matrix3x4_t bonetoworld;
  1742. GetBoneTransform( pEyeball->bone, bonetoworld );
  1743. VectorTransform( pEyeball->org, bonetoworld, origin );
  1744. MatrixAngles( bonetoworld, angles ); // ???
  1745. }
  1746. }
  1747. }
  1748. }
  1749. //=========================================================
  1750. //=========================================================
  1751. int CBaseAnimating::FindTransitionSequence( int iCurrentSequence, int iGoalSequence, int *piDir )
  1752. {
  1753. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  1754. if (piDir == NULL)
  1755. {
  1756. int iDir = 1;
  1757. int sequence = ::FindTransitionSequence( GetModelPtr(), iCurrentSequence, iGoalSequence, &iDir );
  1758. if (iDir != 1)
  1759. return -1;
  1760. else
  1761. return sequence;
  1762. }
  1763. return ::FindTransitionSequence( GetModelPtr(), iCurrentSequence, iGoalSequence, piDir );
  1764. }
  1765. bool CBaseAnimating::GotoSequence( int iCurrentSequence, float flCurrentCycle, float flCurrentRate, int iGoalSequence, int &nNextSequence, float &flNextCycle, int &iNextDir )
  1766. {
  1767. return ::GotoSequence( GetModelPtr(), iCurrentSequence, flCurrentCycle, flCurrentRate, iGoalSequence, nNextSequence, flNextCycle, iNextDir );
  1768. }
  1769. int CBaseAnimating::GetEntryNode( int iSequence )
  1770. {
  1771. CStudioHdr *pstudiohdr = GetModelPtr();
  1772. if (! pstudiohdr)
  1773. return 0;
  1774. return pstudiohdr->EntryNode( iSequence );
  1775. }
  1776. int CBaseAnimating::GetExitNode( int iSequence )
  1777. {
  1778. CStudioHdr *pstudiohdr = GetModelPtr();
  1779. if (! pstudiohdr)
  1780. return 0;
  1781. return pstudiohdr->ExitNode( iSequence );
  1782. }
  1783. //=========================================================
  1784. //=========================================================
  1785. void CBaseAnimating::SetBodygroup( int iGroup, int iValue )
  1786. {
  1787. // SetBodygroup is not supported on pending dynamic models. Wait for it to load!
  1788. // XXX TODO we could buffer up the group and value if we really needed to. -henryg
  1789. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  1790. int newBody = m_nBody;
  1791. ::SetBodygroup( GetModelPtr( ), newBody, iGroup, iValue );
  1792. m_nBody = newBody;
  1793. }
  1794. int CBaseAnimating::GetBodygroup( int iGroup )
  1795. {
  1796. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1797. return IsDynamicModelLoading() ? 0 : ::GetBodygroup( GetModelPtr( ), m_nBody, iGroup );
  1798. }
  1799. const char *CBaseAnimating::GetBodygroupName( int iGroup )
  1800. {
  1801. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1802. return IsDynamicModelLoading() ? "" : ::GetBodygroupName( GetModelPtr( ), iGroup );
  1803. }
  1804. int CBaseAnimating::FindBodygroupByName( const char *name )
  1805. {
  1806. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1807. return IsDynamicModelLoading() ? -1 : ::FindBodygroupByName( GetModelPtr( ), name );
  1808. }
  1809. int CBaseAnimating::GetBodygroupCount( int iGroup )
  1810. {
  1811. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1812. return IsDynamicModelLoading() ? 0 : ::GetBodygroupCount( GetModelPtr( ), iGroup );
  1813. }
  1814. int CBaseAnimating::GetNumBodyGroups( void )
  1815. {
  1816. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1817. return IsDynamicModelLoading() ? 0 : ::GetNumBodyGroups( GetModelPtr( ) );
  1818. }
  1819. int CBaseAnimating::ExtractBbox( int sequence, Vector& mins, Vector& maxs )
  1820. {
  1821. Assert( IsDynamicModelLoading() || GetModelPtr() );
  1822. return IsDynamicModelLoading() ? 0 : ::ExtractBbox( GetModelPtr( ), sequence, mins, maxs );
  1823. }
  1824. //=========================================================
  1825. //=========================================================
  1826. void CBaseAnimating::SetSequenceBox( void )
  1827. {
  1828. Vector mins, maxs;
  1829. // Get sequence bbox
  1830. if ( ExtractBbox( GetSequence(), mins, maxs ) )
  1831. {
  1832. // expand box for rotation
  1833. // find min / max for rotations
  1834. float yaw = GetLocalAngles().y * (M_PI / 180.0);
  1835. Vector xvector, yvector;
  1836. xvector.x = cos(yaw);
  1837. xvector.y = sin(yaw);
  1838. yvector.x = -sin(yaw);
  1839. yvector.y = cos(yaw);
  1840. Vector bounds[2];
  1841. bounds[0] = mins;
  1842. bounds[1] = maxs;
  1843. Vector rmin( 9999, 9999, 9999 );
  1844. Vector rmax( -9999, -9999, -9999 );
  1845. Vector base, transformed;
  1846. for (int i = 0; i <= 1; i++ )
  1847. {
  1848. base.x = bounds[i].x;
  1849. for ( int j = 0; j <= 1; j++ )
  1850. {
  1851. base.y = bounds[j].y;
  1852. for ( int k = 0; k <= 1; k++ )
  1853. {
  1854. base.z = bounds[k].z;
  1855. // transform the point
  1856. transformed.x = xvector.x*base.x + yvector.x*base.y;
  1857. transformed.y = xvector.y*base.x + yvector.y*base.y;
  1858. transformed.z = base.z;
  1859. for ( int l = 0; l < 3; l++ )
  1860. {
  1861. if (transformed[l] < rmin[l])
  1862. rmin[l] = transformed[l];
  1863. if (transformed[l] > rmax[l])
  1864. rmax[l] = transformed[l];
  1865. }
  1866. }
  1867. }
  1868. }
  1869. rmin.z = 0;
  1870. rmax.z = rmin.z + 1;
  1871. UTIL_SetSize( this, rmin, rmax );
  1872. }
  1873. }
  1874. //=========================================================
  1875. //=========================================================
  1876. int CBaseAnimating::RegisterPrivateActivity( const char *pszActivityName )
  1877. {
  1878. return ActivityList_RegisterPrivateActivity( pszActivityName );
  1879. }
  1880. //-----------------------------------------------------------------------------
  1881. // Purpose: Notifies the console that this entity could not retrieve an
  1882. // animation sequence for the specified activity. This probably means
  1883. // there's a typo in the model QC file, or the sequence is missing
  1884. // entirely.
  1885. //
  1886. //
  1887. // Input : iActivity - The activity that failed to resolve to a sequence.
  1888. //
  1889. //
  1890. // NOTE : IMPORTANT - Something needs to be done so that private activities
  1891. // (which are allowed to collide in the activity list) remember each
  1892. // entity that registered an activity there, and the activity name
  1893. // each character registered.
  1894. //-----------------------------------------------------------------------------
  1895. void CBaseAnimating::ReportMissingActivity( int iActivity )
  1896. {
  1897. Msg( "%s has no sequence for act:%s\n", GetClassname(), ActivityList_NameForIndex(iActivity) );
  1898. }
  1899. LocalFlexController_t CBaseAnimating::GetNumFlexControllers( void )
  1900. {
  1901. CStudioHdr *pstudiohdr = GetModelPtr( );
  1902. if (! pstudiohdr)
  1903. return LocalFlexController_t(0);
  1904. return pstudiohdr->numflexcontrollers();
  1905. }
  1906. const char *CBaseAnimating::GetFlexDescFacs( int iFlexDesc )
  1907. {
  1908. CStudioHdr *pstudiohdr = GetModelPtr( );
  1909. if (! pstudiohdr)
  1910. return 0;
  1911. mstudioflexdesc_t *pflexdesc = pstudiohdr->pFlexdesc( iFlexDesc );
  1912. return pflexdesc->pszFACS( );
  1913. }
  1914. const char *CBaseAnimating::GetFlexControllerName( LocalFlexController_t iFlexController )
  1915. {
  1916. CStudioHdr *pstudiohdr = GetModelPtr( );
  1917. if (! pstudiohdr)
  1918. return 0;
  1919. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( iFlexController );
  1920. return pflexcontroller->pszName( );
  1921. }
  1922. const char *CBaseAnimating::GetFlexControllerType( LocalFlexController_t iFlexController )
  1923. {
  1924. CStudioHdr *pstudiohdr = GetModelPtr( );
  1925. if (! pstudiohdr)
  1926. return 0;
  1927. mstudioflexcontroller_t *pflexcontroller = pstudiohdr->pFlexcontroller( iFlexController );
  1928. return pflexcontroller->pszType( );
  1929. }
  1930. //-----------------------------------------------------------------------------
  1931. // Purpose: Converts the ground speed of the animating entity into a true velocity
  1932. // Output : Vector - velocity of the character at its current m_flGroundSpeed
  1933. //-----------------------------------------------------------------------------
  1934. Vector CBaseAnimating::GetGroundSpeedVelocity( void )
  1935. {
  1936. CStudioHdr *pstudiohdr = GetModelPtr();
  1937. if (!pstudiohdr)
  1938. return vec3_origin;
  1939. QAngle vecAngles;
  1940. Vector vecVelocity;
  1941. vecAngles.y = GetSequenceMoveYaw( GetSequence() );
  1942. vecAngles.x = 0;
  1943. vecAngles.z = 0;
  1944. vecAngles.y += GetLocalAngles().y;
  1945. AngleVectors( vecAngles, &vecVelocity );
  1946. vecVelocity = vecVelocity * m_flGroundSpeed;
  1947. return vecVelocity;
  1948. }
  1949. //-----------------------------------------------------------------------------
  1950. // Purpose:
  1951. // Output :
  1952. //-----------------------------------------------------------------------------
  1953. float CBaseAnimating::GetInstantaneousVelocity( float flInterval )
  1954. {
  1955. CStudioHdr *pstudiohdr = GetModelPtr( );
  1956. if (! pstudiohdr)
  1957. return 0;
  1958. // FIXME: someone needs to check for last frame, etc.
  1959. float flNextCycle = GetCycle() + flInterval * GetSequenceCycleRate( GetSequence() ) * m_flPlaybackRate;
  1960. Vector vecVelocity;
  1961. Studio_SeqVelocity( pstudiohdr, GetSequence(), flNextCycle, GetPoseParameterArray(), vecVelocity );
  1962. vecVelocity *= m_flPlaybackRate;
  1963. return vecVelocity.Length();
  1964. }
  1965. //-----------------------------------------------------------------------------
  1966. // Purpose:
  1967. // Output :
  1968. //-----------------------------------------------------------------------------
  1969. float CBaseAnimating::GetEntryVelocity( int iSequence )
  1970. {
  1971. CStudioHdr *pstudiohdr = GetModelPtr( );
  1972. if (! pstudiohdr)
  1973. return 0;
  1974. Vector vecVelocity;
  1975. Studio_SeqVelocity( pstudiohdr, iSequence, 0.0, GetPoseParameterArray(), vecVelocity );
  1976. return vecVelocity.Length();
  1977. }
  1978. float CBaseAnimating::GetExitVelocity( int iSequence )
  1979. {
  1980. CStudioHdr *pstudiohdr = GetModelPtr( );
  1981. if (! pstudiohdr)
  1982. return 0;
  1983. Vector vecVelocity;
  1984. Studio_SeqVelocity( pstudiohdr, iSequence, 1.0, GetPoseParameterArray(), vecVelocity );
  1985. return vecVelocity.Length();
  1986. }
  1987. //-----------------------------------------------------------------------------
  1988. // Purpose:
  1989. // Output :
  1990. //-----------------------------------------------------------------------------
  1991. bool CBaseAnimating::GetIntervalMovement( float flIntervalUsed, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles )
  1992. {
  1993. CStudioHdr *pstudiohdr = GetModelPtr( );
  1994. if (! pstudiohdr || !pstudiohdr->SequencesAvailable())
  1995. return false;
  1996. float flComputedCycleRate = GetSequenceCycleRate( GetSequence() );
  1997. float flNextCycle = GetCycle() + flIntervalUsed * flComputedCycleRate * m_flPlaybackRate;
  1998. if ((!m_bSequenceLoops) && flNextCycle > 1.0)
  1999. {
  2000. flIntervalUsed = GetCycle() / (flComputedCycleRate * m_flPlaybackRate);
  2001. flNextCycle = 1.0;
  2002. bMoveSeqFinished = true;
  2003. }
  2004. else
  2005. {
  2006. bMoveSeqFinished = false;
  2007. }
  2008. Vector deltaPos;
  2009. QAngle deltaAngles;
  2010. if (Studio_SeqMovement( pstudiohdr, GetSequence(), GetCycle(), flNextCycle, GetPoseParameterArray(), deltaPos, deltaAngles ))
  2011. {
  2012. VectorYawRotate( deltaPos, GetLocalAngles().y, deltaPos );
  2013. newPosition = GetLocalOrigin() + deltaPos;
  2014. newAngles.Init();
  2015. newAngles.y = GetLocalAngles().y + deltaAngles.y;
  2016. return true;
  2017. }
  2018. else
  2019. {
  2020. newPosition = GetLocalOrigin();
  2021. newAngles = GetLocalAngles();
  2022. return false;
  2023. }
  2024. }
  2025. //-----------------------------------------------------------------------------
  2026. // Purpose:
  2027. // Output :
  2028. //-----------------------------------------------------------------------------
  2029. bool CBaseAnimating::GetSequenceMovement( int nSequence, float fromCycle, float toCycle, Vector &deltaPosition, QAngle &deltaAngles )
  2030. {
  2031. CStudioHdr *pstudiohdr = GetModelPtr( );
  2032. if (! pstudiohdr)
  2033. return false;
  2034. return Studio_SeqMovement( pstudiohdr, nSequence, fromCycle, toCycle, GetPoseParameterArray(), deltaPosition, deltaAngles );
  2035. }
  2036. //-----------------------------------------------------------------------------
  2037. // Purpose: find frame where they animation has moved a given distance.
  2038. // Output :
  2039. //-----------------------------------------------------------------------------
  2040. float CBaseAnimating::GetMovementFrame( float flDist )
  2041. {
  2042. CStudioHdr *pstudiohdr = GetModelPtr( );
  2043. if (! pstudiohdr)
  2044. return 0;
  2045. float t = Studio_FindSeqDistance( pstudiohdr, GetSequence(), GetPoseParameterArray(), flDist );
  2046. return t;
  2047. }
  2048. //-----------------------------------------------------------------------------
  2049. // Purpose: does a specific sequence have movement?
  2050. // Output :
  2051. //-----------------------------------------------------------------------------
  2052. bool CBaseAnimating::HasMovement( int iSequence )
  2053. {
  2054. CStudioHdr *pstudiohdr = GetModelPtr( );
  2055. if (! pstudiohdr)
  2056. return false;
  2057. // FIXME: this needs to check to see if there are keys, and the object is walking
  2058. Vector deltaPos;
  2059. QAngle deltaAngles;
  2060. if (Studio_SeqMovement( pstudiohdr, iSequence, 0.0f, 1.0f, GetPoseParameterArray(), deltaPos, deltaAngles ))
  2061. {
  2062. return true;
  2063. }
  2064. return false;
  2065. }
  2066. //-----------------------------------------------------------------------------
  2067. // Purpose:
  2068. // Input : *szModelName -
  2069. //-----------------------------------------------------------------------------
  2070. void CBaseAnimating::SetModel( const char *szModelName )
  2071. {
  2072. MDLCACHE_CRITICAL_SECTION();
  2073. // delete exiting studio model container
  2074. UnlockStudioHdr();
  2075. delete m_pStudioHdr;
  2076. m_pStudioHdr = NULL;
  2077. if ( szModelName[0] )
  2078. {
  2079. int modelIndex = modelinfo->GetModelIndex( szModelName );
  2080. const model_t *model = modelinfo->GetModel( modelIndex );
  2081. if ( model && ( modelinfo->GetModelType( model ) != mod_studio ) )
  2082. {
  2083. Msg( "Setting CBaseAnimating to non-studio model %s (type:%i)\n", szModelName, modelinfo->GetModelType( model ) );
  2084. }
  2085. }
  2086. if ( m_boneCacheHandle )
  2087. {
  2088. Studio_DestroyBoneCache( m_boneCacheHandle );
  2089. m_boneCacheHandle = 0;
  2090. }
  2091. UTIL_SetModel( this, szModelName );
  2092. InitBoneControllers( );
  2093. SetSequence( 0 );
  2094. PopulatePoseParameters();
  2095. }
  2096. //-----------------------------------------------------------------------------
  2097. // Purpose:
  2098. // Input :
  2099. //-----------------------------------------------------------------------------
  2100. void CBaseAnimating::LockStudioHdr()
  2101. {
  2102. AUTO_LOCK( m_StudioHdrInitLock );
  2103. const model_t *mdl = GetModel();
  2104. if (mdl)
  2105. {
  2106. MDLHandle_t hStudioHdr = modelinfo->GetCacheHandle( mdl );
  2107. if ( hStudioHdr != MDLHANDLE_INVALID )
  2108. {
  2109. const studiohdr_t *pStudioHdr = mdlcache->LockStudioHdr( hStudioHdr );
  2110. CStudioHdr *pStudioHdrContainer = NULL;
  2111. if ( !m_pStudioHdr )
  2112. {
  2113. if ( pStudioHdr )
  2114. {
  2115. pStudioHdrContainer = new CStudioHdr;
  2116. pStudioHdrContainer->Init( pStudioHdr, mdlcache );
  2117. }
  2118. }
  2119. else
  2120. {
  2121. pStudioHdrContainer = m_pStudioHdr;
  2122. }
  2123. Assert( ( pStudioHdr == NULL && pStudioHdrContainer == NULL ) || pStudioHdrContainer->GetRenderHdr() == pStudioHdr );
  2124. if ( pStudioHdrContainer && pStudioHdrContainer->GetVirtualModel() )
  2125. {
  2126. MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(pStudioHdrContainer->GetRenderHdr()->virtualModel)&0xffff;
  2127. mdlcache->LockStudioHdr( hVirtualModel );
  2128. }
  2129. m_pStudioHdr = pStudioHdrContainer; // must be last to ensure virtual model correctly set up
  2130. }
  2131. }
  2132. }
  2133. void CBaseAnimating::UnlockStudioHdr()
  2134. {
  2135. if ( m_pStudioHdr )
  2136. {
  2137. const model_t *mdl = GetModel();
  2138. if (mdl)
  2139. {
  2140. mdlcache->UnlockStudioHdr( modelinfo->GetCacheHandle( mdl ) );
  2141. if ( m_pStudioHdr->GetVirtualModel() )
  2142. {
  2143. MDLHandle_t hVirtualModel = (MDLHandle_t)(int)(m_pStudioHdr->GetRenderHdr()->virtualModel)&0xffff;
  2144. mdlcache->UnlockStudioHdr( hVirtualModel );
  2145. }
  2146. }
  2147. }
  2148. }
  2149. //-----------------------------------------------------------------------------
  2150. // Purpose: return the index to the shared bone cache
  2151. // Output :
  2152. //-----------------------------------------------------------------------------
  2153. CBoneCache *CBaseAnimating::GetBoneCache( void )
  2154. {
  2155. CStudioHdr *pStudioHdr = GetModelPtr( );
  2156. Assert(pStudioHdr);
  2157. CBoneCache *pcache = Studio_GetBoneCache( m_boneCacheHandle );
  2158. int boneMask = BONE_USED_BY_HITBOX | BONE_USED_BY_ATTACHMENT;
  2159. // TF queries these bones to position weapons when players are killed
  2160. #if defined( TF_DLL )
  2161. boneMask |= BONE_USED_BY_BONE_MERGE;
  2162. #endif
  2163. if ( pcache )
  2164. {
  2165. if ( pcache->IsValid( gpGlobals->curtime ) && (pcache->m_boneMask & boneMask) == boneMask && pcache->m_timeValid <= gpGlobals->curtime)
  2166. {
  2167. // Msg("%s:%s:%s (%x:%x:%8.4f) cache\n", GetClassname(), GetDebugName(), STRING(GetModelName()), boneMask, pcache->m_boneMask, pcache->m_timeValid );
  2168. // in memory and still valid, use it!
  2169. return pcache;
  2170. }
  2171. // in memory, but missing some of the bone masks
  2172. if ( (pcache->m_boneMask & boneMask) != boneMask )
  2173. {
  2174. Studio_DestroyBoneCache( m_boneCacheHandle );
  2175. m_boneCacheHandle = 0;
  2176. pcache = NULL;
  2177. }
  2178. }
  2179. matrix3x4_t bonetoworld[MAXSTUDIOBONES];
  2180. SetupBones( bonetoworld, boneMask );
  2181. if ( pcache )
  2182. {
  2183. // still in memory but out of date, refresh the bones.
  2184. pcache->UpdateBones( bonetoworld, pStudioHdr->numbones(), gpGlobals->curtime );
  2185. }
  2186. else
  2187. {
  2188. bonecacheparams_t params;
  2189. params.pStudioHdr = pStudioHdr;
  2190. params.pBoneToWorld = bonetoworld;
  2191. params.curtime = gpGlobals->curtime;
  2192. params.boneMask = boneMask;
  2193. m_boneCacheHandle = Studio_CreateBoneCache( params );
  2194. pcache = Studio_GetBoneCache( m_boneCacheHandle );
  2195. }
  2196. Assert(pcache);
  2197. return pcache;
  2198. }
  2199. void CBaseAnimating::InvalidateBoneCache( void )
  2200. {
  2201. Studio_InvalidateBoneCache( m_boneCacheHandle );
  2202. }
  2203. bool CBaseAnimating::TestCollision( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  2204. {
  2205. // Return a special case for scaled physics objects
  2206. if ( GetModelScale() != 1.0f )
  2207. {
  2208. IPhysicsObject *pPhysObject = VPhysicsGetObject();
  2209. Vector vecPosition;
  2210. QAngle vecAngles;
  2211. pPhysObject->GetPosition( &vecPosition, &vecAngles );
  2212. const CPhysCollide *pScaledCollide = pPhysObject->GetCollide();
  2213. physcollision->TraceBox( ray, pScaledCollide, vecPosition, vecAngles, &tr );
  2214. return tr.DidHit();
  2215. }
  2216. if ( IsSolidFlagSet( FSOLID_CUSTOMRAYTEST ))
  2217. {
  2218. if (!TestHitboxes( ray, fContentsMask, tr ))
  2219. return true;
  2220. return tr.DidHit();
  2221. }
  2222. // We shouldn't get here.
  2223. Assert(0);
  2224. return false;
  2225. }
  2226. bool CBaseAnimating::TestHitboxes( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
  2227. {
  2228. CStudioHdr *pStudioHdr = GetModelPtr( );
  2229. if (!pStudioHdr)
  2230. {
  2231. Assert(!"CBaseAnimating::GetBonePosition: model missing");
  2232. return false;
  2233. }
  2234. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  2235. if ( !set || !set->numhitboxes )
  2236. return false;
  2237. CBoneCache *pcache = GetBoneCache( );
  2238. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  2239. pcache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() );
  2240. if ( TraceToStudio( physprops, ray, pStudioHdr, set, hitboxbones, fContentsMask, GetAbsOrigin(), GetModelScale(), tr ) )
  2241. {
  2242. mstudiobbox_t *pbox = set->pHitbox( tr.hitbox );
  2243. mstudiobone_t *pBone = pStudioHdr->pBone(pbox->bone);
  2244. tr.surface.name = "**studio**";
  2245. tr.surface.flags = SURF_HITBOX;
  2246. tr.surface.surfaceProps = physprops->GetSurfaceIndex( pBone->pszSurfaceProp() );
  2247. }
  2248. return true;
  2249. }
  2250. void CBaseAnimating::InitBoneControllers ( void ) // FIXME: rename
  2251. {
  2252. int i;
  2253. CStudioHdr *pStudioHdr = GetModelPtr( );
  2254. if (!pStudioHdr)
  2255. return;
  2256. int nBoneControllerCount = pStudioHdr->numbonecontrollers();
  2257. if ( nBoneControllerCount > NUM_BONECTRLS )
  2258. {
  2259. nBoneControllerCount = NUM_BONECTRLS;
  2260. #ifdef _DEBUG
  2261. Warning( "Model %s has too many bone controllers! (Max %d allowed)\n", pStudioHdr->pszName(), NUM_BONECTRLS );
  2262. #endif
  2263. }
  2264. for (i = 0; i < nBoneControllerCount; i++)
  2265. {
  2266. SetBoneController( i, 0.0 );
  2267. }
  2268. Assert( pStudioHdr->SequencesAvailable() );
  2269. if ( pStudioHdr->SequencesAvailable() )
  2270. {
  2271. for (i = 0; i < pStudioHdr->GetNumPoseParameters(); i++)
  2272. {
  2273. SetPoseParameter( i, 0.0 );
  2274. }
  2275. }
  2276. }
  2277. //=========================================================
  2278. //=========================================================
  2279. float CBaseAnimating::SetBoneController ( int iController, float flValue )
  2280. {
  2281. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  2282. CStudioHdr *pmodel = (CStudioHdr*)GetModelPtr();
  2283. Assert(iController >= 0 && iController < NUM_BONECTRLS);
  2284. float newValue;
  2285. float retVal = Studio_SetController( pmodel, iController, flValue, newValue );
  2286. m_flEncodedController.Set( iController, newValue );
  2287. return retVal;
  2288. }
  2289. //=========================================================
  2290. //=========================================================
  2291. float CBaseAnimating::GetBoneController ( int iController )
  2292. {
  2293. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  2294. CStudioHdr *pmodel = (CStudioHdr*)GetModelPtr();
  2295. return Studio_GetController( pmodel, iController, m_flEncodedController[iController] );
  2296. }
  2297. //------------------------------------------------------------------------------
  2298. // Purpose : Returns velcocity of the NPC from it's animation.
  2299. // If physically simulated gets velocity from physics object
  2300. // Input :
  2301. // Output :
  2302. //------------------------------------------------------------------------------
  2303. void CBaseAnimating::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
  2304. {
  2305. if ( GetMoveType() == MOVETYPE_VPHYSICS )
  2306. {
  2307. BaseClass::GetVelocity(vVelocity,vAngVelocity);
  2308. }
  2309. else if ( !(GetFlags() & FL_ONGROUND) )
  2310. {
  2311. BaseClass::GetVelocity(vVelocity,vAngVelocity);
  2312. }
  2313. else
  2314. {
  2315. if (vVelocity != NULL)
  2316. {
  2317. Vector vRawVel;
  2318. GetSequenceLinearMotion( GetSequence(), &vRawVel );
  2319. // Build a rotation matrix from NPC orientation
  2320. matrix3x4_t fRotateMatrix;
  2321. AngleMatrix(GetLocalAngles(), fRotateMatrix);
  2322. VectorRotate( vRawVel, fRotateMatrix, *vVelocity);
  2323. }
  2324. if (vAngVelocity != NULL)
  2325. {
  2326. QAngle tmp = GetLocalAngularVelocity();
  2327. QAngleToAngularImpulse( tmp, *vAngVelocity );
  2328. }
  2329. }
  2330. }
  2331. //=========================================================
  2332. //=========================================================
  2333. void CBaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaternion q[], int boneMask )
  2334. {
  2335. if(!pStudioHdr)
  2336. {
  2337. Assert(!"CBaseAnimating::GetSkeleton() without a model");
  2338. return;
  2339. }
  2340. IBoneSetup boneSetup( pStudioHdr, boneMask, GetPoseParameterArray() );
  2341. boneSetup.InitPose( pos, q );
  2342. boneSetup.AccumulatePose( pos, q, GetSequence(), GetCycle(), 1.0, gpGlobals->curtime, m_pIk );
  2343. if ( m_pIk )
  2344. {
  2345. CIKContext auto_ik;
  2346. auto_ik.Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, 0, boneMask );
  2347. boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik );
  2348. }
  2349. else
  2350. {
  2351. boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, NULL );
  2352. }
  2353. boneSetup.CalcBoneAdj( pos, q, GetEncodedControllerArray() );
  2354. }
  2355. int CBaseAnimating::DrawDebugTextOverlays(void)
  2356. {
  2357. int text_offset = BaseClass::DrawDebugTextOverlays();
  2358. if (m_debugOverlays & OVERLAY_TEXT_BIT)
  2359. {
  2360. // ----------------
  2361. // Print Look time
  2362. // ----------------
  2363. char tempstr[1024];
  2364. Q_snprintf(tempstr, sizeof(tempstr), "Sequence: (%3d) %s",GetSequence(), GetSequenceName( GetSequence() ) );
  2365. EntityText(text_offset,tempstr,0);
  2366. text_offset++;
  2367. const char *pActname = GetSequenceActivityName(GetSequence());
  2368. if ( pActname && strlen(pActname) )
  2369. {
  2370. Q_snprintf(tempstr, sizeof(tempstr), "Activity %s", pActname );
  2371. EntityText(text_offset,tempstr,0);
  2372. text_offset++;
  2373. }
  2374. Q_snprintf(tempstr, sizeof(tempstr), "Cycle: %.5f (%.5f)", (float)GetCycle(), m_flAnimTime.Get() );
  2375. EntityText(text_offset,tempstr,0);
  2376. text_offset++;
  2377. }
  2378. // Visualize attachment points
  2379. if ( m_debugOverlays & OVERLAY_ATTACHMENTS_BIT )
  2380. {
  2381. CStudioHdr *pStudioHdr = GetModelPtr();
  2382. if ( pStudioHdr )
  2383. {
  2384. Vector vecPos, vecForward, vecRight, vecUp;
  2385. char tempstr[256];
  2386. // Iterate all the stored attachments
  2387. for ( int i = 1; i <= pStudioHdr->GetNumAttachments(); i++ )
  2388. {
  2389. GetAttachment( i, vecPos, &vecForward, &vecRight, &vecUp );
  2390. // Red - forward, green - right, blue - up
  2391. NDebugOverlay::Line( vecPos, vecPos + ( vecForward * 4.0f ), 255, 0, 0, true, 0.05f );
  2392. NDebugOverlay::Line( vecPos, vecPos + ( vecRight * 4.0f ), 0, 255, 0, true, 0.05f );
  2393. NDebugOverlay::Line( vecPos, vecPos + ( vecUp * 4.0f ), 0, 0, 255, true, 0.05f );
  2394. Q_snprintf( tempstr, sizeof(tempstr), " < %s (%d)", pStudioHdr->pAttachment(i-1).pszName(), i );
  2395. NDebugOverlay::Text( vecPos, tempstr, true, 0.05f );
  2396. }
  2397. }
  2398. }
  2399. return text_offset;
  2400. }
  2401. //-----------------------------------------------------------------------------
  2402. // Purpose: Force a clientside-animating entity to reset it's frame
  2403. //-----------------------------------------------------------------------------
  2404. void CBaseAnimating::ResetClientsideFrame( void )
  2405. {
  2406. // TODO: Once we can chain MSG_ENTITY messages, use one of them
  2407. m_bClientSideFrameReset = !(bool)m_bClientSideFrameReset;
  2408. }
  2409. //-----------------------------------------------------------------------------
  2410. // Purpose: Returns the origin at which to play an inputted dispatcheffect
  2411. //-----------------------------------------------------------------------------
  2412. void CBaseAnimating::GetInputDispatchEffectPosition( const char *sInputString, Vector &pOrigin, QAngle &pAngles )
  2413. {
  2414. // See if there's a specified attachment point
  2415. int iAttachment;
  2416. if ( GetModelPtr() && sscanf( sInputString, "%d", &iAttachment ) )
  2417. {
  2418. if ( !GetAttachment( iAttachment, pOrigin, pAngles ) )
  2419. {
  2420. Msg( "ERROR: Mapmaker tried to spawn DispatchEffect %s, but %s has no attachment %d\n",
  2421. sInputString, STRING(GetModelName()), iAttachment );
  2422. }
  2423. return;
  2424. }
  2425. BaseClass::GetInputDispatchEffectPosition( sInputString, pOrigin, pAngles );
  2426. }
  2427. //-----------------------------------------------------------------------------
  2428. // Purpose:
  2429. // Input : setnum -
  2430. //-----------------------------------------------------------------------------
  2431. void CBaseAnimating::SetHitboxSet( int setnum )
  2432. {
  2433. #ifdef _DEBUG
  2434. CStudioHdr *pStudioHdr = GetModelPtr();
  2435. if ( !pStudioHdr )
  2436. return;
  2437. if (setnum > pStudioHdr->numhitboxsets())
  2438. {
  2439. // Warn if an bogus hitbox set is being used....
  2440. static bool s_bWarned = false;
  2441. if (!s_bWarned)
  2442. {
  2443. Warning("Using bogus hitbox set in entity %s!\n", GetClassname() );
  2444. s_bWarned = true;
  2445. }
  2446. setnum = 0;
  2447. }
  2448. #endif
  2449. m_nHitboxSet = setnum;
  2450. }
  2451. //-----------------------------------------------------------------------------
  2452. // Purpose:
  2453. // Input : *setname -
  2454. //-----------------------------------------------------------------------------
  2455. void CBaseAnimating::SetHitboxSetByName( const char *setname )
  2456. {
  2457. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  2458. m_nHitboxSet = FindHitboxSetByName( GetModelPtr(), setname );
  2459. }
  2460. //-----------------------------------------------------------------------------
  2461. // Purpose:
  2462. // Output : int
  2463. //-----------------------------------------------------------------------------
  2464. int CBaseAnimating::GetHitboxSet( void )
  2465. {
  2466. return m_nHitboxSet;
  2467. }
  2468. //-----------------------------------------------------------------------------
  2469. // Purpose:
  2470. // Output : char const
  2471. //-----------------------------------------------------------------------------
  2472. const char *CBaseAnimating::GetHitboxSetName( void )
  2473. {
  2474. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  2475. return ::GetHitboxSetName( GetModelPtr(), m_nHitboxSet );
  2476. }
  2477. //-----------------------------------------------------------------------------
  2478. // Purpose:
  2479. // Output : int
  2480. //-----------------------------------------------------------------------------
  2481. int CBaseAnimating::GetHitboxSetCount( void )
  2482. {
  2483. AssertMsg( GetModelPtr(), "GetModelPtr NULL. %s", STRING(GetEntityName()) ? STRING(GetEntityName()) : "" );
  2484. return ::GetHitboxSetCount( GetModelPtr() );
  2485. }
  2486. static Vector hullcolor[8] =
  2487. {
  2488. Vector( 1.0, 1.0, 1.0 ),
  2489. Vector( 1.0, 0.5, 0.5 ),
  2490. Vector( 0.5, 1.0, 0.5 ),
  2491. Vector( 1.0, 1.0, 0.5 ),
  2492. Vector( 0.5, 0.5, 1.0 ),
  2493. Vector( 1.0, 0.5, 1.0 ),
  2494. Vector( 0.5, 1.0, 1.0 ),
  2495. Vector( 1.0, 1.0, 1.0 )
  2496. };
  2497. //-----------------------------------------------------------------------------
  2498. // Purpose: Send the current hitboxes for this model to the client ( to compare with
  2499. // r_drawentities 3 client side boxes ).
  2500. // WARNING: This uses a ton of bandwidth, only use on a listen server
  2501. //-----------------------------------------------------------------------------
  2502. void CBaseAnimating::DrawServerHitboxes( float duration /*= 0.0f*/, bool monocolor /*= false*/ )
  2503. {
  2504. CStudioHdr *pStudioHdr = GetModelPtr();
  2505. if ( !pStudioHdr )
  2506. return;
  2507. mstudiohitboxset_t *set =pStudioHdr->pHitboxSet( m_nHitboxSet );
  2508. if ( !set )
  2509. return;
  2510. Vector position;
  2511. QAngle angles;
  2512. int r = 0;
  2513. int g = 0;
  2514. int b = 255;
  2515. for ( int i = 0; i < set->numhitboxes; i++ )
  2516. {
  2517. mstudiobbox_t *pbox = set->pHitbox( i );
  2518. GetBonePosition( pbox->bone, position, angles );
  2519. if ( !monocolor )
  2520. {
  2521. int j = (pbox->group % 8);
  2522. r = ( int ) ( 255.0f * hullcolor[j][0] );
  2523. g = ( int ) ( 255.0f * hullcolor[j][1] );
  2524. b = ( int ) ( 255.0f * hullcolor[j][2] );
  2525. }
  2526. NDebugOverlay::BoxAngles( position, pbox->bbmin * GetModelScale(), pbox->bbmax * GetModelScale(), angles, r, g, b, 0 ,duration );
  2527. }
  2528. }
  2529. void CBaseAnimating::DrawRawSkeleton( matrix3x4_t boneToWorld[], int boneMask, bool noDepthTest, float duration, bool monocolor )
  2530. {
  2531. CStudioHdr *pStudioHdr = GetModelPtr();
  2532. if ( !pStudioHdr )
  2533. return;
  2534. int i;
  2535. int r = 255;
  2536. int g = 255;
  2537. int b = monocolor ? 255 : 0;
  2538. for (i = 0; i < pStudioHdr->numbones(); i++)
  2539. {
  2540. if (pStudioHdr->pBone( i )->flags & boneMask)
  2541. {
  2542. Vector p1;
  2543. MatrixPosition( boneToWorld[i], p1 );
  2544. if ( pStudioHdr->pBone( i )->parent != -1 )
  2545. {
  2546. Vector p2;
  2547. MatrixPosition( boneToWorld[pStudioHdr->pBone( i )->parent], p2 );
  2548. NDebugOverlay::Line( p1, p2, r, g, b, noDepthTest, duration );
  2549. }
  2550. }
  2551. }
  2552. }
  2553. int CBaseAnimating::GetHitboxBone( int hitboxIndex )
  2554. {
  2555. CStudioHdr *pStudioHdr = GetModelPtr();
  2556. if ( pStudioHdr )
  2557. {
  2558. mstudiohitboxset_t *set =pStudioHdr->pHitboxSet( m_nHitboxSet );
  2559. if ( set && hitboxIndex < set->numhitboxes )
  2560. {
  2561. return set->pHitbox( hitboxIndex )->bone;
  2562. }
  2563. }
  2564. return 0;
  2565. }
  2566. //-----------------------------------------------------------------------------
  2567. // Computes a box that surrounds all hitboxes
  2568. //-----------------------------------------------------------------------------
  2569. bool CBaseAnimating::ComputeHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
  2570. {
  2571. // Note that this currently should not be called during Relink because of IK.
  2572. // The code below recomputes bones so as to get at the hitboxes,
  2573. // which causes IK to trigger, which causes raycasts against the other entities to occur,
  2574. // which is illegal to do while in the Relink phase.
  2575. CStudioHdr *pStudioHdr = GetModelPtr();
  2576. if (!pStudioHdr)
  2577. return false;
  2578. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  2579. if ( !set || !set->numhitboxes )
  2580. return false;
  2581. CBoneCache *pCache = GetBoneCache();
  2582. // Compute a box in world space that surrounds this entity
  2583. pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2584. pVecWorldMaxs->Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  2585. Vector vecBoxAbsMins, vecBoxAbsMaxs;
  2586. for ( int i = 0; i < set->numhitboxes; i++ )
  2587. {
  2588. mstudiobbox_t *pbox = set->pHitbox(i);
  2589. matrix3x4_t *pMatrix = pCache->GetCachedBone(pbox->bone);
  2590. if ( pMatrix )
  2591. {
  2592. TransformAABB( *pMatrix, pbox->bbmin * GetModelScale(), pbox->bbmax * GetModelScale(), vecBoxAbsMins, vecBoxAbsMaxs );
  2593. VectorMin( *pVecWorldMins, vecBoxAbsMins, *pVecWorldMins );
  2594. VectorMax( *pVecWorldMaxs, vecBoxAbsMaxs, *pVecWorldMaxs );
  2595. }
  2596. }
  2597. return true;
  2598. }
  2599. //-----------------------------------------------------------------------------
  2600. // Computes a box that surrounds all hitboxes, in entity space
  2601. //-----------------------------------------------------------------------------
  2602. bool CBaseAnimating::ComputeEntitySpaceHitboxSurroundingBox( Vector *pVecWorldMins, Vector *pVecWorldMaxs )
  2603. {
  2604. // Note that this currently should not be called during position recomputation because of IK.
  2605. // The code below recomputes bones so as to get at the hitboxes,
  2606. // which causes IK to trigger, which causes raycasts against the other entities to occur,
  2607. // which is illegal to do while in the computeabsposition phase.
  2608. CStudioHdr *pStudioHdr = GetModelPtr();
  2609. if (!pStudioHdr)
  2610. return false;
  2611. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  2612. if ( !set || !set->numhitboxes )
  2613. return false;
  2614. CBoneCache *pCache = GetBoneCache();
  2615. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  2616. pCache->ReadCachedBonePointers( hitboxbones, pStudioHdr->numbones() );
  2617. // Compute a box in world space that surrounds this entity
  2618. pVecWorldMins->Init( FLT_MAX, FLT_MAX, FLT_MAX );
  2619. pVecWorldMaxs->Init( -FLT_MAX, -FLT_MAX, -FLT_MAX );
  2620. matrix3x4_t worldToEntity, boneToEntity;
  2621. MatrixInvert( EntityToWorldTransform(), worldToEntity );
  2622. Vector vecBoxAbsMins, vecBoxAbsMaxs;
  2623. for ( int i = 0; i < set->numhitboxes; i++ )
  2624. {
  2625. mstudiobbox_t *pbox = set->pHitbox(i);
  2626. ConcatTransforms( worldToEntity, *hitboxbones[pbox->bone], boneToEntity );
  2627. TransformAABB( boneToEntity, pbox->bbmin, pbox->bbmax, vecBoxAbsMins, vecBoxAbsMaxs );
  2628. VectorMin( *pVecWorldMins, vecBoxAbsMins, *pVecWorldMins );
  2629. VectorMax( *pVecWorldMaxs, vecBoxAbsMaxs, *pVecWorldMaxs );
  2630. }
  2631. return true;
  2632. }
  2633. int CBaseAnimating::GetPhysicsBone( int boneIndex )
  2634. {
  2635. CStudioHdr *pStudioHdr = GetModelPtr();
  2636. if ( pStudioHdr )
  2637. {
  2638. if ( boneIndex >= 0 && boneIndex < pStudioHdr->numbones() )
  2639. return pStudioHdr->pBone( boneIndex )->physicsbone;
  2640. }
  2641. return 0;
  2642. }
  2643. bool CBaseAnimating::LookupHitbox( const char *szName, int& outSet, int& outBox )
  2644. {
  2645. CStudioHdr* pHdr = GetModelPtr();
  2646. outSet = -1;
  2647. outBox = -1;
  2648. if( !pHdr )
  2649. return false;
  2650. for( int set=0; set < pHdr->numhitboxsets(); set++ )
  2651. {
  2652. for( int i = 0; i < pHdr->iHitboxCount(set); i++ )
  2653. {
  2654. mstudiobbox_t* pBox = pHdr->pHitbox( i, set );
  2655. if( !pBox )
  2656. continue;
  2657. const char* szBoxName = pBox->pszHitboxName();
  2658. if( Q_stricmp( szBoxName, szName ) == 0 )
  2659. {
  2660. outSet = set;
  2661. outBox = i;
  2662. return true;
  2663. }
  2664. }
  2665. }
  2666. return false;
  2667. }
  2668. void CBaseAnimating::CopyAnimationDataFrom( CBaseAnimating *pSource )
  2669. {
  2670. this->SetModelName( pSource->GetModelName() );
  2671. this->SetModelIndex( pSource->GetModelIndex() );
  2672. this->SetCycle( pSource->GetCycle() );
  2673. this->SetEffects( pSource->GetEffects() );
  2674. this->IncrementInterpolationFrame();
  2675. this->SetSequence( pSource->GetSequence() );
  2676. this->m_flAnimTime = pSource->m_flAnimTime;
  2677. this->m_nBody = pSource->m_nBody;
  2678. this->m_nSkin = pSource->m_nSkin;
  2679. this->LockStudioHdr();
  2680. }
  2681. int CBaseAnimating::GetHitboxesFrontside( int *boxList, int boxMax, const Vector &normal, float dist )
  2682. {
  2683. int count = 0;
  2684. CStudioHdr *pStudioHdr = GetModelPtr();
  2685. if ( pStudioHdr )
  2686. {
  2687. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( m_nHitboxSet );
  2688. if ( set )
  2689. {
  2690. matrix3x4_t matrix;
  2691. for ( int b = 0; b < set->numhitboxes; b++ )
  2692. {
  2693. mstudiobbox_t *pbox = set->pHitbox( b );
  2694. GetBoneTransform( pbox->bone, matrix );
  2695. Vector center = (pbox->bbmax + pbox->bbmin) * 0.5;
  2696. Vector centerWs;
  2697. VectorTransform( center, matrix, centerWs );
  2698. if ( DotProduct( centerWs, normal ) >= dist )
  2699. {
  2700. if ( count < boxMax )
  2701. {
  2702. boxList[count] = b;
  2703. count++;
  2704. }
  2705. }
  2706. }
  2707. }
  2708. }
  2709. return count;
  2710. }
  2711. void CBaseAnimating::EnableServerIK()
  2712. {
  2713. if (!m_pIk)
  2714. {
  2715. m_pIk = new CIKContext;
  2716. m_iIKCounter = 0;
  2717. }
  2718. }
  2719. void CBaseAnimating::DisableServerIK()
  2720. {
  2721. delete m_pIk;
  2722. m_pIk = NULL;
  2723. }
  2724. Activity CBaseAnimating::GetSequenceActivity( int iSequence )
  2725. {
  2726. if( iSequence == -1 )
  2727. {
  2728. return ACT_INVALID;
  2729. }
  2730. if ( !GetModelPtr() )
  2731. return ACT_INVALID;
  2732. return (Activity)::GetSequenceActivity( GetModelPtr(), iSequence );
  2733. }
  2734. void CBaseAnimating::ModifyOrAppendCriteria( AI_CriteriaSet& set )
  2735. {
  2736. BaseClass::ModifyOrAppendCriteria( set );
  2737. // TODO
  2738. // Append any animation state parameters here
  2739. }
  2740. void CBaseAnimating::DoMuzzleFlash()
  2741. {
  2742. m_nMuzzleFlashParity = (m_nMuzzleFlashParity+1) & ((1 << EF_MUZZLEFLASH_BITS) - 1);
  2743. }
  2744. //-----------------------------------------------------------------------------
  2745. // Purpose:
  2746. // Input : scale -
  2747. //-----------------------------------------------------------------------------
  2748. void CBaseAnimating::SetModelScale( float scale, float change_duration /*= 0.0f*/ )
  2749. {
  2750. if ( change_duration > 0.0f )
  2751. {
  2752. ModelScale *mvs = ( ModelScale * )CreateDataObject( MODELSCALE );
  2753. mvs->m_flModelScaleStart = m_flModelScale;
  2754. mvs->m_flModelScaleGoal = scale;
  2755. mvs->m_flModelScaleStartTime = gpGlobals->curtime;
  2756. mvs->m_flModelScaleFinishTime = mvs->m_flModelScaleStartTime + change_duration;
  2757. SetContextThink( &CBaseAnimating::UpdateModelScale, gpGlobals->curtime, "UpdateModelScaleThink" );
  2758. }
  2759. else
  2760. {
  2761. m_flModelScale = scale;
  2762. RefreshCollisionBounds();
  2763. if ( HasDataObjectType( MODELSCALE ) )
  2764. {
  2765. DestroyDataObject( MODELSCALE );
  2766. }
  2767. }
  2768. }
  2769. void CBaseAnimating::UpdateModelScale()
  2770. {
  2771. ModelScale *mvs = ( ModelScale * )GetDataObject( MODELSCALE );
  2772. if ( !mvs )
  2773. {
  2774. return;
  2775. }
  2776. float dt = mvs->m_flModelScaleFinishTime - mvs->m_flModelScaleStartTime;
  2777. Assert( dt > 0.0f );
  2778. float frac = ( gpGlobals->curtime - mvs->m_flModelScaleStartTime ) / dt;
  2779. frac = clamp( frac, 0.0f, 1.0f );
  2780. if ( gpGlobals->curtime >= mvs->m_flModelScaleFinishTime )
  2781. {
  2782. m_flModelScale = mvs->m_flModelScaleGoal;
  2783. DestroyDataObject( MODELSCALE );
  2784. }
  2785. else
  2786. {
  2787. m_flModelScale = Lerp( frac, mvs->m_flModelScaleStart, mvs->m_flModelScaleGoal );
  2788. }
  2789. RefreshCollisionBounds();
  2790. if ( frac < 1.f )
  2791. {
  2792. SetContextThink( &CBaseAnimating::UpdateModelScale, gpGlobals->curtime, "UpdateModelScaleThink" );
  2793. }
  2794. }
  2795. void CBaseAnimating::RefreshCollisionBounds( void )
  2796. {
  2797. CollisionProp()->RefreshScaledCollisionBounds();
  2798. }
  2799. //-----------------------------------------------------------------------------
  2800. //-----------------------------------------------------------------------------
  2801. void CBaseAnimating::Ignite( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner )
  2802. {
  2803. if( IsOnFire() )
  2804. return;
  2805. bool bIsNPC = IsNPC();
  2806. // Right now this prevents stuff we don't want to catch on fire from catching on fire.
  2807. if( bNPCOnly && bIsNPC == false )
  2808. {
  2809. return;
  2810. }
  2811. if( bIsNPC == true && bCalledByLevelDesigner == false )
  2812. {
  2813. CAI_BaseNPC *pNPC = MyNPCPointer();
  2814. if ( pNPC && pNPC->AllowedToIgnite() == false )
  2815. return;
  2816. }
  2817. CEntityFlame *pFlame = CEntityFlame::Create( this );
  2818. if (pFlame)
  2819. {
  2820. pFlame->SetLifetime( flFlameLifetime );
  2821. AddFlag( FL_ONFIRE );
  2822. SetEffectEntity( pFlame );
  2823. if ( flSize > 0.0f )
  2824. {
  2825. pFlame->SetSize( flSize );
  2826. }
  2827. }
  2828. m_OnIgnite.FireOutput( this, this );
  2829. }
  2830. void CBaseAnimating::IgniteLifetime( float flFlameLifetime )
  2831. {
  2832. if( !IsOnFire() )
  2833. Ignite( 30, false, 0.0f, true );
  2834. CEntityFlame *pFlame = dynamic_cast<CEntityFlame*>( GetEffectEntity() );
  2835. if ( !pFlame )
  2836. return;
  2837. pFlame->SetLifetime( flFlameLifetime );
  2838. }
  2839. void CBaseAnimating::IgniteNumHitboxFires( int iNumHitBoxFires )
  2840. {
  2841. if( !IsOnFire() )
  2842. Ignite( 30, false, 0.0f, true );
  2843. CEntityFlame *pFlame = dynamic_cast<CEntityFlame*>( GetEffectEntity() );
  2844. if ( !pFlame )
  2845. return;
  2846. pFlame->SetNumHitboxFires( iNumHitBoxFires );
  2847. }
  2848. void CBaseAnimating::IgniteHitboxFireScale( float flHitboxFireScale )
  2849. {
  2850. if( !IsOnFire() )
  2851. Ignite( 30, false, 0.0f, true );
  2852. CEntityFlame *pFlame = dynamic_cast<CEntityFlame*>( GetEffectEntity() );
  2853. if ( !pFlame )
  2854. return;
  2855. pFlame->SetHitboxFireScale( flHitboxFireScale );
  2856. }
  2857. //-----------------------------------------------------------------------------
  2858. // Fades out!
  2859. //-----------------------------------------------------------------------------
  2860. bool CBaseAnimating::Dissolve( const char *pMaterialName, float flStartTime, bool bNPCOnly, int nDissolveType, Vector vDissolverOrigin, int iMagnitude )
  2861. {
  2862. // Right now this prevents stuff we don't want to catch on fire from catching on fire.
  2863. if( bNPCOnly && !(GetFlags() & FL_NPC) )
  2864. return false;
  2865. // Can't dissolve twice
  2866. if ( IsDissolving() )
  2867. return false;
  2868. bool bRagdollCreated = false;
  2869. CEntityDissolve *pDissolve = CEntityDissolve::Create( this, pMaterialName, flStartTime, nDissolveType, &bRagdollCreated );
  2870. if (pDissolve)
  2871. {
  2872. SetEffectEntity( pDissolve );
  2873. AddFlag( FL_DISSOLVING );
  2874. m_flDissolveStartTime = flStartTime;
  2875. pDissolve->SetDissolverOrigin( vDissolverOrigin );
  2876. pDissolve->SetMagnitude( iMagnitude );
  2877. }
  2878. // if this is a ragdoll dissolving, fire an event
  2879. if ( ( CLASS_NONE == Classify() ) && ( ClassMatches( "prop_ragdoll" ) ) )
  2880. {
  2881. IGameEvent *event = gameeventmanager->CreateEvent( "ragdoll_dissolved" );
  2882. if ( event )
  2883. {
  2884. event->SetInt( "entindex", entindex() );
  2885. gameeventmanager->FireEvent( event );
  2886. }
  2887. }
  2888. return bRagdollCreated;
  2889. }
  2890. //-----------------------------------------------------------------------------
  2891. // Make a model look as though it's burning.
  2892. //-----------------------------------------------------------------------------
  2893. void CBaseAnimating::Scorch( int rate, int floor )
  2894. {
  2895. color32 color = GetRenderColor();
  2896. if( color.r > floor )
  2897. color.r -= rate;
  2898. if( color.g > floor )
  2899. color.g -= rate;
  2900. if( color.b > floor )
  2901. color.b -= rate;
  2902. SetRenderColor( color.r, color.g, color.b );
  2903. }
  2904. void CBaseAnimating::ResetSequence(int nSequence)
  2905. {
  2906. if (ai_sequence_debug.GetBool() == true && (m_debugOverlays & OVERLAY_NPC_SELECTED_BIT))
  2907. {
  2908. DevMsg("ResetSequence : %s: %s -> %s\n", GetClassname(), GetSequenceName(GetSequence()), GetSequenceName(nSequence));
  2909. }
  2910. if ( !SequenceLoops() )
  2911. {
  2912. SetCycle( 0 );
  2913. }
  2914. // Tracker 17868: If the sequence number didn't actually change, but you call resetsequence info, it changes
  2915. // the newsequenceparity bit which causes the client to call m_flCycle.Reset() which causes a very slight
  2916. // discontinuity in looping animations as they reset around to cycle 0.0. This was causing the parentattached
  2917. // helmet on barney to hitch every time barney's idle cycled back around to its start.
  2918. bool changed = nSequence != GetSequence() ? true : false;
  2919. SetSequence( nSequence );
  2920. if ( changed || !SequenceLoops() )
  2921. {
  2922. ResetSequenceInfo();
  2923. }
  2924. }
  2925. //-----------------------------------------------------------------------------
  2926. //-----------------------------------------------------------------------------
  2927. void CBaseAnimating::InputIgnite( inputdata_t &inputdata )
  2928. {
  2929. Ignite( 30, false, 0.0f, true );
  2930. }
  2931. void CBaseAnimating::InputIgniteLifetime( inputdata_t &inputdata )
  2932. {
  2933. IgniteLifetime( inputdata.value.Float() );
  2934. }
  2935. void CBaseAnimating::InputIgniteNumHitboxFires( inputdata_t &inputdata )
  2936. {
  2937. IgniteNumHitboxFires( inputdata.value.Int() );
  2938. }
  2939. void CBaseAnimating::InputIgniteHitboxFireScale( inputdata_t &inputdata )
  2940. {
  2941. IgniteHitboxFireScale( inputdata.value.Float() );
  2942. }
  2943. void CBaseAnimating::InputBecomeRagdoll( inputdata_t &inputdata )
  2944. {
  2945. BecomeRagdollOnClient( vec3_origin );
  2946. }
  2947. //-----------------------------------------------------------------------------
  2948. // Purpose:
  2949. //-----------------------------------------------------------------------------
  2950. void CBaseAnimating::SetFadeDistance( float minFadeDist, float maxFadeDist )
  2951. {
  2952. m_fadeMinDist = minFadeDist;
  2953. m_fadeMaxDist = maxFadeDist;
  2954. }
  2955. //-----------------------------------------------------------------------------
  2956. // Purpose: Async prefetches all anim data used by a particular sequence. Returns true if all of the required data is memory resident
  2957. // Input : iSequence -
  2958. // Output : Returns true on success, false on failure.
  2959. //-----------------------------------------------------------------------------
  2960. bool CBaseAnimating::PrefetchSequence( int iSequence )
  2961. {
  2962. CStudioHdr *pStudioHdr = GetModelPtr();
  2963. if ( !pStudioHdr )
  2964. return true;
  2965. return Studio_PrefetchSequence( pStudioHdr, iSequence );
  2966. }
  2967. //-----------------------------------------------------------------------------
  2968. // Purpose:
  2969. //-----------------------------------------------------------------------------
  2970. bool CBaseAnimating::IsSequenceLooping( CStudioHdr *pStudioHdr, int iSequence )
  2971. {
  2972. return (::GetSequenceFlags( pStudioHdr, iSequence ) & STUDIO_LOOPING) != 0;
  2973. }
  2974. //-----------------------------------------------------------------------------
  2975. // Purpose: model-change notification. Fires on dynamic load completion as well
  2976. //-----------------------------------------------------------------------------
  2977. CStudioHdr *CBaseAnimating::OnNewModel()
  2978. {
  2979. (void) BaseClass::OnNewModel();
  2980. // TODO: if dynamic, validate m_Sequence and apply queued body group settings?
  2981. if ( IsDynamicModelLoading() )
  2982. {
  2983. // Called while dynamic model still loading -> new model, clear deferred state
  2984. m_bResetSequenceInfoOnLoad = false;
  2985. return NULL;
  2986. }
  2987. CStudioHdr *hdr = GetModelPtr();
  2988. if ( m_bResetSequenceInfoOnLoad )
  2989. {
  2990. m_bResetSequenceInfoOnLoad = false;
  2991. ResetSequenceInfo();
  2992. }
  2993. return hdr;
  2994. }