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.

793 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A shotgun.
  4. //
  5. // Primary attack: single barrel shot.
  6. // Secondary attack: double barrel shot.
  7. //
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "npcevent.h"
  11. #include "basehlcombatweapon_shared.h"
  12. #include "basecombatcharacter.h"
  13. #include "ai_basenpc.h"
  14. #include "player.h"
  15. #include "gamerules.h" // For g_pGameRules
  16. #include "in_buttons.h"
  17. #include "soundent.h"
  18. #include "vstdlib/random.h"
  19. #include "gamestats.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. extern ConVar sk_auto_reload_time;
  23. extern ConVar sk_plr_num_shotgun_pellets;
  24. class CWeaponShotgun : public CBaseHLCombatWeapon
  25. {
  26. DECLARE_DATADESC();
  27. public:
  28. DECLARE_CLASS( CWeaponShotgun, CBaseHLCombatWeapon );
  29. DECLARE_SERVERCLASS();
  30. private:
  31. bool m_bNeedPump; // When emptied completely
  32. bool m_bDelayedFire1; // Fire primary when finished reloading
  33. bool m_bDelayedFire2; // Fire secondary when finished reloading
  34. public:
  35. void Precache( void );
  36. int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
  37. virtual const Vector& GetBulletSpread( void )
  38. {
  39. static Vector vitalAllyCone = VECTOR_CONE_3DEGREES;
  40. static Vector cone = VECTOR_CONE_10DEGREES;
  41. if( GetOwner() && (GetOwner()->Classify() == CLASS_PLAYER_ALLY_VITAL) )
  42. {
  43. // Give Alyx's shotgun blasts more a more directed punch. She needs
  44. // to be at least as deadly as she would be with her pistol to stay interesting (sjb)
  45. return vitalAllyCone;
  46. }
  47. return cone;
  48. }
  49. virtual int GetMinBurst() { return 1; }
  50. virtual int GetMaxBurst() { return 3; }
  51. virtual float GetMinRestTime();
  52. virtual float GetMaxRestTime();
  53. virtual float GetFireRate( void );
  54. bool StartReload( void );
  55. bool Reload( void );
  56. void FillClip( void );
  57. void FinishReload( void );
  58. void CheckHolsterReload( void );
  59. void Pump( void );
  60. // void WeaponIdle( void );
  61. void ItemHolsterFrame( void );
  62. void ItemPostFrame( void );
  63. void PrimaryAttack( void );
  64. void SecondaryAttack( void );
  65. void DryFire( void );
  66. void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles );
  67. void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary );
  68. void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
  69. DECLARE_ACTTABLE();
  70. CWeaponShotgun(void);
  71. };
  72. IMPLEMENT_SERVERCLASS_ST(CWeaponShotgun, DT_WeaponShotgun)
  73. END_SEND_TABLE()
  74. LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun );
  75. PRECACHE_WEAPON_REGISTER(weapon_shotgun);
  76. BEGIN_DATADESC( CWeaponShotgun )
  77. DEFINE_FIELD( m_bNeedPump, FIELD_BOOLEAN ),
  78. DEFINE_FIELD( m_bDelayedFire1, FIELD_BOOLEAN ),
  79. DEFINE_FIELD( m_bDelayedFire2, FIELD_BOOLEAN ),
  80. END_DATADESC()
  81. acttable_t CWeaponShotgun::m_acttable[] =
  82. {
  83. { ACT_IDLE, ACT_IDLE_SMG1, true }, // FIXME: hook to shotgun unique
  84. { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
  85. { ACT_RELOAD, ACT_RELOAD_SHOTGUN, false },
  86. { ACT_WALK, ACT_WALK_RIFLE, true },
  87. { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true },
  88. // Readiness activities (not aiming)
  89. { ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims
  90. { ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false },
  91. { ACT_IDLE_AGITATED, ACT_IDLE_SHOTGUN_AGITATED, false },//always aims
  92. { ACT_WALK_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
  93. { ACT_WALK_STIMULATED, ACT_WALK_RIFLE_STIMULATED, false },
  94. { ACT_WALK_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
  95. { ACT_RUN_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
  96. { ACT_RUN_STIMULATED, ACT_RUN_RIFLE_STIMULATED, false },
  97. { ACT_RUN_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
  98. // Readiness activities (aiming)
  99. { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims
  100. { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_RIFLE_STIMULATED, false },
  101. { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SMG1, false },//always aims
  102. { ACT_WALK_AIM_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
  103. { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_RIFLE_STIMULATED, false },
  104. { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
  105. { ACT_RUN_AIM_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
  106. { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_RIFLE_STIMULATED, false },
  107. { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
  108. //End readiness activities
  109. { ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true },
  110. { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true },
  111. { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true },
  112. { ACT_RUN, ACT_RUN_RIFLE, true },
  113. { ACT_RUN_AIM, ACT_RUN_AIM_SHOTGUN, true },
  114. { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true },
  115. { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true },
  116. { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
  117. { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true },
  118. { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false },
  119. { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },
  120. };
  121. IMPLEMENT_ACTTABLE(CWeaponShotgun);
  122. void CWeaponShotgun::Precache( void )
  123. {
  124. CBaseCombatWeapon::Precache();
  125. }
  126. //-----------------------------------------------------------------------------
  127. // Purpose:
  128. // Input : *pOperator -
  129. //-----------------------------------------------------------------------------
  130. void CWeaponShotgun::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles )
  131. {
  132. Vector vecShootOrigin, vecShootDir;
  133. CAI_BaseNPC *npc = pOperator->MyNPCPointer();
  134. ASSERT( npc != NULL );
  135. WeaponSound( SINGLE_NPC );
  136. pOperator->DoMuzzleFlash();
  137. m_iClip1 = m_iClip1 - 1;
  138. if ( bUseWeaponAngles )
  139. {
  140. QAngle angShootDir;
  141. GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir );
  142. AngleVectors( angShootDir, &vecShootDir );
  143. }
  144. else
  145. {
  146. vecShootOrigin = pOperator->Weapon_ShootPosition();
  147. vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );
  148. }
  149. pOperator->FireBullets( 8, vecShootOrigin, vecShootDir, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. void CWeaponShotgun::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary )
  155. {
  156. // Ensure we have enough rounds in the clip
  157. m_iClip1++;
  158. FireNPCPrimaryAttack( pOperator, true );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose:
  162. // Input :
  163. // Output :
  164. //-----------------------------------------------------------------------------
  165. void CWeaponShotgun::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
  166. {
  167. switch( pEvent->event )
  168. {
  169. case EVENT_WEAPON_SHOTGUN_FIRE:
  170. {
  171. FireNPCPrimaryAttack( pOperator, false );
  172. }
  173. break;
  174. default:
  175. CBaseCombatWeapon::Operator_HandleAnimEvent( pEvent, pOperator );
  176. break;
  177. }
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose: When we shipped HL2, the shotgun weapon did not override the
  181. // BaseCombatWeapon default rest time of 0.3 to 0.6 seconds. When
  182. // NPC's fight from a stationary position, their animation events
  183. // govern when they fire so the rate of fire is specified by the
  184. // animation. When NPC's move-and-shoot, the rate of fire is
  185. // specifically controlled by the shot regulator, so it's imporant
  186. // that GetMinRestTime and GetMaxRestTime are implemented and provide
  187. // reasonable defaults for the weapon. To address difficulty concerns,
  188. // we are going to fix the combine's rate of shotgun fire in episodic.
  189. // This change will not affect Alyx using a shotgun in EP1. (sjb)
  190. //-----------------------------------------------------------------------------
  191. float CWeaponShotgun::GetMinRestTime()
  192. {
  193. if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
  194. {
  195. return 1.2f;
  196. }
  197. return BaseClass::GetMinRestTime();
  198. }
  199. //-----------------------------------------------------------------------------
  200. //-----------------------------------------------------------------------------
  201. float CWeaponShotgun::GetMaxRestTime()
  202. {
  203. if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
  204. {
  205. return 1.5f;
  206. }
  207. return BaseClass::GetMaxRestTime();
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: Time between successive shots in a burst. Also returned for EP2
  211. // with an eye to not messing up Alyx in EP1.
  212. //-----------------------------------------------------------------------------
  213. float CWeaponShotgun::GetFireRate()
  214. {
  215. if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
  216. {
  217. return 0.8f;
  218. }
  219. return 0.7;
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Purpose: Override so only reload one shell at a time
  223. // Input :
  224. // Output :
  225. //-----------------------------------------------------------------------------
  226. bool CWeaponShotgun::StartReload( void )
  227. {
  228. CBaseCombatCharacter *pOwner = GetOwner();
  229. if ( pOwner == NULL )
  230. return false;
  231. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  232. return false;
  233. if (m_iClip1 >= GetMaxClip1())
  234. return false;
  235. // If shotgun totally emptied then a pump animation is needed
  236. //NOTENOTE: This is kinda lame because the player doesn't get strong feedback on when the reload has finished,
  237. // without the pump. Technically, it's incorrect, but it's good for feedback...
  238. if (m_iClip1 <= 0)
  239. {
  240. m_bNeedPump = true;
  241. }
  242. int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  243. if (j <= 0)
  244. return false;
  245. SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
  246. // Make shotgun shell visible
  247. SetBodygroup(1,0);
  248. pOwner->m_flNextAttack = gpGlobals->curtime;
  249. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  250. m_bInReload = true;
  251. return true;
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose: Override so only reload one shell at a time
  255. // Input :
  256. // Output :
  257. //-----------------------------------------------------------------------------
  258. bool CWeaponShotgun::Reload( void )
  259. {
  260. // Check that StartReload was called first
  261. if (!m_bInReload)
  262. {
  263. Warning("ERROR: Shotgun Reload called incorrectly!\n");
  264. }
  265. CBaseCombatCharacter *pOwner = GetOwner();
  266. if ( pOwner == NULL )
  267. return false;
  268. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  269. return false;
  270. if (m_iClip1 >= GetMaxClip1())
  271. return false;
  272. int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  273. if (j <= 0)
  274. return false;
  275. FillClip();
  276. // Play reload on different channel as otherwise steals channel away from fire sound
  277. WeaponSound(RELOAD);
  278. SendWeaponAnim( ACT_VM_RELOAD );
  279. pOwner->m_flNextAttack = gpGlobals->curtime;
  280. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  281. return true;
  282. }
  283. //-----------------------------------------------------------------------------
  284. // Purpose: Play finish reload anim and fill clip
  285. // Input :
  286. // Output :
  287. //-----------------------------------------------------------------------------
  288. void CWeaponShotgun::FinishReload( void )
  289. {
  290. // Make shotgun shell invisible
  291. SetBodygroup(1,1);
  292. CBaseCombatCharacter *pOwner = GetOwner();
  293. if ( pOwner == NULL )
  294. return;
  295. m_bInReload = false;
  296. // Finish reload animation
  297. SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
  298. pOwner->m_flNextAttack = gpGlobals->curtime;
  299. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose: Play finish reload anim and fill clip
  303. // Input :
  304. // Output :
  305. //-----------------------------------------------------------------------------
  306. void CWeaponShotgun::FillClip( void )
  307. {
  308. CBaseCombatCharacter *pOwner = GetOwner();
  309. if ( pOwner == NULL )
  310. return;
  311. // Add them to the clip
  312. if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
  313. {
  314. if ( Clip1() < GetMaxClip1() )
  315. {
  316. m_iClip1++;
  317. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  318. }
  319. }
  320. }
  321. //-----------------------------------------------------------------------------
  322. // Purpose: Play weapon pump anim
  323. // Input :
  324. // Output :
  325. //-----------------------------------------------------------------------------
  326. void CWeaponShotgun::Pump( void )
  327. {
  328. CBaseCombatCharacter *pOwner = GetOwner();
  329. if ( pOwner == NULL )
  330. return;
  331. m_bNeedPump = false;
  332. WeaponSound( SPECIAL1 );
  333. // Finish reload animation
  334. SendWeaponAnim( ACT_SHOTGUN_PUMP );
  335. pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
  336. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose:
  340. //
  341. //
  342. //-----------------------------------------------------------------------------
  343. void CWeaponShotgun::DryFire( void )
  344. {
  345. WeaponSound(EMPTY);
  346. SendWeaponAnim( ACT_VM_DRYFIRE );
  347. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Purpose:
  351. //
  352. //
  353. //-----------------------------------------------------------------------------
  354. void CWeaponShotgun::PrimaryAttack( void )
  355. {
  356. // Only the player fires this way so we can cast
  357. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  358. if (!pPlayer)
  359. {
  360. return;
  361. }
  362. // MUST call sound before removing a round from the clip of a CMachineGun
  363. WeaponSound(SINGLE);
  364. pPlayer->DoMuzzleFlash();
  365. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  366. // player "shoot" animation
  367. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  368. // Don't fire again until fire animation has completed
  369. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  370. m_iClip1 -= 1;
  371. Vector vecSrc = pPlayer->Weapon_ShootPosition( );
  372. Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
  373. pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
  374. // Fire the bullets, and force the first shot to be perfectly accuracy
  375. pPlayer->FireBullets( sk_plr_num_shotgun_pellets.GetInt(), vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, true, true );
  376. pPlayer->ViewPunch( QAngle( random->RandomFloat( -2, -1 ), random->RandomFloat( -2, 2 ), 0 ) );
  377. CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2, GetOwner() );
  378. if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  379. {
  380. // HEV suit - indicate out of ammo condition
  381. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  382. }
  383. if( m_iClip1 )
  384. {
  385. // pump so long as some rounds are left.
  386. m_bNeedPump = true;
  387. }
  388. m_iPrimaryAttacks++;
  389. gamestats->Event_WeaponFired( pPlayer, true, GetClassname() );
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose:
  393. //
  394. //
  395. //-----------------------------------------------------------------------------
  396. void CWeaponShotgun::SecondaryAttack( void )
  397. {
  398. // Only the player fires this way so we can cast
  399. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  400. if (!pPlayer)
  401. {
  402. return;
  403. }
  404. pPlayer->m_nButtons &= ~IN_ATTACK2;
  405. // MUST call sound before removing a round from the clip of a CMachineGun
  406. WeaponSound(WPN_DOUBLE);
  407. pPlayer->DoMuzzleFlash();
  408. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  409. // player "shoot" animation
  410. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  411. // Don't fire again until fire animation has completed
  412. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  413. m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks
  414. Vector vecSrc = pPlayer->Weapon_ShootPosition();
  415. Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
  416. // Fire the bullets
  417. pPlayer->FireBullets( 12, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, false, false );
  418. pPlayer->ViewPunch( QAngle(random->RandomFloat( -5, 5 ),0,0) );
  419. pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
  420. CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2 );
  421. if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  422. {
  423. // HEV suit - indicate out of ammo condition
  424. pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  425. }
  426. if( m_iClip1 )
  427. {
  428. // pump so long as some rounds are left.
  429. m_bNeedPump = true;
  430. }
  431. m_iSecondaryAttacks++;
  432. gamestats->Event_WeaponFired( pPlayer, false, GetClassname() );
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Purpose: Override so shotgun can do mulitple reloads in a row
  436. //-----------------------------------------------------------------------------
  437. void CWeaponShotgun::ItemPostFrame( void )
  438. {
  439. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  440. if (!pOwner)
  441. {
  442. return;
  443. }
  444. if (m_bInReload)
  445. {
  446. // If I'm primary firing and have one round stop reloading and fire
  447. if ((pOwner->m_nButtons & IN_ATTACK ) && (m_iClip1 >=1))
  448. {
  449. m_bInReload = false;
  450. m_bNeedPump = false;
  451. m_bDelayedFire1 = true;
  452. }
  453. // If I'm secondary firing and have one round stop reloading and fire
  454. else if ((pOwner->m_nButtons & IN_ATTACK2 ) && (m_iClip1 >=2))
  455. {
  456. m_bInReload = false;
  457. m_bNeedPump = false;
  458. m_bDelayedFire2 = true;
  459. }
  460. else if (m_flNextPrimaryAttack <= gpGlobals->curtime)
  461. {
  462. // If out of ammo end reload
  463. if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0)
  464. {
  465. FinishReload();
  466. return;
  467. }
  468. // If clip not full reload again
  469. if (m_iClip1 < GetMaxClip1())
  470. {
  471. Reload();
  472. return;
  473. }
  474. // Clip full, stop reloading
  475. else
  476. {
  477. FinishReload();
  478. return;
  479. }
  480. }
  481. }
  482. else
  483. {
  484. // Make shotgun shell invisible
  485. SetBodygroup(1,1);
  486. }
  487. if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  488. {
  489. Pump();
  490. return;
  491. }
  492. // Shotgun uses same timing and ammo for secondary attack
  493. if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2)&&(m_flNextPrimaryAttack <= gpGlobals->curtime))
  494. {
  495. m_bDelayedFire2 = false;
  496. if ( (m_iClip1 <= 1 && UsesClipsForAmmo1()))
  497. {
  498. // If only one shell is left, do a single shot instead
  499. if ( m_iClip1 == 1 )
  500. {
  501. PrimaryAttack();
  502. }
  503. else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
  504. {
  505. DryFire();
  506. }
  507. else
  508. {
  509. StartReload();
  510. }
  511. }
  512. // Fire underwater?
  513. else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
  514. {
  515. WeaponSound(EMPTY);
  516. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  517. return;
  518. }
  519. else
  520. {
  521. // If the firing button was just pressed, reset the firing time
  522. if ( pOwner->m_afButtonPressed & IN_ATTACK )
  523. {
  524. m_flNextPrimaryAttack = gpGlobals->curtime;
  525. }
  526. SecondaryAttack();
  527. }
  528. }
  529. else if ( (m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime)
  530. {
  531. m_bDelayedFire1 = false;
  532. if ( (m_iClip1 <= 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType) ) )
  533. {
  534. if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
  535. {
  536. DryFire();
  537. }
  538. else
  539. {
  540. StartReload();
  541. }
  542. }
  543. // Fire underwater?
  544. else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
  545. {
  546. WeaponSound(EMPTY);
  547. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  548. return;
  549. }
  550. else
  551. {
  552. // If the firing button was just pressed, reset the firing time
  553. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  554. if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK )
  555. {
  556. m_flNextPrimaryAttack = gpGlobals->curtime;
  557. }
  558. PrimaryAttack();
  559. }
  560. }
  561. if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload )
  562. {
  563. // reload when reload is pressed, or if no buttons are down and weapon is empty.
  564. StartReload();
  565. }
  566. else
  567. {
  568. // no fire buttons down
  569. m_bFireOnEmpty = false;
  570. if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime )
  571. {
  572. // weapon isn't useable, switch.
  573. if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon( this ) )
  574. {
  575. m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
  576. return;
  577. }
  578. }
  579. else
  580. {
  581. // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  582. if ( m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
  583. {
  584. if (StartReload())
  585. {
  586. // if we've successfully started to reload, we're done
  587. return;
  588. }
  589. }
  590. }
  591. WeaponIdle( );
  592. return;
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Purpose: Constructor
  597. //-----------------------------------------------------------------------------
  598. CWeaponShotgun::CWeaponShotgun( void )
  599. {
  600. m_bReloadsSingly = true;
  601. m_bNeedPump = false;
  602. m_bDelayedFire1 = false;
  603. m_bDelayedFire2 = false;
  604. m_fMinRange1 = 0.0;
  605. m_fMaxRange1 = 500;
  606. m_fMinRange2 = 0.0;
  607. m_fMaxRange2 = 200;
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Purpose:
  611. //-----------------------------------------------------------------------------
  612. void CWeaponShotgun::ItemHolsterFrame( void )
  613. {
  614. // Must be player held
  615. if ( GetOwner() && GetOwner()->IsPlayer() == false )
  616. return;
  617. // We can't be active
  618. if ( GetOwner()->GetActiveWeapon() == this )
  619. return;
  620. // If it's been longer than three seconds, reload
  621. if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
  622. {
  623. // Reset the timer
  624. m_flHolsterTime = gpGlobals->curtime;
  625. if ( GetOwner() == NULL )
  626. return;
  627. if ( m_iClip1 == GetMaxClip1() )
  628. return;
  629. // Just load the clip with no animations
  630. int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
  631. GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
  632. m_iClip1 += ammoFill;
  633. }
  634. }
  635. //==================================================
  636. // Purpose:
  637. //==================================================
  638. /*
  639. void CWeaponShotgun::WeaponIdle( void )
  640. {
  641. //Only the player fires this way so we can cast
  642. CBasePlayer *pPlayer = GetOwner()
  643. if ( pPlayer == NULL )
  644. return;
  645. //If we're on a target, play the new anim
  646. if ( pPlayer->IsOnTarget() )
  647. {
  648. SendWeaponAnim( ACT_VM_IDLE_ACTIVE );
  649. }
  650. }
  651. */