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.

330 lines
9.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: This is the brickbat weapon
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "grenade_pathfollower.h"
  9. #include "soundent.h"
  10. #include "decals.h"
  11. #include "shake.h"
  12. #include "smoke_trail.h"
  13. #include "entitylist.h"
  14. #include "vstdlib/random.h"
  15. #include "engine/IEngineSound.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. #define GRENADE_PF_TURN_RATE 30
  19. #define GRENADE_PF_TOLERANCE 300
  20. #define GRENADE_PF_MODEL "models/Weapons/w_missile.mdl"
  21. extern short g_sModelIndexFireball; // (in combatweapon.cpp) holds the index for the smoke cloud
  22. ConVar sk_dmg_pathfollower_grenade ( "sk_dmg_pathfollower_grenade","0");
  23. ConVar sk_pathfollower_grenade_radius ( "sk_pathfollower_grenade_radius","0");
  24. BEGIN_DATADESC( CGrenadePathfollower )
  25. DEFINE_FIELD( m_pPathTarget, FIELD_CLASSPTR ),
  26. DEFINE_FIELD( m_flFlySpeed, FIELD_FLOAT ),
  27. DEFINE_FIELD( m_sFlySound, FIELD_SOUNDNAME ),
  28. DEFINE_FIELD( m_flNextFlySoundTime, FIELD_TIME),
  29. DEFINE_FIELD( m_hRocketTrail, FIELD_EHANDLE),
  30. DEFINE_THINKFUNC( AimThink ),
  31. // Function pointers
  32. DEFINE_ENTITYFUNC( GrenadeTouch ),
  33. END_DATADESC()
  34. LINK_ENTITY_TO_CLASS( grenade_pathfollower, CGrenadePathfollower );
  35. void CGrenadePathfollower::Precache()
  36. {
  37. BaseClass::Precache();
  38. PrecacheScriptSound( "GrenadePathfollower.StopSounds" );
  39. }
  40. void CGrenadePathfollower::Spawn( void )
  41. {
  42. Precache( );
  43. // -------------------------
  44. // Inert when first spawned
  45. // -------------------------
  46. SetSolid( SOLID_BBOX );
  47. AddSolidFlags( FSOLID_NOT_SOLID );
  48. SetMoveType( MOVETYPE_NONE );
  49. AddFlag( FL_OBJECT ); // So can be shot down
  50. AddEffects( EF_NODRAW );
  51. UTIL_SetSize(this, Vector(0, 0, 0), Vector(0, 0, 0));
  52. m_flDamage = sk_dmg_pathfollower_grenade.GetFloat();
  53. m_DmgRadius = sk_pathfollower_grenade_radius.GetFloat();
  54. m_takedamage = DAMAGE_YES;
  55. m_iHealth = 200;
  56. SetGravity( 0.00001 );
  57. SetFriction( 0.8 );
  58. SetSequence( 1 );
  59. }
  60. void CGrenadePathfollower::Event_Killed( const CTakeDamageInfo &info )
  61. {
  62. Detonate( );
  63. }
  64. void CGrenadePathfollower::GrenadeTouch( CBaseEntity *pOther )
  65. {
  66. // ----------------------------------
  67. // If I hit the sky, don't explode
  68. // ----------------------------------
  69. trace_t tr;
  70. UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity(), MASK_SOLID_BRUSHONLY,
  71. this, COLLISION_GROUP_NONE, &tr);
  72. if (tr.surface.flags & SURF_SKY)
  73. {
  74. if(m_hRocketTrail)
  75. {
  76. UTIL_Remove(m_hRocketTrail);
  77. m_hRocketTrail = NULL;
  78. }
  79. UTIL_Remove( this );
  80. }
  81. Detonate();
  82. }
  83. //------------------------------------------------------------------------------
  84. // Purpose :
  85. // Input :
  86. // Output :
  87. //------------------------------------------------------------------------------
  88. void CGrenadePathfollower::Detonate(void)
  89. {
  90. StopSound(entindex(), CHAN_BODY, STRING(m_sFlySound));
  91. m_takedamage = DAMAGE_NO;
  92. if(m_hRocketTrail)
  93. {
  94. UTIL_Remove(m_hRocketTrail);
  95. m_hRocketTrail = NULL;
  96. }
  97. CPASFilter filter( GetAbsOrigin() );
  98. te->Explosion( filter, 0.0,
  99. &GetAbsOrigin(),
  100. g_sModelIndexFireball,
  101. 0.5,
  102. 15,
  103. TE_EXPLFLAG_NONE,
  104. m_DmgRadius,
  105. m_flDamage );
  106. Vector vecForward = GetAbsVelocity();
  107. VectorNormalize(vecForward);
  108. trace_t tr;
  109. UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, & tr);
  110. UTIL_DecalTrace( &tr, "Scorch" );
  111. UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START );
  112. CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 400, 0.2 );
  113. RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL );
  114. CPASAttenuationFilter filter2( this, "GrenadePathfollower.StopSounds" );
  115. EmitSound( filter2, entindex(), "GrenadePathfollower.StopSounds" );
  116. UTIL_Remove( this );
  117. }
  118. //------------------------------------------------------------------------------
  119. // Purpose :
  120. // Input :
  121. // Output :
  122. //------------------------------------------------------------------------------
  123. void CGrenadePathfollower::Launch( float flLaunchSpeed, string_t sPathCornerName)
  124. {
  125. m_pPathTarget = gEntList.FindEntityByName( NULL, sPathCornerName );
  126. if (m_pPathTarget)
  127. {
  128. m_flFlySpeed = flLaunchSpeed;
  129. Vector vTargetDir = (m_pPathTarget->GetAbsOrigin() - GetAbsOrigin());
  130. VectorNormalize(vTargetDir);
  131. SetAbsVelocity( m_flFlySpeed * vTargetDir );
  132. QAngle angles;
  133. VectorAngles( GetAbsVelocity(), angles );
  134. SetLocalAngles( angles );
  135. }
  136. else
  137. {
  138. Warning( "ERROR: Grenade_Pathfollower (%s) with no pathcorner!\n",GetDebugName());
  139. return;
  140. }
  141. // Make this thing come to life
  142. RemoveSolidFlags( FSOLID_NOT_SOLID );
  143. SetMoveType( MOVETYPE_FLYGRAVITY );
  144. RemoveEffects( EF_NODRAW );
  145. SetUse( &CGrenadePathfollower::DetonateUse );
  146. SetTouch( &CGrenadePathfollower::GrenadeTouch );
  147. SetThink( &CGrenadePathfollower::AimThink );
  148. SetNextThink( gpGlobals->curtime + 0.1f );
  149. // Make the trail
  150. m_hRocketTrail = RocketTrail::CreateRocketTrail();
  151. if ( m_hRocketTrail )
  152. {
  153. m_hRocketTrail->m_Opacity = 0.2f;
  154. m_hRocketTrail->m_SpawnRate = 100;
  155. m_hRocketTrail->m_ParticleLifetime = 0.5f;
  156. m_hRocketTrail->m_StartColor.Init( 0.65f, 0.65f , 0.65f );
  157. m_hRocketTrail->m_EndColor.Init( 0.0, 0.0, 0.0 );
  158. m_hRocketTrail->m_StartSize = 8;
  159. m_hRocketTrail->m_EndSize = 16;
  160. m_hRocketTrail->m_SpawnRadius = 4;
  161. m_hRocketTrail->m_MinSpeed = 2;
  162. m_hRocketTrail->m_MaxSpeed = 16;
  163. m_hRocketTrail->SetLifetime( 999 );
  164. m_hRocketTrail->FollowEntity( this, "0" );
  165. }
  166. }
  167. //-----------------------------------------------------------------------------
  168. // Purpose:
  169. // Input :
  170. // Output :
  171. //-----------------------------------------------------------------------------
  172. void CGrenadePathfollower::PlayFlySound(void)
  173. {
  174. if (gpGlobals->curtime > m_flNextFlySoundTime)
  175. {
  176. CPASAttenuationFilter filter( this, 0.8 );
  177. EmitSound_t ep;
  178. ep.m_nChannel = CHAN_BODY;
  179. ep.m_pSoundName = STRING(m_sFlySound);
  180. ep.m_flVolume = 1.0f;
  181. ep.m_SoundLevel = SNDLVL_NORM;
  182. EmitSound( filter, entindex(), ep );
  183. m_flNextFlySoundTime = gpGlobals->curtime + 1.0;
  184. }
  185. }
  186. //------------------------------------------------------------------------------
  187. // Purpose :
  188. // Input :
  189. // Output :
  190. //------------------------------------------------------------------------------
  191. void CGrenadePathfollower::AimThink( void )
  192. {
  193. PlayFlySound();
  194. // ---------------------------------------------------
  195. // Check if it's time to skip to the next path corner
  196. // ---------------------------------------------------
  197. if (m_pPathTarget)
  198. {
  199. float flLength = (GetAbsOrigin() - m_pPathTarget->GetAbsOrigin()).Length();
  200. if (flLength < GRENADE_PF_TOLERANCE)
  201. {
  202. m_pPathTarget = gEntList.FindEntityByName( NULL, m_pPathTarget->m_target );
  203. if (!m_pPathTarget)
  204. {
  205. SetGravity( 1.0 );
  206. }
  207. }
  208. }
  209. // --------------------------------------------------
  210. // If I have a pathcorner, aim towards it
  211. // --------------------------------------------------
  212. if (m_pPathTarget)
  213. {
  214. Vector vTargetDir = (m_pPathTarget->GetAbsOrigin() - GetAbsOrigin());
  215. VectorNormalize(vTargetDir);
  216. Vector vecNewVelocity = GetAbsVelocity();
  217. VectorNormalize(vecNewVelocity);
  218. float flTimeToUse = gpGlobals->frametime;
  219. while (flTimeToUse > 0)
  220. {
  221. vecNewVelocity += vTargetDir;
  222. flTimeToUse = -0.1;
  223. }
  224. vecNewVelocity *= m_flFlySpeed;
  225. SetAbsVelocity( vecNewVelocity );
  226. }
  227. QAngle angles;
  228. VectorAngles( GetAbsVelocity(), angles );
  229. SetLocalAngles( angles );
  230. SetNextThink( gpGlobals->curtime + 0.1f );
  231. }
  232. //------------------------------------------------------------------------------
  233. // Purpose :
  234. // Input :
  235. // Output :
  236. //------------------------------------------------------------------------------
  237. Class_T CGrenadePathfollower::Classify( void)
  238. {
  239. return CLASS_MISSILE;
  240. };
  241. CGrenadePathfollower::CGrenadePathfollower(void)
  242. {
  243. m_hRocketTrail = NULL;
  244. }
  245. //------------------------------------------------------------------------------
  246. // Purpose : In case somehow we get removed w/o detonating, make sure
  247. // we stop making sounds
  248. // Input :
  249. // Output :
  250. //------------------------------------------------------------------------------
  251. CGrenadePathfollower::~CGrenadePathfollower(void)
  252. {
  253. StopSound(entindex(), CHAN_BODY, STRING(m_sFlySound));
  254. }
  255. ///------------------------------------------------------------------------------
  256. // Purpose :
  257. // Input :
  258. // Output :
  259. //------------------------------------------------------------------------------
  260. CGrenadePathfollower* CGrenadePathfollower::CreateGrenadePathfollower( string_t sModelName, string_t sFlySound, const Vector &vecOrigin, const QAngle &vecAngles, edict_t *pentOwner )
  261. {
  262. CGrenadePathfollower *pGrenade = (CGrenadePathfollower*)CreateEntityByName( "grenade_pathfollower" );
  263. if ( !pGrenade )
  264. {
  265. Warning( "NULL Ent in CGrenadePathfollower!\n" );
  266. return NULL;
  267. }
  268. if ( pGrenade->edict() )
  269. {
  270. pGrenade->m_sFlySound = sFlySound;
  271. pGrenade->SetOwnerEntity( Instance( pentOwner ) );
  272. pGrenade->SetLocalOrigin( vecOrigin );
  273. pGrenade->SetLocalAngles( vecAngles );
  274. pGrenade->SetModel( STRING(sModelName) );
  275. pGrenade->Spawn();
  276. }
  277. return pGrenade;
  278. }