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.

326 lines
9.3 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Bugbait weapon to summon and direct antlions
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "grenade_bugbait.h"
  8. #include "decals.h"
  9. #include "smoke_trail.h"
  10. #include "soundent.h"
  11. #include "engine/IEngineSound.h"
  12. #include "npc_bullseye.h"
  13. #include "entitylist.h"
  14. #include "antlion_maker.h"
  15. #include "eventqueue.h"
  16. #ifdef PORTAL
  17. #include "portal_util_shared.h"
  18. #endif
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. // Setup the sensor list template
  22. CEntityClassList<CBugBaitSensor> g_BugBaitSensorList;
  23. template <> CBugBaitSensor *CEntityClassList<CBugBaitSensor>::m_pClassList = NULL;
  24. CBugBaitSensor* GetBugBaitSensorList()
  25. {
  26. return g_BugBaitSensorList.m_pClassList;
  27. }
  28. CBugBaitSensor::CBugBaitSensor( void )
  29. {
  30. g_BugBaitSensorList.Insert( this );
  31. }
  32. CBugBaitSensor::~CBugBaitSensor( void )
  33. {
  34. g_BugBaitSensorList.Remove( this );
  35. }
  36. BEGIN_DATADESC( CBugBaitSensor )
  37. // This is re-set up in the constructor
  38. //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ),
  39. DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "Enabled" ),
  40. DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
  41. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  42. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  43. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  44. // Function Pointers
  45. DEFINE_OUTPUT( m_OnBaited, "OnBaited" ),
  46. END_DATADESC()
  47. LINK_ENTITY_TO_CLASS( point_bugbait, CBugBaitSensor );
  48. //=============================================================================
  49. // Bugbait grenade
  50. //=============================================================================
  51. #define GRENADE_MODEL "models/weapons/w_bugbait.mdl"
  52. BEGIN_DATADESC( CGrenadeBugBait )
  53. DEFINE_FIELD( m_flGracePeriodEndsAt, FIELD_TIME ),
  54. DEFINE_FIELD( m_pSporeTrail, FIELD_CLASSPTR ),
  55. // Function Pointers
  56. DEFINE_ENTITYFUNC( BugBaitTouch ),
  57. DEFINE_THINKFUNC( ThinkBecomeSolid ),
  58. END_DATADESC()
  59. LINK_ENTITY_TO_CLASS( npc_grenade_bugbait, CGrenadeBugBait );
  60. //Radius of the bugbait's effect on other creatures
  61. ConVar bugbait_radius( "bugbait_radius", "512" );
  62. ConVar bugbait_hear_radius( "bugbait_hear_radius", "2500" );
  63. ConVar bugbait_distract_time( "bugbait_distract_time", "5" );
  64. ConVar bugbait_grenade_radius( "bugbait_grenade_radius", "150" );
  65. //-----------------------------------------------------------------------------
  66. // Purpose:
  67. //-----------------------------------------------------------------------------
  68. void CGrenadeBugBait::Spawn( void )
  69. {
  70. Precache();
  71. SetModel( GRENADE_MODEL );
  72. SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
  73. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_DEFAULT );
  74. SetSolid( SOLID_BBOX );
  75. UTIL_SetSize( this, Vector( -2, -2, -2), Vector( 2, 2, 2 ) );
  76. SetTouch( &CGrenadeBugBait::BugBaitTouch );
  77. m_takedamage = DAMAGE_NO;
  78. m_pSporeTrail = NULL;
  79. /*
  80. m_pSporeTrail = SporeTrail::CreateSporeTrail();
  81. m_pSporeTrail->m_bEmit = true;
  82. m_pSporeTrail->m_flSpawnRate = 100.0f;
  83. m_pSporeTrail->m_flParticleLifetime = 1.0f;
  84. m_pSporeTrail->m_flStartSize = 1.0f;
  85. m_pSporeTrail->m_flEndSize = 1.0f;
  86. m_pSporeTrail->m_flSpawnRadius = 8.0f;
  87. m_pSporeTrail->m_vecEndColor = Vector( 0, 0, 0 );
  88. */
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose:
  92. //-----------------------------------------------------------------------------
  93. void CGrenadeBugBait::Precache( void )
  94. {
  95. PrecacheModel( GRENADE_MODEL );
  96. PrecacheScriptSound( "GrenadeBugBait.Splat" );
  97. BaseClass::Precache();
  98. }
  99. #define NUM_SPLASHES 6
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CGrenadeBugBait::BugBaitTouch( CBaseEntity *pOther )
  104. {
  105. // Don't hit triggers or water
  106. Assert( pOther );
  107. if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER|FSOLID_VOLUME_CONTENTS) )
  108. return;
  109. if ( m_pSporeTrail != NULL )
  110. {
  111. m_pSporeTrail->m_bEmit = false;
  112. }
  113. //Do effect for the hit
  114. SporeExplosion *pSporeExplosion = SporeExplosion::CreateSporeExplosion();
  115. if ( pSporeExplosion )
  116. {
  117. Vector dir = -GetAbsVelocity();
  118. VectorNormalize( dir );
  119. QAngle angles;
  120. VectorAngles( dir, angles );
  121. pSporeExplosion->SetLocalAngles( angles );
  122. pSporeExplosion->SetLocalOrigin( GetAbsOrigin() );
  123. pSporeExplosion->m_flSpawnRate = 8.0f;
  124. pSporeExplosion->m_flParticleLifetime = 2.0f;
  125. pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f, 0.15f );
  126. pSporeExplosion->m_flStartSize = 32.0f;
  127. pSporeExplosion->m_flEndSize = 64.0f;
  128. pSporeExplosion->m_flSpawnRadius = 32.0f;
  129. pSporeExplosion->SetLifetime( bugbait_distract_time.GetFloat() );
  130. }
  131. trace_t tr;
  132. Vector traceDir = GetAbsVelocity();
  133. VectorNormalize( traceDir );
  134. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + traceDir * 64, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  135. if ( tr.fraction < 1.0f )
  136. {
  137. UTIL_DecalTrace( &tr, "BeerSplash" ); //TODO: Use real decal
  138. }
  139. //Make a splat sound
  140. CPASAttenuationFilter filter( this );
  141. EmitSound( filter, entindex(), "GrenadeBugBait.Splat" );
  142. //Make sure we want to call antlions
  143. if ( ActivateBugbaitTargets( GetThrower(), GetAbsOrigin(), false ) == false )
  144. {
  145. //Alert any antlions around
  146. CSoundEnt::InsertSound( SOUND_BUGBAIT, GetAbsOrigin(), bugbait_hear_radius.GetInt(), bugbait_distract_time.GetFloat(), GetThrower() );
  147. }
  148. // Tell all spawners to now fight to this position
  149. g_AntlionMakerManager.BroadcastFightGoal( GetAbsOrigin() );
  150. //Go away
  151. UTIL_Remove( this );
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Activate any nearby bugbait targets
  155. // Returns true if the bugbait target wants to suppress the call.
  156. //-----------------------------------------------------------------------------
  157. bool CGrenadeBugBait::ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOrigin, bool bSqueezed )
  158. {
  159. //Attempt to activate any spawners in a radius around the bugbait
  160. CBaseEntity* pList[100];
  161. Vector delta( bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat() );
  162. bool suppressCall = false;
  163. int count = UTIL_EntitiesInBox( pList, 100, vecOrigin - delta, vecOrigin + delta, 0 );
  164. // If the bugbait's been thrown, look for nearby targets to affect
  165. if ( !bSqueezed )
  166. {
  167. for ( int i = 0; i < count; i++ )
  168. {
  169. // If close enough, make combine soldiers freak out when hit
  170. if ( UTIL_DistApprox( pList[i]->WorldSpaceCenter(), vecOrigin ) < bugbait_grenade_radius.GetFloat() )
  171. {
  172. // Must be a soldier
  173. if ( FClassnameIs( pList[i], "npc_combine_s") )
  174. {
  175. CAI_BaseNPC *pCombine = pList[i]->MyNPCPointer();
  176. if ( pCombine != NULL )
  177. {
  178. trace_t tr;
  179. UTIL_TraceLine( vecOrigin, pCombine->EyePosition(), MASK_ALL, pOwner, COLLISION_GROUP_NONE, &tr);
  180. if ( tr.fraction == 1.0 || tr.m_pEnt == pCombine )
  181. {
  182. // Randomize the start time a little so multiple combine hit by
  183. // the same bugbait don't all dance in synch.
  184. g_EventQueue.AddEvent( pCombine, "HitByBugbait", RandomFloat(0, 0.5), pOwner, pOwner );
  185. }
  186. }
  187. }
  188. }
  189. }
  190. }
  191. // Iterate over all sensors to see if they detected this impact
  192. for ( CBugBaitSensor *pSensor = GetBugBaitSensorList(); pSensor != NULL; pSensor = pSensor->m_pNext )
  193. {
  194. if ( pSensor == NULL )
  195. continue;
  196. if ( pSensor->IsDisabled() )
  197. continue;
  198. if ( bSqueezed && pSensor->DetectsSqueeze() == false )
  199. continue;
  200. if ( !bSqueezed && pSensor->DetectsThrown() == false )
  201. continue;
  202. //Make sure we're within range of the sensor
  203. if ( pSensor->GetRadius() > ( pSensor->GetAbsOrigin() - vecOrigin ).Length() )
  204. {
  205. //Tell the sensor it's been hit
  206. if ( pSensor->Baited( pOwner ) )
  207. {
  208. //If we're suppressing the call to antlions, then don't make a bugbait sound
  209. if ( pSensor->SuppressCall() )
  210. {
  211. suppressCall = true;
  212. }
  213. }
  214. }
  215. }
  216. return suppressCall;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose:
  220. //-----------------------------------------------------------------------------
  221. void CGrenadeBugBait::ThinkBecomeSolid( void )
  222. {
  223. SetThink( NULL );
  224. RemoveSolidFlags( FSOLID_NOT_SOLID );
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. // Input : duration -
  229. //-----------------------------------------------------------------------------
  230. void CGrenadeBugBait::SetGracePeriod( float duration )
  231. {
  232. SetThink( &CGrenadeBugBait::ThinkBecomeSolid );
  233. SetNextThink( gpGlobals->curtime + duration );
  234. // Become unsolid
  235. AddSolidFlags( FSOLID_NOT_SOLID );
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose:
  239. // Input : &position -
  240. // &angles -
  241. // &velocity -
  242. // &angVelocity -
  243. // *owner -
  244. // Output : CBaseGrenade
  245. //-----------------------------------------------------------------------------
  246. CGrenadeBugBait *BugBaitGrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const QAngle &angVelocity, CBaseEntity *owner )
  247. {
  248. CGrenadeBugBait *pGrenade = (CGrenadeBugBait *) CBaseEntity::Create( "npc_grenade_bugbait", position, angles, owner );
  249. if ( pGrenade != NULL )
  250. {
  251. pGrenade->SetLocalAngularVelocity( angVelocity );
  252. pGrenade->SetAbsVelocity( velocity );
  253. pGrenade->SetThrower( ToBaseCombatCharacter( owner ) );
  254. }
  255. return pGrenade;
  256. }