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.

788 lines
23 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "iviewrender.h"
  9. #include "view.h"
  10. #include "studio.h"
  11. #include "bone_setup.h"
  12. #include "model_types.h"
  13. #include "beamdraw.h"
  14. #include "engine/ivdebugoverlay.h"
  15. #include "iviewrender_beams.h"
  16. #include "fx.h"
  17. #include "IEffects.h"
  18. #include "c_entitydissolve.h"
  19. #include "movevars_shared.h"
  20. #include "precache_register.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. ConVar cl_portal_use_new_dissolve( "cl_portal_use_new_dissolve", "1", FCVAR_CHEAT, "Use new dissolve effect" );
  24. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectBuild )
  25. PRECACHE( MATERIAL,"effects/tesla_glow_noz" )
  26. PRECACHE( MATERIAL,"effects/spark" )
  27. PRECACHE( MATERIAL,"effects/combinemuzzle2" )
  28. PRECACHE( PARTICLE_SYSTEM, "dissolve" )
  29. PRECACHE_REGISTER_END()
  30. //-----------------------------------------------------------------------------
  31. // Networking
  32. //-----------------------------------------------------------------------------
  33. IMPLEMENT_CLIENTCLASS_DT( C_EntityDissolve, DT_EntityDissolve, CEntityDissolve )
  34. RecvPropTime(RECVINFO(m_flStartTime)),
  35. RecvPropFloat(RECVINFO(m_flFadeOutStart)),
  36. RecvPropFloat(RECVINFO(m_flFadeOutLength)),
  37. RecvPropFloat(RECVINFO(m_flFadeOutModelStart)),
  38. RecvPropFloat(RECVINFO(m_flFadeOutModelLength)),
  39. RecvPropFloat(RECVINFO(m_flFadeInStart)),
  40. RecvPropFloat(RECVINFO(m_flFadeInLength)),
  41. RecvPropInt(RECVINFO(m_nDissolveType)),
  42. RecvPropVector( RECVINFO( m_vDissolverOrigin) ),
  43. RecvPropInt( RECVINFO( m_nMagnitude ) ),
  44. END_RECV_TABLE()
  45. extern PMaterialHandle g_Material_Spark;
  46. PMaterialHandle g_Material_AR2Glow = NULL;
  47. //-----------------------------------------------------------------------------
  48. // Purpose:
  49. //-----------------------------------------------------------------------------
  50. CEG_NOINLINE C_EntityDissolve::C_EntityDissolve( void )
  51. {
  52. m_bLinkedToServerEnt = true;
  53. CEG_PROTECT_MEMBER_FUNCTION( C_EntityDissolve_C_EntityDissolve );
  54. m_pController = NULL;
  55. m_bCoreExplode = false;
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Purpose:
  59. //-----------------------------------------------------------------------------
  60. void C_EntityDissolve::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  61. {
  62. if ( GetMoveParent() )
  63. {
  64. GetMoveParent()->GetRenderBounds( theMins, theMaxs );
  65. }
  66. else
  67. {
  68. theMins = GetAbsOrigin();
  69. theMaxs = theMaxs;
  70. }
  71. }
  72. //-----------------------------------------------------------------------------
  73. // On data changed
  74. //-----------------------------------------------------------------------------
  75. void C_EntityDissolve::OnDataChanged( DataUpdateType_t updateType )
  76. {
  77. BaseClass::OnDataChanged( updateType );
  78. if ( updateType == DATA_UPDATE_CREATED )
  79. {
  80. m_flNextSparkTime = m_flStartTime;
  81. SetNextClientThink( CLIENT_THINK_ALWAYS );
  82. if ( cl_portal_use_new_dissolve.GetBool() )
  83. DispatchParticleEffect( "dissolve", PATTACH_ABSORIGIN_FOLLOW, GetMoveParent() );
  84. }
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Cleanup
  88. //-----------------------------------------------------------------------------
  89. void C_EntityDissolve::UpdateOnRemove( void )
  90. {
  91. if ( m_pController )
  92. {
  93. physenv->DestroyMotionController( m_pController );
  94. m_pController = NULL;
  95. }
  96. BaseClass::UpdateOnRemove();
  97. }
  98. //------------------------------------------------------------------------------
  99. // Apply the forces to the entity
  100. //------------------------------------------------------------------------------
  101. IMotionEvent::simresult_e C_EntityDissolve::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
  102. {
  103. linear.Init();
  104. angular.Init();
  105. // Make it zero g
  106. linear.z -= -1.02 * sv_gravity.GetFloat();
  107. Vector vel;
  108. AngularImpulse angVel;
  109. pObject->GetVelocity( &vel, &angVel );
  110. vel += linear * deltaTime; // account for gravity scale
  111. Vector unitVel = vel;
  112. Vector unitAngVel = angVel;
  113. float speed = VectorNormalize( unitVel );
  114. // float angSpeed = VectorNormalize( unitAngVel );
  115. // float speedScale = 0.0;
  116. // float angSpeedScale = 0.0;
  117. float flLinearLimit = 50;
  118. float flLinearLimitDelta = 40;
  119. if ( speed > flLinearLimit )
  120. {
  121. float flDeltaVel = (flLinearLimit - speed) / deltaTime;
  122. if ( flLinearLimitDelta != 0.0f )
  123. {
  124. float flMaxDeltaVel = -flLinearLimitDelta / deltaTime;
  125. if ( flDeltaVel < flMaxDeltaVel )
  126. {
  127. flDeltaVel = flMaxDeltaVel;
  128. }
  129. }
  130. VectorMA( linear, flDeltaVel, unitVel, linear );
  131. }
  132. return SIM_GLOBAL_ACCELERATION;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Tesla effect
  136. //-----------------------------------------------------------------------------
  137. static void FX_BuildTesla( C_BaseEntity *pEntity, Vector &vecOrigin, Vector &vecEnd )
  138. {
  139. BeamInfo_t beamInfo;
  140. beamInfo.m_pStartEnt = pEntity;
  141. beamInfo.m_nStartAttachment = 0;
  142. beamInfo.m_pEndEnt = NULL;
  143. beamInfo.m_nEndAttachment = 0;
  144. beamInfo.m_nType = TE_BEAMTESLA;
  145. beamInfo.m_vecStart = vecOrigin;
  146. beamInfo.m_vecEnd = vecEnd;
  147. beamInfo.m_pszModelName = "sprites/lgtning.vmt";
  148. beamInfo.m_flHaloScale = 0.0;
  149. beamInfo.m_flLife = random->RandomFloat( 0.25f, 1.0f );
  150. beamInfo.m_flWidth = random->RandomFloat( 8.0f, 14.0f );
  151. beamInfo.m_flEndWidth = 1.0f;
  152. beamInfo.m_flFadeLength = 0.5f;
  153. beamInfo.m_flAmplitude = 24;
  154. beamInfo.m_flBrightness = 255.0;
  155. beamInfo.m_flSpeed = 150.0f;
  156. beamInfo.m_nStartFrame = 0.0;
  157. beamInfo.m_flFrameRate = 30.0;
  158. beamInfo.m_flRed = 255.0;
  159. beamInfo.m_flGreen = 255.0;
  160. beamInfo.m_flBlue = 255.0;
  161. beamInfo.m_nSegments = 18;
  162. beamInfo.m_bRenderable = true;
  163. beamInfo.m_nFlags = 0; //FBEAM_ONLYNOISEONCE;
  164. beams->CreateBeamEntPoint( beamInfo );
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Purpose: Tesla effect
  168. //-----------------------------------------------------------------------------
  169. void C_EntityDissolve::BuildTeslaEffect( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld, bool bRandom, float flYawOffset )
  170. {
  171. Vector vecOrigin;
  172. QAngle vecAngles;
  173. MatrixGetColumn( hitboxToWorld, 3, vecOrigin );
  174. MatrixAngles( hitboxToWorld, vecAngles.Base() );
  175. C_BaseEntity *pEntity = GetMoveParent();
  176. // Make a couple of tries at it
  177. int iTries = -1;
  178. Vector vecForward;
  179. trace_t tr;
  180. do
  181. {
  182. iTries++;
  183. // Some beams are deliberatly aimed around the point, the rest are random.
  184. if ( !bRandom )
  185. {
  186. QAngle vecTemp = vecAngles;
  187. vecTemp[YAW] += flYawOffset;
  188. AngleVectors( vecTemp, &vecForward );
  189. // Randomly angle it up or down
  190. vecForward.z = RandomFloat( -1, 1 );
  191. }
  192. else
  193. {
  194. vecForward = RandomVector( -1, 1 );
  195. }
  196. UTIL_TraceLine( vecOrigin, vecOrigin + (vecForward * 192), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
  197. } while ( tr.fraction >= 1.0 && iTries < 3 );
  198. Vector vecEnd = tr.endpos - (vecForward * 8);
  199. // Only spark & glow if we hit something
  200. if ( tr.fraction < 1.0 )
  201. {
  202. if ( !EffectOccluded( tr.endpos ) )
  203. {
  204. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  205. // Move it towards the camera
  206. Vector vecFlash = tr.endpos;
  207. Vector vecForward;
  208. AngleVectors( MainViewAngles(nSlot), &vecForward );
  209. vecFlash -= (vecForward * 8);
  210. g_pEffects->EnergySplash( vecFlash, -vecForward, false );
  211. // End glow
  212. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
  213. pSimple->SetSortOrigin( vecFlash );
  214. SimpleParticle *pParticle;
  215. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
  216. if ( pParticle != NULL )
  217. {
  218. pParticle->m_flLifetime = 0.0f;
  219. pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
  220. pParticle->m_vecVelocity = vec3_origin;
  221. Vector color( 1,1,1 );
  222. float colorRamp = RandomFloat( 0.75f, 1.25f );
  223. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  224. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  225. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  226. pParticle->m_uchStartSize = RandomFloat( 6,13 );
  227. pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
  228. pParticle->m_uchStartAlpha = 255;
  229. pParticle->m_uchEndAlpha = 10;
  230. pParticle->m_flRoll = RandomFloat( 0,360 );
  231. pParticle->m_flRollDelta = 0;
  232. }
  233. }
  234. }
  235. // Build the tesla
  236. FX_BuildTesla( pEntity, vecOrigin, tr.endpos );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Sorts the components of a vector
  240. //-----------------------------------------------------------------------------
  241. static inline void SortAbsVectorComponents( const Vector& src, int* pVecIdx )
  242. {
  243. Vector absVec( fabs(src[0]), fabs(src[1]), fabs(src[2]) );
  244. int maxIdx = (absVec[0] > absVec[1]) ? 0 : 1;
  245. if (absVec[2] > absVec[maxIdx])
  246. {
  247. maxIdx = 2;
  248. }
  249. // always choose something right-handed....
  250. switch( maxIdx )
  251. {
  252. case 0:
  253. pVecIdx[0] = 1;
  254. pVecIdx[1] = 2;
  255. pVecIdx[2] = 0;
  256. break;
  257. case 1:
  258. pVecIdx[0] = 2;
  259. pVecIdx[1] = 0;
  260. pVecIdx[2] = 1;
  261. break;
  262. case 2:
  263. pVecIdx[0] = 0;
  264. pVecIdx[1] = 1;
  265. pVecIdx[2] = 2;
  266. break;
  267. }
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Compute the bounding box's center, size, and basis
  271. //-----------------------------------------------------------------------------
  272. void C_EntityDissolve::ComputeRenderInfo( mstudiobbox_t *pHitBox, const matrix3x4_t &hitboxToWorld,
  273. Vector *pVecAbsOrigin, Vector *pXVec, Vector *pYVec )
  274. {
  275. // Compute the center of the hitbox in worldspace
  276. Vector vecHitboxCenter;
  277. VectorAdd( pHitBox->bbmin, pHitBox->bbmax, vecHitboxCenter );
  278. vecHitboxCenter *= 0.5f;
  279. VectorTransform( vecHitboxCenter, hitboxToWorld, *pVecAbsOrigin );
  280. // Get the object's basis
  281. Vector vec[3];
  282. MatrixGetColumn( hitboxToWorld, 0, vec[0] );
  283. MatrixGetColumn( hitboxToWorld, 1, vec[1] );
  284. MatrixGetColumn( hitboxToWorld, 2, vec[2] );
  285. // vec[1] *= -1.0f;
  286. Vector vecViewDir;
  287. VectorSubtract( CurrentViewOrigin(), *pVecAbsOrigin, vecViewDir );
  288. VectorNormalize( vecViewDir );
  289. // Project the shadow casting direction into the space of the hitbox
  290. Vector localViewDir;
  291. localViewDir[0] = DotProduct( vec[0], vecViewDir );
  292. localViewDir[1] = DotProduct( vec[1], vecViewDir );
  293. localViewDir[2] = DotProduct( vec[2], vecViewDir );
  294. // Figure out which vector has the largest component perpendicular
  295. // to the view direction...
  296. // Sort by how perpendicular it is
  297. int vecIdx[3];
  298. SortAbsVectorComponents( localViewDir, vecIdx );
  299. // Here's our hitbox basis vectors; namely the ones that are
  300. // most perpendicular to the view direction
  301. *pXVec = vec[vecIdx[0]];
  302. *pYVec = vec[vecIdx[1]];
  303. // Project them into a plane perpendicular to the view direction
  304. *pXVec -= vecViewDir * DotProduct( vecViewDir, *pXVec );
  305. *pYVec -= vecViewDir * DotProduct( vecViewDir, *pYVec );
  306. VectorNormalize( *pXVec );
  307. VectorNormalize( *pYVec );
  308. // Compute the hitbox size
  309. Vector boxSize;
  310. VectorSubtract( pHitBox->bbmax, pHitBox->bbmin, boxSize );
  311. // We project the two longest sides into the vectors perpendicular
  312. // to the projection direction, then add in the projection of the perp direction
  313. Vector2D size( boxSize[vecIdx[0]], boxSize[vecIdx[1]] );
  314. size.x *= fabs( DotProduct( vec[vecIdx[0]], *pXVec ) );
  315. size.y *= fabs( DotProduct( vec[vecIdx[1]], *pYVec ) );
  316. // Add the third component into x and y
  317. size.x += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pXVec ) );
  318. size.y += boxSize[vecIdx[2]] * fabs( DotProduct( vec[vecIdx[2]], *pYVec ) );
  319. // Bloat a bit, since the shadow wants to extend outside the model a bit
  320. size *= 2.0f;
  321. // Clamp the minimum size
  322. Vector2DMax( size, Vector2D(10.0f, 10.0f), size );
  323. // Factor the size into the xvec + yvec
  324. (*pXVec) *= size.x * 0.5f;
  325. (*pYVec) *= size.y * 0.5f;
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Sparks!
  329. //-----------------------------------------------------------------------------
  330. void C_EntityDissolve::DoSparks( mstudiohitboxset_t *set, matrix3x4_t *hitboxbones[MAXSTUDIOBONES] )
  331. {
  332. if ( m_flNextSparkTime > gpGlobals->curtime )
  333. return;
  334. float dt = m_flStartTime + m_flFadeOutStart - gpGlobals->curtime;
  335. dt = clamp( dt, 0.0f, m_flFadeOutStart );
  336. float flNextTime;
  337. if (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL)
  338. {
  339. flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 2.0f * TICK_INTERVAL, 0.4f );
  340. }
  341. else
  342. {
  343. // m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT);
  344. flNextTime = SimpleSplineRemapVal( dt, 0.0f, m_flFadeOutStart, 0.3f, 1.0f );
  345. }
  346. m_flNextSparkTime = gpGlobals->curtime + flNextTime;
  347. // Send out beams around us
  348. int iNumBeamsAround = 2;
  349. int iNumRandomBeams = 1;
  350. int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
  351. float flYawOffset = RandomFloat(0,360);
  352. for ( int i = 0; i < iTotalBeams; i++ )
  353. {
  354. int nHitbox = random->RandomInt( 0, set->numhitboxes - 1 );
  355. mstudiobbox_t *pBox = set->pHitbox(nHitbox);
  356. float flActualYawOffset = 0;
  357. bool bRandom = ( i >= iNumBeamsAround );
  358. if ( !bRandom )
  359. {
  360. flActualYawOffset = anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
  361. }
  362. BuildTeslaEffect( pBox, *hitboxbones[pBox->bone], bRandom, flActualYawOffset );
  363. }
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Purpose:
  367. //-----------------------------------------------------------------------------
  368. void C_EntityDissolve::SetupEmitter( void )
  369. {
  370. if ( !m_pEmitter )
  371. {
  372. m_pEmitter = CSimpleEmitter::Create( "C_EntityDissolve" );
  373. m_pEmitter->SetSortOrigin( GetAbsOrigin() );
  374. }
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. // Output : float
  379. //-----------------------------------------------------------------------------
  380. float C_EntityDissolve::GetFadeInPercentage( void )
  381. {
  382. float dt = gpGlobals->curtime - m_flStartTime;
  383. if ( dt > m_flFadeOutStart )
  384. return 1.0f;
  385. if ( dt < m_flFadeInStart )
  386. return 0.0f;
  387. if ( (dt > m_flFadeInStart) && (dt < m_flFadeInStart + m_flFadeInLength) )
  388. {
  389. dt -= m_flFadeInStart;
  390. return ( dt / m_flFadeInLength );
  391. }
  392. return 1.0f;
  393. }
  394. //-----------------------------------------------------------------------------
  395. // Purpose:
  396. // Output : float
  397. //-----------------------------------------------------------------------------
  398. float C_EntityDissolve::GetFadeOutPercentage( void )
  399. {
  400. float dt = gpGlobals->curtime - m_flStartTime;
  401. if ( dt < m_flFadeInStart )
  402. return 1.0f;
  403. if ( dt > m_flFadeOutStart )
  404. {
  405. dt -= m_flFadeOutStart;
  406. RANDOM_CEG_TEST_SECRET();
  407. if ( dt > m_flFadeOutLength )
  408. return 0.0f;
  409. return 1.0f - ( dt / m_flFadeOutLength );
  410. }
  411. return 1.0f;
  412. }
  413. //-----------------------------------------------------------------------------
  414. // Purpose:
  415. // Output : float
  416. //-----------------------------------------------------------------------------
  417. float C_EntityDissolve::GetModelFadeOutPercentage( void )
  418. {
  419. float dt = gpGlobals->curtime - m_flStartTime;
  420. if ( dt < m_flFadeOutModelStart )
  421. return 1.0f;
  422. if ( dt > m_flFadeOutModelStart )
  423. {
  424. dt -= m_flFadeOutModelStart;
  425. if ( dt > m_flFadeOutModelLength )
  426. return 0.0f;
  427. return 1.0f - ( dt / m_flFadeOutModelLength );
  428. }
  429. return 1.0f;
  430. }
  431. //-----------------------------------------------------------------------------
  432. // Purpose:
  433. //-----------------------------------------------------------------------------
  434. void C_EntityDissolve::ClientThink( void )
  435. {
  436. C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL;
  437. if (!pAnimating)
  438. return;
  439. // NOTE: IsRagdoll means *client-side* ragdoll. We shouldn't be trying to fight
  440. // the server ragdoll (or any server physics) on the client
  441. if (( !m_pController ) && ( m_nDissolveType == ENTITY_DISSOLVE_NORMAL ) && pAnimating->IsRagdoll())
  442. {
  443. IPhysicsObject *ppList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
  444. int nCount = pAnimating->VPhysicsGetObjectList( ppList, ARRAYSIZE(ppList) );
  445. if ( nCount > 0 )
  446. {
  447. m_pController = physenv->CreateMotionController( this );
  448. for ( int i = 0; i < nCount; ++i )
  449. {
  450. m_pController->AttachObject( ppList[i], true );
  451. }
  452. }
  453. }
  454. color32 color;
  455. color.r = color.g = color.b = ( 1.0f - GetFadeInPercentage() ) * 255.0f;
  456. color.a = GetModelFadeOutPercentage() * 255.0f;
  457. // Setup the entity fade
  458. pAnimating->SetRenderMode( kRenderTransColor );
  459. pAnimating->SetRenderColor( color.r, color.g, color.b );
  460. pAnimating->SetRenderAlpha( color.a );
  461. if ( GetModelFadeOutPercentage() <= 0.2f )
  462. {
  463. m_bCoreExplode = true;
  464. }
  465. // If we're dead, fade out
  466. if ( GetFadeOutPercentage() <= 0.0f )
  467. {
  468. // Do NOT remove from the client entity list. It'll confuse the local network backdoor, and the entity will never get destroyed
  469. // because when the server says to destroy it, the client won't be able to find it.
  470. // ClientEntityList().RemoveEntity( GetClientHandle() );
  471. ::partition->Remove( PARTITION_CLIENT_SOLID_EDICTS | PARTITION_CLIENT_RESPONSIVE_EDICTS | PARTITION_CLIENT_NON_STATIC_EDICTS, CollisionProp()->GetPartitionHandle() );
  472. RemoveFromLeafSystem();
  473. //FIXME: Ick!
  474. //Adrian: I'll assume we don't need the ragdoll either so I'll remove that too.
  475. if ( m_bLinkedToServerEnt == false )
  476. {
  477. Release();
  478. C_ClientRagdoll *pRagdoll = dynamic_cast <C_ClientRagdoll *> ( pAnimating );
  479. if ( pRagdoll )
  480. {
  481. pRagdoll->ReleaseRagdoll();
  482. }
  483. }
  484. }
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose:
  488. // Input : flags -
  489. // Output : int
  490. //-----------------------------------------------------------------------------
  491. int C_EntityDissolve::DrawModel( int flags, const RenderableInstance_t &instance )
  492. {
  493. if ( !cl_portal_use_new_dissolve.GetBool() )
  494. {
  495. // See if we should draw
  496. if ( gpGlobals->frametime == 0 || m_bReadyToDraw == false )
  497. return 0;
  498. C_BaseAnimating *pAnimating = GetMoveParent() ? GetMoveParent()->GetBaseAnimating() : NULL;
  499. if ( pAnimating == NULL )
  500. return 0;
  501. matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
  502. if ( pAnimating->HitboxToWorldTransforms( hitboxbones ) == false )
  503. return 0;
  504. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
  505. if ( pStudioHdr == NULL )
  506. return false;
  507. mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
  508. if ( set == NULL )
  509. return false;
  510. // Make sure the emitter is setup properly
  511. SetupEmitter();
  512. // Get fade percentages for the effect
  513. float fadeInPerc = GetFadeInPercentage();
  514. float fadeOutPerc = GetFadeOutPercentage();
  515. float fadePerc = ( fadeInPerc >= 1.0f ) ? fadeOutPerc : fadeInPerc;
  516. Vector vecSkew = vec3_origin;
  517. // Do extra effects under certain circumstances
  518. if ( ( fadePerc < 0.99f ) && ( (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL) || (m_nDissolveType == ENTITY_DISSOLVE_ELECTRICAL_LIGHT) ) )
  519. {
  520. DoSparks( set, hitboxbones );
  521. }
  522. // Skew the particles in front or in back of their targets
  523. vecSkew = CurrentViewForward() * ( 8.0f - ( ( 1.0f - fadePerc ) * 32.0f ) );
  524. float spriteScale = ( ( gpGlobals->curtime - m_flStartTime ) / m_flFadeOutLength );
  525. spriteScale = clamp( spriteScale, 0.75f, 1.0f );
  526. // Cache off this material reference
  527. if ( g_Material_Spark == NULL )
  528. {
  529. g_Material_Spark = ParticleMgr()->GetPMaterial( "effects/spark" );
  530. }
  531. if ( g_Material_AR2Glow == NULL )
  532. {
  533. g_Material_AR2Glow = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" );
  534. }
  535. SimpleParticle *sParticle;
  536. for ( int i = 0; i < set->numhitboxes; ++i )
  537. {
  538. Vector vecAbsOrigin, xvec, yvec;
  539. mstudiobbox_t *pBox = set->pHitbox(i);
  540. ComputeRenderInfo( pBox, *hitboxbones[pBox->bone], &vecAbsOrigin, &xvec, &yvec );
  541. Vector offset;
  542. Vector xDir, yDir;
  543. xDir = xvec;
  544. float xScale = VectorNormalize( xDir ) * 0.75f;
  545. yDir = yvec;
  546. float yScale = VectorNormalize( yDir ) * 0.75f;
  547. int numParticles = clamp( 3.0f * fadePerc, 0, 3 );
  548. int iTempParts = 2;
  549. if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
  550. {
  551. if ( m_bCoreExplode == true )
  552. {
  553. numParticles = 15;
  554. iTempParts = 20;
  555. }
  556. }
  557. for ( int j = 0; j < iTempParts; j++ )
  558. {
  559. // Skew the origin
  560. offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
  561. offset += vecSkew;
  562. if ( random->RandomInt( 0, 2 ) != 0 )
  563. continue;
  564. sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_Spark, vecAbsOrigin + offset );
  565. if ( sParticle == NULL )
  566. return 1;
  567. sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( 16.0f, 64.0f ) );
  568. if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
  569. {
  570. if ( m_bCoreExplode == true )
  571. {
  572. Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin;
  573. VectorNormalize( vDirection );
  574. sParticle->m_vecVelocity = vDirection * m_nMagnitude;
  575. }
  576. }
  577. if ( sParticle->m_vecVelocity.z > 0 )
  578. {
  579. sParticle->m_uchStartSize = random->RandomFloat( 4, 6 ) * spriteScale;
  580. }
  581. else
  582. {
  583. sParticle->m_uchStartSize = 2 * spriteScale;
  584. }
  585. sParticle->m_flDieTime = random->RandomFloat( 0.4f, 0.5f );
  586. // If we're the last particles, last longer
  587. if ( numParticles == 0 )
  588. {
  589. sParticle->m_flDieTime *= 2.0f;
  590. sParticle->m_uchStartSize = 2 * spriteScale;
  591. sParticle->m_flRollDelta = Helper_RandomFloat( -4.0f, 4.0f );
  592. if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
  593. {
  594. if ( m_bCoreExplode == true )
  595. {
  596. sParticle->m_flDieTime *= 2.0f;
  597. sParticle->m_flRollDelta = Helper_RandomFloat( -1.0f, 1.0f );
  598. }
  599. }
  600. }
  601. else
  602. {
  603. sParticle->m_flRollDelta = Helper_RandomFloat( -8.0f, 8.0f );
  604. }
  605. sParticle->m_flLifetime = 0.0f;
  606. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  607. float alpha = 255;
  608. sParticle->m_uchColor[0] = alpha;
  609. sParticle->m_uchColor[1] = alpha;
  610. sParticle->m_uchColor[2] = alpha;
  611. sParticle->m_uchStartAlpha = alpha;
  612. sParticle->m_uchEndAlpha = 0;
  613. sParticle->m_uchEndSize = 0;
  614. }
  615. for ( int j = 0; j < numParticles; j++ )
  616. {
  617. offset = xDir * Helper_RandomFloat( -xScale*0.5f, xScale*0.5f ) + yDir * Helper_RandomFloat( -yScale*0.5f, yScale*0.5f );
  618. offset += vecSkew;
  619. sParticle = (SimpleParticle *) m_pEmitter->AddParticle( sizeof(SimpleParticle), g_Material_AR2Glow, vecAbsOrigin + offset );
  620. if ( sParticle == NULL )
  621. return 1;
  622. sParticle->m_vecVelocity = Vector( Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -4.0f, 4.0f ), Helper_RandomFloat( -64.0f, 128.0f ) );
  623. sParticle->m_uchStartSize = random->RandomFloat( 8, 12 ) * spriteScale;
  624. sParticle->m_flDieTime = 0.1f;
  625. sParticle->m_flLifetime = 0.0f;
  626. sParticle->m_flRoll = Helper_RandomInt( 0, 360 );
  627. sParticle->m_flRollDelta = Helper_RandomFloat( -2.0f, 2.0f );
  628. float alpha = 255;
  629. sParticle->m_uchColor[0] = alpha;
  630. sParticle->m_uchColor[1] = alpha;
  631. sParticle->m_uchColor[2] = alpha;
  632. sParticle->m_uchStartAlpha = alpha;
  633. sParticle->m_uchEndAlpha = 0;
  634. sParticle->m_uchEndSize = 0;
  635. if ( m_nDissolveType == ENTITY_DISSOLVE_CORE )
  636. {
  637. if ( m_bCoreExplode == true )
  638. {
  639. Vector vDirection = (vecAbsOrigin + offset) - m_vDissolverOrigin;
  640. VectorNormalize( vDirection );
  641. sParticle->m_vecVelocity = vDirection * m_nMagnitude;
  642. sParticle->m_flDieTime = 0.5f;
  643. }
  644. }
  645. }
  646. }
  647. }
  648. return 1;
  649. }