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_sword.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_sword.cpp')
| -rw-r--r-- | game/shared/tf/tf_weapon_sword.cpp | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/game/shared/tf/tf_weapon_sword.cpp b/game/shared/tf/tf_weapon_sword.cpp new file mode 100644 index 0000000..fba0a9f --- /dev/null +++ b/game/shared/tf/tf_weapon_sword.cpp @@ -0,0 +1,617 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "tf_weapon_sword.h" + +// Client specific. +#ifdef CLIENT_DLL +#include "c_tf_player.h" +#include "econ_entity.h" +// Server specific. +#else +#include "tf_player.h" +#endif + +//============================================================================= +// +// Weapon Sword tables. +// + +// CTFSword +IMPLEMENT_NETWORKCLASS_ALIASED( TFSword, DT_TFWeaponSword ) + +BEGIN_NETWORK_TABLE( CTFSword, DT_TFWeaponSword ) +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CTFSword ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( tf_weapon_sword, CTFSword ); +PRECACHE_WEAPON_REGISTER( tf_weapon_sword ); + +// CTFKatana +IMPLEMENT_NETWORKCLASS_ALIASED( TFKatana, DT_TFWeaponKatana ) + +BEGIN_NETWORK_TABLE( CTFKatana, DT_TFWeaponKatana ) +#ifdef CLIENT_DLL + RecvPropBool( RECVINFO( m_bIsBloody ) ), +#else + SendPropBool( SENDINFO( m_bIsBloody ) ), +#endif +END_NETWORK_TABLE() + +BEGIN_PREDICTION_DATA( CTFKatana ) +END_PREDICTION_DATA() + +LINK_ENTITY_TO_CLASS( tf_weapon_katana, CTFKatana ); +PRECACHE_WEAPON_REGISTER( tf_weapon_katana ); + +//============================================================================= +// +// Decapitation melee weapon base implementation. +// + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFDecapitationMeleeWeaponBase::CTFDecapitationMeleeWeaponBase() + : m_bHolstering( false ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFDecapitationMeleeWeaponBase::Precache() +{ + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CTFDecapitationMeleeWeaponBase::GetMeleeDamage( CBaseEntity *pTarget, int* piDamageType, int* piCustomDamage ) +{ + float flBaseDamage = BaseClass::GetMeleeDamage( pTarget, piDamageType, piCustomDamage ); + + *piCustomDamage = TF_DMG_CUSTOM_DECAPITATION; + + return flBaseDamage; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +Activity CTFDecapitationMeleeWeaponBase::TranslateViewmodelHandActivityInternal( Activity actBase ) +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( !pPlayer ) + return BaseClass::TranslateViewmodelHandActivityInternal( actBase ); + + CEconItemView *pEconItemView = GetAttributeContainer()->GetItem(); + if ( pEconItemView ) + { + if ( pEconItemView->GetAnimationSlot() == TF_WPN_TYPE_MELEE_ALLCLASS ) + return BaseClass::TranslateViewmodelHandActivityInternal( actBase ); + } + + // Alright, so we have some decapitation weapons (katana) that can be used + // by both the soldier and the demoman, but the classes play totally different + // animations using the same weapon. + // + // This logic is also responsible for playing the correct animations on the + // demo when he's using non-shared weapons like the Eyelanders. + if ( pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_DEMOMAN ) + { + switch ( actBase ) + { + case ACT_VM_DRAW: + actBase = ACT_VM_DRAW_SPECIAL; + break; + case ACT_VM_HOLSTER: + actBase = ACT_VM_HOLSTER_SPECIAL; + break; + case ACT_VM_IDLE: + actBase = ACT_VM_IDLE_SPECIAL; + break; + case ACT_VM_PULLBACK: + actBase = ACT_VM_PULLBACK_SPECIAL; + break; + case ACT_VM_PRIMARYATTACK: + actBase = ACT_VM_PRIMARYATTACK_SPECIAL; + break; + case ACT_VM_SECONDARYATTACK: + actBase = ACT_VM_PRIMARYATTACK_SPECIAL; + break; + case ACT_VM_HITCENTER: + actBase = ACT_VM_HITCENTER_SPECIAL; + break; + case ACT_VM_SWINGHARD: + actBase = ACT_VM_SWINGHARD_SPECIAL; + break; + case ACT_VM_IDLE_TO_LOWERED: + actBase = ACT_VM_IDLE_TO_LOWERED_SPECIAL; + break; + case ACT_VM_IDLE_LOWERED: + actBase = ACT_VM_IDLE_LOWERED_SPECIAL; + break; + case ACT_VM_LOWERED_TO_IDLE: + actBase = ACT_VM_LOWERED_TO_IDLE_SPECIAL; + break; + default: + break; + } + } + + return BaseClass::TranslateViewmodelHandActivityInternal( actBase ); +} +/* +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFDecapitationMeleeWeaponBase::SendWeaponAnim( int iActivity ) +{ + +}*/ + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFDecapitationMeleeWeaponBase::CanDecapitate( void ) +{ + CEconItemView *pScriptItem = GetAttributeContainer()->GetItem(); + if ( !pScriptItem ) + return false; + + CEconItemDefinition *pStaticData = pScriptItem->GetStaticData(); + if ( !pStaticData ) + return false; + + int iDecapitateType = 0; + CALL_ATTRIB_HOOK_INT( iDecapitateType, decapitate_type ); + return iDecapitateType != 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFDecapitationMeleeWeaponBase::SetupGameEventListeners( void ) +{ + ListenForGameEvent( "player_death" ); +} + +#ifdef CLIENT_DLL +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFDecapitationMeleeWeaponBase::UpdateAttachmentModels( void ) +{ + BaseClass::UpdateAttachmentModels(); + + CTFPlayer *pTFPlayer = GetTFPlayerOwner(); + if ( !pTFPlayer ) + return; + + if ( !pTFPlayer->IsLocalPlayer() ) + return; + + if ( !pTFPlayer->GetViewModel() ) + return; + + if ( !pTFPlayer->m_Shared.IsShieldEquipped() ) + return; + + CTFWearableDemoShield* pMyShield = dynamic_cast<CTFWearableDemoShield*>( m_hShield.Get() ); + + if ( pMyShield ) + { + pMyShield->UpdateAttachmentModels(); + } + else + { + // Find a shield wearable... + for ( int i=0; i<pTFPlayer->GetNumWearables(); ++i ) + { + CEconWearable* pItem = pTFPlayer->GetWearable(i); + if ( !pItem ) + continue; + + pMyShield = dynamic_cast<CTFWearableDemoShield*>( pItem ); + if ( !pMyShield ) + continue; + + m_hShield.Set( pMyShield ); + } + + if ( pMyShield ) + { + pMyShield->UpdateAttachmentModels(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFDecapitationMeleeWeaponBase::DrawOverriddenViewmodel( C_BaseViewModel *pViewmodel, int flags ) +{ + int iRes = BaseClass::DrawOverriddenViewmodel( pViewmodel, flags ); + + CTFWearableDemoShield* pMyShield = dynamic_cast<CTFWearableDemoShield*>( m_hShield.Get() ); + + if ( pMyShield ) + { + pMyShield->DrawOverriddenViewmodel( pViewmodel, flags ); + } + + return iRes; +} +#endif // CLIENT_DLL + +//============================================================================= +// +// Weapon Sword functions. +// + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFSword::WeaponReset( void ) +{ + BaseClass::WeaponReset(); + +#ifdef CLIENT_DLL + m_flNextIdleWavRoll = 0; + m_iPrevWavDecap = 0; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFSword::GetSwingRange( void ) +{ + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( pOwner && pOwner->m_Shared.InCond( TF_COND_SHIELD_CHARGE ) ) + { + return 128; + } + else + { + //int iRange = 0; + //CALL_ATTRIB_HOOK_INT( iRange, is_a_sword ) + //return 72; + return 72; + } +} + +//----------------------------------------------------------------------------- +// Purpose: A speed mod that is applied even if the weapon isn't in hand. +//----------------------------------------------------------------------------- +float CTFSword::GetSwordSpeedMod( void ) +{ + if ( m_bHolstering ) + return 1.f; + + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return 0; + + if ( !CanDecapitate() ) + return 1.f; + + int iDecaps = MIN( MAX_DECAPITATIONS, pOwner->m_Shared.GetDecapitations() ); + return 1.f + (iDecaps * 0.08f); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFSword::GetSwordHealthMod( void ) +{ + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return 0; + + if ( !CanDecapitate() ) + return 0.f; + + int iDecaps = MIN( MAX_DECAPITATIONS, pOwner->m_Shared.GetDecapitations() ); + return (iDecaps * 15); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFSword::OnDecapitation( CTFPlayer *pDeadPlayer ) +{ + BaseClass::OnDecapitation( pDeadPlayer ); + +#ifdef GAME_DLL + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + Assert( pOwner ); + + // The pyro's scythe is actually a "sword" as far as the gameplay code is concerned, + // but we don't want the demo's head-collecting silliness to apply. + if ( pOwner->GetPlayerClass()->GetClassIndex() == TF_CLASS_DEMOMAN ) + { + // We have chopped someone's bloody 'ead off! + int iDecap = pOwner->m_Shared.GetDecapitations(); + + // transfer decapitations + if ( pDeadPlayer ) + { + iDecap += pDeadPlayer->m_Shared.GetDecapitations(); + } + pOwner->m_Shared.SetDecapitations( ++iDecap ); + pOwner->TeamFortress_SetSpeed(); + if ( pOwner->m_Shared.GetBestOverhealDecayMult() == -1.f ) + { + pOwner->m_Shared.SetBestOverhealDecayMult( 0.25f ); + } + if ( pOwner->GetHealth() < pOwner->m_Shared.GetMaxBuffedHealth() ) + { + pOwner->TakeHealth( 15, DMG_IGNORE_MAXHEALTH ); + } + if ( !pOwner->m_Shared.InCond( TF_COND_DEMO_BUFF ) ) + { + pOwner->m_Shared.AddCond( TF_COND_DEMO_BUFF ); + } + } +#endif // GAME_DLL +} + +#ifdef GAME_DLL + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFDecapitationMeleeWeaponBase::Holster( CBaseCombatWeapon *pSwitchingTo ) +{ + m_bHolstering = true; + bool res = BaseClass::Holster( pSwitchingTo ); + m_bHolstering = false; + if ( res ) + { + StopListeningForAllEvents(); + } + return res; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFDecapitationMeleeWeaponBase::FireGameEvent( IGameEvent *event ) +{ + const char *pszEventName = event->GetName(); + if ( Q_strcmp( pszEventName, "player_death" ) != 0 ) + return; + + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + int iAttackerID = event->GetInt( "attacker" ); + if ( iAttackerID != pOwner->GetUserID() ) + return; + + int iWeaponID = event->GetInt( "weaponid" ); + int iCustomKill = event->GetInt( "customkill" ); + if ( iWeaponID != TF_WEAPON_SWORD && iCustomKill != TF_DMG_CUSTOM_TAUNTATK_BARBARIAN_SWING ) + return; + + // Off with their heads! + if ( !CanDecapitate() ) + return; + + OnDecapitation( ToTFPlayer( UTIL_PlayerByUserId( event->GetInt( "userid" ) ) ) ); +} +#endif + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFSword::Deploy( void ) +{ + bool res = BaseClass::Deploy(); + + if ( !CanDecapitate() ) + { + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return res; + + pOwner->m_Shared.SetDecapitations( 0 ); + + return res; + } + +#ifdef GAME_DLL + if ( res ) + { + SetupGameEventListeners(); + } +#else + // When we go active, there's a chance we immediately thirst for heads. + if ( RandomInt( 1,4 ) == 1 ) + { + m_flNextIdleWavRoll = gpGlobals->curtime + 3.0; + } + else + { + m_flNextIdleWavRoll = gpGlobals->curtime + RandomFloat( 5.0, 30.0 ); + } +#endif + + return res; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFSword::GetCount( void ) +{ + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return 0; + + if ( !CanDecapitate() ) + return 0; + + return pOwner->m_Shared.GetDecapitations(); +} + +#ifdef CLIENT_DLL +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFSword::WeaponIdle( void ) +{ + BaseClass::WeaponIdle(); + + CTFPlayer *pOwner = ToTFPlayer( GetOwner() ); + if ( !pOwner ) + return; + + if ( !CanDecapitate() ) + return; + + // If we've decapped someone recently, we roll shortly afterwards + int iDecaps = pOwner->m_Shared.GetDecapitations(); + if ( m_iPrevWavDecap < iDecaps ) + { + m_flNextIdleWavRoll = MIN( m_flNextIdleWavRoll, gpGlobals->curtime + RandomFloat(3,5) ); + } + m_iPrevWavDecap = iDecaps; + + // Randomly play sounds to the local player. The more decaps we have, the more chance it's a good wav. + if ( m_flNextIdleWavRoll < gpGlobals->curtime ) + { + float flChance = RemapValClamped( iDecaps, 0, 10, 0.25, 0.9 ); + if ( RandomFloat() <= flChance ) + { + // Chance to get the more powerful wav: + float flChanceForGoodWav = RemapValClamped( iDecaps, 0, 10, 0.1, 0.75 ); + if ( RandomFloat() <= flChanceForGoodWav ) + { + WeaponSound( SPECIAL2 ); + } + else + { + WeaponSound( SPECIAL1 ); + } + } + + m_flNextIdleWavRoll = gpGlobals->curtime + RandomFloat( 30.0, 60.0 ); + } +} + +#endif + + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFKatana::CTFKatana() +{ + m_bIsBloody = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFKatana::Deploy( void ) +{ + bool res = BaseClass::Deploy(); + + m_bIsBloody = false; + + if ( CanDecapitate() && res ) + { +#ifdef GAME_DLL + SetupGameEventListeners(); +#endif + } + + return res; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CTFKatana::GetMeleeDamage( CBaseEntity *pTarget, int* piDamageType, int* piCustomDamage ) +{ + // Start with our base damage. We use this to generate our custom damage flags, + // if any. We may trash the damage amount. + float fDamage = BaseClass::GetMeleeDamage( pTarget, piDamageType, piCustomDamage ); + + // The katana is a weapon of honor!!!! (Hitting someone wielding a katana with + // your katana results in a massive damage boost, a one-hit kill.) + if ( IsHonorBound() ) + { + CTFPlayer *pTFPlayerTarget = ToTFPlayer( pTarget ); + if ( pTFPlayerTarget ) + { + // If our victim is wielding the weapon we're looking for, bump the damage way up. + if ( pTFPlayerTarget->GetActiveTFWeapon() && pTFPlayerTarget->GetActiveTFWeapon()->IsHonorBound() ) + { + fDamage = MAX( fDamage, pTFPlayerTarget->GetHealth() * 3 ); + *piDamageType |= DMG_DONT_COUNT_DAMAGE_TOWARDS_CRIT_RATE; + } + } + } + + return fDamage; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFKatana::GetActivityWeaponRole() const +{ + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( pPlayer && pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_DEMOMAN ) + { + // demo should use act table item1 + return TF_WPN_TYPE_ITEM1; + } + + return BaseClass::GetActivityWeaponRole(); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFKatana::OnDecapitation( CTFPlayer *pDeadPlayer ) +{ + BaseClass::OnDecapitation( pDeadPlayer ); + +#ifndef CLIENT_DLL + m_bIsBloody = true; +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CTFKatana::GetSkinOverride() const +{ + if ( m_bIsBloody && !UTIL_IsLowViolence() ) + { + CTFPlayer *pPlayer = GetTFPlayerOwner(); + if ( pPlayer ) + { + return ( ( pPlayer->GetTeamNumber() == TF_TEAM_RED ) ? 2 : 3 ); + } + } + + return BaseClass::GetSkinOverride(); +} |