summaryrefslogtreecommitdiff
path: root/game/shared/tf/tf_weapon_sword.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/tf/tf_weapon_sword.cpp
downloadarchived-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.cpp617
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();
+}