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.

333 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "particles_simple.h"
  8. #include "particles_localspace.h"
  9. #include "c_te_effect_dispatch.h"
  10. #include "clienteffectprecachesystem.h"
  11. #include "tier0/vprof.h"
  12. #include "fx.h"
  13. #include "r_efx.h"
  14. #include "tier1/KeyValues.h"
  15. #include "dlight.h"
  16. #include "tf_shareddefs.h"
  17. #include "tf_fx_muzzleflash.h"
  18. #include "toolframework/itoolframework.h"
  19. #include "IEffects.h"
  20. #include "fx_sparks.h"
  21. #include "iefx.h"
  22. #include "fx_quad.h"
  23. #include "fx.h"
  24. #include "toolframework_client.h"
  25. // Precache our effects
  26. CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffect_TF_MuzzleFlash )
  27. CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" )
  28. CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" )
  29. CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" )
  30. CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" )
  31. CLIENTEFFECT_REGISTER_END()
  32. ConVar cl_muzzleflash_dlight_1st( "cl_muzzleflash_dlight_1st", "1" );
  33. void TE_DynamicLight( IRecipientFilter& filter, float delay,
  34. const Vector* org, int r, int g, int b, int exponent, float radius, float time, float decay, int nLightIndex = LIGHT_INDEX_TE_DYNAMIC );
  35. extern PMaterialHandle g_Material_Spark;
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. //-----------------------------------------------------------------------------
  39. void TF_3rdPersonMuzzleFlashCallback( const CEffectData &data )
  40. {
  41. float scale = data.m_flMagnitude;
  42. int attachmentIndex = data.m_nAttachmentIndex;
  43. CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", data.m_hEntity, attachmentIndex, 0 );
  44. Vector forward(1,0,0), offset, right(0,1,0);
  45. //
  46. // Flash
  47. //
  48. if ( data.m_nHitBox > 0 ) // >0 is a mg flash in script based muzzleflashes ..
  49. {
  50. offset = vec3_origin;
  51. // small inner cone
  52. scale *= 4;
  53. float flScale = random->RandomFloat( scale-0.1f, scale+0.1f );
  54. for ( int i = 1; i < 9; i++ )
  55. {
  56. offset = (forward * (i*2.0f*scale));
  57. SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
  58. if ( pParticle == NULL )
  59. return;
  60. pParticle->m_flLifetime = 0.0f;
  61. pParticle->m_flDieTime = 0.1f;
  62. pParticle->m_vecVelocity.Init();
  63. pParticle->m_uchColor[0] = 255;
  64. pParticle->m_uchColor[1] = 255;
  65. pParticle->m_uchColor[2] = 255;
  66. pParticle->m_uchStartAlpha = 255;
  67. pParticle->m_uchEndAlpha = 128;
  68. pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
  69. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  70. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  71. pParticle->m_flRollDelta = 0.0f;
  72. }
  73. }
  74. else
  75. {
  76. scale *= 4;
  77. float flScale = random->RandomFloat( scale-0.1f, scale+0.1f );
  78. for ( int i = 1; i < 9; i++ )
  79. {
  80. offset = (forward * (i*2.0f*scale));
  81. SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
  82. if ( pParticle == NULL )
  83. return;
  84. pParticle->m_flLifetime = 0.0f;
  85. pParticle->m_flDieTime = 0.1f;
  86. pParticle->m_vecVelocity.Init();
  87. pParticle->m_uchColor[0] = 255;
  88. pParticle->m_uchColor[1] = 255;
  89. pParticle->m_uchColor[2] = 255;
  90. pParticle->m_uchStartAlpha = 128;
  91. pParticle->m_uchEndAlpha = 64;
  92. pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
  93. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  94. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  95. pParticle->m_flRollDelta = 0.0f;
  96. }
  97. }
  98. //Smoke
  99. int i;
  100. offset = vec3_origin;
  101. for( i=0;i<3;i++ )
  102. {
  103. SimpleParticle *pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset );
  104. if ( pParticle )
  105. {
  106. pParticle->m_flLifetime = 0.0f;
  107. pParticle->m_flDieTime = 0.3f;
  108. pParticle->m_vecVelocity.Init();
  109. pParticle->m_vecVelocity = forward * ( random->RandomFloat( 80.0f, 100.0f ) + (2-i)*15 );
  110. int color = random->RandomInt( 200, 255 );
  111. pParticle->m_uchColor[0] = color;
  112. pParticle->m_uchColor[1] = color;
  113. pParticle->m_uchColor[2] = color;
  114. pParticle->m_uchStartAlpha = 32;
  115. pParticle->m_uchEndAlpha = 0;
  116. pParticle->m_uchStartSize = ( 4.0 + 3.0*(2-i) ) * data.m_flMagnitude;
  117. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 13.0f;
  118. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  119. pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
  120. }
  121. }
  122. }
  123. void TF_3rdPersonMuzzleFlashCallback_SentryGun( const CEffectData &data )
  124. {
  125. int iMuzzleFlashAttachment = data.m_nAttachmentIndex;
  126. int iUpgradeLevel = data.m_fFlags;
  127. C_BaseEntity *pEnt = data.GetEntity();
  128. if ( pEnt && !pEnt->IsDormant() )
  129. {
  130. // The created entity kills itself
  131. //C_MuzzleFlashModel::CreateMuzzleFlashModel( "models/effects/sentry1_muzzle/sentry1_muzzle.mdl", pEnt, iMuzzleFlashAttachment );
  132. const char *pszMuzzleFlashParticleEffect = NULL;
  133. switch( iUpgradeLevel )
  134. {
  135. case 1:
  136. default:
  137. pszMuzzleFlashParticleEffect = "muzzle_sentry";
  138. break;
  139. case 2:
  140. case 3:
  141. pszMuzzleFlashParticleEffect = "muzzle_sentry2";
  142. break;
  143. }
  144. DispatchParticleEffect( pszMuzzleFlashParticleEffect, PATTACH_POINT_FOLLOW, pEnt, iMuzzleFlashAttachment );
  145. }
  146. }
  147. //TODO: Come back and make this guy a nice particle.
  148. DECLARE_CLIENT_EFFECT( "TF_3rdPersonMuzzleFlash", TF_3rdPersonMuzzleFlashCallback );
  149. DECLARE_CLIENT_EFFECT( "TF_3rdPersonMuzzleFlash_SentryGun", TF_3rdPersonMuzzleFlashCallback_SentryGun );
  150. //-----------------------------------------------------------------------------
  151. // Purpose:
  152. // Input : *pszModelName -
  153. // vecOrigin -
  154. // vecForceDir -
  155. // vecAngularImp -
  156. // Output : Returns true on success, false on failure.
  157. //-----------------------------------------------------------------------------
  158. C_MuzzleFlashModel *C_MuzzleFlashModel::CreateMuzzleFlashModel( const char *pszModelName, C_BaseEntity *pParent, int iAttachment, float flLifetime )
  159. {
  160. C_MuzzleFlashModel *pFlash = new C_MuzzleFlashModel;
  161. if ( !pFlash )
  162. return NULL;
  163. if ( !pFlash->InitializeMuzzleFlash( pszModelName, pParent, iAttachment, flLifetime ) )
  164. return NULL;
  165. return pFlash;
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. //-----------------------------------------------------------------------------
  170. bool C_MuzzleFlashModel::InitializeMuzzleFlash( const char *pszModelName, C_BaseEntity *pParent, int iAttachment, float flLifetime )
  171. {
  172. AddEffects( EF_NORECEIVESHADOW | EF_NOSHADOW );
  173. if ( InitializeAsClientEntity( pszModelName, RENDER_GROUP_OPAQUE_ENTITY ) == false )
  174. {
  175. Release();
  176. return false;
  177. }
  178. SetParent( pParent, iAttachment );
  179. SetLocalOrigin( vec3_origin );
  180. SetLocalAngles( vec3_angle );
  181. AddSolidFlags( FSOLID_NOT_SOLID );
  182. m_flRotateAt = gpGlobals->curtime + 0.2;
  183. SetLifetime( flLifetime );
  184. SetNextClientThink( CLIENT_THINK_ALWAYS );
  185. SetCycle( 0 );
  186. return true;
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Purpose:
  190. //-----------------------------------------------------------------------------
  191. void C_MuzzleFlashModel::SetLifetime( float flLifetime )
  192. {
  193. // Expire when the lifetime is up
  194. m_flExpiresAt = gpGlobals->curtime + flLifetime;
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. //-----------------------------------------------------------------------------
  199. void C_MuzzleFlashModel::ClientThink( void )
  200. {
  201. if ( !GetMoveParent() || gpGlobals->curtime > m_flExpiresAt )
  202. {
  203. Release();
  204. return;
  205. }
  206. if ( gpGlobals->curtime > m_flRotateAt )
  207. {
  208. // Pick a new anim frame
  209. float flDelta = RandomFloat(0.2,0.4) * (RandomInt(0,1) == 1 ? 1 : -1);
  210. float flCycle = clamp( GetCycle() + flDelta, 0.f, 1.f );
  211. SetCycle( flCycle );
  212. SetLocalAngles( QAngle(0,0,RandomFloat(0,360)) );
  213. m_flRotateAt = gpGlobals->curtime + 0.075;
  214. }
  215. }
  216. //-----------------------------------------------------------------------------
  217. // This is an incredibly brutal hack to get muzzle flashes positioned correctly for recording
  218. //-----------------------------------------------------------------------------
  219. void C_MuzzleFlashModel::SetIs3rdPersonFlash( bool bEnable )
  220. {
  221. m_bIs3rdPersonFlash = bEnable;
  222. }
  223. bool C_MuzzleFlashModel::SetupBones( matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime )
  224. {
  225. // FIXME: This is an incredibly brutal hack to get muzzle flashes positioned correctly for recording
  226. // NOTE: The correct, long-term solution, is to make weapon models
  227. // always store the 3rd person model and to have view model entities
  228. // always store the 1st person model. I didn't have time to do that for Leipzig.
  229. int nModelIndex = 0;
  230. int nWorldModelIndex = 0;
  231. CBaseCombatWeapon *pParent = dynamic_cast<CBaseCombatWeapon*>( GetMoveParent() );
  232. if ( m_bIs3rdPersonFlash && pParent )
  233. {
  234. nModelIndex = pParent->GetModelIndex();
  235. nWorldModelIndex = pParent->GetWorldModelIndex();
  236. pParent->SetModelIndex( nWorldModelIndex );
  237. }
  238. bool bResult = BaseClass::SetupBones( pBoneToWorldOut, nMaxBones, boneMask, currentTime );
  239. if ( m_bIs3rdPersonFlash && pParent )
  240. {
  241. pParent->SetModelIndex( nModelIndex );
  242. }
  243. return bResult;
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Recording
  247. //-----------------------------------------------------------------------------
  248. void C_MuzzleFlashModel::GetToolRecordingState( KeyValues *msg )
  249. {
  250. if ( !ToolsEnabled() )
  251. return;
  252. VPROF_BUDGET( "C_MuzzleFlashModel::GetToolRecordingState", VPROF_BUDGETGROUP_TOOLS );
  253. BaseClass::GetToolRecordingState( msg );
  254. C_BaseEntity *pParent = GetMoveParent();
  255. if ( pParent )
  256. {
  257. BaseEntityRecordingState_t *pBaseEntity = (BaseEntityRecordingState_t*)msg->GetPtr( "baseentity" );
  258. pBaseEntity->m_nOwner = pParent->entindex();
  259. // FIXME: This recording path is a giant hack in a cascading series of hacks
  260. C_BaseCombatWeapon *pParentWeapon = dynamic_cast<C_BaseCombatWeapon*>( pParent );
  261. if ( pParentWeapon )
  262. {
  263. if ( pParentWeapon->WeaponState() == WEAPON_NOT_CARRIED )
  264. {
  265. pBaseEntity->m_bVisible = false;
  266. }
  267. }
  268. }
  269. }