3DL1N

weapon_carabine

Oct 3rd, 2019
322
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 24.83 KB | None | 0 0
  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:     Carabine - The Paradox carabine weapon
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7.  
  8. #include "cbase.h"
  9. #include "npcevent.h"
  10. #include "basehlcombatweapon_shared.h"
  11. #include "basecombatcharacter.h"
  12. #include "ai_basenpc.h"
  13. #include "player.h"
  14. #include "gamerules.h"      // For g_pGameRules
  15. #include "in_buttons.h"
  16. #include "soundent.h"
  17. #include "vstdlib/random.h"
  18. #include "gamestats.h"
  19.  
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22.  
  23. extern ConVar sk_auto_reload_time;
  24.  
  25. class CWeaponCarabine : public CBaseHLCombatWeapon
  26. {
  27.     DECLARE_DATADESC();
  28. public:
  29.     DECLARE_CLASS(CWeaponCarabine, CBaseHLCombatWeapon);
  30.  
  31.     DECLARE_SERVERCLASS();
  32.  
  33. private:
  34.     bool    m_bNeedPump;        // When emptied completely
  35.     bool    m_bDelayedFire1;    // Fire primary when finished reloading
  36.     bool    m_bDelayedFire2;    // Fire secondary when finished reloading
  37.  
  38.     bool bFlip;
  39.  
  40. public:
  41.     void    Precache(void);
  42.  
  43.     int CapabilitiesGet(void) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
  44.  
  45.     virtual const Vector& GetBulletSpread(void)
  46.     {
  47.         static Vector vitalAllyCone = VECTOR_CONE_3DEGREES;
  48.         static Vector cone = VECTOR_CONE_10DEGREES;
  49.  
  50.         if (GetOwner() && (GetOwner()->Classify() == CLASS_PLAYER_ALLY_VITAL))
  51.         {
  52.             // Give Alyx's carabine blasts more a more directed punch. She needs
  53.             // to be at least as deadly as she would be with her pistol to stay interesting (sjb)
  54.             return vitalAllyCone;
  55.         }
  56.  
  57.         return cone;
  58.     }
  59.  
  60.     virtual int             GetMinBurst() { return 1; }
  61.     virtual int             GetMaxBurst() { return 3; }
  62.  
  63.     virtual float           GetMinRestTime();
  64.     virtual float           GetMaxRestTime();
  65.  
  66.     virtual float           GetFireRate(void);
  67.  
  68.     bool StartReload(void);
  69.     bool Reload(void);
  70.     void FillClip(void);
  71.     void FinishReload(void);
  72.     void CheckHolsterReload(void);
  73.     void Pump(void);
  74.     void WeaponIdle( void );
  75.     void ItemHolsterFrame(void);
  76.     void ItemPostFrame(void);
  77.     void PrimaryAttack(void);
  78.     void LeftGunAttack(void);
  79.     void SecondaryAttack(void);
  80.     void DryFire(void);
  81.  
  82.     void FireNPCPrimaryAttack(CBaseCombatCharacter *pOperator, bool bUseWeaponAngles);
  83.     void Operator_ForceNPCFire(CBaseCombatCharacter  *pOperator, bool bSecondary);
  84.     void Operator_HandleAnimEvent(animevent_t *pEvent, CBaseCombatCharacter *pOperator);
  85.  
  86.     DECLARE_ACTTABLE();
  87.  
  88.     CWeaponCarabine(void);
  89. };
  90.  
  91. IMPLEMENT_SERVERCLASS_ST(CWeaponCarabine, DT_WeaponCarabine)
  92. END_SEND_TABLE()
  93.  
  94. LINK_ENTITY_TO_CLASS(weapon_carabine, CWeaponCarabine);
  95. PRECACHE_WEAPON_REGISTER(weapon_carabine);
  96.  
  97. BEGIN_DATADESC(CWeaponCarabine)
  98.  
  99. DEFINE_FIELD(m_bNeedPump, FIELD_BOOLEAN),
  100. DEFINE_FIELD(m_bDelayedFire1, FIELD_BOOLEAN),
  101. DEFINE_FIELD(m_bDelayedFire2, FIELD_BOOLEAN),
  102.  
  103. END_DATADESC()
  104.  
  105. acttable_t  CWeaponCarabine::m_acttable[] =
  106. {
  107.     { ACT_IDLE, ACT_IDLE_SMG1, true }// FIXME: hook to shotgun unique
  108.  
  109.     { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true },
  110.     { ACT_RELOAD, ACT_RELOAD_SHOTGUN, false },
  111.     { ACT_WALK, ACT_WALK_RIFLE, true },
  112.     { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SHOTGUN, true },
  113.  
  114.     // Readiness activities (not aiming)
  115.     { ACT_IDLE_RELAXED, ACT_IDLE_SHOTGUN_RELAXED, false },//never aims
  116.     { ACT_IDLE_STIMULATED, ACT_IDLE_SHOTGUN_STIMULATED, false },
  117.     { ACT_IDLE_AGITATED, ACT_IDLE_SHOTGUN_AGITATED, false },//always aims
  118.  
  119.     { ACT_WALK_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
  120.     { ACT_WALK_STIMULATED, ACT_WALK_RIFLE_STIMULATED, false },
  121.     { ACT_WALK_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
  122.  
  123.     { ACT_RUN_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
  124.     { ACT_RUN_STIMULATED, ACT_RUN_RIFLE_STIMULATED, false },
  125.     { ACT_RUN_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
  126.  
  127.     // Readiness activities (aiming)
  128.     { ACT_IDLE_AIM_RELAXED, ACT_IDLE_SMG1_RELAXED, false },//never aims
  129.     { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_AIM_RIFLE_STIMULATED, false },
  130.     { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_SMG1, false },//always aims
  131.  
  132.     { ACT_WALK_AIM_RELAXED, ACT_WALK_RIFLE_RELAXED, false },//never aims
  133.     { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_RIFLE_STIMULATED, false },
  134.     { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_RIFLE, false },//always aims
  135.  
  136.     { ACT_RUN_AIM_RELAXED, ACT_RUN_RIFLE_RELAXED, false },//never aims
  137.     { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_RIFLE_STIMULATED, false },
  138.     { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_RIFLE, false },//always aims
  139.     //End readiness activities
  140.  
  141.     { ACT_WALK_AIM, ACT_WALK_AIM_SHOTGUN, true },
  142.     { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, true },
  143.     { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, true },
  144.     { ACT_RUN, ACT_RUN_RIFLE, true },
  145.     { ACT_RUN_AIM, ACT_RUN_AIM_SHOTGUN, true },
  146.     { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, true },
  147.     { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, true },
  148.     { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true },
  149.     { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_SHOTGUN_LOW, true },
  150.     { ACT_RELOAD_LOW, ACT_RELOAD_SHOTGUN_LOW, false },
  151.     { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SHOTGUN, false },
  152. };
  153.  
  154. IMPLEMENT_ACTTABLE(CWeaponCarabine);
  155.  
  156. void CWeaponCarabine::Precache(void)
  157. {
  158.     CBaseCombatWeapon::Precache();
  159. }
  160.  
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. // Input  : *pOperator -
  164. //-----------------------------------------------------------------------------
  165. void CWeaponCarabine::FireNPCPrimaryAttack(CBaseCombatCharacter *pOperator, bool bUseWeaponAngles)
  166. {
  167.     Vector vecShootOrigin, vecShootDir;
  168.     CAI_BaseNPC *npc = pOperator->MyNPCPointer();
  169.     ASSERT(npc != NULL);
  170.     WeaponSound(SINGLE_NPC);
  171.     pOperator->DoMuzzleFlash();
  172.     m_iClip1 = m_iClip1 - 1;
  173.  
  174.     if (bUseWeaponAngles)
  175.     {
  176.         QAngle  angShootDir;
  177.         GetAttachment(LookupAttachment("muzzle"), vecShootOrigin, angShootDir);
  178.         AngleVectors(angShootDir, &vecShootDir);
  179.     }
  180.     else
  181.     {
  182.         vecShootOrigin = pOperator->Weapon_ShootPosition();
  183.         vecShootDir = npc->GetActualShootTrajectory(vecShootOrigin);
  184.     }
  185.  
  186.     pOperator->FireBullets(8, vecShootOrigin, vecShootDir, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0);
  187. }
  188.  
  189. //-----------------------------------------------------------------------------
  190. // Purpose:
  191. //-----------------------------------------------------------------------------
  192. void CWeaponCarabine::Operator_ForceNPCFire(CBaseCombatCharacter *pOperator, bool bSecondary)
  193. {
  194.     // Ensure we have enough rounds in the clip
  195.     m_iClip1++;
  196.  
  197.     FireNPCPrimaryAttack(pOperator, true);
  198. }
  199.  
  200. //-----------------------------------------------------------------------------
  201. // Purpose:
  202. // Input  :
  203. // Output :
  204. //-----------------------------------------------------------------------------
  205. void CWeaponCarabine::Operator_HandleAnimEvent(animevent_t *pEvent, CBaseCombatCharacter *pOperator)
  206. {
  207.     switch (pEvent->event)
  208.     {
  209.     case EVENT_WEAPON_SHOTGUN_FIRE:
  210.     {
  211.         FireNPCPrimaryAttack(pOperator, false);
  212.     }
  213.     break;
  214.  
  215.     default:
  216.         CBaseCombatWeapon::Operator_HandleAnimEvent(pEvent, pOperator);
  217.         break;
  218.     }
  219. }
  220.  
  221.  
  222. //-----------------------------------------------------------------------------
  223. // Purpose: When we shipped HL2, the carabine weapon did not override the
  224. //          BaseCombatWeapon default rest time of 0.3 to 0.6 seconds. When
  225. //          NPC's fight from a stationary position, their animation events
  226. //          govern when they fire so the rate of fire is specified by the
  227. //          animation. When NPC's move-and-shoot, the rate of fire is
  228. //          specifically controlled by the shot regulator, so it's imporant
  229. //          that GetMinRestTime and GetMaxRestTime are implemented and provide
  230. //          reasonable defaults for the weapon. To address difficulty concerns,
  231. //          we are going to fix the combine's rate of carabine fire in episodic.
  232. //          This change will not affect Alyx using a carabine in EP1. (sjb)
  233. //-----------------------------------------------------------------------------
  234. float CWeaponCarabine::GetMinRestTime()
  235. {
  236.     if (hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE)
  237.     {
  238.         return 1.2f;
  239.     }
  240.  
  241.     return BaseClass::GetMinRestTime();
  242. }
  243.  
  244. //-----------------------------------------------------------------------------
  245. //-----------------------------------------------------------------------------
  246. float CWeaponCarabine::GetMaxRestTime()
  247. {
  248.     if (hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE)
  249.     {
  250.         return 1.5f;
  251.     }
  252.  
  253.     return BaseClass::GetMaxRestTime();
  254. }
  255.  
  256. //-----------------------------------------------------------------------------
  257. // Purpose: Time between successive shots in a burst. Also returned for EP2
  258. //          with an eye to not messing up Alyx in EP1.
  259. //-----------------------------------------------------------------------------
  260. float CWeaponCarabine::GetFireRate()
  261. {
  262.     if (hl2_episodic.GetBool() && GetOwner() && GetOwner()->Classify() == CLASS_COMBINE)
  263.     {
  264.         return 0.8f;
  265.     }
  266.  
  267.     return 0.7;
  268. }
  269.  
  270. //-----------------------------------------------------------------------------
  271. // Purpose: Override so only reload one shell at a time
  272. // Input  :
  273. // Output :
  274. //-----------------------------------------------------------------------------
  275. bool CWeaponCarabine::StartReload(void)
  276. {
  277.     CBaseCombatCharacter *pOwner = GetOwner();
  278.  
  279.     if (pOwner == NULL)
  280.         return false;
  281.  
  282.     if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  283.         return false;
  284.  
  285.     if (m_iClip1 >= GetMaxClip1())
  286.         return false;
  287.  
  288.     // If carabine totally emptied then a pump animation is needed
  289.  
  290.     //NOTENOTE: This is kinda lame because the player doesn't get strong feedback on when the reload has finished,
  291.     //          without the pump.  Technically, it's incorrect, but it's good for feedback...
  292.  
  293.     if (m_iClip1 <= 0)
  294.     {
  295.         m_bNeedPump = true;
  296.     }
  297.  
  298.     int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  299.  
  300.     if (j <= 0)
  301.         return false;
  302.  
  303.     SendWeaponAnim(ACT_SHOTGUN_RELOAD_START);
  304.  
  305.     // Make carabine shell visible
  306.     SetBodygroup(1, 0);
  307.  
  308.     pOwner->m_flNextAttack = gpGlobals->curtime;
  309.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  310.     m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  311.  
  312.     m_bInReload = true;
  313.     return true;
  314. }
  315.  
  316. //-----------------------------------------------------------------------------
  317. // Purpose: Override so only reload one shell at a time
  318. // Input  :
  319. // Output :
  320. //-----------------------------------------------------------------------------
  321. bool CWeaponCarabine::Reload(void)
  322. {
  323.     // Check that StartReload was called first
  324.     if (!m_bInReload)
  325.     {
  326.         Warning("ERROR: Carabine Reload called incorrectly!\n");
  327.     }
  328.  
  329.     CBaseCombatCharacter *pOwner = GetOwner();
  330.  
  331.     if (pOwner == NULL)
  332.         return false;
  333.  
  334.     if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  335.         return false;
  336.  
  337.     if (m_iClip1 >= GetMaxClip1())
  338.         return false;
  339.  
  340.     int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
  341.  
  342.     if (j <= 0)
  343.         return false;
  344.  
  345.     FillClip();
  346.     // Play reload on different channel as otherwise steals channel away from fire sound
  347.     WeaponSound(RELOAD);
  348.     SendWeaponAnim(ACT_VM_RELOAD);
  349.  
  350.     pOwner->m_flNextAttack = gpGlobals->curtime;
  351.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  352.     m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  353.  
  354.     return true;
  355. }
  356.  
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Play finish reload anim and fill clip
  359. // Input  :
  360. // Output :
  361. //-----------------------------------------------------------------------------
  362. void CWeaponCarabine::FinishReload(void)
  363. {
  364.     // Make carabine shell invisible
  365.     SetBodygroup(1, 1);
  366.  
  367.     CBaseCombatCharacter *pOwner = GetOwner();
  368.  
  369.     if (pOwner == NULL)
  370.         return;
  371.  
  372.     m_bInReload = false;
  373.  
  374.     // Finish reload animation
  375.     SendWeaponAnim(ACT_SHOTGUN_RELOAD_FINISH);
  376.  
  377.     pOwner->m_flNextAttack = gpGlobals->curtime;
  378.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  379. }
  380.  
  381. //-----------------------------------------------------------------------------
  382. // Purpose: Play finish reload anim and fill clip
  383. // Input  :
  384. // Output :
  385. //-----------------------------------------------------------------------------
  386. void CWeaponCarabine::FillClip(void)
  387. {
  388.     CBaseCombatCharacter *pOwner = GetOwner();
  389.  
  390.     if (pOwner == NULL)
  391.         return;
  392.  
  393.     // Add them to the clip
  394.     if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) > 0)
  395.     {
  396.         if (Clip1() < GetMaxClip1())
  397.         {
  398.             m_iClip1++;
  399.             pOwner->RemoveAmmo(1, m_iPrimaryAmmoType);
  400.         }
  401.     }
  402. }
  403.  
  404. //-----------------------------------------------------------------------------
  405. // Purpose: Play weapon pump anim
  406. // Input  :
  407. // Output :
  408. //-----------------------------------------------------------------------------
  409. void CWeaponCarabine::Pump(void)
  410. {
  411.     CBaseCombatCharacter *pOwner = GetOwner();
  412.  
  413.     if (pOwner == NULL)
  414.         return;
  415.  
  416.     m_bNeedPump = false;
  417.  
  418.     WeaponSound(SPECIAL1);
  419.  
  420.     // Finish reload animation
  421.     SendWeaponAnim(ACT_SHOTGUN_PUMP);
  422.  
  423.     pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
  424.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  425. }
  426.  
  427. //-----------------------------------------------------------------------------
  428. // Purpose:
  429. //
  430. //
  431. //-----------------------------------------------------------------------------
  432. void CWeaponCarabine::DryFire(void)
  433. {
  434.     WeaponSound(EMPTY);
  435.     SendWeaponAnim(ACT_VM_DRYFIRE);
  436.  
  437.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  438. }
  439.  
  440. //-----------------------------------------------------------------------------
  441. // Purpose:
  442. //
  443. //
  444. //-----------------------------------------------------------------------------
  445. void CWeaponCarabine::PrimaryAttack(void)
  446. {
  447.     // Only the player fires this way so we can cast
  448.     CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
  449.  
  450.     if (!pPlayer)
  451.     {
  452.         return;
  453.     }
  454.  
  455.     // MUST call sound before removing a round from the clip of a CMachineGun
  456.     WeaponSound(SINGLE);
  457.  
  458.     pPlayer->DoMuzzleFlash();
  459.  
  460.     SendWeaponAnim(ACT_VM_PRIMARYATTACK);
  461.  
  462.     // player "shoot" animation
  463.     pPlayer->SetAnimation(PLAYER_ATTACK1);
  464.  
  465.     // Don't fire again until fire animation has completed
  466.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  467.     m_iClip1 -= 1;
  468.  
  469.     Vector  vecSrc = pPlayer->Weapon_ShootPosition();
  470.     Vector  vecAiming = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT);
  471.  
  472.     pPlayer->SetMuzzleFlashTime(gpGlobals->curtime + 1.0);
  473.  
  474.     // Fire the bullets, and force the first shot to be perfectly accuracy
  475.     pPlayer->FireBullets(6, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, true, true);
  476.  
  477.     pPlayer->ViewPunch(QAngle(random->RandomFloat(-2, -1), random->RandomFloat(-2, 2), 0));
  478.  
  479.     CSoundEnt::InsertSound(SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2, GetOwner());
  480.  
  481.     if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  482.     {
  483.         // HEV suit - indicate out of ammo condition
  484.         pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  485.     }
  486.  
  487.     //if (m_iClip1)
  488.     //{
  489.     //  // pump so long as some rounds are left.
  490.     //  m_bNeedPump = true;
  491.     //}
  492.  
  493.     //Flipping Code -Jman
  494.     if ( !bFlip)
  495.     {
  496.         BaseClass::PrimaryAttack();
  497.         m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  498.         bFlip= true;
  499.     }
  500.     else
  501.     {
  502.         LeftGunAttack();
  503.         m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  504.         bFlip = false;
  505.     }
  506.  
  507.     m_iPrimaryAttacks++;
  508.     gamestats->Event_WeaponFired(pPlayer, true, GetClassname());
  509. }
  510.  
  511. //-----------------------------------------------------------------------------
  512. // Purpose: Carabine Fire second barrel
  513. //-----------------------------------------------------------------------------
  514. void CWeaponCarabine::LeftGunAttack()
  515. {
  516.     // If my clip is empty (and I use clips) start reload
  517.     if (UsesClipsForAmmo1() && !m_iClip1)
  518.     {
  519.         Reload();
  520.         return;
  521.     }
  522.  
  523.     // Only the player fires this way so we can cast
  524.     CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
  525.  
  526.     if (!pPlayer)
  527.     {
  528.         return;
  529.     }
  530.  
  531.     // MUST call sound before removing a round from the clip of a CMachineGun
  532.     WeaponSound(SINGLE);
  533.  
  534.     pPlayer->DoMuzzleFlash();
  535.  
  536.     SendWeaponAnim(GetSecondaryAttackActivity());
  537.  
  538.     // player "shoot" animation
  539.     pPlayer->SetAnimation(PLAYER_ATTACK1);
  540.  
  541.     FireBulletsInfo_t info;
  542.     info.m_vecSrc = pPlayer->Weapon_ShootPosition();
  543.  
  544.     info.m_vecDirShooting = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT);
  545.  
  546.     // To make the firing framerate independent, we may have to fire more than one bullet here on low-framerate systems,
  547.     // especially if the weapon we're firing has a really fast rate of fire.
  548.     info.m_iShots = 0;
  549.     float fireRate = GetFireRate();
  550.  
  551.     while (m_flNextPrimaryAttack <= gpGlobals->curtime)
  552.     {
  553.         m_flNextPrimaryAttack = m_flNextPrimaryAttack + fireRate;
  554.         info.m_iShots++;
  555.         if (!fireRate)
  556.             break;
  557.     }
  558.  
  559.     // Make sure we don't fire more than the amount in the clip
  560.     if (UsesClipsForAmmo1())
  561.     {
  562.         info.m_iShots = min(info.m_iShots, m_iClip1);
  563.         m_iClip1 -= info.m_iShots;
  564.     }
  565.     else
  566.     {
  567.         info.m_iShots = min(info.m_iShots, pPlayer->GetAmmoCount(m_iPrimaryAmmoType));
  568.         pPlayer->RemoveAmmo(info.m_iShots, m_iPrimaryAmmoType);
  569.     }
  570.  
  571.     info.m_flDistance = MAX_TRACE_LENGTH;
  572.     info.m_iAmmoType = m_iPrimaryAmmoType;
  573.     info.m_iTracerFreq = 2;
  574.  
  575. #if !defined( CLIENT_DLL )
  576.     // Fire the bullets
  577.     info.m_vecSpread = pPlayer->GetAttackSpread(this);
  578. #else
  579.     //!!!HACKHACK - what does the client want this function for?
  580.     info.m_vecSpread = GetActiveWeapon()->GetBulletSpread();
  581. #endif // CLIENT_DLL
  582.  
  583.     pPlayer->FireBullets(info);
  584.  
  585.     if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  586.     {
  587.         // HEV suit - indicate out of ammo condition
  588.         pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  589.     }
  590.  
  591.     //Add our view kick in
  592.     AddViewKick();
  593. }
  594.  
  595. //-----------------------------------------------------------------------------
  596. // Purpose:
  597. //
  598. //
  599. //-----------------------------------------------------------------------------
  600. void CWeaponCarabine::SecondaryAttack(void)
  601. {
  602.     // Only the player fires this way so we can cast
  603.     CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
  604.  
  605.     if (!pPlayer)
  606.     {
  607.         return;
  608.     }
  609.  
  610.     pPlayer->m_nButtons &= ~IN_ATTACK2;
  611.     // MUST call sound before removing a round from the clip of a CMachineGun
  612.     WeaponSound(WPN_DOUBLE);
  613.  
  614.     pPlayer->DoMuzzleFlash();
  615.  
  616.     SendWeaponAnim(ACT_VM_SECONDARYATTACK);
  617.  
  618.     // player "shoot" animation
  619.     pPlayer->SetAnimation(PLAYER_ATTACK1);
  620.  
  621.     // Don't fire again until fire animation has completed
  622.     m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  623.     m_iClip1 -= 2;  // Carabine uses same clip for primary and secondary attacks
  624.  
  625.     Vector vecSrc = pPlayer->Weapon_ShootPosition();
  626.     Vector vecAiming = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT);
  627.  
  628.     // Fire the bullets
  629.     pPlayer->FireBullets(12, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, false, false);
  630.     pPlayer->ViewPunch(QAngle(random->RandomFloat(-5, 5), 0, 0));
  631.  
  632.     pPlayer->SetMuzzleFlashTime(gpGlobals->curtime + 1.0);
  633.  
  634.     CSoundEnt::InsertSound(SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_SHOTGUN, 0.2);
  635.  
  636.     if (!m_iClip1 && pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  637.     {
  638.         // HEV suit - indicate out of ammo condition
  639.         pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0);
  640.     }
  641.  
  642.     if (m_iClip1)
  643.     {
  644.         // pump so long as some rounds are left.
  645.         m_bNeedPump = true;
  646.     }
  647.  
  648.     m_iSecondaryAttacks++;
  649.     gamestats->Event_WeaponFired(pPlayer, false, GetClassname());
  650. }
  651.  
  652. //-----------------------------------------------------------------------------
  653. // Purpose: Override so carabine can do multiple reloads in a row
  654. //-----------------------------------------------------------------------------
  655. void CWeaponCarabine::ItemPostFrame(void)
  656. {
  657.     CBasePlayer *pOwner = ToBasePlayer(GetOwner());
  658.     if (!pOwner)
  659.     {
  660.         return;
  661.     }
  662.  
  663.     if (m_bInReload)
  664.     {
  665.         // If I'm primary firing and have one round stop reloading and fire
  666.         if ((pOwner->m_nButtons & IN_ATTACK) && (m_iClip1 >= 1))
  667.         {
  668.             m_bInReload = false;
  669.             m_bNeedPump = false;
  670.             m_bDelayedFire1 = true;
  671.         }
  672.         // If I'm secondary firing and have one round stop reloading and fire
  673.         else if ((pOwner->m_nButtons & IN_ATTACK2) && (m_iClip1 >= 2))
  674.         {
  675.             m_bInReload = false;
  676.             m_bNeedPump = false;
  677.             m_bDelayedFire2 = true;
  678.         }
  679.         else if (m_flNextPrimaryAttack <= gpGlobals->curtime)
  680.         {
  681.             // If out of ammo end reload
  682.             if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0)
  683.             {
  684.                 FinishReload();
  685.                 return;
  686.             }
  687.             // If clip not full reload again
  688.             if (m_iClip1 < GetMaxClip1())
  689.             {
  690.                 Reload();
  691.                 return;
  692.             }
  693.             // Clip full, stop reloading
  694.             else
  695.             {
  696.                 FinishReload();
  697.                 return;
  698.             }
  699.         }
  700.     }
  701.     else
  702.     {
  703.         // Make carabine shell invisible
  704.         SetBodygroup(1, 1);
  705.     }
  706.  
  707.     if ((m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  708.     {
  709.         Pump();
  710.         return;
  711.     }
  712.  
  713.     // Carabine uses same timing and ammo for secondary attack
  714.     if ((m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2) && (m_flNextPrimaryAttack <= gpGlobals->curtime))
  715.     {
  716.         m_bDelayedFire2 = false;
  717.  
  718.         if ((m_iClip1 <= 1 && UsesClipsForAmmo1()))
  719.         {
  720.             // If only one shell is left, do a single shot instead 
  721.             if (m_iClip1 == 1)
  722.             {
  723.                 PrimaryAttack();
  724.             }
  725.             else if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
  726.             {
  727.                 DryFire();
  728.             }
  729.             else
  730.             {
  731.                 StartReload();
  732.             }
  733.         }
  734.  
  735.         // Fire underwater?
  736.         else if (GetOwner()->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
  737.         {
  738.             WeaponSound(EMPTY);
  739.             m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  740.             return;
  741.         }
  742.         else
  743.         {
  744.             // If the firing button was just pressed, reset the firing time
  745.             if (pOwner->m_afButtonPressed & IN_ATTACK)
  746.             {
  747.                 m_flNextPrimaryAttack = gpGlobals->curtime;
  748.             }
  749.             SecondaryAttack();
  750.         }
  751.     }
  752.     else if ((m_bDelayedFire1 || pOwner->m_nButtons & IN_ATTACK) && m_flNextPrimaryAttack <= gpGlobals->curtime)
  753.     {
  754.         m_bDelayedFire1 = false;
  755.         if ((m_iClip1 <= 0 && UsesClipsForAmmo1()) || (!UsesClipsForAmmo1() && !pOwner->GetAmmoCount(m_iPrimaryAmmoType)))
  756.         {
  757.             if (!pOwner->GetAmmoCount(m_iPrimaryAmmoType))
  758.             {
  759.                 DryFire();
  760.             }
  761.             else
  762.             {
  763.                 StartReload();
  764.             }
  765.         }
  766.         // Fire underwater?
  767.         else if (pOwner->GetWaterLevel() == 3 && m_bFiresUnderwater == false)
  768.         {
  769.             WeaponSound(EMPTY);
  770.             m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  771.             return;
  772.         }
  773.         else
  774.         {
  775.             // If the firing button was just pressed, reset the firing time
  776.             CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
  777.             if (pPlayer && pPlayer->m_afButtonPressed & IN_ATTACK)
  778.             {
  779.                 m_flNextPrimaryAttack = gpGlobals->curtime;
  780.             }
  781.             PrimaryAttack();
  782.         }
  783.     }
  784.  
  785.     if (pOwner->m_nButtons & IN_RELOAD && UsesClipsForAmmo1() && !m_bInReload)
  786.     {
  787.         // reload when reload is pressed, or if no buttons are down and weapon is empty.
  788.         StartReload();
  789.     }
  790.     else
  791.     {
  792.         // no fire buttons down
  793.         m_bFireOnEmpty = false;
  794.  
  795.         if (!HasAnyAmmo() && m_flNextPrimaryAttack < gpGlobals->curtime)
  796.         {
  797.             // weapon isn't useable, switch.
  798.             if (!(GetWeaponFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && pOwner->SwitchToNextBestWeapon(this))
  799.             {
  800.                 m_flNextPrimaryAttack = gpGlobals->curtime + 0.3;
  801.                 return;
  802.             }
  803.         }
  804.         else
  805.         {
  806.             // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
  807.             if (m_iClip1 <= 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime)
  808.             {
  809.                 if (StartReload())
  810.                 {
  811.                     // if we've successfully started to reload, we're done
  812.                     return;
  813.                 }
  814.             }
  815.         }
  816.  
  817.         WeaponIdle();
  818.         return;
  819.     }
  820.  
  821. }
  822.  
  823.  
  824.  
  825. //-----------------------------------------------------------------------------
  826. // Purpose: Constructor
  827. //-----------------------------------------------------------------------------
  828. CWeaponCarabine::CWeaponCarabine(void)
  829. {
  830.     m_bReloadsSingly = true;
  831.  
  832.     m_bNeedPump = false;
  833.     m_bDelayedFire1 = false;
  834.     m_bDelayedFire2 = false;
  835.  
  836.     m_fMinRange1 = 0.0;
  837.     m_fMaxRange1 = 500;
  838.     m_fMinRange2 = 0.0;
  839.     m_fMaxRange2 = 200;
  840. }
  841.  
  842. //-----------------------------------------------------------------------------
  843. // Purpose:
  844. //-----------------------------------------------------------------------------
  845. void CWeaponCarabine::ItemHolsterFrame(void)
  846. {
  847.     // Must be player held
  848.     if (GetOwner() && GetOwner()->IsPlayer() == false)
  849.         return;
  850.  
  851.     // We can't be active
  852.     if (GetOwner()->GetActiveWeapon() == this)
  853.         return;
  854.  
  855.     // If it's been longer than three seconds, reload
  856.     if ((gpGlobals->curtime - m_flHolsterTime) > sk_auto_reload_time.GetFloat())
  857.     {
  858.         // Reset the timer
  859.         m_flHolsterTime = gpGlobals->curtime;
  860.  
  861.         if (GetOwner() == NULL)
  862.             return;
  863.  
  864.         if (m_iClip1 == GetMaxClip1())
  865.             return;
  866.  
  867.         // Just load the clip with no animations
  868.         int ammoFill = MIN((GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount(GetPrimaryAmmoType()));
  869.  
  870.         GetOwner()->RemoveAmmo(ammoFill, GetPrimaryAmmoType());
  871.         m_iClip1 += ammoFill;
  872.     }
  873. }
  874.  
  875. //==================================================
  876. // Purpose:
  877. //==================================================
  878.  
  879. void CWeaponCarabine::WeaponIdle( void )
  880. {
  881. //Only the player fires this way so we can cast
  882.     CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
  883.  
  884. if ( pPlayer == NULL )
  885. return;
  886.  
  887. //If we're on a target, play the new anim
  888. if ( pPlayer->IsOnTarget() )
  889. {
  890. SendWeaponAnim( ACT_VM_IDLE );
  891. }
  892. }
Advertisement
Add Comment
Please, Sign In to add comment