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.

3199 lines
85 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 "model_types.h"
  10. #include "view_shared.h"
  11. #include "iviewrender.h"
  12. #include "tempentity.h"
  13. #include "dlight.h"
  14. #include "tempent.h"
  15. #include "c_te_legacytempents.h"
  16. #include "clientsideeffects.h"
  17. #include "cl_animevent.h"
  18. #include "iefx.h"
  19. #include "engine/IEngineSound.h"
  20. #include "env_wind_shared.h"
  21. #include "precache_register.h"
  22. #include "fx_sparks.h"
  23. #include "fx.h"
  24. #include "movevars_shared.h"
  25. #include "engine/ivmodelinfo.h"
  26. #include "SoundEmitterSystem/isoundemittersystembase.h"
  27. #include "view.h"
  28. #include "tier0/vprof.h"
  29. #include "particles_localspace.h"
  30. #include "physpropclientside.h"
  31. #include "tier0/icommandline.h"
  32. #include "datacache/imdlcache.h"
  33. #include "engine/ivdebugoverlay.h"
  34. #include "effect_dispatch_data.h"
  35. #include "c_te_effect_dispatch.h"
  36. // NOTE: Always include this last!
  37. #include "tier0/memdbgon.h"
  38. extern ConVar muzzleflash_light;
  39. #define TENT_WIND_ACCEL 50
  40. color24 white24 = {255, 255, 255};
  41. //Precache the effects
  42. #if !defined(TF_CLIENT_DLL) && !defined(DOTA_CLIENT_DLL)
  43. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectMuzzleFlash )
  44. #if !defined( CSTRIKE_DLL )
  45. PRECACHE( MATERIAL, "effects/combinemuzzle1" )
  46. PRECACHE( MATERIAL, "effects/combinemuzzle2" )
  47. PRECACHE( MATERIAL, "effects/combinemuzzle1_noz" )
  48. PRECACHE( MATERIAL, "effects/combinemuzzle2_noz" )
  49. #endif
  50. PRECACHE( MATERIAL, "effects/muzzleflash1" )
  51. PRECACHE( MATERIAL, "effects/muzzleflash2" )
  52. PRECACHE( MATERIAL, "effects/muzzleflash3" )
  53. PRECACHE( MATERIAL, "effects/muzzleflash4" )
  54. PRECACHE( MATERIAL, "effects/muzzleflash1_noz" )
  55. PRECACHE( MATERIAL, "effects/muzzleflash2_noz" )
  56. PRECACHE( MATERIAL, "effects/muzzleflash3_noz" )
  57. PRECACHE( MATERIAL, "effects/muzzleflash4_noz" )
  58. #if !defined( CSTRIKE_DLL )
  59. PRECACHE( MATERIAL, "effects/strider_muzzle" )
  60. #endif
  61. PRECACHE_REGISTER_END()
  62. #endif
  63. ConVar func_break_max_pieces( "func_break_max_pieces", "15", FCVAR_ARCHIVE | FCVAR_REPLICATED );
  64. ConVar cl_fasttempentcollision( "cl_fasttempentcollision", "5" );
  65. // Temp entity interface
  66. static CTempEnts g_TempEnts;
  67. // Expose to rest of the client .dll
  68. ITempEnts *tempents = ( ITempEnts * )&g_TempEnts;
  69. C_LocalTempEntity::C_LocalTempEntity()
  70. {
  71. #ifdef _DEBUG
  72. tentOffset.Init();
  73. m_vecTempEntVelocity.Init();
  74. m_vecTempEntAngVelocity.Init();
  75. m_vecNormal.Init();
  76. #endif
  77. m_vecTempEntAcceleration.Init();
  78. m_pfnDrawHelper = 0;
  79. m_pszImpactEffect = NULL;
  80. }
  81. #if defined( CSTRIKE_DLL ) || defined (SDK_DLL )
  82. #define TE_RIFLE_SHELL 1024
  83. #define TE_PISTOL_SHELL 2048
  84. #define TE_SHOTGUN_SHELL 4096
  85. #endif
  86. //-----------------------------------------------------------------------------
  87. // Purpose: Prepare a temp entity for creation
  88. // Input : time -
  89. // *model -
  90. //-----------------------------------------------------------------------------
  91. void C_LocalTempEntity::Prepare( model_t *pmodel, float time )
  92. {
  93. Interp_SetupMappings( GetVarMapping() );
  94. index = -1;
  95. Clear();
  96. // Use these to set per-frame and termination conditions / actions
  97. flags = FTENT_NONE;
  98. die = time + 0.75;
  99. SetModelPointer( pmodel );
  100. SetRenderMode( kRenderNormal );
  101. SetRenderFX( kRenderFxNone );
  102. SetBody( 0 );
  103. SetSkin( 0 );
  104. fadeSpeed = 0.5;
  105. hitSound = 0;
  106. clientIndex = -1;
  107. bounceFactor = 1;
  108. m_nFlickerFrame = 0;
  109. m_bParticleCollision = false;
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Sets the velocity
  113. //-----------------------------------------------------------------------------
  114. void C_LocalTempEntity::SetVelocity( const Vector &vecVelocity )
  115. {
  116. m_vecTempEntVelocity = vecVelocity;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Sets the velocity
  120. //-----------------------------------------------------------------------------
  121. void C_LocalTempEntity::SetAcceleration( const Vector &vecVelocity )
  122. {
  123. m_vecTempEntAcceleration = vecVelocity;
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. // Output : int
  128. //-----------------------------------------------------------------------------
  129. int C_LocalTempEntity::DrawStudioModel( int flags )
  130. {
  131. VPROF_BUDGET( "C_LocalTempEntity::DrawStudioModel", VPROF_BUDGETGROUP_MODEL_RENDERING );
  132. int drawn = 0;
  133. if ( !GetModel() || modelinfo->GetModelType( GetModel() ) != mod_studio )
  134. return drawn;
  135. // Make sure m_pstudiohdr is valid for drawing
  136. MDLCACHE_CRITICAL_SECTION();
  137. if ( !GetModelPtr() )
  138. return drawn;
  139. if ( m_pfnDrawHelper )
  140. {
  141. drawn = ( *m_pfnDrawHelper )( this, flags );
  142. }
  143. else
  144. {
  145. drawn = modelrender->DrawModel(
  146. flags,
  147. this,
  148. MODEL_INSTANCE_INVALID,
  149. index,
  150. GetModel(),
  151. GetAbsOrigin(),
  152. GetAbsAngles(),
  153. GetSkin(),
  154. GetBody(),
  155. m_nHitboxSet );
  156. }
  157. return drawn;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose:
  161. // Input : flags -
  162. //-----------------------------------------------------------------------------
  163. int C_LocalTempEntity::DrawModel( int flags, const RenderableInstance_t &instance )
  164. {
  165. int drawn = 0;
  166. if ( !GetModel() )
  167. {
  168. return drawn;
  169. }
  170. if ( this->flags & FTENT_BEOCCLUDED )
  171. {
  172. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  173. // Check normal
  174. Vector vecDelta = (GetAbsOrigin() - MainViewOrigin(nSlot));
  175. VectorNormalize( vecDelta );
  176. float flDot = DotProduct( m_vecNormal, vecDelta );
  177. if ( flDot > 0 )
  178. {
  179. float flAlpha = RemapVal( MIN(flDot,0.3), 0, 0.3, 0, 1 );
  180. flAlpha = MAX( 1.0, tempent_renderamt - (tempent_renderamt * flAlpha) );
  181. SetRenderAlpha( flAlpha );
  182. }
  183. }
  184. switch ( modelinfo->GetModelType( GetModel() ) )
  185. {
  186. case mod_sprite:
  187. drawn = DrawSprite(
  188. this,
  189. GetModel(),
  190. GetAbsOrigin(),
  191. GetAbsAngles(),
  192. m_flFrame, // sprite frame to render
  193. GetBody() > 0 ? cl_entitylist->GetBaseEntity( GetBody() ) : NULL, // attach to
  194. GetSkin(), // attachment point
  195. GetRenderMode(), // rendermode
  196. GetRenderFX(), // renderfx
  197. GetRenderAlpha(), // alpha
  198. GetRenderColorR(),
  199. GetRenderColorG(),
  200. GetRenderColorB(),
  201. m_flSpriteScale // sprite scale
  202. );
  203. break;
  204. case mod_studio:
  205. drawn = DrawStudioModel( flags );
  206. break;
  207. default:
  208. break;
  209. }
  210. return drawn;
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose:
  214. // Output : Returns true on success, false on failure.
  215. //-----------------------------------------------------------------------------
  216. bool C_LocalTempEntity::IsActive( void )
  217. {
  218. bool active = true;
  219. float life = die - gpGlobals->curtime;
  220. if ( life < 0 )
  221. {
  222. if ( flags & FTENT_FADEOUT )
  223. {
  224. int alpha;
  225. if (GetRenderMode() == kRenderNormal)
  226. {
  227. SetRenderMode( kRenderTransTexture );
  228. }
  229. alpha = tempent_renderamt * ( 1 + life * fadeSpeed );
  230. if ( alpha <= 0 )
  231. {
  232. active = false;
  233. alpha = 0;
  234. }
  235. SetRenderAlpha( alpha );
  236. }
  237. else
  238. {
  239. active = false;
  240. }
  241. }
  242. // Never die tempents only die when their die is cleared
  243. if ( flags & FTENT_NEVERDIE )
  244. {
  245. active = (die != 0);
  246. }
  247. return active;
  248. }
  249. bool C_LocalTempEntity::Frame( float frametime, int framenumber )
  250. {
  251. float fastFreq = gpGlobals->curtime * 5.5;
  252. float gravity = -frametime * sv_gravity.GetFloat();
  253. float gravitySlow = gravity * 0.5;
  254. float traceFraction = 1;
  255. Assert( !GetMoveParent() );
  256. m_vecPrevLocalOrigin = GetLocalOrigin();
  257. m_vecTempEntVelocity = m_vecTempEntVelocity + ( m_vecTempEntAcceleration * frametime );
  258. if ( flags & FTENT_PLYRATTACHMENT )
  259. {
  260. if ( IClientEntity *pClient = cl_entitylist->GetClientEntity( clientIndex ) )
  261. {
  262. SetLocalOrigin( pClient->GetAbsOrigin() + tentOffset );
  263. }
  264. }
  265. else if ( flags & FTENT_SINEWAVE )
  266. {
  267. x += m_vecTempEntVelocity[0] * frametime;
  268. y += m_vecTempEntVelocity[1] * frametime;
  269. SetLocalOrigin( Vector(
  270. x + sin( m_vecTempEntVelocity[2] + gpGlobals->curtime /* * anim.prevframe */ ) * (10*m_flSpriteScale),
  271. y + sin( m_vecTempEntVelocity[2] + fastFreq + 0.7 ) * (8*m_flSpriteScale),
  272. GetLocalOriginDim( Z_INDEX ) + m_vecTempEntVelocity[2] * frametime ) );
  273. }
  274. else if ( flags & FTENT_SPIRAL )
  275. {
  276. float s, c;
  277. SinCos( m_vecTempEntVelocity[2] + fastFreq, &s, &c );
  278. SetLocalOrigin( GetLocalOrigin() + Vector(
  279. m_vecTempEntVelocity[0] * frametime + 8 * sin( gpGlobals->curtime * 20 ),
  280. m_vecTempEntVelocity[1] * frametime + 4 * sin( gpGlobals->curtime * 30 ),
  281. m_vecTempEntVelocity[2] * frametime ) );
  282. }
  283. else
  284. {
  285. SetLocalOrigin( GetLocalOrigin() + m_vecTempEntVelocity * frametime );
  286. }
  287. if ( flags & FTENT_SPRANIMATE )
  288. {
  289. m_flFrame += frametime * m_flFrameRate;
  290. if ( m_flFrame >= m_flFrameMax )
  291. {
  292. m_flFrame = m_flFrame - (int)(m_flFrame);
  293. if ( !(flags & FTENT_SPRANIMATELOOP) )
  294. {
  295. // this animating sprite isn't set to loop, so destroy it.
  296. die = 0.0f;
  297. return false;
  298. }
  299. }
  300. }
  301. else if ( flags & FTENT_SPRCYCLE )
  302. {
  303. m_flFrame += frametime * 10;
  304. if ( m_flFrame >= m_flFrameMax )
  305. {
  306. m_flFrame = m_flFrame - (int)(m_flFrame);
  307. }
  308. }
  309. if ( flags & FTENT_SMOKEGROWANDFADE )
  310. {
  311. m_flSpriteScale += frametime * 0.5f;
  312. //m_clrRender.a -= frametime * 1500;
  313. }
  314. if ( flags & FTENT_ROTATE )
  315. {
  316. SetLocalAngles( GetLocalAngles() + m_vecTempEntAngVelocity * frametime );
  317. }
  318. else if ( flags & FTENT_ALIGNTOMOTION )
  319. {
  320. if ( m_vecTempEntVelocity.Length() > 0.0f )
  321. {
  322. QAngle angles;
  323. VectorAngles( m_vecTempEntVelocity, angles );
  324. SetAbsAngles( angles );
  325. }
  326. }
  327. if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) )
  328. {
  329. Vector traceNormal;
  330. traceNormal.Init();
  331. bool bShouldCollide = true;
  332. trace_t trace;
  333. if ( flags & FTENT_COLLIDEALL )
  334. {
  335. Vector vPrevOrigin = m_vecPrevLocalOrigin;
  336. if ( cl_fasttempentcollision.GetInt() > 0 && flags & FTENT_USEFASTCOLLISIONS )
  337. {
  338. if ( m_iLastCollisionFrame + cl_fasttempentcollision.GetInt() > gpGlobals->framecount )
  339. {
  340. bShouldCollide = false;
  341. }
  342. else
  343. {
  344. if ( m_vLastCollisionOrigin != vec3_origin )
  345. {
  346. vPrevOrigin = m_vLastCollisionOrigin;
  347. }
  348. m_iLastCollisionFrame = gpGlobals->framecount;
  349. bShouldCollide = true;
  350. }
  351. }
  352. if ( bShouldCollide == true )
  353. {
  354. // If the FTENT_COLLISIONGROUP flag is set, use the entity's collision group
  355. int collisionGroup = COLLISION_GROUP_NONE;
  356. if ( flags & FTENT_COLLISIONGROUP )
  357. {
  358. collisionGroup = GetCollisionGroup();
  359. }
  360. UTIL_TraceLine( vPrevOrigin, GetLocalOrigin(), MASK_SOLID, GetOwnerEntity(), collisionGroup, &trace );
  361. // Make sure it didn't bump into itself... (?!?)
  362. if (
  363. (trace.fraction != 1) &&
  364. ( (trace.DidHitWorld()) ||
  365. (trace.m_pEnt != ClientEntityList().GetEnt(clientIndex)) )
  366. )
  367. {
  368. traceFraction = trace.fraction;
  369. VectorCopy( trace.plane.normal, traceNormal );
  370. }
  371. m_vLastCollisionOrigin = trace.endpos;
  372. }
  373. }
  374. else if ( flags & FTENT_COLLIDEWORLD )
  375. {
  376. CTraceFilterWorldOnly traceFilter;
  377. UTIL_TraceLine( m_vecPrevLocalOrigin, GetLocalOrigin(), MASK_SOLID, &traceFilter, &trace );
  378. if ( trace.fraction != 1 )
  379. {
  380. traceFraction = trace.fraction;
  381. VectorCopy( trace.plane.normal, traceNormal );
  382. }
  383. }
  384. if ( traceFraction != 1 ) // Decent collision now, and damping works
  385. {
  386. float proj, damp;
  387. SetLocalOrigin( trace.endpos );
  388. // Damp velocity
  389. damp = bounceFactor;
  390. if ( flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) )
  391. {
  392. damp *= 0.5;
  393. if ( traceNormal[2] > 0.9 ) // Hit floor?
  394. {
  395. if ( m_vecTempEntVelocity[2] <= 0 && m_vecTempEntVelocity[2] >= gravity*3 )
  396. {
  397. damp = 0; // Stop
  398. flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL);
  399. SetLocalAnglesDim( X_INDEX, 0 );
  400. SetLocalAnglesDim( Z_INDEX, 0 );
  401. }
  402. }
  403. }
  404. if ( flags & (FTENT_CHANGERENDERONCOLLIDE) )
  405. {
  406. OnTranslucencyTypeChanged();
  407. flags &= ~FTENT_CHANGERENDERONCOLLIDE;
  408. }
  409. if (hitSound)
  410. {
  411. tempents->PlaySound(this, damp);
  412. }
  413. if ( m_pszImpactEffect )
  414. {
  415. CEffectData data;
  416. //data.m_vOrigin = newOrigin;
  417. data.m_vOrigin = trace.endpos;
  418. data.m_vStart = trace.startpos;
  419. data.m_nSurfaceProp = trace.surface.surfaceProps;
  420. data.m_nHitBox = trace.hitbox;
  421. data.m_nDamageType = TEAM_UNASSIGNED;
  422. IClientNetworkable *pClient = cl_entitylist->GetClientEntity( clientIndex );
  423. if ( pClient )
  424. {
  425. C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>(pClient);
  426. if( pPlayer )
  427. {
  428. data.m_nDamageType = pPlayer->GetTeamNumber();
  429. }
  430. }
  431. if ( trace.m_pEnt )
  432. {
  433. data.m_hEntity = ClientEntityList().EntIndexToHandle( trace.m_pEnt->entindex() );
  434. }
  435. DispatchEffect( m_pszImpactEffect, data );
  436. }
  437. // Check for a collision and stop the particle system.
  438. if ( flags & FTENT_CLIENTSIDEPARTICLES )
  439. {
  440. // Stop the emission of particles on collision - removed from the ClientEntityList on removal from the tempent pool.
  441. ParticleProp()->StopEmission();
  442. m_bParticleCollision = true;
  443. }
  444. if (flags & FTENT_COLLIDEKILL)
  445. {
  446. // die on impact
  447. flags &= ~FTENT_FADEOUT;
  448. die = gpGlobals->curtime;
  449. }
  450. else if ( flags & FTENT_ATTACHTOTARGET)
  451. {
  452. // If we've hit the world, just stop moving
  453. if ( trace.DidHitWorld() && !( trace.surface.flags & SURF_SKY ) )
  454. {
  455. m_vecTempEntVelocity = vec3_origin;
  456. m_vecTempEntAcceleration = vec3_origin;
  457. // Remove movement flags so we don't keep tracing
  458. flags &= ~(FTENT_COLLIDEALL | FTENT_COLLIDEWORLD);
  459. }
  460. else
  461. {
  462. // Couldn't attach to this entity. Die.
  463. flags &= ~FTENT_FADEOUT;
  464. die = gpGlobals->curtime;
  465. }
  466. }
  467. else
  468. {
  469. // Reflect velocity
  470. if ( damp != 0 )
  471. {
  472. proj = ((Vector)m_vecTempEntVelocity).Dot(traceNormal);
  473. VectorMA( m_vecTempEntVelocity, -proj*2, traceNormal, m_vecTempEntVelocity );
  474. // Reflect rotation (fake)
  475. SetLocalAnglesDim( Y_INDEX, -GetLocalAnglesDim( Y_INDEX ) );
  476. }
  477. if ( damp != 1 )
  478. {
  479. VectorScale( m_vecTempEntVelocity, damp, m_vecTempEntVelocity );
  480. SetLocalAngles( GetLocalAngles() * 0.9 );
  481. }
  482. }
  483. }
  484. }
  485. if ( (flags & FTENT_FLICKER) && framenumber == m_nFlickerFrame )
  486. {
  487. dlight_t *dl = effects->CL_AllocDlight (LIGHT_INDEX_TE_DYNAMIC);
  488. VectorCopy (GetLocalOrigin(), dl->origin);
  489. dl->radius = 60;
  490. dl->color.r = 255;
  491. dl->color.g = 120;
  492. dl->color.b = 0;
  493. dl->die = gpGlobals->curtime + 0.01;
  494. }
  495. if ( flags & FTENT_SMOKETRAIL )
  496. {
  497. Assert( !"FIXME: Rework smoketrail to be client side\n" );
  498. }
  499. // add gravity if we didn't collide in this frame
  500. if ( traceFraction == 1 )
  501. {
  502. if ( flags & FTENT_GRAVITY )
  503. m_vecTempEntVelocity[2] += gravity;
  504. else if ( flags & FTENT_SLOWGRAVITY )
  505. m_vecTempEntVelocity[2] += gravitySlow;
  506. }
  507. if ( flags & FTENT_WINDBLOWN )
  508. {
  509. Vector vecWind;
  510. GetWindspeedAtTime( gpGlobals->curtime, vecWind );
  511. for ( int i = 0 ; i < 2 ; i++ )
  512. {
  513. if ( m_vecTempEntVelocity[i] < vecWind[i] )
  514. {
  515. m_vecTempEntVelocity[i] += ( frametime * TENT_WIND_ACCEL );
  516. // clamp
  517. if ( m_vecTempEntVelocity[i] > vecWind[i] )
  518. m_vecTempEntVelocity[i] = vecWind[i];
  519. }
  520. else if (m_vecTempEntVelocity[i] > vecWind[i] )
  521. {
  522. m_vecTempEntVelocity[i] -= ( frametime * TENT_WIND_ACCEL );
  523. // clamp.
  524. if ( m_vecTempEntVelocity[i] < vecWind[i] )
  525. m_vecTempEntVelocity[i] = vecWind[i];
  526. }
  527. }
  528. }
  529. return true;
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Purpose: Attach a particle effect to a temp entity.
  533. //-----------------------------------------------------------------------------
  534. void C_LocalTempEntity::AddParticleEffect( const char *pszParticleEffect )
  535. {
  536. // Do we have a valid particle effect.
  537. if ( !pszParticleEffect || ( pszParticleEffect[0] == '\0' ) )
  538. return;
  539. // Check to see that we don't already have a particle effect.
  540. if ( ( flags & FTENT_CLIENTSIDEPARTICLES ) != 0 )
  541. return;
  542. // Add the entity to the ClientEntityList and create the particle system.
  543. ClientEntityList().AddNonNetworkableEntity( this );
  544. ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW );
  545. // Set the particle flag on the temp entity and save the name of the particle effect.
  546. flags |= FTENT_CLIENTSIDEPARTICLES;
  547. SetParticleEffect( pszParticleEffect );
  548. }
  549. //-----------------------------------------------------------------------------
  550. // Purpose: This helper keeps track of batches of "breakmodels" so that they can all share the lighting origin
  551. // of the first of the group (because the server sends down 15 chunks at a time, and rebuilding 15 light cache
  552. // entries for a map with a lot of worldlights is really slow).
  553. //-----------------------------------------------------------------------------
  554. class CBreakableHelper
  555. {
  556. public:
  557. void Insert( C_LocalTempEntity *entity, bool isSlave );
  558. void Remove( C_LocalTempEntity *entity );
  559. void Clear();
  560. const Vector *GetLightingOrigin( C_LocalTempEntity *entity );
  561. private:
  562. // A context is the first master until the next one, which starts a new context
  563. struct BreakableList_t
  564. {
  565. unsigned int context;
  566. C_LocalTempEntity *entity;
  567. };
  568. CUtlLinkedList< BreakableList_t, unsigned short > m_Breakables;
  569. unsigned int m_nCurrentContext;
  570. };
  571. //-----------------------------------------------------------------------------
  572. // Purpose: Adds brekable to list, starts new context if needed
  573. // Input : *entity -
  574. // isSlave -
  575. //-----------------------------------------------------------------------------
  576. void CBreakableHelper::Insert( C_LocalTempEntity *entity, bool isSlave )
  577. {
  578. // A master signifies the start of a new run of broken objects
  579. if ( !isSlave )
  580. {
  581. ++m_nCurrentContext;
  582. }
  583. BreakableList_t entry;
  584. entry.context = m_nCurrentContext;
  585. entry.entity = entity;
  586. m_Breakables.AddToTail( entry );
  587. }
  588. //-----------------------------------------------------------------------------
  589. // Purpose: Removes all instances of entity in the list
  590. // Input : *entity -
  591. //-----------------------------------------------------------------------------
  592. void CBreakableHelper::Remove( C_LocalTempEntity *entity )
  593. {
  594. for ( unsigned short i = m_Breakables.Head(); i != m_Breakables.InvalidIndex() ; )
  595. {
  596. unsigned short n = m_Breakables.Next( i );
  597. if ( m_Breakables[ i ].entity == entity )
  598. {
  599. m_Breakables.Remove( i );
  600. }
  601. i = n;
  602. }
  603. }
  604. //-----------------------------------------------------------------------------
  605. // Purpose: For a given breakable, find the "first" or head object and use it's current
  606. // origin as the lighting origin for the entire group of objects
  607. // Input : *entity -
  608. // Output : const Vector
  609. //-----------------------------------------------------------------------------
  610. const Vector *CBreakableHelper::GetLightingOrigin( C_LocalTempEntity *entity )
  611. {
  612. unsigned int nCurContext = 0;
  613. C_LocalTempEntity *head = NULL;
  614. FOR_EACH_LL( m_Breakables, i )
  615. {
  616. BreakableList_t& e = m_Breakables[ i ];
  617. if ( e.context != nCurContext )
  618. {
  619. nCurContext = e.context;
  620. head = e.entity;
  621. }
  622. if ( e.entity == entity )
  623. {
  624. Assert( head );
  625. return head ? &head->GetAbsOrigin() : NULL;
  626. }
  627. }
  628. return NULL;
  629. }
  630. //-----------------------------------------------------------------------------
  631. // Purpose: Wipe breakable helper list
  632. // Input : -
  633. //-----------------------------------------------------------------------------
  634. void CBreakableHelper::Clear()
  635. {
  636. m_Breakables.RemoveAll();
  637. m_nCurrentContext = 0;
  638. }
  639. static CBreakableHelper g_BreakableHelper;
  640. //-----------------------------------------------------------------------------
  641. // Purpose: See if it's in the breakable helper list and, if so, remove
  642. // Input : -
  643. //-----------------------------------------------------------------------------
  644. void C_LocalTempEntity::OnRemoveTempEntity()
  645. {
  646. g_BreakableHelper.Remove( this );
  647. }
  648. //-----------------------------------------------------------------------------
  649. // Purpose:
  650. //-----------------------------------------------------------------------------
  651. CTempEnts::CTempEnts( void ) :
  652. m_TempEntsPool( ( MAX_TEMP_ENTITIES / 20 ), CUtlMemoryPool::GROW_SLOW, 16 )
  653. {
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Purpose:
  657. //-----------------------------------------------------------------------------
  658. CTempEnts::~CTempEnts( void )
  659. {
  660. m_TempEntsPool.Clear();
  661. m_TempEnts.RemoveAll();
  662. }
  663. //-----------------------------------------------------------------------------
  664. // Purpose: Create a fizz effect
  665. // Input : *pent -
  666. // modelIndex -
  667. // density -
  668. //-----------------------------------------------------------------------------
  669. void CTempEnts::FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int current )
  670. {
  671. C_LocalTempEntity *pTemp;
  672. const model_t *model;
  673. int i, width, depth, count, frameCount;
  674. float maxHeight, speed, xspeed, yspeed;
  675. Vector origin;
  676. Vector mins, maxs;
  677. if ( !pent->GetModel() || !modelIndex )
  678. return;
  679. model = modelinfo->GetModel( modelIndex );
  680. if ( !model )
  681. return;
  682. count = density + 1;
  683. density = count * 3 + 6;
  684. modelinfo->GetModelBounds( pent->GetModel(), mins, maxs );
  685. maxHeight = maxs[2] - mins[2];
  686. width = maxs[0] - mins[0];
  687. depth = maxs[1] - mins[1];
  688. speed = current;
  689. SinCos( pent->GetLocalAngles()[1]*M_PI/180, &yspeed, &xspeed );
  690. xspeed *= speed;
  691. yspeed *= speed;
  692. frameCount = modelinfo->GetModelFrameCount( model );
  693. for (i=0 ; i<count ; i++)
  694. {
  695. origin[0] = mins[0] + random->RandomInt(0,width-1);
  696. origin[1] = mins[1] + random->RandomInt(0,depth-1);
  697. origin[2] = mins[2];
  698. pTemp = TempEntAlloc( origin, (model_t *)model );
  699. if (!pTemp)
  700. return;
  701. pTemp->flags |= FTENT_SINEWAVE;
  702. pTemp->x = origin[0];
  703. pTemp->y = origin[1];
  704. float zspeed = random->RandomInt(80,140);
  705. pTemp->SetVelocity( Vector(xspeed, yspeed, zspeed) );
  706. pTemp->die = gpGlobals->curtime + (maxHeight / zspeed) - 0.1;
  707. pTemp->m_flFrame = random->RandomInt(0,frameCount-1);
  708. // Set sprite scale
  709. pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(2,5);
  710. pTemp->SetRenderMode( kRenderTransAlpha );
  711. pTemp->SetRenderAlpha( 255 );
  712. }
  713. }
  714. //-----------------------------------------------------------------------------
  715. // Purpose: Create bubbles
  716. // Input : *mins -
  717. // *maxs -
  718. // height -
  719. // modelIndex -
  720. // count -
  721. // speed -
  722. //-----------------------------------------------------------------------------
  723. void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed )
  724. {
  725. C_LocalTempEntity *pTemp;
  726. const model_t *model;
  727. int i, frameCount;
  728. float sine, cosine;
  729. Vector origin;
  730. if ( !modelIndex )
  731. return;
  732. model = modelinfo->GetModel( modelIndex );
  733. if ( !model )
  734. return;
  735. frameCount = modelinfo->GetModelFrameCount( model );
  736. for (i=0 ; i<count ; i++)
  737. {
  738. origin[0] = random->RandomInt( mins[0], maxs[0] );
  739. origin[1] = random->RandomInt( mins[1], maxs[1] );
  740. origin[2] = random->RandomInt( mins[2], maxs[2] );
  741. pTemp = TempEntAlloc( origin, ( model_t * )model );
  742. if (!pTemp)
  743. return;
  744. pTemp->flags |= FTENT_SINEWAVE;
  745. pTemp->x = origin[0];
  746. pTemp->y = origin[1];
  747. SinCos( random->RandomInt( -M_PI, M_PI ), &sine, &cosine );
  748. float zspeed = random->RandomInt(80,140);
  749. pTemp->SetVelocity( Vector(speed * cosine, speed * sine, zspeed) );
  750. pTemp->die = gpGlobals->curtime + ((height - (origin[2] - mins[2])) / zspeed) - 0.1;
  751. pTemp->m_flFrame = random->RandomInt( 0, frameCount-1 );
  752. // Set sprite scale
  753. pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,16);
  754. pTemp->SetRenderMode( kRenderTransAlpha );
  755. pTemp->SetRenderColor( 255, 255, 255 );
  756. pTemp->SetRenderAlpha( 192 );
  757. }
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Purpose: Create bubble trail
  761. // Input : *start -
  762. // *end -
  763. // height -
  764. // modelIndex -
  765. // count -
  766. // speed -
  767. //-----------------------------------------------------------------------------
  768. void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWaterZ, int modelIndex, int count, float speed )
  769. {
  770. C_LocalTempEntity *pTemp;
  771. const model_t *model;
  772. int i, frameCount;
  773. float dist, angle;
  774. Vector origin;
  775. if ( !modelIndex )
  776. return;
  777. model = modelinfo->GetModel( modelIndex );
  778. if ( !model )
  779. return;
  780. frameCount = modelinfo->GetModelFrameCount( model );
  781. for (i=0 ; i<count ; i++)
  782. {
  783. dist = random->RandomFloat( 0, 1.0 );
  784. VectorLerp( start, end, dist, origin );
  785. pTemp = TempEntAlloc( origin, ( model_t * )model );
  786. if (!pTemp)
  787. return;
  788. pTemp->flags |= FTENT_SINEWAVE;
  789. pTemp->x = origin[0];
  790. pTemp->y = origin[1];
  791. angle = random->RandomInt( -M_PI, M_PI );
  792. float zspeed = random->RandomInt(80,140);
  793. pTemp->SetVelocity( Vector(speed * cos(angle), speed * sin(angle), zspeed) );
  794. pTemp->die = gpGlobals->curtime + ((flWaterZ - origin[2]) / zspeed) - 0.1;
  795. pTemp->m_flFrame = random->RandomInt(0,frameCount-1);
  796. // Set sprite scale
  797. pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,8);
  798. pTemp->SetRenderMode( kRenderTransAlpha );
  799. pTemp->SetRenderColor( 255, 255, 255 );
  800. pTemp->SetRenderAlpha( 192 );
  801. }
  802. }
  803. #define SHARD_VOLUME 12.0 // on shard ever n^3 units
  804. //-----------------------------------------------------------------------------
  805. // Purpose: Only used by BreakModel temp ents for now. Allows them to share a single
  806. // lighting origin amongst a group of objects. If the master object goes away, the next object
  807. // in the group becomes the new lighting origin, etc.
  808. // Input : *entity -
  809. // flags -
  810. // Output : int
  811. //-----------------------------------------------------------------------------
  812. int BreakModelDrawHelper( C_LocalTempEntity *entity, int flags )
  813. {
  814. ModelRenderInfo_t sInfo;
  815. sInfo.flags = flags;
  816. sInfo.pRenderable = entity;
  817. sInfo.instance = MODEL_INSTANCE_INVALID;
  818. sInfo.entity_index = entity->index;
  819. sInfo.pModel = entity->GetModel();
  820. sInfo.origin = entity->GetRenderOrigin();
  821. sInfo.angles = entity->GetRenderAngles();
  822. sInfo.skin = entity->GetSkin();
  823. sInfo.body = entity->GetBody();
  824. sInfo.hitboxset = entity->m_nHitboxSet;
  825. // This is the main change, look up a lighting origin from the helper singleton
  826. const Vector *pLightingOrigin = g_BreakableHelper.GetLightingOrigin( entity );
  827. if ( pLightingOrigin )
  828. {
  829. sInfo.pLightingOrigin = pLightingOrigin;
  830. }
  831. int drawn = modelrender->DrawModelEx( sInfo );
  832. return drawn;
  833. }
  834. //-----------------------------------------------------------------------------
  835. // Purpose: Create model shattering shards
  836. // Input : *pos -
  837. // *size -
  838. // *dir -
  839. // random -
  840. // life -
  841. // count -
  842. // modelIndex -
  843. // flags -
  844. //-----------------------------------------------------------------------------
  845. void CTempEnts::BreakModel( const Vector &pos, const QAngle &angles, const Vector &size, const Vector &dir,
  846. float randRange, float life, int count, int modelIndex, char flags)
  847. {
  848. int i, frameCount;
  849. C_LocalTempEntity *pTemp;
  850. const model_t *pModel;
  851. if (!modelIndex)
  852. return;
  853. pModel = modelinfo->GetModel( modelIndex );
  854. if ( !pModel )
  855. return;
  856. // See g_BreakableHelper above for notes...
  857. bool isSlave = ( flags & BREAK_SLAVE ) ? true : false;
  858. frameCount = modelinfo->GetModelFrameCount( pModel );
  859. if (count == 0)
  860. {
  861. // assume surface (not volume)
  862. count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0])/(3 * SHARD_VOLUME * SHARD_VOLUME);
  863. }
  864. if ( count > func_break_max_pieces.GetInt() )
  865. {
  866. count = func_break_max_pieces.GetInt();
  867. }
  868. matrix3x4_t transform;
  869. AngleMatrix( angles, pos, transform );
  870. for ( i = 0; i < count; i++ )
  871. {
  872. Vector vecLocalSpot, vecSpot;
  873. // fill up the box with stuff
  874. vecLocalSpot[0] = random->RandomFloat(-0.5,0.5) * size[0];
  875. vecLocalSpot[1] = random->RandomFloat(-0.5,0.5) * size[1];
  876. vecLocalSpot[2] = random->RandomFloat(-0.5,0.5) * size[2];
  877. VectorTransform( vecLocalSpot, transform, vecSpot );
  878. pTemp = TempEntAlloc(vecSpot, ( model_t * )pModel);
  879. if (!pTemp)
  880. return;
  881. // keep track of break_type, so we know how to play sound on collision
  882. pTemp->hitSound = flags;
  883. if ( modelinfo->GetModelType( pModel ) == mod_sprite )
  884. {
  885. pTemp->m_flFrame = random->RandomInt(0,frameCount-1);
  886. }
  887. else if ( modelinfo->GetModelType( pModel ) == mod_studio )
  888. {
  889. pTemp->SetBody( random->RandomInt(0,frameCount-1) );
  890. }
  891. pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
  892. if ( random->RandomInt(0,255) < 200 )
  893. {
  894. pTemp->flags |= FTENT_ROTATE;
  895. pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-256,255);
  896. pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-256,255);
  897. pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-256,255);
  898. }
  899. if ( (random->RandomInt(0,255) < 100 ) && (flags & BREAK_SMOKE) )
  900. {
  901. pTemp->flags |= FTENT_SMOKETRAIL;
  902. }
  903. if ((flags & BREAK_GLASS) || (flags & BREAK_TRANS))
  904. {
  905. pTemp->SetRenderMode( kRenderTransTexture );
  906. pTemp->SetRenderAlpha( 128 );
  907. pTemp->tempent_renderamt = 128;
  908. pTemp->bounceFactor = 0.3f;
  909. }
  910. else
  911. {
  912. pTemp->SetRenderMode( kRenderNormal );
  913. pTemp->tempent_renderamt = 255; // Set this for fadeout
  914. }
  915. pTemp->SetVelocity( Vector( dir[0] + random->RandomFloat(-randRange,randRange),
  916. dir[1] + random->RandomFloat(-randRange,randRange),
  917. dir[2] + random->RandomFloat( 0,randRange) ) );
  918. pTemp->die = gpGlobals->curtime + life + random->RandomFloat(0,1); // Add an extra 0-1 secs of life
  919. // We use a special rendering function because these objects will want to share their lighting
  920. // origin with the first/master object. Prevents a huge spike in Light Cache building in maps
  921. // with many worldlights.
  922. pTemp->SetDrawHelper( BreakModelDrawHelper );
  923. g_BreakableHelper.Insert( pTemp, isSlave );
  924. }
  925. }
  926. void CTempEnts::PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int flags, int effects, color24 renderColor)
  927. {
  928. C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew();
  929. if ( !pEntity )
  930. return;
  931. const model_t *model = modelinfo->GetModel( modelindex );
  932. if ( !model )
  933. {
  934. DevMsg("CTempEnts::PhysicsProp: model index %i not found\n", modelindex );
  935. return;
  936. }
  937. pEntity->SetModelName( modelinfo->GetModelName(model) );
  938. pEntity->SetSkin( skin );
  939. pEntity->SetAbsOrigin( pos );
  940. pEntity->SetAbsAngles( angles );
  941. pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE );
  942. pEntity->SetEffects( effects );
  943. pEntity->SetRenderColor( renderColor.r, renderColor.g, renderColor.b );
  944. if ( flags & 1 )
  945. {
  946. // We are not calling initialize on this entity here, so we need to manually set some of the required values otherwise set in initialize.
  947. pEntity->SetModelIndex( modelindex );
  948. pEntity->SetCollisionGroup( COLLISION_GROUP_PUSHAWAY );
  949. pEntity->SetAbsVelocity( vel );
  950. const model_t *mod = pEntity->GetModel();
  951. if ( mod )
  952. {
  953. Vector mins, maxs;
  954. modelinfo->GetModelBounds( mod, mins, maxs );
  955. pEntity->SetCollisionBounds( mins, maxs );
  956. }
  957. pEntity->Spawn();
  958. pEntity->SetHealth( 0 );
  959. pEntity->Break();
  960. return;
  961. }
  962. if ( !pEntity->Initialize() )
  963. {
  964. pEntity->Release();
  965. return;
  966. }
  967. IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
  968. if( pPhysicsObject )
  969. {
  970. pPhysicsObject->AddVelocity( &vel, NULL );
  971. }
  972. else
  973. {
  974. // failed to create a physics object
  975. pEntity->Release();
  976. return;
  977. }
  978. if ( flags & 2 )
  979. {
  980. int numBodygroups = pEntity->GetBodygroupCount( 0 );
  981. pEntity->SetBodygroup( 0, RandomInt( 0, numBodygroups - 1 ) );
  982. }
  983. }
  984. //-----------------------------------------------------------------------------
  985. // Purpose: Create a clientside projectile
  986. // Input : vecOrigin -
  987. // vecVelocity -
  988. // modelindex -
  989. // lifetime -
  990. // *pOwner -
  991. //-----------------------------------------------------------------------------
  992. C_LocalTempEntity *CTempEnts::ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelIndex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect, const char *pszParticleEffect )
  993. {
  994. C_LocalTempEntity *pTemp;
  995. const model_t *model;
  996. if ( !modelIndex )
  997. return NULL;
  998. model = modelinfo->GetModel( modelIndex );
  999. if ( !model )
  1000. {
  1001. Warning("ClientProjectile: No model %d!\n", modelIndex);
  1002. return NULL;
  1003. }
  1004. pTemp = TempEntAlloc( vecOrigin, ( model_t * )model );
  1005. if (!pTemp)
  1006. return NULL;
  1007. pTemp->SetVelocity( vecVelocity );
  1008. pTemp->SetAcceleration( vecAcceleration );
  1009. QAngle angles;
  1010. VectorAngles( vecVelocity, angles );
  1011. pTemp->SetAbsAngles( angles );
  1012. pTemp->SetAbsOrigin( vecOrigin );
  1013. pTemp->die = gpGlobals->curtime + lifetime;
  1014. pTemp->flags = FTENT_COLLIDEALL | FTENT_ATTACHTOTARGET | FTENT_ALIGNTOMOTION;
  1015. pTemp->clientIndex = ( pOwner != NULL ) ? pOwner->entindex() : 0;
  1016. pTemp->SetOwnerEntity( pOwner );
  1017. pTemp->SetImpactEffect( pszImpactEffect );
  1018. if ( pszParticleEffect )
  1019. {
  1020. // Add the entity to the ClientEntityList and create the particle system.
  1021. ClientEntityList().AddNonNetworkableEntity( pTemp );
  1022. pTemp->ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW );
  1023. // Set the particle flag on the temp entity and save the name of the particle effect.
  1024. pTemp->flags |= FTENT_CLIENTSIDEPARTICLES;
  1025. pTemp->SetParticleEffect( pszParticleEffect );
  1026. }
  1027. return pTemp;
  1028. }
  1029. //-----------------------------------------------------------------------------
  1030. // Purpose: Create sprite TE
  1031. // Input : *pos -
  1032. // *dir -
  1033. // scale -
  1034. // modelIndex -
  1035. // rendermode -
  1036. // renderfx -
  1037. // a -
  1038. // life -
  1039. // flags -
  1040. // Output : C_LocalTempEntity
  1041. //-----------------------------------------------------------------------------
  1042. C_LocalTempEntity *CTempEnts::TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector &normal )
  1043. {
  1044. C_LocalTempEntity *pTemp;
  1045. const model_t *model;
  1046. int frameCount;
  1047. if ( !modelIndex )
  1048. return NULL;
  1049. model = modelinfo->GetModel( modelIndex );
  1050. if ( !model )
  1051. {
  1052. Warning("No model %d!\n", modelIndex);
  1053. return NULL;
  1054. }
  1055. frameCount = modelinfo->GetModelFrameCount( model );
  1056. pTemp = TempEntAlloc( pos, ( model_t * )model );
  1057. if (!pTemp)
  1058. return NULL;
  1059. pTemp->m_flFrameMax = frameCount - 1;
  1060. pTemp->m_flFrameRate = 10;
  1061. pTemp->SetRenderMode( (RenderMode_t)rendermode );
  1062. pTemp->SetRenderFX( (RenderFx_t)renderfx );
  1063. pTemp->m_flSpriteScale = scale;
  1064. pTemp->tempent_renderamt = a * 255;
  1065. pTemp->m_vecNormal = normal;
  1066. pTemp->SetRenderColor( 255, 255, 255 );
  1067. pTemp->SetRenderAlpha( a * 255 );
  1068. pTemp->flags |= flags;
  1069. pTemp->SetVelocity( dir );
  1070. pTemp->SetLocalOrigin( pos );
  1071. if ( life )
  1072. pTemp->die = gpGlobals->curtime + life;
  1073. else
  1074. pTemp->die = gpGlobals->curtime + (frameCount * 0.1) + 1;
  1075. pTemp->m_flFrame = 0;
  1076. return pTemp;
  1077. }
  1078. //-----------------------------------------------------------------------------
  1079. // Purpose: Spray sprite
  1080. // Input : *pos -
  1081. // *dir -
  1082. // modelIndex -
  1083. // count -
  1084. // speed -
  1085. // iRand -
  1086. //-----------------------------------------------------------------------------
  1087. void CTempEnts::Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand )
  1088. {
  1089. C_LocalTempEntity *pTemp;
  1090. const model_t *pModel;
  1091. float noise;
  1092. float znoise;
  1093. int frameCount;
  1094. int i;
  1095. noise = (float)iRand / 100;
  1096. // more vertical displacement
  1097. znoise = noise * 1.5;
  1098. if ( znoise > 1 )
  1099. {
  1100. znoise = 1;
  1101. }
  1102. pModel = modelinfo->GetModel( modelIndex );
  1103. if ( !pModel )
  1104. {
  1105. Warning("No model %d!\n", modelIndex);
  1106. return;
  1107. }
  1108. frameCount = modelinfo->GetModelFrameCount( pModel ) - 1;
  1109. for ( i = 0; i < count; i++ )
  1110. {
  1111. pTemp = TempEntAlloc( pos, ( model_t * )pModel );
  1112. if (!pTemp)
  1113. return;
  1114. pTemp->SetRenderMode( kRenderTransAlpha );
  1115. pTemp->SetRenderColor( 255, 255, 255 );
  1116. pTemp->SetRenderAlpha( 255 );
  1117. pTemp->tempent_renderamt = 255;
  1118. pTemp->SetRenderFX( kRenderFxNoDissipation );
  1119. //pTemp->scale = random->RandomFloat( 0.1, 0.25 );
  1120. pTemp->m_flSpriteScale = 0.5;
  1121. pTemp->flags |= FTENT_FADEOUT | FTENT_SLOWGRAVITY;
  1122. pTemp->fadeSpeed = 2.0;
  1123. // make the spittle fly the direction indicated, but mix in some noise.
  1124. Vector velocity;
  1125. velocity.x = dir[ 0 ] + random->RandomFloat ( -noise, noise );
  1126. velocity.y = dir[ 1 ] + random->RandomFloat ( -noise, noise );
  1127. velocity.z = dir[ 2 ] + random->RandomFloat ( 0, znoise );
  1128. velocity *= random->RandomFloat( (speed * 0.8), (speed * 1.2) );
  1129. pTemp->SetVelocity( velocity );
  1130. pTemp->SetLocalOrigin( pos );
  1131. pTemp->die = gpGlobals->curtime + 0.35;
  1132. pTemp->m_flFrame = random->RandomInt( 0, frameCount );
  1133. }
  1134. }
  1135. void CTempEnts::Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed )
  1136. {
  1137. C_LocalTempEntity *pTemp;
  1138. const model_t *pModel;
  1139. int flFrameCount;
  1140. pModel = modelinfo->GetModel( modelIndex );
  1141. if ( !pModel )
  1142. {
  1143. Warning("No model %d!\n", modelIndex);
  1144. return;
  1145. }
  1146. flFrameCount = modelinfo->GetModelFrameCount( pModel );
  1147. Vector vecDelta;
  1148. VectorSubtract( vecEnd, vecStart, vecDelta );
  1149. Vector vecDir;
  1150. VectorCopy( vecDelta, vecDir );
  1151. VectorNormalize( vecDir );
  1152. flAmplitude /= 256.0;
  1153. for ( int i = 0 ; i < nCount; i++ )
  1154. {
  1155. Vector vecPos;
  1156. // Be careful of divide by 0 when using 'count' here...
  1157. if ( i == 0 )
  1158. {
  1159. VectorMA( vecStart, 0, vecDelta, vecPos );
  1160. }
  1161. else
  1162. {
  1163. VectorMA( vecStart, i / (nCount - 1.0), vecDelta, vecPos );
  1164. }
  1165. pTemp = TempEntAlloc( vecPos, ( model_t * )pModel );
  1166. if (!pTemp)
  1167. return;
  1168. pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_SPRCYCLE | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
  1169. Vector vecVel = vecDir * flSpeed;
  1170. vecVel.x += random->RandomInt( -127,128 ) * flAmplitude;
  1171. vecVel.y += random->RandomInt( -127,128 ) * flAmplitude;
  1172. vecVel.z += random->RandomInt( -127,128 ) * flAmplitude;
  1173. pTemp->SetVelocity( vecVel );
  1174. pTemp->SetLocalOrigin( vecPos );
  1175. pTemp->m_flSpriteScale = flSize;
  1176. pTemp->SetRenderMode( kRenderGlow );
  1177. pTemp->SetRenderFX( kRenderFxNoDissipation );
  1178. pTemp->tempent_renderamt = nRenderamt;
  1179. pTemp->SetRenderColor( 255, 255, 255 );
  1180. pTemp->m_flFrame = random->RandomInt( 0, flFrameCount - 1 );
  1181. pTemp->m_flFrameMax = flFrameCount - 1;
  1182. pTemp->die = gpGlobals->curtime + flLife + random->RandomFloat( 0, 4 );
  1183. }
  1184. }
  1185. //-----------------------------------------------------------------------------
  1186. // Purpose: Attaches entity to player
  1187. // Input : client -
  1188. // modelIndex -
  1189. // zoffset -
  1190. // life -
  1191. //-----------------------------------------------------------------------------
  1192. void CTempEnts::AttachTentToPlayer( int client, int modelIndex, float zoffset, float life )
  1193. {
  1194. C_LocalTempEntity *pTemp;
  1195. const model_t *pModel;
  1196. Vector position;
  1197. int frameCount;
  1198. if ( client <= 0 || client > gpGlobals->maxClients )
  1199. {
  1200. Warning("Bad client in AttachTentToPlayer()!\n");
  1201. return;
  1202. }
  1203. IClientEntity *clientClass = cl_entitylist->GetClientEntity( client );
  1204. if ( !clientClass )
  1205. {
  1206. Warning("Couldn't get IClientEntity for %i\n", client );
  1207. return;
  1208. }
  1209. pModel = modelinfo->GetModel( modelIndex );
  1210. if ( !pModel )
  1211. {
  1212. Warning("No model %d!\n", modelIndex);
  1213. return;
  1214. }
  1215. VectorCopy( clientClass->GetAbsOrigin(), position );
  1216. position[ 2 ] += zoffset;
  1217. pTemp = TempEntAllocHigh( position, ( model_t * )pModel );
  1218. if (!pTemp)
  1219. {
  1220. Warning("No temp ent.\n");
  1221. return;
  1222. }
  1223. pTemp->SetRenderMode( kRenderNormal );
  1224. pTemp->SetRenderAlpha( 255 );
  1225. pTemp->tempent_renderamt = 255;
  1226. pTemp->SetRenderFX( kRenderFxNoDissipation );
  1227. pTemp->clientIndex = client;
  1228. pTemp->tentOffset[ 0 ] = 0;
  1229. pTemp->tentOffset[ 1 ] = 0;
  1230. pTemp->tentOffset[ 2 ] = zoffset;
  1231. pTemp->die = gpGlobals->curtime + life;
  1232. pTemp->flags |= FTENT_PLYRATTACHMENT | FTENT_PERSIST;
  1233. // is the model a sprite?
  1234. if ( modelinfo->GetModelType( pTemp->GetModel() ) == mod_sprite )
  1235. {
  1236. frameCount = modelinfo->GetModelFrameCount( pModel );
  1237. pTemp->m_flFrameMax = frameCount - 1;
  1238. pTemp->flags |= FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP;
  1239. pTemp->m_flFrameRate = 10;
  1240. }
  1241. else
  1242. {
  1243. // no animation support for attached clientside studio models.
  1244. pTemp->m_flFrameMax = 0;
  1245. }
  1246. pTemp->m_flFrame = 0;
  1247. }
  1248. //-----------------------------------------------------------------------------
  1249. // Purpose: Detach entity from player
  1250. //-----------------------------------------------------------------------------
  1251. void CTempEnts::KillAttachedTents( int client )
  1252. {
  1253. if ( client <= 0 || client > gpGlobals->maxClients )
  1254. {
  1255. Warning("Bad client in KillAttachedTents()!\n");
  1256. return;
  1257. }
  1258. FOR_EACH_LL( m_TempEnts, i )
  1259. {
  1260. C_LocalTempEntity *pTemp = m_TempEnts[ i ];
  1261. if ( pTemp->flags & FTENT_PLYRATTACHMENT )
  1262. {
  1263. // this TENT is player attached.
  1264. // if it is attached to this client, set it to die instantly.
  1265. if ( pTemp->clientIndex == client )
  1266. {
  1267. pTemp->die = gpGlobals->curtime;// good enough, it will die on next tent update.
  1268. }
  1269. }
  1270. }
  1271. }
  1272. //-----------------------------------------------------------------------------
  1273. // Purpose: Create ricochet sprite
  1274. // Input : *pos -
  1275. // *pmodel -
  1276. // duration -
  1277. // scale -
  1278. //-----------------------------------------------------------------------------
  1279. void CTempEnts::RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale )
  1280. {
  1281. C_LocalTempEntity *pTemp;
  1282. pTemp = TempEntAlloc( pos, ( model_t * )pmodel );
  1283. if (!pTemp)
  1284. return;
  1285. pTemp->SetRenderMode( kRenderGlow );
  1286. pTemp->SetRenderFX( kRenderFxNoDissipation );
  1287. pTemp->SetRenderAlpha( 200 );
  1288. pTemp->tempent_renderamt = 200;
  1289. pTemp->m_flSpriteScale = scale;
  1290. pTemp->flags = FTENT_FADEOUT;
  1291. pTemp->SetVelocity( vec3_origin );
  1292. pTemp->SetLocalOrigin( pos );
  1293. pTemp->fadeSpeed = 8;
  1294. pTemp->die = gpGlobals->curtime;
  1295. pTemp->m_flFrame = 0;
  1296. pTemp->SetLocalAnglesDim( Z_INDEX, 45 * random->RandomInt( 0, 7 ) );
  1297. }
  1298. //-----------------------------------------------------------------------------
  1299. // Purpose: Create blood sprite
  1300. // Input : *org -
  1301. // colorindex -
  1302. // modelIndex -
  1303. // modelIndex2 -
  1304. // size -
  1305. //-----------------------------------------------------------------------------
  1306. void CTempEnts::BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size )
  1307. {
  1308. const model_t *model;
  1309. //Validate the model first
  1310. if ( modelIndex && (model = modelinfo->GetModel( modelIndex ) ) != NULL )
  1311. {
  1312. C_LocalTempEntity *pTemp;
  1313. int frameCount = modelinfo->GetModelFrameCount( model );
  1314. //Large, single blood sprite is a high-priority tent
  1315. if ( ( pTemp = TempEntAllocHigh( org, ( model_t * )model ) ) != NULL )
  1316. {
  1317. pTemp->SetRenderMode( kRenderTransTexture );
  1318. pTemp->SetRenderFX( kRenderFxNone );
  1319. pTemp->m_flSpriteScale = random->RandomFloat( size / 25, size / 35);
  1320. pTemp->flags = FTENT_SPRANIMATE;
  1321. pTemp->SetRenderColor( r, g, b );
  1322. pTemp->SetRenderAlpha( a );
  1323. pTemp->tempent_renderamt= pTemp->GetRenderAlpha();
  1324. pTemp->SetVelocity( vec3_origin );
  1325. pTemp->m_flFrameRate = frameCount * 4; // Finish in 0.250 seconds
  1326. pTemp->die = gpGlobals->curtime + (frameCount / pTemp->m_flFrameRate); // Play the whole thing Once
  1327. pTemp->m_flFrame = 0;
  1328. pTemp->m_flFrameMax = frameCount - 1;
  1329. pTemp->bounceFactor = 0;
  1330. pTemp->SetLocalAnglesDim( Z_INDEX, random->RandomInt( 0, 360 ) );
  1331. }
  1332. }
  1333. }
  1334. //-----------------------------------------------------------------------------
  1335. // Purpose: Create default sprite TE
  1336. // Input : *pos -
  1337. // spriteIndex -
  1338. // framerate -
  1339. // Output : C_LocalTempEntity
  1340. //-----------------------------------------------------------------------------
  1341. C_LocalTempEntity *CTempEnts::DefaultSprite( const Vector &pos, int spriteIndex, float framerate )
  1342. {
  1343. C_LocalTempEntity *pTemp;
  1344. int frameCount;
  1345. const model_t *pSprite;
  1346. // don't spawn while paused
  1347. if ( gpGlobals->frametime == 0.0 )
  1348. return NULL;
  1349. pSprite = modelinfo->GetModel( spriteIndex );
  1350. if ( !spriteIndex || !pSprite || modelinfo->GetModelType( pSprite ) != mod_sprite )
  1351. {
  1352. DevWarning( 1,"No Sprite %d!\n", spriteIndex);
  1353. return NULL;
  1354. }
  1355. frameCount = modelinfo->GetModelFrameCount( pSprite );
  1356. pTemp = TempEntAlloc( pos, ( model_t * )pSprite );
  1357. if (!pTemp)
  1358. return NULL;
  1359. pTemp->m_flFrameMax = frameCount - 1;
  1360. pTemp->m_flSpriteScale = 1.0;
  1361. pTemp->flags |= FTENT_SPRANIMATE;
  1362. if ( framerate == 0 )
  1363. framerate = 10;
  1364. pTemp->m_flFrameRate = framerate;
  1365. pTemp->die = gpGlobals->curtime + (float)frameCount / framerate;
  1366. pTemp->m_flFrame = 0;
  1367. pTemp->SetLocalOrigin( pos );
  1368. return pTemp;
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // Purpose: Create sprite smoke
  1372. // Input : *pTemp -
  1373. // scale -
  1374. //-----------------------------------------------------------------------------
  1375. void CTempEnts::Sprite_Smoke( C_LocalTempEntity *pTemp, float scale )
  1376. {
  1377. if ( !pTemp )
  1378. return;
  1379. pTemp->SetRenderMode( kRenderTransAlpha );
  1380. pTemp->SetRenderFX( kRenderFxNone );
  1381. pTemp->SetVelocity( Vector( 0, 0, 30 ) );
  1382. int iColor = random->RandomInt(20,35);
  1383. pTemp->SetRenderColor( iColor, iColor, iColor );
  1384. pTemp->SetRenderAlpha( 255 );
  1385. pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 20 );
  1386. pTemp->m_flSpriteScale = scale;
  1387. pTemp->flags = FTENT_WINDBLOWN;
  1388. }
  1389. //-----------------------------------------------------------------------------
  1390. // Purpose: Create some simple physically simulated models
  1391. //-----------------------------------------------------------------------------
  1392. C_LocalTempEntity * CTempEnts::SpawnTempModel( model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags )
  1393. {
  1394. Assert( pModel );
  1395. // Alloc a new tempent
  1396. C_LocalTempEntity *pTemp = TempEntAlloc( vecOrigin, pModel );
  1397. if ( !pTemp )
  1398. return NULL;
  1399. pTemp->SetAbsAngles( vecAngles );
  1400. pTemp->SetBody( 0 );
  1401. pTemp->flags |= iFlags;
  1402. pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-255,255);
  1403. pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-255,255);
  1404. pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-255,255);
  1405. pTemp->SetRenderMode( kRenderNormal );
  1406. pTemp->tempent_renderamt = 255;
  1407. pTemp->SetVelocity( vecVelocity );
  1408. pTemp->die = gpGlobals->curtime + flLifeTime;
  1409. return pTemp;
  1410. }
  1411. //-----------------------------------------------------------------------------
  1412. // Purpose:
  1413. // Input : type -
  1414. // entityIndex -
  1415. // attachmentIndex -
  1416. // firstPerson -
  1417. //-----------------------------------------------------------------------------
  1418. void CTempEnts::MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson )
  1419. {
  1420. switch( type )
  1421. {
  1422. case MUZZLEFLASH_COMBINE:
  1423. if ( firstPerson )
  1424. {
  1425. MuzzleFlash_Combine_Player( hEntity, attachmentIndex );
  1426. }
  1427. else
  1428. {
  1429. MuzzleFlash_Combine_NPC( hEntity, attachmentIndex );
  1430. }
  1431. break;
  1432. case MUZZLEFLASH_SMG1:
  1433. if ( firstPerson )
  1434. {
  1435. MuzzleFlash_SMG1_Player( hEntity, attachmentIndex );
  1436. }
  1437. else
  1438. {
  1439. MuzzleFlash_SMG1_NPC( hEntity, attachmentIndex );
  1440. }
  1441. break;
  1442. case MUZZLEFLASH_PISTOL:
  1443. if ( firstPerson )
  1444. {
  1445. MuzzleFlash_Pistol_Player( hEntity, attachmentIndex );
  1446. }
  1447. else
  1448. {
  1449. MuzzleFlash_Pistol_NPC( hEntity, attachmentIndex );
  1450. }
  1451. break;
  1452. case MUZZLEFLASH_SHOTGUN:
  1453. if ( firstPerson )
  1454. {
  1455. MuzzleFlash_Shotgun_Player( hEntity, attachmentIndex );
  1456. }
  1457. else
  1458. {
  1459. MuzzleFlash_Shotgun_NPC( hEntity, attachmentIndex );
  1460. }
  1461. break;
  1462. case MUZZLEFLASH_357:
  1463. if ( firstPerson )
  1464. {
  1465. MuzzleFlash_357_Player( hEntity, attachmentIndex );
  1466. }
  1467. break;
  1468. case MUZZLEFLASH_RPG:
  1469. if ( firstPerson )
  1470. {
  1471. // MuzzleFlash_RPG_Player( hEntity, attachmentIndex );
  1472. }
  1473. else
  1474. {
  1475. MuzzleFlash_RPG_NPC( hEntity, attachmentIndex );
  1476. }
  1477. break;
  1478. break;
  1479. default:
  1480. {
  1481. //NOTENOTE: This means you specified an invalid muzzleflash type, check your spelling?
  1482. Assert( 0 );
  1483. }
  1484. break;
  1485. }
  1486. }
  1487. //-----------------------------------------------------------------------------
  1488. // Purpose: Play muzzle flash
  1489. // Input : *pos1 -
  1490. // type -
  1491. //-----------------------------------------------------------------------------
  1492. void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, ClientEntityHandle_t hEntity, bool firstPerson )
  1493. {
  1494. #ifdef CSTRIKE_DLL
  1495. return;
  1496. #else
  1497. //NOTENOTE: This function is becoming obsolete as the muzzles are moved over to being local to attachments
  1498. switch ( type )
  1499. {
  1500. //
  1501. // Shotgun
  1502. //
  1503. case MUZZLEFLASH_SHOTGUN:
  1504. if ( firstPerson )
  1505. {
  1506. MuzzleFlash_Shotgun_Player( hEntity, 1 );
  1507. }
  1508. else
  1509. {
  1510. MuzzleFlash_Shotgun_NPC( hEntity, 1 );
  1511. }
  1512. break;
  1513. // UNDONE: These need their own effects/sprites. For now use the pistol
  1514. // SMG1
  1515. case MUZZLEFLASH_SMG1:
  1516. if ( firstPerson )
  1517. {
  1518. MuzzleFlash_SMG1_Player( hEntity, 1 );
  1519. }
  1520. else
  1521. {
  1522. MuzzleFlash_SMG1_NPC( hEntity, 1 );
  1523. }
  1524. break;
  1525. // SMG2
  1526. case MUZZLEFLASH_SMG2:
  1527. case MUZZLEFLASH_PISTOL:
  1528. if ( firstPerson )
  1529. {
  1530. MuzzleFlash_Pistol_Player( hEntity, 1 );
  1531. }
  1532. else
  1533. {
  1534. MuzzleFlash_Pistol_NPC( hEntity, 1 );
  1535. }
  1536. break;
  1537. case MUZZLEFLASH_COMBINE:
  1538. if ( firstPerson )
  1539. {
  1540. //FIXME: These should go away
  1541. MuzzleFlash_Combine_Player( hEntity, 1 );
  1542. }
  1543. else
  1544. {
  1545. //FIXME: These should go away
  1546. MuzzleFlash_Combine_NPC( hEntity, 1 );
  1547. }
  1548. break;
  1549. default:
  1550. // There's no supported muzzle flash for the type specified!
  1551. Warning( "Attempted to use an unsupported muzzle flash type.. new particle effect needed here!\n" );
  1552. break;
  1553. }
  1554. #endif
  1555. }
  1556. //-----------------------------------------------------------------------------
  1557. // Purpose: Create explosion sprite
  1558. // Input : *pTemp -
  1559. // scale -
  1560. // flags -
  1561. //-----------------------------------------------------------------------------
  1562. void CTempEnts::Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags )
  1563. {
  1564. if ( !pTemp )
  1565. return;
  1566. if ( flags & TE_EXPLFLAG_NOADDITIVE )
  1567. {
  1568. // solid sprite
  1569. pTemp->SetRenderMode( kRenderNormal );
  1570. pTemp->SetRenderAlpha( 255 );
  1571. }
  1572. else if( flags & TE_EXPLFLAG_DRAWALPHA )
  1573. {
  1574. // alpha sprite
  1575. pTemp->SetRenderMode( kRenderTransAlpha );
  1576. pTemp->SetRenderAlpha( 180 );
  1577. }
  1578. else
  1579. {
  1580. // additive sprite
  1581. pTemp->SetRenderMode( kRenderTransAdd );
  1582. pTemp->SetRenderAlpha( 180 );
  1583. }
  1584. if ( flags & TE_EXPLFLAG_ROTATE )
  1585. {
  1586. pTemp->SetLocalAnglesDim( Z_INDEX, random->RandomInt( 0, 360 ) );
  1587. }
  1588. pTemp->SetRenderFX( kRenderFxNone );
  1589. pTemp->SetVelocity( Vector( 0, 0, 8 ) );
  1590. pTemp->SetRenderColor( 255, 255, 255 );
  1591. pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 10 );
  1592. pTemp->m_flSpriteScale = scale;
  1593. }
  1594. enum
  1595. {
  1596. SHELL_NONE = 0,
  1597. SHELL_SMALL,
  1598. SHELL_BIG,
  1599. SHELL_SHOTGUN,
  1600. };
  1601. //-----------------------------------------------------------------------------
  1602. // Purpose: Clear existing temp entities
  1603. //-----------------------------------------------------------------------------
  1604. void CTempEnts::Clear( void )
  1605. {
  1606. FOR_EACH_LL( m_TempEnts, i )
  1607. {
  1608. C_LocalTempEntity *p = m_TempEnts[ i ];
  1609. m_TempEntsPool.Free( p );
  1610. }
  1611. m_TempEnts.RemoveAll();
  1612. g_BreakableHelper.Clear();
  1613. }
  1614. C_LocalTempEntity *CTempEnts::FindTempEntByID( int nID, int nSubID )
  1615. {
  1616. // HACK HACK: We're using skin and hitsounds as a hacky way to store an ID and sub-ID for later identification
  1617. FOR_EACH_LL( m_TempEnts, i )
  1618. {
  1619. C_LocalTempEntity *p = m_TempEnts[ i ];
  1620. if ( p && p->m_nSkin == nID && p->hitSound == nSubID )
  1621. {
  1622. return p;
  1623. }
  1624. }
  1625. return NULL;
  1626. }
  1627. //-----------------------------------------------------------------------------
  1628. // Purpose: Allocate temp entity ( normal/low priority )
  1629. // Input : *org -
  1630. // *model -
  1631. // Output : C_LocalTempEntity
  1632. //-----------------------------------------------------------------------------
  1633. C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, model_t *model )
  1634. {
  1635. C_LocalTempEntity *pTemp;
  1636. if ( !model )
  1637. {
  1638. DevWarning( 1, "Can't create temporary entity with NULL model!\n" );
  1639. return NULL;
  1640. }
  1641. pTemp = TempEntAlloc();
  1642. if ( !pTemp )
  1643. {
  1644. DevWarning( 1, "Overflow %d temporary ents!\n", MAX_TEMP_ENTITIES );
  1645. return NULL;
  1646. }
  1647. m_TempEnts.AddToTail( pTemp );
  1648. pTemp->Prepare( model, gpGlobals->curtime );
  1649. pTemp->priority = TENTPRIORITY_LOW;
  1650. pTemp->SetAbsOrigin( org );
  1651. pTemp->AddToLeafSystem( false );
  1652. if ( CommandLine()->CheckParm( "-tools" ) != NULL )
  1653. {
  1654. #ifdef _DEBUG
  1655. static bool first = true;
  1656. if ( first )
  1657. {
  1658. Msg( "Currently not recording tempents, since recording them as entites causes them to be deleted as entities, even though they were allocated through the tempent pool. (crash)\n" );
  1659. first = false;
  1660. }
  1661. #endif
  1662. // ClientEntityList().AddNonNetworkableEntity( pTemp );
  1663. }
  1664. return pTemp;
  1665. }
  1666. //-----------------------------------------------------------------------------
  1667. // Purpose:
  1668. // Output : C_LocalTempEntity
  1669. //-----------------------------------------------------------------------------
  1670. C_LocalTempEntity *CTempEnts::TempEntAlloc()
  1671. {
  1672. if ( m_TempEnts.Count() >= MAX_TEMP_ENTITIES )
  1673. return NULL;
  1674. MEM_ALLOC_CREDIT();
  1675. C_LocalTempEntity *pTemp = m_TempEntsPool.AllocZero();
  1676. return pTemp;
  1677. }
  1678. void CTempEnts::TempEntFree( int index )
  1679. {
  1680. C_LocalTempEntity *pTemp = m_TempEnts[ index ];
  1681. if ( pTemp )
  1682. {
  1683. // Remove from the active list.
  1684. m_TempEnts.Remove( index );
  1685. // Cleanup its data.
  1686. pTemp->RemoveFromLeafSystem();
  1687. // Remove the tempent from the ClientEntityList before removing it from the pool.
  1688. if ( ( pTemp->flags & FTENT_CLIENTSIDEPARTICLES ) )
  1689. {
  1690. // Stop the particle emission if this hasn't happened already - collision or system timing out on its own.
  1691. if ( !pTemp->m_bParticleCollision )
  1692. {
  1693. pTemp->ParticleProp()->StopEmission();
  1694. }
  1695. ClientEntityList().RemoveEntity( pTemp->GetRefEHandle() );
  1696. }
  1697. pTemp->OnRemoveTempEntity();
  1698. m_TempEntsPool.Free( pTemp );
  1699. }
  1700. }
  1701. // Free the first low priority tempent it finds.
  1702. bool CTempEnts::FreeLowPriorityTempEnt()
  1703. {
  1704. int next = 0;
  1705. for( int i = m_TempEnts.Head(); i != m_TempEnts.InvalidIndex(); i = next )
  1706. {
  1707. next = m_TempEnts.Next( i );
  1708. C_LocalTempEntity *pActive = m_TempEnts[ i ];
  1709. if ( pActive->priority == TENTPRIORITY_LOW )
  1710. {
  1711. TempEntFree( i );
  1712. return true;
  1713. }
  1714. }
  1715. return false;
  1716. }
  1717. //-----------------------------------------------------------------------------
  1718. // Purpose: Allocate a temp entity, if there are no slots, kick out a low priority
  1719. // one if possible
  1720. // Input : *org -
  1721. // *model -
  1722. // Output : C_LocalTempEntity
  1723. //-----------------------------------------------------------------------------
  1724. C_LocalTempEntity *CTempEnts::TempEntAllocHigh( const Vector& org, model_t *model )
  1725. {
  1726. C_LocalTempEntity *pTemp;
  1727. if ( !model )
  1728. {
  1729. DevWarning( 1, "temporary ent model invalid\n" );
  1730. return NULL;
  1731. }
  1732. pTemp = TempEntAlloc();
  1733. if ( !pTemp )
  1734. {
  1735. // no temporary ents free, so find the first active low-priority temp ent
  1736. // and overwrite it.
  1737. FreeLowPriorityTempEnt();
  1738. pTemp = TempEntAlloc();
  1739. }
  1740. if ( !pTemp )
  1741. {
  1742. // didn't find anything? The tent list is either full of high-priority tents
  1743. // or all tents in the list are still due to live for > 10 seconds.
  1744. DevWarning( 1,"Couldn't alloc a high priority TENT (max %i)!\n", MAX_TEMP_ENTITIES );
  1745. return NULL;
  1746. }
  1747. m_TempEnts.AddToTail( pTemp );
  1748. pTemp->Prepare( model, gpGlobals->curtime );
  1749. pTemp->priority = TENTPRIORITY_HIGH;
  1750. pTemp->SetLocalOrigin( org );
  1751. pTemp->AddToLeafSystem( false );
  1752. if ( CommandLine()->CheckParm( "-tools" ) != NULL )
  1753. {
  1754. ClientEntityList().AddNonNetworkableEntity( pTemp );
  1755. }
  1756. return pTemp;
  1757. }
  1758. //-----------------------------------------------------------------------------
  1759. // Purpose: Play sound when temp ent collides with something
  1760. // Input : *pTemp -
  1761. // damp -
  1762. //-----------------------------------------------------------------------------
  1763. void CTempEnts::PlaySound ( C_LocalTempEntity *pTemp, float damp )
  1764. {
  1765. const char *soundname = NULL;
  1766. float fvol;
  1767. bool isshellcasing = false;
  1768. int zvel;
  1769. switch ( pTemp->hitSound )
  1770. {
  1771. default:
  1772. return; // null sound
  1773. case BOUNCE_GLASS:
  1774. {
  1775. soundname = "Bounce.Glass";
  1776. }
  1777. break;
  1778. case BOUNCE_METAL:
  1779. {
  1780. soundname = "Bounce.Metal";
  1781. }
  1782. break;
  1783. case BOUNCE_FLESH:
  1784. {
  1785. soundname = "Bounce.Flesh";
  1786. }
  1787. break;
  1788. case BOUNCE_WOOD:
  1789. {
  1790. soundname = "Bounce.Wood";
  1791. }
  1792. break;
  1793. case BOUNCE_SHRAP:
  1794. {
  1795. soundname = "Bounce.Shrapnel";
  1796. }
  1797. break;
  1798. case BOUNCE_SHOTSHELL:
  1799. {
  1800. soundname = "Bounce.ShotgunShell";
  1801. isshellcasing = true; // shell casings have different playback parameters
  1802. }
  1803. break;
  1804. case BOUNCE_SHELL:
  1805. {
  1806. soundname = "Bounce.Shell";
  1807. isshellcasing = true; // shell casings have different playback parameters
  1808. }
  1809. break;
  1810. case BOUNCE_CONCRETE:
  1811. {
  1812. soundname = "Bounce.Concrete";
  1813. }
  1814. break;
  1815. #ifdef CSTRIKE_DLL
  1816. case TE_PISTOL_SHELL:
  1817. {
  1818. soundname = "Bounce.PistolShell";
  1819. }
  1820. break;
  1821. case TE_RIFLE_SHELL:
  1822. {
  1823. soundname = "Bounce.RifleShell";
  1824. }
  1825. break;
  1826. case TE_SHOTGUN_SHELL:
  1827. {
  1828. soundname = "Bounce.ShotgunShell";
  1829. }
  1830. break;
  1831. #endif
  1832. }
  1833. zvel = abs( pTemp->GetVelocity()[2] );
  1834. // only play one out of every n
  1835. if ( isshellcasing )
  1836. {
  1837. // play first bounce, then 1 out of 3
  1838. if ( zvel < 200 && random->RandomInt(0,3) )
  1839. return;
  1840. }
  1841. else
  1842. {
  1843. if ( random->RandomInt(0,5) )
  1844. return;
  1845. }
  1846. CSoundParameters params;
  1847. if ( !C_BaseEntity::GetParametersForSound( soundname, params, NULL ) )
  1848. return;
  1849. fvol = params.volume;
  1850. if ( damp > 0.0 )
  1851. {
  1852. int pitch;
  1853. if ( isshellcasing )
  1854. {
  1855. fvol *= MIN(1.0, ((float)zvel) / 350.0);
  1856. }
  1857. else
  1858. {
  1859. fvol *= MIN(1.0, ((float)zvel) / 450.0);
  1860. }
  1861. if ( !random->RandomInt(0,3) && !isshellcasing )
  1862. {
  1863. pitch = random->RandomInt( params.pitchlow, params.pitchhigh );
  1864. }
  1865. else
  1866. {
  1867. pitch = params.pitch;
  1868. }
  1869. CLocalPlayerFilter filter;
  1870. EmitSound_t ep;
  1871. ep.m_nChannel = params.channel;
  1872. ep.m_pSoundName = params.soundname;
  1873. ep.m_flVolume = fvol;
  1874. ep.m_SoundLevel = params.soundlevel;
  1875. ep.m_nPitch = pitch;
  1876. ep.m_pOrigin = &pTemp->GetAbsOrigin();
  1877. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
  1878. }
  1879. }
  1880. //-----------------------------------------------------------------------------
  1881. // Purpose: Add temp entity to visible entities list of it's in PVS
  1882. // Input : *pEntity -
  1883. // Output : int
  1884. //-----------------------------------------------------------------------------
  1885. int CTempEnts::AddVisibleTempEntity( C_LocalTempEntity *pEntity )
  1886. {
  1887. int i;
  1888. Vector mins, maxs;
  1889. Vector model_mins, model_maxs;
  1890. if ( !pEntity->GetModel() )
  1891. return 0;
  1892. modelinfo->GetModelBounds( pEntity->GetModel(), model_mins, model_maxs );
  1893. for (i=0 ; i<3 ; i++)
  1894. {
  1895. mins[i] = pEntity->GetAbsOrigin()[i] + model_mins[i];
  1896. maxs[i] = pEntity->GetAbsOrigin()[i] + model_maxs[i];
  1897. }
  1898. // FIXME: Vis isn't setup by the time we get here, so this call fails if
  1899. // you try to add a tempent before the first frame is drawn, and it's
  1900. // one frame behind the rest of the time. Fix this.
  1901. // does the box intersect a visible leaf?
  1902. //if ( engine->IsBoxInViewCluster( mins, maxs ) )
  1903. {
  1904. // Temporary entities have no corresponding element in cl_entitylist
  1905. pEntity->index = -1;
  1906. // Add to list
  1907. pEntity->AddToLeafSystem( false );
  1908. return 1;
  1909. }
  1910. return 0;
  1911. }
  1912. //-----------------------------------------------------------------------------
  1913. // Purpose: Runs Temp Ent simulation routines
  1914. //-----------------------------------------------------------------------------
  1915. void CTempEnts::Update(void)
  1916. {
  1917. VPROF_("CTempEnts::Update", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
  1918. static int gTempEntFrame = 0;
  1919. float frametime;
  1920. // Don't simulate while loading
  1921. if ( ( m_TempEnts.Count() == 0 ) || !engine->IsInGame() )
  1922. {
  1923. return;
  1924. }
  1925. // !!!BUGBUG -- This needs to be time based
  1926. gTempEntFrame = (gTempEntFrame+1) & 31;
  1927. frametime = gpGlobals->frametime;
  1928. // in order to have tents collide with players, we have to run the player prediction code so
  1929. // that the client has the player list. We run this code once when we detect any COLLIDEALL
  1930. // tent, then set this BOOL to true so the code doesn't get run again if there's more than
  1931. // one COLLIDEALL ent for this update. (often are).
  1932. // !!! Don't simulate while paused.... This is sort of a hack, revisit.
  1933. if ( frametime == 0 )
  1934. {
  1935. FOR_EACH_LL( m_TempEnts, i )
  1936. {
  1937. C_LocalTempEntity *current = m_TempEnts[ i ];
  1938. AddVisibleTempEntity( current );
  1939. }
  1940. }
  1941. else
  1942. {
  1943. int next = 0;
  1944. for( int i = m_TempEnts.Head(); i != m_TempEnts.InvalidIndex(); i = next )
  1945. {
  1946. next = m_TempEnts.Next( i );
  1947. C_LocalTempEntity *current = m_TempEnts[ i ];
  1948. // Kill it
  1949. if ( !current->IsActive() || !current->Frame( frametime, gTempEntFrame ) )
  1950. {
  1951. TempEntFree( i );
  1952. }
  1953. else
  1954. {
  1955. // Cull to PVS (not frustum cull, just PVS)
  1956. if ( !AddVisibleTempEntity( current ) )
  1957. {
  1958. if ( !( current->flags & FTENT_PERSIST ) )
  1959. {
  1960. // If we can't draw it this frame, just dump it.
  1961. current->die = gpGlobals->curtime;
  1962. // Don't fade out, just die
  1963. current->flags &= ~FTENT_FADEOUT;
  1964. TempEntFree( i );
  1965. }
  1966. }
  1967. }
  1968. }
  1969. }
  1970. }
  1971. // Recache tempents which might have been flushed
  1972. void CTempEnts::LevelInit()
  1973. {
  1974. // We don't use any of these models in CSTRIKE15
  1975. #if !defined (CSTRIKE15)
  1976. #if !defined (TF_CLIENT_DLL) && !defined (DOTA_DLL) && !defined (PORTAL2)
  1977. m_pSpriteMuzzleFlash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1.vmt" );
  1978. m_pSpriteMuzzleFlash[1] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" );
  1979. m_pSpriteMuzzleFlash[2] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" );
  1980. m_pSpriteAR2Flash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1b.vmt" );
  1981. m_pSpriteAR2Flash[1] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle2b.vmt" );
  1982. m_pSpriteAR2Flash[2] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle3b.vmt" );
  1983. m_pSpriteAR2Flash[3] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle4b.vmt" );
  1984. m_pSpriteCombineFlash[0] = (model_t *)engine->LoadModel( "effects/combinemuzzle1.vmt" );
  1985. m_pSpriteCombineFlash[1] = (model_t *)engine->LoadModel( "effects/combinemuzzle2.vmt" );
  1986. m_pShells[0] = (model_t *) engine->LoadModel( "models/weapons/shell.mdl" );
  1987. m_pShells[1] = (model_t *) engine->LoadModel( "models/weapons/rifleshell.mdl" );
  1988. m_pShells[2] = (model_t *) engine->LoadModel( "models/weapons/shotgun_shell.mdl" );
  1989. #endif
  1990. #if defined( CSTRIKE_DLL ) || defined ( SDK_DLL )
  1991. m_pCS_9MMShell = (model_t *)engine->LoadModel( "models/Shells/shell_9mm.mdl" );
  1992. m_pCS_57Shell = (model_t *)engine->LoadModel( "models/Shells/shell_57.mdl" );
  1993. m_pCS_12GaugeShell = (model_t *)engine->LoadModel( "models/Shells/shell_12gauge.mdl" );
  1994. m_pCS_556Shell = (model_t *)engine->LoadModel( "models/Shells/shell_556.mdl" );
  1995. m_pCS_762NATOShell = (model_t *)engine->LoadModel( "models/Shells/shell_762nato.mdl" );
  1996. m_pCS_338MAGShell = (model_t *)engine->LoadModel( "models/Shells/shell_338mag.mdl" );
  1997. #endif
  1998. #endif
  1999. }
  2000. //-----------------------------------------------------------------------------
  2001. // Purpose: Initialize TE system
  2002. //-----------------------------------------------------------------------------
  2003. void CTempEnts::Init (void)
  2004. {
  2005. m_pSpriteMuzzleFlash[0] = NULL;
  2006. m_pSpriteMuzzleFlash[1] = NULL;
  2007. m_pSpriteMuzzleFlash[2] = NULL;
  2008. m_pSpriteAR2Flash[0] = NULL;
  2009. m_pSpriteAR2Flash[1] = NULL;
  2010. m_pSpriteAR2Flash[2] = NULL;
  2011. m_pSpriteAR2Flash[3] = NULL;
  2012. m_pSpriteCombineFlash[0] = NULL;
  2013. m_pSpriteCombineFlash[1] = NULL;
  2014. m_pShells[0] = NULL;
  2015. m_pShells[1] = NULL;
  2016. m_pShells[2] = NULL;
  2017. #if defined( CSTRIKE_DLL ) || defined ( SDK_DLL )
  2018. m_pCS_9MMShell = NULL;
  2019. m_pCS_57Shell = NULL;
  2020. m_pCS_12GaugeShell = NULL;
  2021. m_pCS_556Shell = NULL;
  2022. m_pCS_762NATOShell = NULL;
  2023. m_pCS_338MAGShell = NULL;
  2024. #endif
  2025. // Clear out lists to start
  2026. Clear();
  2027. }
  2028. void CTempEnts::LevelShutdown()
  2029. {
  2030. // Free all active tempents.
  2031. Clear();
  2032. }
  2033. //-----------------------------------------------------------------------------
  2034. // Purpose:
  2035. //-----------------------------------------------------------------------------
  2036. void CTempEnts::Shutdown()
  2037. {
  2038. LevelShutdown();
  2039. }
  2040. //-----------------------------------------------------------------------------
  2041. // Purpose: Cache off all material references
  2042. // Input : *pEmitter - Emitter used for material lookup
  2043. //-----------------------------------------------------------------------------
  2044. inline void CTempEnts::CacheMuzzleFlashes( void )
  2045. {
  2046. int i;
  2047. for ( i = 0; i < 4; i++ )
  2048. {
  2049. if ( m_Material_MuzzleFlash_Player[i] == NULL )
  2050. {
  2051. m_Material_MuzzleFlash_Player[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/muzzleflash%d_noz", i+1 ) );
  2052. }
  2053. }
  2054. for ( i = 0; i < 4; i++ )
  2055. {
  2056. if ( m_Material_MuzzleFlash_NPC[i] == NULL )
  2057. {
  2058. m_Material_MuzzleFlash_NPC[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/muzzleflash%d", i+1 ) );
  2059. }
  2060. }
  2061. for ( i = 0; i < 2; i++ )
  2062. {
  2063. if ( m_Material_Combine_MuzzleFlash_Player[i] == NULL )
  2064. {
  2065. m_Material_Combine_MuzzleFlash_Player[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/combinemuzzle%d_noz", i+1 ) );
  2066. }
  2067. }
  2068. for ( i = 0; i < 2; i++ )
  2069. {
  2070. if ( m_Material_Combine_MuzzleFlash_NPC[i] == NULL )
  2071. {
  2072. m_Material_Combine_MuzzleFlash_NPC[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/combinemuzzle%d", i+1 ) );
  2073. }
  2074. }
  2075. }
  2076. //-----------------------------------------------------------------------------
  2077. // Purpose:
  2078. // Input : entityIndex -
  2079. // attachmentIndex -
  2080. //-----------------------------------------------------------------------------
  2081. void CTempEnts::MuzzleFlash_Combine_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
  2082. {
  2083. VPROF_BUDGET( "MuzzleFlash_Combine_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2084. CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex, FLE_VIEWMODEL );
  2085. CacheMuzzleFlashes();
  2086. SimpleParticle *pParticle;
  2087. Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
  2088. float flScale = random->RandomFloat( 2.0f, 2.25f );
  2089. pSimple->SetDrawBeforeViewModel( true );
  2090. // Flash
  2091. for ( int i = 1; i < 6; i++ )
  2092. {
  2093. offset = (forward * (i*8.0f*flScale));
  2094. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Combine_MuzzleFlash_Player[random->RandomInt(0,1)], offset );
  2095. if ( pParticle == NULL )
  2096. return;
  2097. pParticle->m_flLifetime = 0.0f;
  2098. pParticle->m_flDieTime = 0.025f;
  2099. pParticle->m_vecVelocity.Init();
  2100. pParticle->m_uchColor[0] = 255;
  2101. pParticle->m_uchColor[1] = 255;
  2102. pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
  2103. pParticle->m_uchStartAlpha = 255;
  2104. pParticle->m_uchEndAlpha = 255;
  2105. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (12-(i))/12) * flScale );
  2106. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2107. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2108. pParticle->m_flRollDelta = 0.0f;
  2109. }
  2110. // Tack on the smoke
  2111. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Combine_MuzzleFlash_Player[random->RandomInt(0,1)], vec3_origin );
  2112. if ( pParticle == NULL )
  2113. return;
  2114. pParticle->m_flLifetime = 0.0f;
  2115. pParticle->m_flDieTime = 0.025f;
  2116. pParticle->m_vecVelocity.Init();
  2117. pParticle->m_uchColor[0] = 255;
  2118. pParticle->m_uchColor[1] = 255;
  2119. pParticle->m_uchColor[2] = 255;
  2120. pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
  2121. pParticle->m_uchEndAlpha = 32;
  2122. pParticle->m_uchStartSize = random->RandomFloat( 10.0f, 16.0f );
  2123. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2124. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2125. pParticle->m_flRollDelta = 0.0f;
  2126. }
  2127. //-----------------------------------------------------------------------------
  2128. // Purpose:
  2129. // Input : &origin -
  2130. // &angles -
  2131. // entityIndex -
  2132. //-----------------------------------------------------------------------------
  2133. void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attachmentIndex )
  2134. {
  2135. VPROF_BUDGET( "MuzzleFlash_Combine_NPC", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2136. CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Combine_NPC", hEntity, attachmentIndex );
  2137. SimpleParticle *pParticle;
  2138. Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
  2139. float flScale = random->RandomFloat( 1.0f, 1.5f );
  2140. float burstSpeed = random->RandomFloat( 50.0f, 150.0f );
  2141. #define FRONT_LENGTH 6
  2142. // Front flash
  2143. for ( int i = 1; i < FRONT_LENGTH; i++ )
  2144. {
  2145. offset = (forward * (i*2.0f*flScale));
  2146. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset );
  2147. if ( pParticle == NULL )
  2148. return;
  2149. pParticle->m_flLifetime = 0.0f;
  2150. pParticle->m_flDieTime = 0.1f;
  2151. pParticle->m_vecVelocity = forward * burstSpeed;
  2152. pParticle->m_uchColor[0] = 255;
  2153. pParticle->m_uchColor[1] = 255;
  2154. pParticle->m_uchColor[2] = 255;
  2155. pParticle->m_uchStartAlpha = 255.0f;
  2156. pParticle->m_uchEndAlpha = 0;
  2157. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (FRONT_LENGTH*1.25f-(i))/(FRONT_LENGTH)) * flScale );
  2158. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2159. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2160. pParticle->m_flRollDelta = 0.0f;
  2161. }
  2162. Vector right(0,1,0), up(0,0,1);
  2163. Vector dir = right - up;
  2164. #define SIDE_LENGTH 6
  2165. burstSpeed = random->RandomFloat( 50.0f, 150.0f );
  2166. // Diagonal flash
  2167. for ( int i = 1; i < SIDE_LENGTH; i++ )
  2168. {
  2169. offset = (dir * (i*flScale));
  2170. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset );
  2171. if ( pParticle == NULL )
  2172. return;
  2173. pParticle->m_flLifetime = 0.0f;
  2174. pParticle->m_flDieTime = 0.2f;
  2175. pParticle->m_vecVelocity = dir * burstSpeed * 0.25f;
  2176. pParticle->m_uchColor[0] = 255;
  2177. pParticle->m_uchColor[1] = 255;
  2178. pParticle->m_uchColor[2] = 255;
  2179. pParticle->m_uchStartAlpha = 255;
  2180. pParticle->m_uchEndAlpha = 0;
  2181. pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale );
  2182. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2183. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2184. pParticle->m_flRollDelta = 0.0f;
  2185. }
  2186. dir = right + up;
  2187. burstSpeed = random->RandomFloat( 50.0f, 150.0f );
  2188. // Diagonal flash
  2189. for ( int i = 1; i < SIDE_LENGTH; i++ )
  2190. {
  2191. offset = (-dir * (i*flScale));
  2192. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset );
  2193. if ( pParticle == NULL )
  2194. return;
  2195. pParticle->m_flLifetime = 0.0f;
  2196. pParticle->m_flDieTime = 0.2f;
  2197. pParticle->m_vecVelocity = dir * -burstSpeed * 0.25f;
  2198. pParticle->m_uchColor[0] = 255;
  2199. pParticle->m_uchColor[1] = 255;
  2200. pParticle->m_uchColor[2] = 255;
  2201. pParticle->m_uchStartAlpha = 255;
  2202. pParticle->m_uchEndAlpha = 0;
  2203. pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale );
  2204. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2205. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2206. pParticle->m_flRollDelta = 0.0f;
  2207. }
  2208. dir = up;
  2209. burstSpeed = random->RandomFloat( 50.0f, 150.0f );
  2210. // Top flash
  2211. for ( int i = 1; i < SIDE_LENGTH; i++ )
  2212. {
  2213. offset = (dir * (i*flScale));
  2214. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset );
  2215. if ( pParticle == NULL )
  2216. return;
  2217. pParticle->m_flLifetime = 0.0f;
  2218. pParticle->m_flDieTime = 0.2f;
  2219. pParticle->m_vecVelocity = dir * burstSpeed * 0.25f;
  2220. pParticle->m_uchColor[0] = 255;
  2221. pParticle->m_uchColor[1] = 255;
  2222. pParticle->m_uchColor[2] = 255;
  2223. pParticle->m_uchStartAlpha = 255;
  2224. pParticle->m_uchEndAlpha = 0;
  2225. pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale );
  2226. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2227. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2228. pParticle->m_flRollDelta = 0.0f;
  2229. }
  2230. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[2], vec3_origin );
  2231. if ( pParticle == NULL )
  2232. return;
  2233. pParticle->m_flLifetime = 0.0f;
  2234. pParticle->m_flDieTime = random->RandomFloat( 0.3f, 0.4f );
  2235. pParticle->m_vecVelocity.Init();
  2236. pParticle->m_uchColor[0] = 255;
  2237. pParticle->m_uchColor[1] = 255;
  2238. pParticle->m_uchColor[2] = 255;
  2239. pParticle->m_uchStartAlpha = 255;
  2240. pParticle->m_uchEndAlpha = 0;
  2241. pParticle->m_uchStartSize = flScale * random->RandomFloat( 12.0f, 16.0f );
  2242. pParticle->m_uchEndSize = 0.0f;
  2243. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2244. pParticle->m_flRollDelta = 0.0f;
  2245. matrix3x4_t matAttachment;
  2246. Vector origin;
  2247. // Grab the origin out of the transform for the attachment
  2248. if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) )
  2249. {
  2250. origin.x = matAttachment[0][3];
  2251. origin.y = matAttachment[1][3];
  2252. origin.z = matAttachment[2][3];
  2253. }
  2254. else
  2255. {
  2256. //NOTENOTE: If you're here, you've specified an entity or an attachment that is invalid
  2257. Assert(0);
  2258. return;
  2259. }
  2260. if ( muzzleflash_light.GetBool() )
  2261. {
  2262. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
  2263. if ( pEnt )
  2264. {
  2265. dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + pEnt->entindex() );
  2266. el->origin = origin;
  2267. el->color.r = 64;
  2268. el->color.g = 128;
  2269. el->color.b = 255;
  2270. el->color.exponent = 5;
  2271. el->radius = random->RandomInt( 32, 128 );
  2272. el->decay = el->radius / 0.05f;
  2273. el->die = gpGlobals->curtime + 0.05f;
  2274. }
  2275. }
  2276. }
  2277. //==================================================
  2278. // Purpose:
  2279. // Input:
  2280. //==================================================
  2281. void CTempEnts::MuzzleFlash_AR2_NPC( const Vector &origin, const QAngle &angles, ClientEntityHandle_t hEntity )
  2282. {
  2283. //Draw the cloud of fire
  2284. FX_MuzzleEffect( origin, angles, 1.0f, hEntity );
  2285. }
  2286. //-----------------------------------------------------------------------------
  2287. // Purpose:
  2288. //-----------------------------------------------------------------------------
  2289. void CTempEnts::MuzzleFlash_SMG1_NPC( ClientEntityHandle_t hEntity, int attachmentIndex )
  2290. {
  2291. //Draw the cloud of fire
  2292. FX_MuzzleEffectAttached( 1.0f, hEntity, attachmentIndex, NULL, true );
  2293. }
  2294. //-----------------------------------------------------------------------------
  2295. // Purpose:
  2296. //-----------------------------------------------------------------------------
  2297. void CTempEnts::MuzzleFlash_SMG1_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
  2298. {
  2299. VPROF_BUDGET( "MuzzleFlash_SMG1_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2300. CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_SMG1_Player", hEntity, attachmentIndex, FLE_VIEWMODEL );
  2301. CacheMuzzleFlashes();
  2302. SimpleParticle *pParticle;
  2303. Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
  2304. float flScale = random->RandomFloat( 1.25f, 1.5f );
  2305. pSimple->SetDrawBeforeViewModel( true );
  2306. // Flash
  2307. for ( int i = 1; i < 6; i++ )
  2308. {
  2309. offset = (forward * (i*8.0f*flScale));
  2310. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset );
  2311. if ( pParticle == NULL )
  2312. return;
  2313. pParticle->m_flLifetime = 0.0f;
  2314. pParticle->m_flDieTime = 0.025f;
  2315. pParticle->m_vecVelocity.Init();
  2316. pParticle->m_uchColor[0] = 255;
  2317. pParticle->m_uchColor[1] = 255;
  2318. pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
  2319. pParticle->m_uchStartAlpha = 255;
  2320. pParticle->m_uchEndAlpha = 255;
  2321. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale );
  2322. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2323. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2324. pParticle->m_flRollDelta = 0.0f;
  2325. }
  2326. }
  2327. //==================================================
  2328. // Purpose:
  2329. // Input:
  2330. //==================================================
  2331. void CTempEnts::MuzzleFlash_Shotgun_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
  2332. {
  2333. VPROF_BUDGET( "MuzzleFlash_Shotgun_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2334. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_Shotgun_Player" );
  2335. pSimple->SetDrawBeforeViewModel( true );
  2336. CacheMuzzleFlashes();
  2337. Vector origin;
  2338. QAngle angles;
  2339. // Get our attachment's transformation matrix
  2340. FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
  2341. pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
  2342. Vector forward;
  2343. AngleVectors( angles, &forward, NULL, NULL );
  2344. SimpleParticle *pParticle;
  2345. Vector offset;
  2346. float flScale = random->RandomFloat( 1.25f, 1.5f );
  2347. // Flash
  2348. for ( int i = 1; i < 6; i++ )
  2349. {
  2350. offset = origin + (forward * (i*8.0f*flScale));
  2351. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset );
  2352. if ( pParticle == NULL )
  2353. return;
  2354. pParticle->m_flLifetime = 0.0f;
  2355. pParticle->m_flDieTime = 0.0001f;
  2356. pParticle->m_vecVelocity.Init();
  2357. pParticle->m_uchColor[0] = 255;
  2358. pParticle->m_uchColor[1] = 255;
  2359. pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
  2360. pParticle->m_uchStartAlpha = 255;
  2361. pParticle->m_uchEndAlpha = 255;
  2362. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale );
  2363. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2364. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2365. pParticle->m_flRollDelta = 0.0f;
  2366. }
  2367. }
  2368. //==================================================
  2369. // Purpose:
  2370. // Input:
  2371. //==================================================
  2372. void CTempEnts::MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attachmentIndex )
  2373. {
  2374. //Draw the cloud of fire
  2375. FX_MuzzleEffectAttached( 0.75f, hEntity, attachmentIndex );
  2376. QAngle angles;
  2377. Vector forward;
  2378. int i;
  2379. // Setup the origin.
  2380. Vector origin;
  2381. IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( hEntity );
  2382. if ( !pRenderable )
  2383. return;
  2384. pRenderable->GetAttachment( attachmentIndex, origin, angles );
  2385. AngleVectors( angles, &forward );
  2386. //Embers less often
  2387. if ( random->RandomInt( 0, 2 ) == 0 )
  2388. {
  2389. //Embers
  2390. CSmartPtr<CEmberEffect> pEmbers = CEmberEffect::Create( "muzzle_embers" );
  2391. pEmbers->SetSortOrigin( origin );
  2392. SimpleParticle *pParticle;
  2393. int numEmbers = random->RandomInt( 0, 4 );
  2394. for ( int i = 0; i < numEmbers; i++ )
  2395. {
  2396. pParticle = (SimpleParticle *) pEmbers->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[0], origin );
  2397. if ( pParticle == NULL )
  2398. return;
  2399. pParticle->m_flLifetime = 0.0f;
  2400. pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
  2401. pParticle->m_vecVelocity.Random( -0.05f, 0.05f );
  2402. pParticle->m_vecVelocity += forward;
  2403. VectorNormalize( pParticle->m_vecVelocity );
  2404. pParticle->m_vecVelocity *= random->RandomFloat( 64.0f, 256.0f );
  2405. pParticle->m_uchColor[0] = 255;
  2406. pParticle->m_uchColor[1] = 128;
  2407. pParticle->m_uchColor[2] = 64;
  2408. pParticle->m_uchStartAlpha = 255;
  2409. pParticle->m_uchEndAlpha = 0;
  2410. pParticle->m_uchStartSize = 1;
  2411. pParticle->m_uchEndSize = 0;
  2412. pParticle->m_flRoll = 0;
  2413. pParticle->m_flRollDelta = 0;
  2414. }
  2415. }
  2416. //
  2417. // Trails
  2418. //
  2419. CSmartPtr<CTrailParticles> pTrails = CTrailParticles::Create( "MuzzleFlash_Shotgun_NPC" );
  2420. pTrails->SetSortOrigin( origin );
  2421. TrailParticle *pTrailParticle;
  2422. pTrails->SetFlag( bitsPARTICLE_TRAIL_FADE );
  2423. pTrails->m_ParticleCollision.SetGravity( 0.0f );
  2424. int numEmbers = random->RandomInt( 4, 8 );
  2425. for ( i = 0; i < numEmbers; i++ )
  2426. {
  2427. pTrailParticle = (TrailParticle *) pTrails->AddParticle( sizeof( TrailParticle ), g_Mat_SMG_Muzzleflash[0], origin );
  2428. if ( pTrailParticle == NULL )
  2429. return;
  2430. pTrailParticle->m_flLifetime = 0.0f;
  2431. pTrailParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.2f );
  2432. float spread = 0.05f;
  2433. pTrailParticle->m_vecVelocity.Random( -spread, spread );
  2434. pTrailParticle->m_vecVelocity += forward;
  2435. VectorNormalize( pTrailParticle->m_vecVelocity );
  2436. VectorNormalize( forward );
  2437. float dot = forward.Dot( pTrailParticle->m_vecVelocity );
  2438. dot = (1.0f-fabs(dot)) / spread;
  2439. pTrailParticle->m_vecVelocity *= (random->RandomFloat( 256.0f, 1024.0f ) * (1.0f-dot));
  2440. Color32Init( pTrailParticle->m_color, 255, 242, 191, 255 );
  2441. pTrailParticle->m_flLength = 0.05f;
  2442. pTrailParticle->m_flWidth = random->RandomFloat( 0.25f, 0.5f );
  2443. }
  2444. }
  2445. //==================================================
  2446. // Purpose:
  2447. //==================================================
  2448. void CTempEnts::MuzzleFlash_357_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
  2449. {
  2450. VPROF_BUDGET( "MuzzleFlash_357_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2451. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_357_Player" );
  2452. pSimple->SetDrawBeforeViewModel( true );
  2453. CacheMuzzleFlashes();
  2454. Vector origin;
  2455. QAngle angles;
  2456. // Get our attachment's transformation matrix
  2457. FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
  2458. pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
  2459. Vector forward;
  2460. AngleVectors( angles, &forward, NULL, NULL );
  2461. SimpleParticle *pParticle;
  2462. Vector offset;
  2463. // Smoke
  2464. offset = origin + forward * 8.0f;
  2465. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset );
  2466. if ( pParticle == NULL )
  2467. return;
  2468. pParticle->m_flLifetime = 0.0f;
  2469. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  2470. pParticle->m_vecVelocity.Init();
  2471. pParticle->m_vecVelocity = forward * random->RandomFloat( 8.0f, 64.0f );
  2472. pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
  2473. int color = random->RandomInt( 200, 255 );
  2474. pParticle->m_uchColor[0] = color;
  2475. pParticle->m_uchColor[1] = color;
  2476. pParticle->m_uchColor[2] = color;
  2477. pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
  2478. pParticle->m_uchEndAlpha = 0;
  2479. pParticle->m_uchStartSize = random->RandomInt( 2, 4 );
  2480. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8.0f;
  2481. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2482. pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
  2483. float flScale = random->RandomFloat( 1.25f, 1.5f );
  2484. // Flash
  2485. for ( int i = 1; i < 6; i++ )
  2486. {
  2487. offset = origin + (forward * (i*8.0f*flScale));
  2488. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset );
  2489. if ( pParticle == NULL )
  2490. return;
  2491. pParticle->m_flLifetime = 0.0f;
  2492. pParticle->m_flDieTime = 0.01f;
  2493. pParticle->m_vecVelocity.Init();
  2494. pParticle->m_uchColor[0] = 255;
  2495. pParticle->m_uchColor[1] = 255;
  2496. pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
  2497. pParticle->m_uchStartAlpha = 255;
  2498. pParticle->m_uchEndAlpha = 255;
  2499. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale );
  2500. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2501. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2502. pParticle->m_flRollDelta = 0.0f;
  2503. }
  2504. }
  2505. //==================================================
  2506. // Purpose:
  2507. // Input:
  2508. //==================================================
  2509. void CTempEnts::MuzzleFlash_Pistol_Player( ClientEntityHandle_t hEntity, int attachmentIndex )
  2510. {
  2511. VPROF_BUDGET( "MuzzleFlash_Pistol_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  2512. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_Pistol_Player" );
  2513. pSimple->SetDrawBeforeViewModel( true );
  2514. CacheMuzzleFlashes();
  2515. Vector origin;
  2516. QAngle angles;
  2517. // Get our attachment's transformation matrix
  2518. FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
  2519. pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
  2520. Vector forward;
  2521. AngleVectors( angles, &forward, NULL, NULL );
  2522. SimpleParticle *pParticle;
  2523. Vector offset;
  2524. // Smoke
  2525. offset = origin + forward * 8.0f;
  2526. if ( random->RandomInt( 0, 3 ) != 0 )
  2527. {
  2528. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset );
  2529. if ( pParticle == NULL )
  2530. return;
  2531. pParticle->m_flLifetime = 0.0f;
  2532. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  2533. pParticle->m_vecVelocity.Init();
  2534. pParticle->m_vecVelocity = forward * random->RandomFloat( 48.0f, 64.0f );
  2535. pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
  2536. int color = random->RandomInt( 200, 255 );
  2537. pParticle->m_uchColor[0] = color;
  2538. pParticle->m_uchColor[1] = color;
  2539. pParticle->m_uchColor[2] = color;
  2540. pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
  2541. pParticle->m_uchEndAlpha = 0;
  2542. pParticle->m_uchStartSize = random->RandomInt( 2, 4 );
  2543. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4.0f;
  2544. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2545. pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f );
  2546. }
  2547. float flScale = random->RandomFloat( 1.0f, 1.25f );
  2548. // Flash
  2549. for ( int i = 1; i < 6; i++ )
  2550. {
  2551. offset = origin + (forward * (i*4.0f*flScale));
  2552. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset );
  2553. if ( pParticle == NULL )
  2554. return;
  2555. pParticle->m_flLifetime = 0.0f;
  2556. pParticle->m_flDieTime = 0.01f;
  2557. pParticle->m_vecVelocity.Init();
  2558. pParticle->m_uchColor[0] = 255;
  2559. pParticle->m_uchColor[1] = 255;
  2560. pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
  2561. pParticle->m_uchStartAlpha = 255;
  2562. pParticle->m_uchEndAlpha = 255;
  2563. pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale );
  2564. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  2565. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  2566. pParticle->m_flRollDelta = 0.0f;
  2567. }
  2568. }
  2569. //==================================================
  2570. // Purpose:
  2571. // Input:
  2572. //==================================================
  2573. void CTempEnts::MuzzleFlash_Pistol_NPC( ClientEntityHandle_t hEntity, int attachmentIndex )
  2574. {
  2575. FX_MuzzleEffectAttached( 0.5f, hEntity, attachmentIndex, NULL, true );
  2576. }
  2577. //==================================================
  2578. // Purpose:
  2579. // Input:
  2580. //==================================================
  2581. void CTempEnts::MuzzleFlash_RPG_NPC( ClientEntityHandle_t hEntity, int attachmentIndex )
  2582. {
  2583. //Draw the cloud of fire
  2584. FX_MuzzleEffectAttached( 1.5f, hEntity, attachmentIndex );
  2585. }
  2586. void CTempEnts::RocketFlare( const Vector& pos )
  2587. {
  2588. C_LocalTempEntity *pTemp;
  2589. const model_t *model;
  2590. int nframeCount;
  2591. model = (model_t *)engine->LoadModel( "sprites/animglow01.vmt" );
  2592. if ( !model )
  2593. {
  2594. return;
  2595. }
  2596. nframeCount = modelinfo->GetModelFrameCount( model );
  2597. pTemp = TempEntAlloc( pos, (model_t *)model );
  2598. if ( !pTemp )
  2599. return;
  2600. pTemp->m_flFrameMax = nframeCount - 1;
  2601. pTemp->SetRenderMode( kRenderGlow );
  2602. pTemp->SetRenderFX( kRenderFxNoDissipation );
  2603. pTemp->tempent_renderamt = 255;
  2604. pTemp->m_flFrameRate = 1.0;
  2605. pTemp->m_flFrame = random->RandomInt( 0, nframeCount - 1);
  2606. pTemp->m_flSpriteScale = 1.0;
  2607. pTemp->SetAbsOrigin( pos );
  2608. pTemp->die = gpGlobals->curtime + 0.01;
  2609. }