//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: TF Base Rockets. // //=============================================================================// #include "cbase.h" #include "tf_wearable_item_demoshield.h" #include "tf_gamerules.h" #include "engine/ivdebugoverlay.h" #include "tf_weapon_medigun.h" #ifdef CLIENT_DLL #include "tf_weapon_sword.h" #include "renamed_recvtable_compat.h" NOTE_RENAMED_RECVTABLE( DT_TFWearableItemDemoShield, DT_TFWearableDemoShield ) #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" LINK_ENTITY_TO_CLASS( tf_wearable_demoshield, CTFWearableDemoShield ); IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableDemoShield, DT_TFWearableDemoShield ) // Network Table -- BEGIN_NETWORK_TABLE( CTFWearableDemoShield, DT_TFWearableDemoShield ) #if defined( GAME_DLL ) #else #endif // GAME_DLL END_NETWORK_TABLE() // -- Network Table // Data Desc -- BEGIN_DATADESC( CTFWearableDemoShield ) END_DATADESC() // -- Data Desc //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CTFWearableDemoShield::CTFWearableDemoShield() : CTFWearable() { #ifdef GAME_DLL m_bImpactedSomething = false; #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWearableDemoShield::Precache() { BaseClass::Precache(); PrecacheScriptSound( "DemoCharge.HitWorld" ); PrecacheScriptSound( "DemoCharge.HitFlesh" ); PrecacheScriptSound( "DemoCharge.HitFleshRange" ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWearableDemoShield::DoSpecialAction( CTFPlayer *pPlayer ) { if ( CanCharge( pPlayer ) ) { DoCharge( pPlayer ); return; } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWearableDemoShield::EndSpecialAction( CTFPlayer *pPlayer ) { int nAttackNotCancelCharge = 0; CALL_ATTRIB_HOOK_INT( nAttackNotCancelCharge, attack_not_cancel_charge ); if ( nAttackNotCancelCharge > 0 ) { return; } if ( pPlayer->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) ) { pPlayer->m_Shared.CalcChargeCrit(); pPlayer->m_Shared.SetDemomanChargeMeter( 0 ); pPlayer->m_Shared.RemoveCond( TF_COND_SHIELD_CHARGE ); } } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CTFWearableDemoShield::CanCharge( CTFPlayer *pPlayer ) { // 6/14/2011 - Demos can now charge while in the air to counter pyro control. // if ( !(pPlayer->GetFlags() & FL_ONGROUND) ) // return false; if ( TFGameRules() && (TFGameRules()->State_Get() == GR_STATE_PREROUND) ) return false; if ( pPlayer->m_Shared.IsLoser() ) return false; if ( pPlayer->m_Shared.InCond( TF_COND_STUNNED ) ) return false; if ( pPlayer->IsTaunting() ) return false; if ( pPlayer->GetGrapplingHookTarget() ) return false; if ( pPlayer->m_Shared.GetDemomanChargeMeter() == 100.f ) return true; if ( TFGameRules() && TFGameRules()->IsPasstimeMode() && pPlayer->m_Shared.HasPasstimeBall() ) return false; return false; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWearableDemoShield::DoCharge( CTFPlayer *pPlayer ) { #ifdef GAME_DLL float flChargeTime = 1.5f; CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pPlayer, flChargeTime, mod_charge_time ); pPlayer->m_Shared.AddCond( TF_COND_SHIELD_CHARGE, flChargeTime ); m_bImpactedSomething = false; #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWearableDemoShield::ShieldBash( CTFPlayer *pPlayer, float flCurrentChargeMeter ) { CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); if ( !pOwner ) return; #ifdef GAME_DLL if ( m_bImpactedSomething ) return; m_bImpactedSomething = true; // Setup the swing range. Vector vecForward; AngleVectors( pOwner->EyeAngles(), &vecForward ); Vector vecStart = pOwner->Weapon_ShootPosition(); Vector vecEnd = vecStart + vecForward * 48; // See if we hit anything. trace_t trace; UTIL_TraceHull( vecStart, vecEnd, -Vector(24,24,24), Vector(24,24,24), MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &trace ); // Play an impact sound. bool bImpactDamage = false; if ( trace.m_pEnt ) { const char* pszSoundName = ""; if ( trace.m_pEnt->IsPlayer() ) { bImpactDamage = true; pszSoundName = "DemoCharge.HitFleshRange"; } else { pszSoundName = "DemoCharge.HitWorld"; } pOwner->EmitSound( pszSoundName ); } // Apply impact damage, if any. if ( bImpactDamage ) { float flBashDamage = CalculateChargeDamage( flCurrentChargeMeter ); CTakeDamageInfo info; info.SetAttacker( pOwner ); info.SetInflictor( this ); info.SetWeapon( this ); info.SetDamage( flBashDamage ); info.SetDamageCustom( TF_DMG_CUSTOM_CHARGE_IMPACT ); info.SetDamageForce( GetShieldDamageForce( flCurrentChargeMeter ) ); info.SetDamagePosition( trace.endpos ); info.SetDamageType( DMG_CLUB ); Vector dir; AngleVectors( pOwner->GetAbsAngles(), &dir ); trace.m_pEnt->DispatchTraceAttack( info, dir, &trace ); ApplyMultiDamage(); // Calculate charge crit if we did any bash damage pOwner->m_Shared.CalcChargeCrit(); } UTIL_ScreenShake( pOwner->WorldSpaceCenter(), 25.0, 150.0, 1.0, 750, SHAKE_START ); #endif } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- float CTFWearableDemoShield::CalculateChargeDamage( float flCurrentChargeMeter ) { float flImpactDamage = RemapValClamped( flCurrentChargeMeter, 90.0f, 40.0f, 15.0f, 50.0f ); CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); if ( !pOwner ) return flImpactDamage; // Cap at 5 decapitations for dmg bonus int iDecaps = Min( pOwner->m_Shared.GetDecapitations(), 5 ); if ( iDecaps > 0 ) { flImpactDamage *= (1.0f + iDecaps * 0.1f ); } CALL_ATTRIB_HOOK_FLOAT_ON_OTHER( pOwner, flImpactDamage, charge_impact_damage ); return flImpactDamage; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- Vector CTFWearableDemoShield::GetShieldDamageForce( float flCurrentChargeMeter ) { Vector vecVelocity = GetAbsVelocity(); IPhysicsObject *pPhysicsObject = VPhysicsGetObject(); if ( pPhysicsObject ) { pPhysicsObject->GetVelocity( &vecVelocity, NULL ); VectorNormalize( vecVelocity ); } return (vecVelocity * CalculateChargeDamage( flCurrentChargeMeter ) ); } //----------------------------------------------------------------------------- // Purpose: Attaches the item to the player. //----------------------------------------------------------------------------- void CTFWearableDemoShield::Equip( CBasePlayer* pOwner ) { BaseClass::Equip( pOwner ); if ( !CanEquip( pOwner ) ) return; CTFPlayer *pTFPlayer = ToTFPlayer( pOwner ); if ( pTFPlayer ) { pTFPlayer->m_Shared.SetShieldEquipped( true ); } } //----------------------------------------------------------------------------- // Purpose: Remove item from the player. //----------------------------------------------------------------------------- void CTFWearableDemoShield::UnEquip( CBasePlayer* pOwner ) { BaseClass::UnEquip( pOwner ); CTFPlayer *pTFPlayer = ToTFPlayer( pOwner ); if ( pTFPlayer ) { pTFPlayer->m_Shared.SetShieldEquipped( false ); } }