summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_weapon_compound_bow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tf/tf_weapon_compound_bow.cpp')
-rw-r--r--game/shared/tf/tf_weapon_compound_bow.cpp685
1 files changed, 685 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weapon_compound_bow.cpp b/game/shared/tf/tf_weapon_compound_bow.cpp
new file mode 100644
index 0000000..eec161e
--- /dev/null
+++ b/game/shared/tf/tf_weapon_compound_bow.cpp
@@ -0,0 +1,685 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+//
+//=============================================================================
+#include "cbase.h"
+#include "tf_weapon_compound_bow.h"
+#include "tf_fx_shared.h"
+#include "tf_gamerules.h"
+#include "in_buttons.h"
+
+// Client specific.
+#ifdef CLIENT_DLL
+#include "c_tf_player.h"
+#include "c_tf_gamestats.h"
+#include "prediction.h"
+// Server specific.
+#else
+#include "tf_player.h"
+#include "tf_gamestats.h"
+#include "tf_projectile_arrow.h"
+#endif
+
+//=============================================================================
+//
+// Weapon tables.
+//
+IMPLEMENT_NETWORKCLASS_ALIASED( TFCompoundBow, DT_WeaponCompoundBow )
+
+BEGIN_NETWORK_TABLE( CTFCompoundBow, DT_WeaponCompoundBow )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bArrowAlight ) ),
+ RecvPropBool( RECVINFO( m_bNoFire ) ),
+#else
+ SendPropBool( SENDINFO( m_bArrowAlight ) ),
+ SendPropBool( SENDINFO( m_bNoFire ) ),
+#endif
+END_NETWORK_TABLE()
+
+BEGIN_PREDICTION_DATA( CTFCompoundBow )
+#ifdef CLIENT_DLL
+ DEFINE_PRED_FIELD( m_flChargeBeginTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bNoFire, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+#endif
+END_PREDICTION_DATA()
+
+LINK_ENTITY_TO_CLASS( tf_weapon_compound_bow, CTFCompoundBow );
+PRECACHE_WEAPON_REGISTER( tf_weapon_compound_bow );
+
+// Server specific.
+#ifndef CLIENT_DLL
+BEGIN_DATADESC( CTFCompoundBow )
+END_DATADESC()
+#endif
+
+#define TF_ARROW_MAX_CHARGE_TIME 5.0f
+
+//=============================================================================
+//
+// Weapon functions.
+//
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFCompoundBow::CTFCompoundBow()
+{
+ m_flLastDenySoundTime = 0.0f;
+ m_bNoFire = false;
+ m_bReloadsSingly = false;
+}
+
+void CTFCompoundBow::Precache( void )
+{
+ PrecacheScriptSound( "Weapon_CompoundBow.SinglePull" );
+ PrecacheScriptSound( "ArrowLight" );
+
+ BaseClass::Precache();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::WeaponReset( void )
+{
+ BaseClass::WeaponReset();
+
+// m_flChargeBeginTime = 0;
+ m_bArrowAlight = false;
+ m_bNoAutoRelease = true;
+ m_bNoFire = false;
+}
+
+#ifdef GAME_DLL
+
+#ifdef STAGING_ONLY
+void CTFCompoundBow::CreateExtraArrow( CTFProjectile_Arrow* pMainArrow, const QAngle& qSpreadAngles, float flSpeed )
+{
+ CTFProjectile_Arrow* pExtraArrow = CTFProjectile_Arrow::Create( pMainArrow->GetAbsOrigin(), qSpreadAngles, flSpeed, GetProjectileGravity(), (ProjectileType_t)GetWeaponProjectileType(), pMainArrow->GetOwnerEntity(), pMainArrow->GetOwnerEntity() );
+ if ( pExtraArrow )
+ {
+ pExtraArrow->SetLauncher( this );
+ pExtraArrow->SetCritical( IsCurrentAttackACrit() );
+ pExtraArrow->SetDamage( 0.5f * GetProjectileDamage() );
+ if ( pMainArrow->CanPenetrate() )
+ {
+ pExtraArrow->SetPenetrate( true );
+ }
+ pExtraArrow->SetCollisionGroup( pMainArrow->GetCollisionGroup() );
+ }
+}
+
+ConVar sv_arrow_spread_angle( "sv_arrow_spread_angle", "5.f" );
+ConVar sv_arrow_max_random_spread_angle( "sv_arrow_random_spread_angle", "5.f" );
+float CTFCompoundBow::GetRandomSpreadOffset( int iLevel )
+{
+ float flMaxRandomSpread = sv_arrow_max_random_spread_angle.GetFloat();
+ float flRandom = RemapValClamped( gpGlobals->curtime - m_flChargeBeginTime, 0.f, GetChargeMaxTime(), RandomFloat( -flMaxRandomSpread, flMaxRandomSpread ), 0.f );
+ return sv_arrow_spread_angle.GetFloat() * iLevel + flRandom;
+}
+#endif // STAGING_ONLY
+
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::LaunchGrenade( void )
+{
+ // Get the player owning the weapon.
+ CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
+ if ( !pPlayer )
+ return;
+
+ CalcIsAttackCritical();
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+
+ pPlayer->SetAnimation( PLAYER_ATTACK1 );
+ pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY );
+
+ m_bWantsToShoot = false;
+
+#ifdef GAME_DLL
+ CTFProjectile_Arrow *pMainArrow = assert_cast<CTFProjectile_Arrow*>( FireProjectile( pPlayer ) );
+ if ( pMainArrow )
+ {
+ pMainArrow->SetArrowAlight( m_bArrowAlight );
+
+#ifdef STAGING_ONLY
+ if ( TFGameRules() && TFGameRules()->GameModeUsesUpgrades() )
+ {
+ Vector vecMainVelocity = pMainArrow->GetAbsVelocity();
+ float flMainSpeed = vecMainVelocity.Length();
+ int iArrowMastery = 0;
+ CALL_ATTRIB_HOOK_INT( iArrowMastery, arrow_mastery );
+ for ( int i=0; i<iArrowMastery; ++i )
+ {
+ QAngle qOffset1 = pMainArrow->GetAbsAngles() + QAngle( 0, GetRandomSpreadOffset( i + 1 ), 0 );
+ CreateExtraArrow( pMainArrow, qOffset1, flMainSpeed );
+ QAngle qOffset2 = pMainArrow->GetAbsAngles() + QAngle( 0, -GetRandomSpreadOffset( i + 1 ), 0 );
+ CreateExtraArrow( pMainArrow, qOffset2, flMainSpeed );
+ }
+ }
+#endif
+ }
+
+#else
+ FireProjectile( pPlayer );
+#endif
+
+#if !defined( CLIENT_DLL )
+ pPlayer->SpeakWeaponFire();
+ CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() );
+#endif
+#ifdef CLIENT_DLL
+ C_CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACrit() );
+#endif
+
+ // Set next attack times.
+ float flBaseFireDelay = m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_flTimeFireDelay;
+ float flFireDelay = ApplyFireDelay( flBaseFireDelay );
+
+ ApplyRefireSpeedModifications( flFireDelay );
+
+ float flRateMultiplyer = flBaseFireDelay / flFireDelay;
+
+ // Speed up the reload animation built in to firing
+ if ( pPlayer->GetViewModel(0) )
+ {
+ pPlayer->GetViewModel(0)->SetPlaybackRate( flRateMultiplyer );
+ }
+ if ( pPlayer->GetViewModel(1) )
+ {
+ pPlayer->GetViewModel(1)->SetPlaybackRate( flRateMultiplyer );
+ }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + flFireDelay;
+ m_flLastDenySoundTime = gpGlobals->curtime;
+
+ float flIdleDelay = 0.5f * flRateMultiplyer;
+ SetWeaponIdleTime( m_flNextPrimaryAttack + flIdleDelay );
+
+ pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
+ pPlayer->TeamFortress_SetSpeed();
+
+ m_flChargeBeginTime = 0;
+ m_bArrowAlight = false;
+
+ // The bow doesn't actually reload, it instead uses the AE_WPN_INCREMENTAMMO anim event in the fire to reload the clip.
+ // We need to reset this bool each time we fire so that anim event works.
+ m_bReloadedThroughAnimEvent = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::PrimaryAttack( void )
+{
+ CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
+ if ( !pPlayer )
+ return;
+
+ // Check for ammunition.
+ if ( m_iClip1 <= 0 && m_iClip1 != -1 )
+ return;
+
+ // Are we capable of firing again?
+ if ( m_flNextPrimaryAttack > gpGlobals->curtime )
+ return;
+
+ if ( m_bNoFire )
+ return;
+
+ if ( !CanAttack() )
+ {
+ m_flChargeBeginTime = 0;
+ return;
+ }
+
+ if ( m_flChargeBeginTime <= 0 )
+ {
+ // Set the weapon mode.
+ m_iWeaponMode = TF_WEAPON_PRIMARY_MODE;
+
+ // save that we had the attack button down
+ m_flChargeBeginTime = gpGlobals->curtime;
+
+ SendWeaponAnim( ACT_VM_PULLBACK );
+
+ float flRateMultiplyer = ApplyFireDelay( 1.0f );
+ ApplyRefireSpeedModifications( flRateMultiplyer );
+ if ( flRateMultiplyer > 0.0f )
+ {
+ flRateMultiplyer = 1.0f / flRateMultiplyer;
+ }
+
+ // Speed up the reload animation built in to firing
+ if ( pPlayer->GetViewModel(0) )
+ {
+ pPlayer->GetViewModel(0)->SetPlaybackRate( flRateMultiplyer );
+ }
+ if ( pPlayer->GetViewModel(1) )
+ {
+ pPlayer->GetViewModel(1)->SetPlaybackRate( flRateMultiplyer );
+ }
+
+ bool bPlaySound = true;
+#ifdef CLIENT_DLL
+ bPlaySound = prediction->IsFirstTimePredicted();
+#endif
+ if ( bPlaySound )
+ {
+ // Increase the pitch of the pull sound when the fire rate is higher
+ CSoundParameters params;
+ if ( CBaseEntity::GetParametersForSound( "Weapon_CompoundBow.SinglePull", params, NULL ) )
+ {
+ CPASAttenuationFilter filter( pPlayer->GetAbsOrigin(), params.soundlevel );
+#ifdef GAME_DLL
+ filter.RemoveRecipient( pPlayer );
+#endif
+ EmitSound_t ep( params );
+ ep.m_nPitch *= flRateMultiplyer;
+
+ pPlayer->EmitSound( filter, pPlayer->entindex(), ep );
+ }
+ }
+
+ // Slow down movement speed while the bow is pulled back.
+ pPlayer->m_Shared.AddCond( TF_COND_AIMING );
+ pPlayer->TeamFortress_SetSpeed();
+ }
+ else
+ {
+ float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
+
+ if ( flTotalChargeTime >= GetChargeMaxTime() )
+ {
+ flTotalChargeTime = GetChargeMaxTime();
+// LaunchGrenade();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CTFCompoundBow::GetChargeMaxTime( void )
+{
+ // It takes less time to charge if the fire rate is higher
+ float flChargeMaxTime = ApplyFireDelay( 1.0f );
+ ApplyRefireSpeedModifications( flChargeMaxTime );
+
+ return flChargeMaxTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CTFCompoundBow::GetCurrentCharge( void )
+{
+ if ( m_flChargeBeginTime == 0 )
+ return 0;
+ else
+ return MIN( gpGlobals->curtime - m_flChargeBeginTime, 1.f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CTFCompoundBow::GetProjectileDamage( void )
+{
+ float flDamage = BaseClass::GetProjectileDamage();
+ float flBaseDamage = 50.f;
+ float flScale = MIN( GetCurrentCharge() / GetChargeMaxTime(), 1.f);
+ float flScaleDamage = flDamage * flScale;
+
+ return (flBaseDamage + flScaleDamage);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CTFCompoundBow::GetProjectileSpeed( void )
+{
+ return RemapValClamped( GetCurrentCharge(), 0.0f, 1.f, 1800, 2600 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CTFCompoundBow::GetProjectileGravity( void )
+{
+ return RemapValClamped( GetCurrentCharge(), 0.0f, 1.f, 0.5, 0.1 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::AddPipeBomb( CTFGrenadePipebombProjectile *pBomb )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::SecondaryAttack( void )
+{
+ LowerBow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Un-nocks a ready arrow.
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::LowerBow( void )
+{
+ if ( GetCurrentCharge() == 0.f )
+ return; // No arrow nocked.
+
+ m_flChargeBeginTime = 0;
+
+ CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
+ pPlayer->TeamFortress_SetSpeed();
+ }
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.f;
+
+ m_bNoFire = true;
+ m_bWantsToShoot = false;
+
+ SendWeaponAnim( ACT_ITEM2_VM_DRYFIRE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::DetonateRemotePipebombs( bool bFizzle )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::OwnerCanJump( void )
+{
+ if ( GetCurrentCharge() > 0.f )
+ return false;
+ else
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
+ if ( pPlayer )
+ {
+ pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
+ pPlayer->TeamFortress_SetSpeed();
+ }
+ m_bNoFire = false;
+ SetArrowAlight( false );
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Play animation appropriate to ball status.
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::SendWeaponAnim( int iActivity )
+{
+ CTFPlayer *pPlayer = GetTFPlayerOwner();
+ if ( !pPlayer )
+ return BaseClass::SendWeaponAnim( iActivity );
+
+ if ( iActivity == ACT_VM_PULLBACK )
+ {
+ iActivity = ACT_ITEM2_VM_CHARGE;
+ }
+
+ float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
+ if ( GetCurrentCharge() > 0 )
+ {
+ switch ( iActivity )
+ {
+ case ACT_VM_IDLE:
+ if ( flTotalChargeTime >= TF_ARROW_MAX_CHARGE_TIME )
+ {
+ int iAct = GetActivity();
+ if ( iAct == ACT_ITEM2_VM_IDLE_3 || iAct == ACT_ITEM2_VM_CHARGE_IDLE_3 )
+ {
+ iActivity = ACT_ITEM2_VM_IDLE_3;
+ }
+ else
+ {
+ iActivity = ACT_ITEM2_VM_CHARGE_IDLE_3;
+ }
+ }
+ else
+ {
+ iActivity = ACT_ITEM2_VM_IDLE_2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return BaseClass::SendWeaponAnim( iActivity );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Play animation appropriate to ball status.
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::ItemPostFrame( void )
+{
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+ if ( !pOwner )
+ return;
+
+ if ( !CanAttack() )
+ {
+ LowerBow();
+ }
+
+ // If we just fired, and we're past the point at which we tried to reload ourselves,
+ // and we don't have any ammo in the clip, switch away to another weapon to stop us
+ // from playing the "draw another arrow from the quiver" animation.
+ if ( m_bReloadedThroughAnimEvent && m_iClip1 <= 0 && pOwner->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
+ {
+ g_pGameRules->SwitchToNextBestWeapon( pOwner, this );
+ return;
+ }
+
+ BaseClass::ItemPostFrame();
+
+ if ( !(pOwner->m_nButtons & IN_ATTACK) && !(pOwner->m_nButtons & IN_ATTACK2) )
+ {
+ // Both buttons released. The player can draw the bow again.
+ m_bNoFire = false;
+
+ if ( GetActivity() == ACT_ITEM2_VM_PRIMARYATTACK && IsViewModelSequenceFinished() )
+ {
+ SendWeaponAnim( ACT_VM_IDLE );
+ }
+ }
+
+ if ( GetCurrentCharge() == 1.f && IsViewModelSequenceFinished() )
+ {
+ SendWeaponAnim( ACT_VM_IDLE );
+ }
+
+ if ( m_bNoFire )
+ {
+ WeaponIdle();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Held the arrow drawn too long. Give up & play a fail animation.
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::ForceLaunchGrenade( void )
+{
+ // LowerBow();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::GetProjectileFireSetup( CTFPlayer *pPlayer, Vector vecOffset, Vector *vecSrc, QAngle *angForward, bool bHitTeammates, float flEndDist )
+{
+ BaseClass::GetProjectileFireSetup( pPlayer, vecOffset, vecSrc, angForward, bHitTeammates, flEndDist );
+
+ float flTotalChargeTime = gpGlobals->curtime - m_flChargeBeginTime;
+ if ( flTotalChargeTime >= TF_ARROW_MAX_CHARGE_TIME )
+ {
+ // We want to fire a really inaccurate shot.
+ float frand = (float) rand() / VALVE_RAND_MAX;
+ angForward->x += -6 + frand*12.f;
+ frand = (float) rand() / VALVE_RAND_MAX;
+ angForward->y += -6 + frand*12.f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::ApplyRefireSpeedModifications( float &flBaseRef )
+{
+ CALL_ATTRIB_HOOK_FLOAT( flBaseRef, fast_reload );
+
+ // Prototype hack
+ CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
+ if ( pPlayer )
+ {
+ int iMaster = 0;
+ CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iMaster, ability_master_sniper );
+ if ( iMaster )
+ {
+ flBaseRef *= RemapValClamped( iMaster, 1, 2, 0.6f, 0.3f );
+ }
+ else if ( pPlayer->m_Shared.GetCarryingRuneType() == RUNE_HASTE )
+ {
+ flBaseRef *= 0.4f;
+ }
+ }
+}
+
+#ifdef CLIENT_DLL
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::StartBurningEffect( void )
+{
+ // clear any old effect before adding a new one
+ if ( m_pBurningArrowEffect )
+ {
+ StopBurningEffect();
+ }
+
+ const char *pszEffect;
+ m_hParticleEffectOwner = GetWeaponForEffect();
+ if ( m_hParticleEffectOwner )
+ {
+ if ( m_hParticleEffectOwner != this )
+ {
+ // We're on the viewmodel
+ pszEffect = "v_flaming_arrow";
+ }
+ else
+ {
+ pszEffect = "flaming_arrow";
+ }
+
+ m_pBurningArrowEffect = m_hParticleEffectOwner->ParticleProp()->Create( pszEffect, PATTACH_POINT_FOLLOW, "muzzle" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::StopBurningEffect( void )
+{
+ if ( m_pBurningArrowEffect )
+ {
+ if ( m_hParticleEffectOwner && m_hParticleEffectOwner->ParticleProp() )
+ {
+ m_hParticleEffectOwner->ParticleProp()->StopEmission( m_pBurningArrowEffect );
+ }
+
+ m_pBurningArrowEffect = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::UpdateOnRemove( void )
+{
+ StopBurningEffect();
+ BaseClass::UpdateOnRemove();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::OnDataChanged( DataUpdateType_t type )
+{
+ BaseClass::OnDataChanged( type );
+
+ // Handle particle effect creation / destruction
+ if ( m_bArrowAlight && !m_pBurningArrowEffect )
+ {
+ StartBurningEffect();
+ EmitSound( "ArrowLight" );
+ }
+ else if ( !m_bArrowAlight && m_pBurningArrowEffect )
+ {
+ StopBurningEffect();
+ }
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::Reload( void )
+{
+ if ( m_flNextPrimaryAttack > gpGlobals->curtime )
+ return false;
+ return BaseClass::Reload();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFCompoundBow::CalcIsAttackCriticalHelper()
+{
+ CTFPlayer *pPlayer = GetTFPlayerOwner();
+
+ // Crit boosted players fire all crits
+ if ( pPlayer && pPlayer->m_Shared.IsCritBoosted() )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFCompoundBow::SetArrowAlight( bool bAlight )
+{
+ // Don't light arrows if we're still firing one.
+ if (GetActivity() != ACT_ITEM2_VM_PRIMARYATTACK )
+ {
+ m_bArrowAlight = bAlight;
+ }
+} \ No newline at end of file