summaryrefslogtreecommitdiff
path: root/game/server/hl2/weapon_shotgun.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/hl2/weapon_shotgun.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/hl2/weapon_shotgun.cpp')
-rw-r--r--game/server/hl2/weapon_shotgun.cpp793
1 files changed, 793 insertions, 0 deletions
diff --git a/game/server/hl2/weapon_shotgun.cpp b/game/server/hl2/weapon_shotgun.cpp
new file mode 100644
index 0000000..a832a3d
--- /dev/null
+++ b/game/server/hl2/weapon_shotgun.cpp
@@ -0,0 +1,793 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A shotgun.
+//
+// Primary attack: single barrel shot.
+// Secondary attack: double barrel shot.
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "npcevent.h"
+#include "basehlcombatweapon_shared.h"
+#include "basecombatcharacter.h"
+#include "ai_basenpc.h"
+#include "player.h"
+#include "gamerules.h" // For g_pGameRules
+#include "in_buttons.h"
+#include "soundent.h"
+#include "vstdlib/random.h"
+#include "gamestats.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern ConVar sk_auto_reload_time;
+extern ConVar sk_plr_num_shotgun_pellets;
+
+class CWeaponShotgun : public CBaseHLCombatWeapon
+{
+ DECLARE_DATADESC();
+public:
+ DECLARE_CLASS( CWeaponShotgun, CBaseHLCombatWeapon );
+
+ DECLARE_SERVERCLASS();
+
+private:
+ bool m_bNeedPump; // When emptied completely
+ bool m_bDelayedFire1; // Fire primary when finished reloading
+ bool m_bDelayedFire2; // Fire secondary when finished reloading
+
+public:
+ void Precache( void );
+
+ int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
+
+ virtual const Vector& GetBulletSpread( void )
+ {
+ static Vector vitalAllyCone = VECTOR_CONE_3DEGREES;
+ static Vector cone = VECTOR_CONE_10DEGREES;
+
+ if( GetOwner() && (GetOwner()->Classify() == CLASS_PLAYER_ALLY_VITAL) )
+ {
+ // Give Alyx's shotgun blasts more a more directed punch. She needs
+ // to be at least as deadly as she would be with her pistol to stay interesting (sjb)
+ return vitalAllyCone;
+ }
+
+ return cone;
+ }
+
+ virtual int GetMinBurst() { return 1; }
+ virtual int GetMaxBurst() { return 3; }
+
+ virtual float GetMinRestTime();
+ virtual float GetMaxRestTime();
+
+ virtual float GetFireRate( void );
+
+ bool StartReload( void );
+ bool Reload( void );
+ void FillClip( void );
+ void FinishReload( void );
+ void CheckHolsterReload( void );
+ void Pump( void );
+// void WeaponIdle( void );
+ void ItemHolsterFrame( void );
+ void ItemPostFrame( void );
+ void PrimaryAttack( void );
+ void SecondaryAttack( void );
+ void DryFire( void );
+
+ void FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles );
+ void Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary );
+ void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
+
+ DECLARE_ACTTABLE();
+
+ CWeaponShotgun(void);
+};
+
+IMPLEMENT_SERVERCLASS_ST(CWeaponShotgun, DT_WeaponShotgun)
+END_SEND_TABLE()
+
+LINK_ENTITY_TO_CLASS( weapon_shotgun, CWeaponShotgun );
+PRECACHE_WEAPON_REGISTER(weapon_shotgun);
+
+BEGIN_DATADESC( CWeaponShotgun )
+
+ DEFINE_FIELD( m_bNeedPump, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bDelayedFire1, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bDelayedFire2, FIELD_BOOLEAN ),
+
+END_DATADESC()
+
+acttable_t CWeaponShotgun::m_acttable[] =
+{
+ { ACT_IDLE, ACT_IDLE_SMG1, true }, // FIXME: hook to shotgun unique
+
+ { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
+ { ACT_RELOAD, ACT_RELOAD_SHOTGUN, false },
+ { ACT_WALK, ACT_WALK_RIFLE, true },
+ { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true },
+
+// Readiness activities (not aiming)
+ { ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims
+ { ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false },
+ { ACT_IDLE_AGITATED, ACT_IDLE_SHOTGUN_AGITATED, false },//always aims
+
+ { ACT_WALK_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
+ { ACT_WALK_STIMULATED, ACT_WALK_RIFLE_STIMULATED, false },
+ { ACT_WALK_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
+
+ { ACT_RUN_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
+ { ACT_RUN_STIMULATED, ACT_RUN_RIFLE_STIMULATED, false },
+ { ACT_RUN_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
+
+// Readiness activities (aiming)
+ { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims
+ { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_RIFLE_STIMULATED, false },
+ { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SMG1, false },//always aims
+
+ { ACT_WALK_AIM_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
+ { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_RIFLE_STIMULATED, false },
+ { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
+
+ { ACT_RUN_AIM_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
+ { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_RIFLE_STIMULATED, false },
+ { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
+//End readiness activities
+
+ { ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true },
+ { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true },
+ { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true },
+ { ACT_RUN, ACT_RUN_RIFLE, true },
+ { ACT_RUN_AIM, ACT_RUN_AIM_SHOTGUN, true },
+ { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true },
+ { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true },
+ { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
+ { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true },
+ { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false },
+ { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },
+};
+
+IMPLEMENT_ACTTABLE(CWeaponShotgun);
+
+void CWeaponShotgun::Precache( void )
+{
+ CBaseCombatWeapon::Precache();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pOperator -
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles )
+{
+ Vector vecShootOrigin, vecShootDir;
+ CAI_BaseNPC *npc = pOperator->MyNPCPointer();
+ ASSERT( npc != NULL );
+ WeaponSound( SINGLE_NPC );
+ pOperator->DoMuzzleFlash();
+ m_iClip1 = m_iClip1 - 1;
+
+ if ( bUseWeaponAngles )
+ {
+ QAngle angShootDir;
+ GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir );
+ AngleVectors( angShootDir, &vecShootDir );
+ }
+ else
+ {
+ vecShootOrigin = pOperator->Weapon_ShootPosition();
+ vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );
+ }
+
+ pOperator->FireBullets( 8, vecShootOrigin, vecShootDir, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary )
+{
+ // Ensure we have enough rounds in the clip
+ m_iClip1++;
+
+ FireNPCPrimaryAttack( pOperator, true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
+{
+ switch( pEvent->event )
+ {
+ case EVENT_WEAPON_SHOTGUN_FIRE:
+ {
+ FireNPCPrimaryAttack( pOperator, false );
+ }
+ break;
+
+ default:
+ CBaseCombatWeapon::Operator_HandleAnimEvent( pEvent, pOperator );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: When we shipped HL2, the shotgun weapon did not override the
+// BaseCombatWeapon default rest time of 0.3 to 0.6 seconds. When
+// NPC's fight from a stationary position, their animation events
+// govern when they fire so the rate of fire is specified by the
+// animation. When NPC's move-and-shoot, the rate of fire is
+// specifically controlled by the shot regulator, so it's imporant
+// that GetMinRestTime and GetMaxRestTime are implemented and provide
+// reasonable defaults for the weapon. To address difficulty concerns,
+// we are going to fix the combine's rate of shotgun fire in episodic.
+// This change will not affect Alyx using a shotgun in EP1. (sjb)
+//-----------------------------------------------------------------------------
+float CWeaponShotgun::GetMinRestTime()
+{
+ if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
+ {
+ return 1.2f;
+ }
+
+ return BaseClass::GetMinRestTime();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+float CWeaponShotgun::GetMaxRestTime()
+{
+ if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
+ {
+ return 1.5f;
+ }
+
+ return BaseClass::GetMaxRestTime();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Time between successive shots in a burst. Also returned for EP2
+// with an eye to not messing up Alyx in EP1.
+//-----------------------------------------------------------------------------
+float CWeaponShotgun::GetFireRate()
+{
+ if( hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE )
+ {
+ return 0.8f;
+ }
+
+ return 0.7;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Override so only reload one shell at a time
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+bool CWeaponShotgun::StartReload( void )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return false;
+
+ if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ return false;
+
+ if (m_iClip1 >= GetMaxClip1())
+ return false;
+
+ // If shotgun totally emptied then a pump animation is needed
+
+ //NOTENOTE: This is kinda lame because the player doesn't get strong feedback on when the reload has finished,
+ // without the pump. Technically, it's incorrect, but it's good for feedback...
+
+ if (m_iClip1 <= 0)
+ {
+ m_bNeedPump = true;
+ }
+
+ int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
+
+ if (j <= 0)
+ return false;
+
+ SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
+
+ // Make shotgun shell visible
+ SetBodygroup(1,0);
+
+ pOwner->m_flNextAttack = gpGlobals->curtime;
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+
+ m_bInReload = true;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Override so only reload one shell at a time
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+bool CWeaponShotgun::Reload( void )
+{
+ // Check that StartReload was called first
+ if (!m_bInReload)
+ {
+ Warning("ERROR: Shotgun Reload called incorrectly!\n");
+ }
+
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return false;
+
+ if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ return false;
+
+ if (m_iClip1 >= GetMaxClip1())
+ return false;
+
+ int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
+
+ if (j <= 0)
+ return false;
+
+ FillClip();
+ // Play reload on different channel as otherwise steals channel away from fire sound
+ WeaponSound(RELOAD);
+ SendWeaponAnim( ACT_VM_RELOAD );
+
+ pOwner->m_flNextAttack = gpGlobals->curtime;
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play finish reload anim and fill clip
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::FinishReload( void )
+{
+ // Make shotgun shell invisible
+ SetBodygroup(1,1);
+
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return;
+
+ m_bInReload = false;
+
+ // Finish reload animation
+ SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
+
+ pOwner->m_flNextAttack = gpGlobals->curtime;
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play finish reload anim and fill clip
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::FillClip( void )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return;
+
+ // Add them to the clip
+ if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
+ {
+ if ( Clip1() < GetMaxClip1() )
+ {
+ m_iClip1++;
+ pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play weapon pump anim
+// Input :
+// Output :
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::Pump( void )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return;
+
+ m_bNeedPump = false;
+
+ WeaponSound( SPECIAL1 );
+
+ // Finish reload animation
+ SendWeaponAnim( ACT_SHOTGUN_PUMP );
+
+ pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+//
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::DryFire( void )
+{
+ WeaponSound(EMPTY);
+ SendWeaponAnim( ACT_VM_DRYFIRE );
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+//
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::PrimaryAttack( void )
+{
+ // Only the player fires this way so we can cast
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ if (!pPlayer)
+ {
+ return;
+ }
+
+ // MUST call sound before removing a round from the clip of a CMachineGun
+ WeaponSound(SINGLE);
+
+ pPlayer->DoMuzzleFlash();
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+ // Don't fire again until fire animation has completed
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_iClip1 -= 1;
+
+ Vector vecSrc = pPlayer->Weapon_ShootPosition( );
+ Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
+
+ pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
+
+ // Fire the bullets, and force the first shot to be perfectly accuracy
+ pPlayer->FireBullets( sk_plr_num_shotgun_pellets.GetInt(), vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, true, true );
+
+ pPlayer->ViewPunch( QAngle( random->RandomFloat( -2, -1 ), random->RandomFloat( -2, 2 ), 0 ) );
+
+ CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2, GetOwner() );
+
+ if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ {
+ // HEV suit - indicate out of ammo condition
+ pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
+ }
+
+ if( m_iClip1 )
+ {
+ // pump so long as some rounds are left.
+ m_bNeedPump = true;
+ }
+
+ m_iPrimaryAttacks++;
+ gamestats->Event_WeaponFired( pPlayer, true, GetClassname() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+//
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::SecondaryAttack( void )
+{
+ // Only the player fires this way so we can cast
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ if (!pPlayer)
+ {
+ return;
+ }
+
+ pPlayer->m_nButtons &= ~IN_ATTACK2;
+ // MUST call sound before removing a round from the clip of a CMachineGun
+ WeaponSound(WPN_DOUBLE);
+
+ pPlayer->DoMuzzleFlash();
+
+ SendWeaponAnim( ACT_VM_SECONDARYATTACK );
+
+ // player "shoot" animation
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+
+ // Don't fire again until fire animation has completed
+ m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
+ m_iClip1 -= 2; // Shotgun uses same clip for primary and secondary attacks
+
+ Vector vecSrc = pPlayer->Weapon_ShootPosition();
+ Vector vecAiming = pPlayer->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT );
+
+ // Fire the bullets
+ pPlayer->FireBullets( 12, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, false, false );
+ pPlayer->ViewPunch( QAngle(random->RandomFloat( -5, 5 ),0,0) );
+
+ pPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 1.0 );
+
+ CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2 );
+
+ if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
+ {
+ // HEV suit - indicate out of ammo condition
+ pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
+ }
+
+ if( m_iClip1 )
+ {
+ // pump so long as some rounds are left.
+ m_bNeedPump = true;
+ }
+
+ m_iSecondaryAttacks++;
+ gamestats->Event_WeaponFired( pPlayer, false, GetClassname() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Override so shotgun can do mulitple reloads in a row
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::ItemPostFrame( void )
+{
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+ if (!pOwner)
+ {
+ return;
+ }
+
+ if (m_bInReload)
+ {
+ // If I'm primary firing and have one round stop reloading and fire
+ if ((pOwner->m_nButtons & IN_ATTACK ) && (m_iClip1 >=1))
+ {
+ m_bInReload = false;
+ m_bNeedPump = false;
+ m_bDelayedFire1 = true;
+ }
+ // If I'm secondary firing and have one round stop reloading and fire
+ else if ((pOwner->m_nButtons & IN_ATTACK2 ) && (m_iClip1 >=2))
+ {
+ m_bInReload = false;
+ m_bNeedPump = false;
+ m_bDelayedFire2 = true;
+ }
+ else if (m_flNextPrimaryAttack <= gpGlobals->curtime)
+ {
+ // If out of ammo end reload
+ if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <=0)
+ {
+ FinishReload();
+ return;
+ }
+ // If clip not full reload again
+ if (m_iClip1 < GetMaxClip1())
+ {
+ Reload();
+ return;
+ }
+ // Clip full, stop reloading
+ else
+ {
+ FinishReload();
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Make shotgun shell invisible
+ SetBodygroup(1,1);
+ }
+
+ if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
+ {
+ Pump();
+ return;
+ }
+
+ // Shotgun uses same timing and ammo for secondary attack
+ if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2)&&(m_flNextPrimaryAttack <= gpGlobals->curtime))
+ {
+ m_bDelayedFire2 = false;
+
+ if ( (m_iClip1 <= 1 && UsesClipsForAmmo1()))
+ {
+ // If only one shell is left, do a single shot instead
+ if ( m_iClip1 == 1 )
+ {
+ PrimaryAttack();
+ }
+ else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
+ {
+ DryFire();
+ }
+ else
+ {
+ StartReload();
+ }
+ }
+
+ // Fire underwater?
+ else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
+ {
+ WeaponSound(EMPTY);
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ return;
+ }
+ else
+ {
+ // If the firing button was just pressed, reset the firing time
+ if ( pOwner->m_afButtonPressed & IN_ATTACK )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime;
+ }
+ SecondaryAttack();
+ }
+ }
+ else if ( (m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime)
+ {
+ m_bDelayedFire1 = false;
+ if ( (m_iClip1 <= 0 && UsesClipsForAmmo1()) || ( !UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType) ) )
+ {
+ if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
+ {
+ DryFire();
+ }
+ else
+ {
+ StartReload();
+ }
+ }
+ // Fire underwater?
+ else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
+ {
+ WeaponSound(EMPTY);
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ return;
+ }
+ else
+ {
+ // If the firing button was just pressed, reset the firing time
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+ if ( pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime;
+ }
+ PrimaryAttack();
+ }
+ }
+
+ if ( pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload )
+ {
+ // reload when reload is pressed, or if no buttons are down and weapon is empty.
+ StartReload();
+ }
+ else
+ {
+ // no fire buttons down
+ m_bFireOnEmpty = false;
+
+ if ( !HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime )
+ {
+ // weapon isn't useable, switch.
+ if ( !(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon( this ) )
+ {
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
+ return;
+ }
+ }
+ else
+ {
+ // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
+ if ( m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
+ {
+ if (StartReload())
+ {
+ // if we've successfully started to reload, we're done
+ return;
+ }
+ }
+ }
+
+ WeaponIdle( );
+ return;
+ }
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CWeaponShotgun::CWeaponShotgun( void )
+{
+ m_bReloadsSingly = true;
+
+ m_bNeedPump = false;
+ m_bDelayedFire1 = false;
+ m_bDelayedFire2 = false;
+
+ m_fMinRange1 = 0.0;
+ m_fMaxRange1 = 500;
+ m_fMinRange2 = 0.0;
+ m_fMaxRange2 = 200;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponShotgun::ItemHolsterFrame( void )
+{
+ // Must be player held
+ if ( GetOwner() && GetOwner()->IsPlayer() == false )
+ return;
+
+ // We can't be active
+ if ( GetOwner()->GetActiveWeapon() == this )
+ return;
+
+ // If it's been longer than three seconds, reload
+ if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() )
+ {
+ // Reset the timer
+ m_flHolsterTime = gpGlobals->curtime;
+
+ if ( GetOwner() == NULL )
+ return;
+
+ if ( m_iClip1 == GetMaxClip1() )
+ return;
+
+ // Just load the clip with no animations
+ int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) );
+
+ GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() );
+ m_iClip1 += ammoFill;
+ }
+}
+
+//==================================================
+// Purpose:
+//==================================================
+/*
+void CWeaponShotgun::WeaponIdle( void )
+{
+ //Only the player fires this way so we can cast
+ CBasePlayer *pPlayer = GetOwner()
+
+ if ( pPlayer == NULL )
+ return;
+
+ //If we're on a target, play the new anim
+ if ( pPlayer->IsOnTarget() )
+ {
+ SendWeaponAnim( ACT_VM_IDLE_ACTIVE );
+ }
+}
+*/