source-engine/game/shared/tf2base/tf_weapon_knife.cpp
2022-08-13 03:20:41 +03:00

177 lines
5.0 KiB
C++

//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose: Weapon Knife.
//
//=============================================================================
#include "cbase.h"
#include "tf_gamerules.h"
#include "tf_weapon_knife.h"
#include "decals.h"
// Client specific.
#ifdef CLIENT_DLL
#include "c_tf_player.h"
// Server specific.
#else
#include "tf_player.h"
#include "tf_gamestats.h"
#endif
//=============================================================================
//
// Weapon Knife tables.
//
IMPLEMENT_NETWORKCLASS_ALIASED( TFKnife, DT_TFWeaponKnife )
BEGIN_NETWORK_TABLE( CTFKnife, DT_TFWeaponKnife )
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CTFKnife )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( tf_weapon_knife, CTFKnife );
PRECACHE_WEAPON_REGISTER( tf_weapon_knife );
//=============================================================================
//
// Weapon Knife functions.
//
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFKnife::CTFKnife()
{
}
//-----------------------------------------------------------------------------
// Purpose: Set stealth attack bool
//-----------------------------------------------------------------------------
void CTFKnife::PrimaryAttack( void )
{
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( !CanAttack() )
return;
// Set the weapon usage mode - primary, secondary.
m_iWeaponMode = TF_WEAPON_PRIMARY_MODE;
trace_t trace;
if ( DoSwingTrace( trace ) == true )
{
// we will hit something with the attack
if( trace.m_pEnt && trace.m_pEnt->IsPlayer() )
{
CTFPlayer *pTarget = ToTFPlayer( trace.m_pEnt );
if ( pTarget && pTarget->GetTeamNumber() != pPlayer->GetTeamNumber() )
{
// Deal extra damage to players when stabbing them from behind
if ( IsBehindTarget( trace.m_pEnt ) )
{
// this will be a backstab, do the strong anim
m_iWeaponMode = TF_WEAPON_SECONDARY_MODE;
// store the victim to compare when we do the damage
m_hBackstabVictim = trace.m_pEnt;
}
}
}
}
#ifndef CLIENT_DLL
pPlayer->RemoveInvisibility();
pPlayer->RemoveDisguise();
#endif
// Swing the weapon.
Swing( pPlayer );
#if !defined( CLIENT_DLL )
pPlayer->SpeakWeaponFire();
CTF_GameStats.Event_PlayerFiredWeapon( pPlayer, IsCurrentAttackACritical() );
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Do backstab damage
//-----------------------------------------------------------------------------
float CTFKnife::GetMeleeDamage( CBaseEntity *pTarget, int &iCustomDamage )
{
float flBaseDamage = BaseClass::GetMeleeDamage( pTarget, iCustomDamage );
if ( pTarget->IsPlayer() )
{
// This counts as a backstab if:
// a ) we are behind the target player
// or b) we were behind this target player when we started the stab
if ( IsBehindTarget( pTarget ) ||
( m_iWeaponMode == TF_WEAPON_SECONDARY_MODE && m_hBackstabVictim.Get() == pTarget ) )
{
// this will be a backstab, do the strong anim.
// Do twice the target's health so that random modification will still kill him.
flBaseDamage = pTarget->GetHealth() * 2;
// Declare a backstab.
iCustomDamage = TF_DMG_CUSTOM_BACKSTAB;
}
else
{
m_bCurrentAttackIsCrit = false; // don't do a crit if we failed the above checks.
}
}
return flBaseDamage;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFKnife::IsBehindTarget( CBaseEntity *pTarget )
{
Assert( pTarget );
// Get the forward view vector of the target, ignore Z
Vector vecVictimForward;
AngleVectors( pTarget->EyeAngles(), &vecVictimForward, NULL, NULL );
vecVictimForward.z = 0.0f;
vecVictimForward.NormalizeInPlace();
// Get a vector from my origin to my targets origin
Vector vecToTarget;
vecToTarget = pTarget->WorldSpaceCenter() - GetOwner()->WorldSpaceCenter();
vecToTarget.z = 0.0f;
vecToTarget.NormalizeInPlace();
float flDot = DotProduct( vecVictimForward, vecToTarget );
return ( flDot > -0.1 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFKnife::CalcIsAttackCriticalHelper( void )
{
// Always crit from behind, never from front
return ( m_iWeaponMode == TF_WEAPON_SECONDARY_MODE );
}
//-----------------------------------------------------------------------------
// Purpose: Allow melee weapons to send different anim events
// Input : -
//-----------------------------------------------------------------------------
void CTFKnife::SendPlayerAnimEvent( CTFPlayer *pPlayer )
{
if ( m_iWeaponMode == TF_WEAPON_SECONDARY_MODE )
{
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_CUSTOM_GESTURE, ACT_MP_ATTACK_STAND_SECONDARYFIRE );
}
else
{
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY );
}
}