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.

395 lines
8.1 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 CWeaponUSP C_WeaponUSP
  11. #include "c_cs_player.h"
  12. #else
  13. #include "cs_player.h"
  14. #endif
  15. class CWeaponUSP : public CWeaponCSBase
  16. {
  17. public:
  18. DECLARE_CLASS( CWeaponUSP, CWeaponCSBase );
  19. DECLARE_NETWORKCLASS();
  20. DECLARE_PREDICTABLE();
  21. CWeaponUSP();
  22. virtual void Spawn();
  23. virtual void Precache();
  24. virtual void PrimaryAttack();
  25. virtual void SecondaryAttack();
  26. virtual bool Deploy();
  27. virtual bool Holster( CBaseCombatWeapon *pSwitchingTo );
  28. virtual void Drop( const Vector &vecVelocity );
  29. virtual float GetInaccuracy() const;
  30. virtual bool Reload();
  31. virtual void WeaponIdle();
  32. // We overload this so we can translate all weapon activities to silenced versions.
  33. virtual bool SendWeaponAnim( int iActivity );
  34. virtual CSWeaponID GetWeaponID( void ) const { return WEAPON_USP; }
  35. // return true if this weapon has a silencer equipped
  36. virtual bool IsSilenced( void ) const { return m_bSilencerOn; }
  37. virtual Activity GetDeployActivity( void );
  38. #ifdef CLIENT_DLL
  39. virtual int GetMuzzleFlashStyle( void );
  40. #endif
  41. virtual const char *GetWorldModel( void ) const;
  42. virtual int GetWorldModelIndex( void );
  43. private:
  44. CWeaponUSP( const CWeaponUSP & );
  45. CNetworkVar( bool, m_bSilencerOn );
  46. CNetworkVar( float, m_flDoneSwitchingSilencer ); // soonest time switching the silencer will be complete
  47. float m_flLastFire;
  48. int m_silencedModelIndex;
  49. bool m_inPrecache;
  50. };
  51. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponUSP, DT_WeaponUSP )
  52. BEGIN_NETWORK_TABLE( CWeaponUSP, DT_WeaponUSP )
  53. #ifdef CLIENT_DLL
  54. RecvPropBool( RECVINFO( m_bSilencerOn ) ),
  55. RecvPropTime( RECVINFO( m_flDoneSwitchingSilencer ) ),
  56. #else
  57. SendPropBool( SENDINFO( m_bSilencerOn ) ),
  58. SendPropTime( SENDINFO( m_flDoneSwitchingSilencer ) ),
  59. #endif
  60. END_NETWORK_TABLE()
  61. #ifdef CLIENT_DLL
  62. BEGIN_PREDICTION_DATA( CWeaponUSP )
  63. DEFINE_PRED_FIELD( m_bSilencerOn, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  64. DEFINE_FIELD( m_flLastFire, FIELD_FLOAT ),
  65. END_PREDICTION_DATA()
  66. #endif
  67. LINK_ENTITY_TO_CLASS( weapon_usp, CWeaponUSP );
  68. PRECACHE_WEAPON_REGISTER( weapon_usp );
  69. Activity g_SilencedTranslations[][2] =
  70. {
  71. { ACT_VM_RELOAD, ACT_VM_RELOAD_SILENCED },
  72. { ACT_VM_PRIMARYATTACK, ACT_VM_PRIMARYATTACK_SILENCED },
  73. { ACT_VM_DRAW, ACT_VM_DRAW_SILENCED },
  74. };
  75. CWeaponUSP::CWeaponUSP()
  76. {
  77. m_flLastFire = gpGlobals->curtime;
  78. m_bSilencerOn = false;
  79. m_flDoneSwitchingSilencer = 0.0f;
  80. m_inPrecache = false;
  81. }
  82. void CWeaponUSP::Spawn()
  83. {
  84. //m_iDefaultAmmo = 12;
  85. m_flAccuracy = 0.92;
  86. m_bSilencerOn = false;
  87. m_weaponMode = Primary_Mode;
  88. m_flDoneSwitchingSilencer = 0.0f;
  89. //FallInit();// get ready to fall down.
  90. BaseClass::Spawn();
  91. }
  92. void CWeaponUSP::Precache()
  93. {
  94. m_inPrecache = true;
  95. BaseClass::Precache();
  96. m_silencedModelIndex = CBaseEntity::PrecacheModel( GetCSWpnData().m_szSilencerModel );
  97. m_inPrecache = false;
  98. }
  99. int CWeaponUSP::GetWorldModelIndex( void )
  100. {
  101. if ( !m_bSilencerOn || m_inPrecache )
  102. {
  103. return m_iWorldModelIndex;
  104. }
  105. else
  106. {
  107. return m_silencedModelIndex;
  108. }
  109. }
  110. const char * CWeaponUSP::GetWorldModel( void ) const
  111. {
  112. if ( !m_bSilencerOn || m_inPrecache )
  113. {
  114. return BaseClass::GetWorldModel();
  115. }
  116. else
  117. {
  118. return GetCSWpnData().m_szSilencerModel;
  119. }
  120. }
  121. bool CWeaponUSP::Deploy()
  122. {
  123. m_flAccuracy = 0.92;
  124. m_flDoneSwitchingSilencer = 0.0f;
  125. return BaseClass::Deploy();
  126. }
  127. bool CWeaponUSP::Holster( CBaseCombatWeapon *pSwitchingTo )
  128. {
  129. if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
  130. {
  131. // still switching the silencer. Cancel the switch.
  132. m_bSilencerOn = !m_bSilencerOn;
  133. m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
  134. SetWeaponModelIndex( GetWorldModel() );
  135. }
  136. return BaseClass::Holster( pSwitchingTo );
  137. }
  138. void CWeaponUSP::Drop( const Vector &vecVelocity )
  139. {
  140. if ( gpGlobals->curtime < m_flDoneSwitchingSilencer )
  141. {
  142. // still switching the silencer. Cancel the switch.
  143. m_bSilencerOn = !m_bSilencerOn;
  144. m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
  145. SetWeaponModelIndex( GetWorldModel() );
  146. }
  147. BaseClass::Drop( vecVelocity );
  148. }
  149. Activity CWeaponUSP::GetDeployActivity( void )
  150. {
  151. if( IsSilenced() )
  152. {
  153. return ACT_VM_DRAW_SILENCED;
  154. }
  155. else
  156. {
  157. return ACT_VM_DRAW;
  158. }
  159. }
  160. void CWeaponUSP::SecondaryAttack()
  161. {
  162. if ( m_bSilencerOn )
  163. {
  164. SendWeaponAnim( ACT_VM_DETACH_SILENCER );
  165. }
  166. else
  167. {
  168. SendWeaponAnim( ACT_VM_ATTACH_SILENCER );
  169. }
  170. m_bSilencerOn = !m_bSilencerOn;
  171. m_weaponMode = m_bSilencerOn ? Secondary_Mode : Primary_Mode;
  172. m_flDoneSwitchingSilencer = gpGlobals->curtime + 3;
  173. m_flNextSecondaryAttack = gpGlobals->curtime + 3;
  174. m_flNextPrimaryAttack = gpGlobals->curtime + 3;
  175. SetWeaponIdleTime( gpGlobals->curtime + 3 );
  176. SetWeaponModelIndex( GetWorldModel() );
  177. }
  178. float CWeaponUSP::GetInaccuracy() const
  179. {
  180. if ( weapon_accuracy_model.GetInt() == 1 )
  181. {
  182. CCSPlayer *pPlayer = GetPlayerOwner();
  183. if ( !pPlayer )
  184. return 0.0f;
  185. if ( m_bSilencerOn )
  186. {
  187. if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
  188. return 1.3f * (1 - m_flAccuracy);
  189. else if (pPlayer->GetAbsVelocity().Length2D() > 5)
  190. return 0.25f * (1 - m_flAccuracy);
  191. else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
  192. return 0.125f * (1 - m_flAccuracy);
  193. else
  194. return 0.15f * (1 - m_flAccuracy);
  195. }
  196. else
  197. {
  198. if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
  199. return 1.2f * (1 - m_flAccuracy );
  200. else if (pPlayer->GetAbsVelocity().Length2D() > 5)
  201. return 0.225f * (1 - m_flAccuracy);
  202. else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
  203. return 0.08f * (1 - m_flAccuracy);
  204. else
  205. return 0.1f * (1 - m_flAccuracy);
  206. }
  207. }
  208. else
  209. return BaseClass::GetInaccuracy();
  210. }
  211. void CWeaponUSP::PrimaryAttack()
  212. {
  213. CCSPlayer *pPlayer = GetPlayerOwner();
  214. if ( !pPlayer )
  215. return;
  216. float flCycleTime = GetCSWpnData().m_flCycleTime;
  217. // Mark the time of this shot and determine the accuracy modifier based on the last shot fired...
  218. m_flAccuracy -= (0.275)*(0.3 - (gpGlobals->curtime - m_flLastFire));
  219. if (m_flAccuracy > 0.92)
  220. m_flAccuracy = 0.92;
  221. else if (m_flAccuracy < 0.6)
  222. m_flAccuracy = 0.6;
  223. m_flLastFire = gpGlobals->curtime;
  224. if (m_iClip1 <= 0)
  225. {
  226. if ( m_bFireOnEmpty )
  227. {
  228. PlayEmptySound();
  229. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  230. m_bFireOnEmpty = false;
  231. }
  232. return;
  233. }
  234. pPlayer->m_iShotsFired++;
  235. m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + flCycleTime;
  236. m_iClip1--;
  237. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  238. // player "shoot" animation
  239. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  240. if ( !m_bSilencerOn )
  241. {
  242. pPlayer->DoMuzzleFlash();
  243. }
  244. FX_FireBullets(
  245. pPlayer->entindex(),
  246. pPlayer->Weapon_ShootPosition(),
  247. pPlayer->EyeAngles() + 2.0f * pPlayer->GetPunchAngle(),
  248. GetWeaponID(),
  249. m_weaponMode,
  250. CBaseEntity::GetPredictionRandomSeed() & 255,
  251. GetInaccuracy(),
  252. GetSpread());
  253. if (!m_iClip1 && pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
  254. {
  255. // HEV suit - indicate out of ammo condition
  256. pPlayer->SetSuitUpdate("!HEV_AMO0", false, 0);
  257. }
  258. SetWeaponIdleTime( gpGlobals->curtime + 2 );
  259. // update accuracy
  260. m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyImpulseFire[m_weaponMode];
  261. QAngle angle = pPlayer->GetPunchAngle();
  262. angle.x -= 2;
  263. pPlayer->SetPunchAngle( angle );
  264. }
  265. bool CWeaponUSP::Reload()
  266. {
  267. if ( !DefaultPistolReload() )
  268. return false;
  269. m_flAccuracy = 0.92;
  270. return true;
  271. }
  272. void CWeaponUSP::WeaponIdle()
  273. {
  274. if (m_flTimeWeaponIdle > gpGlobals->curtime)
  275. return;
  276. // only idle if the slid isn't back
  277. if (m_iClip1 != 0)
  278. {
  279. SetWeaponIdleTime( gpGlobals->curtime + 6.0 );
  280. }
  281. }
  282. bool CWeaponUSP::SendWeaponAnim( int iActivity )
  283. {
  284. // Translate the activity?
  285. if ( m_bSilencerOn )
  286. {
  287. for ( int i=0; i < ARRAYSIZE( g_SilencedTranslations ); i++ )
  288. {
  289. if ( g_SilencedTranslations[i][0] == iActivity )
  290. {
  291. iActivity = g_SilencedTranslations[i][1];
  292. break;
  293. }
  294. }
  295. }
  296. return BaseClass::SendWeaponAnim( iActivity );
  297. }
  298. #ifdef CLIENT_DLL
  299. int CWeaponUSP::GetMuzzleFlashStyle( void )
  300. {
  301. if( m_bSilencerOn )
  302. {
  303. return CS_MUZZLEFLASH_NONE;
  304. }
  305. else
  306. {
  307. return CS_MUZZLEFLASH_NORM;
  308. }
  309. }
  310. #endif