diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_weapon_compound_bow.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/tf/tf_weapon_compound_bow.cpp')
| -rw-r--r-- | game/shared/tf/tf_weapon_compound_bow.cpp | 685 |
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 |