Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1327 lines
40 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $NoKeywords: $
  7. //=============================================================================//
  8. #include "cbase.h"
  9. #include "engine/IEngineSound.h"
  10. #include "particles_simple.h"
  11. #include "particles_localspace.h"
  12. #include "dlight.h"
  13. #include "iefx.h"
  14. #include "clientsideeffects.h"
  15. #include "precache_register.h"
  16. #include "glow_overlay.h"
  17. #include "effect_dispatch_data.h"
  18. #include "c_te_effect_dispatch.h"
  19. #include "tier0/vprof.h"
  20. #include "tier1/keyvalues.h"
  21. #include "effect_color_tables.h"
  22. #include "iviewrender_beams.h"
  23. #include "view.h"
  24. #include "IEffects.h"
  25. #include "fx.h"
  26. #include "c_te_legacytempents.h"
  27. #include "toolframework_client.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. //Precahce the effects
  31. #if !defined(TF_CLIENT_DLL) && !defined(DOTA_CLIENT_DLL)
  32. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheMuzzleFlash )
  33. PRECACHE( MATERIAL, "effects/muzzleflash1" )
  34. PRECACHE( MATERIAL, "effects/muzzleflash2" )
  35. PRECACHE( MATERIAL, "effects/muzzleflash3" )
  36. PRECACHE( MATERIAL, "effects/muzzleflash4" )
  37. #if !defined( CSTRIKE_DLL )
  38. PRECACHE( MATERIAL, "effects/bluemuzzle" )
  39. PRECACHE( MATERIAL, "effects/gunshipmuzzle" )
  40. PRECACHE( MATERIAL, "effects/gunshiptracer" )
  41. PRECACHE( MATERIAL, "effects/huntertracer" )
  42. PRECACHE( MATERIAL, "sprites/physcannon_bluelight2" )
  43. PRECACHE( MATERIAL, "effects/combinemuzzle1" )
  44. PRECACHE( MATERIAL, "effects/combinemuzzle2" )
  45. PRECACHE( MATERIAL, "effects/combinemuzzle2_nocull" )
  46. #endif
  47. PRECACHE_REGISTER_END()
  48. #endif
  49. //Whether or not we should emit a dynamic light
  50. ConVar muzzleflash_light( "muzzleflash_light", "1", FCVAR_ARCHIVE );
  51. extern void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType );
  52. //===================================================================
  53. //===================================================================
  54. class CImpactOverlay : public CWarpOverlay
  55. {
  56. public:
  57. virtual bool Update( void )
  58. {
  59. m_flLifetime += gpGlobals->frametime;
  60. const float flTotalLifetime = 0.1f;
  61. if ( m_flLifetime < flTotalLifetime )
  62. {
  63. float flColorScale = 1.0f - ( m_flLifetime / flTotalLifetime );
  64. for( int i=0; i < m_nSprites; i++ )
  65. {
  66. m_Sprites[i].m_vColor = m_vBaseColors[i] * flColorScale;
  67. m_Sprites[i].m_flHorzSize += 1.0f * gpGlobals->frametime;
  68. m_Sprites[i].m_flVertSize += 1.0f * gpGlobals->frametime;
  69. }
  70. return true;
  71. }
  72. return false;
  73. }
  74. public:
  75. float m_flLifetime;
  76. Vector m_vBaseColors[MAX_SUN_LAYERS];
  77. };
  78. //-----------------------------------------------------------------------------
  79. // Purpose: Play random ricochet sound
  80. // Input : *pos -
  81. //-----------------------------------------------------------------------------
  82. void FX_RicochetSound( const Vector& pos )
  83. {
  84. Vector org = pos;
  85. CLocalPlayerFilter filter;
  86. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "FX_RicochetSound.Ricochet", &org );
  87. if (RandomFloat() < 0.01) // 1% chance of playing legacy cs 1.6 ric sound.
  88. {
  89. C_BaseEntity::EmitSound(filter, SOUND_FROM_WORLD, "FX_RicochetSound.Ricochet_Legacy", &org);
  90. }
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. // Input : entityIndex -
  95. // attachmentIndex -
  96. // *origin -
  97. // *angles -
  98. // Output : Returns true on success, false on failure.
  99. //-----------------------------------------------------------------------------
  100. bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, Vector *origin, QAngle *angles )
  101. {
  102. // Validate our input
  103. if ( ( hEntity == INVALID_EHANDLE ) || ( attachmentIndex < 1 ) )
  104. {
  105. if ( origin != NULL )
  106. {
  107. *origin = vec3_origin;
  108. }
  109. if ( angles != NULL )
  110. {
  111. *angles = QAngle(0,0,0);
  112. }
  113. return false;
  114. }
  115. // Get the actual entity
  116. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( hEntity );
  117. if ( pRenderable )
  118. {
  119. Vector attachOrigin;
  120. QAngle attachAngles;
  121. // Find the attachment's matrix
  122. pRenderable->GetAttachment( attachmentIndex, attachOrigin, attachAngles );
  123. if ( origin != NULL )
  124. {
  125. *origin = attachOrigin;
  126. }
  127. if ( angles != NULL )
  128. {
  129. *angles = attachAngles;
  130. }
  131. return true;
  132. }
  133. return false;
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose:
  137. // Input : entityIndex -
  138. // attachmentIndex -
  139. // &transform -
  140. //-----------------------------------------------------------------------------
  141. bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, matrix3x4_t &transform )
  142. {
  143. Vector origin;
  144. QAngle angles;
  145. if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles ) )
  146. {
  147. AngleMatrix( angles, origin, transform );
  148. return true;
  149. }
  150. // Entity doesn't exist
  151. SetIdentityMatrix( transform );
  152. return false;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. //-----------------------------------------------------------------------------
  157. void FX_MuzzleEffect(
  158. const Vector &origin,
  159. const QAngle &angles,
  160. float scale,
  161. ClientEntityHandle_t hEntity,
  162. unsigned char *pFlashColor,
  163. bool bOneFrame )
  164. {
  165. VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  166. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
  167. pSimple->SetSortOrigin( origin );
  168. SimpleParticle *pParticle;
  169. Vector forward, offset;
  170. AngleVectors( angles, &forward );
  171. float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
  172. if ( flScale < 0.5f )
  173. {
  174. flScale = 0.5f;
  175. }
  176. else if ( flScale > 8.0f )
  177. {
  178. flScale = 8.0f;
  179. }
  180. //
  181. // Flash
  182. //
  183. int i;
  184. for ( i = 1; i < 9; i++ )
  185. {
  186. offset = origin + (forward * (i*2.0f*scale));
  187. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
  188. if ( pParticle == NULL )
  189. return;
  190. pParticle->m_flLifetime = 0.0f;
  191. pParticle->m_flDieTime = /*bOneFrame ? 0.0001f : */0.1f;
  192. pParticle->m_vecVelocity.Init();
  193. if ( !pFlashColor )
  194. {
  195. pParticle->m_uchColor[0] = 255;
  196. pParticle->m_uchColor[1] = 255;
  197. pParticle->m_uchColor[2] = 255;
  198. }
  199. else
  200. {
  201. pParticle->m_uchColor[0] = pFlashColor[0];
  202. pParticle->m_uchColor[1] = pFlashColor[1];
  203. pParticle->m_uchColor[2] = pFlashColor[2];
  204. }
  205. pParticle->m_uchStartAlpha = 255;
  206. pParticle->m_uchEndAlpha = 128;
  207. pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
  208. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  209. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  210. pParticle->m_flRollDelta = 0.0f;
  211. }
  212. //
  213. // Smoke
  214. //
  215. /*
  216. for ( i = 0; i < 4; i++ )
  217. {
  218. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_smokegrenade" ), origin );
  219. if ( pParticle == NULL )
  220. return;
  221. alpha = random->RandomInt( 32, 84 );
  222. color = random->RandomInt( 64, 164 );
  223. pParticle->m_flLifetime = 0.0f;
  224. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  225. pParticle->m_vecVelocity.Random( -0.5f, 0.5f );
  226. pParticle->m_vecVelocity += forward;
  227. VectorNormalize( pParticle->m_vecVelocity );
  228. pParticle->m_vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
  229. pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
  230. pParticle->m_uchColor[0] = color;
  231. pParticle->m_uchColor[1] = color;
  232. pParticle->m_uchColor[2] = color;
  233. pParticle->m_uchStartAlpha = alpha;
  234. pParticle->m_uchEndAlpha = 0;
  235. pParticle->m_uchStartSize = random->RandomInt( 4, 8 ) * flScale;
  236. pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
  237. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  238. pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
  239. }
  240. */
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose:
  244. // Input : scale -
  245. // attachmentIndex -
  246. // bOneFrame -
  247. //-----------------------------------------------------------------------------
  248. void FX_MuzzleEffectAttached(
  249. float scale,
  250. ClientEntityHandle_t hEntity,
  251. int attachmentIndex,
  252. unsigned char *pFlashColor,
  253. bool bOneFrame )
  254. {
  255. VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  256. CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex );
  257. Assert( pSimple );
  258. if ( pSimple == NULL )
  259. return;
  260. // Lock our bounding box
  261. pSimple->GetBinding().SetBBox( -( Vector( 16, 16, 16 ) * scale ), ( Vector( 16, 16, 16 ) * scale ) );
  262. SimpleParticle *pParticle;
  263. Vector forward(1,0,0), offset;
  264. float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
  265. if ( flScale < 0.5f )
  266. {
  267. flScale = 0.5f;
  268. }
  269. else if ( flScale > 8.0f )
  270. {
  271. flScale = 8.0f;
  272. }
  273. //
  274. // Flash
  275. //
  276. int i;
  277. for ( i = 1; i < 9; i++ )
  278. {
  279. offset = (forward * (i*2.0f*scale));
  280. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[random->RandomInt(0,3)], offset );
  281. if ( pParticle == NULL )
  282. return;
  283. pParticle->m_flLifetime = 0.0f;
  284. pParticle->m_flDieTime = bOneFrame ? 0.0001f : 0.1f;
  285. pParticle->m_vecVelocity.Init();
  286. if ( !pFlashColor )
  287. {
  288. pParticle->m_uchColor[0] = 255;
  289. pParticle->m_uchColor[1] = 255;
  290. pParticle->m_uchColor[2] = 255;
  291. }
  292. else
  293. {
  294. pParticle->m_uchColor[0] = pFlashColor[0];
  295. pParticle->m_uchColor[1] = pFlashColor[1];
  296. pParticle->m_uchColor[2] = pFlashColor[2];
  297. }
  298. pParticle->m_uchStartAlpha = 255;
  299. pParticle->m_uchEndAlpha = 128;
  300. pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
  301. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  302. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  303. pParticle->m_flRollDelta = 0.0f;
  304. }
  305. if ( !ToolsEnabled() )
  306. return;
  307. if ( !clienttools->IsInRecordingMode() )
  308. return;
  309. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
  310. if ( pEnt )
  311. {
  312. pEnt->RecordToolMessage();
  313. }
  314. // NOTE: Particle system destruction message will be sent by the particle effect itself.
  315. int nId = pSimple->AllocateToolParticleEffectId();
  316. KeyValues *msg = new KeyValues( "OldParticleSystem_Create" );
  317. msg->SetString( "name", "FX_MuzzleEffectAttached" );
  318. msg->SetInt( "id", nId );
  319. msg->SetFloat( "time", gpGlobals->curtime );
  320. KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true );
  321. pEmitter->SetInt( "count", 9 );
  322. pEmitter->SetFloat( "duration", 0 );
  323. pEmitter->SetString( "material", "effects/muzzleflash2" ); // FIXME - create DmeMultiMaterialSpriteEmitter to support the 4 materials of muzzleflash
  324. pEmitter->SetInt( "active", true );
  325. KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
  326. KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true );
  327. pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
  328. pPosition->SetInt( "attachmentIndex", attachmentIndex );
  329. pPosition->SetFloat( "linearOffsetX", 2.0f * scale );
  330. // TODO - create a DmeConstantLifetimeInitializer
  331. KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
  332. pLifetime->SetFloat( "minLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
  333. pLifetime->SetFloat( "maxLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
  334. KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
  335. pVelocity->SetFloat( "velocityX", 0.0f );
  336. pVelocity->SetFloat( "velocityY", 0.0f );
  337. pVelocity->SetFloat( "velocityZ", 0.0f );
  338. KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
  339. pRoll->SetFloat( "minRoll", 0.0f );
  340. pRoll->SetFloat( "maxRoll", 360.0f );
  341. // TODO - create a DmeConstantRollSpeedInitializer
  342. KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
  343. pRollSpeed->SetFloat( "minRollSpeed", 0.0f );
  344. pRollSpeed->SetFloat( "maxRollSpeed", 0.0f );
  345. // TODO - create a DmeConstantColorInitializer
  346. KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
  347. Color color( pFlashColor ? pFlashColor[ 0 ] : 255, pFlashColor ? pFlashColor[ 1 ] : 255, pFlashColor ? pFlashColor[ 2 ] : 255, 255 );
  348. pColor->SetColor( "color1", color );
  349. pColor->SetColor( "color2", color );
  350. // TODO - create a DmeConstantAlphaInitializer
  351. KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
  352. pAlpha->SetInt( "minStartAlpha", 255 );
  353. pAlpha->SetInt( "maxStartAlpha", 255 );
  354. pAlpha->SetInt( "minEndAlpha", 128 );
  355. pAlpha->SetInt( "maxEndAlpha", 128 );
  356. // size = rand(6..9) * indexed(12/9..4/9) * flScale = rand(6..9) * ( 4f + f * i )
  357. KeyValues *pSize = pInitializers->FindKey( "DmeMuzzleFlashSizeInitializer", true );
  358. float f = flScale / 9.0f;
  359. pSize->SetFloat( "indexedBase", 4.0f * f );
  360. pSize->SetFloat( "indexedDelta", f );
  361. pSize->SetFloat( "minRandomFactor", 6.0f );
  362. pSize->SetFloat( "maxRandomFactor", 9.0f );
  363. /*
  364. KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
  365. pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
  366. pUpdaters->FindKey( "DmeRollUpdater", true );
  367. pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
  368. pUpdaters->FindKey( "DmeSizeUpdater", true );
  369. */
  370. ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
  371. msg->deleteThis();
  372. }
  373. //-----------------------------------------------------------------------------
  374. // Old-style muzzle flashes
  375. //-----------------------------------------------------------------------------
  376. void MuzzleFlashCallback( const CEffectData &data )
  377. {
  378. Vector vecOrigin = data.m_vOrigin;
  379. QAngle vecAngles = data.m_vAngles;
  380. if ( data.entindex() > 0 )
  381. {
  382. IClientRenderable *pRenderable = data.GetRenderable();
  383. if ( !pRenderable )
  384. return;
  385. if ( data.m_nAttachmentIndex )
  386. {
  387. //FIXME: We also need to allocate these particles into an attachment space setup
  388. pRenderable->GetAttachment( data.m_nAttachmentIndex, vecOrigin, vecAngles );
  389. }
  390. else
  391. {
  392. vecOrigin = pRenderable->GetRenderOrigin();
  393. vecAngles = pRenderable->GetRenderAngles();
  394. }
  395. }
  396. tempents->MuzzleFlash( vecOrigin, vecAngles, data.m_fFlags & (~MUZZLEFLASH_FIRSTPERSON), data.m_hEntity, (data.m_fFlags & MUZZLEFLASH_FIRSTPERSON) != 0 );
  397. }
  398. DECLARE_CLIENT_EFFECT( MuzzleFlash, MuzzleFlashCallback );
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. // Input : &origin -
  402. // &velocity -
  403. // scale -
  404. // numParticles -
  405. // *pColor -
  406. // iAlpha -
  407. // *pMaterial -
  408. // flRoll -
  409. // flRollDelta -
  410. //-----------------------------------------------------------------------------
  411. CSmartPtr<CSimpleEmitter> FX_Smoke( const Vector &origin, const Vector &velocity, float scale, int numParticles, float flDietime, unsigned char *pColor, int iAlpha, const char *pMaterial, float flRoll, float flRollDelta )
  412. {
  413. VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  414. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Smoke" );
  415. pSimple->SetSortOrigin( origin );
  416. SimpleParticle *pParticle;
  417. // Smoke
  418. for ( int i = 0; i < numParticles; i++ )
  419. {
  420. PMaterialHandle hMaterial = pSimple->GetPMaterial( pMaterial );
  421. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
  422. if ( pParticle == NULL )
  423. return NULL;
  424. pParticle->m_flLifetime = 0.0f;
  425. pParticle->m_flDieTime = flDietime;
  426. pParticle->m_vecVelocity = velocity;
  427. for( int i = 0; i < 3; ++i )
  428. {
  429. pParticle->m_uchColor[i] = pColor[i];
  430. }
  431. pParticle->m_uchStartAlpha = iAlpha;
  432. pParticle->m_uchEndAlpha = 0;
  433. pParticle->m_uchStartSize = scale;
  434. pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
  435. pParticle->m_flRoll = flRoll;
  436. pParticle->m_flRollDelta = flRollDelta;
  437. }
  438. return pSimple;
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Purpose: Smoke puffs
  442. //-----------------------------------------------------------------------------
  443. void FX_Smoke( const Vector &origin, const QAngle &angles, float scale, int numParticles, unsigned char *pColor, int iAlpha )
  444. {
  445. VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  446. Vector vecVelocity;
  447. Vector vecForward;
  448. // Smoke
  449. for ( int i = 0; i < numParticles; i++ )
  450. {
  451. // Velocity
  452. AngleVectors( angles, &vecForward );
  453. vecVelocity.Random( -0.5f, 0.5f );
  454. vecVelocity += vecForward;
  455. VectorNormalize( vecVelocity );
  456. vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
  457. vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
  458. // Color
  459. unsigned char particlecolor[3];
  460. if ( !pColor )
  461. {
  462. int color = random->RandomInt( 64, 164 );
  463. particlecolor[0] = color;
  464. particlecolor[1] = color;
  465. particlecolor[2] = color;
  466. }
  467. else
  468. {
  469. particlecolor[0] = pColor[0];
  470. particlecolor[1] = pColor[1];
  471. particlecolor[2] = pColor[2];
  472. }
  473. // Alpha
  474. int alpha = iAlpha;
  475. if ( alpha == -1 )
  476. {
  477. alpha = random->RandomInt( 10, 25 );
  478. }
  479. // Scale
  480. int iSize = random->RandomInt( 4, 8 ) * scale;
  481. // Roll
  482. float flRoll = random->RandomInt( 0, 360 );
  483. float flRollDelta = random->RandomFloat( -4.0f, 4.0f );
  484. //pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
  485. FX_Smoke( origin, vecVelocity, iSize, 1, random->RandomFloat( 0.5f, 1.0f ), particlecolor, alpha, "particle/particle_smokegrenade", flRoll, flRollDelta );
  486. }
  487. }
  488. //-----------------------------------------------------------------------------
  489. // Purpose: Smoke Emitter
  490. // This is an emitter that keeps spitting out particles for its lifetime
  491. // It won't create particles if it's not in view, so it's best when short lived
  492. //-----------------------------------------------------------------------------
  493. class CSmokeEmitter : public CSimpleEmitter
  494. {
  495. typedef CSimpleEmitter BaseClass;
  496. public:
  497. CSmokeEmitter( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName ) : CSimpleEmitter( pDebugName )
  498. {
  499. m_hEntity = hEntity;
  500. m_nAttachmentIndex = nAttachment;
  501. m_flDeathTime = 0;
  502. m_flLastParticleSpawnTime = 0;
  503. }
  504. // Create
  505. static CSmokeEmitter *Create( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName="smoke" )
  506. {
  507. return new CSmokeEmitter( hEntity, nAttachment, pDebugName );
  508. }
  509. void SetLifeTime( float flTime )
  510. {
  511. m_flDeathTime = gpGlobals->curtime + flTime;
  512. }
  513. void SetSpurtAngle( QAngle &vecAngles )
  514. {
  515. AngleVectors( vecAngles, &m_vecSpurtForward );
  516. }
  517. void SetSpurtColor( const Vector4D &pColor )
  518. {
  519. for ( int i = 0; i <= 3; i++ )
  520. {
  521. m_SpurtColor[i] = pColor[i];
  522. }
  523. }
  524. void SetSpawnRate( float flRate )
  525. {
  526. m_flSpawnRate = flRate;
  527. }
  528. void CreateSpurtParticles( void )
  529. {
  530. SimpleParticle *pParticle;
  531. // PMaterialHandle hMaterial = GetPMaterial( "particle/particle_smokegrenade" );
  532. Vector vecOrigin = m_vSortOrigin;
  533. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle(m_hEntity);
  534. if ( pRenderable && m_nAttachmentIndex )
  535. {
  536. QAngle tmp;
  537. pRenderable->GetAttachment( m_nAttachmentIndex, vecOrigin, tmp );
  538. SetSortOrigin( vecOrigin );
  539. }
  540. // Smoke
  541. int numParticles = RandomInt( 1,2 );
  542. for ( int i = 0; i < numParticles; i++ )
  543. {
  544. pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], vecOrigin );
  545. if ( pParticle == NULL )
  546. break;
  547. pParticle->m_flLifetime = 0.0f;
  548. pParticle->m_flDieTime = RandomFloat( 0.5, 1.0 );
  549. // Random velocity around the angles forward
  550. Vector vecVelocity;
  551. vecVelocity.Random( -0.1f, 0.1f );
  552. vecVelocity += m_vecSpurtForward;
  553. VectorNormalize( vecVelocity );
  554. vecVelocity *= RandomFloat( 160.0f, 640.0f );
  555. pParticle->m_vecVelocity = vecVelocity;
  556. // Randomize the color a little
  557. int color[3][2];
  558. for( int i = 0; i < 3; ++i )
  559. {
  560. color[i][0] = MAX( 0, m_SpurtColor[i] - 64 );
  561. color[i][1] = MIN( 255, m_SpurtColor[i] + 64 );
  562. }
  563. pParticle->m_uchColor[0] = random->RandomInt( color[0][0], color[0][1] );
  564. pParticle->m_uchColor[1] = random->RandomInt( color[1][0], color[1][1] );
  565. pParticle->m_uchColor[2] = random->RandomInt( color[2][0], color[2][1] );
  566. pParticle->m_uchStartAlpha = m_SpurtColor[3];
  567. pParticle->m_uchEndAlpha = 0;
  568. pParticle->m_uchStartSize = RandomInt( 50, 60 );
  569. pParticle->m_uchEndSize = pParticle->m_uchStartSize*3;
  570. pParticle->m_flRoll = RandomFloat( 0, 360 );
  571. pParticle->m_flRollDelta = RandomFloat( -4.0f, 4.0f );
  572. }
  573. m_flLastParticleSpawnTime = gpGlobals->curtime + m_flSpawnRate;
  574. }
  575. virtual void SimulateParticles( CParticleSimulateIterator *pIterator )
  576. {
  577. Particle *pParticle = pIterator->GetFirst();
  578. while ( pParticle )
  579. {
  580. // If our lifetime isn't up, create more particles
  581. if ( m_flDeathTime > gpGlobals->curtime )
  582. {
  583. if ( m_flLastParticleSpawnTime <= gpGlobals->curtime )
  584. {
  585. CreateSpurtParticles();
  586. }
  587. }
  588. pParticle = pIterator->GetNext();
  589. }
  590. BaseClass::SimulateParticles( pIterator );
  591. }
  592. private:
  593. float m_flDeathTime;
  594. float m_flLastParticleSpawnTime;
  595. float m_flSpawnRate;
  596. Vector m_vecSpurtForward;
  597. Vector4D m_SpurtColor;
  598. ClientEntityHandle_t m_hEntity;
  599. int m_nAttachmentIndex;
  600. CSmokeEmitter( const CSmokeEmitter & ); // not defined, not accessible
  601. };
  602. //-----------------------------------------------------------------------------
  603. // Purpose: Small hose gas spurt
  604. //-----------------------------------------------------------------------------
  605. void FX_BuildSmoke( Vector &vecOrigin, QAngle &vecAngles, ClientEntityHandle_t hEntity, int nAttachment, float flLifeTime, const Vector4D &pColor )
  606. {
  607. CSmartPtr<CSmokeEmitter> pSimple = CSmokeEmitter::Create( hEntity, nAttachment, "FX_Smoke" );
  608. pSimple->SetSortOrigin( vecOrigin );
  609. pSimple->SetLifeTime( flLifeTime );
  610. pSimple->SetSpurtAngle( vecAngles );
  611. pSimple->SetSpurtColor( pColor );
  612. pSimple->SetSpawnRate( 0.03 );
  613. pSimple->CreateSpurtParticles();
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Purpose: Green hose gas spurt
  617. //-----------------------------------------------------------------------------
  618. void SmokeCallback( const CEffectData &data )
  619. {
  620. Vector vecOrigin = data.m_vOrigin;
  621. QAngle vecAngles = data.m_vAngles;
  622. Vector4D color( 50,50,50,255 );
  623. FX_BuildSmoke( vecOrigin, vecAngles, data.m_hEntity, data.m_nAttachmentIndex, 100.0, color );
  624. }
  625. DECLARE_CLIENT_EFFECT( Smoke, SmokeCallback );
  626. //-----------------------------------------------------------------------------
  627. // Purpose: Shockwave for gunship bullet impacts!
  628. // Input : &pos -
  629. //
  630. // NOTES: -Don't draw this effect when the viewer is very far away.
  631. //-----------------------------------------------------------------------------
  632. void FX_GunshipImpact( const Vector &pos, const Vector &normal, float r, float g, float b )
  633. {
  634. VPROF_BUDGET( "FX_GunshipImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  635. if ( CImpactOverlay *pOverlay = new CImpactOverlay )
  636. {
  637. pOverlay->m_flLifetime = 0;
  638. VectorMA( pos, 1.0f, normal, pOverlay->m_vPos ); // Doesn't show up on terrain if you don't do this(sjb)
  639. pOverlay->m_nSprites = 1;
  640. pOverlay->m_vBaseColors[0].Init( r, g, b );
  641. pOverlay->m_Sprites[0].m_flHorzSize = 0.01f;
  642. pOverlay->m_Sprites[0].m_flVertSize = 0.01f;
  643. pOverlay->Activate();
  644. }
  645. }
  646. //-----------------------------------------------------------------------------
  647. // Purpose:
  648. // Input : data -
  649. //-----------------------------------------------------------------------------
  650. void GunshipImpactCallback( const CEffectData & data )
  651. {
  652. Vector vecPosition;
  653. vecPosition = data.m_vOrigin;
  654. FX_GunshipImpact( vecPosition, Vector( 0, 0, 1 ), 100, 0, 200 );
  655. }
  656. DECLARE_CLIENT_EFFECT( GunshipImpact, GunshipImpactCallback );
  657. //-----------------------------------------------------------------------------
  658. //-----------------------------------------------------------------------------
  659. void CommandPointerCallback( const CEffectData & data )
  660. {
  661. int size = COLOR_TABLE_SIZE( commandercolors );
  662. for( int i = 0 ; i < size ; i++ )
  663. {
  664. if( commandercolors[ i ].index == data.m_nColor )
  665. {
  666. FX_GunshipImpact( data.m_vOrigin, Vector( 0, 0, 1 ), commandercolors[ i ].r, commandercolors[ i ].g, commandercolors[ i ].b );
  667. return;
  668. }
  669. }
  670. }
  671. DECLARE_CLIENT_EFFECT( CommandPointer, CommandPointerCallback );
  672. //-----------------------------------------------------------------------------
  673. // Purpose:
  674. //-----------------------------------------------------------------------------
  675. void FX_GunshipMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
  676. {
  677. VPROF_BUDGET( "FX_GunshipMuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  678. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
  679. pSimple->SetSortOrigin( origin );
  680. SimpleParticle *pParticle;
  681. Vector forward, offset;
  682. AngleVectors( angles, &forward );
  683. //
  684. // Flash
  685. //
  686. offset = origin;
  687. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/gunshipmuzzle" ), offset );
  688. if ( pParticle == NULL )
  689. return;
  690. pParticle->m_flLifetime = 0.0f;
  691. pParticle->m_flDieTime = 0.15f;
  692. pParticle->m_vecVelocity.Init();
  693. pParticle->m_uchStartSize = random->RandomFloat( 40.0, 50.0 );
  694. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  695. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  696. pParticle->m_flRollDelta = 0.15f;
  697. pParticle->m_uchColor[0] = 255;
  698. pParticle->m_uchColor[1] = 255;
  699. pParticle->m_uchColor[2] = 255;
  700. pParticle->m_uchStartAlpha = 255;
  701. pParticle->m_uchEndAlpha = 255;
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Purpose:
  705. // Input : start -
  706. // end -
  707. // velocity -
  708. // makeWhiz -
  709. //-----------------------------------------------------------------------------
  710. void FX_GunshipTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
  711. {
  712. VPROF_BUDGET( "FX_GunshipTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  713. Vector vNear, dStart, dEnd, shotDir;
  714. float totalDist;
  715. //Get out shot direction and length
  716. VectorSubtract( end, start, shotDir );
  717. totalDist = VectorNormalize( shotDir );
  718. //Don't make small tracers
  719. if ( totalDist <= 256 )
  720. return;
  721. float length = random->RandomFloat( 128.0f, 256.0f );
  722. float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
  723. //Add it
  724. FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 5.0f, life, "effects/gunshiptracer" );
  725. if( makeWhiz )
  726. {
  727. FX_TracerSound( start, end, TRACER_TYPE_GUNSHIP );
  728. }
  729. }
  730. //-----------------------------------------------------------------------------
  731. //-----------------------------------------------------------------------------
  732. void FX_StriderMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
  733. {
  734. Vector vecDir;
  735. AngleVectors( angles, &vecDir );
  736. float life = 0.3f;
  737. float speed = 100.0f;
  738. for( int i = 0 ; i < 5 ; i++ )
  739. {
  740. FX_AddDiscreetLine( origin, vecDir, speed, 32, speed * life, 5.0f, life, "effects/bluespark" );
  741. speed *= 1.5f;
  742. }
  743. }
  744. //-----------------------------------------------------------------------------
  745. // Purpose:
  746. // Input : start -
  747. // end -
  748. // velocity -
  749. // makeWhiz -
  750. //-----------------------------------------------------------------------------
  751. void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
  752. {
  753. VPROF_BUDGET( "FX_StriderTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  754. Vector vNear, dStart, dEnd, shotDir;
  755. float totalDist;
  756. //Get out shot direction and length
  757. VectorSubtract( end, start, shotDir );
  758. totalDist = VectorNormalize( shotDir );
  759. //Don't make small tracers
  760. if ( totalDist <= 256 )
  761. return;
  762. float length = random->RandomFloat( 64.0f, 128.0f );
  763. float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
  764. //Add it
  765. FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 2.5f, life, "effects/gunshiptracer" );
  766. if( makeWhiz )
  767. {
  768. FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
  769. }
  770. }
  771. //-----------------------------------------------------------------------------
  772. // Purpose:
  773. // Input : start -
  774. // end -
  775. // velocity -
  776. // makeWhiz -
  777. //-----------------------------------------------------------------------------
  778. void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
  779. {
  780. VPROF_BUDGET( "FX_HunterTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  781. Vector vNear, dStart, dEnd, shotDir;
  782. float totalDist;
  783. // Get out shot direction and length
  784. VectorSubtract( end, start, shotDir );
  785. totalDist = VectorNormalize( shotDir );
  786. // Make short tracers in close quarters
  787. // float flMinLength = MIN( totalDist, 128.0f );
  788. // float flMaxLength = MIN( totalDist, 128.0f );
  789. float length = 128.0f;//random->RandomFloat( flMinLength, flMaxLength );
  790. float life = ( totalDist + length ) / velocity; // NOTENOTE: We want the tail to finish its run as well
  791. // Add it
  792. FX_AddDiscreetLine( start, shotDir, velocity*0.5f, length, totalDist, 2.0f, life, "effects/huntertracer" );
  793. if( makeWhiz )
  794. {
  795. FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
  796. }
  797. }
  798. //-----------------------------------------------------------------------------
  799. // Purpose:
  800. // Input : start -
  801. // end -
  802. // velocity -
  803. // makeWhiz -
  804. //-----------------------------------------------------------------------------
  805. void FX_GaussTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
  806. {
  807. VPROF_BUDGET( "FX_GaussTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  808. Vector vNear, dStart, dEnd, shotDir;
  809. float totalDist;
  810. //Get out shot direction and length
  811. VectorSubtract( end, start, shotDir );
  812. totalDist = VectorNormalize( shotDir );
  813. //Don't make small tracers
  814. if ( totalDist <= 256 )
  815. return;
  816. float length = random->RandomFloat( 250.0f, 500.0f );
  817. float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
  818. //Add it
  819. FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, random->RandomFloat( 5.0f, 8.0f ), life, "effects/spark" );
  820. }
  821. //-----------------------------------------------------------------------------
  822. // Purpose: Create a tesla effect between two points
  823. //-----------------------------------------------------------------------------
  824. void FX_BuildTesla(
  825. C_BaseEntity *pEntity,
  826. const Vector &vecOrigin,
  827. const Vector &vecEnd,
  828. const char *pModelName,
  829. float flBeamWidth,
  830. const Vector &vColor,
  831. int nFlags,
  832. float flTimeVisible )
  833. {
  834. BeamInfo_t beamInfo;
  835. beamInfo.m_nType = TE_BEAMTESLA;
  836. beamInfo.m_vecStart = vecOrigin;
  837. beamInfo.m_vecEnd = vecEnd;
  838. beamInfo.m_pszModelName = pModelName;
  839. beamInfo.m_flHaloScale = 0.0;
  840. beamInfo.m_flLife = flTimeVisible;
  841. beamInfo.m_flWidth = flBeamWidth;
  842. beamInfo.m_flEndWidth = 1;
  843. beamInfo.m_flFadeLength = 0.3;
  844. beamInfo.m_flAmplitude = 16;
  845. beamInfo.m_flBrightness = 200.0;
  846. beamInfo.m_flSpeed = 0.0;
  847. beamInfo.m_nStartFrame = 0.0;
  848. beamInfo.m_flFrameRate = 1.0;
  849. beamInfo.m_flRed = vColor.x * 255.0;
  850. beamInfo.m_flGreen = vColor.y * 255.0;
  851. beamInfo.m_flBlue = vColor.z * 255.0;
  852. beamInfo.m_nSegments = 20;
  853. beamInfo.m_bRenderable = true;
  854. beamInfo.m_nFlags = nFlags;
  855. beams->CreateBeamPoints( beamInfo );
  856. }
  857. void FX_Tesla( const CTeslaInfo &teslaInfo )
  858. {
  859. C_BaseEntity *pEntity = ClientEntityList().GetEnt( teslaInfo.m_nEntIndex );
  860. // Send out beams around us
  861. int iNumBeamsAround = (teslaInfo.m_nBeams * 2) / 3; // (2/3 of the beams are placed around in a circle)
  862. int iNumRandomBeams = teslaInfo.m_nBeams - iNumBeamsAround;
  863. int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
  864. float flYawOffset = RandomFloat(0,360);
  865. for ( int i = 0; i < iTotalBeams; i++ )
  866. {
  867. // Make a couple of tries at it
  868. int iTries = -1;
  869. Vector vecForward;
  870. trace_t tr;
  871. do
  872. {
  873. iTries++;
  874. // Some beams are deliberatly aimed around the point, the rest are random.
  875. if ( i < iNumBeamsAround )
  876. {
  877. QAngle vecTemp = teslaInfo.m_vAngles;
  878. vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
  879. AngleVectors( vecTemp, &vecForward );
  880. // Randomly angle it up or down
  881. vecForward.z = RandomFloat( -1, 1 );
  882. }
  883. else
  884. {
  885. vecForward = RandomVector( -1, 1 );
  886. }
  887. VectorNormalize( vecForward );
  888. UTIL_TraceLine( teslaInfo.m_vPos, teslaInfo.m_vPos + (vecForward * teslaInfo.m_flRadius), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
  889. } while ( tr.fraction >= 1.0 && iTries < 3 );
  890. Vector vecEnd = tr.endpos - (vecForward * 8);
  891. // Only spark & glow if we hit something
  892. if ( tr.fraction < 1.0 )
  893. {
  894. if ( !EffectOccluded( tr.endpos, 0 ) )
  895. {
  896. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  897. // Move it towards the camera
  898. Vector vecFlash = tr.endpos;
  899. Vector vecForward;
  900. AngleVectors( MainViewAngles(nSlot), &vecForward );
  901. vecFlash -= (vecForward * 8);
  902. g_pEffects->EnergySplash( vecFlash, -vecForward, false );
  903. // End glow
  904. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
  905. pSimple->SetSortOrigin( vecFlash );
  906. SimpleParticle *pParticle;
  907. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
  908. if ( pParticle != NULL )
  909. {
  910. pParticle->m_flLifetime = 0.0f;
  911. pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
  912. pParticle->m_vecVelocity = vec3_origin;
  913. Vector color( 1,1,1 );
  914. float colorRamp = RandomFloat( 0.75f, 1.25f );
  915. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  916. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  917. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  918. pParticle->m_uchStartSize = RandomFloat( 6,13 );
  919. pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
  920. pParticle->m_uchStartAlpha = 255;
  921. pParticle->m_uchEndAlpha = 10;
  922. pParticle->m_flRoll = RandomFloat( 0,360 );
  923. pParticle->m_flRollDelta = 0;
  924. }
  925. }
  926. }
  927. // Build the tesla
  928. FX_BuildTesla( pEntity, teslaInfo.m_vPos, tr.endpos, teslaInfo.m_pszSpriteName, teslaInfo.m_flBeamWidth, teslaInfo.m_vColor, FBEAM_ONLYNOISEONCE, teslaInfo.m_flTimeVisible );
  929. }
  930. }
  931. //-----------------------------------------------------------------------------
  932. // Purpose: Tesla effect
  933. //-----------------------------------------------------------------------------
  934. void BuildTeslaCallback( const CEffectData &data )
  935. {
  936. if ( data.entindex() < 0 )
  937. return;
  938. CTeslaInfo teslaInfo;
  939. teslaInfo.m_vPos = data.m_vOrigin;
  940. teslaInfo.m_vAngles = data.m_vAngles;
  941. teslaInfo.m_nEntIndex = data.entindex();
  942. teslaInfo.m_flBeamWidth = 5;
  943. teslaInfo.m_vColor.Init( 1, 1, 1 );
  944. teslaInfo.m_flTimeVisible = 0.3;
  945. teslaInfo.m_flRadius = 192;
  946. teslaInfo.m_nBeams = 6;
  947. teslaInfo.m_pszSpriteName = "sprites/physbeam.vmt";
  948. FX_Tesla( teslaInfo );
  949. }
  950. //-----------------------------------------------------------------------------
  951. // Purpose: Tesla hitbox
  952. //-----------------------------------------------------------------------------
  953. void FX_BuildTeslaHitbox(
  954. C_BaseEntity *pEntity,
  955. int nStartAttachment,
  956. int nEndAttachment,
  957. float flBeamWidth,
  958. const Vector &vColor,
  959. float flTimeVisible )
  960. {
  961. // One along the body
  962. BeamInfo_t beamInfo;
  963. beamInfo.m_nType = TE_BEAMTESLA;
  964. beamInfo.m_vecStart = vec3_origin;
  965. beamInfo.m_vecEnd = vec3_origin;
  966. beamInfo.m_pszModelName = "sprites/lgtning.vmt";
  967. beamInfo.m_flHaloScale = 8.0f;
  968. beamInfo.m_flLife = 0.01f;
  969. beamInfo.m_flWidth = random->RandomFloat( 3.0f, 6.0f );
  970. beamInfo.m_flEndWidth = 0.0f;
  971. beamInfo.m_flFadeLength = 0.0f;
  972. beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
  973. beamInfo.m_flBrightness = 255.0f;
  974. beamInfo.m_flSpeed = 32.0;
  975. beamInfo.m_nStartFrame = 0.0;
  976. beamInfo.m_flFrameRate = 30.0;
  977. beamInfo.m_flRed = vColor.x * 255.0;
  978. beamInfo.m_flGreen = vColor.y * 255.0;
  979. beamInfo.m_flBlue = vColor.z * 255.0;
  980. beamInfo.m_nSegments = 32;
  981. beamInfo.m_bRenderable = true;
  982. beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
  983. beamInfo.m_nFlags = (FBEAM_USE_HITBOXES);
  984. beamInfo.m_pStartEnt = pEntity;
  985. beamInfo.m_nStartAttachment = nStartAttachment;
  986. beamInfo.m_pEndEnt = pEntity;
  987. beamInfo.m_nEndAttachment = nEndAttachment;
  988. beams->CreateBeamEntPoint( beamInfo );
  989. // One out to the world
  990. trace_t tr;
  991. Vector randomDir;
  992. randomDir = RandomVector( -1.0f, 1.0f );
  993. VectorNormalize( randomDir );
  994. UTIL_TraceLine( pEntity->WorldSpaceCenter(), pEntity->WorldSpaceCenter() + ( randomDir * 100 ), MASK_SOLID_BRUSHONLY, pEntity, COLLISION_GROUP_NONE, &tr );
  995. if ( tr.fraction < 1.0f )
  996. {
  997. beamInfo.m_nType = TE_BEAMTESLA;
  998. beamInfo.m_vecStart = vec3_origin;
  999. beamInfo.m_vecEnd = tr.endpos;
  1000. beamInfo.m_pszModelName = "sprites/lgtning.vmt";
  1001. beamInfo.m_flHaloScale = 8.0f;
  1002. beamInfo.m_flLife = 0.05f;
  1003. beamInfo.m_flWidth = random->RandomFloat( 2.0f, 6.0f );
  1004. beamInfo.m_flEndWidth = 0.0f;
  1005. beamInfo.m_flFadeLength = 0.0f;
  1006. beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
  1007. beamInfo.m_flBrightness = 255.0f;
  1008. beamInfo.m_flSpeed = 32.0;
  1009. beamInfo.m_nStartFrame = 0.0;
  1010. beamInfo.m_flFrameRate = 30.0;
  1011. beamInfo.m_flRed = vColor.x * 255.0;
  1012. beamInfo.m_flGreen = vColor.y * 255.0;
  1013. beamInfo.m_flBlue = vColor.z * 255.0;
  1014. beamInfo.m_nSegments = 32;
  1015. beamInfo.m_bRenderable = true;
  1016. beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
  1017. beamInfo.m_pStartEnt = pEntity;
  1018. beamInfo.m_nStartAttachment = nStartAttachment;
  1019. beams->CreateBeamEntPoint( beamInfo );
  1020. }
  1021. // Create an elight to illuminate the target
  1022. if ( pEntity != NULL )
  1023. {
  1024. dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_TE_DYNAMIC + pEntity->entindex() );
  1025. // Randomly place it
  1026. el->origin = pEntity->WorldSpaceCenter() + RandomVector( -32, 32 );
  1027. el->color.r = 235;
  1028. el->color.g = 235;
  1029. el->color.b = 255;
  1030. el->color.exponent = 4;
  1031. el->radius = random->RandomInt( 32, 128 );
  1032. el->decay = el->radius / 0.1f;
  1033. el->die = gpGlobals->curtime + 0.1f;
  1034. }
  1035. }
  1036. //-----------------------------------------------------------------------------
  1037. // Purpose: Tesla effect
  1038. //-----------------------------------------------------------------------------
  1039. void FX_BuildTeslaHitbox( const CEffectData &data )
  1040. {
  1041. Vector vColor( 1, 1, 1 );
  1042. C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.entindex() );
  1043. C_BaseAnimating *pAnimating = pEntity ? pEntity->GetBaseAnimating() : NULL;
  1044. if (!pAnimating)
  1045. return;
  1046. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  1047. if (!pStudioHdr)
  1048. return;
  1049. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
  1050. if ( !set )
  1051. return;
  1052. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  1053. if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
  1054. return;
  1055. int nBeamCount = (int)(data.m_flMagnitude + 0.5f);
  1056. for ( int i = 0; i < nBeamCount; ++i )
  1057. {
  1058. int nStartHitBox = random->RandomInt( 1, set->numhitboxes );
  1059. int nEndHitBox = random->RandomInt( 1, set->numhitboxes );
  1060. FX_BuildTeslaHitbox( pEntity, nStartHitBox, nEndHitBox, data.m_flScale, vColor, random->RandomFloat( 0.05f, 0.2f ) );
  1061. }
  1062. }
  1063. DECLARE_CLIENT_EFFECT( TeslaHitboxes, FX_BuildTeslaHitbox );
  1064. //-----------------------------------------------------------------------------
  1065. // Purpose: Tesla effect
  1066. //-----------------------------------------------------------------------------
  1067. void FX_BuildTeslaZap( const CEffectData &data )
  1068. {
  1069. // Build the tesla, only works on entities
  1070. C_BaseEntity *pEntity = data.GetEntity();
  1071. if ( !pEntity )
  1072. return;
  1073. Vector vColor( 1, 1, 1 );
  1074. BeamInfo_t beamInfo;
  1075. beamInfo.m_nType = TE_BEAMTESLA;
  1076. beamInfo.m_pStartEnt = pEntity;
  1077. beamInfo.m_nStartAttachment = data.m_nAttachmentIndex;
  1078. beamInfo.m_pEndEnt = NULL;
  1079. beamInfo.m_vecEnd = data.m_vOrigin;
  1080. beamInfo.m_pszModelName = "sprites/physbeam.vmt";
  1081. beamInfo.m_flHaloScale = 0.0;
  1082. beamInfo.m_flLife = 0.3f;
  1083. beamInfo.m_flWidth = data.m_flScale;
  1084. beamInfo.m_flEndWidth = 1;
  1085. beamInfo.m_flFadeLength = 0.3;
  1086. beamInfo.m_flAmplitude = 16;
  1087. beamInfo.m_flBrightness = 200.0;
  1088. beamInfo.m_flSpeed = 0.0;
  1089. beamInfo.m_nStartFrame = 0.0;
  1090. beamInfo.m_flFrameRate = 1.0;
  1091. beamInfo.m_flRed = vColor.x * 255.0;
  1092. beamInfo.m_flGreen = vColor.y * 255.0;
  1093. beamInfo.m_flBlue = vColor.z * 255.0;
  1094. beamInfo.m_nSegments = 20;
  1095. beamInfo.m_bRenderable = true;
  1096. beamInfo.m_nFlags = 0;
  1097. beams->CreateBeamEntPoint( beamInfo );
  1098. }
  1099. DECLARE_CLIENT_EFFECT( TeslaZap, FX_BuildTeslaZap );