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

2010 lines
60 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. #include "cbase.h"
  9. #include "c_smoke_trail.h"
  10. #include "fx.h"
  11. #include "engine/ivdebugoverlay.h"
  12. #include "engine/IEngineSound.h"
  13. #include "c_te_effect_dispatch.h"
  14. #include "glow_overlay.h"
  15. #include "fx_explosion.h"
  16. #include "tier1/KeyValues.h"
  17. #include "toolframework_client.h"
  18. #include "view.h"
  19. #include "clienteffectprecachesystem.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. //
  23. // CRocketTrailParticle
  24. //
  25. class CRocketTrailParticle : public CSimpleEmitter
  26. {
  27. public:
  28. CRocketTrailParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  29. //Create
  30. static CRocketTrailParticle *Create( const char *pDebugName )
  31. {
  32. return new CRocketTrailParticle( pDebugName );
  33. }
  34. //Roll
  35. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  36. {
  37. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  38. pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
  39. //Cap the minimum roll
  40. if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
  41. {
  42. pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
  43. }
  44. return pParticle->m_flRoll;
  45. }
  46. //Alpha
  47. virtual float UpdateAlpha( const SimpleParticle *pParticle )
  48. {
  49. return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
  50. }
  51. private:
  52. CRocketTrailParticle( const CRocketTrailParticle & );
  53. };
  54. //
  55. // CSmokeParticle
  56. //
  57. class CSmokeParticle : public CSimpleEmitter
  58. {
  59. public:
  60. CSmokeParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  61. //Create
  62. static CSmokeParticle *Create( const char *pDebugName )
  63. {
  64. return new CSmokeParticle( pDebugName );
  65. }
  66. //Alpha
  67. virtual float UpdateAlpha( const SimpleParticle *pParticle )
  68. {
  69. return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
  70. }
  71. //Color
  72. virtual Vector UpdateColor( const SimpleParticle *pParticle )
  73. {
  74. Vector color;
  75. float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
  76. float ramp = 1.0f - tLifetime;
  77. color[0] = ( (float) pParticle->m_uchColor[0] * ramp ) / 255.0f;
  78. color[1] = ( (float) pParticle->m_uchColor[1] * ramp ) / 255.0f;
  79. color[2] = ( (float) pParticle->m_uchColor[2] * ramp ) / 255.0f;
  80. return color;
  81. }
  82. //Roll
  83. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  84. {
  85. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  86. pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
  87. //Cap the minimum roll
  88. if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
  89. {
  90. pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
  91. }
  92. return pParticle->m_flRoll;
  93. }
  94. private:
  95. CSmokeParticle( const CSmokeParticle & );
  96. };
  97. // Datatable.. this can have all the smoketrail parameters when we need it to.
  98. IMPLEMENT_CLIENTCLASS_DT(C_SmokeTrail, DT_SmokeTrail, SmokeTrail)
  99. RecvPropFloat(RECVINFO(m_SpawnRate)),
  100. RecvPropVector(RECVINFO(m_StartColor)),
  101. RecvPropVector(RECVINFO(m_EndColor)),
  102. RecvPropFloat(RECVINFO(m_ParticleLifetime)),
  103. RecvPropFloat(RECVINFO(m_StopEmitTime)),
  104. RecvPropFloat(RECVINFO(m_MinSpeed)),
  105. RecvPropFloat(RECVINFO(m_MaxSpeed)),
  106. RecvPropFloat(RECVINFO(m_MinDirectedSpeed)),
  107. RecvPropFloat(RECVINFO(m_MaxDirectedSpeed)),
  108. RecvPropFloat(RECVINFO(m_StartSize)),
  109. RecvPropFloat(RECVINFO(m_EndSize)),
  110. RecvPropFloat(RECVINFO(m_SpawnRadius)),
  111. RecvPropInt(RECVINFO(m_bEmit)),
  112. RecvPropInt(RECVINFO(m_nAttachment)),
  113. RecvPropFloat(RECVINFO(m_Opacity)),
  114. END_RECV_TABLE()
  115. // ------------------------------------------------------------------------- //
  116. // ParticleMovieExplosion
  117. // ------------------------------------------------------------------------- //
  118. C_SmokeTrail::C_SmokeTrail()
  119. {
  120. m_MaterialHandle[0] = NULL;
  121. m_MaterialHandle[1] = NULL;
  122. m_SpawnRate = 10;
  123. m_ParticleSpawn.Init(10);
  124. m_StartColor.Init(0.5, 0.5, 0.5);
  125. m_EndColor.Init(0,0,0);
  126. m_ParticleLifetime = 5;
  127. m_StopEmitTime = 0; // No end time
  128. m_MinSpeed = 2;
  129. m_MaxSpeed = 4;
  130. m_MinDirectedSpeed = m_MaxDirectedSpeed = 0;
  131. m_StartSize = 35;
  132. m_EndSize = 55;
  133. m_SpawnRadius = 2;
  134. m_VelocityOffset.Init();
  135. m_Opacity = 0.5f;
  136. m_bEmit = true;
  137. m_nAttachment = -1;
  138. m_pSmokeEmitter = NULL;
  139. m_pParticleMgr = NULL;
  140. }
  141. C_SmokeTrail::~C_SmokeTrail()
  142. {
  143. if ( ToolsEnabled() && clienttools->IsInRecordingMode() && m_pSmokeEmitter.IsValid() && m_pSmokeEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID )
  144. {
  145. KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" );
  146. msg->SetInt( "id", m_pSmokeEmitter->GetToolParticleEffectId() );
  147. msg->SetInt( "emitter", 0 );
  148. msg->SetInt( "active", false );
  149. msg->SetFloat( "time", gpGlobals->curtime );
  150. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  151. msg->deleteThis();
  152. }
  153. if ( m_pParticleMgr )
  154. {
  155. m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
  156. }
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. void C_SmokeTrail::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles )
  162. {
  163. C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity();
  164. if (pEnt && (m_nAttachment > 0))
  165. {
  166. pEnt->GetAttachment( m_nAttachment, *pAbsOrigin, *pAbsAngles );
  167. }
  168. else
  169. {
  170. BaseClass::GetAimEntOrigin( pAttachedTo, pAbsOrigin, pAbsAngles );
  171. }
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose:
  175. // Input : bEmit -
  176. //-----------------------------------------------------------------------------
  177. void C_SmokeTrail::SetEmit(bool bEmit)
  178. {
  179. m_bEmit = bEmit;
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose:
  183. // Input : rate -
  184. //-----------------------------------------------------------------------------
  185. void C_SmokeTrail::SetSpawnRate(float rate)
  186. {
  187. m_SpawnRate = rate;
  188. m_ParticleSpawn.Init(rate);
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose:
  192. // Input : bnewentity -
  193. //-----------------------------------------------------------------------------
  194. void C_SmokeTrail::OnDataChanged(DataUpdateType_t updateType)
  195. {
  196. C_BaseEntity::OnDataChanged(updateType);
  197. if ( updateType == DATA_UPDATE_CREATED )
  198. {
  199. Start( ParticleMgr(), NULL );
  200. }
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose:
  204. // Input : *pParticleMgr -
  205. // *pArgs -
  206. //-----------------------------------------------------------------------------
  207. void C_SmokeTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  208. {
  209. if(!pParticleMgr->AddEffect( &m_ParticleEffect, this ))
  210. return;
  211. m_pParticleMgr = pParticleMgr;
  212. m_pSmokeEmitter = CSmokeParticle::Create("smokeTrail");
  213. if ( !m_pSmokeEmitter )
  214. {
  215. Assert( false );
  216. return;
  217. }
  218. m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() );
  219. m_pSmokeEmitter->SetNearClip( 64.0f, 128.0f );
  220. m_MaterialHandle[0] = g_Mat_DustPuff[0];
  221. m_MaterialHandle[1] = g_Mat_DustPuff[1];
  222. m_ParticleSpawn.Init( m_SpawnRate );
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose:
  226. // Input : fTimeDelta -
  227. //-----------------------------------------------------------------------------
  228. void C_SmokeTrail::Update( float fTimeDelta )
  229. {
  230. if ( !m_pSmokeEmitter )
  231. return;
  232. Vector offsetColor;
  233. // Add new particles
  234. if ( !m_bEmit )
  235. return;
  236. if ( ( m_StopEmitTime != 0 ) && ( m_StopEmitTime <= gpGlobals->curtime ) )
  237. return;
  238. float tempDelta = fTimeDelta;
  239. SimpleParticle *pParticle;
  240. Vector offset;
  241. Vector vecOrigin;
  242. VectorMA( GetAbsOrigin(), -fTimeDelta, GetAbsVelocity(), vecOrigin );
  243. Vector vecForward;
  244. GetVectors( &vecForward, NULL, NULL );
  245. while( m_ParticleSpawn.NextEvent( tempDelta ) )
  246. {
  247. float fldt = fTimeDelta - tempDelta;
  248. offset.Random( -m_SpawnRadius, m_SpawnRadius );
  249. offset += vecOrigin;
  250. VectorMA( offset, fldt, GetAbsVelocity(), offset );
  251. pParticle = (SimpleParticle *) m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), m_MaterialHandle[random->RandomInt(0,1)], offset );
  252. if ( pParticle == NULL )
  253. continue;
  254. pParticle->m_flLifetime = 0.0f;
  255. pParticle->m_flDieTime = m_ParticleLifetime;
  256. pParticle->m_vecVelocity.Random( -1.0f, 1.0f );
  257. pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed );
  258. pParticle->m_vecVelocity = pParticle->m_vecVelocity + GetAbsVelocity();
  259. float flDirectedVel = random->RandomFloat( m_MinDirectedSpeed, m_MaxDirectedSpeed );
  260. VectorMA( pParticle->m_vecVelocity, flDirectedVel, vecForward, pParticle->m_vecVelocity );
  261. offsetColor = m_StartColor;
  262. float flMaxVal = MAX( m_StartColor[0], m_StartColor[1] );
  263. if ( flMaxVal < m_StartColor[2] )
  264. {
  265. flMaxVal = m_StartColor[2];
  266. }
  267. offsetColor /= flMaxVal;
  268. offsetColor *= random->RandomFloat( -0.2f, 0.2f );
  269. offsetColor += m_StartColor;
  270. offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f );
  271. offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f );
  272. offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f );
  273. pParticle->m_uchColor[0] = offsetColor[0]*255.0f;
  274. pParticle->m_uchColor[1] = offsetColor[1]*255.0f;
  275. pParticle->m_uchColor[2] = offsetColor[2]*255.0f;
  276. pParticle->m_uchStartSize = m_StartSize;
  277. pParticle->m_uchEndSize = m_EndSize;
  278. float alpha = random->RandomFloat( m_Opacity*0.75f, m_Opacity*1.25f );
  279. alpha = clamp( alpha, 0.0f, 1.0f );
  280. pParticle->m_uchStartAlpha = alpha * 255;
  281. pParticle->m_uchEndAlpha = 0;
  282. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  283. pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
  284. }
  285. }
  286. void C_SmokeTrail::RenderParticles( CParticleRenderIterator *pIterator )
  287. {
  288. }
  289. void C_SmokeTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
  290. {
  291. }
  292. //-----------------------------------------------------------------------------
  293. // This is called after sending this entity's recording state
  294. //-----------------------------------------------------------------------------
  295. void C_SmokeTrail::CleanupToolRecordingState( KeyValues *msg )
  296. {
  297. if ( !ToolsEnabled() )
  298. return;
  299. BaseClass::CleanupToolRecordingState( msg );
  300. // Generally, this is used to allow the entity to clean up
  301. // allocated state it put into the message, but here we're going
  302. // to use it to send particle system messages because we
  303. // know the grenade has been recorded at this point
  304. if ( !clienttools->IsInRecordingMode() || !m_pSmokeEmitter.IsValid() )
  305. return;
  306. // For now, we can't record smoketrails that don't have a moveparent
  307. C_BaseEntity *pEnt = GetMoveParent();
  308. if ( !pEnt )
  309. return;
  310. bool bEmitterActive = m_bEmit && ( ( m_StopEmitTime == 0 ) || ( m_StopEmitTime > gpGlobals->curtime ) );
  311. // NOTE: Particle system destruction message will be sent by the particle effect itself.
  312. if ( m_pSmokeEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID )
  313. {
  314. int nId = m_pSmokeEmitter->AllocateToolParticleEffectId();
  315. KeyValues *oldmsg = new KeyValues( "OldParticleSystem_Create" );
  316. oldmsg->SetString( "name", "C_SmokeTrail" );
  317. oldmsg->SetInt( "id", nId );
  318. oldmsg->SetFloat( "time", gpGlobals->curtime );
  319. KeyValues *pRandomEmitter = oldmsg->FindKey( "DmeRandomEmitter", true );
  320. pRandomEmitter->SetInt( "count", m_SpawnRate ); // particles per second, when duration is < 0
  321. pRandomEmitter->SetFloat( "duration", -1 );
  322. pRandomEmitter->SetInt( "active", bEmitterActive );
  323. KeyValues *pEmitterParent1 = pRandomEmitter->FindKey( "emitter1", true );
  324. pEmitterParent1->SetFloat( "randomamount", 0.5f );
  325. KeyValues *pEmitterParent2 = pRandomEmitter->FindKey( "emitter2", true );
  326. pEmitterParent2->SetFloat( "randomamount", 0.5f );
  327. KeyValues *pEmitter = pEmitterParent1->FindKey( "DmeSpriteEmitter", true );
  328. pEmitter->SetString( "material", "particle/particle_smokegrenade" );
  329. KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
  330. // FIXME: Until we can interpolate ent logs during emission, this can't work
  331. KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true );
  332. pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
  333. pPosition->SetInt( "attachmentIndex", m_nAttachment );
  334. pPosition->SetFloat( "randomDist", m_SpawnRadius );
  335. pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x );
  336. pPosition->SetFloat( "starty", pEnt->GetAbsOrigin().y );
  337. pPosition->SetFloat( "startz", pEnt->GetAbsOrigin().z );
  338. KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
  339. pLifetime->SetFloat( "minLifetime", m_ParticleLifetime );
  340. pLifetime->SetFloat( "maxLifetime", m_ParticleLifetime );
  341. KeyValues *pVelocity = pInitializers->FindKey( "DmeAttachmentVelocityInitializer", true );
  342. pVelocity->SetPtr( "entindex", (void*)entindex() );
  343. pVelocity->SetFloat( "minAttachmentSpeed", m_MinDirectedSpeed );
  344. pVelocity->SetFloat( "maxAttachmentSpeed", m_MaxDirectedSpeed );
  345. pVelocity->SetFloat( "minRandomSpeed", m_MinSpeed );
  346. pVelocity->SetFloat( "maxRandomSpeed", m_MaxSpeed );
  347. KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
  348. pRoll->SetFloat( "minRoll", 0.0f );
  349. pRoll->SetFloat( "maxRoll", 360.0f );
  350. KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
  351. pRollSpeed->SetFloat( "minRollSpeed", -1.0f );
  352. pRollSpeed->SetFloat( "maxRollSpeed", 1.0f );
  353. KeyValues *pColor = pInitializers->FindKey( "DmeRandomValueColorInitializer", true );
  354. Color c(
  355. FastFToC( clamp( m_StartColor.x, 0.f, 1.f ) ),
  356. FastFToC( clamp( m_StartColor.y, 0.f, 1.f ) ),
  357. FastFToC( clamp( m_StartColor.z, 0.f, 1.f ) ),
  358. 255 );
  359. pColor->SetColor( "startColor", c );
  360. pColor->SetFloat( "minStartValueDelta", -0.2f );
  361. pColor->SetFloat( "maxStartValueDelta", 0.2f );
  362. pColor->SetColor( "endColor", Color( 0, 0, 0, 255 ) );
  363. KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
  364. int nMinAlpha = 255 * m_Opacity * 0.75f;
  365. int nMaxAlpha = 255 * m_Opacity * 1.25f;
  366. pAlpha->SetInt( "minStartAlpha", 0 );
  367. pAlpha->SetInt( "maxStartAlpha", 0 );
  368. pAlpha->SetInt( "minEndAlpha", clamp( nMinAlpha, 0, 255 ) );
  369. pAlpha->SetInt( "maxEndAlpha", clamp( nMaxAlpha, 0, 255 ) );
  370. KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true );
  371. pSize->SetFloat( "minStartSize", m_StartSize );
  372. pSize->SetFloat( "maxStartSize", m_StartSize );
  373. pSize->SetFloat( "minEndSize", m_EndSize );
  374. pSize->SetFloat( "maxEndSize", m_EndSize );
  375. KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
  376. pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
  377. pUpdaters->FindKey( "DmeRollUpdater", true );
  378. KeyValues *pRollSpeedUpdater = pUpdaters->FindKey( "DmeRollSpeedAttenuateUpdater", true );
  379. pRollSpeedUpdater->SetFloat( "attenuation", 1.0f - 8.0f / 30.0f );
  380. pRollSpeedUpdater->SetFloat( "attenuationTme", 1.0f / 30.0f );
  381. pRollSpeedUpdater->SetFloat( "minRollSpeed", 0.5f );
  382. pUpdaters->FindKey( "DmeAlphaSineUpdater", true );
  383. pUpdaters->FindKey( "DmeColorUpdater", true );
  384. pUpdaters->FindKey( "DmeSizeUpdater", true );
  385. KeyValues *pEmitter2 = pEmitter->MakeCopy();
  386. pEmitter2->SetString( "material", "particle/particle_noisesphere" );
  387. pEmitterParent2->AddSubKey( pEmitter2 );
  388. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, oldmsg );
  389. oldmsg->deleteThis();
  390. }
  391. else
  392. {
  393. KeyValues *oldmsg = new KeyValues( "OldParticleSystem_ActivateEmitter" );
  394. oldmsg->SetInt( "id", m_pSmokeEmitter->GetToolParticleEffectId() );
  395. oldmsg->SetInt( "emitter", 0 );
  396. oldmsg->SetInt( "active", bEmitterActive );
  397. oldmsg->SetFloat( "time", gpGlobals->curtime );
  398. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, oldmsg );
  399. oldmsg->deleteThis();
  400. }
  401. }
  402. //==================================================
  403. // RocketTrail
  404. //==================================================
  405. // Expose to the particle app.
  406. EXPOSE_PROTOTYPE_EFFECT(RocketTrail, C_RocketTrail);
  407. // Datatable.. this can have all the smoketrail parameters when we need it to.
  408. IMPLEMENT_CLIENTCLASS_DT(C_RocketTrail, DT_RocketTrail, RocketTrail)
  409. RecvPropFloat(RECVINFO(m_SpawnRate)),
  410. RecvPropVector(RECVINFO(m_StartColor)),
  411. RecvPropVector(RECVINFO(m_EndColor)),
  412. RecvPropFloat(RECVINFO(m_ParticleLifetime)),
  413. RecvPropFloat(RECVINFO(m_StopEmitTime)),
  414. RecvPropFloat(RECVINFO(m_MinSpeed)),
  415. RecvPropFloat(RECVINFO(m_MaxSpeed)),
  416. RecvPropFloat(RECVINFO(m_StartSize)),
  417. RecvPropFloat(RECVINFO(m_EndSize)),
  418. RecvPropFloat(RECVINFO(m_SpawnRadius)),
  419. RecvPropInt(RECVINFO(m_bEmit)),
  420. RecvPropInt(RECVINFO(m_nAttachment)),
  421. RecvPropFloat(RECVINFO(m_Opacity)),
  422. RecvPropInt(RECVINFO(m_bDamaged)),
  423. RecvPropFloat(RECVINFO(m_flFlareScale)),
  424. END_RECV_TABLE()
  425. // ------------------------------------------------------------------------- //
  426. // ParticleMovieExplosion
  427. // ------------------------------------------------------------------------- //
  428. C_RocketTrail::C_RocketTrail()
  429. {
  430. m_MaterialHandle[0] = NULL;
  431. m_MaterialHandle[1] = NULL;
  432. m_SpawnRate = 10;
  433. m_ParticleSpawn.Init(10);
  434. m_StartColor.Init(0.5, 0.5, 0.5);
  435. m_EndColor.Init(0,0,0);
  436. m_ParticleLifetime = 5;
  437. m_StopEmitTime = 0; // No end time
  438. m_MinSpeed = 2;
  439. m_MaxSpeed = 4;
  440. m_StartSize = 35;
  441. m_EndSize = 55;
  442. m_SpawnRadius = 2;
  443. m_VelocityOffset.Init();
  444. m_Opacity = 0.5f;
  445. m_bEmit = true;
  446. m_bDamaged = false;
  447. m_nAttachment = -1;
  448. m_pRocketEmitter = NULL;
  449. m_pParticleMgr = NULL;
  450. }
  451. C_RocketTrail::~C_RocketTrail()
  452. {
  453. if ( m_pParticleMgr )
  454. {
  455. m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
  456. }
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose:
  460. //-----------------------------------------------------------------------------
  461. void C_RocketTrail::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles )
  462. {
  463. C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity();
  464. if (pEnt && (m_nAttachment > 0))
  465. {
  466. pEnt->GetAttachment( m_nAttachment, *pAbsOrigin, *pAbsAngles );
  467. }
  468. else
  469. {
  470. BaseClass::GetAimEntOrigin( pAttachedTo, pAbsOrigin, pAbsAngles );
  471. }
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose:
  475. // Input : bEmit -
  476. //-----------------------------------------------------------------------------
  477. void C_RocketTrail::SetEmit(bool bEmit)
  478. {
  479. m_bEmit = bEmit;
  480. }
  481. //-----------------------------------------------------------------------------
  482. // Purpose:
  483. // Input : rate -
  484. //-----------------------------------------------------------------------------
  485. void C_RocketTrail::SetSpawnRate(float rate)
  486. {
  487. m_SpawnRate = rate;
  488. m_ParticleSpawn.Init(rate);
  489. }
  490. //-----------------------------------------------------------------------------
  491. // Purpose:
  492. // Input : bnewentity -
  493. //-----------------------------------------------------------------------------
  494. void C_RocketTrail::OnDataChanged(DataUpdateType_t updateType)
  495. {
  496. C_BaseEntity::OnDataChanged(updateType);
  497. if ( updateType == DATA_UPDATE_CREATED )
  498. {
  499. Start( ParticleMgr(), NULL );
  500. }
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose:
  504. // Input : *pParticleMgr -
  505. // *pArgs -
  506. //-----------------------------------------------------------------------------
  507. void C_RocketTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  508. {
  509. if(!pParticleMgr->AddEffect( &m_ParticleEffect, this ))
  510. return;
  511. m_pParticleMgr = pParticleMgr;
  512. m_pRocketEmitter = CRocketTrailParticle::Create("smokeTrail");
  513. if ( !m_pRocketEmitter )
  514. {
  515. Assert( false );
  516. return;
  517. }
  518. m_pRocketEmitter->SetSortOrigin( GetAbsOrigin() );
  519. m_pRocketEmitter->SetNearClip( 64.0f, 128.0f );
  520. m_MaterialHandle[0] = g_Mat_DustPuff[0];
  521. m_MaterialHandle[1] = g_Mat_DustPuff[1];
  522. m_ParticleSpawn.Init( m_SpawnRate );
  523. m_vecLastPosition = GetAbsOrigin();
  524. }
  525. //-----------------------------------------------------------------------------
  526. // Purpose:
  527. // Input : fTimeDelta -
  528. //-----------------------------------------------------------------------------
  529. void C_RocketTrail::Update( float fTimeDelta )
  530. {
  531. if ( !m_pRocketEmitter )
  532. return;
  533. if ( gpGlobals->frametime == 0.0f )
  534. return;
  535. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
  536. pSimple->SetSortOrigin( GetAbsOrigin() );
  537. SimpleParticle *pParticle;
  538. Vector forward, offset;
  539. AngleVectors( GetAbsAngles(), &forward );
  540. forward.Negate();
  541. float flScale = random->RandomFloat( m_flFlareScale-0.5f, m_flFlareScale+0.5f );
  542. //
  543. // Flash
  544. //
  545. int i;
  546. for ( i = 1; i < 9; i++ )
  547. {
  548. offset = GetAbsOrigin() + (forward * (i*2.0f*m_flFlareScale));
  549. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
  550. if ( pParticle == NULL )
  551. return;
  552. pParticle->m_flLifetime = 0.0f;
  553. pParticle->m_flDieTime = 0.01f;
  554. pParticle->m_vecVelocity.Init();
  555. pParticle->m_uchColor[0] = 255;
  556. pParticle->m_uchColor[1] = 255;
  557. pParticle->m_uchColor[2] = 255;
  558. pParticle->m_uchStartAlpha = 255;
  559. pParticle->m_uchEndAlpha = 128;
  560. pParticle->m_uchStartSize = (random->RandomFloat( 5.0f, 6.0f ) * (12-(i))/9) * flScale;
  561. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  562. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  563. pParticle->m_flRollDelta = 0.0f;
  564. }
  565. // Add new particles (undamaged version)
  566. if ( m_bEmit )
  567. {
  568. Vector moveDiff = GetAbsOrigin() - m_vecLastPosition;
  569. float moveLength = VectorNormalize( moveDiff );
  570. int numPuffs = moveLength / ( m_StartSize / 2.0f );
  571. //debugoverlay->AddLineOverlay( m_vecLastPosition, GetAbsOrigin(), 255, 0, 0, true, 2.0f );
  572. //FIXME: More rational cap here, perhaps
  573. if ( numPuffs > 50 )
  574. numPuffs = 50;
  575. Vector offsetColor;
  576. float step = moveLength / numPuffs;
  577. //Fill in the gaps
  578. for ( i = 1; i < numPuffs+1; i++ )
  579. {
  580. offset = m_vecLastPosition + ( moveDiff * step * i );
  581. //debugoverlay->AddBoxOverlay( offset, -Vector(2,2,2), Vector(2,2,2), vec3_angle, i*4, i*4, i*4, true, 4.0f );
  582. pParticle = (SimpleParticle *) m_pRocketEmitter->AddParticle( sizeof( SimpleParticle ), m_MaterialHandle[random->RandomInt(0,1)], offset );
  583. if ( pParticle != NULL )
  584. {
  585. pParticle->m_flLifetime = 0.0f;
  586. pParticle->m_flDieTime = m_ParticleLifetime + random->RandomFloat(m_ParticleLifetime*0.9f,m_ParticleLifetime*1.1f);
  587. pParticle->m_vecVelocity.Random( -1.0f, 1.0f );
  588. pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed );
  589. offsetColor = m_StartColor * random->RandomFloat( 0.75f, 1.25f );
  590. offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f );
  591. offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f );
  592. offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f );
  593. pParticle->m_uchColor[0] = offsetColor[0]*255.0f;
  594. pParticle->m_uchColor[1] = offsetColor[1]*255.0f;
  595. pParticle->m_uchColor[2] = offsetColor[2]*255.0f;
  596. pParticle->m_uchStartSize = m_StartSize * random->RandomFloat( 0.75f, 1.25f );
  597. pParticle->m_uchEndSize = m_EndSize * random->RandomFloat( 1.0f, 1.25f );
  598. float alpha = random->RandomFloat( m_Opacity*0.75f, m_Opacity*1.25f );
  599. if ( alpha > 1.0f )
  600. alpha = 1.0f;
  601. if ( alpha < 0.0f )
  602. alpha = 0.0f;
  603. pParticle->m_uchStartAlpha = alpha * 255;
  604. pParticle->m_uchEndAlpha = 0;
  605. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  606. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  607. }
  608. }
  609. }
  610. if ( m_bDamaged )
  611. {
  612. Vector offsetColor;
  613. CSmartPtr<CEmberEffect> pEmitter = CEmberEffect::Create("C_RocketTrail::damaged");
  614. pEmitter->SetSortOrigin( GetAbsOrigin() );
  615. PMaterialHandle flameMaterial = m_pRocketEmitter->GetPMaterial( VarArgs( "sprites/flamelet%d", random->RandomInt( 1, 4 ) ) );
  616. // Flames from the rocket
  617. for ( i = 0; i < 8; i++ )
  618. {
  619. offset = RandomVector( -8, 8 ) + GetAbsOrigin();
  620. pParticle = (SimpleParticle *) pEmitter->AddParticle( sizeof( SimpleParticle ), flameMaterial, offset );
  621. if ( pParticle != NULL )
  622. {
  623. pParticle->m_flLifetime = 0.0f;
  624. pParticle->m_flDieTime = 0.25f;
  625. pParticle->m_vecVelocity.Random( -1.0f, 1.0f );
  626. pParticle->m_vecVelocity *= random->RandomFloat( 32, 128 );
  627. offsetColor = m_StartColor * random->RandomFloat( 0.75f, 1.25f );
  628. offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f );
  629. offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f );
  630. offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f );
  631. pParticle->m_uchColor[0] = offsetColor[0]*255.0f;
  632. pParticle->m_uchColor[1] = offsetColor[1]*255.0f;
  633. pParticle->m_uchColor[2] = offsetColor[2]*255.0f;
  634. pParticle->m_uchStartSize = 8.0f;
  635. pParticle->m_uchEndSize = 32.0f;
  636. pParticle->m_uchStartAlpha = 255;
  637. pParticle->m_uchEndAlpha = 0;
  638. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  639. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  640. }
  641. }
  642. }
  643. m_vecLastPosition = GetAbsOrigin();
  644. }
  645. void C_RocketTrail::RenderParticles( CParticleRenderIterator *pIterator )
  646. {
  647. }
  648. void C_RocketTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
  649. {
  650. }
  651. SporeEffect::SporeEffect( const char *pDebugName ) : CSimpleEmitter( pDebugName )
  652. {
  653. }
  654. SporeEffect* SporeEffect::Create( const char *pDebugName )
  655. {
  656. return new SporeEffect( pDebugName );
  657. }
  658. //-----------------------------------------------------------------------------
  659. // Purpose:
  660. // Input : fTimeDelta -
  661. // Output : Vector
  662. //-----------------------------------------------------------------------------
  663. void SporeEffect::UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
  664. {
  665. float speed = VectorNormalize( pParticle->m_vecVelocity );
  666. Vector offset;
  667. speed -= ( 64.0f * timeDelta );
  668. offset.Random( -0.5f, 0.5f );
  669. pParticle->m_vecVelocity += offset;
  670. VectorNormalize( pParticle->m_vecVelocity );
  671. pParticle->m_vecVelocity *= speed;
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Purpose:
  675. // Input : *pParticle -
  676. // timeDelta -
  677. //-----------------------------------------------------------------------------
  678. Vector SporeEffect::UpdateColor( const SimpleParticle *pParticle )
  679. {
  680. Vector color;
  681. float ramp = ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) );//1.0f - ( pParticle->m_flLifetime / pParticle->m_flDieTime );
  682. color[0] = ( (float) pParticle->m_uchColor[0] * ramp ) / 255.0f;
  683. color[1] = ( (float) pParticle->m_uchColor[1] * ramp ) / 255.0f;
  684. color[2] = ( (float) pParticle->m_uchColor[2] * ramp ) / 255.0f;
  685. return color;
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose:
  689. // Input : *pParticle -
  690. // timeDelta -
  691. // Output : float
  692. //-----------------------------------------------------------------------------
  693. float SporeEffect::UpdateAlpha( const SimpleParticle *pParticle )
  694. {
  695. return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
  696. }
  697. //==================================================
  698. // C_SporeExplosion
  699. //==================================================
  700. EXPOSE_PROTOTYPE_EFFECT( SporeExplosion, C_SporeExplosion );
  701. IMPLEMENT_CLIENTCLASS_DT( C_SporeExplosion, DT_SporeExplosion, SporeExplosion )
  702. RecvPropFloat(RECVINFO(m_flSpawnRate)),
  703. RecvPropFloat(RECVINFO(m_flParticleLifetime)),
  704. RecvPropFloat(RECVINFO(m_flStartSize)),
  705. RecvPropFloat(RECVINFO(m_flEndSize)),
  706. RecvPropFloat(RECVINFO(m_flSpawnRadius)),
  707. RecvPropBool(RECVINFO(m_bEmit)),
  708. RecvPropBool(RECVINFO(m_bDontRemove)),
  709. END_RECV_TABLE()
  710. C_SporeExplosion::C_SporeExplosion( void )
  711. {
  712. m_pParticleMgr = NULL;
  713. m_flSpawnRate = 32;
  714. m_flParticleLifetime = 5;
  715. m_flStartSize = 32;
  716. m_flEndSize = 64;
  717. m_flSpawnRadius = 32;
  718. m_pSporeEffect = NULL;
  719. m_teParticleSpawn.Init( 32 );
  720. m_bEmit = true;
  721. m_bDontRemove = false;
  722. }
  723. C_SporeExplosion::~C_SporeExplosion()
  724. {
  725. if ( m_pParticleMgr != NULL )
  726. {
  727. m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
  728. }
  729. }
  730. //-----------------------------------------------------------------------------
  731. // Purpose:
  732. // Input : bnewentity -
  733. //-----------------------------------------------------------------------------
  734. void C_SporeExplosion::OnDataChanged( DataUpdateType_t updateType )
  735. {
  736. C_BaseEntity::OnDataChanged( updateType );
  737. if ( updateType == DATA_UPDATE_CREATED )
  738. {
  739. m_flPreviousSpawnRate = m_flSpawnRate;
  740. m_teParticleSpawn.Init( m_flSpawnRate );
  741. Start( ParticleMgr(), NULL );
  742. }
  743. else if( m_bEmit )
  744. {
  745. // Just been turned on by the server.
  746. m_flPreviousSpawnRate = m_flSpawnRate;
  747. m_teParticleSpawn.Init( m_flSpawnRate );
  748. }
  749. m_pSporeEffect->SetDontRemove( m_bDontRemove );
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Purpose:
  753. // Input : *pParticleMgr -
  754. // *pArgs -
  755. //-----------------------------------------------------------------------------
  756. void C_SporeExplosion::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  757. {
  758. //Add us into the effect manager
  759. if( pParticleMgr->AddEffect( &m_ParticleEffect, this ) == false )
  760. return;
  761. //Create our main effect
  762. m_pSporeEffect = SporeEffect::Create( "C_SporeExplosion" );
  763. if ( m_pSporeEffect == NULL )
  764. return;
  765. m_hMaterial = m_pSporeEffect->GetPMaterial( "particle/fire" );
  766. m_pSporeEffect->SetSortOrigin( GetAbsOrigin() );
  767. m_pSporeEffect->SetNearClip( 64, 128 );
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Purpose:
  771. //-----------------------------------------------------------------------------
  772. void C_SporeExplosion::AddParticles( void )
  773. {
  774. //Spores
  775. Vector offset;
  776. Vector dir;
  777. //Get our direction
  778. AngleVectors( GetAbsAngles(), &dir );
  779. SimpleParticle *sParticle;
  780. for ( int i = 0; i < 4; i++ )
  781. {
  782. //Add small particle to the effect's origin
  783. offset.Random( -m_flSpawnRadius, m_flSpawnRadius );
  784. sParticle = (SimpleParticle *) m_pSporeEffect->AddParticle( sizeof(SimpleParticle), m_hMaterial, GetAbsOrigin()+offset );
  785. if ( sParticle == NULL )
  786. return;
  787. sParticle->m_flLifetime = 0.0f;
  788. sParticle->m_flDieTime = 2.0f;
  789. sParticle->m_flRoll = 0;
  790. sParticle->m_flRollDelta = 0;
  791. sParticle->m_uchColor[0] = 225;
  792. sParticle->m_uchColor[1] = 140;
  793. sParticle->m_uchColor[2] = 64;
  794. sParticle->m_uchStartAlpha = Helper_RandomInt( 128, 255 );
  795. sParticle->m_uchEndAlpha = 0;
  796. sParticle->m_uchStartSize = Helper_RandomInt( 1, 2 );
  797. sParticle->m_uchEndSize = 1;
  798. sParticle->m_vecVelocity = dir * Helper_RandomFloat( 128.0f, 256.0f );
  799. }
  800. //Add smokey bits
  801. offset.Random( -(m_flSpawnRadius * 0.5), (m_flSpawnRadius * 0.5) );
  802. sParticle = (SimpleParticle *) m_pSporeEffect->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[1], GetAbsOrigin()+offset );
  803. if ( sParticle == NULL )
  804. return;
  805. sParticle->m_flLifetime = 0.0f;
  806. sParticle->m_flDieTime = 1.0f;
  807. sParticle->m_flRoll = Helper_RandomFloat( 0, 360 );
  808. sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
  809. sParticle->m_uchColor[0] = 225;
  810. sParticle->m_uchColor[1] = 140;
  811. sParticle->m_uchColor[2] = 64;
  812. sParticle->m_uchStartAlpha = Helper_RandomInt( 32, 64 );
  813. sParticle->m_uchEndAlpha = 0;
  814. sParticle->m_uchStartSize = m_flStartSize;
  815. sParticle->m_uchEndSize = m_flEndSize;
  816. sParticle->m_vecVelocity = dir * Helper_RandomFloat( 64.0f, 128.0f );
  817. }
  818. ConVar cl_sporeclipdistance( "cl_sporeclipdistance", "512", FCVAR_CHEAT | FCVAR_CLIENTDLL );
  819. //-----------------------------------------------------------------------------
  820. // Purpose:
  821. // Input : fTimeDelta -
  822. //-----------------------------------------------------------------------------
  823. void C_SporeExplosion::Update( float fTimeDelta )
  824. {
  825. if( m_bEmit )
  826. {
  827. float tempDelta = fTimeDelta;
  828. float flDist = (MainViewOrigin() - GetAbsOrigin()).Length();
  829. //Lower the spawnrate by half if we're far away from it.
  830. if ( cl_sporeclipdistance.GetFloat() <= flDist )
  831. {
  832. if ( m_flSpawnRate == m_flPreviousSpawnRate )
  833. {
  834. m_flPreviousSpawnRate = m_flSpawnRate * 0.5f;
  835. m_teParticleSpawn.ResetRate( m_flPreviousSpawnRate );
  836. }
  837. }
  838. else
  839. {
  840. if ( m_flSpawnRate != m_flPreviousSpawnRate )
  841. {
  842. m_flPreviousSpawnRate = m_flSpawnRate;
  843. m_teParticleSpawn.ResetRate( m_flPreviousSpawnRate );
  844. }
  845. }
  846. while ( m_teParticleSpawn.NextEvent( tempDelta ) )
  847. {
  848. AddParticles();
  849. }
  850. }
  851. }
  852. void C_SporeExplosion::SimulateParticles( CParticleSimulateIterator *pIterator )
  853. {
  854. StandardParticle_t *pParticle = (StandardParticle_t*)pIterator->GetFirst();
  855. while ( pParticle )
  856. {
  857. pParticle->m_Lifetime += pIterator->GetTimeDelta();
  858. if( pParticle->m_Lifetime > m_flParticleLifetime )
  859. {
  860. pIterator->RemoveParticle( pParticle );
  861. }
  862. pParticle = (StandardParticle_t*)pIterator->GetNext();
  863. }
  864. }
  865. void C_SporeExplosion::RenderParticles( CParticleRenderIterator *pIterator )
  866. {
  867. }
  868. //-----------------------------------------------------------------------------
  869. // Purpose:
  870. //-----------------------------------------------------------------------------
  871. void RPGShotDownCallback( const CEffectData &data )
  872. {
  873. CLocalPlayerFilter filter;
  874. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Missile.ShotDown", &data.m_vOrigin );
  875. if ( CExplosionOverlay *pOverlay = new CExplosionOverlay )
  876. {
  877. pOverlay->m_flLifetime = 0;
  878. pOverlay->m_vPos = data.m_vOrigin;
  879. pOverlay->m_nSprites = 1;
  880. pOverlay->m_vBaseColors[0].Init( 1.0f, 0.9f, 0.7f );
  881. pOverlay->m_Sprites[0].m_flHorzSize = 0.01f;
  882. pOverlay->m_Sprites[0].m_flVertSize = pOverlay->m_Sprites[0].m_flHorzSize*0.5f;
  883. pOverlay->Activate();
  884. }
  885. }
  886. DECLARE_CLIENT_EFFECT( "RPGShotDown", RPGShotDownCallback );
  887. //==================================================
  888. // C_SporeTrail
  889. //==================================================
  890. class C_SporeTrail : public C_BaseParticleEntity
  891. {
  892. public:
  893. DECLARE_CLASS( C_SporeTrail, C_BaseParticleEntity );
  894. DECLARE_CLIENTCLASS();
  895. C_SporeTrail( void );
  896. virtual ~C_SporeTrail( void );
  897. public:
  898. void SetEmit( bool bEmit );
  899. // C_BaseEntity
  900. public:
  901. virtual void OnDataChanged( DataUpdateType_t updateType );
  902. virtual void GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles );
  903. // IPrototypeAppEffect
  904. public:
  905. virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs );
  906. // IParticleEffect
  907. public:
  908. virtual void Update( float fTimeDelta );
  909. virtual void RenderParticles( CParticleRenderIterator *pIterator );
  910. virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
  911. virtual void StartRender( VMatrix &effectMatrix );
  912. public:
  913. Vector m_vecEndColor;
  914. float m_flSpawnRate;
  915. float m_flParticleLifetime;
  916. float m_flStartSize;
  917. float m_flEndSize;
  918. float m_flSpawnRadius;
  919. Vector m_vecVelocityOffset;
  920. bool m_bEmit;
  921. private:
  922. C_SporeTrail( const C_SporeTrail & );
  923. void AddParticles( void );
  924. PMaterialHandle m_hMaterial;
  925. TimedEvent m_teParticleSpawn;
  926. //CSmartPtr<SporeSmokeEffect> m_pSmokeEffect;
  927. Vector m_vecPos;
  928. Vector m_vecLastPos; // This is stored so we can spawn particles in between the previous and new position
  929. // to eliminate holes in the trail.
  930. VMatrix m_mAttachmentMatrix;
  931. CParticleMgr *m_pParticleMgr;
  932. };
  933. //==================================================
  934. // C_SporeTrail
  935. //==================================================
  936. IMPLEMENT_CLIENTCLASS_DT( C_SporeTrail, DT_SporeTrail, SporeTrail )
  937. RecvPropFloat(RECVINFO(m_flSpawnRate)),
  938. RecvPropVector(RECVINFO(m_vecEndColor)),
  939. RecvPropFloat(RECVINFO(m_flParticleLifetime)),
  940. RecvPropFloat(RECVINFO(m_flStartSize)),
  941. RecvPropFloat(RECVINFO(m_flEndSize)),
  942. RecvPropFloat(RECVINFO(m_flSpawnRadius)),
  943. RecvPropInt(RECVINFO(m_bEmit)),
  944. END_RECV_TABLE()
  945. C_SporeTrail::C_SporeTrail( void )
  946. {
  947. m_pParticleMgr = NULL;
  948. //m_pSmokeEffect = SporeSmokeEffect::Create( "C_SporeTrail" );
  949. m_flSpawnRate = 10;
  950. m_flParticleLifetime = 5;
  951. m_flStartSize = 35;
  952. m_flEndSize = 55;
  953. m_flSpawnRadius = 2;
  954. m_teParticleSpawn.Init( 5 );
  955. m_vecEndColor.Init();
  956. m_vecPos.Init();
  957. m_vecLastPos.Init();
  958. m_vecVelocityOffset.Init();
  959. m_bEmit = true;
  960. }
  961. C_SporeTrail::~C_SporeTrail()
  962. {
  963. if( m_pParticleMgr )
  964. {
  965. m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
  966. }
  967. }
  968. //-----------------------------------------------------------------------------
  969. // Purpose:
  970. // Input : bEmit -
  971. //-----------------------------------------------------------------------------
  972. void C_SporeTrail::SetEmit( bool bEmit )
  973. {
  974. m_bEmit = bEmit;
  975. }
  976. //-----------------------------------------------------------------------------
  977. // Purpose:
  978. // Input : bnewentity -
  979. //-----------------------------------------------------------------------------
  980. void C_SporeTrail::OnDataChanged( DataUpdateType_t updateType )
  981. {
  982. C_BaseEntity::OnDataChanged( updateType );
  983. if ( updateType == DATA_UPDATE_CREATED )
  984. {
  985. Start( ParticleMgr(), NULL );
  986. }
  987. }
  988. //-----------------------------------------------------------------------------
  989. // Purpose:
  990. // Input : *pParticleMgr -
  991. // *pArgs -
  992. //-----------------------------------------------------------------------------
  993. void C_SporeTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  994. {
  995. if( pParticleMgr->AddEffect( &m_ParticleEffect, this ) == false )
  996. return;
  997. m_hMaterial = g_Mat_DustPuff[1];
  998. m_pParticleMgr = pParticleMgr;
  999. m_teParticleSpawn.Init( 64 );
  1000. }
  1001. //-----------------------------------------------------------------------------
  1002. // Purpose:
  1003. //-----------------------------------------------------------------------------
  1004. void C_SporeTrail::AddParticles( void )
  1005. {
  1006. Vector offset = RandomVector( -4.0f, 4.0f );
  1007. //Make a new particle
  1008. SimpleParticle *sParticle = (SimpleParticle *) m_ParticleEffect.AddParticle( sizeof(SimpleParticle), m_hMaterial );//m_pSmokeEffect->AddParticle( sizeof(SimpleParticle), m_hMaterial, GetAbsOrigin()+offset );
  1009. if ( sParticle == NULL )
  1010. return;
  1011. sParticle->m_Pos = offset;
  1012. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  1013. sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
  1014. sParticle->m_flLifetime = 0.0f;
  1015. sParticle->m_flDieTime = 0.5f;
  1016. sParticle->m_uchColor[0] = 225;
  1017. sParticle->m_uchColor[1] = 140;
  1018. sParticle->m_uchColor[2] = 64;
  1019. sParticle->m_uchStartAlpha = Helper_RandomInt( 64, 128 );
  1020. sParticle->m_uchEndAlpha = 0;
  1021. sParticle->m_uchStartSize = 1.0f;
  1022. sParticle->m_uchEndSize = 1.0f;
  1023. sParticle->m_vecVelocity = RandomVector( -8.0f, 8.0f );
  1024. }
  1025. //-----------------------------------------------------------------------------
  1026. // Purpose:
  1027. // Input : fTimeDelta -
  1028. //-----------------------------------------------------------------------------
  1029. void C_SporeTrail::Update( float fTimeDelta )
  1030. {
  1031. if ( m_pParticleMgr == NULL )
  1032. return;
  1033. //Add new particles
  1034. if ( m_bEmit )
  1035. {
  1036. float tempDelta = fTimeDelta;
  1037. while ( m_teParticleSpawn.NextEvent( tempDelta ) )
  1038. {
  1039. AddParticles();
  1040. }
  1041. }
  1042. }
  1043. //-----------------------------------------------------------------------------
  1044. // Purpose:
  1045. // Input : &effectMatrix -
  1046. //-----------------------------------------------------------------------------
  1047. void C_SporeTrail::StartRender( VMatrix &effectMatrix )
  1048. {
  1049. effectMatrix = effectMatrix * m_mAttachmentMatrix;
  1050. }
  1051. void C_SporeTrail::RenderParticles( CParticleRenderIterator *pIterator )
  1052. {
  1053. if ( m_bEmit == false )
  1054. return;
  1055. const SimpleParticle *pParticle = (const SimpleParticle*)pIterator->GetFirst();
  1056. while ( pParticle )
  1057. {
  1058. //Render
  1059. Vector tPos;
  1060. TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
  1061. float sortKey = tPos.z;
  1062. Vector color = Vector( 1.0f, 1.0f, 1.0f );
  1063. //Render it
  1064. RenderParticle_ColorSize(
  1065. pIterator->GetParticleDraw(),
  1066. tPos,
  1067. color,
  1068. 1.0f,
  1069. 4 );
  1070. pParticle = (const SimpleParticle*)pIterator->GetNext( sortKey );
  1071. }
  1072. }
  1073. void C_SporeTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
  1074. {
  1075. if ( m_bEmit == false )
  1076. return;
  1077. SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst();
  1078. while ( pParticle )
  1079. {
  1080. //UpdateVelocity( pParticle, timeDelta );
  1081. pParticle->m_Pos += pParticle->m_vecVelocity * pIterator->GetTimeDelta();
  1082. //Should this particle die?
  1083. pParticle->m_flLifetime += pIterator->GetTimeDelta();
  1084. if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
  1085. {
  1086. pIterator->RemoveParticle( pParticle );
  1087. }
  1088. pParticle = (SimpleParticle*)pIterator->GetNext();
  1089. }
  1090. }
  1091. //-----------------------------------------------------------------------------
  1092. // Purpose:
  1093. //-----------------------------------------------------------------------------
  1094. void C_SporeTrail::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles )
  1095. {
  1096. C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity();
  1097. pEnt->GetAttachment( 1, *pAbsOrigin, *pAbsAngles );
  1098. matrix3x4_t matrix;
  1099. AngleMatrix( *pAbsAngles, *pAbsOrigin, matrix );
  1100. m_mAttachmentMatrix = matrix;
  1101. }
  1102. //==================================================
  1103. // FireTrailhou
  1104. //==================================================
  1105. // Datatable.. this can have all the smoketrail parameters when we need it to.
  1106. IMPLEMENT_CLIENTCLASS_DT(C_FireTrail, DT_FireTrail, CFireTrail)
  1107. RecvPropInt(RECVINFO(m_nAttachment)),
  1108. RecvPropFloat(RECVINFO(m_flLifetime)),
  1109. END_RECV_TABLE()
  1110. // ------------------------------------------------------------------------- //
  1111. // ParticleMovieExplosion
  1112. // ------------------------------------------------------------------------- //
  1113. C_FireTrail::C_FireTrail()
  1114. {
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Purpose:
  1118. //-----------------------------------------------------------------------------
  1119. C_FireTrail::~C_FireTrail( void )
  1120. {
  1121. }
  1122. //-----------------------------------------------------------------------------
  1123. // Purpose:
  1124. // Input : *pParticleMgr -
  1125. // *pArgs -
  1126. //-----------------------------------------------------------------------------
  1127. void C_FireTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  1128. {
  1129. BaseClass::Start( pParticleMgr, pArgs );
  1130. m_pTrailEmitter = CSimpleEmitter::Create( "FireTrail" );
  1131. if ( !m_pTrailEmitter )
  1132. {
  1133. Assert( false );
  1134. return;
  1135. }
  1136. m_pTrailEmitter->SetSortOrigin( GetAbsOrigin() );
  1137. // Setup our materials
  1138. m_hMaterial[FTRAIL_SMOKE1] = g_Mat_DustPuff[0];
  1139. m_hMaterial[FTRAIL_SMOKE2] = g_Mat_DustPuff[1];
  1140. m_hMaterial[FTRAIL_FLAME1] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet1" );
  1141. m_hMaterial[FTRAIL_FLAME2] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet2" );
  1142. m_hMaterial[FTRAIL_FLAME3] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet3" );
  1143. m_hMaterial[FTRAIL_FLAME4] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet4" );
  1144. m_hMaterial[FTRAIL_FLAME5] = m_pTrailEmitter->GetPMaterial( "sprites/flamelet5" );
  1145. // Setup our smoke emitter
  1146. m_pSmokeEmitter = CSmokeParticle::Create( "FireTrail_Smoke" );
  1147. m_pSmokeEmitter->SetSortOrigin( GetAbsOrigin() );
  1148. m_pSmokeEmitter->SetNearClip( 64.0f, 128.0f );
  1149. if ( !m_pSmokeEmitter )
  1150. {
  1151. Assert( false );
  1152. return;
  1153. }
  1154. // Seed our first position as the last known one
  1155. m_vecLastPosition = GetAbsOrigin();
  1156. }
  1157. //-----------------------------------------------------------------------------
  1158. // Purpose:
  1159. // Input : fTimeDelta -
  1160. //-----------------------------------------------------------------------------
  1161. void C_FireTrail::Update( float fTimeDelta )
  1162. {
  1163. if ( !m_pTrailEmitter )
  1164. return;
  1165. if ( ( m_flLifetime != 0 ) && ( m_flLifetime <= gpGlobals->curtime ) )
  1166. return;
  1167. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FireTrail" );
  1168. pSimple->SetSortOrigin( GetAbsOrigin() );
  1169. Vector offset;
  1170. #define STARTSIZE 8
  1171. #define ENDSIZE 16
  1172. #define PARTICLE_LIFETIME 0.075f
  1173. #define MIN_SPEED 32
  1174. #define MAX_SPEED 64
  1175. // Add new particles
  1176. //if ( ShouldEmit() )
  1177. {
  1178. Vector moveDiff = GetAbsOrigin() - m_vecLastPosition;
  1179. float moveLength = VectorNormalize( moveDiff );
  1180. int numPuffs = moveLength / ( STARTSIZE / 2.0f );
  1181. //FIXME: More rational cap here, perhaps
  1182. numPuffs = clamp( numPuffs, 1, 32 );
  1183. SimpleParticle *pParticle;
  1184. Vector offsetColor;
  1185. float step = moveLength / numPuffs;
  1186. //Fill in the gaps
  1187. for ( int i = 1; i < numPuffs+1; i++ )
  1188. {
  1189. offset = m_vecLastPosition + ( moveDiff * step * i ) + RandomVector( -4.0f, 4.0f );
  1190. //debugoverlay->AddBoxOverlay( offset, -Vector(2,2,2), Vector(2,2,2), vec3_angle, i*4, i*4, i*4, true, 1.0f );
  1191. pParticle = (SimpleParticle *) m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), m_hMaterial[random->RandomInt( FTRAIL_FLAME1,FTRAIL_FLAME5 )], offset );
  1192. if ( pParticle != NULL )
  1193. {
  1194. pParticle->m_flLifetime = 0.0f;
  1195. pParticle->m_flDieTime = /*PARTICLE_LIFETIME*/ 0.5f;// + random->RandomFloat(PARTICLE_LIFETIME*0.75f, PARTICLE_LIFETIME*1.25f);
  1196. pParticle->m_vecVelocity.Random( 0.0f, 1.0f );
  1197. pParticle->m_vecVelocity *= random->RandomFloat( MIN_SPEED, MAX_SPEED );
  1198. pParticle->m_vecVelocity[2] += 50;//random->RandomFloat( 32, 64 );
  1199. pParticle->m_uchColor[0] = 255.0f;
  1200. pParticle->m_uchColor[1] = 255.0f;
  1201. pParticle->m_uchColor[2] = 255.0f;
  1202. pParticle->m_uchStartSize = STARTSIZE * 2.0f;
  1203. pParticle->m_uchEndSize = STARTSIZE * 0.5f;
  1204. pParticle->m_uchStartAlpha = 255;
  1205. pParticle->m_uchEndAlpha = 0;
  1206. pParticle->m_flRoll = 0.0f;//random->RandomInt( 0, 360 );
  1207. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  1208. }
  1209. }
  1210. //
  1211. // Smoke
  1212. //
  1213. offset = RandomVector( -STARTSIZE*0.5f, STARTSIZE*0.5f ) + GetAbsOrigin();
  1214. pParticle = (SimpleParticle *) m_pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), m_hMaterial[random->RandomInt( FTRAIL_SMOKE1, FTRAIL_SMOKE2 )], offset );
  1215. if ( pParticle != NULL )
  1216. {
  1217. pParticle->m_flLifetime = 0.0f;
  1218. pParticle->m_flDieTime = ( PARTICLE_LIFETIME * 10.0f ) + random->RandomFloat(PARTICLE_LIFETIME*0.75f, PARTICLE_LIFETIME*1.25f);
  1219. pParticle->m_vecVelocity.Random( 0.0f, 1.0f );
  1220. pParticle->m_vecVelocity *= random->RandomFloat( MIN_SPEED, MAX_SPEED );
  1221. pParticle->m_vecVelocity[2] += random->RandomFloat( 50, 100 );
  1222. pParticle->m_uchColor[0] = 255.0f * 0.5f;
  1223. pParticle->m_uchColor[1] = 245.0f * 0.5f;
  1224. pParticle->m_uchColor[2] = 205.0f * 0.5f;
  1225. pParticle->m_uchStartSize = 16 * random->RandomFloat( 0.75f, 1.25f );
  1226. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2.5f;
  1227. pParticle->m_uchStartAlpha = 64;
  1228. pParticle->m_uchEndAlpha = 0;
  1229. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  1230. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  1231. }
  1232. }
  1233. // Save off this position
  1234. m_vecLastPosition = GetAbsOrigin();
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. // Purpose: High drag, non color changing particle
  1238. //-----------------------------------------------------------------------------
  1239. class CDustFollower : public CSimpleEmitter
  1240. {
  1241. public:
  1242. CDustFollower( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  1243. //Create
  1244. static CDustFollower *Create( const char *pDebugName )
  1245. {
  1246. return new CDustFollower( pDebugName );
  1247. }
  1248. //Alpha
  1249. virtual float UpdateAlpha( const SimpleParticle *pParticle )
  1250. {
  1251. return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
  1252. }
  1253. virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
  1254. {
  1255. pParticle->m_vecVelocity = pParticle->m_vecVelocity * ExponentialDecay( 0.3, timeDelta );
  1256. }
  1257. //Roll
  1258. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  1259. {
  1260. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  1261. pParticle->m_flRollDelta *= ExponentialDecay( 0.5, timeDelta );
  1262. return pParticle->m_flRoll;
  1263. }
  1264. private:
  1265. CDustFollower( const CDustFollower & );
  1266. };
  1267. // Datatable.. this can have all the smoketrail parameters when we need it to.
  1268. IMPLEMENT_CLIENTCLASS_DT(C_DustTrail, DT_DustTrail, DustTrail)
  1269. RecvPropFloat(RECVINFO(m_SpawnRate)),
  1270. RecvPropVector(RECVINFO(m_Color)),
  1271. RecvPropFloat(RECVINFO(m_ParticleLifetime)),
  1272. RecvPropFloat(RECVINFO(m_StopEmitTime)),
  1273. RecvPropFloat(RECVINFO(m_MinSpeed)),
  1274. RecvPropFloat(RECVINFO(m_MaxSpeed)),
  1275. RecvPropFloat(RECVINFO(m_MinDirectedSpeed)),
  1276. RecvPropFloat(RECVINFO(m_MaxDirectedSpeed)),
  1277. RecvPropFloat(RECVINFO(m_StartSize)),
  1278. RecvPropFloat(RECVINFO(m_EndSize)),
  1279. RecvPropFloat(RECVINFO(m_SpawnRadius)),
  1280. RecvPropInt(RECVINFO(m_bEmit)),
  1281. RecvPropFloat(RECVINFO(m_Opacity)),
  1282. END_RECV_TABLE()
  1283. // ------------------------------------------------------------------------- //
  1284. // ParticleMovieExplosion
  1285. // ------------------------------------------------------------------------- //
  1286. C_DustTrail::C_DustTrail()
  1287. {
  1288. for (int i = 0; i < DUSTTRAIL_MATERIALS; i++)
  1289. {
  1290. m_MaterialHandle[i] = NULL;
  1291. }
  1292. m_SpawnRate = 10;
  1293. m_ParticleSpawn.Init(10);
  1294. m_Color.Init(0.5, 0.5, 0.5);
  1295. m_ParticleLifetime = 5;
  1296. m_StartEmitTime = gpGlobals->curtime;
  1297. m_StopEmitTime = 0; // No end time
  1298. m_MinSpeed = 2;
  1299. m_MaxSpeed = 4;
  1300. m_MinDirectedSpeed = m_MaxDirectedSpeed = 0;
  1301. m_StartSize = 35;
  1302. m_EndSize = 55;
  1303. m_SpawnRadius = 2;
  1304. m_VelocityOffset.Init();
  1305. m_Opacity = 0.5f;
  1306. m_bEmit = true;
  1307. m_pDustEmitter = NULL;
  1308. m_pParticleMgr = NULL;
  1309. }
  1310. C_DustTrail::~C_DustTrail()
  1311. {
  1312. if ( ToolsEnabled() && clienttools->IsInRecordingMode() && m_pDustEmitter.IsValid() && m_pDustEmitter->GetToolParticleEffectId() != TOOLPARTICLESYSTEMID_INVALID )
  1313. {
  1314. KeyValues *msg = new KeyValues( "OldParticleSystem_ActivateEmitter" );
  1315. msg->SetInt( "id", m_pDustEmitter->GetToolParticleEffectId() );
  1316. msg->SetInt( "emitter", 0 );
  1317. msg->SetInt( "active", false );
  1318. msg->SetFloat( "time", gpGlobals->curtime );
  1319. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  1320. msg->deleteThis();
  1321. }
  1322. if ( m_pParticleMgr )
  1323. {
  1324. m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
  1325. }
  1326. }
  1327. //-----------------------------------------------------------------------------
  1328. // Purpose:
  1329. // Input : bEmit -
  1330. //-----------------------------------------------------------------------------
  1331. void C_DustTrail::SetEmit(bool bEmit)
  1332. {
  1333. m_bEmit = bEmit;
  1334. }
  1335. //-----------------------------------------------------------------------------
  1336. // Purpose:
  1337. // Input : rate -
  1338. //-----------------------------------------------------------------------------
  1339. void C_DustTrail::SetSpawnRate(float rate)
  1340. {
  1341. m_SpawnRate = rate;
  1342. m_ParticleSpawn.Init(rate);
  1343. }
  1344. //-----------------------------------------------------------------------------
  1345. // Purpose:
  1346. // Input : bnewentity -
  1347. //-----------------------------------------------------------------------------
  1348. void C_DustTrail::OnDataChanged(DataUpdateType_t updateType)
  1349. {
  1350. C_BaseEntity::OnDataChanged(updateType);
  1351. if ( updateType == DATA_UPDATE_CREATED )
  1352. {
  1353. Start( ParticleMgr(), NULL );
  1354. }
  1355. }
  1356. // FIXME: These all have to be moved out of this old system and into the new to leverage art assets!
  1357. CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectDusttrail )
  1358. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0001" )
  1359. /*
  1360. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0002" )
  1361. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0003" )
  1362. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0004" )
  1363. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0005" )
  1364. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0006" )
  1365. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0007" )
  1366. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0008" )
  1367. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0009" )
  1368. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0010" )
  1369. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0011" )
  1370. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0012" )
  1371. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0013" )
  1372. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0014" )
  1373. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0015" )
  1374. CLIENTEFFECT_MATERIAL( "particle/smokesprites_0016" )
  1375. */
  1376. CLIENTEFFECT_REGISTER_END()
  1377. //-----------------------------------------------------------------------------
  1378. // Purpose:
  1379. // Input : *pParticleMgr -
  1380. // *pArgs -
  1381. //-----------------------------------------------------------------------------
  1382. void C_DustTrail::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
  1383. {
  1384. if(!pParticleMgr->AddEffect( &m_ParticleEffect, this ))
  1385. return;
  1386. m_pParticleMgr = pParticleMgr;
  1387. m_pDustEmitter = CDustFollower::Create("DustTrail");
  1388. if ( !m_pDustEmitter )
  1389. {
  1390. Assert( false );
  1391. return;
  1392. }
  1393. m_pDustEmitter->SetSortOrigin( GetAbsOrigin() );
  1394. m_pDustEmitter->SetNearClip( 64.0f, 128.0f );
  1395. for (int i = 0; i < DUSTTRAIL_MATERIALS; i++)
  1396. {
  1397. //char name[256];
  1398. //Q_snprintf( name, sizeof( name ), "particle/smokesprites_%04d", i + 1 );
  1399. m_MaterialHandle[i] = m_pDustEmitter->GetPMaterial( "particle/smokesprites_0001" );
  1400. }
  1401. m_ParticleSpawn.Init( m_SpawnRate );
  1402. }
  1403. //-----------------------------------------------------------------------------
  1404. // Purpose:
  1405. // Input : fTimeDelta -
  1406. //-----------------------------------------------------------------------------
  1407. void C_DustTrail::Update( float fTimeDelta )
  1408. {
  1409. if ( !m_pDustEmitter )
  1410. return;
  1411. Vector offsetColor;
  1412. // Add new particles
  1413. if ( !m_bEmit )
  1414. return;
  1415. if ( ( m_StopEmitTime != 0 ) && ( m_StopEmitTime <= gpGlobals->curtime ) )
  1416. return;
  1417. float tempDelta = fTimeDelta;
  1418. SimpleParticle *pParticle;
  1419. Vector offset;
  1420. Vector vecOrigin;
  1421. VectorMA( GetAbsOrigin(), -fTimeDelta, GetAbsVelocity(), vecOrigin );
  1422. Vector vecForward;
  1423. GetVectors( &vecForward, NULL, NULL );
  1424. while( m_ParticleSpawn.NextEvent( tempDelta ) )
  1425. {
  1426. float fldt = fTimeDelta - tempDelta;
  1427. offset.Random( -m_SpawnRadius, m_SpawnRadius );
  1428. offset += vecOrigin;
  1429. VectorMA( offset, fldt, GetAbsVelocity(), offset );
  1430. //if ( random->RandomFloat( 0.f, 5.0f ) > GetAbsVelocity().Length())
  1431. // continue;
  1432. pParticle = (SimpleParticle *) m_pDustEmitter->AddParticle( sizeof( SimpleParticle ), m_MaterialHandle[random->RandomInt(0,0)], offset ); // FIXME: the other sprites look bad
  1433. if ( pParticle == NULL )
  1434. continue;
  1435. pParticle->m_flLifetime = 0.0f;
  1436. pParticle->m_flDieTime = m_ParticleLifetime;
  1437. pParticle->m_vecVelocity.Random( -1.0f, 1.0f );
  1438. pParticle->m_vecVelocity *= random->RandomFloat( m_MinSpeed, m_MaxSpeed );
  1439. pParticle->m_vecVelocity = pParticle->m_vecVelocity + GetAbsVelocity();
  1440. float flDirectedVel = random->RandomFloat( m_MinDirectedSpeed, m_MaxDirectedSpeed );
  1441. VectorMA( pParticle->m_vecVelocity, flDirectedVel, vecForward, pParticle->m_vecVelocity );
  1442. offsetColor = m_Color;
  1443. float flMaxVal = MAX( m_Color[0], m_Color[1] );
  1444. if ( flMaxVal < m_Color[2] )
  1445. {
  1446. flMaxVal = m_Color[2];
  1447. }
  1448. offsetColor /= flMaxVal;
  1449. offsetColor *= random->RandomFloat( -0.2f, 0.2f );
  1450. offsetColor += m_Color;
  1451. offsetColor[0] = clamp( offsetColor[0], 0.0f, 1.0f );
  1452. offsetColor[1] = clamp( offsetColor[1], 0.0f, 1.0f );
  1453. offsetColor[2] = clamp( offsetColor[2], 0.0f, 1.0f );
  1454. pParticle->m_uchColor[0] = offsetColor[0]*255.0f;
  1455. pParticle->m_uchColor[1] = offsetColor[1]*255.0f;
  1456. pParticle->m_uchColor[2] = offsetColor[2]*255.0f;
  1457. pParticle->m_uchStartSize = m_StartSize;
  1458. pParticle->m_uchEndSize = m_EndSize;
  1459. float alpha = random->RandomFloat( m_Opacity*0.75f, m_Opacity*1.25f );
  1460. alpha = clamp( alpha, 0.0f, 1.0f );
  1461. if ( m_StopEmitTime != 0 && m_StopEmitTime > m_StartEmitTime )
  1462. {
  1463. alpha *= sqrt( (m_StopEmitTime - gpGlobals->curtime) /(m_StopEmitTime - m_StartEmitTime) );
  1464. }
  1465. pParticle->m_uchStartAlpha = alpha * 255;
  1466. pParticle->m_uchEndAlpha = 0;
  1467. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  1468. pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
  1469. }
  1470. }
  1471. void C_DustTrail::RenderParticles( CParticleRenderIterator *pIterator )
  1472. {
  1473. }
  1474. void C_DustTrail::SimulateParticles( CParticleSimulateIterator *pIterator )
  1475. {
  1476. }
  1477. //-----------------------------------------------------------------------------
  1478. // This is called after sending this entity's recording state
  1479. //-----------------------------------------------------------------------------
  1480. void C_DustTrail::CleanupToolRecordingState( KeyValues *msg )
  1481. {
  1482. if ( !ToolsEnabled() )
  1483. return;
  1484. BaseClass::CleanupToolRecordingState( msg );
  1485. // Generally, this is used to allow the entity to clean up
  1486. // allocated state it put into the message, but here we're going
  1487. // to use it to send particle system messages because we
  1488. // know the grenade has been recorded at this point
  1489. if ( !clienttools->IsInRecordingMode() || !m_pDustEmitter.IsValid() )
  1490. return;
  1491. // For now, we can't record Dusttrails that don't have a moveparent
  1492. C_BaseEntity *pEnt = GetMoveParent();
  1493. if ( !pEnt )
  1494. return;
  1495. bool bEmitterActive = m_bEmit && ( ( m_StopEmitTime == 0 ) || ( m_StopEmitTime > gpGlobals->curtime ) );
  1496. // NOTE: Particle system destruction message will be sent by the particle effect itself.
  1497. if ( m_pDustEmitter->GetToolParticleEffectId() == TOOLPARTICLESYSTEMID_INVALID )
  1498. {
  1499. int nId = m_pDustEmitter->AllocateToolParticleEffectId();
  1500. KeyValues *oldmsg = new KeyValues( "OldParticleSystem_Create" );
  1501. oldmsg->SetString( "name", "C_DustTrail" );
  1502. oldmsg->SetInt( "id", nId );
  1503. oldmsg->SetFloat( "time", gpGlobals->curtime );
  1504. KeyValues *pEmitter = oldmsg->FindKey( "DmeSpriteEmitter", true );
  1505. pEmitter->SetString( "material", "particle/smokesprites_0001" );
  1506. pEmitter->SetInt( "count", m_SpawnRate ); // particles per second, when duration is < 0
  1507. pEmitter->SetFloat( "duration", -1 ); // FIXME
  1508. pEmitter->SetInt( "active", bEmitterActive );
  1509. KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
  1510. // FIXME: Until we can interpolate ent logs during emission, this can't work
  1511. KeyValues *pPosition = pInitializers->FindKey( "DmePositionPointToEntityInitializer", true );
  1512. pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
  1513. pPosition->SetInt( "attachmentIndex", GetParentAttachment() );
  1514. pPosition->SetFloat( "randomDist", m_SpawnRadius );
  1515. pPosition->SetFloat( "startx", pEnt->GetAbsOrigin().x );
  1516. pPosition->SetFloat( "starty", pEnt->GetAbsOrigin().y );
  1517. pPosition->SetFloat( "startz", pEnt->GetAbsOrigin().z );
  1518. KeyValues *pVelocity = pInitializers->FindKey( "DmeDecayVelocityInitializer", true );
  1519. pVelocity->SetFloat( "velocityX", pEnt->GetAbsVelocity().x );
  1520. pVelocity->SetFloat( "velocityY", pEnt->GetAbsVelocity().y );
  1521. pVelocity->SetFloat( "velocityZ", pEnt->GetAbsVelocity().z );
  1522. pVelocity->SetFloat( "decayto", 0.5 );
  1523. pVelocity->SetFloat( "decaytime", 0.3 );
  1524. KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
  1525. pLifetime->SetFloat( "minLifetime", m_ParticleLifetime );
  1526. pLifetime->SetFloat( "maxLifetime", m_ParticleLifetime );
  1527. KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
  1528. pRoll->SetFloat( "minRoll", 0.0f );
  1529. pRoll->SetFloat( "maxRoll", 360.0f );
  1530. KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
  1531. pRollSpeed->SetFloat( "minRollSpeed", -1.0f );
  1532. pRollSpeed->SetFloat( "maxRollSpeed", 1.0f );
  1533. KeyValues *pColor = pInitializers->FindKey( "DmeRandomValueColorInitializer", true );
  1534. Color c(
  1535. FastFToC( clamp( m_Color.x, 0.f, 1.f ) ),
  1536. FastFToC( clamp( m_Color.y, 0.f, 1.f ) ),
  1537. FastFToC( clamp( m_Color.z, 0.f, 1.f ) ),
  1538. 255 );
  1539. pColor->SetColor( "startColor", c );
  1540. pColor->SetFloat( "minStartValueDelta", 0.0f );
  1541. pColor->SetFloat( "maxStartValueDelta", 0.0f );
  1542. pColor->SetColor( "endColor", c );
  1543. KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
  1544. int nMinAlpha = 255 * m_Opacity * 0.75f;
  1545. int nMaxAlpha = 255 * m_Opacity * 1.25f;
  1546. pAlpha->SetInt( "minStartAlpha", clamp( nMinAlpha, 0, 255 ) );
  1547. pAlpha->SetInt( "maxStartAlpha", clamp( nMaxAlpha, 0, 255 ) );
  1548. pAlpha->SetInt( "minEndAlpha", clamp( nMinAlpha, 0, 255 ) );
  1549. pAlpha->SetInt( "maxEndAlpha", clamp( nMaxAlpha, 0, 255 ) );
  1550. KeyValues *pSize = pInitializers->FindKey( "DmeRandomSizeInitializer", true );
  1551. pSize->SetFloat( "minStartSize", m_StartSize );
  1552. pSize->SetFloat( "maxStartSize", m_StartSize );
  1553. pSize->SetFloat( "minEndSize", m_EndSize );
  1554. pSize->SetFloat( "maxEndSize", m_EndSize );
  1555. KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
  1556. pUpdaters->FindKey( "DmePositionVelocityDecayUpdater", true );
  1557. pUpdaters->FindKey( "DmeRollUpdater", true );
  1558. KeyValues *pRollSpeedUpdater = pUpdaters->FindKey( "DmeRollSpeedAttenuateUpdater", true );
  1559. pRollSpeedUpdater->SetFloat( "attenuation", 1.0f - 8.0f / 30.0f );
  1560. pRollSpeedUpdater->SetFloat( "attenuationTme", 1.0f / 30.0f );
  1561. pRollSpeedUpdater->SetFloat( "minRollSpeed", 0.5f );
  1562. pUpdaters->FindKey( "DmeAlphaSineRampUpdater", true );
  1563. pUpdaters->FindKey( "DmeColorUpdater", true );
  1564. pUpdaters->FindKey( "DmeSizeUpdater", true );
  1565. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, oldmsg );
  1566. oldmsg->deleteThis();
  1567. }
  1568. else
  1569. {
  1570. KeyValues *oldmsg = new KeyValues( "OldParticleSystem_ActivateEmitter" );
  1571. oldmsg->SetInt( "id", m_pDustEmitter->GetToolParticleEffectId() );
  1572. oldmsg->SetInt( "emitter", 0 );
  1573. oldmsg->SetInt( "active", bEmitterActive );
  1574. oldmsg->SetFloat( "time", gpGlobals->curtime );
  1575. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, oldmsg );
  1576. oldmsg->deleteThis();
  1577. }
  1578. }