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.

421 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "basegrenade_shared.h"
  8. #include "fx_interpvalue.h"
  9. #include "fx_envelope.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #include "particles_simple.h"
  12. #include "particles_attractor.h"
  13. // FIXME: Move out
  14. extern void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color );
  15. #define EXPLOSION_DURATION 3.0f
  16. //-----------------------------------------------------------------------------
  17. // Explosion effect for hopwire
  18. //-----------------------------------------------------------------------------
  19. class C_HopwireExplosion : public C_EnvelopeFX
  20. {
  21. typedef C_EnvelopeFX BaseClass;
  22. public:
  23. C_HopwireExplosion( void ) :
  24. m_hOwner( NULL )
  25. {
  26. m_FXCoreScale.SetAbsolute( 0.0f );
  27. m_FXCoreAlpha.SetAbsolute( 0.0f );
  28. }
  29. virtual void Update( void );
  30. virtual int DrawModel( int flags );
  31. virtual void GetRenderBounds( Vector& mins, Vector& maxs );
  32. bool SetupEmitters( void );
  33. void AddParticles( void );
  34. void SetOwner( C_BaseEntity *pOwner );
  35. void StartExplosion( void );
  36. void StopExplosion( void );
  37. void StartPreExplosion( void );
  38. private:
  39. CInterpolatedValue m_FXCoreScale;
  40. CInterpolatedValue m_FXCoreAlpha;
  41. CSmartPtr<CSimpleEmitter> m_pSimpleEmitter;
  42. CSmartPtr<CParticleAttractor> m_pAttractorEmitter;
  43. TimedEvent m_ParticleTimer;
  44. CHandle<C_BaseEntity> m_hOwner;
  45. };
  46. //-----------------------------------------------------------------------------
  47. // Purpose: Setup the emitters we'll be using
  48. //-----------------------------------------------------------------------------
  49. bool C_HopwireExplosion::SetupEmitters( void )
  50. {
  51. // Setup the basic core emitter
  52. if ( m_pSimpleEmitter.IsValid() == false )
  53. {
  54. m_pSimpleEmitter = CSimpleEmitter::Create( "hopwirecore" );
  55. if ( m_pSimpleEmitter.IsValid() == false )
  56. return false;
  57. }
  58. // Setup the attractor emitter
  59. if ( m_pAttractorEmitter.IsValid() == false )
  60. {
  61. m_pAttractorEmitter = CParticleAttractor::Create( GetRenderOrigin(), "hopwireattractor" );
  62. if ( m_pAttractorEmitter.IsValid() == false )
  63. return false;
  64. }
  65. return true;
  66. }
  67. //-----------------------------------------------------------------------------
  68. // Purpose:
  69. //-----------------------------------------------------------------------------
  70. void C_HopwireExplosion::AddParticles( void )
  71. {
  72. // Make sure the emitters are setup properly
  73. if ( SetupEmitters() == false )
  74. return;
  75. float tempDelta = gpGlobals->frametime;
  76. while( m_ParticleTimer.NextEvent( tempDelta ) )
  77. {
  78. // ========================
  79. // Attracted dust particles
  80. // ========================
  81. // Update our attractor point
  82. m_pAttractorEmitter->SetAttractorOrigin( GetRenderOrigin() );
  83. Vector offset;
  84. SimpleParticle *sParticle;
  85. offset = GetRenderOrigin() + RandomVector( -256.0f, 256.0f );
  86. sParticle = (SimpleParticle *) m_pAttractorEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_Fleck_Cement[0], offset );
  87. if ( sParticle == NULL )
  88. return;
  89. sParticle->m_vecVelocity = Vector(0,0,8);
  90. sParticle->m_flDieTime = 0.5f;
  91. sParticle->m_flLifetime = 0.0f;
  92. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  93. sParticle->m_flRollDelta = 1.0f;
  94. float alpha = random->RandomFloat( 128.0f, 200.0f );
  95. sParticle->m_uchColor[0] = alpha;
  96. sParticle->m_uchColor[1] = alpha;
  97. sParticle->m_uchColor[2] = alpha;
  98. sParticle->m_uchStartAlpha = alpha;
  99. sParticle->m_uchEndAlpha = alpha;
  100. sParticle->m_uchStartSize = random->RandomInt( 1, 4 );
  101. sParticle->m_uchEndSize = 0;
  102. // ========================
  103. // Core effects
  104. // ========================
  105. // Reset our sort origin
  106. m_pSimpleEmitter->SetSortOrigin( GetRenderOrigin() );
  107. // Base of the core effect
  108. sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), m_pSimpleEmitter->GetPMaterial( "effects/strider_muzzle" ), GetRenderOrigin() );
  109. if ( sParticle == NULL )
  110. return;
  111. sParticle->m_vecVelocity = vec3_origin;
  112. sParticle->m_flDieTime = 0.2f;
  113. sParticle->m_flLifetime = 0.0f;
  114. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  115. sParticle->m_flRollDelta = 4.0f;
  116. alpha = random->RandomInt( 32, 200 );
  117. sParticle->m_uchColor[0] = alpha;
  118. sParticle->m_uchColor[1] = alpha;
  119. sParticle->m_uchColor[2] = alpha;
  120. sParticle->m_uchStartAlpha = 0;
  121. sParticle->m_uchEndAlpha = alpha;
  122. sParticle->m_uchStartSize = 255;
  123. sParticle->m_uchEndSize = 0;
  124. // Make sure we encompass the complete particle here!
  125. m_pSimpleEmitter->SetParticleCullRadius( sParticle->m_uchEndSize );
  126. // =========================
  127. // Dust ring effect
  128. // =========================
  129. if ( random->RandomInt( 0, 5 ) != 1 )
  130. return;
  131. Vector vecDustColor;
  132. vecDustColor.x = 0.35f;
  133. vecDustColor.y = 0.3f;
  134. vecDustColor.z = 0.25f;
  135. Vector color;
  136. int numRingSprites = 8;
  137. float yaw;
  138. Vector forward, vRight, vForward;
  139. vForward = Vector( 0, 1, 0 );
  140. vRight = Vector( 1, 0, 0 );
  141. float yawOfs = random->RandomFloat( 0, 359 );
  142. for ( int i = 0; i < numRingSprites; i++ )
  143. {
  144. yaw = ( (float) i / (float) numRingSprites ) * 360.0f;
  145. yaw += yawOfs;
  146. forward = ( vRight * sin( DEG2RAD( yaw) ) ) + ( vForward * cos( DEG2RAD( yaw ) ) );
  147. VectorNormalize( forward );
  148. trace_t tr;
  149. UTIL_TraceLine( GetRenderOrigin(), GetRenderOrigin()+(Vector(0, 0, -1024)), MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
  150. offset = ( RandomVector( -4.0f, 4.0f ) + tr.endpos ) + ( forward * 512.0f );
  151. sParticle = (SimpleParticle *) m_pSimpleEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[random->RandomInt(0,1)], offset );
  152. if ( sParticle != NULL )
  153. {
  154. sParticle->m_flLifetime = 0.0f;
  155. sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  156. sParticle->m_vecVelocity = forward * -random->RandomFloat( 1000, 1500 );
  157. sParticle->m_vecVelocity[2] += 128.0f;
  158. #if __EXPLOSION_DEBUG
  159. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + sParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  160. #endif
  161. sParticle->m_uchColor[0] = vecDustColor.x * 255.0f;
  162. sParticle->m_uchColor[1] = vecDustColor.y * 255.0f;
  163. sParticle->m_uchColor[2] = vecDustColor.z * 255.0f;
  164. sParticle->m_uchStartSize = random->RandomInt( 32, 128 );
  165. sParticle->m_uchEndSize = 200;
  166. sParticle->m_uchStartAlpha = random->RandomFloat( 16, 64 );
  167. sParticle->m_uchEndAlpha = 0;
  168. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  169. sParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  170. }
  171. }
  172. }
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. // Input : *pOwner -
  177. //-----------------------------------------------------------------------------
  178. void C_HopwireExplosion::SetOwner( C_BaseEntity *pOwner )
  179. {
  180. m_hOwner = pOwner;
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose: Updates the internal values for the effect
  184. //-----------------------------------------------------------------------------
  185. void C_HopwireExplosion::Update( void )
  186. {
  187. if ( m_hOwner )
  188. {
  189. SetRenderOrigin( m_hOwner->GetRenderOrigin() );
  190. }
  191. BaseClass::Update();
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose: Updates and renders all effects
  195. //-----------------------------------------------------------------------------
  196. int C_HopwireExplosion::DrawModel( int flags )
  197. {
  198. AddParticles();
  199. CMatRenderContextPtr pRenderContext( materials );
  200. pRenderContext->Flush();
  201. UpdateRefractTexture();
  202. IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS );
  203. float refract = m_FXCoreAlpha.Interp( gpGlobals->curtime );
  204. float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
  205. IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL );
  206. pVar->SetFloatValue( refract );
  207. pRenderContext->Bind( pMat, (IClientRenderable*)this );
  208. float sin1 = sinf( gpGlobals->curtime * 10 );
  209. float sin2 = sinf( gpGlobals->curtime );
  210. float scaleY = ( sin1 * sin2 ) * 32.0f;
  211. float scaleX = (sin2 * sin2) * 32.0f;
  212. // FIXME: The ball needs to sort properly at all times
  213. static color32 white = {255,255,255,255};
  214. DrawSpriteTangentSpace( GetRenderOrigin() + ( CurrentViewForward() * 128.0f ), scale+scaleX, scale+scaleY, white );
  215. return 1;
  216. }
  217. //-----------------------------------------------------------------------------
  218. // Purpose: Returns the bounds relative to the origin (render bounds)
  219. //-----------------------------------------------------------------------------
  220. void C_HopwireExplosion::GetRenderBounds( Vector& mins, Vector& maxs )
  221. {
  222. float scale = m_FXCoreScale.Interp( gpGlobals->curtime );
  223. mins.Init( -scale, -scale, -scale );
  224. maxs.Init( scale, scale, scale );
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. //-----------------------------------------------------------------------------
  229. void C_HopwireExplosion::StartExplosion( void )
  230. {
  231. m_FXCoreScale.Init( 300.0f, 500.0f, 2.0f, INTERP_SPLINE );
  232. m_FXCoreAlpha.Init( 0.0f, 0.1f, 1.5f, INTERP_SPLINE );
  233. // Particle timer
  234. m_ParticleTimer.Init( 60 );
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Purpose:
  238. //-----------------------------------------------------------------------------
  239. void C_HopwireExplosion::StopExplosion( void )
  240. {
  241. m_FXCoreAlpha.InitFromCurrent( 0.0f, 1.0f, INTERP_SPLINE );
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose:
  245. //-----------------------------------------------------------------------------
  246. void C_HopwireExplosion::StartPreExplosion( void )
  247. {
  248. }
  249. //-----------------------------------------------------------------------------
  250. // Hopwire client class
  251. //-----------------------------------------------------------------------------
  252. class C_GrenadeHopwire : public C_BaseGrenade
  253. {
  254. DECLARE_CLASS( C_GrenadeHopwire, C_BaseGrenade );
  255. DECLARE_CLIENTCLASS();
  256. public:
  257. C_GrenadeHopwire( void );
  258. virtual int DrawModel( int flags );
  259. virtual void OnDataChanged( DataUpdateType_t updateType );
  260. virtual void ReceiveMessage( int classID, bf_read &msg );
  261. private:
  262. C_HopwireExplosion m_ExplosionEffect; // Explosion effect information and drawing
  263. };
  264. IMPLEMENT_CLIENTCLASS_DT( C_GrenadeHopwire, DT_GrenadeHopwire, CGrenadeHopwire )
  265. END_RECV_TABLE()
  266. #define HOPWIRE_START_EXPLOSION 0
  267. #define HOPWIRE_STOP_EXPLOSION 1
  268. #define HOPWIRE_START_PRE_EXPLOSION 2
  269. //-----------------------------------------------------------------------------
  270. // Constructor
  271. //-----------------------------------------------------------------------------
  272. C_GrenadeHopwire::C_GrenadeHopwire( void )
  273. {
  274. m_ExplosionEffect.SetActive( false );
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: Receive messages from the server
  278. // Input : classID - class to receive the message
  279. // &msg - message in question
  280. //-----------------------------------------------------------------------------
  281. void C_GrenadeHopwire::ReceiveMessage( int classID, bf_read &msg )
  282. {
  283. if ( classID != GetClientClass()->m_ClassID )
  284. {
  285. // Message is for subclass
  286. BaseClass::ReceiveMessage( classID, msg );
  287. return;
  288. }
  289. int messageType = msg.ReadByte();
  290. switch( messageType )
  291. {
  292. case HOPWIRE_START_EXPLOSION:
  293. {
  294. m_ExplosionEffect.SetActive();
  295. m_ExplosionEffect.SetOwner( this );
  296. m_ExplosionEffect.StartExplosion();
  297. }
  298. break;
  299. case HOPWIRE_STOP_EXPLOSION:
  300. {
  301. m_ExplosionEffect.StopExplosion();
  302. }
  303. break;
  304. default:
  305. break;
  306. }
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Purpose:
  310. // Input : updateType -
  311. //-----------------------------------------------------------------------------
  312. void C_GrenadeHopwire::OnDataChanged( DataUpdateType_t updateType )
  313. {
  314. BaseClass::OnDataChanged( updateType );
  315. m_ExplosionEffect.Update();
  316. }
  317. //-----------------------------------------------------------------------------
  318. // Purpose:
  319. // Input : flags -
  320. //-----------------------------------------------------------------------------
  321. int C_GrenadeHopwire::DrawModel( int flags )
  322. {
  323. if ( m_ExplosionEffect.IsActive() )
  324. return 1;
  325. return BaseClass::DrawModel( flags );
  326. }