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.

242 lines
6.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Game-specific explosion effects
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "c_te_effect_dispatch.h"
  8. #include "tempent.h"
  9. #include "c_te_legacytempents.h"
  10. #include "tf_shareddefs.h"
  11. #include "engine/IEngineSound.h"
  12. #include "tf_weapon_parse.h"
  13. #include "c_basetempentity.h"
  14. #include "tier0/vprof.h"
  15. #include "c_tf_player.h"
  16. #include "econ_item_system.h"
  17. #include "c_tf_fx.h"
  18. #include "networkstringtabledefs.h"
  19. //--------------------------------------------------------------------------------------------------------------
  20. CTFWeaponInfo *GetTFWeaponInfo( int iWeapon )
  21. {
  22. // Get the weapon information.
  23. const char *pszWeaponAlias = WeaponIdToAlias( iWeapon );
  24. if ( !pszWeaponAlias )
  25. {
  26. return NULL;
  27. }
  28. WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( pszWeaponAlias );
  29. if ( hWpnInfo == GetInvalidWeaponInfoHandle() )
  30. {
  31. return NULL;
  32. }
  33. CTFWeaponInfo *pWeaponInfo = static_cast<CTFWeaponInfo*>( GetFileWeaponInfoFromHandle( hWpnInfo ) );
  34. return pWeaponInfo;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. //-----------------------------------------------------------------------------
  39. void TFExplosionCallback( const Vector &vecOrigin, const Vector &vecNormal, int iWeaponID, ClientEntityHandle_t hEntity, int nDefID, int nSound, int iCustomParticleIndex )
  40. {
  41. // Get the weapon information.
  42. CTFWeaponInfo *pWeaponInfo = NULL;
  43. switch( iWeaponID )
  44. {
  45. case TF_WEAPON_GRENADE_PIPEBOMB:
  46. case TF_WEAPON_GRENADE_DEMOMAN:
  47. case TF_WEAPON_PUMPKIN_BOMB:
  48. pWeaponInfo = GetTFWeaponInfo( TF_WEAPON_PIPEBOMBLAUNCHER );
  49. break;
  50. case TF_WEAPON_FLAMETHROWER_ROCKET:
  51. pWeaponInfo = GetTFWeaponInfo( TF_WEAPON_FLAMETHROWER );
  52. break;
  53. default:
  54. pWeaponInfo = GetTFWeaponInfo( iWeaponID );
  55. break;
  56. }
  57. bool bIsPlayer = false;
  58. if ( hEntity.Get() )
  59. {
  60. C_BaseEntity *pEntity = C_BaseEntity::Instance( hEntity );
  61. if ( pEntity && pEntity->IsPlayer() )
  62. {
  63. bIsPlayer = true;
  64. }
  65. }
  66. // Calculate the angles, given the normal.
  67. bool bIsWater = ( UTIL_PointContents( vecOrigin ) & CONTENTS_WATER );
  68. bool bInAir = false;
  69. QAngle angExplosion( 0.0f, 0.0f, 0.0f );
  70. // Cannot use zeros here because we are sending the normal at a smaller bit size.
  71. if ( fabs( vecNormal.x ) < 0.05f && fabs( vecNormal.y ) < 0.05f && fabs( vecNormal.z ) < 0.05f )
  72. {
  73. bInAir = true;
  74. angExplosion.Init();
  75. }
  76. else
  77. {
  78. VectorAngles( vecNormal, angExplosion );
  79. bInAir = false;
  80. }
  81. // Base explosion effect and sound.
  82. const char *pszEffect = "ExplosionCore_wall";
  83. const char *pszSound = "BaseExplosionEffect.Sound";
  84. // check for a custom particle effect
  85. if ( iCustomParticleIndex != INVALID_STRING_INDEX )
  86. {
  87. pszEffect = GetParticleSystemNameFromIndex( iCustomParticleIndex );
  88. }
  89. if ( pWeaponInfo )
  90. {
  91. // Explosions.
  92. if ( iCustomParticleIndex == INVALID_STRING_INDEX )
  93. {
  94. if ( bIsWater )
  95. {
  96. if ( Q_strlen( pWeaponInfo->m_szExplosionWaterEffect ) > 0 )
  97. {
  98. pszEffect = pWeaponInfo->m_szExplosionWaterEffect;
  99. }
  100. }
  101. else
  102. {
  103. if ( bIsPlayer || bInAir )
  104. {
  105. if ( Q_strlen( pWeaponInfo->m_szExplosionPlayerEffect ) > 0 )
  106. {
  107. pszEffect = pWeaponInfo->m_szExplosionPlayerEffect;
  108. }
  109. }
  110. else
  111. {
  112. if ( Q_strlen( pWeaponInfo->m_szExplosionEffect ) > 0 )
  113. {
  114. pszEffect = pWeaponInfo->m_szExplosionEffect;
  115. }
  116. }
  117. }
  118. }
  119. // Sound.
  120. if ( Q_strlen( pWeaponInfo->m_szExplosionSound ) > 0 )
  121. {
  122. // Check for a replacement sound in the itemdef first - defaults to SPECIAL1
  123. if ( nDefID >= 0 )
  124. {
  125. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  126. if ( pLocalPlayer )
  127. {
  128. CEconItemDefinition *pItemDef = ItemSystem()->GetStaticDataForItemByDefIndex( nDefID );
  129. if ( pItemDef )
  130. {
  131. pszSound = (char *)pItemDef->GetWeaponReplacementSound( pLocalPlayer->GetTeamNumber(), (WeaponSound_t)nSound );
  132. if ( !pszSound || !pszSound[0] )
  133. {
  134. pszSound = pWeaponInfo->m_szExplosionSound;
  135. }
  136. }
  137. }
  138. }
  139. else
  140. {
  141. pszSound = pWeaponInfo->m_szExplosionSound;
  142. }
  143. }
  144. }
  145. if ( iWeaponID == TF_WEAPON_PUMPKIN_BOMB )
  146. {
  147. pszSound = "Halloween.PumpkinExplode";
  148. }
  149. CLocalPlayerFilter filter;
  150. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, pszSound, &vecOrigin );
  151. if ( GameRules() )
  152. {
  153. pszEffect = GameRules()->TranslateEffectForVisionFilter( "particles", pszEffect );
  154. }
  155. DispatchParticleEffect( pszEffect, vecOrigin, angExplosion );
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Purpose:
  159. //-----------------------------------------------------------------------------
  160. class C_TETFExplosion : public C_BaseTempEntity
  161. {
  162. public:
  163. DECLARE_CLASS( C_TETFExplosion, C_BaseTempEntity );
  164. DECLARE_CLIENTCLASS();
  165. C_TETFExplosion( void );
  166. virtual void PostDataUpdate( DataUpdateType_t updateType );
  167. public:
  168. Vector m_vecOrigin;
  169. Vector m_vecNormal;
  170. int m_iWeaponID;
  171. ClientEntityHandle_t m_hEntity;
  172. int m_nDefID;
  173. int m_nSound;
  174. int m_iCustomParticleIndex;
  175. };
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. C_TETFExplosion::C_TETFExplosion( void )
  180. {
  181. m_vecOrigin.Init();
  182. m_vecNormal.Init();
  183. m_iWeaponID = TF_WEAPON_NONE;
  184. m_hEntity = INVALID_EHANDLE_INDEX;
  185. m_nDefID = -1;
  186. m_nSound = SPECIAL1;
  187. m_iCustomParticleIndex = INVALID_STRING_INDEX;
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Purpose:
  191. //-----------------------------------------------------------------------------
  192. void C_TETFExplosion::PostDataUpdate( DataUpdateType_t updateType )
  193. {
  194. VPROF( "C_TETFExplosion::PostDataUpdate" );
  195. TFExplosionCallback( m_vecOrigin, m_vecNormal, m_iWeaponID, m_hEntity, m_nDefID, m_nSound, m_iCustomParticleIndex );
  196. }
  197. static void RecvProxy_ExplosionEntIndex( const CRecvProxyData *pData, void *pStruct, void *pOut )
  198. {
  199. int nEntIndex = pData->m_Value.m_Int;
  200. // The 'new' encoding for INVALID_EHANDLE_INDEX is 2047, but the old encoding
  201. // was -1. Old demos and replays will use the old encoding so we have to check
  202. // for it. The field is now unsigned so -1 will not be created in new replays.
  203. ((C_TETFExplosion*)pStruct)->m_hEntity = (nEntIndex == kInvalidEHandleExplosion || nEntIndex == -1) ? INVALID_EHANDLE_INDEX : ClientEntityList().EntIndexToHandle( nEntIndex );
  204. }
  205. IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TETFExplosion, DT_TETFExplosion, CTETFExplosion )
  206. RecvPropFloat( RECVINFO( m_vecOrigin[0] ) ),
  207. RecvPropFloat( RECVINFO( m_vecOrigin[1] ) ),
  208. RecvPropFloat( RECVINFO( m_vecOrigin[2] ) ),
  209. RecvPropVector( RECVINFO( m_vecNormal ) ),
  210. RecvPropInt( RECVINFO( m_iWeaponID ) ),
  211. RecvPropInt( "entindex", 0, SIZEOF_IGNORE, 0, RecvProxy_ExplosionEntIndex ),
  212. RecvPropInt( RECVINFO( m_nDefID ) ),
  213. RecvPropInt( RECVINFO( m_nSound ) ),
  214. RecvPropInt( RECVINFO( m_iCustomParticleIndex ) ),
  215. END_RECV_TABLE()