//========= Copyright Valve Corporation, All rights reserved. ============// // // //============================================================================= #include "cbase.h" #include "tf_weapon_revolver.h" #include "tf_fx_shared.h" #include "datamap.h" #include "tf_weaponbase_gun.h" // Client specific. #ifdef CLIENT_DLL #include "c_tf_player.h" // Server specific. #else #include "tf_player.h" #endif //============================================================================= // // Weapon Revolver tables. // IMPLEMENT_NETWORKCLASS_ALIASED( TFRevolver, DT_WeaponRevolver ) BEGIN_NETWORK_TABLE( CTFRevolver, DT_WeaponRevolver ) END_NETWORK_TABLE() #ifdef CLIENT_DLL BEGIN_PREDICTION_DATA( CTFRevolver ) DEFINE_PRED_FIELD( m_flLastAccuracyCheck, FIELD_FLOAT, 0 ), END_PREDICTION_DATA() #endif LINK_ENTITY_TO_CLASS( tf_weapon_revolver, CTFRevolver ); PRECACHE_WEAPON_REGISTER( tf_weapon_revolver ); // Server specific. #ifndef CLIENT_DLL BEGIN_DATADESC( CTFRevolver ) END_DATADESC() #endif #ifdef STAGING_ONLY CREATE_SIMPLE_WEAPON_TABLE( TFRevolver_Secondary, tf_weapon_revolver_secondary ) #endif //============================================================================= // // Weapon Revolver functions. // CTFRevolver::CTFRevolver() { m_flLastAccuracyCheck = 0.f; m_flAccuracyCheckTime = 0.f; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFRevolver::DefaultReload( int iClipSize1, int iClipSize2, int iActivity ) { // The the owning local player. CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( !pPlayer ) return false; if ( pPlayer->IsPlayerClass( TF_CLASS_SPY ) ) { if ( pPlayer->m_Shared.InCond( TF_COND_STEALTHED ) ) { return false; } } if ( pPlayer->m_Shared.IsFeignDeathReady() ) return false; // Can't reload if our feign death arm is up. return BaseClass::DefaultReload( iClipSize1, iClipSize2, iActivity ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CTFRevolver::GetDamageType( void ) const { if ( CanHeadshot() && (gpGlobals->curtime - m_flLastAccuracyCheck > 1.f) ) { int iDamageType = BaseClass::GetDamageType() | DMG_USE_HITLOCATIONS; return iDamageType; } return BaseClass::GetDamageType(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFRevolver::CanFireCriticalShot( bool bIsHeadshot ) { if ( !BaseClass::CanFireCriticalShot( bIsHeadshot ) ) return false; CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( pPlayer && pPlayer->m_Shared.IsCritBoosted() ) return true; // can only fire a crit shot if this is a headshot, unless we're critboosted if ( !bIsHeadshot ) { // Base revolver still randomly crits. Ambassador doesn't. return !CanHeadshot(); } return true; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFRevolver::PrimaryAttack( void ) { // Check for ammunition. if ( m_iClip1 <= 0 && m_iClip1 != -1 ) return; // Are we capable of firing again? if ( m_flNextPrimaryAttack > gpGlobals->curtime ) return; // Get the player owning the weapon. CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() ); if ( !pPlayer ) return; if ( !CanAttack() ) return; BaseClass::PrimaryAttack(); if ( HasLastShotCritical() ) { pPlayer->m_Shared.AddCond( TF_COND_CRITBOOSTED ); } else { int iAttr = 0; CALL_ATTRIB_HOOK_INT( iAttr, last_shot_crits ); if ( iAttr ) { pPlayer->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); } } m_flLastAccuracyCheck = gpGlobals->curtime; if ( SapperKillsCollectCrits() ) { // Do this after the attack, so that we know if we are doing custom damage CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( pOwner ) { int iRevengeCrits = pOwner->m_Shared.GetRevengeCrits(); if ( iRevengeCrits > 0 ) { pOwner->m_Shared.SetRevengeCrits( iRevengeCrits-1 ); } } } #ifdef GAME_DLL // Lower bonus for each attack int iExtraDamageOnHitPenalty = 0; CALL_ATTRIB_HOOK_INT( iExtraDamageOnHitPenalty, extra_damage_on_hit_penalty ); if ( iExtraDamageOnHitPenalty ) { int iDecaps = pPlayer->m_Shared.GetDecapitations(); pPlayer->m_Shared.SetDecapitations( Max( 0, iDecaps - iExtraDamageOnHitPenalty ) ); } #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- float CTFRevolver::GetWeaponSpread( void ) { float fSpread = BaseClass::GetWeaponSpread(); if ( CanHeadshot() ) { // We are highly accurate for our first shot. float flTimeSinceCheck = gpGlobals->curtime - m_flLastAccuracyCheck; fSpread = RemapValClamped( flTimeSinceCheck, 1.0f, 0.5f, 0.0f, fSpread+0.0f ); } return fSpread; } #ifdef CLIENT_DLL //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFRevolver::GetWeaponCrosshairScale( float &flScale ) { C_TFPlayer* pTFPlayer = ToTFPlayer( GetOwner() ); if ( !pTFPlayer ) return; if ( CanHeadshot() ) { float curtime = pTFPlayer->GetFinalPredictedTime() + ( gpGlobals->interpolation_amount * TICK_INTERVAL ); float flTimeSinceCheck = curtime - m_flLastAccuracyCheck; flScale = RemapValClamped( flTimeSinceCheck, 1.0f, 0.5f, 0.75f, 2.5f ); } else { BaseClass::GetWeaponCrosshairScale( flScale ); } } #endif //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- int CTFRevolver::GetCount( void ) { CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( !pOwner ) return 0; if ( SapperKillsCollectCrits() ) { return pOwner->m_Shared.GetRevengeCrits(); } int iExtraDamageOnHit = 0; CALL_ATTRIB_HOOK_INT( iExtraDamageOnHit, extra_damage_on_hit ); if ( iExtraDamageOnHit ) { return Min( 200, pOwner->m_Shared.GetDecapitations() ); } return 0; } //----------------------------------------------------------------------------- const char* CTFRevolver::GetEffectLabelText( void ) { int iExtraDamageOnHit = 0; CALL_ATTRIB_HOOK_INT( iExtraDamageOnHit, extra_damage_on_hit ); if ( iExtraDamageOnHit ) { return "#TF_BONUS"; } return "#TF_CRITS"; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFRevolver::Holster( CBaseCombatWeapon *pSwitchingTo ) { #ifdef GAME_DLL CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( pOwner ) { if ( SapperKillsCollectCrits() ) { if ( pOwner->m_Shared.GetRevengeCrits() ) { pOwner->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); } } if ( HasLastShotCritical() ) { pOwner->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); } } #endif return BaseClass::Holster( pSwitchingTo ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFRevolver::Deploy( void ) { #ifdef GAME_DLL CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() ); if ( pOwner ) { if ( SapperKillsCollectCrits() ) { if ( pOwner->m_Shared.GetRevengeCrits() ) { pOwner->m_Shared.AddCond( TF_COND_CRITBOOSTED ); } } if ( HasLastShotCritical() ) { pOwner->m_Shared.AddCond( TF_COND_CRITBOOSTED ); } } #endif return BaseClass::Deploy(); } #ifdef GAME_DLL //----------------------------------------------------------------------------- // Purpose: Reset revenge crits when the revolver is changed //----------------------------------------------------------------------------- void CTFRevolver::Detach( void ) { if ( SapperKillsCollectCrits() ) { CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( pPlayer ) { pPlayer->m_Shared.SetRevengeCrits( 0 ); pPlayer->m_Shared.RemoveCond( TF_COND_CRITBOOSTED ); } } BaseClass::Detach(); } //----------------------------------------------------------------------------- float CTFRevolver::GetProjectileDamage( void ) { float flDamageMod = 1.0f; int iExtraDamageOnHit = 0; CALL_ATTRIB_HOOK_INT( iExtraDamageOnHit, extra_damage_on_hit ); if ( iExtraDamageOnHit ) { CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); if ( pOwner ) { flDamageMod = 1.0f + ( Min( 200, pOwner->m_Shared.GetDecapitations() ) * 0.01f ); } } return BaseClass::GetProjectileDamage() * flDamageMod; } #endif