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.

1186 lines
34 KiB

  1. //===== Copyright � 1996-2006, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: particle system definitions
  4. //
  5. //===========================================================================//
  6. #include "cbase.h"
  7. #include "particles/particles.h"
  8. #include "baseparticleentity.h"
  9. #include "entityparticletrail_shared.h"
  10. #include "collisionutils.h"
  11. #include "engine/ivdebugoverlay.h"
  12. #include "raytrace.h"
  13. #include "animation.h"
  14. #include "activitylist.h"
  15. #if defined( CLIENT_DLL )
  16. #include "c_pixel_visibility.h"
  17. #include "c_effects.h"
  18. #include "view.h"
  19. #include "viewrender.h"
  20. #include "model_types.h"
  21. #include "c_env_projectedtexture.h"
  22. #endif
  23. #ifdef TF_CLIENT_DLL
  24. #include "tf_shareddefs.h"
  25. #endif
  26. #ifdef SWARM_DLL
  27. #include "asw_shareddefs.h"
  28. #endif
  29. #ifdef GAME_DLL
  30. #include "ai_utils.h"
  31. #endif
  32. // memdbgon must be the last include file in a .cpp file!!!
  33. #include "tier0/memdbgon.h"
  34. #if defined( CLIENT_DLL )
  35. typedef struct SProjectedTextureInfo
  36. {
  37. int m_nParticleID;
  38. IMaterial *m_pMaterial;
  39. Vector m_vOrigin;
  40. float m_flSize;
  41. float m_flRotation;
  42. float m_r, m_g, m_b, m_a;
  43. C_EnvProjectedTexture *m_pEntity;
  44. bool m_bUsedThisFrame;
  45. } TProjectedTextureInfo;
  46. #endif // #if defined( CLIENT_DLL )
  47. #define POINT_AT_ORIGIN_EPSILON 0.1f
  48. //-----------------------------------------------------------------------------
  49. // Interface to allow the particle system to call back into the game code
  50. //-----------------------------------------------------------------------------
  51. class CParticleSystemQuery : public CBaseAppSystem< IParticleSystemQuery >
  52. {
  53. public:
  54. virtual bool IsEditor( ) { return false; }
  55. // Inherited from IParticleSystemQuery
  56. virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &cTint );
  57. virtual void TraceLine( const Vector& vecAbsStart,
  58. const Vector& vecAbsEnd, unsigned int mask,
  59. const IHandleEntity *ignore,
  60. int collisionGroup, CBaseTrace *ptr );
  61. virtual bool IsPointInSolid( const Vector& vecPos, const int nContentsMask );
  62. virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles,
  63. void *pObject,
  64. Vector *pPnt );
  65. virtual void GetRandomPointsOnControllingObjectHitBox(
  66. CParticleCollection *pParticles,
  67. int nControlPointNumber,
  68. int nNumPtsOut,
  69. float flBBoxScale,
  70. int nNumTrysToGetAPointInsideTheModel,
  71. Vector *pPntsOut,
  72. Vector vecDirectionalBias,
  73. Vector *pHitBoxRelativeCoordOut,
  74. int *pHitBoxIndexOut,
  75. int nDesiredHitbox,
  76. const char *pszHitboxSetName );
  77. void GetClosestControllingObjectHitBox(
  78. CParticleCollection *pParticles,
  79. int nControlPointNumber,
  80. int nNumPtsIn,
  81. float flBBoxScale,
  82. Vector *pPntsIn,
  83. Vector *pHitBoxRelativeCoordOut,
  84. int *pHitBoxIndexOut,
  85. int nDesiredHitbox,
  86. const char *pszHitboxSetName );
  87. virtual int GetRayTraceEnvironmentFromName( const char *pszRtEnvName );
  88. virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName );
  89. virtual int GetControllingObjectHitBoxInfo(
  90. CParticleCollection *pParticles,
  91. int nControlPointNumber,
  92. int nBufSize, // # of output slots available
  93. ModelHitBoxInfo_t *pHitBoxOutputBuffer,
  94. const char *pszHitboxSetName );
  95. virtual bool IsPointInControllingObjectHitBox(
  96. CParticleCollection *pParticles,
  97. int nControlPointNumber, Vector vecPos, bool bBBoxOnly,
  98. const char *pszHitboxSetName );
  99. virtual void GetControllingObjectOBBox(
  100. CParticleCollection *pParticles,
  101. int nControlPointNumber, Vector vecMin, Vector vecMax );
  102. // Traces Four Rays against a defined RayTraceEnvironment
  103. virtual void TraceAgainstRayTraceEnv( int envnumber, const FourRays &rays, fltx4 TMin, fltx4 TMax,
  104. RayTracingResult *rslt_out, int32 skip_id ) const ;
  105. virtual Vector GetLocalPlayerPos( void );
  106. virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL );
  107. virtual Vector GetCurrentViewOrigin();
  108. virtual int GetActivityCount();
  109. virtual const char *GetActivityNameFromIndex( int nActivityIndex );
  110. virtual int GetActivityNumber( void *pModel, const char *m_pszActivityName );
  111. virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale );
  112. virtual void SetUpLightingEnvironment( const Vector& pos );
  113. virtual void PreSimulate( );
  114. virtual void PostSimulate( );
  115. virtual void DebugDrawLine( const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float duration );
  116. virtual void BeginDrawModels( int nMaxNumToDraw, Vector const &vecCenterPosition, CParticleCollection *pParticles )
  117. {
  118. }
  119. virtual void DrawModel( void *pModel, const matrix3x4_t &DrawMatrix, CParticleCollection *pParticles, int nParticleNumber, int nBodyPart, int nSubModel,
  120. int nSkin, int nAnimationSequence = 0, float flAnimationRate = 30.0f, float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f );
  121. virtual void FinishDrawModels( CParticleCollection *pParticles )
  122. {
  123. }
  124. virtual void *GetModel( char const *pMdlName );
  125. virtual void UpdateProjectedTexture( const int nParticleID, IMaterial *pMaterial, Vector &vOrigin, float flRadius, float flRotation, float r, float g, float b, float a, void *&pUserVar );
  126. private:
  127. #if defined( CLIENT_DLL )
  128. CTSQueue< TProjectedTextureInfo * > m_ProjectedInfoAdds;
  129. CUtlVector< TProjectedTextureInfo * > m_ActiveProjectedInfos;
  130. #endif // #if defined( CLIENT_DLL )
  131. };
  132. static CParticleSystemQuery s_ParticleSystemQuery;
  133. IParticleSystemQuery *g_pParticleSystemQuery = &s_ParticleSystemQuery;
  134. //-----------------------------------------------------------------------------
  135. // Exposes the interface (so tools can get at it)
  136. //-----------------------------------------------------------------------------
  137. #ifdef CLIENT_DLL
  138. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CParticleSystemQuery, IParticleSystemQuery, PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION, s_ParticleSystemQuery );
  139. #endif
  140. static CThreadFastMutex s_LightMutex;
  141. static CThreadFastMutex s_BoneMutex;
  142. //-----------------------------------------------------------------------------
  143. // Inherited from IParticleSystemQuery
  144. //-----------------------------------------------------------------------------
  145. void CParticleSystemQuery::GetLightingAtPoint( const Vector& vecOrigin, Color &cTint )
  146. {
  147. VPROF("CParticleSystemQuery::GetLightingAtPoint");
  148. #ifdef GAME_DLL
  149. // FIXME: Go through to the engine from the server to get these values
  150. cTint.SetColor( 255, 255, 255, 255 );
  151. #else
  152. if ( engine->IsInGame() )
  153. {
  154. s_LightMutex.Lock();
  155. // Compute our lighting at our position
  156. Vector totalColor = engine->GetLightForPoint( vecOrigin, true );
  157. s_LightMutex.Unlock();
  158. // Get our lighting information
  159. cTint.SetColor( totalColor.x*255, totalColor.y*255, totalColor.z*255, 0 );
  160. }
  161. else
  162. {
  163. // FIXME: Go through to the engine from the server to get these values
  164. cTint.SetColor( 255, 255, 255, 255 );
  165. }
  166. #endif
  167. }
  168. void CParticleSystemQuery::SetUpLightingEnvironment( const Vector& pos )
  169. {
  170. #ifndef GAME_DLL
  171. if ( !engine->IsInGame() )
  172. return;
  173. s_LightMutex.Lock();
  174. modelrender->SetupLighting( pos );
  175. s_LightMutex.Unlock();
  176. #endif
  177. }
  178. void CParticleSystemQuery::TraceLine( const Vector& vecAbsStart,
  179. const Vector& vecAbsEnd, unsigned int mask,
  180. const IHandleEntity *ignore,
  181. int collisionGroup, CBaseTrace *ptr )
  182. {
  183. bool bDoTrace = false;
  184. #ifndef GAME_DLL
  185. bDoTrace = engine->IsInGame();
  186. #endif
  187. if ( bDoTrace )
  188. {
  189. trace_t tempTrace;
  190. UTIL_TraceLine( vecAbsStart, vecAbsEnd, mask, ignore, collisionGroup, &tempTrace );
  191. memcpy( ptr, &tempTrace, sizeof ( CBaseTrace ) );
  192. }
  193. else
  194. {
  195. ptr->startsolid = 0;
  196. ptr->fraction = 1.0;
  197. }
  198. }
  199. bool CParticleSystemQuery::IsPointInSolid( const Vector& vecPos, const int nContentsMask )
  200. {
  201. bool bDoTrace = false;
  202. #ifndef GAME_DLL
  203. bDoTrace = engine->IsInGame();
  204. #endif
  205. if ( bDoTrace )
  206. {
  207. return ( UTIL_PointContents(vecPos, nContentsMask) & nContentsMask ) != 0;
  208. }
  209. return false;
  210. }
  211. bool CParticleSystemQuery::MovePointInsideControllingObject(
  212. CParticleCollection *pParticles, void *pObject, Vector *pPnt )
  213. {
  214. #ifdef GAME_DLL
  215. return true;
  216. #else
  217. if (! pObject )
  218. return true; // accept the input point unmodified
  219. Ray_t ray;
  220. trace_t tr;
  221. ray.Init( *pPnt, *pPnt );
  222. enginetrace->ClipRayToEntity( ray, MASK_ALL, (CBaseEntity *) pObject, &tr );
  223. return ( tr.startsolid );
  224. #endif
  225. }
  226. static float GetSurfaceCoord( float flRand, float flMinX, float flMaxX )
  227. {
  228. return Lerp( flRand, flMinX, flMaxX );
  229. }
  230. void CParticleSystemQuery::GetRandomPointsOnControllingObjectHitBox(
  231. CParticleCollection *pParticles,
  232. int nControlPointNumber,
  233. int nNumPtsOut,
  234. float flBBoxScale,
  235. int nNumTrysToGetAPointInsideTheModel,
  236. Vector *pPntsOut,
  237. Vector vecDirectionalBias,
  238. Vector *pHitBoxRelativeCoordOut,
  239. int *pHitBoxIndexOut,
  240. int nDesiredHitbox,
  241. const char *pszHitboxSetName )
  242. {
  243. bool bSucesss = false;
  244. #ifndef GAME_DLL
  245. EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject );
  246. CBaseEntity *pMoveParent = NULL;
  247. if ( phMoveParent )
  248. {
  249. pMoveParent = *( phMoveParent );
  250. }
  251. if ( pMoveParent )
  252. {
  253. float flRandMax = flBBoxScale;
  254. float flRandMin = 1.0 - flBBoxScale;
  255. Vector vecBasePos;
  256. pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos );
  257. s_BoneMutex.Lock();
  258. C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  259. if ( pAnimating )
  260. {
  261. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  262. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  263. {
  264. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  265. if ( pStudioHdr )
  266. {
  267. // Try to get the desired set first, otherwise use their current set
  268. int nEffectsHitboxSet = FindHitboxSetByName( pAnimating->GetModelPtr(), pszHitboxSetName );
  269. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( nEffectsHitboxSet != -1 ? nEffectsHitboxSet : pAnimating->GetHitboxSet() );
  270. if ( set )
  271. {
  272. bSucesss = true;
  273. Vector vecWorldPosition;
  274. float u = 0, v = 0, w = 0;
  275. int nHitbox = 0;
  276. int nNumIters = nNumTrysToGetAPointInsideTheModel;
  277. if (! vecDirectionalBias.IsZero( 0.0001 ) )
  278. nNumIters = MAX( nNumIters, 5 );
  279. int nHitboxMin = 0;
  280. int nHitboxMax = set->numhitboxes - 1;
  281. if ( nDesiredHitbox >= 0 )
  282. {
  283. nHitboxMin = MIN( set->numhitboxes - 1, nDesiredHitbox );
  284. nHitboxMax = MIN( set->numhitboxes - 1, nDesiredHitbox );
  285. }
  286. for( int i=0 ; i < nNumPtsOut; i++)
  287. {
  288. int nTryCnt = nNumIters;
  289. float flBestPointGoodness = -1.0e20;
  290. do
  291. {
  292. int nTryHitbox = pParticles->RandomInt( nHitboxMin, nHitboxMax );
  293. mstudiobbox_t *pBox = set->pHitbox(nTryHitbox);
  294. // E3 HACK - check for hitboxes at the origin and ignore those
  295. if ( fabs( (*hitboxbones[pBox->bone])[0][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[1][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[2][3] ) < POINT_AT_ORIGIN_EPSILON )
  296. {
  297. continue;
  298. }
  299. float flTryU = pParticles->RandomFloat( flRandMin, flRandMax );
  300. float flTryV = pParticles->RandomFloat( flRandMin, flRandMax );
  301. float flTryW = pParticles->RandomFloat( flRandMin, flRandMax );
  302. Vector vecLocalPosition;
  303. vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x*pAnimating->GetModelHierarchyScale(), pBox->bbmax.x*pAnimating->GetModelHierarchyScale() );
  304. vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y*pAnimating->GetModelHierarchyScale(), pBox->bbmax.y*pAnimating->GetModelHierarchyScale() );
  305. vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z*pAnimating->GetModelHierarchyScale(), pBox->bbmax.z*pAnimating->GetModelHierarchyScale() );
  306. Vector vecTryWorldPosition;
  307. VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition );
  308. float flPointGoodness = pParticles->RandomFloat( 0, 72 )
  309. + DotProduct( vecTryWorldPosition - vecBasePos,
  310. vecDirectionalBias );
  311. if ( nNumTrysToGetAPointInsideTheModel )
  312. {
  313. // do a point in solid test
  314. Ray_t ray;
  315. trace_t tr;
  316. ray.Init( vecTryWorldPosition, vecTryWorldPosition );
  317. enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr );
  318. if ( tr.startsolid )
  319. flPointGoodness += 1000.; // got a point inside!
  320. }
  321. if ( flPointGoodness > flBestPointGoodness )
  322. {
  323. u = flTryU;
  324. v = flTryV;
  325. w = flTryW;
  326. vecWorldPosition = vecTryWorldPosition;
  327. nHitbox = nTryHitbox;
  328. flBestPointGoodness = flPointGoodness;
  329. }
  330. } while ( nTryCnt-- );
  331. *( pPntsOut++ ) = vecWorldPosition;
  332. if ( pHitBoxRelativeCoordOut )
  333. ( pHitBoxRelativeCoordOut++ )->Init( u, v, w );
  334. if ( pHitBoxIndexOut )
  335. *( pHitBoxIndexOut++ ) = nHitbox;
  336. }
  337. }
  338. }
  339. }
  340. }
  341. if ( pMoveParent->IsBrushModel() )
  342. {
  343. Vector vecMin;
  344. Vector vecMax;
  345. matrix3x4_t matOrientation;
  346. Vector VecOrigin;
  347. pMoveParent->GetRenderBounds( vecMin, vecMax );
  348. VecOrigin = pMoveParent->GetRenderOrigin();
  349. matOrientation = pMoveParent->EntityToWorldTransform();
  350. Vector vecWorldPosition;
  351. float u = 0, v = 0, w = 0;
  352. int nHitbox = 0;
  353. int nNumIters = nNumTrysToGetAPointInsideTheModel;
  354. if (! vecDirectionalBias.IsZero( 0.0001 ) )
  355. nNumIters = MAX( nNumIters, 5 );
  356. for( int i=0 ; i < nNumPtsOut; i++)
  357. {
  358. int nTryCnt = nNumIters;
  359. float flBestPointGoodness = -1.0e20;
  360. do
  361. {
  362. float flTryU = pParticles->RandomFloat( flRandMin, flRandMax );
  363. float flTryV = pParticles->RandomFloat( flRandMin, flRandMax );
  364. float flTryW = pParticles->RandomFloat( flRandMin, flRandMax );
  365. Vector vecLocalPosition;
  366. vecLocalPosition.x = GetSurfaceCoord( flTryU, vecMin.x, vecMax.x );
  367. vecLocalPosition.y = GetSurfaceCoord( flTryV, vecMin.y, vecMax.y );
  368. vecLocalPosition.z = GetSurfaceCoord( flTryW, vecMin.z, vecMax.z );
  369. Vector vecTryWorldPosition;
  370. VectorTransform( vecLocalPosition, matOrientation, vecTryWorldPosition );
  371. float flPointGoodness = pParticles->RandomFloat( 0, 72 )
  372. + DotProduct( vecTryWorldPosition - vecBasePos,
  373. vecDirectionalBias );
  374. if ( nNumTrysToGetAPointInsideTheModel )
  375. {
  376. // do a point in solid test
  377. Ray_t ray;
  378. trace_t tr;
  379. ray.Init( vecTryWorldPosition, vecTryWorldPosition );
  380. enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr );
  381. if ( tr.startsolid )
  382. flPointGoodness += 1000.; // got a point inside!
  383. }
  384. if ( flPointGoodness > flBestPointGoodness )
  385. {
  386. u = flTryU;
  387. v = flTryV;
  388. w = flTryW;
  389. vecWorldPosition = vecTryWorldPosition;
  390. nHitbox = 0;
  391. flBestPointGoodness = flPointGoodness;
  392. }
  393. } while ( nTryCnt-- );
  394. *( pPntsOut++ ) = vecWorldPosition;
  395. if ( pHitBoxRelativeCoordOut )
  396. ( pHitBoxRelativeCoordOut++ )->Init( u, v, w );
  397. if ( pHitBoxIndexOut )
  398. *( pHitBoxIndexOut++ ) = nHitbox;
  399. }
  400. }
  401. s_BoneMutex.Unlock();
  402. }
  403. #endif
  404. if (! bSucesss )
  405. {
  406. // don't have a model or am in editor or something - fill return with control point
  407. for( int i=0 ; i < nNumPtsOut; i++)
  408. {
  409. pPntsOut[i] = pParticles->ControlPoint( nControlPointNumber ).m_Position; // fallback if anything goes wrong
  410. if ( pHitBoxIndexOut )
  411. pHitBoxIndexOut[i] = 0;
  412. if ( pHitBoxRelativeCoordOut )
  413. pHitBoxRelativeCoordOut[i].Init();
  414. }
  415. }
  416. }
  417. void CParticleSystemQuery::GetClosestControllingObjectHitBox(
  418. CParticleCollection *pParticles,
  419. int nControlPointNumber,
  420. int nNumPtsIn,
  421. float flBBoxScale,
  422. Vector *pPntsIn,
  423. Vector *pHitBoxRelativeCoordOut,
  424. int *pHitBoxIndexOut,
  425. int nDesiredHitbox,
  426. const char *pszHitboxSetName )
  427. {
  428. bool bSucesss = false;
  429. #ifndef GAME_DLL
  430. EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject );
  431. CBaseEntity *pMoveParent = NULL;
  432. if ( phMoveParent )
  433. {
  434. pMoveParent = *( phMoveParent );
  435. }
  436. if ( pMoveParent )
  437. {
  438. float flRandMax = flBBoxScale;
  439. float flRandMin = 1.0 - flBBoxScale;
  440. Vector vecBasePos;
  441. pParticles->GetControlPointAtTime( nControlPointNumber, pParticles->m_flCurTime, &vecBasePos );
  442. s_BoneMutex.Lock();
  443. C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  444. if ( pAnimating )
  445. {
  446. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  447. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  448. {
  449. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  450. if ( pStudioHdr )
  451. {
  452. // Try to get the desired set first, otherwise use their current set
  453. int nEffectsHitboxSet = FindHitboxSetByName( pAnimating->GetModelPtr(), pszHitboxSetName );
  454. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( nEffectsHitboxSet != -1 ? nEffectsHitboxSet : pAnimating->GetHitboxSet() );
  455. if ( set )
  456. {
  457. bSucesss = true;
  458. Vector vecWorldPosition;
  459. float u = 0, v = 0, w = 0;
  460. int nHitbox = 0;
  461. int nHitboxMin = 0;
  462. int nHitboxMax = set->numhitboxes - 1;
  463. if ( nDesiredHitbox >= 0 )
  464. {
  465. nHitboxMin = MIN( set->numhitboxes - 1, nDesiredHitbox );
  466. nHitboxMax = MIN( set->numhitboxes - 1, nDesiredHitbox );
  467. }
  468. for( int i=0 ; i < nNumPtsIn; i++)
  469. {
  470. float flBestPointGoodness = FLT_MAX;
  471. Vector vecCurrentPoint = *( pPntsIn++ );
  472. for ( int j = nHitboxMin; j < nHitboxMax; j++ )
  473. {
  474. int nTryHitbox = j;
  475. mstudiobbox_t *pBox = set->pHitbox(nTryHitbox);
  476. float flTryU = pParticles->RandomFloat( flRandMin, flRandMax );
  477. float flTryV = pParticles->RandomFloat( flRandMin, flRandMax );
  478. float flTryW = pParticles->RandomFloat( flRandMin, flRandMax );
  479. Vector vecLocalPosition;
  480. vecLocalPosition.x = GetSurfaceCoord( flTryU, pBox->bbmin.x*pAnimating->GetModelScale(), pBox->bbmax.x*pAnimating->GetModelScale() );
  481. vecLocalPosition.y = GetSurfaceCoord( flTryV, pBox->bbmin.y*pAnimating->GetModelScale(), pBox->bbmax.y*pAnimating->GetModelScale() );
  482. vecLocalPosition.z = GetSurfaceCoord( flTryW, pBox->bbmin.z*pAnimating->GetModelScale(), pBox->bbmax.z*pAnimating->GetModelScale() );
  483. Vector vecTryWorldPosition;
  484. VectorTransform( vecLocalPosition, *hitboxbones[pBox->bone], vecTryWorldPosition );
  485. Vector vecBoxDistance;
  486. VectorTransform( ( ( pBox->bbmin + pBox->bbmax ) / 2 ), *hitboxbones[pBox->bone], vecBoxDistance );
  487. vecBoxDistance -= vecCurrentPoint;
  488. float flPointGoodness = vecBoxDistance.Length();
  489. if ( flPointGoodness < flBestPointGoodness )
  490. {
  491. u = flTryU;
  492. v = flTryV;
  493. w = flTryW;
  494. nHitbox = nTryHitbox;
  495. flBestPointGoodness = flPointGoodness;
  496. }
  497. }
  498. if ( pHitBoxRelativeCoordOut )
  499. ( pHitBoxRelativeCoordOut++ )->Init( u, v, w );
  500. if ( pHitBoxIndexOut )
  501. *( pHitBoxIndexOut++ ) = nHitbox;
  502. }
  503. }
  504. }
  505. }
  506. }
  507. s_BoneMutex.Unlock();
  508. }
  509. #endif
  510. if (! bSucesss )
  511. {
  512. // don't have a model or am in editor or something - fill return with control point
  513. for( int i=0 ; i < nNumPtsIn; i++)
  514. {
  515. if ( pHitBoxIndexOut )
  516. pHitBoxIndexOut[i] = 0;
  517. if ( pHitBoxRelativeCoordOut )
  518. pHitBoxRelativeCoordOut[i].Init();
  519. }
  520. }
  521. }
  522. int CParticleSystemQuery::GetControllingObjectHitBoxInfo(
  523. CParticleCollection *pParticles,
  524. int nControlPointNumber,
  525. int nBufSize, // # of output slots available
  526. ModelHitBoxInfo_t *pHitBoxOutputBuffer,
  527. const char *pszHitboxSetName )
  528. {
  529. int nRet = 0;
  530. #ifndef GAME_DLL
  531. s_BoneMutex.Lock();
  532. EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject );
  533. CBaseEntity *pMoveParent = NULL;
  534. if ( phMoveParent )
  535. {
  536. pMoveParent = *( phMoveParent );
  537. }
  538. if ( pMoveParent )
  539. {
  540. C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  541. if ( pAnimating )
  542. {
  543. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  544. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  545. {
  546. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  547. if ( pStudioHdr )
  548. {
  549. // Try to get the desired set first, otherwise use their current set
  550. int nEffectsHitboxSet = FindHitboxSetByName( pAnimating->GetModelPtr(), pszHitboxSetName );
  551. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( nEffectsHitboxSet != -1 ? nEffectsHitboxSet : pAnimating->GetHitboxSet() );
  552. if ( set )
  553. {
  554. for( int i=0 ; i < set->numhitboxes; i++ )
  555. {
  556. mstudiobbox_t *pBox = set->pHitbox( i );
  557. // E3 HACK - check for hitboxes at the origin and ignore those
  558. if ( fabs( (*hitboxbones[pBox->bone])[0][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[1][3] ) < POINT_AT_ORIGIN_EPSILON && fabs( (*hitboxbones[pBox->bone])[2][3] ) < POINT_AT_ORIGIN_EPSILON )
  559. {
  560. continue;
  561. }
  562. pHitBoxOutputBuffer[nRet].m_vecBoxMins.x = pBox->bbmin.x;
  563. pHitBoxOutputBuffer[nRet].m_vecBoxMins.y = pBox->bbmin.y;
  564. pHitBoxOutputBuffer[nRet].m_vecBoxMins.z = pBox->bbmin.z;
  565. pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.x = pBox->bbmax.x;
  566. pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.y = pBox->bbmax.y;
  567. pHitBoxOutputBuffer[nRet].m_vecBoxMaxes.z = pBox->bbmax.z;
  568. pHitBoxOutputBuffer[nRet].m_Transform = *hitboxbones[pBox->bone];
  569. nRet++;
  570. if ( nRet >= nBufSize )
  571. {
  572. break;
  573. }
  574. }
  575. }
  576. }
  577. }
  578. }
  579. if ( pMoveParent->IsBrushModel() )
  580. {
  581. Vector vecMin;
  582. Vector vecMax;
  583. matrix3x4_t matOrientation;
  584. pMoveParent->GetRenderBounds( vecMin, vecMax );
  585. matOrientation = pMoveParent->EntityToWorldTransform();
  586. pHitBoxOutputBuffer[0].m_vecBoxMins = vecMin;
  587. pHitBoxOutputBuffer[0].m_vecBoxMaxes = vecMax;
  588. pHitBoxOutputBuffer[0].m_Transform = matOrientation;
  589. nRet = 1;
  590. }
  591. }
  592. s_BoneMutex.Unlock();
  593. #endif
  594. return nRet;
  595. }
  596. bool CParticleSystemQuery::IsPointInControllingObjectHitBox(
  597. CParticleCollection *pParticles,
  598. int nControlPointNumber, Vector vecPos, bool bBBoxOnly,
  599. const char *pszHitboxSetName )
  600. {
  601. bool bSuccess = false;
  602. #ifndef GAME_DLL
  603. EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject );
  604. CBaseEntity *pMoveParent = NULL;
  605. if ( phMoveParent )
  606. {
  607. pMoveParent = *( phMoveParent );
  608. }
  609. if ( pMoveParent )
  610. {
  611. s_BoneMutex.Lock();
  612. C_BaseAnimating *pAnimating = pMoveParent->GetBaseAnimating();
  613. bool bInBBox = false;
  614. Vector vecBBoxMin;
  615. Vector vecBBoxMax;
  616. Vector vecOrigin;
  617. vecBBoxMin = pMoveParent->CollisionProp()->OBBMins();
  618. vecBBoxMax = pMoveParent->CollisionProp()->OBBMaxs();
  619. Vector vecLocalPos = vecPos;
  620. if ( pMoveParent->CollisionProp()->IsBoundsDefinedInEntitySpace() )
  621. {
  622. matrix3x4_t matOrientation;
  623. matOrientation = pMoveParent->EntityToWorldTransform();
  624. VectorITransform( vecPos, matOrientation, vecLocalPos );
  625. }
  626. if ( IsPointInBox( vecLocalPos, vecBBoxMin, vecBBoxMax ) )
  627. bInBBox = true;
  628. if ( bInBBox && bBBoxOnly )
  629. bSuccess = true;
  630. else if ( pAnimating && bInBBox )
  631. {
  632. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  633. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  634. {
  635. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  636. if ( pStudioHdr )
  637. {
  638. // Try to get the "effects" set first, otherwise use their current set
  639. int nEffectsHitboxSet = FindHitboxSetByName( pAnimating->GetModelPtr(), pszHitboxSetName );
  640. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( nEffectsHitboxSet != -1 ? nEffectsHitboxSet : pAnimating->GetHitboxSet() );
  641. if ( set )
  642. {
  643. // do a point in solid test
  644. Ray_t ray;
  645. trace_t tr;
  646. ray.Init( vecPos, vecPos );
  647. enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr );
  648. if ( tr.startsolid )
  649. bSuccess = true;
  650. }
  651. }
  652. }
  653. }
  654. else if ( pMoveParent->IsBrushModel() && bInBBox )
  655. {
  656. // do a point in solid test
  657. Ray_t ray;
  658. trace_t tr;
  659. ray.Init( vecPos, vecPos );
  660. enginetrace->ClipRayToEntity( ray, MASK_ALL, pMoveParent, &tr );
  661. if ( tr.startsolid )
  662. bSuccess = true;
  663. }
  664. s_BoneMutex.Unlock();
  665. }
  666. #endif
  667. return bSuccess;
  668. }
  669. void CParticleSystemQuery::GetControllingObjectOBBox(
  670. CParticleCollection *pParticles,
  671. int nControlPointNumber, Vector vecMin, Vector vecMax )
  672. {
  673. vecMin = vecMax = vec3_origin;
  674. #ifndef GAME_DLL
  675. EHANDLE *phMoveParent = reinterpret_cast<EHANDLE *> ( pParticles->ControlPoint( nControlPointNumber ).m_pObject );
  676. CBaseEntity *pMoveParent = NULL;
  677. if ( phMoveParent )
  678. {
  679. pMoveParent = *( phMoveParent );
  680. }
  681. if ( pMoveParent )
  682. {
  683. vecMin = pMoveParent->CollisionProp()->OBBMins();
  684. vecMax = pMoveParent->CollisionProp()->OBBMaxs();
  685. }
  686. #endif
  687. }
  688. extern CUtlVector< RayTracingEnvironment * > g_RayTraceEnvironments;
  689. void CParticleSystemQuery::TraceAgainstRayTraceEnv( int envnumber, const FourRays &rays, fltx4 TMin, fltx4 TMax,
  690. RayTracingResult *rslt_out, int32 skip_id ) const
  691. {
  692. #if defined( CLIENT_DLL )
  693. if ( g_RayTraceEnvironments.IsValidIndex( envnumber ) )
  694. {
  695. RayTracingEnvironment *RtEnv = g_RayTraceEnvironments.Element( envnumber );
  696. RtEnv->Trace4Rays( rays, TMin, TMax, rslt_out, skip_id );
  697. }
  698. #endif
  699. }
  700. struct RayTraceEnvironmentNameRecord_t
  701. {
  702. const char *m_pszGroupName;
  703. int m_nGroupID;
  704. };
  705. static RayTraceEnvironmentNameRecord_t s_RtEnvNameMap[]={
  706. { "PRECIPITATION", 0 },
  707. { "PRECIPITATIONBLOCKER", 1 },
  708. };
  709. int CParticleSystemQuery::GetRayTraceEnvironmentFromName( const char *pszRtEnvName )
  710. {
  711. for(int i = 0; i < ARRAYSIZE( s_RtEnvNameMap ); i++ )
  712. {
  713. if ( ! stricmp( s_RtEnvNameMap[i].m_pszGroupName, pszRtEnvName ) )
  714. return s_RtEnvNameMap[i].m_nGroupID;
  715. }
  716. return 0;
  717. }
  718. struct CollisionGroupNameRecord_t
  719. {
  720. const char *m_pszGroupName;
  721. int m_nGroupID;
  722. };
  723. static CollisionGroupNameRecord_t s_NameMap[]={
  724. { "NONE", COLLISION_GROUP_NONE },
  725. { "DEBRIS", COLLISION_GROUP_DEBRIS },
  726. { "INTERACTIVE", COLLISION_GROUP_INTERACTIVE },
  727. { "NPC", COLLISION_GROUP_NPC },
  728. { "ACTOR", COLLISION_GROUP_NPC_ACTOR },
  729. { "PASSABLE", COLLISION_GROUP_PASSABLE_DOOR },
  730. #if defined( TF_CLIENT_DLL )
  731. { "ROCKETS", TFCOLLISION_GROUP_ROCKETS },
  732. #endif
  733. #if defined( SWARM_DLL )
  734. { "SENTRYPROJ", ASW_COLLISION_GROUP_SENTRY_PROJECTILE },
  735. #endif
  736. };
  737. int CParticleSystemQuery::GetCollisionGroupFromName( const char *pszCollisionGroupName )
  738. {
  739. for(int i = 0; i < ARRAYSIZE( s_NameMap ); i++ )
  740. {
  741. if ( ! stricmp( s_NameMap[i].m_pszGroupName, pszCollisionGroupName ) )
  742. return s_NameMap[i].m_nGroupID;
  743. }
  744. return COLLISION_GROUP_NONE;
  745. }
  746. Vector CParticleSystemQuery::GetLocalPlayerPos( void )
  747. {
  748. #ifdef CLIENT_DLL
  749. // HACK_GETLOCALPLAYER_GUARD( "CParticleSystemQuery::GetLocalPlayerPos" );
  750. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  751. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  752. if ( !pPlayer )
  753. return vec3_origin;
  754. return pPlayer->WorldSpaceCenter();
  755. #else
  756. CBasePlayer *pPlayer = AI_GetSinglePlayer();
  757. if ( !pPlayer )
  758. return vec3_origin;
  759. return pPlayer->WorldSpaceCenter();
  760. #endif
  761. }
  762. void CParticleSystemQuery::GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight, Vector *pUp )
  763. {
  764. #ifdef CLIENT_DLL
  765. // HACK_GETLOCALPLAYER_GUARD( "CParticleSystemQuery::GetLocalPlayerPos" );
  766. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  767. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  768. if ( !pPlayer )
  769. {
  770. *pForward = vec3_origin;
  771. *pRight = vec3_origin;
  772. *pUp = vec3_origin;
  773. return;
  774. }
  775. pPlayer->EyeVectors( pForward, pRight, pUp );
  776. #else
  777. CBasePlayer *pPlayer = AI_GetSinglePlayer();
  778. if ( !pPlayer )
  779. {
  780. *pForward = vec3_origin;
  781. *pRight = vec3_origin;
  782. *pUp = vec3_origin;
  783. return;
  784. }
  785. pPlayer->EyeVectors( pForward, pRight, pUp );
  786. #endif
  787. }
  788. Vector CParticleSystemQuery::GetCurrentViewOrigin()
  789. {
  790. #ifdef CLIENT_DLL
  791. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  792. return CurrentViewOrigin();
  793. #else
  794. return vec3_origin;
  795. #endif
  796. }
  797. float CParticleSystemQuery::GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale )
  798. {
  799. #ifdef CLIENT_DLL
  800. ACTIVE_SPLITSCREEN_PLAYER_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  801. pixelvis_queryparams_t params;
  802. params.Init( vecOrigin, flScale, 1.0 );
  803. float flVisibility = PixelVisibility_FractionVisible( params, pQueryHandle );
  804. flVisibility = MAX( 0.0f, flVisibility );
  805. return flVisibility;
  806. #else
  807. return 0.0f;
  808. #endif
  809. }
  810. void CParticleSystemQuery::DebugDrawLine( const Vector &origin, const Vector &target, int r, int g, int b, bool noDepthTest, float duration )
  811. {
  812. debugoverlay->AddLineOverlay( origin, target, r, g, b, noDepthTest, duration );
  813. }
  814. #include "tier3/mdlutils.h"
  815. #ifdef CLIENT_DLL
  816. static void SetBodygroup( studiohdr_t *pstudiohdr, int &body, int iGroup, int iValue )
  817. {
  818. if ( !pstudiohdr )
  819. {
  820. return;
  821. }
  822. if ( iGroup >= pstudiohdr->numbodyparts )
  823. {
  824. return;
  825. }
  826. mstudiobodyparts_t *pbodypart = pstudiohdr->pBodypart( iGroup );
  827. if ( iValue >= pbodypart->nummodels )
  828. {
  829. return;
  830. }
  831. int iCurrent = ( body / pbodypart->base ) % pbodypart->nummodels;
  832. body = ( body - ( iCurrent * pbodypart->base ) + ( iValue * pbodypart->base ) );
  833. }
  834. #endif
  835. // callback to draw models given abstract ptr
  836. void CParticleSystemQuery::DrawModel( void *pModel, const matrix3x4_t &DrawMatrix, CParticleCollection *pParticles, int nParticleNumber, int nBodyPart, int nSubModel,
  837. int nSkin, int nAnimationSequence, float flAnimationRate, float r, float g, float b, float a )
  838. {
  839. #ifdef CLIENT_DLL
  840. model_t *pMDL = ( model_t * ) pModel;
  841. if ( pMDL )
  842. {
  843. MDLHandle_t hStudioHdr = modelinfo->GetCacheHandle( pMDL );
  844. studiohdr_t *pStudioHdr = mdlcache->GetStudioHdr( hStudioHdr );
  845. CMDL MDL;
  846. MDL.SetMDL( hStudioHdr );
  847. SetBodygroup( pStudioHdr, MDL.m_nBody, nBodyPart, nSubModel );
  848. MDL.m_Color = Color( r * 255, g * 255, b * 255, a * 255 );
  849. MDL.m_nSkin = nSkin;
  850. MDL.m_nSequence = nAnimationSequence;
  851. MDL.m_flPlaybackRate = flAnimationRate;
  852. MDL.m_flTime = pParticles->m_flCurTime;
  853. if ( pStudioHdr )
  854. {
  855. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  856. CMatRenderData< matrix3x4_t > rdBoneToWorld( pRenderContext, pStudioHdr->numbones );
  857. MDL.SetUpBones( DrawMatrix, pStudioHdr->numbones, rdBoneToWorld.Base() );
  858. MDL.Draw(DrawMatrix, rdBoneToWorld.Base(), STUDIORENDER_DRAW_NO_SHADOWS );
  859. }
  860. else
  861. {
  862. MDL.Draw(DrawMatrix);
  863. }
  864. //debugging
  865. // debugoverlay->AddTextOverlay( origin, 0.1, "p", pMDL );
  866. //Vector myOrigin = Vector( DrawMatrix.m_flMatVal[0][3], DrawMatrix.m_flMatVal[1][3], DrawMatrix.m_flMatVal[2][3] );
  867. //Vector vecFwd, vecRight, vecUp;
  868. //MatrixVectors( pRenderable->m_DrawModelMatrix, &vecFwd, &vecRight, &vecUp );
  869. //debugoverlay->AddLineOverlay( myOrigin, myOrigin + 36 * vecFwd, 255, 0, 0, true, 0.1 );
  870. //debugoverlay->AddLineOverlay( myOrigin, myOrigin + 36 * vecUp, 0, 0, 255, true, 0.1 );
  871. //debugoverlay->AddLineOverlay( myOrigin, myOrigin + 36 * vecRight, 0, 255, 0, true, 0.1 );
  872. }
  873. #endif
  874. }
  875. void *CParticleSystemQuery::GetModel( char const *pMdlName )
  876. {
  877. #ifdef CLIENT_DLL
  878. // int modelIndex = modelinfo->GetModelIndex( pMdlName );
  879. // const model_t *pModel = modelinfo->GetModel( modOelIndex );
  880. CUtlString ModelName = "models/";
  881. ModelName += pMdlName;
  882. model_t *pModel = (model_t *)engine->LoadModel( ModelName ); //, true );
  883. //pMdlName = "models/weapons/shells/shell_pistol.mdl";
  884. return ( void * )pModel;
  885. #else
  886. return NULL;
  887. #endif
  888. }
  889. void CParticleSystemQuery::PreSimulate( )
  890. {
  891. #if defined( CLIENT_DLL )
  892. for( int i = 0; i < m_ActiveProjectedInfos.Count(); i++ )
  893. {
  894. m_ActiveProjectedInfos[ i ]->m_bUsedThisFrame = false;
  895. }
  896. #endif // #if defined( CLIENT_DLL )
  897. }
  898. void CParticleSystemQuery::PostSimulate( )
  899. {
  900. #if defined( CLIENT_DLL )
  901. TProjectedTextureInfo *pInfo = NULL;
  902. while( m_ProjectedInfoAdds.PopItem( &pInfo ) == true )
  903. {
  904. m_ActiveProjectedInfos.AddToTail( pInfo );
  905. }
  906. for( int i = 0; i < m_ActiveProjectedInfos.Count(); i++ )
  907. {
  908. if ( m_ActiveProjectedInfos[ i ]->m_bUsedThisFrame == false )
  909. {
  910. delete m_ActiveProjectedInfos[ i ]->m_pEntity;
  911. m_ActiveProjectedInfos.Remove( i );
  912. i--;
  913. continue;
  914. }
  915. if ( m_ActiveProjectedInfos[ i ]->m_pEntity == NULL )
  916. {
  917. m_ActiveProjectedInfos[ i ]->m_pEntity = C_EnvProjectedTexture::Create();
  918. }
  919. m_ActiveProjectedInfos[ i ]->m_pEntity->SetAbsOrigin( m_ActiveProjectedInfos[ i ]->m_vOrigin );
  920. m_ActiveProjectedInfos[ i ]->m_pEntity->SetMaterial( m_ActiveProjectedInfos[ i ]->m_pMaterial );
  921. m_ActiveProjectedInfos[ i ]->m_pEntity->SetLightColor( m_ActiveProjectedInfos[ i ]->m_r * 255, m_ActiveProjectedInfos[ i ]->m_g * 255, m_ActiveProjectedInfos[ i ]->m_b * 255, m_ActiveProjectedInfos[ i ]->m_a * 255 );
  922. m_ActiveProjectedInfos[ i ]->m_pEntity->SetSize( m_ActiveProjectedInfos[ i ]->m_flSize );
  923. m_ActiveProjectedInfos[ i ]->m_pEntity->SetRotation( m_ActiveProjectedInfos[ i ]->m_flRotation );
  924. }
  925. #endif // #if defined( CLIENT_DLL )
  926. }
  927. void CParticleSystemQuery::UpdateProjectedTexture( const int nParticleID, IMaterial *pMaterial, Vector &vOrigin, float flRadius, float flRotation, float r, float g, float b, float a, void *&pUserVar )
  928. {
  929. #if defined( CLIENT_DLL )
  930. TProjectedTextureInfo *pInfo = reinterpret_cast< TProjectedTextureInfo * >( pUserVar );
  931. if ( pInfo == NULL )
  932. {
  933. pUserVar = pInfo = new TProjectedTextureInfo;
  934. memset( pInfo, 0, sizeof( *pInfo ) );
  935. m_ProjectedInfoAdds.PushItem( pInfo );
  936. }
  937. pInfo->m_nParticleID = nParticleID;
  938. pInfo->m_pMaterial = pMaterial;
  939. pInfo->m_vOrigin = vOrigin;
  940. pInfo->m_flSize = flRadius;
  941. pInfo->m_flRotation = flRotation;
  942. pInfo->m_r = r;
  943. pInfo->m_g = g;
  944. pInfo->m_b = b;
  945. pInfo->m_a = a;
  946. pInfo->m_bUsedThisFrame = true;
  947. // ClientEntityList().AddNonNetworkableEntity( this );
  948. #endif // #if defined( CLIENT_DLL )
  949. }
  950. int CParticleSystemQuery::GetActivityCount()
  951. {
  952. return 0;
  953. }
  954. const char* CParticleSystemQuery::GetActivityNameFromIndex( int nActivityIndex )
  955. {
  956. return 0;
  957. }
  958. int CParticleSystemQuery::GetActivityNumber( void *pModel, const char *m_pszActivityName )
  959. {
  960. model_t *pMDL = ( model_t * ) pModel;
  961. if ( pMDL )
  962. {
  963. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pMDL );
  964. if ( !pStudioHdr )
  965. return -1;
  966. CStudioHdr studioHdr( pStudioHdr, mdlcache );
  967. int nActivityNum = LookupActivity( &studioHdr, m_pszActivityName );
  968. return SelectWeightedSequence( &studioHdr, nActivityNum );
  969. }
  970. return -1;
  971. }