Counter Strike : Global Offensive Source Code
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.

4194 lines
116 KiB

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