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.

704 lines
19 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "weapon_csbase.h"
  8. #include "gamerules.h"
  9. #include "npcevent.h"
  10. #include "engine/IEngineSound.h"
  11. #include "weapon_basecsgrenade.h"
  12. #include "in_buttons.h"
  13. #include "datacache/imdlcache.h"
  14. #include "cs_shareddefs.h"
  15. #ifdef CLIENT_DLL
  16. #include "c_cs_player.h"
  17. #include "HUD/sfweaponselection.h"
  18. #include "c_rumble.h"
  19. #include "rumble_shared.h"
  20. #else
  21. #include "cs_player.h"
  22. #include "items.h"
  23. #include "cs_gamestats.h"
  24. #endif
  25. // NOTE: This has to be the last file included!
  26. #include "tier0/memdbgon.h"
  27. #define GRENADE_TIMER 1.5f //Seconds
  28. IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenade, DT_BaseCSGrenade )
  29. BEGIN_NETWORK_TABLE(CBaseCSGrenade, DT_BaseCSGrenade)
  30. #ifndef CLIENT_DLL
  31. SendPropBool( SENDINFO(m_bRedraw) ),
  32. SendPropBool( SENDINFO(m_bIsHeldByPlayer) ),
  33. SendPropBool( SENDINFO(m_bPinPulled) ),
  34. SendPropFloat( SENDINFO(m_fThrowTime), 0, SPROP_NOSCALE ),
  35. SendPropBool( SENDINFO( m_bLoopingSoundPlaying ) ),
  36. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  37. SendPropFloat( SENDINFO(m_flThrowStrength), 0, SPROP_NOSCALE ),
  38. #endif
  39. #else
  40. RecvPropBool( RECVINFO(m_bRedraw) ),
  41. RecvPropBool( RECVINFO(m_bIsHeldByPlayer) ),
  42. RecvPropBool( RECVINFO(m_bPinPulled) ),
  43. RecvPropFloat( RECVINFO(m_fThrowTime) ),
  44. RecvPropBool( RECVINFO( m_bLoopingSoundPlaying ) ),
  45. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  46. RecvPropFloat( RECVINFO(m_flThrowStrength) ),
  47. #endif
  48. #endif
  49. END_NETWORK_TABLE()
  50. #if defined CLIENT_DLL
  51. BEGIN_PREDICTION_DATA( CBaseCSGrenade )
  52. DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  53. DEFINE_PRED_FIELD( m_bPinPulled, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  54. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  55. DEFINE_PRED_FIELD( m_flThrowStrength, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  56. #endif
  57. END_PREDICTION_DATA()
  58. #endif
  59. LINK_ENTITY_TO_CLASS_ALIASED( weapon_basecsgrenade, BaseCSGrenade );
  60. #ifndef CLIENT_DLL
  61. ConVar sv_ignoregrenaderadio( "sv_ignoregrenaderadio", "0", FCVAR_RELEASE, "Turn off Fire in the hole messages" );
  62. #endif
  63. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  64. #define GRENADE_SECONDARY_DAMPENING 0.3f
  65. #define GRENADE_SECONDARY_LOWER 12.0f
  66. #define GRENADE_SECONDARY_TRANSITION 1.3f
  67. #define GRENADE_SECONDARY_INTERP 2.0f
  68. #endif
  69. CBaseCSGrenade::CBaseCSGrenade()
  70. {
  71. m_bRedraw = false;
  72. m_bIsHeldByPlayer = false;
  73. m_bPinPulled = false;
  74. m_fThrowTime = 0;
  75. m_bLoopingSoundPlaying = false;
  76. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  77. m_flThrowStrength = 1.0f;
  78. m_flThrowStrengthClientSmooth = 1.0f;
  79. #endif
  80. #ifndef CLIENT_DLL
  81. m_bHasEmittedProjectile = false;
  82. #endif
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void CBaseCSGrenade::Precache()
  88. {
  89. BaseClass::Precache();
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. //-----------------------------------------------------------------------------
  94. bool CBaseCSGrenade::Deploy()
  95. {
  96. m_bRedraw = false;
  97. m_bIsHeldByPlayer = true;
  98. m_bPinPulled = false;
  99. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  100. m_flThrowStrength = 1.0f;
  101. m_flThrowStrengthClientSmooth = 1.0f;
  102. #endif
  103. m_fThrowTime = 0;
  104. #ifndef CLIENT_DLL
  105. // if we're officially out of grenades, ditch this weapon
  106. CCSPlayer *pPlayer = GetPlayerOwner();
  107. if ( !pPlayer )
  108. return false;
  109. if ( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  110. {
  111. pPlayer->Weapon_Drop( this, NULL, NULL );
  112. UTIL_Remove(this);
  113. return false;
  114. }
  115. #endif
  116. return BaseClass::Deploy();
  117. }
  118. #ifdef CLIENT_DLL
  119. int CBaseCSGrenade::DrawModel( int flags, const RenderableInstance_t &instance )
  120. {
  121. //hide the grenade that's in the player's hand while playing grenade throwing animations
  122. CCSPlayer *pPlayer = GetPlayerOwner();
  123. if ( pPlayer )
  124. {
  125. if ( !pPlayer->m_bUseNewAnimstate && pPlayer->m_PlayerAnimState && pPlayer->m_PlayerAnimState->ShouldHideGrenadeDuringThrow() )
  126. {
  127. return 0;
  128. }
  129. }
  130. return BaseClass::DrawModel( flags, instance );
  131. }
  132. #endif
  133. //-----------------------------------------------------------------------------
  134. // Purpose:
  135. // Output : Returns true on success, false on failure.
  136. //-----------------------------------------------------------------------------
  137. bool CBaseCSGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
  138. {
  139. m_bRedraw = false;
  140. // we don't want to set m_bIsHeldByPlayer to true because the weapon actually holsters before it's removed from the inventory after the last grenade has been thrown
  141. // this causes a visual bug in the weapon selection UI
  142. m_bPinPulled = false; // when this is holstered make sure the pin isnt pulled.
  143. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  144. m_flThrowStrength = 1.0f;
  145. m_flThrowStrengthClientSmooth = 1.0f;
  146. #endif
  147. m_fThrowTime = 0;
  148. #ifndef CLIENT_DLL
  149. // If they attempt to switch weapons before the throw animation is done,
  150. // allow it, but kill the weapon if we have to.
  151. CCSPlayer *pPlayer = GetPlayerOwner();
  152. if ( !pPlayer )
  153. return false;
  154. if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  155. {
  156. CBaseCombatCharacter *pOwner = (CBaseCombatCharacter *)pPlayer;
  157. pOwner->Weapon_Drop( this );
  158. UTIL_Remove(this);
  159. }
  160. #endif
  161. return BaseClass::Holster( pSwitchingTo );
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose:
  165. //-----------------------------------------------------------------------------
  166. void CBaseCSGrenade::PrimaryAttack()
  167. {
  168. if ( !m_bIsHeldByPlayer || m_bPinPulled || m_fThrowTime > 0.0f )
  169. return;
  170. CCSPlayer *pPlayer = GetPlayerOwner();
  171. if ( !pPlayer || pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  172. return;
  173. // Ensure that the player can use this grenade
  174. if ( !pPlayer->CanUseGrenade( GetCSWeaponID() ) )
  175. {
  176. return;
  177. }
  178. #ifndef CLIENT_DLL
  179. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_GRENADE_PULL_PIN );
  180. #endif
  181. // The pull pin animation has to finish, then we wait until they aren't holding the primary
  182. // attack button, then throw the grenade.
  183. SendWeaponAnim( ACT_VM_PULLPIN );
  184. m_bPinPulled = true;
  185. // Don't let weapon idle interfere in the middle of a throw!
  186. MDLCACHE_CRITICAL_SECTION();
  187. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  188. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose:
  192. //-----------------------------------------------------------------------------
  193. void CBaseCSGrenade::SecondaryAttack()
  194. {
  195. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  196. if ( !m_bPinPulled )
  197. {
  198. m_flThrowStrength = 0.0f;
  199. m_flThrowStrengthClientSmooth = 0.0f;
  200. }
  201. if ( CSGameRules()->IsFreezePeriod() ) // Don't let Brian molotov the team during freezetime
  202. return;
  203. PrimaryAttack();
  204. return;
  205. #endif
  206. /*if ( m_bRedraw )
  207. return;
  208. CCSPlayer *pPlayer = GetPlayerOwner();
  209. if ( pPlayer == NULL )
  210. return;
  211. //See if we're ducking
  212. if ( pPlayer->GetFlags() & FL_DUCKING )
  213. {
  214. //Send the weapon animation
  215. SendWeaponAnim( ACT_VM_SECONDARYATTACK );
  216. }
  217. else
  218. {
  219. //Send the weapon animation
  220. SendWeaponAnim( ACT_VM_HAULBACK );
  221. }
  222. // Don't let weapon idle interfere in the middle of a throw!
  223. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  224. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();*/
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. // Output : Returns true on success, false on failure.
  229. //-----------------------------------------------------------------------------
  230. bool CBaseCSGrenade::Reload()
  231. {
  232. if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
  233. {
  234. //Redraw the weapon
  235. SendWeaponAnim( ACT_VM_DRAW );
  236. //Update our times
  237. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
  238. m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
  239. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  240. //Mark this as done
  241. // m_bRedraw = false;
  242. }
  243. return true;
  244. }
  245. //-----------------------------------------------------------------------------
  246. // Purpose:
  247. // Input : *pPicker -
  248. //-----------------------------------------------------------------------------
  249. void CBaseCSGrenade::OnPickedUp( CBaseCombatCharacter *pNewOwner )
  250. {
  251. BaseClass::OnPickedUp( pNewOwner );
  252. #if !defined( CLIENT_DLL )
  253. if ( pNewOwner )
  254. {
  255. m_bIsHeldByPlayer = true;
  256. }
  257. #endif
  258. }
  259. void CBaseCSGrenade::ItemPreFrame()
  260. {
  261. BaseClass::ItemPreFrame();
  262. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  263. if ( pOwner == NULL )
  264. return;
  265. #ifdef CLIENT_DLL
  266. //we want to control the grenade model's visibility so opt out of the fast path
  267. if (GetBaseAnimating())
  268. GetBaseAnimating()->SetAllowFastPath(false);
  269. #endif
  270. }
  271. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  272. float CBaseCSGrenade::ApproachThrownStrength()
  273. {
  274. m_flThrowStrengthClientSmooth = Approach(
  275. m_flThrowStrength,
  276. m_flThrowStrengthClientSmooth,
  277. gpGlobals->frametime * GRENADE_SECONDARY_INTERP
  278. );
  279. return m_flThrowStrengthClientSmooth;
  280. }
  281. #endif
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. //-----------------------------------------------------------------------------
  285. void CBaseCSGrenade::ItemPostFrame()
  286. {
  287. CCSPlayer *pPlayer = GetPlayerOwner();
  288. if ( !pPlayer )
  289. return;
  290. CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex );
  291. if ( !vm )
  292. return;
  293. bool bPrimaryHeld = (pPlayer->m_nButtons & IN_ATTACK) != 0;
  294. bool bSecondaryHeld = (pPlayer->m_nButtons & IN_ATTACK2) != 0;
  295. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  296. if ( m_bPinPulled && ( bPrimaryHeld || bSecondaryHeld ) )
  297. {
  298. float flIdealThrowStrength = 0.5f;
  299. if ( bPrimaryHeld )
  300. flIdealThrowStrength += 0.5f;
  301. if ( bSecondaryHeld )
  302. flIdealThrowStrength -= 0.5f;
  303. m_flThrowStrength = Approach( flIdealThrowStrength, m_flThrowStrength, gpGlobals->frametime * GRENADE_SECONDARY_TRANSITION );
  304. }
  305. #endif
  306. // If they let go of the fire buttons, they want to throw the grenade.
  307. if ( m_bPinPulled && !(bPrimaryHeld) && !(bSecondaryHeld) )
  308. {
  309. #ifndef CLIENT_DLL
  310. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  311. if ( IsThrownUnderhand() )
  312. {
  313. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE_UNDERHAND );
  314. }
  315. else
  316. #endif
  317. {
  318. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
  319. }
  320. #endif
  321. StartGrenadeThrow();
  322. MDLCACHE_CRITICAL_SECTION();
  323. m_bPinPulled = false;
  324. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  325. if ( IsThrownUnderhand() )
  326. {
  327. SendWeaponAnim( ACT_VM_RELEASE );
  328. }
  329. else
  330. #endif
  331. {
  332. SendWeaponAnim( ACT_VM_THROW );
  333. }
  334. SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
  335. m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); // we're still throwing, so reset our next primary attack
  336. #ifndef CLIENT_DLL
  337. IGameEvent * event = gameeventmanager->CreateEvent( "weapon_fire" );
  338. if( event )
  339. {
  340. const char *weaponName = STRING( m_iClassname );
  341. if ( IsWeaponClassname( weaponName ) )
  342. {
  343. weaponName += WEAPON_CLASSNAME_PREFIX_LENGTH;
  344. }
  345. event->SetInt( "userid", pPlayer->GetUserID() );
  346. event->SetString( "weapon", weaponName );
  347. event->SetBool( "silenced", false );
  348. gameeventmanager->FireEvent( event );
  349. }
  350. #else
  351. RumbleEffect( XBX_GetUserId( pPlayer->GetSplitScreenPlayerSlot() ), RUMBLE_CROWBAR_SWING, 0, RUMBLE_FLAG_RESTART );
  352. #endif
  353. }
  354. else if ((m_fThrowTime > 0) && (m_fThrowTime < gpGlobals->curtime))
  355. {
  356. // only decrement our ammo when we actually create the projectile
  357. DecrementAmmo( pPlayer );
  358. ThrowGrenade();
  359. }
  360. else if( !m_bIsHeldByPlayer )
  361. {
  362. // Has the throw animation finished playing
  363. if( m_flTimeWeaponIdle < gpGlobals->curtime )
  364. {
  365. // if we're officially out of grenades, ditch this weapon
  366. int nAmmoCount = pPlayer->GetAmmoCount(m_iPrimaryAmmoType);
  367. if( nAmmoCount <= 0 )
  368. {
  369. pPlayer->Weapon_Drop( this, NULL, NULL );
  370. #ifndef CLIENT_DLL
  371. //pPlayer->RemoveWeaponOnPlayer( this );
  372. UTIL_Remove(this);
  373. #endif
  374. }
  375. else
  376. {
  377. pPlayer->SwitchToNextBestWeapon( this );
  378. }
  379. #if defined (CLIENT_DLL)
  380. // when a grenade is removed, force the local player to update thier inventory screen
  381. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  382. if ( pLocalPlayer && pLocalPlayer == pPlayer )
  383. {
  384. SFWeaponSelection *pHudWS = GET_HUDELEMENT( SFWeaponSelection );
  385. if ( pHudWS )
  386. {
  387. int nAmmoCount = pPlayer->GetAmmoCount(m_iPrimaryAmmoType);
  388. if ( nAmmoCount <= 0 )
  389. {
  390. pHudWS->ShowAndUpdateSelection( WEPSELECT_DROP, this );
  391. }
  392. else
  393. {
  394. // we need to tell the hud that this weapon still exists and then update the selected weapon
  395. pHudWS->ShowAndUpdateSelection( WEPSELECT_PICKUP, this );
  396. }
  397. }
  398. }
  399. #endif
  400. return; //don't animate this grenade any more!
  401. }
  402. }
  403. else if( !m_bRedraw )
  404. {
  405. BaseClass::ItemPostFrame();
  406. }
  407. }
  408. #ifdef CLIENT_DLL
  409. void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
  410. {
  411. }
  412. void CBaseCSGrenade::DropGrenade()
  413. {
  414. m_bRedraw = true;
  415. m_bIsHeldByPlayer = false;
  416. m_fThrowTime = 0.0f;
  417. }
  418. void CBaseCSGrenade::ThrowGrenade()
  419. {
  420. m_bRedraw = true;
  421. m_bIsHeldByPlayer = false;
  422. m_fThrowTime = 0.0f;
  423. CBaseHudWeaponSelection *pHudSelection = GetHudWeaponSelection();
  424. if ( pHudSelection )
  425. {
  426. pHudSelection->OnWeaponDrop( this );
  427. }
  428. }
  429. void CBaseCSGrenade::StartGrenadeThrow()
  430. {
  431. m_fThrowTime = gpGlobals->curtime + 0.1f;
  432. }
  433. #else
  434. BEGIN_DATADESC( CBaseCSGrenade )
  435. DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
  436. DEFINE_FIELD( m_bIsHeldByPlayer, FIELD_BOOLEAN ),
  437. END_DATADESC()
  438. int CBaseCSGrenade::CapabilitiesGet()
  439. {
  440. return bits_CAP_WEAPON_RANGE_ATTACK1;
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. // Input : *pOwner -
  445. //-----------------------------------------------------------------------------
  446. void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
  447. {
  448. pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
  449. }
  450. void CBaseCSGrenade::StartGrenadeThrow()
  451. {
  452. m_fThrowTime = gpGlobals->curtime + 0.1f;
  453. CBroadcastRecipientFilter filter;
  454. CSoundParameters params;
  455. if ( GetParametersForSound( GetShootSound( SINGLE ), params, NULL ) )
  456. {
  457. //CPASAttenuationFilter filter( this );
  458. EmitSound( filter, entindex(), GetShootSound( SINGLE ));
  459. }
  460. //WeaponSound(SINGLE, gpGlobals->curtime + 3.0f);
  461. }
  462. void CBaseCSGrenade::ThrowGrenade()
  463. {
  464. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  465. if ( !pPlayer )
  466. {
  467. Assert( false );
  468. return;
  469. }
  470. QAngle angThrow = pPlayer->GetFinalAimAngle();
  471. if ( angThrow[PITCH] > 90.0f )
  472. {
  473. angThrow[PITCH] -= 360.0f;
  474. }
  475. else if ( angThrow[PITCH] < -90.0f )
  476. {
  477. angThrow[PITCH] += 360.0f;
  478. }
  479. AssertMsg( angThrow[PITCH] <= 90.0f && angThrow[PITCH] >= -90.0f, "Grenade throw pitch angle must be between -90 and 90 for the adustments to work.");
  480. // NB. a pitch of +90 is looking straight down, -90 is looking straight up
  481. // add a 10 degrees upwards angle to the throw when looking horizontal, lerp the upwards boost to 0 at the pitch extremes
  482. angThrow[PITCH] -= 10.0f * (90.0f - fabsf(angThrow[PITCH])) / 90.0f;
  483. const float kBaseVelocity = GetThrowVelocity();
  484. //const float kThrowVelocityClampRatio = 750.0f / 540.0f; // from original CSS values
  485. //float flVel = clamp((90 - angThrow.x) / 90, 0.0f, kThrowVelocityClampRatio) * kBaseVelocity;
  486. float flVel = clamp( (kBaseVelocity * 0.9f), 15, 750 );
  487. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  488. //clamp the throw strength ranges just to be sure
  489. float flClampedThrowStrength = m_flThrowStrength;
  490. flClampedThrowStrength = clamp( flClampedThrowStrength, 0.0f, 1.0f );
  491. flVel *= Lerp( flClampedThrowStrength, GRENADE_SECONDARY_DAMPENING, 1.0f );
  492. #endif
  493. Vector vForward;
  494. AngleVectors( angThrow, &vForward );
  495. Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
  496. #ifdef GRENADE_UNDERHAND_FEATURE_ENABLED
  497. vecSrc += Vector(0, 0, Lerp( flClampedThrowStrength, -GRENADE_SECONDARY_LOWER, 0.0f ) );
  498. #endif
  499. // We want to throw the grenade from 16 units out. But that can cause problems if we're facing
  500. // a thin wall. Do a hull trace to be safe.
  501. // Wills: Moved the trace length out to 22 inches, then subtract 6. This way we default to 16,
  502. // but pull back 6 from wherever we hit, so we don't emit from EXACTLY inside the close surface, which can lead to
  503. // the grenade penetrating the wall anyway.
  504. trace_t trace;
  505. Vector mins( -2, -2, -2 );
  506. Vector maxs( 2, 2, 2 );
  507. UTIL_TraceHull( vecSrc, vecSrc + vForward * 22, mins, maxs, MASK_SOLID | CONTENTS_GRENADECLIP, pPlayer, COLLISION_GROUP_NONE, &trace );
  508. vecSrc = trace.endpos - (vForward * 6);
  509. Vector vecThrow = vForward * flVel + (pPlayer->GetAbsVelocity() * 1.25);
  510. EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, GetCSWpnData() );
  511. m_bHasEmittedProjectile = true; // Flag the grenade weapon as having emitted a projectile. The 'grenade' is now flying away from the player, so we don't want to drop *this* grenade on death (that'll make a duplicate)
  512. m_bRedraw = true;
  513. m_bIsHeldByPlayer = false;
  514. m_fThrowTime = 0.0f;
  515. CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
  516. if ( pCSPlayer )
  517. {
  518. int iWeaponId = GetCSWeaponID();
  519. pCSPlayer->PlayerUsedGrenade( iWeaponId );
  520. if ( !sv_ignoregrenaderadio.GetBool() )
  521. {
  522. if ( iWeaponId == WEAPON_FLASHBANG )
  523. pCSPlayer->Radio( "Radio.Flashbang", "#SFUI_TitlesTXT_Flashbang_in_the_hole", true );
  524. else if ( iWeaponId == WEAPON_SMOKEGRENADE )
  525. pCSPlayer->Radio( "Radio.Smoke", "#SFUI_TitlesTXT_Smoke_in_the_hole", true );
  526. else if ( iWeaponId == WEAPON_MOLOTOV )
  527. pCSPlayer->Radio( "Radio.Molotov", "#SFUI_TitlesTXT_Molotov_in_the_hole", true );
  528. else if ( iWeaponId == WEAPON_INCGRENADE )
  529. pCSPlayer->Radio( "Radio.Incendiary", "#SFUI_TitlesTXT_Incendiary_in_the_hole", true );
  530. else if ( iWeaponId == WEAPON_DECOY )
  531. pCSPlayer->Radio( "Radio.Decoy", "#SFUI_TitlesTXT_Decoy_in_the_hole", true );
  532. else
  533. pCSPlayer->Radio( "Radio.FireInTheHole", "#SFUI_TitlesTXT_Fire_in_the_hole", true );
  534. }
  535. CCS_GameStats.IncrementStat( pCSPlayer, CSSTAT_GRENADES_THROWN, 1 );
  536. }
  537. IGameEvent * event = gameeventmanager->CreateEvent( "grenade_thrown" );
  538. if ( event )
  539. {
  540. const char *weaponName = STRING( m_iClassname );
  541. if ( IsWeaponClassname( weaponName ) )
  542. {
  543. weaponName += WEAPON_CLASSNAME_PREFIX_LENGTH;
  544. }
  545. event->SetInt( "userid", pPlayer->GetUserID() );
  546. event->SetString( "weapon", weaponName );
  547. gameeventmanager->FireEvent( event );
  548. }
  549. }
  550. void CBaseCSGrenade::DropGrenade()
  551. {
  552. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  553. if ( !pPlayer )
  554. {
  555. Assert( false );
  556. return;
  557. }
  558. Vector vForward;
  559. pPlayer->EyeVectors( &vForward );
  560. Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset() + vForward * 16;
  561. Vector vecVel = pPlayer->GetAbsVelocity();
  562. EmitGrenade( vecSrc, vec3_angle, vecVel, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer, GetCSWpnData() );
  563. CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
  564. if( pCSPlayer )
  565. {
  566. CCS_GameStats.IncrementStat( pCSPlayer, CSSTAT_GRENADES_THROWN, 1 );
  567. }
  568. m_bRedraw = true;
  569. m_bIsHeldByPlayer = false;
  570. m_fThrowTime = 0.0f;
  571. }
  572. void CBaseCSGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, const CCSWeaponInfo& weaponInfo )
  573. {
  574. Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" );
  575. }
  576. bool CBaseCSGrenade::AllowsAutoSwitchFrom( void ) const
  577. {
  578. return !m_bPinPulled;
  579. }
  580. #endif