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.

426 lines
14 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "filesystem.h"
  8. #include <keyvalues.h>
  9. #include "particle_parse.h"
  10. #include "particles/particles.h"
  11. #ifdef GAME_DLL
  12. #include "te_effect_dispatch.h"
  13. #include "networkstringtable_gamedll.h"
  14. #else
  15. #include "c_te_effect_dispatch.h"
  16. #include "networkstringtable_clientdll.h"
  17. #endif
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. extern void StartParticleEffect( const CEffectData &data, int nSplitScreenPlayerSlot = -1 );
  21. //-----------------------------------------------------------------------------
  22. // Purpose:
  23. //-----------------------------------------------------------------------------
  24. int GetAttachTypeFromString( const char *pszString )
  25. {
  26. if ( !pszString || !pszString[0] )
  27. return -1;
  28. // If you add new attach types, you need to add them to this list
  29. static const char *pAttachmentNames[MAX_PATTACH_TYPES] =
  30. {
  31. "start_at_origin", // PATTACH_ABSORIGIN = 0,
  32. "follow_origin", // PATTACH_ABSORIGIN_FOLLOW,
  33. "start_at_customorigin",// PATTACH_CUSTOMORIGIN,
  34. "follow_customorigin", // PATTACH_CUSTOMORIGIN_FOLLOW,
  35. "start_at_attachment", // PATTACH_POINT,
  36. "follow_attachment", // PATTACH_POINT_FOLLOW,
  37. "follow_eyes", // PATTACH_EYES_FOLLOW,
  38. "follow_overhead", // PATTACH_OVERHEAD_FOLLOW
  39. "world_origin", // PATTACH_WORLDORIGIN
  40. "follow_rootbone" // PATTACH_ROOTBONE_FOLLOW
  41. };
  42. for ( int i = 0; i < MAX_PATTACH_TYPES; i++ )
  43. {
  44. if ( FStrEq( pAttachmentNames[i], pszString ) )
  45. return i;
  46. }
  47. return -1;
  48. }
  49. //-----------------------------------------------------------------------------
  50. // Purpose:
  51. //-----------------------------------------------------------------------------
  52. void ParseParticleEffects( bool bLoadSheets )
  53. {
  54. MEM_ALLOC_CREDIT();
  55. g_pParticleSystemMgr->ShouldLoadSheets( bLoadSheets );
  56. CUtlVector<CUtlString> files;
  57. GetParticleManifest( files );
  58. int nCount = files.Count();
  59. for ( int i = 0; i < nCount; ++i )
  60. {
  61. g_pParticleSystemMgr->ReadParticleConfigFile( files[i], false, false );
  62. }
  63. g_pParticleSystemMgr->DecommitTempMemory();
  64. }
  65. //-----------------------------------------------------------------------------
  66. // Purpose:
  67. //-----------------------------------------------------------------------------
  68. void PrecacheStandardParticleSystems( )
  69. {
  70. #ifdef GAME_DLL
  71. // Now add each particle system name to the network string pool, so we can send string_t's
  72. // down to the client instead of full particle system names.
  73. for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
  74. {
  75. const char *pParticleSystemName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
  76. CParticleSystemDefinition *pParticleSystem = g_pParticleSystemMgr->FindParticleSystem( pParticleSystemName );
  77. if ( pParticleSystem->ShouldAlwaysPrecache() )
  78. {
  79. PrecacheParticleSystem( pParticleSystemName );
  80. }
  81. }
  82. #endif
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, bool bResetAllParticlesOnEntity, int nSplitScreenPlayerSlot /*= -1*/, IRecipientFilter *filter /*= NULL*/ )
  88. {
  89. int iAttachment = -1;
  90. if ( pEntity && pEntity->GetBaseAnimating() )
  91. {
  92. // Find the attachment point index
  93. iAttachment = pEntity->GetBaseAnimating()->LookupAttachment( pszAttachmentName );
  94. if ( iAttachment == -1 )
  95. {
  96. Warning("Model '%s' doesn't have attachment '%s' to attach particle system '%s' to.\n", STRING(pEntity->GetBaseAnimating()->GetModelName()), pszAttachmentName, pszParticleName );
  97. return;
  98. }
  99. }
  100. DispatchParticleEffect( pszParticleName, iAttachType, pEntity, iAttachment, bResetAllParticlesOnEntity, nSplitScreenPlayerSlot, filter );
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose:
  104. //-----------------------------------------------------------------------------
  105. void DispatchParticleEffect( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, int iAttachmentPoint, bool bResetAllParticlesOnEntity, int nSplitScreenPlayerSlot /*= -1*/, IRecipientFilter *filter /*= NULL*/, bool bAllowDormantSpawn )
  106. {
  107. CEffectData data;
  108. if ( pEntity )
  109. {
  110. data.m_vOrigin = pEntity->GetAbsOrigin();
  111. }
  112. data.m_nHitBox = GetParticleSystemIndex( pszParticleName );
  113. if ( pEntity )
  114. {
  115. #ifdef CLIENT_DLL
  116. data.m_hEntity = pEntity;
  117. #else
  118. data.m_nEntIndex = pEntity->entindex();
  119. #endif
  120. data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY;
  121. }
  122. data.m_nDamageType = iAttachType;
  123. data.m_nAttachmentIndex = iAttachmentPoint;
  124. if ( bResetAllParticlesOnEntity )
  125. {
  126. data.m_fFlags |= PARTICLE_DISPATCH_RESET_PARTICLES;
  127. }
  128. if ( bAllowDormantSpawn )
  129. {
  130. data.m_fFlags |= PARTICLE_DISPATCH_ALLOW_DORMANT;
  131. }
  132. // Avoid an unnecessary string search, also behaves better w/ precache checks
  133. #ifndef CLIENT_DLL
  134. if ( filter )
  135. DispatchEffect( *filter, 0.0f, "ParticleEffect", data );
  136. else
  137. DispatchEffect( "ParticleEffect", data );
  138. #else
  139. StartParticleEffect( data, nSplitScreenPlayerSlot );
  140. #endif
  141. }
  142. //-----------------------------------------------------------------------------
  143. // Purpose:
  144. //-----------------------------------------------------------------------------
  145. void DispatchParticleEffectLink( const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, CBaseEntity *pOtherEntity, int iAttachmentPoint, bool bResetAllParticlesOnEntity, int nSplitScreenPlayerSlot /*= -1*/ )
  146. {
  147. CEffectData data;
  148. if ( pEntity )
  149. {
  150. data.m_vOrigin = pEntity->GetAbsOrigin();
  151. }
  152. data.m_nHitBox = GetParticleSystemIndex( pszParticleName );
  153. if ( pEntity && pOtherEntity )
  154. {
  155. #ifdef CLIENT_DLL
  156. data.m_hEntity = pEntity;
  157. #else
  158. data.m_nEntIndex = pEntity->entindex();
  159. #endif
  160. data.m_nOtherEntIndex = pOtherEntity->entindex();
  161. data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY;
  162. }
  163. data.m_nDamageType = iAttachType;
  164. data.m_nAttachmentIndex = iAttachmentPoint;
  165. if ( bResetAllParticlesOnEntity )
  166. {
  167. data.m_fFlags |= PARTICLE_DISPATCH_RESET_PARTICLES;
  168. }
  169. // Avoid an unnecessary string search, also behaves better w/ precache checks
  170. #ifndef CLIENT_DLL
  171. DispatchEffect( "ParticleEffect", data );
  172. #else
  173. StartParticleEffect( data, nSplitScreenPlayerSlot );
  174. #endif
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. void DispatchParticleEffect( int nEffectIndex, const Vector &vecOrigin, const QAngle &vecAngles, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, int nSplitScreenPlayerSlot /*= -1*/ )
  180. {
  181. CEffectData data;
  182. data.m_nHitBox = nEffectIndex;
  183. data.m_vOrigin = vecOrigin;
  184. data.m_vAngles = vecAngles;
  185. if ( pEntity )
  186. {
  187. #ifdef CLIENT_DLL
  188. data.m_hEntity = pEntity;
  189. #else
  190. data.m_nEntIndex = pEntity->entindex();
  191. #endif
  192. data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY;
  193. data.m_nDamageType = iAttachType;
  194. }
  195. else
  196. {
  197. #ifdef CLIENT_DLL
  198. data.m_hEntity = NULL;
  199. #else
  200. data.m_nEntIndex = 0;
  201. #endif
  202. }
  203. #ifndef CLIENT_DLL
  204. DispatchEffect( "ParticleEffect", data );
  205. #else
  206. // Avoid an unnecessary search, also behaves better w/ precache checks...
  207. StartParticleEffect( data, nSplitScreenPlayerSlot );
  208. #endif
  209. }
  210. void DispatchParticleEffect( const char *pszParticleName, const Vector &vecOrigin, const QAngle &vecAngles, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, int nSplitScreenPlayerSlot /*= -1*/ )
  211. {
  212. int nEffectIndex = GetParticleSystemIndex( pszParticleName );
  213. DispatchParticleEffect( nEffectIndex, vecOrigin, vecAngles, iAttachType, pEntity, nSplitScreenPlayerSlot );
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose:
  217. //-----------------------------------------------------------------------------
  218. void DispatchParticleEffect( int iEffectIndex, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity, int nSplitScreenPlayerSlot /*= -1*/, IRecipientFilter *filter /*= NULL*/ )
  219. {
  220. CEffectData data;
  221. data.m_nHitBox = iEffectIndex;
  222. data.m_vOrigin = vecOrigin;
  223. data.m_vStart = vecStart;
  224. data.m_vAngles = vecAngles;
  225. if ( pEntity )
  226. {
  227. #ifdef CLIENT_DLL
  228. data.m_hEntity = pEntity;
  229. #else
  230. data.m_nEntIndex = pEntity->entindex();
  231. #endif
  232. data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY;
  233. data.m_nDamageType = PATTACH_CUSTOMORIGIN;
  234. }
  235. else
  236. {
  237. #ifdef CLIENT_DLL
  238. data.m_hEntity = NULL;
  239. #else
  240. data.m_nEntIndex = 0;
  241. #endif
  242. }
  243. #ifndef CLIENT_DLL
  244. if ( filter )
  245. {
  246. DispatchEffect( *filter, 0.0f, "ParticleEffect", data );
  247. }
  248. else
  249. {
  250. DispatchEffect( "ParticleEffect", data );
  251. }
  252. #else
  253. // Avoid an unnecessary search, also behaves better w/ precache checks...
  254. StartParticleEffect( data, nSplitScreenPlayerSlot );
  255. #endif
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose:
  259. //-----------------------------------------------------------------------------
  260. void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, QAngle vecAngles, CBaseEntity *pEntity, int nSplitScreenPlayerSlot /*= -1*/, IRecipientFilter *filter /*= NULL*/ )
  261. {
  262. int iIndex = GetParticleSystemIndex( pszParticleName );
  263. DispatchParticleEffect( iIndex, vecOrigin, vecOrigin, vecAngles, pEntity, nSplitScreenPlayerSlot, filter );
  264. }
  265. //-----------------------------------------------------------------------------
  266. // Purpose: Yet another overload, lets us supply vecStart
  267. //-----------------------------------------------------------------------------
  268. void DispatchParticleEffect( const char *pszParticleName, Vector vecOrigin, Vector vecStart, QAngle vecAngles, CBaseEntity *pEntity, int nSplitScreenPlayerSlot /*= -1*/, IRecipientFilter *filter /*= NULL*/ )
  269. {
  270. int iIndex = GetParticleSystemIndex( pszParticleName );
  271. DispatchParticleEffect( iIndex, vecOrigin, vecStart, vecAngles, pEntity, nSplitScreenPlayerSlot, filter );
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose:
  275. //-----------------------------------------------------------------------------
  276. void StopParticleEffects( CBaseEntity *pEntity )
  277. {
  278. CEffectData data;
  279. if ( pEntity )
  280. {
  281. #ifdef CLIENT_DLL
  282. data.m_hEntity = pEntity;
  283. #else
  284. data.m_nEntIndex = pEntity->entindex();
  285. #endif
  286. }
  287. DispatchEffect( "ParticleEffectStop", data );
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose:
  291. //-----------------------------------------------------------------------------
  292. void StopParticleEffect( CBaseEntity *pEntity, const char *pszParticleName )
  293. {
  294. CEffectData data;
  295. if ( pEntity )
  296. {
  297. #ifdef CLIENT_DLL
  298. data.m_hEntity = pEntity;
  299. #else
  300. data.m_nEntIndex = pEntity->entindex();
  301. #endif
  302. }
  303. data.m_nHitBox = GetParticleSystemIndex( pszParticleName );
  304. DispatchEffect( "ParticleEffectStop", data );
  305. }
  306. #ifndef CLIENT_DLL
  307. extern CBaseEntity *GetNextCommandEntity( CBasePlayer *pPlayer, const char *name, CBaseEntity *ent );
  308. ConVar particle_test_file( "particle_test_file", "", FCVAR_CHEAT, "Name of the particle system to dynamically spawn" );
  309. ConVar particle_test_attach_mode( "particle_test_attach_mode", "follow_attachment", FCVAR_CHEAT, "Possible Values: 'start_at_attachment', 'follow_attachment', 'start_at_origin', 'follow_origin'" );
  310. ConVar particle_test_attach_attachment( "particle_test_attach_attachment", "0", FCVAR_CHEAT, "Attachment index for attachment mode" );
  311. void Particle_Test_Start( CBasePlayer* pPlayer, const char *name, bool bStart )
  312. {
  313. if ( !pPlayer )
  314. return;
  315. int iAttachType = GetAttachTypeFromString( particle_test_attach_mode.GetString() );
  316. if ( iAttachType < 0 )
  317. {
  318. Warning( "Invalid attach type specified for particle_test in cvar 'particle_test_attach_mode.\n" );
  319. return;
  320. }
  321. int iAttachmentIndex = particle_test_attach_attachment.GetInt();
  322. const char *pszParticleFile = particle_test_file.GetString();
  323. CBaseEntity *pEntity = NULL;
  324. while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL )
  325. {
  326. /*
  327. Fire the test particle system on this entity
  328. */
  329. DispatchParticleEffect(
  330. pszParticleFile,
  331. (ParticleAttachment_t)iAttachType,
  332. pEntity,
  333. iAttachmentIndex,
  334. true ); // stops existing particle systems
  335. }
  336. }
  337. void CC_Particle_Test_Start( const CCommand& args )
  338. {
  339. Particle_Test_Start( UTIL_GetCommandClient(), args[1], true );
  340. }
  341. static ConCommand particle_test_start("particle_test_start", CC_Particle_Test_Start, "Dispatches the test particle system with the parameters specified in particle_test_file,\n particle_test_attach_mode and particle_test_attach_param on the entity the player is looking at.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  342. void Particle_Test_Stop( CBasePlayer* pPlayer, const char *name, bool bStart )
  343. {
  344. if ( !pPlayer )
  345. return;
  346. CBaseEntity *pEntity = NULL;
  347. while ( (pEntity = GetNextCommandEntity( pPlayer, name, pEntity )) != NULL )
  348. {
  349. //Stop all particle systems on the selected entity
  350. DispatchParticleEffect( "", PATTACH_ABSORIGIN, pEntity, 0, true );
  351. }
  352. }
  353. void CC_Particle_Test_Stop( const CCommand& args )
  354. {
  355. Particle_Test_Stop( UTIL_GetCommandClient(), args[1], false );
  356. }
  357. static ConCommand particle_test_stop("particle_test_stop", CC_Particle_Test_Stop, "Stops all particle systems on the selected entities.\n\tArguments: {entity_name} / {class_name} / no argument picks what player is looking at ", FCVAR_CHEAT);
  358. #endif //CLIENT_DLL