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.

208 lines
4.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Snark
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "npcevent.h"
  9. #include "hl1_basecombatweapon_shared.h"
  10. #include "basecombatcharacter.h"
  11. #include "ai_basenpc.h"
  12. #include "player.h"
  13. #include "gamerules.h"
  14. #include "in_buttons.h"
  15. #include "soundent.h"
  16. #include "game.h"
  17. #include "vstdlib/random.h"
  18. #include "engine/IEngineSound.h"
  19. #include "hl1_npc_snark.h"
  20. #include "beam_shared.h"
  21. //-----------------------------------------------------------------------------
  22. // CWeaponSnark
  23. //-----------------------------------------------------------------------------
  24. #define SNARK_NEST_MODEL "models/w_sqknest.mdl"
  25. class CWeaponSnark : public CBaseHL1CombatWeapon
  26. {
  27. DECLARE_CLASS( CWeaponSnark, CBaseHL1CombatWeapon );
  28. public:
  29. CWeaponSnark( void );
  30. void Precache( void );
  31. void PrimaryAttack( void );
  32. void WeaponIdle( void );
  33. bool Deploy( void );
  34. bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL );
  35. DECLARE_SERVERCLASS();
  36. DECLARE_DATADESC();
  37. private:
  38. bool m_bJustThrown;
  39. };
  40. LINK_ENTITY_TO_CLASS( weapon_snark, CWeaponSnark );
  41. PRECACHE_WEAPON_REGISTER( weapon_snark );
  42. IMPLEMENT_SERVERCLASS_ST( CWeaponSnark, DT_WeaponSnark )
  43. END_SEND_TABLE()
  44. BEGIN_DATADESC( CWeaponSnark )
  45. DEFINE_FIELD( m_bJustThrown, FIELD_BOOLEAN ),
  46. END_DATADESC()
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Constructor
  49. //-----------------------------------------------------------------------------
  50. CWeaponSnark::CWeaponSnark( void )
  51. {
  52. m_bReloadsSingly = false;
  53. m_bFiresUnderwater = true;
  54. m_bJustThrown = false;
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. //-----------------------------------------------------------------------------
  59. void CWeaponSnark::Precache( void )
  60. {
  61. BaseClass::Precache();
  62. PrecacheScriptSound( "WpnSnark.PrimaryAttack" );
  63. PrecacheScriptSound( "WpnSnark.Deploy" );
  64. UTIL_PrecacheOther("monster_snark");
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. void CWeaponSnark::PrimaryAttack( void )
  70. {
  71. // Only the player fires this way so we can cast
  72. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  73. if ( !pPlayer )
  74. {
  75. return;
  76. }
  77. if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  78. return;
  79. Vector vecForward;
  80. pPlayer->EyeVectors( &vecForward );
  81. // find place to toss monster
  82. // Does this need to consider a crouched player?
  83. Vector vecStart = pPlayer->WorldSpaceCenter() + (vecForward * 20);
  84. Vector vecEnd = vecStart + (vecForward * 44);
  85. trace_t tr;
  86. UTIL_TraceLine( vecStart, vecEnd, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
  87. if ( tr.allsolid || tr.startsolid || tr.fraction <= 0.25 )
  88. return;
  89. // player "shoot" animation
  90. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  91. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  92. CSnark *pSnark = (CSnark*)Create( "monster_snark", tr.endpos, pPlayer->EyeAngles(), GetOwner() );
  93. if ( pSnark )
  94. {
  95. pSnark->SetAbsVelocity( vecForward * 200 + pPlayer->GetAbsVelocity() );
  96. }
  97. // play hunt sound
  98. CPASAttenuationFilter filter( this );
  99. EmitSound( filter, entindex(), "WpnSnark.PrimaryAttack" );
  100. CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin(), 200, 0.2 );
  101. pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
  102. m_bJustThrown = true;
  103. m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
  104. SetWeaponIdleTime( gpGlobals->curtime + 1.0 );
  105. }
  106. void CWeaponSnark::WeaponIdle( void )
  107. {
  108. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  109. if ( !pPlayer )
  110. {
  111. return;
  112. }
  113. if ( !HasWeaponIdleTimeElapsed() )
  114. return;
  115. if ( m_bJustThrown )
  116. {
  117. m_bJustThrown = false;
  118. if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  119. {
  120. if ( !pPlayer->SwitchToNextBestWeapon( pPlayer->GetActiveWeapon() ) )
  121. Holster();
  122. }
  123. else
  124. {
  125. SendWeaponAnim( ACT_VM_DRAW );
  126. SetWeaponIdleTime( gpGlobals->curtime + random->RandomFloat( 10, 15 ) );
  127. }
  128. }
  129. else
  130. {
  131. if ( random->RandomFloat( 0, 1 ) <= 0.75 )
  132. {
  133. SendWeaponAnim( ACT_VM_IDLE );
  134. }
  135. else
  136. {
  137. SendWeaponAnim( ACT_VM_FIDGET );
  138. }
  139. }
  140. }
  141. bool CWeaponSnark::Deploy( void )
  142. {
  143. CPASAttenuationFilter filter( this );
  144. EmitSound( filter, entindex(), "WpnSnark.Deploy" );
  145. return BaseClass::Deploy();
  146. }
  147. bool CWeaponSnark::Holster( CBaseCombatWeapon *pSwitchingTo )
  148. {
  149. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  150. if ( !pPlayer )
  151. {
  152. return false;
  153. }
  154. if ( !BaseClass::Holster( pSwitchingTo ) )
  155. {
  156. return false;
  157. }
  158. if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  159. {
  160. SetThink( &CWeaponSnark::DestroyItem );
  161. SetNextThink( gpGlobals->curtime + 0.1 );
  162. }
  163. pPlayer->SetNextAttack( gpGlobals->curtime + 0.5 );
  164. return true;
  165. }