Counter Strike : Global Offensive Source Code
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.

953 lines
26 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_csbasegun.h"
  8. #include "fx_cs_shared.h"
  9. #include "in_buttons.h"
  10. #ifdef CLIENT_DLL
  11. #include "c_cs_player.h"
  12. #include "cs_client_gamestats.h"
  13. #include "cdll_client_int.h"
  14. #else
  15. #include "cs_player.h"
  16. #endif
  17. // NOTE: This has to be the last file included!
  18. #include "tier0/memdbgon.h"
  19. #define DETACHABLE_SILENCER 1
  20. #define SILENCER_BODYGROUP_UNSET -2
  21. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCSBaseGun, DT_WeaponCSBaseGun )
  22. BEGIN_NETWORK_TABLE( CWeaponCSBaseGun, DT_WeaponCSBaseGun )
  23. #if defined( GAME_DLL )
  24. SendPropInt( SENDINFO( m_zoomLevel ), 2, SPROP_UNSIGNED ),
  25. SendPropInt( SENDINFO( m_iBurstShotsRemaining ) ),
  26. #else
  27. RecvPropInt( RECVINFO( m_zoomLevel ) ),
  28. RecvPropInt( RECVINFO( m_iBurstShotsRemaining ) ),
  29. #endif
  30. END_NETWORK_TABLE()
  31. #if defined( CLIENT_DLL )
  32. BEGIN_PREDICTION_DATA( CWeaponCSBaseGun )
  33. DEFINE_PRED_FIELD( m_zoomLevel, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  34. DEFINE_PRED_FIELD( m_iBurstShotsRemaining, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
  35. DEFINE_PRED_FIELD( m_fNextBurstShot, FIELD_FLOAT, 0 ),
  36. END_PREDICTION_DATA()
  37. #endif
  38. LINK_ENTITY_TO_CLASS_ALIASED( weapon_csbase_gun, WeaponCSBaseGun );
  39. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( AK47, WeaponCSBaseGun, DT_WeaponAK47, weapon_ak47 );
  40. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponAug, WeaponCSBaseGun, DT_WeaponAug, weapon_aug );
  41. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponAWP, WeaponCSBaseGun, DT_WeaponAWP, weapon_awp );
  42. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponBizon, WeaponCSBaseGun, DT_WeaponBizon, weapon_bizon );
  43. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponFamas, WeaponCSBaseGun, DT_WeaponFamas, weapon_famas );
  44. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponFiveSeven, WeaponCSBaseGun, DT_WeaponFiveSeven, weapon_fiveseven );
  45. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponG3SG1, WeaponCSBaseGun, DT_WeaponG3SG1, weapon_g3sg1 );
  46. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGalil, WeaponCSBaseGun, DT_WeaponGalil, weapon_galil );
  47. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGalilAR, WeaponCSBaseGun, DT_WeaponGalilAR, weapon_galilar );
  48. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGlock, WeaponCSBaseGun, DT_WeaponGlock, weapon_glock );
  49. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponHKP2000, WeaponCSBaseGun, DT_WeaponHKP2000, weapon_hkp2000 );
  50. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponM4A1, WeaponCSBaseGun, DT_WeaponM4A1, weapon_m4a1 );
  51. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMAC10, WeaponCSBaseGun, DT_WeaponMAC10, weapon_mac10 );
  52. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMag7, WeaponCSBaseGun, DT_WeaponMag7, weapon_mag7 );
  53. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP5Navy, WeaponCSBaseGun, DT_WeaponMP5Navy, weapon_mp5navy );
  54. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP7, WeaponCSBaseGun, DT_WeaponMP7, weapon_mp7 );
  55. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP9, WeaponCSBaseGun, DT_WeaponMP9, weapon_mp9 );
  56. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponNegev, WeaponCSBaseGun, DT_WeaponNegev, weapon_negev );
  57. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP228, WeaponCSBaseGun, DT_WeaponP228, weapon_p228 );
  58. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP250, WeaponCSBaseGun, DT_WeaponP250, weapon_p250 );
  59. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP90, WeaponCSBaseGun, DT_WeaponP90, weapon_p90 );
  60. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( SCAR17, WeaponCSBaseGun, DT_WeaponSCAR17, weapon_scar17 );
  61. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSCAR20, WeaponCSBaseGun, DT_WeaponSCAR20, weapon_scar20 );
  62. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponScout, WeaponCSBaseGun, DT_WeaponScout, weapon_scout );
  63. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSG550, WeaponCSBaseGun, DT_WeaponSG550, weapon_sg550 );
  64. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSG556, WeaponCSBaseGun, DT_WeaponSG556, weapon_sg556 );
  65. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSSG08, WeaponCSBaseGun, DT_WeaponSSG08, weapon_ssg08 );
  66. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponTec9, WeaponCSBaseGun, DT_WeaponTec9, weapon_tec9 );
  67. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponTMP, WeaponCSBaseGun, DT_WeaponTMP, weapon_tmp );
  68. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponUMP45, WeaponCSBaseGun, DT_WeaponUMP45, weapon_ump45 );
  69. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponM249, WeaponCSBaseGun, DT_WeaponM249, weapon_m249 );
  70. LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponUSP, WeaponCSBaseGun, DT_WeaponUSP, weapon_usp );
  71. CWeaponCSBaseGun::CWeaponCSBaseGun()
  72. {
  73. m_pWeaponInfo = NULL;
  74. m_zoomLevel = 0;
  75. m_inPrecache = false;
  76. #ifdef CLIENT_DLL
  77. m_iSilencerBodygroup = SILENCER_BODYGROUP_UNSET;
  78. #endif
  79. }
  80. void CWeaponCSBaseGun::Spawn( )
  81. {
  82. BaseClass::Spawn();
  83. m_bBurstMode = false;
  84. m_iBurstShotsRemaining = 0;
  85. m_fNextBurstShot = 0.0f;
  86. ResetPostponeFireReadyTime();
  87. }
  88. void CWeaponCSBaseGun::Precache()
  89. {
  90. m_inPrecache = true;
  91. BaseClass::Precache();
  92. m_inPrecache = false;
  93. }
  94. const char * CWeaponCSBaseGun::GetWorldModel( void ) const
  95. {
  96. return BaseClass::GetWorldModel();
  97. }
  98. Activity CWeaponCSBaseGun::GetDeployActivity( void )
  99. {
  100. if( IsSilenced() )
  101. {
  102. return ACT_VM_DRAW_SILENCED;
  103. }
  104. else
  105. {
  106. return BaseClass::GetDeployActivity();
  107. }
  108. }
  109. void CWeaponCSBaseGun::Drop( const Vector &vecVelocity )
  110. {
  111. // re-deploying the weapon is punishment enough for canceling a silencer attach/detach before completion
  112. if ( (GetActivity() == ACT_VM_ATTACH_SILENCER && m_bSilencerOn == false) ||
  113. (GetActivity() == ACT_VM_DETACH_SILENCER && m_bSilencerOn == true ) )
  114. {
  115. m_flDoneSwitchingSilencer = gpGlobals->curtime;
  116. m_flNextSecondaryAttack = gpGlobals->curtime;
  117. m_flNextPrimaryAttack = gpGlobals->curtime;
  118. }
  119. //make sure the world-model silencer bodygroup is correct, we might have hidden/unhidden it prematurely to make the 3rd-person animation look correct
  120. else if ( (GetActivity() == ACT_VM_ATTACH_SILENCER) || (GetActivity() == ACT_VM_DETACH_SILENCER) )
  121. {
  122. int iBodyGroup = FindBodygroupByName( "silencer" );
  123. if ( iBodyGroup != -1 )
  124. SetBodygroup( iBodyGroup, m_bSilencerOn ? 0 : 1 );
  125. }
  126. BaseClass::Drop( vecVelocity );
  127. }
  128. void CWeaponCSBaseGun::ItemBusyFrame()
  129. {
  130. CCSPlayer *pPlayer = GetPlayerOwner();
  131. if ( !pPlayer )
  132. return;
  133. // if we're scoped during a reload, pull us out of the scope for the duration (and set resumezoom so we'll re-zoom when reloading is done)
  134. if ( HasZoom() && (IsZoomed() || pPlayer->m_bIsScoped) && m_bInReload )
  135. {
  136. //m_zoomLevel = 0; //don't affect zoom level, so it'll restore when reloading is done
  137. pPlayer->m_bIsScoped = false;
  138. pPlayer->m_bResumeZoom = true;
  139. pPlayer->SetFOV( pPlayer, GetZoomFOV( 0 ), GetZoomTime( 0 ) );
  140. m_weaponMode = Primary_Mode;
  141. }
  142. BaseClass::ItemBusyFrame();
  143. }
  144. void CWeaponCSBaseGun::ItemPostFrame()
  145. {
  146. CCSPlayer *pPlayer = GetPlayerOwner();
  147. if ( !pPlayer )
  148. return;
  149. // smoother out the accuracy a bit
  150. //float flFOV = GetFOVForAccuracy();
  151. //GOOSEMAN : Return zoom level back to previous zoom level before we fired a shot. This is used only for the AWP.
  152. // And Scout.
  153. if ( (m_flNextPrimaryAttack <= gpGlobals->curtime) && (pPlayer->m_bResumeZoom == TRUE)
  154. && m_zoomLevel > 0 ) // only need to re-zoom the zoom when there's a zoom to re-zoom to. who knew?
  155. {
  156. if ( m_iClip1 != 0 || ( GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD ) )
  157. {
  158. m_weaponMode = Secondary_Mode;
  159. // the zoom amount is taking care of below
  160. pPlayer->SetFOV( pPlayer, GetZoomFOV( m_zoomLevel ), 0.1f );
  161. m_fScopeZoomEndTime = gpGlobals->curtime + 0.1;
  162. pPlayer->m_bIsScoped = true;
  163. #ifdef CLIENT_DLL
  164. /*
  165. ScreenFade_t fade;
  166. fade.duration = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0.175 );
  167. fade.holdTime = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0 );
  168. fade.fadeFlags = 0;
  169. fade.fadeFlags |= FFADE_IN;
  170. fade.r = 0;
  171. fade.g = 0;
  172. fade.b = 0;
  173. fade.a = 255;
  174. clientdll->View_Fade( &fade );
  175. */
  176. #endif
  177. }
  178. pPlayer->m_bResumeZoom = false;
  179. }
  180. /*
  181. // do this for sniper rifles only and only when the initial zoom has finished zooming
  182. if ( GetCSWpnData().m_iZoomLevels >= 2 && (m_fScopeZoomEndTime <= gpGlobals->curtime) && m_weaponMode == Secondary_Mode )
  183. {
  184. // if we're zoomed in
  185. if ( IsZoomed() )
  186. {
  187. // this is the zoom we are suppoed to be at if we're standing still
  188. float flFOVDiff = MAX( 0, flFOV - pPlayer->GetFOV() );
  189. flFOV = ceil( flFOV );
  190. if ( flFOV < 0 )
  191. flFOV *= -1;
  192. if ( flFOVDiff >= 1.0f )
  193. {
  194. flFOVDiff = MIN( flFOVDiff, 10.0f )/50;
  195. if ( flFOVDiff < 0.05f )
  196. flFOVDiff = 0;
  197. pPlayer->SetFOV( pPlayer, flFOV, flFOVDiff );
  198. }
  199. }
  200. else
  201. {
  202. m_fAccuracySmoothedForZoom = 0;
  203. }
  204. }
  205. */
  206. if ( WeaponHasBurst() )
  207. {
  208. if ( m_iBurstShotsRemaining > 0 && gpGlobals->curtime >= m_fNextBurstShot )
  209. {
  210. BurstFireRemaining();
  211. }
  212. }
  213. BaseClass::ItemPostFrame();
  214. }
  215. bool CWeaponCSBaseGun::SendWeaponAnim( int iActivity )
  216. {
  217. #ifndef CLIENT_DLL
  218. // firing or reloading should interrupt weapon inspection
  219. if ( iActivity == ACT_VM_PRIMARYATTACK || iActivity == ACT_VM_RELOAD || iActivity == ACT_SECONDARY_VM_RELOAD || iActivity == ACT_VM_ATTACH_SILENCER || iActivity == ACT_VM_DETACH_SILENCER )
  220. {
  221. if ( CCSPlayer *pPlayer = GetPlayerOwner() )
  222. {
  223. pPlayer->StopLookingAtWeapon();
  224. }
  225. }
  226. #endif
  227. return BaseClass::SendWeaponAnim( iActivity );
  228. }
  229. float CWeaponCSBaseGun::GetFOVForAccuracy( void )
  230. {
  231. const CCSWeaponInfo& weaponInfo = GetCSWpnData();
  232. CCSPlayer *pPlayer = GetPlayerOwner();
  233. if ( !pPlayer )
  234. return 0;
  235. float flDefaultAccuracy = weaponInfo.GetInaccuracyStand( GetEconItemView(), m_weaponMode );
  236. // if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
  237. // {
  238. // flDefaultAccuracy = weaponInfo.GetInaccuracyLadder( m_weaponMode, GetEconItemView() ) + weaponInfo.GetInaccuracyLadder( 0, GetEconItemView() );
  239. // }
  240. if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
  241. {
  242. flDefaultAccuracy = weaponInfo.GetInaccuracyCrouch( GetEconItemView(), m_weaponMode );
  243. }
  244. m_fAccuracySmoothedForZoom = Approach( GetInaccuracy(), m_fAccuracySmoothedForZoom, gpGlobals->frametime * 10.0f );
  245. float flTargetFOVForZoom = GetZoomFOV( m_zoomLevel );
  246. float flFOV = flTargetFOVForZoom;
  247. // and apply it to the player's fov
  248. if ( m_fAccuracySmoothedForZoom >= 0 )
  249. {
  250. flFOV = flTargetFOVForZoom - ( m_fAccuracySmoothedForZoom - flDefaultAccuracy ) * 10;//MIN( flTargetFOVForZoom * ( 1 + ( m_fAccuracySmoothedForZoom*2 ) ), flTargetFOVForZoom * ( 1 + ( m_fAccuracySmoothedForZoom ) ) );
  251. //Msg( "flFOV = %f\n", flFOV );
  252. }
  253. return flFOV;
  254. }
  255. void CWeaponCSBaseGun::PrimaryAttack()
  256. {
  257. CCSPlayer *pPlayer = GetPlayerOwner();
  258. if ( !pPlayer )
  259. return;
  260. if ( CannotShootUnderwater() )
  261. {
  262. PlayEmptySound();
  263. m_flNextPrimaryAttack = gpGlobals->curtime + 0.15f;
  264. return;
  265. }
  266. float flCycleTime = GetCycleTime();
  267. // change a few things if we're in burst mode
  268. if ( IsInBurstMode() )
  269. {
  270. CALL_ATTRIB_HOOK_FLOAT( flCycleTime, cycletime_when_in_burst_mode );
  271. m_iBurstShotsRemaining = 2;
  272. m_fNextBurstShot = gpGlobals->curtime;
  273. CALL_ATTRIB_HOOK_FLOAT( m_fNextBurstShot, time_between_burst_shots );
  274. }
  275. if ( IsZoomed() )
  276. {
  277. CALL_ATTRIB_HOOK_FLOAT( flCycleTime, cycletime_when_zoomed );
  278. }
  279. if ( !CSBaseGunFire( flCycleTime, m_weaponMode ) ) // <-- 'PEW PEW' HAPPENS HERE
  280. return;
  281. if ( IsSilenced() )
  282. SendWeaponAnim( ACT_VM_PRIMARYATTACK_SILENCED );
  283. // Does this gun unzoom after a shot, as in a bolt action rifle?
  284. if ( IsZoomed() && ( DoesUnzoomAfterShot() ) )
  285. {
  286. pPlayer->m_bIsScoped = false;
  287. pPlayer->m_bResumeZoom = true;
  288. pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.05f );
  289. m_weaponMode = Primary_Mode;
  290. }
  291. }
  292. void CWeaponCSBaseGun::SecondaryAttack()
  293. {
  294. CCSPlayer *pPlayer = GetPlayerOwner();
  295. if ( pPlayer == NULL )
  296. {
  297. Assert(pPlayer != NULL);
  298. return;
  299. }
  300. if ( HasZoom() )
  301. {
  302. if ( ++m_zoomLevel > GetZoomLevels() )
  303. m_zoomLevel = 0;
  304. bool bIsSniperRifle = GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE;
  305. if ( IsZoomed() )
  306. {
  307. m_weaponMode = Secondary_Mode;
  308. //float flFOV = GetFOVForAccuracy();
  309. if ( bIsSniperRifle )
  310. pPlayer->SetFOV( pPlayer, GetZoomFOV( m_zoomLevel ), GetZoomTime( m_zoomLevel) );
  311. m_fAccuracyPenalty += GetCSWpnData().GetInaccuracyAltSwitch();
  312. m_fAccuracySmoothedForZoom = 0;
  313. pPlayer->m_bIsScoped = true;
  314. #ifdef IRONSIGHT
  315. if ( pPlayer->GetActiveCSWeapon() )
  316. {
  317. CIronSightController *pIronSightController = pPlayer->GetActiveCSWeapon()->GetIronSightController();
  318. if (pIronSightController)
  319. {
  320. pPlayer->GetActiveCSWeapon()->UpdateIronSightController();
  321. pPlayer->SetFOV(pPlayer, pIronSightController->GetIronSightIdealFOV(), pIronSightController->GetIronSightPullUpDuration());
  322. pIronSightController->SetState( IronSight_should_approach_sighted );
  323. //stop looking at weapon when going into ironsights
  324. #ifndef CLIENT_DLL
  325. pPlayer->StopLookingAtWeapon();
  326. //force idle animation
  327. CBaseViewModel *pViewModel = pPlayer->GetViewModel();
  328. if (pViewModel)
  329. {
  330. int nSequence = pViewModel->LookupSequence("idle");
  331. if (nSequence != ACTIVITY_NOT_AVAILABLE)
  332. {
  333. pViewModel->ForceCycle(0);
  334. pViewModel->ResetSequence(nSequence);
  335. }
  336. }
  337. #endif
  338. }
  339. }
  340. #endif
  341. }
  342. else
  343. {
  344. m_weaponMode = Primary_Mode;
  345. if ( bIsSniperRifle )
  346. {
  347. int iFOV = FBitSet( pPlayer->GetFlags(), FL_DUCKING ) ? pPlayer->GetDefaultCrouchedFOV() : pPlayer->GetDefaultFOV();
  348. pPlayer->SetFOV( pPlayer, iFOV, GetZoomTime( 0 ));
  349. }
  350. m_fAccuracySmoothedForZoom = 0;
  351. pPlayer->m_bIsScoped = false;
  352. #ifdef IRONSIGHT
  353. if ( pPlayer->GetActiveCSWeapon() )
  354. {
  355. CIronSightController *pIronSightController = pPlayer->GetActiveCSWeapon()->GetIronSightController();
  356. if (pIronSightController)
  357. {
  358. pPlayer->GetActiveCSWeapon()->UpdateIronSightController();
  359. int iFOV = FBitSet(pPlayer->GetFlags(), FL_DUCKING) ? pPlayer->GetDefaultCrouchedFOV() : pPlayer->GetDefaultFOV();
  360. pPlayer->SetFOV(pPlayer, iFOV, pIronSightController->GetIronSightPutDownDuration());
  361. pIronSightController->SetState(IronSight_should_approach_unsighted);
  362. SendWeaponAnim(ACT_VM_FIDGET);
  363. }
  364. }
  365. #endif
  366. }
  367. #ifdef CLIENT_DLL
  368. /*
  369. if ( GetPlayerOwner() && ( bIsSniperRifle && IsZoomed() && m_zoomLevel == 1 ) )
  370. {
  371. ScreenFade_t fade;
  372. fade.duration = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0.22 );
  373. fade.holdTime = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0 );
  374. fade.fadeFlags = 0;
  375. fade.fadeFlags |= FFADE_IN;
  376. fade.r = 0;
  377. fade.g = 0;
  378. fade.b = 0;
  379. fade.a = 255;
  380. clientdll->View_Fade( &fade );
  381. }
  382. */
  383. #endif
  384. #ifndef CLIENT_DLL
  385. // If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
  386. // Let the server play it since if only the client plays it, it's liable to get played twice cause of
  387. // a prediction error. joy.
  388. // [tj] Playing this from the player so that we don't try to play the sound outside the level.
  389. if ( GetPlayerOwner() )
  390. {
  391. if ( IsZoomed() )
  392. {
  393. const char *pszZoomSound = GetZoomInSound();
  394. if ( pszZoomSound && pszZoomSound[0] )
  395. {
  396. GetPlayerOwner()->EmitSound( pszZoomSound );
  397. }
  398. //if ( !bIsSniperRifle )
  399. //{
  400. // color32 clr = {0, 0, 0, 200};
  401. // float flZoomTime = weaponInfo.m_fZoomTime[m_zoomLevel];
  402. // float flBlackTime = MAX( flZoomTime/15, 0.02 );
  403. // UTIL_ScreenFade( pPlayer, clr, flBlackTime, (flZoomTime - (flZoomTime/5)) - flBlackTime, FFADE_IN );
  404. //}
  405. }
  406. else
  407. {
  408. const char *pszZoomSound = GetZoomOutSound();
  409. if ( pszZoomSound && pszZoomSound[0] )
  410. {
  411. GetPlayerOwner()->EmitSound( pszZoomSound );
  412. }
  413. //if ( !bIsSniperRifle )
  414. //{
  415. // color32 clr = {0, 0, 0, 175};
  416. // float flZoomTime = weaponInfo.m_fZoomTime[0];
  417. // float flBlackTime = MAX( flZoomTime/15, 0.02 );
  418. // UTIL_ScreenFade( pPlayer, clr, flBlackTime, flZoomTime - flBlackTime, FFADE_OUT );
  419. //}
  420. }
  421. if ( bIsSniperRifle )
  422. {
  423. // let the bots hear the sniper rifle zoom
  424. IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
  425. if ( event )
  426. {
  427. event->SetInt( "userid", pPlayer->GetUserID() );
  428. gameeventmanager->FireEvent( event );
  429. }
  430. }
  431. else
  432. {
  433. // exists for the game instructor to let it know when the player zoomed in with a regular rifle
  434. // different from the above weapon_zoom because we don't use this event to notify bots
  435. IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom_rifle" );
  436. if ( event )
  437. {
  438. event->SetInt( "userid", pPlayer->GetUserID() );
  439. gameeventmanager->FireEvent( event );
  440. }
  441. }
  442. }
  443. #endif
  444. m_fScopeZoomEndTime = gpGlobals->curtime + GetZoomTime( m_zoomLevel );
  445. }
  446. #ifndef CLIENT_DLL
  447. else if ( WeaponHasBurst() )
  448. {
  449. if ( IsInBurstMode() )
  450. {
  451. pPlayer->HintMessage( "#Cstrike_TitlesTXT_Switch_To_FullAuto", false );
  452. m_bBurstMode = false;
  453. m_weaponMode = Primary_Mode;
  454. }
  455. else
  456. {
  457. pPlayer->HintMessage( "#Cstrike_TitlesTXT_Switch_To_BurstFire", false );
  458. m_bBurstMode = true;
  459. m_weaponMode = Secondary_Mode;
  460. }
  461. pPlayer->EmitSound( "Weapon.AutoSemiAutoSwitch" );
  462. }
  463. #endif
  464. #if DETACHABLE_SILENCER
  465. else if ( HasSilencer() && m_flDoneSwitchingSilencer <= gpGlobals->curtime )
  466. {
  467. if ( m_bSilencerOn )
  468. {
  469. SendWeaponAnim( ACT_VM_DETACH_SILENCER );
  470. #ifndef CLIENT_DLL
  471. SendActivityEvents( ACT_VM_DETACH_SILENCER );
  472. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SILENCER_DETACH );
  473. IGameEvent * event = gameeventmanager->CreateEvent( "silencer_detach" );
  474. if ( event )
  475. {
  476. event->SetInt( "userid", pPlayer->GetUserID() );
  477. gameeventmanager->FireEvent( event );
  478. }
  479. #endif
  480. }
  481. else
  482. {
  483. SendWeaponAnim( ACT_VM_ATTACH_SILENCER );
  484. #ifndef CLIENT_DLL
  485. SendActivityEvents( ACT_VM_ATTACH_SILENCER );
  486. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SILENCER_ATTACH );
  487. #endif
  488. }
  489. float nextAttackTime = gpGlobals->curtime + SequenceDuration();
  490. m_flDoneSwitchingSilencer = nextAttackTime;
  491. m_flNextSecondaryAttack = nextAttackTime;
  492. m_flNextPrimaryAttack = nextAttackTime;
  493. SetWeaponIdleTime( nextAttackTime );
  494. }
  495. #endif
  496. else if ( IsRevolver() && m_flNextSecondaryAttack < gpGlobals->curtime )
  497. {
  498. float flCycletimeAlt = GetCycleTime( Secondary_Mode );
  499. m_weaponMode = Secondary_Mode;
  500. UpdateAccuracyPenalty();
  501. #ifndef CLIENT_DLL
  502. // Logic for weapon_fire event mimics weapon_csbase.cpp CWeaponCSBase::ItemPostFrame() primary fire implementation
  503. IGameEvent * event = gameeventmanager->CreateEvent( ( HasAmmo() ) ? "weapon_fire" : "weapon_fire_on_empty" );
  504. if ( event )
  505. {
  506. const char *weaponName = GetDefinitionName();
  507. event->SetInt( "userid", pPlayer->GetUserID() );
  508. event->SetString( "weapon", weaponName );
  509. event->SetBool( "silenced", IsSilenced() );
  510. gameeventmanager->FireEvent( event );
  511. }
  512. #endif
  513. CSBaseGunFire( flCycletimeAlt, Secondary_Mode ); // <-- 'PEW PEW' HAPPENS HERE
  514. m_flNextSecondaryAttack = gpGlobals->curtime + flCycletimeAlt;
  515. return;
  516. }
  517. else
  518. {
  519. BaseClass::SecondaryAttack();
  520. }
  521. m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
  522. }
  523. void CWeaponCSBaseGun::BurstFireRemaining()
  524. {
  525. CCSPlayer *pPlayer = GetPlayerOwner();
  526. if ( !pPlayer || m_iClip1 <= 0 )
  527. {
  528. m_iClip1 = 0;
  529. m_iBurstShotsRemaining = 0;
  530. m_fNextBurstShot = 0.0f;
  531. return;
  532. }
  533. uint16 nItemDefIndex = 0;
  534. FX_FireBullets(
  535. pPlayer->entindex(),
  536. nItemDefIndex,
  537. pPlayer->Weapon_ShootPosition(),
  538. pPlayer->GetFinalAimAngle(),
  539. GetCSWeaponID(),
  540. Secondary_Mode,
  541. CBaseEntity::GetPredictionRandomSeed( SERVER_PLATTIME_RNG ) & 255,
  542. GetInaccuracy(),
  543. GetSpread(),
  544. GetAccuracyFishtail(),
  545. m_fNextBurstShot,
  546. (HasSilencer() && IsSilenced()) ? SPECIAL1 : SINGLE,
  547. m_flRecoilIndex );
  548. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  549. pPlayer->DoMuzzleFlash();
  550. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  551. --m_iBurstShotsRemaining;
  552. if ( m_iBurstShotsRemaining > 0 )
  553. {
  554. CALL_ATTRIB_HOOK_FLOAT( m_fNextBurstShot, time_between_burst_shots );
  555. }
  556. else
  557. {
  558. m_fNextBurstShot = 0.0f;
  559. }
  560. const CCSWeaponInfo& weaponInfo = GetCSWpnData();
  561. // update accuracy
  562. m_fAccuracyPenalty += weaponInfo.GetInaccuracyFire( GetEconItemView(), m_weaponMode );
  563. // table driven recoil
  564. Recoil( Secondary_Mode );
  565. ++pPlayer->m_iShotsFired;
  566. m_flRecoilIndex += 1.0f;
  567. --m_iClip1;
  568. }
  569. bool CWeaponCSBaseGun::CSBaseGunFire( float flCycleTime, CSWeaponMode weaponMode )
  570. {
  571. CCSPlayer *pPlayer = GetPlayerOwner();
  572. if ( !pPlayer )
  573. return false;
  574. const CCSWeaponInfo& weaponInfo = GetCSWpnData();
  575. if ( m_iClip1 == 0 )
  576. {
  577. if ( m_bFireOnEmpty )
  578. {
  579. PlayEmptySound();
  580. m_iNumEmptyAttacks++;
  581. // NOTE[pmf]: we don't want to actually play the dry fire animations, as most seem to depict the weapon actually firing.
  582. // SendWeaponAnim( ACT_VM_DRYFIRE );
  583. //++pPlayer->m_iShotsFired; // don't play "auto" empty clicks -- make the player release the trigger before clicking again
  584. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f;
  585. if ( IsRevolver() )
  586. {
  587. m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetCycleTime( weaponMode );
  588. BaseClass::SendWeaponAnim( ACT_VM_DRYFIRE ); // empty!
  589. }
  590. }
  591. return false;
  592. }
  593. float flCurAttack = CalculateNextAttackTime( flCycleTime );
  594. if ( (GetWeaponType() != WEAPONTYPE_SNIPER_RIFLE && IsZoomed()) || (IsRevolver() && weaponMode == Secondary_Mode) )
  595. {
  596. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  597. }
  598. else if ( IsRevolver() )
  599. {
  600. BaseClass::SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  601. }
  602. else
  603. {
  604. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  605. }
  606. // player "shoot" animation
  607. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  608. uint16 nItemDefIndex = 0;
  609. FX_FireBullets(
  610. pPlayer->entindex(),
  611. nItemDefIndex,
  612. pPlayer->Weapon_ShootPosition(),
  613. pPlayer->GetFinalAimAngle(),
  614. GetCSWeaponID(),
  615. weaponMode,
  616. CBaseEntity::GetPredictionRandomSeed( SERVER_PLATTIME_RNG ) & 255,
  617. GetInaccuracy(),
  618. GetSpread(),
  619. GetAccuracyFishtail(),
  620. flCurAttack,
  621. (HasSilencer() && IsSilenced()) ? SPECIAL1 : SINGLE,
  622. m_flRecoilIndex );
  623. DoFireEffects();
  624. #ifdef IRONSIGHT
  625. #ifdef CLIENT_DLL
  626. if ( GetIronSightController() )
  627. {
  628. GetIronSightController()->IncreaseDotBlur( RandomFloat( 0.22f, 0.28f ) );
  629. }
  630. #endif
  631. #endif
  632. SetWeaponIdleTime( gpGlobals->curtime + weaponInfo.GetTimeToIdleAfterFire( GetEconItemView() ) );
  633. // update accuracy
  634. m_fAccuracyPenalty += weaponInfo.GetInaccuracyFire( GetEconItemView(), weaponMode );
  635. // table driven recoil
  636. Recoil( weaponMode );
  637. ++pPlayer->m_iShotsFired;
  638. m_flRecoilIndex += 1.0f;
  639. --m_iClip1;
  640. return true;
  641. }
  642. bool CWeaponCSBaseGun::IsFullAuto() const
  643. {
  644. if ( BaseClass::IsFullAuto() )
  645. {
  646. return !IsInBurstMode();
  647. }
  648. else
  649. {
  650. return false;
  651. }
  652. }
  653. void CWeaponCSBaseGun::DoFireEffects()
  654. {
  655. if ( IsSilenced() )
  656. return;
  657. CCSPlayer *pPlayer = GetPlayerOwner();
  658. if ( pPlayer )
  659. pPlayer->DoMuzzleFlash();
  660. }
  661. bool CWeaponCSBaseGun::Reload()
  662. {
  663. CCSPlayer *pPlayer = GetPlayerOwner();
  664. if ( !pPlayer )
  665. return false;
  666. if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )
  667. return false;
  668. int iResult = 0;
  669. iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), m_iReloadActivityIndex );
  670. if ( !iResult )
  671. return false;
  672. pPlayer->SetAnimation( PLAYER_RELOAD );
  673. if ( HasZoom() )
  674. {
  675. m_zoomLevel = 0;
  676. m_weaponMode = Primary_Mode;
  677. }
  678. if ( pPlayer->GetFOV() != pPlayer->GetDefaultFOV() && pPlayer->m_bIsScoped)
  679. {
  680. pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.0f );
  681. pPlayer->m_bIsScoped = false;
  682. }
  683. pPlayer->m_iShotsFired = 0;
  684. m_flRecoilIndex += 1.0f;
  685. return BaseClass::Reload();
  686. }
  687. void CWeaponCSBaseGun::WeaponIdle()
  688. {
  689. if (m_flTimeWeaponIdle > gpGlobals->curtime)
  690. return;
  691. // only idle if the slid isn't back
  692. if ( m_iClip1 != 0 )
  693. {
  694. SetWeaponIdleTime( gpGlobals->curtime + GetCSWpnData().GetIdleInterval( GetEconItemView() ) );
  695. //silencers are bodygroups, so there is no longer a silencer-specific idle.
  696. SendWeaponAnim( ACT_VM_IDLE );
  697. }
  698. }
  699. bool CWeaponCSBaseGun::Holster( CBaseCombatWeapon *pSwitchingTo )
  700. {
  701. // re-deploying the weapon is punishment enough for canceling a silencer attach/detach before completion
  702. if ( (GetActivity() == ACT_VM_ATTACH_SILENCER && m_bSilencerOn == false) ||
  703. (GetActivity() == ACT_VM_DETACH_SILENCER && m_bSilencerOn == true ) )
  704. {
  705. m_flDoneSwitchingSilencer = gpGlobals->curtime;
  706. m_flNextSecondaryAttack = gpGlobals->curtime;
  707. m_flNextPrimaryAttack = gpGlobals->curtime;
  708. }
  709. if ( HasZoom() )
  710. {
  711. m_zoomLevel = 0;
  712. m_weaponMode = Primary_Mode;
  713. }
  714. // not sure we want to fully support animation cancelling
  715. if ( m_bInReload && !m_bReloadVisuallyComplete )
  716. {
  717. m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime;
  718. }
  719. return BaseClass::Holster(pSwitchingTo);
  720. }
  721. bool CWeaponCSBaseGun::Deploy()
  722. {
  723. // don't allow weapon switching to shortcut cycle time (quickswitch exploit)
  724. float fOldNextPrimaryAttack = m_flNextPrimaryAttack;
  725. float fOldNextSecondaryAttack = m_flNextSecondaryAttack;
  726. m_flDoneSwitchingSilencer = 0.0f;
  727. m_iBurstShotsRemaining = 0;
  728. m_fNextBurstShot = 0.0f;
  729. if ( !BaseClass::Deploy() )
  730. return false;
  731. if ( HasZoom() )
  732. {
  733. m_zoomLevel = 0;
  734. m_weaponMode = Primary_Mode;
  735. }
  736. if ( IsRevolver() )
  737. {
  738. m_weaponMode = Secondary_Mode;
  739. }
  740. m_flNextPrimaryAttack = Max( m_flNextPrimaryAttack.Get(), fOldNextPrimaryAttack );
  741. m_flNextSecondaryAttack = Max( m_flNextSecondaryAttack.Get(), fOldNextSecondaryAttack );
  742. return true;
  743. }
  744. bool CWeaponCSBaseGun::HasZoom()
  745. {
  746. return GetZoomLevels() != 0;
  747. }
  748. #ifdef CLIENT_DLL
  749. const char* CWeaponCSBaseGun::GetMuzzleFlashEffectName_1stPerson( void )
  750. {
  751. if ( HasSilencer() && IsSilenced() )
  752. {
  753. return GetCSWpnData().GetMuzzleFlashEffectName_1stPersonAlt( GetEconItemView() );
  754. }
  755. else
  756. {
  757. return GetCSWpnData().GetMuzzleFlashEffectName_1stPerson( GetEconItemView() );
  758. }
  759. }
  760. const char* CWeaponCSBaseGun::GetMuzzleFlashEffectName_3rdPerson( void )
  761. {
  762. if ( HasSilencer() && IsSilenced() )
  763. {
  764. return GetCSWpnData().GetMuzzleFlashEffectName_3rdPersonAlt( GetEconItemView() );
  765. }
  766. else
  767. {
  768. return GetCSWpnData().GetMuzzleFlashEffectName_3rdPerson( GetEconItemView() );
  769. }
  770. }
  771. #endif
  772. CCSWeaponInfo const & CWeaponCSBaseGun::GetCSWpnData() const
  773. {
  774. if ( m_pWeaponInfo != NULL )
  775. return *m_pWeaponInfo;
  776. else
  777. return BaseClass::GetCSWpnData();
  778. }
  779. bool CWeaponCSBaseGun::IsInBurstMode() const
  780. {
  781. return m_bBurstMode;
  782. }
  783. bool CWeaponCSBaseGun::IsZoomed( void ) const
  784. {
  785. return ( m_zoomLevel > 0 );
  786. }