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.

253 lines
6.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "grenade_ar2.h"
  9. #include "weapon_ar2.h"
  10. #include "soundent.h"
  11. #include "decals.h"
  12. #include "shake.h"
  13. #include "smoke_trail.h"
  14. #include "ar2_explosion.h"
  15. #include "vstdlib/random.h"
  16. #include "engine/IEngineSound.h"
  17. #include "world.h"
  18. #ifdef PORTAL
  19. #include "portal_util_shared.h"
  20. #endif
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. #define AR2_GRENADE_MAX_DANGER_RADIUS 300
  24. extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
  25. // Moved to HL2_SharedGameRules because these are referenced by shared AmmoDef functions
  26. extern ConVar sk_plr_dmg_smg1_grenade;
  27. extern ConVar sk_npc_dmg_smg1_grenade;
  28. extern ConVar sk_max_smg1_grenade;
  29. ConVar sk_smg1_grenade_radius ( "sk_smg1_grenade_radius","0");
  30. ConVar g_CV_SmokeTrail("smoke_trail", "1", 0); // temporary dust explosion switch
  31. BEGIN_DATADESC( CGrenadeAR2 )
  32. DEFINE_FIELD( m_hSmokeTrail, FIELD_EHANDLE ),
  33. DEFINE_FIELD( m_fSpawnTime, FIELD_TIME ),
  34. DEFINE_FIELD( m_fDangerRadius, FIELD_FLOAT ),
  35. // Function pointers
  36. DEFINE_ENTITYFUNC( GrenadeAR2Touch ),
  37. DEFINE_THINKFUNC( GrenadeAR2Think ),
  38. END_DATADESC()
  39. LINK_ENTITY_TO_CLASS( grenade_ar2, CGrenadeAR2 );
  40. void CGrenadeAR2::Spawn( void )
  41. {
  42. Precache( );
  43. SetSolid( SOLID_BBOX );
  44. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  45. // Hits everything but debris
  46. SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
  47. SetModel( "models/Weapons/ar2_grenade.mdl");
  48. UTIL_SetSize(this, Vector(-3, -3, -3), Vector(3, 3, 3));
  49. // UTIL_SetSize(this, Vector(0, 0, 0), Vector(0, 0, 0));
  50. SetUse( &CGrenadeAR2::DetonateUse );
  51. SetTouch( &CGrenadeAR2::GrenadeAR2Touch );
  52. SetThink( &CGrenadeAR2::GrenadeAR2Think );
  53. SetNextThink( gpGlobals->curtime + 0.1f );
  54. if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() )
  55. {
  56. m_flDamage = sk_plr_dmg_smg1_grenade.GetFloat();
  57. }
  58. else
  59. {
  60. m_flDamage = sk_npc_dmg_smg1_grenade.GetFloat();
  61. }
  62. m_DmgRadius = sk_smg1_grenade_radius.GetFloat();
  63. m_takedamage = DAMAGE_YES;
  64. m_bIsLive = true;
  65. m_iHealth = 1;
  66. SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for grenades to make them easier to see
  67. SetFriction( 0.8 );
  68. SetSequence( 0 );
  69. m_fDangerRadius = 100;
  70. m_fSpawnTime = gpGlobals->curtime;
  71. // -------------
  72. // Smoke trail.
  73. // -------------
  74. if( g_CV_SmokeTrail.GetInt() && !IsXbox() )
  75. {
  76. m_hSmokeTrail = SmokeTrail::CreateSmokeTrail();
  77. if( m_hSmokeTrail )
  78. {
  79. m_hSmokeTrail->m_SpawnRate = 48;
  80. m_hSmokeTrail->m_ParticleLifetime = 1;
  81. m_hSmokeTrail->m_StartColor.Init(0.1f, 0.1f, 0.1f);
  82. m_hSmokeTrail->m_EndColor.Init(0,0,0);
  83. m_hSmokeTrail->m_StartSize = 12;
  84. m_hSmokeTrail->m_EndSize = m_hSmokeTrail->m_StartSize * 4;
  85. m_hSmokeTrail->m_SpawnRadius = 4;
  86. m_hSmokeTrail->m_MinSpeed = 4;
  87. m_hSmokeTrail->m_MaxSpeed = 24;
  88. m_hSmokeTrail->m_Opacity = 0.2f;
  89. m_hSmokeTrail->SetLifetime(10.0f);
  90. m_hSmokeTrail->FollowEntity(this);
  91. }
  92. }
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: The grenade has a slight delay before it goes live. That way the
  96. // person firing it can bounce it off a nearby wall. However if it
  97. // hits another character it blows up immediately
  98. // Input :
  99. // Output :
  100. //-----------------------------------------------------------------------------
  101. void CGrenadeAR2::GrenadeAR2Think( void )
  102. {
  103. SetNextThink( gpGlobals->curtime + 0.05f );
  104. if (!m_bIsLive)
  105. {
  106. // Go live after a short delay
  107. if (m_fSpawnTime + MAX_AR2_NO_COLLIDE_TIME < gpGlobals->curtime)
  108. {
  109. m_bIsLive = true;
  110. }
  111. }
  112. // If I just went solid and my velocity is zero, it means I'm resting on
  113. // the floor already when I went solid so blow up
  114. if (m_bIsLive)
  115. {
  116. if (GetAbsVelocity().Length() == 0.0 ||
  117. GetGroundEntity() != NULL )
  118. {
  119. Detonate();
  120. }
  121. }
  122. // The old way of making danger sounds would scare the crap out of EVERYONE between you and where the grenade
  123. // was going to hit. The radius of the danger sound now 'blossoms' over the grenade's lifetime, making it seem
  124. // dangerous to a larger area downrange than it does from where it was fired.
  125. if( m_fDangerRadius <= AR2_GRENADE_MAX_DANGER_RADIUS )
  126. {
  127. m_fDangerRadius += ( AR2_GRENADE_MAX_DANGER_RADIUS * 0.05 );
  128. }
  129. CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin() + GetAbsVelocity() * 0.5, m_fDangerRadius, 0.2, this, SOUNDENT_CHANNEL_REPEATED_DANGER );
  130. }
  131. void CGrenadeAR2::Event_Killed( const CTakeDamageInfo &info )
  132. {
  133. Detonate( );
  134. }
  135. void CGrenadeAR2::GrenadeAR2Touch( CBaseEntity *pOther )
  136. {
  137. Assert( pOther );
  138. if ( !pOther->IsSolid() )
  139. return;
  140. // If I'm live go ahead and blow up
  141. if (m_bIsLive)
  142. {
  143. Detonate();
  144. }
  145. else
  146. {
  147. // If I'm not live, only blow up if I'm hitting an chacter that
  148. // is not the owner of the weapon
  149. CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pOther );
  150. if (pBCC && GetThrower() != pBCC)
  151. {
  152. m_bIsLive = true;
  153. Detonate();
  154. }
  155. }
  156. }
  157. void CGrenadeAR2::Detonate(void)
  158. {
  159. if (!m_bIsLive)
  160. {
  161. return;
  162. }
  163. m_bIsLive = false;
  164. m_takedamage = DAMAGE_NO;
  165. if(m_hSmokeTrail)
  166. {
  167. UTIL_Remove(m_hSmokeTrail);
  168. m_hSmokeTrail = NULL;
  169. }
  170. CPASFilter filter( GetAbsOrigin() );
  171. te->Explosion( filter, 0.0,
  172. &GetAbsOrigin(),
  173. g_sModelIndexFireball,
  174. 2.0,
  175. 15,
  176. TE_EXPLFLAG_NONE,
  177. m_DmgRadius,
  178. m_flDamage );
  179. Vector vecForward = GetAbsVelocity();
  180. VectorNormalize(vecForward);
  181. trace_t tr;
  182. UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SHOT,
  183. this, COLLISION_GROUP_NONE, &tr);
  184. if ((tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0))
  185. {
  186. // non-world needs smaller decals
  187. if( tr.m_pEnt && !tr.m_pEnt->IsNPC() )
  188. {
  189. UTIL_DecalTrace( &tr, "SmallScorch" );
  190. }
  191. }
  192. else
  193. {
  194. UTIL_DecalTrace( &tr, "Scorch" );
  195. }
  196. UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START );
  197. RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
  198. UTIL_Remove( this );
  199. }
  200. void CGrenadeAR2::Precache( void )
  201. {
  202. PrecacheModel("models/Weapons/ar2_grenade.mdl");
  203. }
  204. CGrenadeAR2::CGrenadeAR2(void)
  205. {
  206. m_hSmokeTrail = NULL;
  207. }