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.

443 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "basehlcombatweapon.h"
  9. #include "engine/IEngineSound.h"
  10. #include "npcevent.h"
  11. #include "in_buttons.h"
  12. #include "antlion_maker.h"
  13. #include "grenade_bugbait.h"
  14. #include "gamestats.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. //
  18. // Bug Bait Weapon
  19. //
  20. class CWeaponBugBait : public CBaseHLCombatWeapon
  21. {
  22. DECLARE_CLASS( CWeaponBugBait, CBaseHLCombatWeapon );
  23. public:
  24. DECLARE_SERVERCLASS();
  25. CWeaponBugBait( void );
  26. void Spawn( void );
  27. void FallInit( void );
  28. int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
  29. void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
  30. void Drop( const Vector &vecVelocity );
  31. void BugbaitStickyTouch( CBaseEntity *pOther );
  32. void OnPickedUp( CBaseCombatCharacter *pNewOwner );
  33. bool Deploy( void );
  34. bool Holster( CBaseCombatWeapon *pSwitchingTo );
  35. void ItemPostFrame( void );
  36. void Precache( void );
  37. void PrimaryAttack( void );
  38. void SecondaryAttack( void );
  39. void ThrowGrenade( CBasePlayer *pPlayer );
  40. bool HasAnyAmmo( void ) { return true; }
  41. bool Reload( void );
  42. void SetSporeEmitterState( bool state = true );
  43. bool ShouldDisplayHUDHint() { return true; }
  44. DECLARE_DATADESC();
  45. protected:
  46. bool m_bDrawBackFinished;
  47. bool m_bRedraw;
  48. bool m_bEmitSpores;
  49. EHANDLE m_hSporeTrail;
  50. };
  51. IMPLEMENT_SERVERCLASS_ST(CWeaponBugBait, DT_WeaponBugBait)
  52. END_SEND_TABLE()
  53. LINK_ENTITY_TO_CLASS( weapon_bugbait, CWeaponBugBait );
  54. #ifndef HL2MP
  55. PRECACHE_WEAPON_REGISTER( weapon_bugbait );
  56. #endif
  57. BEGIN_DATADESC( CWeaponBugBait )
  58. DEFINE_FIELD( m_hSporeTrail, FIELD_EHANDLE ),
  59. DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
  60. DEFINE_FIELD( m_bEmitSpores, FIELD_BOOLEAN ),
  61. DEFINE_FIELD( m_bDrawBackFinished, FIELD_BOOLEAN ),
  62. DEFINE_FUNCTION( BugbaitStickyTouch ),
  63. END_DATADESC()
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. CWeaponBugBait::CWeaponBugBait( void )
  68. {
  69. m_bDrawBackFinished = false;
  70. m_bRedraw = false;
  71. m_hSporeTrail = NULL;
  72. }
  73. //-----------------------------------------------------------------------------
  74. // Purpose:
  75. //-----------------------------------------------------------------------------
  76. void CWeaponBugBait::Spawn( void )
  77. {
  78. BaseClass::Spawn();
  79. // Increase the bugbait's pickup volume. It spawns inside the antlion guard's body,
  80. // and playtesters seem to be wary about moving into the body.
  81. SetSize( Vector( -4, -4, -4), Vector(4, 4, 4) );
  82. CollisionProp()->UseTriggerBounds( true, 100 );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void CWeaponBugBait::FallInit( void )
  88. {
  89. // Bugbait shouldn't be physics, because it musn't roll/move away from it's spawnpoint.
  90. // The game will break if the player can't pick it up, so it must stay still.
  91. SetModel( GetWorldModel() );
  92. VPhysicsDestroyObject();
  93. SetMoveType( MOVETYPE_FLYGRAVITY );
  94. SetSolid( SOLID_BBOX );
  95. AddSolidFlags( FSOLID_TRIGGER );
  96. SetPickupTouch();
  97. SetThink( &CBaseCombatWeapon::FallThink );
  98. SetNextThink( gpGlobals->curtime + 0.1f );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CWeaponBugBait::Precache( void )
  104. {
  105. BaseClass::Precache();
  106. UTIL_PrecacheOther( "npc_grenade_bugbait" );
  107. PrecacheScriptSound( "Weapon_Bugbait.Splat" );
  108. }
  109. //-----------------------------------------------------------------------------
  110. // Purpose:
  111. //-----------------------------------------------------------------------------
  112. void CWeaponBugBait::Drop( const Vector &vecVelocity )
  113. {
  114. BaseClass::Drop( vecVelocity );
  115. // On touch, stick & stop moving. Increase our thinktime a bit so we don't stomp the touch for a bit
  116. SetNextThink( gpGlobals->curtime + 3.0 );
  117. SetTouch( &CWeaponBugBait::BugbaitStickyTouch );
  118. m_hSporeTrail = SporeExplosion::CreateSporeExplosion();
  119. if ( m_hSporeTrail )
  120. {
  121. SporeExplosion *pSporeExplosion = (SporeExplosion *)m_hSporeTrail.Get();
  122. QAngle angles;
  123. VectorAngles( Vector(0,0,1), angles );
  124. pSporeExplosion->SetAbsAngles( angles );
  125. pSporeExplosion->SetAbsOrigin( GetAbsOrigin() );
  126. pSporeExplosion->SetParent( this );
  127. pSporeExplosion->m_flSpawnRate = 16.0f;
  128. pSporeExplosion->m_flParticleLifetime = 0.5f;
  129. pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f, 0.15f );
  130. pSporeExplosion->m_flStartSize = 32;
  131. pSporeExplosion->m_flEndSize = 48;
  132. pSporeExplosion->m_flSpawnRadius = 4;
  133. pSporeExplosion->SetLifetime( 9999 );
  134. }
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose: Stick to the world when we touch it
  138. //-----------------------------------------------------------------------------
  139. void CWeaponBugBait::BugbaitStickyTouch( CBaseEntity *pOther )
  140. {
  141. if ( !pOther->IsWorld() )
  142. return;
  143. // Stop moving, wait for pickup
  144. SetMoveType( MOVETYPE_NONE );
  145. SetThink( NULL );
  146. SetPickupTouch();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. // Input : *pPicker -
  151. //-----------------------------------------------------------------------------
  152. void CWeaponBugBait::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  153. {
  154. BaseClass::OnPickedUp( pNewOwner );
  155. if ( m_hSporeTrail )
  156. {
  157. UTIL_Remove( m_hSporeTrail );
  158. }
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose:
  162. //-----------------------------------------------------------------------------
  163. void CWeaponBugBait::PrimaryAttack( void )
  164. {
  165. if ( m_bRedraw )
  166. return;
  167. CBaseCombatCharacter *pOwner = GetOwner();
  168. if ( pOwner == NULL )
  169. return;
  170. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  171. if ( pPlayer == NULL )
  172. return;
  173. SendWeaponAnim( ACT_VM_HAULBACK );
  174. m_flTimeWeaponIdle = FLT_MAX;
  175. m_flNextPrimaryAttack = FLT_MAX;
  176. m_iPrimaryAttacks++;
  177. gamestats->Event_WeaponFired( pPlayer, true, GetClassname() );
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose:
  181. //-----------------------------------------------------------------------------
  182. void CWeaponBugBait::SecondaryAttack( void )
  183. {
  184. // Squeeze!
  185. CPASAttenuationFilter filter( this );
  186. EmitSound( filter, entindex(), "Weapon_Bugbait.Splat" );
  187. if ( CGrenadeBugBait::ActivateBugbaitTargets( GetOwner(), GetAbsOrigin(), true ) == false )
  188. {
  189. g_AntlionMakerManager.BroadcastFollowGoal( GetOwner() );
  190. }
  191. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  192. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  193. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  194. if ( pOwner )
  195. {
  196. m_iSecondaryAttacks++;
  197. gamestats->Event_WeaponFired( pOwner, false, GetClassname() );
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. // Input : *pPlayer -
  203. //-----------------------------------------------------------------------------
  204. void CWeaponBugBait::ThrowGrenade( CBasePlayer *pPlayer )
  205. {
  206. Vector vForward, vRight, vUp, vThrowPos, vThrowVel;
  207. pPlayer->EyeVectors( &vForward, &vRight, &vUp );
  208. vThrowPos = pPlayer->EyePosition();
  209. vThrowPos += vForward * 18.0f;
  210. vThrowPos += vRight * 12.0f;
  211. pPlayer->GetVelocity( &vThrowVel, NULL );
  212. vThrowVel += vForward * 1000;
  213. CGrenadeBugBait *pGrenade = BugBaitGrenade_Create( vThrowPos, vec3_angle, vThrowVel, QAngle(600,random->RandomInt(-1200,1200),0), pPlayer );
  214. if ( pGrenade != NULL )
  215. {
  216. // If the shot is clear to the player, give the missile a grace period
  217. trace_t tr;
  218. UTIL_TraceLine( pPlayer->EyePosition(), pPlayer->EyePosition() + ( vForward * 128 ), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  219. if ( tr.fraction == 1.0 )
  220. {
  221. pGrenade->SetGracePeriod( 0.1f );
  222. }
  223. }
  224. m_bRedraw = true;
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. // Input : *pEvent -
  229. // *pOperator -
  230. //-----------------------------------------------------------------------------
  231. void CWeaponBugBait::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  232. {
  233. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  234. switch( pEvent->event )
  235. {
  236. case EVENT_WEAPON_SEQUENCE_FINISHED:
  237. m_bDrawBackFinished = true;
  238. break;
  239. case EVENT_WEAPON_THROW:
  240. ThrowGrenade( pOwner );
  241. break;
  242. default:
  243. BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
  244. break;
  245. }
  246. }
  247. //-----------------------------------------------------------------------------
  248. // Purpose:
  249. // Output : Returns true on success, false on failure.
  250. //-----------------------------------------------------------------------------
  251. bool CWeaponBugBait::Reload( void )
  252. {
  253. if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) )
  254. {
  255. //Redraw the weapon
  256. SendWeaponAnim( ACT_VM_DRAW );
  257. //Update our times
  258. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  259. //Mark this as done
  260. m_bRedraw = false;
  261. }
  262. return true;
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. void CWeaponBugBait::ItemPostFrame( void )
  268. {
  269. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  270. if ( pOwner == NULL )
  271. return;
  272. // See if we're cocked and ready to throw
  273. if ( m_bDrawBackFinished )
  274. {
  275. if ( ( pOwner->m_nButtons & IN_ATTACK ) == false )
  276. {
  277. SendWeaponAnim( ACT_VM_THROW );
  278. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  279. m_bDrawBackFinished = false;
  280. }
  281. }
  282. else
  283. {
  284. //See if we're attacking
  285. if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) )
  286. {
  287. PrimaryAttack();
  288. }
  289. else if ( ( pOwner->m_nButtons & IN_ATTACK2 ) && ( m_flNextSecondaryAttack < gpGlobals->curtime ) )
  290. {
  291. SecondaryAttack();
  292. }
  293. }
  294. if ( m_bRedraw )
  295. {
  296. if ( IsViewModelSequenceFinished() )
  297. {
  298. Reload();
  299. }
  300. }
  301. WeaponIdle();
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose:
  305. //-----------------------------------------------------------------------------
  306. bool CWeaponBugBait::Deploy( void )
  307. {
  308. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  309. if ( pOwner == NULL )
  310. return false;
  311. /*
  312. if ( m_hSporeTrail == NULL )
  313. {
  314. m_hSporeTrail = SporeTrail::CreateSporeTrail();
  315. m_hSporeTrail->m_bEmit = true;
  316. m_hSporeTrail->m_flSpawnRate = 100.0f;
  317. m_hSporeTrail->m_flParticleLifetime = 2.0f;
  318. m_hSporeTrail->m_flStartSize = 1.0f;
  319. m_hSporeTrail->m_flEndSize = 4.0f;
  320. m_hSporeTrail->m_flSpawnRadius = 8.0f;
  321. m_hSporeTrail->m_vecEndColor = Vector( 0, 0, 0 );
  322. CBaseViewModel *vm = pOwner->GetViewModel();
  323. if ( vm != NULL )
  324. {
  325. m_hSporeTrail->FollowEntity( vm );
  326. }
  327. }
  328. */
  329. m_bRedraw = false;
  330. m_bDrawBackFinished = false;
  331. return BaseClass::Deploy();
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. bool CWeaponBugBait::Holster( CBaseCombatWeapon *pSwitchingTo )
  337. {
  338. m_bRedraw = false;
  339. m_bDrawBackFinished = false;
  340. return BaseClass::Holster( pSwitchingTo );
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose:
  344. // Input : true -
  345. //-----------------------------------------------------------------------------
  346. void CWeaponBugBait::SetSporeEmitterState( bool state )
  347. {
  348. m_bEmitSpores = state;
  349. }