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.

350 lines
9.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Grigori's personal shotgun (npc_monk)
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "npcevent.h"
  8. #include "basehlcombatweapon_shared.h"
  9. #include "basecombatcharacter.h"
  10. #include "ai_basenpc.h"
  11. #include "player.h"
  12. #include "gamerules.h" // For g_pGameRules
  13. #include "in_buttons.h"
  14. #include "soundent.h"
  15. #include "vstdlib/random.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. extern ConVar sk_auto_reload_time;
  19. class CWeaponAnnabelle : public CBaseHLCombatWeapon
  20. {
  21. DECLARE_DATADESC();
  22. public:
  23. DECLARE_CLASS( CWeaponAnnabelle, CBaseHLCombatWeapon );
  24. DECLARE_SERVERCLASS();
  25. private:
  26. bool m_bNeedPump; // When emptied completely
  27. bool m_bDelayedFire1; // Fire primary when finished reloading
  28. bool m_bDelayedFire2; // Fire secondary when finished reloading
  29. public:
  30. void Precache( void );
  31. int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
  32. virtual const Vector& GetBulletSpread( void )
  33. {
  34. static Vector cone = vec3_origin;
  35. return cone;
  36. }
  37. virtual int GetMinBurst() { return 1; }
  38. virtual int GetMaxBurst() { return 3; }
  39. void ItemHolsterFrame( void );
  40. bool StartReload( void );
  41. bool Reload( void );
  42. void FillClip( void );
  43. void FinishReload( void );
  44. void CheckHolsterReload( void );
  45. void Pump( void );
  46. void DryFire( void );
  47. virtual float GetFireRate( void ) { return 1.5; };
  48. virtual float GetMinRestTime() { return 1.0; }
  49. virtual float GetMaxRestTime() { return 1.5; }
  50. void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
  51. DECLARE_ACTTABLE();
  52. CWeaponAnnabelle(void);
  53. };
  54. IMPLEMENT_SERVERCLASS_ST(CWeaponAnnabelle, DT_WeaponAnnabelle)
  55. END_SEND_TABLE()
  56. LINK_ENTITY_TO_CLASS( weapon_annabelle, CWeaponAnnabelle );
  57. #ifndef HL2MP
  58. PRECACHE_WEAPON_REGISTER(weapon_annabelle);
  59. #endif
  60. BEGIN_DATADESC( CWeaponAnnabelle )
  61. DEFINE_FIELD( m_bNeedPump, FIELD_BOOLEAN ),
  62. DEFINE_FIELD( m_bDelayedFire1, FIELD_BOOLEAN ),
  63. DEFINE_FIELD( m_bDelayedFire2, FIELD_BOOLEAN ),
  64. END_DATADESC()
  65. acttable_t CWeaponAnnabelle::m_acttable[] =
  66. {
  67. { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SMG1, true },
  68. { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
  69. { ACT_RELOAD, ACT_RELOAD_SMG1, true },
  70. { ACT_WALK, ACT_WALK_RIFLE, true },
  71. { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true },
  72. { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, false },
  73. { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, false },
  74. { ACT_RUN, ACT_RUN_RIFLE, true },
  75. { ACT_RUN_AIM, ACT_RUN_AIM_RIFLE, true },
  76. { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, false },
  77. { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, false },
  78. { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
  79. { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false },
  80. { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false },
  81. };
  82. IMPLEMENT_ACTTABLE(CWeaponAnnabelle);
  83. void CWeaponAnnabelle::Precache( void )
  84. {
  85. CBaseCombatWeapon::Precache();
  86. }
  87. //-----------------------------------------------------------------------------
  88. // Purpose:
  89. // Input :
  90. // Output :
  91. //-----------------------------------------------------------------------------
  92. void CWeaponAnnabelle::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  93. {
  94. switch( pEvent->event )
  95. {
  96. case EVENT_WEAPON_SHOTGUN_FIRE:
  97. {
  98. Vector vecShootOrigin, vecShootDir;
  99. vecShootOrigin = pOperator->Weapon_ShootPosition();
  100. CAI_BaseNPC *npc = pOperator->MyNPCPointer();
  101. ASSERT( npc != NULL );
  102. WeaponSound( SINGLE_NPC );
  103. pOperator->DoMuzzleFlash();
  104. m_iClip1 = m_iClip1 - 1;
  105. vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );
  106. pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
  107. }
  108. break;
  109. default:
  110. CBaseCombatWeapon::Operator_HandleAnimEvent( pEvent, pOperator );
  111. break;
  112. }
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose: Override so only reload one shell at a time
  116. // Input :
  117. // Output :
  118. //-----------------------------------------------------------------------------
  119. bool CWeaponAnnabelle::StartReload( void )
  120. {
  121. CBaseCombatCharacter *pOwner = GetOwner();
  122. if ( pOwner == NULL )
  123. return false;
  124. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  125. return false;
  126. if (m_iClip1 >= GetMaxClip1())
  127. return false;
  128. // If shotgun totally emptied then a pump animation is needed
  129. if (m_iClip1 <= 0)
  130. {
  131. m_bNeedPump = true;
  132. }
  133. int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  134. if (j <= 0)
  135. return false;
  136. SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
  137. // Make shotgun shell visible
  138. SetBodygroup(1,0);
  139. pOwner->m_flNextAttack = gpGlobals->curtime;
  140. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  141. m_bInReload = true;
  142. return true;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Purpose: Override so only reload one shell at a time
  146. // Input :
  147. // Output :
  148. //-----------------------------------------------------------------------------
  149. bool CWeaponAnnabelle::Reload( void )
  150. {
  151. // Check that StartReload was called first
  152. if (!m_bInReload)
  153. {
  154. Warning("ERROR: Shotgun Reload called incorrectly!\n");
  155. }
  156. CBaseCombatCharacter *pOwner = GetOwner();
  157. if ( pOwner == NULL )
  158. return false;
  159. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  160. return false;
  161. if (m_iClip1 >= GetMaxClip1())
  162. return false;
  163. int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  164. if (j <= 0)
  165. return false;
  166. FillClip();
  167. // Play reload on different channel as otherwise steals channel away from fire sound
  168. WeaponSound(RELOAD);
  169. SendWeaponAnim( ACT_VM_RELOAD );
  170. pOwner->m_flNextAttack = gpGlobals->curtime;
  171. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  172. return true;
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose: Play finish reload anim and fill clip
  176. // Input :
  177. // Output :
  178. //-----------------------------------------------------------------------------
  179. void CWeaponAnnabelle::FinishReload( void )
  180. {
  181. // Make shotgun shell invisible
  182. SetBodygroup(1,1);
  183. CBaseCombatCharacter *pOwner = GetOwner();
  184. if ( pOwner == NULL )
  185. return;
  186. m_bInReload = false;
  187. // Finish reload animation
  188. SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
  189. pOwner->m_flNextAttack = gpGlobals->curtime;
  190. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose: Play finish reload anim and fill clip
  194. // Input :
  195. // Output :
  196. //-----------------------------------------------------------------------------
  197. void CWeaponAnnabelle::FillClip( void )
  198. {
  199. CBaseCombatCharacter *pOwner = GetOwner();
  200. if ( pOwner == NULL )
  201. return;
  202. // Add them to the clip
  203. if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  204. {
  205. if ( Clip1() < GetMaxClip1() )
  206. {
  207. m_iClip1++;
  208. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  209. }
  210. }
  211. }
  212. //-----------------------------------------------------------------------------
  213. // Purpose: Play weapon pump anim
  214. // Input :
  215. // Output :
  216. //-----------------------------------------------------------------------------
  217. void CWeaponAnnabelle::Pump( void )
  218. {
  219. CBaseCombatCharacter *pOwner = GetOwner();
  220. if ( pOwner == NULL )
  221. return;
  222. m_bNeedPump = false;
  223. WeaponSound( SPECIAL1 );
  224. // Finish reload animation
  225. SendWeaponAnim( ACT_SHOTGUN_PUMP );
  226. pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
  227. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  228. }
  229. //-----------------------------------------------------------------------------
  230. // Purpose:
  231. //
  232. //
  233. //-----------------------------------------------------------------------------
  234. void CWeaponAnnabelle::DryFire( void )
  235. {
  236. WeaponSound(EMPTY);
  237. SendWeaponAnim( ACT_VM_DRYFIRE );
  238. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose:
  242. //-----------------------------------------------------------------------------
  243. void CWeaponAnnabelle::ItemHolsterFrame( void )
  244. {
  245. // Must be player held
  246. if ( GetOwner() && GetOwner()->IsPlayer() == false )
  247. return;
  248. // We can't be active
  249. if ( GetOwner()->GetActiveWeapon() == this )
  250. return;
  251. // If it's been longer than three seconds, reload
  252. if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
  253. {
  254. // Reset the timer
  255. m_flHolsterTime = gpGlobals->curtime;
  256. if ( GetOwner() == NULL )
  257. return;
  258. if ( m_iClip1 == GetMaxClip1() )
  259. return;
  260. // Just load the clip with no animations
  261. int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
  262. GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
  263. m_iClip1 += ammoFill;
  264. }
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose: Constructor
  268. //-----------------------------------------------------------------------------
  269. CWeaponAnnabelle::CWeaponAnnabelle( void )
  270. {
  271. m_bReloadsSingly = true;
  272. m_bNeedPump = false;
  273. m_bDelayedFire1 = false;
  274. m_bDelayedFire2 = false;
  275. m_fMinRange1 = 0.0;
  276. m_fMaxRange1 = 500;
  277. m_fMinRange2 = 0.0;
  278. m_fMaxRange2 = 200;
  279. }