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.

369 lines
7.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 CWeaponGlock C_WeaponGlock
  11. #include "c_cs_player.h"
  12. #else
  13. #include "cs_player.h"
  14. #endif
  15. class CWeaponGlock : public CWeaponCSBase
  16. {
  17. public:
  18. DECLARE_CLASS( CWeaponGlock, CWeaponCSBase );
  19. DECLARE_NETWORKCLASS();
  20. DECLARE_PREDICTABLE();
  21. CWeaponGlock();
  22. virtual void Spawn();
  23. virtual void PrimaryAttack();
  24. virtual void SecondaryAttack();
  25. virtual bool Deploy();
  26. virtual void ItemPostFrame();
  27. void GlockFire( float fSpread, bool bFireBurst );
  28. void FireRemaining( float fSpread );
  29. virtual bool Reload();
  30. virtual void WeaponIdle();
  31. virtual float GetInaccuracy() const;
  32. virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_GLOCK; }
  33. private:
  34. CWeaponGlock( const CWeaponGlock & );
  35. CNetworkVar( bool, m_bBurstMode );
  36. CNetworkVar( int, m_iBurstShotsRemaining ); // used to keep track of the shots fired during the Glock18 burst fire mode.
  37. float m_fNextBurstShot; // time to shoot the next bullet in burst fire mode
  38. float m_flLastFire;
  39. };
  40. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGlock, DT_WeaponGlock )
  41. BEGIN_NETWORK_TABLE( CWeaponGlock, DT_WeaponGlock )
  42. #ifdef CLIENT_DLL
  43. RecvPropBool( RECVINFO( m_bBurstMode ) ),
  44. RecvPropInt( RECVINFO( m_iBurstShotsRemaining ) ),
  45. #else
  46. SendPropBool( SENDINFO( m_bBurstMode ) ),
  47. SendPropInt( SENDINFO( m_iBurstShotsRemaining ) ),
  48. #endif
  49. END_NETWORK_TABLE()
  50. #if defined(CLIENT_DLL)
  51. BEGIN_PREDICTION_DATA( CWeaponGlock )
  52. DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
  53. DEFINE_PRED_FIELD( m_iBurstShotsRemaining, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  54. DEFINE_PRED_FIELD( m_fNextBurstShot, FIELD_FLOAT, 0 ),
  55. END_PREDICTION_DATA()
  56. #endif
  57. LINK_ENTITY_TO_CLASS( weapon_glock, CWeaponGlock );
  58. PRECACHE_WEAPON_REGISTER( weapon_glock );
  59. const float kGlockBurstCycleTime = 0.06f;
  60. CWeaponGlock::CWeaponGlock()
  61. {
  62. m_bBurstMode = false;
  63. m_flLastFire = gpGlobals->curtime;
  64. m_iBurstShotsRemaining = 0;
  65. m_fNextBurstShot = 0.0f;
  66. }
  67. void CWeaponGlock::Spawn( )
  68. {
  69. BaseClass::Spawn();
  70. m_bBurstMode = false;
  71. m_iBurstShotsRemaining = 0;
  72. m_fNextBurstShot = 0.0f;
  73. m_flAccuracy = 0.9f;
  74. }
  75. bool CWeaponGlock::Deploy( )
  76. {
  77. m_iBurstShotsRemaining = 0;
  78. m_fNextBurstShot = 0.0f;
  79. m_flAccuracy = 0.9f;
  80. return BaseClass::Deploy();
  81. }
  82. void CWeaponGlock::SecondaryAttack()
  83. {
  84. CCSPlayer *pPlayer = GetPlayerOwner();
  85. if ( !pPlayer )
  86. return;
  87. if ( m_bBurstMode )
  88. {
  89. ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_SemiAuto" );
  90. m_bBurstMode = false;
  91. m_weaponMode = Primary_Mode;
  92. }
  93. else
  94. {
  95. ClientPrint( pPlayer, HUD_PRINTCENTER, "#Switch_To_BurstFire" );
  96. m_bBurstMode = true;
  97. m_weaponMode = Secondary_Mode;
  98. }
  99. m_flNextSecondaryAttack = gpGlobals->curtime + 0.3;
  100. }
  101. float CWeaponGlock::GetInaccuracy() const
  102. {
  103. if ( weapon_accuracy_model.GetInt() == 1 )
  104. {
  105. CCSPlayer *pPlayer = GetPlayerOwner();
  106. if ( !pPlayer )
  107. return 0.0f;
  108. if ( m_bBurstMode )
  109. {
  110. if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
  111. return 1.2f * (1 - m_flAccuracy);
  112. else if (pPlayer->GetAbsVelocity().Length2D() > 5)
  113. return 0.185f * (1 - m_flAccuracy);
  114. else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
  115. return 0.095f * (1 - m_flAccuracy);
  116. else
  117. return 0.3f * (1 - m_flAccuracy);
  118. }
  119. else
  120. {
  121. if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
  122. return 1.0f * (1 - m_flAccuracy);
  123. else if (pPlayer->GetAbsVelocity().Length2D() > 5)
  124. return 0.165f * (1 - m_flAccuracy);
  125. else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
  126. return 0.075f * (1 - m_flAccuracy);
  127. else
  128. return 0.1f * (1 - m_flAccuracy);
  129. }
  130. }
  131. else
  132. return BaseClass::GetInaccuracy();
  133. }
  134. void CWeaponGlock::PrimaryAttack()
  135. {
  136. CCSPlayer *pPlayer = GetPlayerOwner();
  137. if ( !pPlayer )
  138. return;
  139. float flCycleTime = m_bBurstMode ? 0.5f : GetCSWpnData().m_flCycleTime;
  140. // Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
  141. m_flAccuracy -= (0.275)*(0.325 - (gpGlobals->curtime - m_flLastFire));
  142. if (m_flAccuracy > 0.9)
  143. m_flAccuracy = 0.9;
  144. else if (m_flAccuracy < 0.6)
  145. m_flAccuracy = 0.6;
  146. m_flLastFire = gpGlobals->curtime;
  147. if (m_iClip1 <= 0)
  148. {
  149. if ( m_bFireOnEmpty )
  150. {
  151. PlayEmptySound();
  152. m_flNextPrimaryAttack = gpGlobals->curtime + 0.1f;
  153. m_bFireOnEmpty = false;
  154. }
  155. return;
  156. }
  157. pPlayer->m_iShotsFired++;
  158. m_iClip1--;
  159. pPlayer->DoMuzzleFlash();
  160. //SetPlayerShieldAnim();
  161. // player "shoot" animation
  162. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  163. // non-silenced
  164. //pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME;
  165. //pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH;
  166. FX_FireBullets(
  167. pPlayer->entindex(),
  168. pPlayer->Weapon_ShootPosition(),
  169. pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
  170. GetWeaponID(),
  171. Primary_Mode,
  172. CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
  173. GetInaccuracy(),
  174. GetSpread(),
  175. gpGlobals->curtime);
  176. m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime;
  177. if (!m_iClip1 && pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0)
  178. {
  179. // HEV suit - indicate out of ammo condition
  180. pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
  181. }
  182. SetWeaponIdleTime( gpGlobals->curtime + 2.5f );
  183. if ( m_bBurstMode )
  184. {
  185. // Fire off the next two rounds
  186. m_fNextBurstShot = gpGlobals->curtime + kGlockBurstCycleTime;
  187. m_iBurstShotsRemaining = 2;
  188. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  189. }
  190. else
  191. {
  192. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  193. }
  194. // update accuracy
  195. m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[m_weaponMode];
  196. //ResetPlayerShieldAnim();
  197. }
  198. // GOOSEMAN : FireRemaining used by Glock18
  199. void CWeaponGlock::FireRemaining( float fSpread )
  200. {
  201. CCSPlayer *pPlayer = GetPlayerOwner();
  202. if ( !pPlayer )
  203. Error( "!pPlayer" );
  204. if ( m_iBurstShotsRemaining == 0 )
  205. return;
  206. if (m_iClip1 <= 0)
  207. {
  208. m_iClip1 = 0;
  209. m_iBurstShotsRemaining = 0;
  210. m_fNextBurstShot = 0.0f;
  211. return;
  212. }
  213. --m_iClip1;
  214. // TODO FIXME damage = 18, rangemode 0.9
  215. float fInaccuracy = GetInaccuracy();
  216. if ( weapon_accuracy_model.GetInt() == 1 )
  217. fInaccuracy = 0.05;
  218. FX_FireBullets(
  219. pPlayer->entindex(),
  220. pPlayer->Weapon_ShootPosition(),
  221. pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
  222. GetWeaponID(),
  223. Secondary_Mode,
  224. CBaseEntity::GetPredictionRandomSeed() & 255, // wrap it for network traffic so it's the same between client and server
  225. fInaccuracy,
  226. GetSpread(),
  227. m_fNextBurstShot);
  228. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  229. pPlayer->m_iShotsFired++;
  230. --m_iBurstShotsRemaining;
  231. if ( m_iBurstShotsRemaining > 0 )
  232. m_fNextBurstShot += kGlockBurstCycleTime;
  233. else
  234. m_fNextBurstShot = 0.0;
  235. // update accuracy
  236. m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[Secondary_Mode];
  237. }
  238. void CWeaponGlock::ItemPostFrame()
  239. {
  240. while ( m_iBurstShotsRemaining > 0 && gpGlobals->curtime >= m_fNextBurstShot )
  241. {
  242. if ( weapon_accuracy_model.GetInt() == 1 )
  243. FireRemaining(0.05f);
  244. else
  245. FireRemaining(GetSpread());
  246. }
  247. BaseClass::ItemPostFrame();
  248. }
  249. bool CWeaponGlock::Reload()
  250. {
  251. if ( m_iBurstShotsRemaining != 0 )
  252. return true;
  253. if ( !DefaultPistolReload() )
  254. return false;
  255. m_flAccuracy = 0.9;
  256. return true;
  257. }
  258. void CWeaponGlock::WeaponIdle()
  259. {
  260. CCSPlayer *pPlayer = GetPlayerOwner();
  261. if ( !pPlayer )
  262. return;
  263. if (m_flTimeWeaponIdle > gpGlobals->curtime)
  264. return;
  265. if ( pPlayer->HasShield() )
  266. {
  267. SetWeaponIdleTime( gpGlobals->curtime + 20 );
  268. //MIKETODO: shields
  269. //if ( FBitSet(m_iWeaponState, WPNSTATE_SHIELD_DRAWN) )
  270. // SendWeaponAnim( GLOCK18_SHIELD_IDLE, UseDecrement() ? 1:0 );
  271. }
  272. else
  273. {
  274. // only idle if the slid isn't back
  275. if (m_iClip1 != 0)
  276. {
  277. SendWeaponAnim( ACT_VM_IDLE );
  278. }
  279. }
  280. }