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.

684 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //
  4. //=============================================================================
  5. #include "cbase.h"
  6. #include "tf_weapon_compound_bow.h"
  7. #include "tf_fx_shared.h"
  8. #include "tf_gamerules.h"
  9. #include "in_buttons.h"
  10. // Client specific.
  11. #ifdef CLIENT_DLL
  12. #include "c_tf_player.h"
  13. #include "c_tf_gamestats.h"
  14. #include "prediction.h"
  15. // Server specific.
  16. #else
  17. #include "tf_player.h"
  18. #include "tf_gamestats.h"
  19. #include "tf_projectile_arrow.h"
  20. #endif
  21. //=============================================================================
  22. //
  23. // Weapon tables.
  24. //
  25. IMPLEMENT_NETWORKCLASS_ALIASED( TFCompoundBow, DT_WeaponCompoundBow )
  26. BEGIN_NETWORK_TABLE( CTFCompoundBow, DT_WeaponCompoundBow )
  27. #ifdef CLIENT_DLL
  28. RecvPropBool( RECVINFO( m_bArrowAlight ) ),
  29. RecvPropBool( RECVINFO( m_bNoFire ) ),
  30. #else
  31. SendPropBool( SENDINFO( m_bArrowAlight ) ),
  32. SendPropBool( SENDINFO( m_bNoFire ) ),
  33. #endif
  34. END_NETWORK_TABLE()
  35. BEGIN_PREDICTION_DATA( CTFCompoundBow )
  36. #ifdef CLIENT_DLL
  37. DEFINE_PRED_FIELD( m_flChargeBeginTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  38. DEFINE_PRED_FIELD( m_bNoFire, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  39. #endif
  40. END_PREDICTION_DATA()
  41. LINK_ENTITY_TO_CLASS( tf_weapon_compound_bow, CTFCompoundBow );
  42. PRECACHE_WEAPON_REGISTER( tf_weapon_compound_bow );
  43. // Server specific.
  44. #ifndef CLIENT_DLL
  45. BEGIN_DATADESC( CTFCompoundBow )
  46. END_DATADESC()
  47. #endif
  48. #define TF_ARROW_MAX_CHARGE_TIME 5.0f
  49. //=============================================================================
  50. //
  51. // Weapon functions.
  52. //
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. CTFCompoundBow::CTFCompoundBow()
  57. {
  58. m_flLastDenySoundTime = 0.0f;
  59. m_bNoFire = false;
  60. m_bReloadsSingly = false;
  61. }
  62. void CTFCompoundBow::Precache( void )
  63. {
  64. PrecacheScriptSound( "Weapon_CompoundBow.SinglePull" );
  65. PrecacheScriptSound( "ArrowLight" );
  66. BaseClass::Precache();
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CTFCompoundBow::WeaponReset( void )
  72. {
  73. BaseClass::WeaponReset();
  74. // m_flChargeBeginTime = 0;
  75. m_bArrowAlight = false;
  76. m_bNoAutoRelease = true;
  77. m_bNoFire = false;
  78. }
  79. #ifdef GAME_DLL
  80. #ifdef STAGING_ONLY
  81. void CTFCompoundBow::CreateExtraArrow( CTFProjectile_Arrow* pMainArrow, const QAngle& qSpreadAngles, float flSpeed )
  82. {
  83. CTFProjectile_Arrow* pExtraArrow = CTFProjectile_Arrow::Create( pMainArrow->GetAbsOrigin(), qSpreadAngles, flSpeed, GetProjectileGravity(), (ProjectileType_t)GetWeaponProjectileType(), pMainArrow->GetOwnerEntity(), pMainArrow->GetOwnerEntity() );
  84. if ( pExtraArrow )
  85. {
  86. pExtraArrow->SetLauncher( this );
  87. pExtraArrow->SetCritical( IsCurrentAttackACrit() );
  88. pExtraArrow->SetDamage( 0.5f * GetProjectileDamage() );
  89. if ( pMainArrow->CanPenetrate() )
  90. {
  91. pExtraArrow->SetPenetrate( true );
  92. }
  93. pExtraArrow->SetCollisionGroup( pMainArrow->GetCollisionGroup() );
  94. }
  95. }
  96. ConVar sv_arrow_spread_angle( "sv_arrow_spread_angle", "5.f" );
  97. ConVar sv_arrow_max_random_spread_angle( "sv_arrow_random_spread_angle", "5.f" );
  98. float CTFCompoundBow::GetRandomSpreadOffset( int iLevel )
  99. {
  100. float flMaxRandomSpread = sv_arrow_max_random_spread_angle.GetFloat();
  101. float flRandom = RemapValClamped( gpGlobals->curtime - m_flChargeBeginTime, 0.f, GetChargeMaxTime(), RandomFloat( -flMaxRandomSpread, flMaxRandomSpread ), 0.f );
  102. return sv_arrow_spread_angle.GetFloat() * iLevel + flRandom;
  103. }
  104. #endif // STAGING_ONLY
  105. #endif
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CTFCompoundBow::LaunchGrenade( void )
  110. {
  111. // Get the player owning the weapon.
  112. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  113. if ( !pPlayer )
  114. return;
  115. CalcIsAttackCritical();
  116. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  117. pPlayer->SetAnimation( PLAYER_ATTACK1 );
  118. pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY );
  119. m_bWantsToShoot = false;
  120. #ifdef GAME_DLL
  121. CTFProjectile_Arrow *pMainArrow = assert_cast<CTFProjectile_Arrow*>( FireProjectile( pPlayer ) );
  122. if ( pMainArrow )
  123. {
  124. pMainArrow->SetArrowAlight( m_bArrowAlight );
  125. #ifdef STAGING_ONLY
  126. if ( TFGameRules() && TFGameRules()->GameModeUsesUpgrades() )
  127. {
  128. Vector vecMainVelocity = pMainArrow->GetAbsVelocity();
  129. float flMainSpeed = vecMainVelocity.Length();
  130. int iArrowMastery = 0;
  131. CALL_ATTRIB_HOOK_INT( iArrowMastery, arrow_mastery );
  132. for ( int i=0; i<iArrowMastery; ++i )
  133. {
  134. QAngle qOffset1 = pMainArrow->GetAbsAngles() + QAngle( 0, GetRandomSpreadOffset( i + 1 ), 0 );
  135. CreateExtraArrow( pMainArrow, qOffset1, flMainSpeed );
  136. QAngle qOffset2 = pMainArrow->GetAbsAngles() + QAngle( 0, -GetRandomSpreadOffset( i + 1 ), 0 );
  137. CreateExtraArrow( pMainArrow, qOffset2, flMainSpeed );
  138. }
  139. }
  140. #endif
  141. }
  142. #else
  143. FireProjectile( pPlayer );
  144. #endif
  145. #if !defined( CLIENT_DLL )
  146. pPlayer->SpeakWeaponFire();
  147. CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() );
  148. #endif
  149. #ifdef CLIENT_DLL
  150. C_CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() );
  151. #endif
  152. // Set next attack times.
  153. float flBaseFireDelay = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay;
  154. float flFireDelay = ApplyFireDelay( flBaseFireDelay );
  155. ApplyRefireSpeedModifications( flFireDelay );
  156. float flRateMultiplyer = flBaseFireDelay / flFireDelay;
  157. // Speed up the reload animation built in to firing
  158. if ( pPlayer->GetViewModel(0) )
  159. {
  160. pPlayer->GetViewModel(0)->SetPlaybackRate( flRateMultiplyer );
  161. }
  162. if ( pPlayer->GetViewModel(1) )
  163. {
  164. pPlayer->GetViewModel(1)->SetPlaybackRate( flRateMultiplyer );
  165. }
  166. m_flNextPrimaryAttack = gpGlobals->curtime + flFireDelay;
  167. m_flLastDenySoundTime = gpGlobals->curtime;
  168. float flIdleDelay = 0.5f * flRateMultiplyer;
  169. SetWeaponIdleTime( m_flNextPrimaryAttack + flIdleDelay );
  170. pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
  171. pPlayer->TeamFortress_SetSpeed();
  172. m_flChargeBeginTime = 0;
  173. m_bArrowAlight = false;
  174. // The bow doesn't actually reload, it instead uses the AE_WPN_INCREMENTAMMO anim event in the fire to reload the clip.
  175. // We need to reset this bool each time we fire so that anim event works.
  176. m_bReloadedThroughAnimEvent = false;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. //-----------------------------------------------------------------------------
  181. void CTFCompoundBow::PrimaryAttack( void )
  182. {
  183. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  184. if ( !pPlayer )
  185. return;
  186. // Check for ammunition.
  187. if ( m_iClip1 <= 0 && m_iClip1 != -1 )
  188. return;
  189. // Are we capable of firing again?
  190. if ( m_flNextPrimaryAttack > gpGlobals->curtime )
  191. return;
  192. if ( m_bNoFire )
  193. return;
  194. if ( !CanAttack() )
  195. {
  196. m_flChargeBeginTime = 0;
  197. return;
  198. }
  199. if ( m_flChargeBeginTime <= 0 )
  200. {
  201. // Set the weapon mode.
  202. m_iWeaponMode = TF_WEAPON_PRIMARY_MODE;
  203. // save that we had the attack button down
  204. m_flChargeBeginTime = gpGlobals->curtime;
  205. SendWeaponAnim( ACT_VM_PULLBACK );
  206. float flRateMultiplyer = ApplyFireDelay( 1.0f );
  207. ApplyRefireSpeedModifications( flRateMultiplyer );
  208. if ( flRateMultiplyer > 0.0f )
  209. {
  210. flRateMultiplyer = 1.0f / flRateMultiplyer;
  211. }
  212. // Speed up the reload animation built in to firing
  213. if ( pPlayer->GetViewModel(0) )
  214. {
  215. pPlayer->GetViewModel(0)->SetPlaybackRate( flRateMultiplyer );
  216. }
  217. if ( pPlayer->GetViewModel(1) )
  218. {
  219. pPlayer->GetViewModel(1)->SetPlaybackRate( flRateMultiplyer );
  220. }
  221. bool bPlaySound = true;
  222. #ifdef CLIENT_DLL
  223. bPlaySound = prediction->IsFirstTimePredicted();
  224. #endif
  225. if ( bPlaySound )
  226. {
  227. // Increase the pitch of the pull sound when the fire rate is higher
  228. CSoundParameters params;
  229. if ( CBaseEntity::GetParametersForSound( "Weapon_CompoundBow.SinglePull", params, NULL ) )
  230. {
  231. CPASAttenuationFilter filter( pPlayer->GetAbsOrigin(), params.soundlevel );
  232. #ifdef GAME_DLL
  233. filter.RemoveRecipient( pPlayer );
  234. #endif
  235. EmitSound_t ep( params );
  236. ep.m_nPitch *= flRateMultiplyer;
  237. pPlayer->EmitSound( filter, pPlayer->entindex(), ep );
  238. }
  239. }
  240. // Slow down movement speed while the bow is pulled back.
  241. pPlayer->m_Shared.AddCond( TF_COND_AIMING );
  242. pPlayer->TeamFortress_SetSpeed();
  243. }
  244. else
  245. {
  246. float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
  247. if ( flTotalChargeTime >= GetChargeMaxTime() )
  248. {
  249. flTotalChargeTime = GetChargeMaxTime();
  250. // LaunchGrenade();
  251. }
  252. }
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Purpose:
  256. //-----------------------------------------------------------------------------
  257. float CTFCompoundBow::GetChargeMaxTime( void )
  258. {
  259. // It takes less time to charge if the fire rate is higher
  260. float flChargeMaxTime = ApplyFireDelay( 1.0f );
  261. ApplyRefireSpeedModifications( flChargeMaxTime );
  262. return flChargeMaxTime;
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose:
  266. //-----------------------------------------------------------------------------
  267. float CTFCompoundBow::GetCurrentCharge( void )
  268. {
  269. if ( m_flChargeBeginTime == 0 )
  270. return 0;
  271. else
  272. return MIN( gpGlobals->curtime - m_flChargeBeginTime, 1.f );
  273. }
  274. //-----------------------------------------------------------------------------
  275. // Purpose:
  276. //-----------------------------------------------------------------------------
  277. float CTFCompoundBow::GetProjectileDamage( void )
  278. {
  279. float flDamage = BaseClass::GetProjectileDamage();
  280. float flBaseDamage = 50.f;
  281. float flScale = MIN( GetCurrentCharge() / GetChargeMaxTime(), 1.f);
  282. float flScaleDamage = flDamage * flScale;
  283. return (flBaseDamage + flScaleDamage);
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose:
  287. //-----------------------------------------------------------------------------
  288. float CTFCompoundBow::GetProjectileSpeed( void )
  289. {
  290. return RemapValClamped( GetCurrentCharge(), 0.0f, 1.f, 1800, 2600 );
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose:
  294. //-----------------------------------------------------------------------------
  295. float CTFCompoundBow::GetProjectileGravity( void )
  296. {
  297. return RemapValClamped( GetCurrentCharge(), 0.0f, 1.f, 0.5, 0.1 );
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose:
  301. //-----------------------------------------------------------------------------
  302. void CTFCompoundBow::AddPipeBomb( CTFGrenadePipebombProjectile *pBomb )
  303. {
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose:
  307. //-----------------------------------------------------------------------------
  308. void CTFCompoundBow::SecondaryAttack( void )
  309. {
  310. LowerBow();
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose: Un-nocks a ready arrow.
  314. //-----------------------------------------------------------------------------
  315. void CTFCompoundBow::LowerBow( void )
  316. {
  317. if ( GetCurrentCharge() == 0.f )
  318. return; // No arrow nocked.
  319. m_flChargeBeginTime = 0;
  320. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  321. if ( pPlayer )
  322. {
  323. pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
  324. pPlayer->TeamFortress_SetSpeed();
  325. }
  326. m_flNextPrimaryAttack = gpGlobals->curtime + 1.f;
  327. m_bNoFire = true;
  328. m_bWantsToShoot = false;
  329. SendWeaponAnim( ACT_ITEM2_VM_DRYFIRE );
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose:
  333. //-----------------------------------------------------------------------------
  334. bool CTFCompoundBow::DetonateRemotePipebombs( bool bFizzle )
  335. {
  336. return false;
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose:
  340. //-----------------------------------------------------------------------------
  341. bool CTFCompoundBow::OwnerCanJump( void )
  342. {
  343. if ( GetCurrentCharge() > 0.f )
  344. return false;
  345. else
  346. return true;
  347. }
  348. //-----------------------------------------------------------------------------
  349. // Purpose:
  350. //-----------------------------------------------------------------------------
  351. bool CTFCompoundBow::Holster( CBaseCombatWeapon *pSwitchingTo )
  352. {
  353. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
  354. if ( pPlayer )
  355. {
  356. pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
  357. pPlayer->TeamFortress_SetSpeed();
  358. }
  359. m_bNoFire = false;
  360. SetArrowAlight( false );
  361. return BaseClass::Holster( pSwitchingTo );
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Purpose: Play animation appropriate to ball status.
  365. //-----------------------------------------------------------------------------
  366. bool CTFCompoundBow::SendWeaponAnim( int iActivity )
  367. {
  368. CTFPlayer *pPlayer = GetTFPlayerOwner();
  369. if ( !pPlayer )
  370. return BaseClass::SendWeaponAnim( iActivity );
  371. if ( iActivity == ACT_VM_PULLBACK )
  372. {
  373. iActivity = ACT_ITEM2_VM_CHARGE;
  374. }
  375. float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
  376. if ( GetCurrentCharge() > 0 )
  377. {
  378. switch ( iActivity )
  379. {
  380. case ACT_VM_IDLE:
  381. if ( flTotalChargeTime >= TF_ARROW_MAX_CHARGE_TIME )
  382. {
  383. int iAct = GetActivity();
  384. if ( iAct == ACT_ITEM2_VM_IDLE_3 || iAct == ACT_ITEM2_VM_CHARGE_IDLE_3 )
  385. {
  386. iActivity = ACT_ITEM2_VM_IDLE_3;
  387. }
  388. else
  389. {
  390. iActivity = ACT_ITEM2_VM_CHARGE_IDLE_3;
  391. }
  392. }
  393. else
  394. {
  395. iActivity = ACT_ITEM2_VM_IDLE_2;
  396. }
  397. break;
  398. default:
  399. break;
  400. }
  401. }
  402. return BaseClass::SendWeaponAnim( iActivity );
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Purpose: Play animation appropriate to ball status.
  406. //-----------------------------------------------------------------------------
  407. void CTFCompoundBow::ItemPostFrame( void )
  408. {
  409. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  410. if ( !pOwner )
  411. return;
  412. if ( !CanAttack() )
  413. {
  414. LowerBow();
  415. }
  416. // If we just fired, and we're past the point at which we tried to reload ourselves,
  417. // and we don't have any ammo in the clip, switch away to another weapon to stop us
  418. // from playing the "draw another arrow from the quiver" animation.
  419. if ( m_bReloadedThroughAnimEvent && m_iClip1 <= 0 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
  420. {
  421. g_pGameRules->SwitchToNextBestWeapon( pOwner, this );
  422. return;
  423. }
  424. BaseClass::ItemPostFrame();
  425. if ( !(pOwner->m_nButtons & IN_ATTACK) && !(pOwner->m_nButtons & IN_ATTACK2) )
  426. {
  427. // Both buttons released. The player can draw the bow again.
  428. m_bNoFire = false;
  429. if ( GetActivity() == ACT_ITEM2_VM_PRIMARYATTACK && IsViewModelSequenceFinished() )
  430. {
  431. SendWeaponAnim( ACT_VM_IDLE );
  432. }
  433. }
  434. if ( GetCurrentCharge() == 1.f && IsViewModelSequenceFinished() )
  435. {
  436. SendWeaponAnim( ACT_VM_IDLE );
  437. }
  438. if ( m_bNoFire )
  439. {
  440. WeaponIdle();
  441. }
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Purpose: Held the arrow drawn too long. Give up & play a fail animation.
  445. //-----------------------------------------------------------------------------
  446. void CTFCompoundBow::ForceLaunchGrenade( void )
  447. {
  448. // LowerBow();
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. //-----------------------------------------------------------------------------
  453. void CTFCompoundBow::GetProjectileFireSetup( CTFPlayer *pPlayer, Vector vecOffset, Vector *vecSrc, QAngle *angForward, bool bHitTeammates, float flEndDist )
  454. {
  455. BaseClass::GetProjectileFireSetup( pPlayer, vecOffset, vecSrc, angForward, bHitTeammates, flEndDist );
  456. float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
  457. if ( flTotalChargeTime >= TF_ARROW_MAX_CHARGE_TIME )
  458. {
  459. // We want to fire a really inaccurate shot.
  460. float frand = (float) rand() / VALVE_RAND_MAX;
  461. angForward->x += -6 + frand*12.f;
  462. frand = (float) rand() / VALVE_RAND_MAX;
  463. angForward->y += -6 + frand*12.f;
  464. }
  465. }
  466. //-----------------------------------------------------------------------------
  467. // Purpose:
  468. //-----------------------------------------------------------------------------
  469. void CTFCompoundBow::ApplyRefireSpeedModifications( float &flBaseRef )
  470. {
  471. CALL_ATTRIB_HOOK_FLOAT( flBaseRef, fast_reload );
  472. // Prototype hack
  473. CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
  474. if ( pPlayer )
  475. {
  476. int iMaster = 0;
  477. CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iMaster, ability_master_sniper );
  478. if ( iMaster )
  479. {
  480. flBaseRef *= RemapValClamped( iMaster, 1, 2, 0.6f, 0.3f );
  481. }
  482. else if ( pPlayer->m_Shared.GetCarryingRuneType() == RUNE_HASTE )
  483. {
  484. flBaseRef *= 0.4f;
  485. }
  486. }
  487. }
  488. #ifdef CLIENT_DLL
  489. //-----------------------------------------------------------------------------
  490. // Purpose:
  491. //-----------------------------------------------------------------------------
  492. void CTFCompoundBow::StartBurningEffect( void )
  493. {
  494. // clear any old effect before adding a new one
  495. if ( m_pBurningArrowEffect )
  496. {
  497. StopBurningEffect();
  498. }
  499. const char *pszEffect;
  500. m_hParticleEffectOwner = GetWeaponForEffect();
  501. if ( m_hParticleEffectOwner )
  502. {
  503. if ( m_hParticleEffectOwner != this )
  504. {
  505. // We're on the viewmodel
  506. pszEffect = "v_flaming_arrow";
  507. }
  508. else
  509. {
  510. pszEffect = "flaming_arrow";
  511. }
  512. m_pBurningArrowEffect = m_hParticleEffectOwner->ParticleProp()->Create( pszEffect, PATTACH_POINT_FOLLOW, "muzzle" );
  513. }
  514. }
  515. //-----------------------------------------------------------------------------
  516. // Purpose:
  517. //-----------------------------------------------------------------------------
  518. void CTFCompoundBow::StopBurningEffect( void )
  519. {
  520. if ( m_pBurningArrowEffect )
  521. {
  522. if ( m_hParticleEffectOwner && m_hParticleEffectOwner->ParticleProp() )
  523. {
  524. m_hParticleEffectOwner->ParticleProp()->StopEmission( m_pBurningArrowEffect );
  525. }
  526. m_pBurningArrowEffect = NULL;
  527. }
  528. }
  529. //-----------------------------------------------------------------------------
  530. // Purpose:
  531. //-----------------------------------------------------------------------------
  532. void CTFCompoundBow::UpdateOnRemove( void )
  533. {
  534. StopBurningEffect();
  535. BaseClass::UpdateOnRemove();
  536. }
  537. //-----------------------------------------------------------------------------
  538. // Purpose:
  539. //-----------------------------------------------------------------------------
  540. void CTFCompoundBow::OnDataChanged( DataUpdateType_t type )
  541. {
  542. BaseClass::OnDataChanged( type );
  543. // Handle particle effect creation / destruction
  544. if ( m_bArrowAlight && !m_pBurningArrowEffect )
  545. {
  546. StartBurningEffect();
  547. EmitSound( "ArrowLight" );
  548. }
  549. else if ( !m_bArrowAlight && m_pBurningArrowEffect )
  550. {
  551. StopBurningEffect();
  552. }
  553. }
  554. #endif
  555. //-----------------------------------------------------------------------------
  556. // Purpose:
  557. //-----------------------------------------------------------------------------
  558. bool CTFCompoundBow::Reload( void )
  559. {
  560. if ( m_flNextPrimaryAttack > gpGlobals->curtime )
  561. return false;
  562. return BaseClass::Reload();
  563. }
  564. //-----------------------------------------------------------------------------
  565. // Purpose:
  566. //-----------------------------------------------------------------------------
  567. bool CTFCompoundBow::CalcIsAttackCriticalHelper()
  568. {
  569. CTFPlayer *pPlayer = GetTFPlayerOwner();
  570. // Crit boosted players fire all crits
  571. if ( pPlayer && pPlayer->m_Shared.IsCritBoosted() )
  572. return true;
  573. return false;
  574. }
  575. //-----------------------------------------------------------------------------
  576. // Purpose:
  577. //-----------------------------------------------------------------------------
  578. void CTFCompoundBow::SetArrowAlight( bool bAlight )
  579. {
  580. // Don't light arrows if we're still firing one.
  581. if (GetActivity() != ACT_ITEM2_VM_PRIMARYATTACK )
  582. {
  583. m_bArrowAlight = bAlight;
  584. }
  585. }