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.

293 lines
5.8 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_csbase.h"
  8. #include "fx_cs_shared.h"
  9. #if defined( CLIENT_DLL )
  10. #define CWeaponM3 C_WeaponM3
  11. #include "c_cs_player.h"
  12. #else
  13. #include "cs_player.h"
  14. #include "te_shotgun_shot.h"
  15. #endif
  16. class CWeaponM3 : public CWeaponCSBase
  17. {
  18. public:
  19. DECLARE_CLASS( CWeaponM3, CWeaponCSBase );
  20. DECLARE_NETWORKCLASS();
  21. DECLARE_PREDICTABLE();
  22. CWeaponM3();
  23. virtual void PrimaryAttack();
  24. virtual bool Reload();
  25. virtual void WeaponIdle();
  26. virtual float GetInaccuracy() const;
  27. virtual float GetSpread() const;
  28. virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_M3; }
  29. private:
  30. CWeaponM3( const CWeaponM3 & );
  31. float m_flPumpTime;
  32. CNetworkVar( int, m_reloadState );
  33. };
  34. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponM3, DT_WeaponM3 )
  35. BEGIN_NETWORK_TABLE( CWeaponM3, DT_WeaponM3 )
  36. #ifdef CLIENT_DLL
  37. RecvPropInt( RECVINFO( m_reloadState ) )
  38. #else
  39. SendPropInt( SENDINFO( m_reloadState ), 2, SPROP_UNSIGNED )
  40. #endif
  41. END_NETWORK_TABLE()
  42. #if defined(CLIENT_DLL)
  43. BEGIN_PREDICTION_DATA( CWeaponM3 )
  44. DEFINE_PRED_FIELD( m_reloadState, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  45. END_PREDICTION_DATA()
  46. #endif
  47. LINK_ENTITY_TO_CLASS( weapon_m3, CWeaponM3 );
  48. PRECACHE_WEAPON_REGISTER( weapon_m3 );
  49. CWeaponM3::CWeaponM3()
  50. {
  51. m_flPumpTime = 0;
  52. m_reloadState = 0;
  53. }
  54. float CWeaponM3::GetInaccuracy() const
  55. {
  56. if ( weapon_accuracy_model.GetInt() == 1 )
  57. {
  58. return 0.0f;
  59. }
  60. else
  61. return BaseClass::GetInaccuracy();
  62. }
  63. float CWeaponM3::GetSpread() const
  64. {
  65. if ( weapon_accuracy_model.GetInt() == 1 )
  66. return 0.0675f;
  67. return GetCSWpnData().m_fSpread[Primary_Mode];
  68. }
  69. void CWeaponM3::PrimaryAttack()
  70. {
  71. CCSPlayer *pPlayer = GetPlayerOwner();
  72. if ( !pPlayer )
  73. return;
  74. float flCycleTime = GetCSWpnData().m_flCycleTime;
  75. // don't fire underwater
  76. if (pPlayer->GetWaterLevel() == 3)
  77. {
  78. PlayEmptySound( );
  79. m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
  80. return;
  81. }
  82. // Out of ammo?
  83. if ( m_iClip1 <= 0 )
  84. {
  85. Reload();
  86. if ( m_iClip1 == 0 )
  87. {
  88. PlayEmptySound();
  89. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  90. }
  91. return;
  92. }
  93. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  94. m_iClip1--;
  95. pPlayer->DoMuzzleFlash();
  96. // player "shoot" animation
  97. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  98. // Dispatch the FX right away with full accuracy.
  99. float flCurAttack = CalculateNextAttackTime( flCycleTime );
  100. FX_FireBullets(
  101. pPlayer->entindex(),
  102. pPlayer->Weapon_ShootPosition(),
  103. pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
  104. GetWeaponID(),
  105. Primary_Mode,
  106. CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
  107. GetInaccuracy(),
  108. GetSpread(),
  109. flCurAttack );
  110. if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
  111. {
  112. // HEV suit - indicate out of ammo condition
  113. pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
  114. }
  115. if (m_iClip1 != 0)
  116. m_flPumpTime = gpGlobals->curtime + 0.5;
  117. if (m_iClip1 != 0)
  118. SetWeaponIdleTime( gpGlobals->curtime + 2.5 );
  119. else
  120. SetWeaponIdleTime( gpGlobals->curtime + 0.875 );
  121. m_reloadState = 0;
  122. // update accuracy
  123. m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Primary_Mode];
  124. // Update punch angles.
  125. QAngle angle = pPlayer->GetPunchAngle();
  126. if ( pPlayer->GetFlags() & FL_ONGROUND )
  127. {
  128. angle.x -= SharedRandomInt( "M3PunchAngleGround", 4, 6 );
  129. }
  130. else
  131. {
  132. angle.x -= SharedRandomInt( "M3PunchAngleAir", 8, 11 );
  133. }
  134. pPlayer->SetPunchAngle( angle );
  135. }
  136. bool CWeaponM3::Reload()
  137. {
  138. CCSPlayer *pPlayer = GetPlayerOwner();
  139. if ( !pPlayer )
  140. return false;
  141. if (pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 || m_iClip1 == GetMaxClip1())
  142. return true;
  143. // don't reload until recoil is done
  144. if (m_flNextPrimaryAttack > gpGlobals->curtime)
  145. return true;
  146. // check to see if we're ready to reload
  147. if (m_reloadState == 0)
  148. {
  149. pPlayer->SetAnimation( PLAYER_RELOAD );
  150. SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
  151. m_reloadState = 1;
  152. pPlayer->m_flNextAttack = gpGlobals->curtime + 0.5;
  153. m_flNextPrimaryAttack = gpGlobals->curtime + 0.5;
  154. m_flNextSecondaryAttack = gpGlobals->curtime + 0.5;
  155. SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
  156. #ifdef GAME_DLL
  157. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_START );
  158. #endif
  159. return true;
  160. }
  161. else if (m_reloadState == 1)
  162. {
  163. if (m_flTimeWeaponIdle > gpGlobals->curtime)
  164. return true;
  165. // was waiting for gun to move to side
  166. m_reloadState = 2;
  167. SendWeaponAnim( ACT_VM_RELOAD );
  168. SetWeaponIdleTime( gpGlobals->curtime + 0.5 );
  169. #ifdef GAME_DLL
  170. if ( m_iClip1 == 7 )
  171. {
  172. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_END );
  173. }
  174. else
  175. {
  176. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD_LOOP );
  177. }
  178. #endif
  179. }
  180. else
  181. {
  182. // Add them to the clip
  183. m_iClip1 += 1;
  184. #ifdef GAME_DLL
  185. SendReloadEvents();
  186. #endif
  187. CCSPlayer *pPlayer = GetPlayerOwner();
  188. if ( pPlayer )
  189. pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
  190. m_reloadState = 1;
  191. }
  192. return true;
  193. }
  194. void CWeaponM3::WeaponIdle()
  195. {
  196. CCSPlayer *pPlayer = GetPlayerOwner();
  197. if ( !pPlayer )
  198. return;
  199. if (m_flPumpTime && m_flPumpTime < gpGlobals->curtime)
  200. {
  201. // play pumping sound
  202. m_flPumpTime = 0;
  203. }
  204. if (m_flTimeWeaponIdle < gpGlobals->curtime)
  205. {
  206. if (m_iClip1 == 0 && m_reloadState == 0 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
  207. {
  208. Reload( );
  209. }
  210. else if (m_reloadState != 0)
  211. {
  212. if (m_iClip1 != 8 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ))
  213. {
  214. Reload( );
  215. }
  216. else
  217. {
  218. // reload debounce has timed out
  219. //MIKETODO: shotgun anims
  220. SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
  221. // play cocking sound
  222. m_reloadState = 0;
  223. SetWeaponIdleTime( gpGlobals->curtime + 1.5 );
  224. }
  225. }
  226. else
  227. {
  228. SendWeaponAnim( ACT_VM_IDLE );
  229. }
  230. }
  231. }