Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3438 lines
90 KiB

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