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.

306 lines
8.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "particlemgr.h"
  9. #include "particle_prototype.h"
  10. #include "particle_util.h"
  11. #include "c_te_particlesystem.h"
  12. #include "fx.h"
  13. #include "fx_quad.h"
  14. #include "clienteffectprecachesystem.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. // ==============================================
  18. // Rotorwash particle emitter
  19. // ==============================================
  20. #ifndef _XBOX
  21. class WashEmitter : public CSimpleEmitter
  22. {
  23. public:
  24. WashEmitter( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  25. static WashEmitter *Create( const char *pDebugName )
  26. {
  27. return new WashEmitter( pDebugName );
  28. }
  29. void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
  30. {
  31. // Float up when lifetime is half gone.
  32. pParticle->m_vecVelocity[ 2 ] += 64 * timeDelta;
  33. // FIXME: optimize this....
  34. pParticle->m_vecVelocity *= ExponentialDecay( 0.8, 0.05, timeDelta );
  35. }
  36. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  37. {
  38. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  39. pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -2.0f );
  40. //Cap the minimum roll
  41. if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
  42. {
  43. pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
  44. }
  45. return pParticle->m_flRoll;
  46. }
  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. WashEmitter( const WashEmitter & );
  53. };
  54. #endif // !_XBOX
  55. // ==============================================
  56. // Rotorwash entity
  57. // ==============================================
  58. #define ROTORWASH_THINK_INTERVAL 0.1f
  59. class C_RotorWashEmitter : public C_BaseEntity
  60. {
  61. public:
  62. DECLARE_CLASS( C_RotorWashEmitter, C_BaseEntity );
  63. DECLARE_CLIENTCLASS();
  64. C_RotorWashEmitter( void );
  65. virtual void OnDataChanged( DataUpdateType_t updateType );
  66. virtual void ClientThink( void );
  67. protected:
  68. float m_flAltitude;
  69. PMaterialHandle m_hWaterMaterial[2];
  70. #ifndef _XBOX
  71. void InitSpawner( void );
  72. CSmartPtr<WashEmitter> m_pSimple;
  73. #endif // !XBOX
  74. };
  75. IMPLEMENT_CLIENTCLASS_DT( C_RotorWashEmitter, DT_RotorWashEmitter, CRotorWashEmitter)
  76. RecvPropFloat(RECVINFO(m_flAltitude)),
  77. END_RECV_TABLE()
  78. //-----------------------------------------------------------------------------
  79. // Purpose:
  80. //-----------------------------------------------------------------------------
  81. C_RotorWashEmitter::C_RotorWashEmitter( void )
  82. {
  83. #ifndef _XBOX
  84. m_pSimple = NULL;
  85. m_hWaterMaterial[0] = NULL;
  86. m_hWaterMaterial[1] = NULL;
  87. #endif // !_XBOX
  88. }
  89. #ifndef _XBOX
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. void C_RotorWashEmitter::InitSpawner( void )
  94. {
  95. if ( m_pSimple.IsValid() )
  96. return;
  97. m_pSimple = WashEmitter::Create( "wash" );
  98. m_pSimple->SetNearClip( 128, 256 );
  99. }
  100. #endif // !XBOX
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. // Input : updateType -
  104. //-----------------------------------------------------------------------------
  105. void C_RotorWashEmitter::OnDataChanged( DataUpdateType_t updateType )
  106. {
  107. BaseClass::OnDataChanged( updateType );
  108. if ( updateType == DATA_UPDATE_CREATED )
  109. {
  110. SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL );
  111. #ifndef _XBOX
  112. InitSpawner();
  113. #endif // !XBOX
  114. }
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. //-----------------------------------------------------------------------------
  119. void C_RotorWashEmitter::ClientThink( void )
  120. {
  121. SetNextClientThink( gpGlobals->curtime + ROTORWASH_THINK_INTERVAL );
  122. trace_t tr;
  123. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin()+(Vector(0, 0, -1024)), (MASK_SOLID_BRUSHONLY|CONTENTS_WATER|CONTENTS_SLIME), NULL, COLLISION_GROUP_NONE, &tr );
  124. if ( /*!m_bIgnoreSolid && */(tr.fraction == 1.0f || tr.startsolid || tr.allsolid) )
  125. return;
  126. // If we hit the skybox, don't do it either
  127. if ( tr.surface.flags & SURF_SKY )
  128. return;
  129. float heightScale = RemapValClamped( tr.fraction * 1024, 512, 1024, 1.0f, 0.0f );
  130. Vector vecDustColor;
  131. if ( tr.contents & CONTENTS_WATER )
  132. {
  133. vecDustColor.x = 0.8f;
  134. vecDustColor.y = 0.8f;
  135. vecDustColor.z = 0.75f;
  136. }
  137. else if ( tr.contents & CONTENTS_SLIME )
  138. {
  139. vecDustColor.x = 0.6f;
  140. vecDustColor.y = 0.5f;
  141. vecDustColor.z = 0.15f;
  142. }
  143. else
  144. {
  145. vecDustColor.x = 0.35f;
  146. vecDustColor.y = 0.3f;
  147. vecDustColor.z = 0.25f;
  148. }
  149. #ifndef _XBOX
  150. InitSpawner();
  151. if ( m_pSimple.IsValid() == false )
  152. return;
  153. m_pSimple->SetSortOrigin( GetAbsOrigin() );
  154. PMaterialHandle *hMaterial;
  155. // Cache and set our material based on the surface we're over (ie. water)
  156. if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
  157. {
  158. if ( m_hWaterMaterial[0] == NULL )
  159. {
  160. m_hWaterMaterial[0] = m_pSimple->GetPMaterial("effects/splash1");
  161. m_hWaterMaterial[1] = m_pSimple->GetPMaterial("effects/splash2");
  162. }
  163. hMaterial = m_hWaterMaterial;
  164. }
  165. else
  166. {
  167. hMaterial = g_Mat_DustPuff;
  168. }
  169. #endif // !XBOX
  170. // If we're above water, make ripples
  171. if ( tr.contents & (CONTENTS_WATER|CONTENTS_SLIME) )
  172. {
  173. float flScale = random->RandomFloat( 7.5f, 8.5f );
  174. Vector color = Vector( 0.8f, 0.8f, 0.75f );
  175. Vector startPos = tr.endpos + Vector(0,0,8);
  176. Vector endPos = tr.endpos + Vector(0,0,-64);
  177. if ( tr.fraction < 1.0f )
  178. {
  179. //Add a ripple quad to the surface
  180. FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ),
  181. tr.plane.normal,
  182. 64.0f * flScale,
  183. 128.0f * flScale,
  184. 0.8f,
  185. 0.75f * heightScale,
  186. 0.0f,
  187. 0.75f,
  188. random->RandomFloat( 0, 360 ),
  189. random->RandomFloat( -2.0f, 2.0f ),
  190. vecDustColor,
  191. 0.2f,
  192. "effects/splashwake3",
  193. (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
  194. }
  195. }
  196. #ifndef _XBOX
  197. int numRingSprites = 32;
  198. float yaw = random->RandomFloat( 0, 2*M_PI ); // Randomly placed on the unit circle
  199. float yawIncr = (2*M_PI) / numRingSprites;
  200. Vector vecForward;
  201. Vector offset;
  202. SimpleParticle *pParticle;
  203. // Draw the rings
  204. for ( int i = 0; i < numRingSprites; i++ )
  205. {
  206. // Get our x,y on the unit circle
  207. SinCos( yaw, &vecForward.y, &vecForward.x );
  208. // Increment ahead
  209. yaw += yawIncr;
  210. // @NOTE toml (3-28-07): broke out following expression because vc2005 optimizer was screwing up in presence of SinCos inline assembly. Would also
  211. // go away if offset were referenced below as in the AddLineOverlay()
  212. //offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( vecForward * 128.0f );
  213. offset = vecForward * 128.0f;
  214. offset += tr.endpos + RandomVector( -4.0f, 4.0f );
  215. pParticle = (SimpleParticle *) m_pSimple->AddParticle( sizeof(SimpleParticle), hMaterial[random->RandomInt(0,1)], offset );
  216. if ( pParticle != NULL )
  217. {
  218. pParticle->m_flLifetime = 0.0f;
  219. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 1.0f );
  220. pParticle->m_vecVelocity = vecForward * random->RandomFloat( 1000, 1500 );
  221. #if __EXPLOSION_DEBUG
  222. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  223. #endif
  224. if ( tr.contents & CONTENTS_SLIME )
  225. {
  226. vecDustColor.x = random->RandomFloat( 0.4f, 0.6f );
  227. vecDustColor.y = random->RandomFloat( 0.3f, 0.5f );
  228. vecDustColor.z = random->RandomFloat( 0.1f, 0.2f );
  229. }
  230. pParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
  231. pParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
  232. pParticle->m_uchColor[2] = vecDustColor.z * 255.0f;
  233. pParticle->m_uchStartSize = random->RandomInt( 16, 64 );
  234. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  235. pParticle->m_uchStartAlpha = random->RandomFloat( 16, 32 ) * heightScale;
  236. pParticle->m_uchEndAlpha = 0;
  237. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  238. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  239. }
  240. }
  241. #endif // !XBOX
  242. }