source-engine/game/shared/dod/weapon_dodbasemelee.cpp
2022-04-16 12:05:19 +03:00

237 lines
6.3 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "weapon_dodbasemelee.h"
#include "dod_gamerules.h"
#if defined( CLIENT_DLL )
#include "c_dod_player.h"
#else
#include "dod_player.h"
#include "ilagcompensationmanager.h"
#endif
#include "effect_dispatch_data.h"
#define KNIFE_BODYHIT_VOLUME 128
#define KNIFE_WALLHIT_VOLUME 512
// ----------------------------------------------------------------------------- //
// CWeaponDODBaseMelee tables.
// ----------------------------------------------------------------------------- //
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponDODBaseMelee, DT_WeaponDODBaseMelee )
BEGIN_NETWORK_TABLE_NOBASE( CWeaponDODBaseMelee, DT_LocalActiveWeaponBaseMeleeData )
END_NETWORK_TABLE()
BEGIN_NETWORK_TABLE( CWeaponDODBaseMelee, DT_WeaponDODBaseMelee )
END_NETWORK_TABLE()
#ifdef CLIENT_DLL
BEGIN_PREDICTION_DATA( CWeaponDODBaseMelee )
DEFINE_PRED_FIELD( m_flSmackTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
#endif
LINK_ENTITY_TO_CLASS( weapon_dod_base_melee, CWeaponDODBaseMelee );
#ifndef CLIENT_DLL
BEGIN_DATADESC( CWeaponDODBaseMelee )
DEFINE_FUNCTION( Smack )
END_DATADESC()
#endif
// ----------------------------------------------------------------------------- //
// CWeaponDODBaseMelee implementation.
// ----------------------------------------------------------------------------- //
CWeaponDODBaseMelee::CWeaponDODBaseMelee()
{
}
void CWeaponDODBaseMelee::Spawn()
{
Precache();
WEAPON_FILE_INFO_HANDLE hWpnInfo = LookupWeaponInfoSlot( GetClassname() );
Assert( hWpnInfo != GetInvalidWeaponInfoHandle() );
CDODWeaponInfo *pWeaponInfo = dynamic_cast< CDODWeaponInfo* >( GetFileWeaponInfoFromHandle( hWpnInfo ) );
Assert( pWeaponInfo && "Failed to get CDODWeaponInfo in melee weapon spawn" );
m_pWeaponInfo = pWeaponInfo;
Assert( m_pWeaponInfo );
m_iClip1 = -1;
BaseClass::Spawn();
}
void CWeaponDODBaseMelee::WeaponIdle( void )
{
if ( m_flTimeWeaponIdle > gpGlobals->curtime )
return;
SendWeaponAnim( ACT_VM_IDLE );
m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
}
void CWeaponDODBaseMelee::PrimaryAttack()
{
MeleeAttack( 60, MELEE_DMG_EDGE, 0.2f, 0.4f );
}
CBaseEntity *CWeaponDODBaseMelee::MeleeAttack( int iDamageAmount, int iDamageType, float flDmgDelay, float flAttackDelay )
{
if ( !CanAttack() )
return NULL;
CDODPlayer *pPlayer = ToDODPlayer( GetPlayerOwner() );
#if !defined (CLIENT_DLL)
// Move other players back to history positions based on local player's lag
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
#endif
Vector vForward, vRight, vUp;
AngleVectors( pPlayer->EyeAngles(), &vForward, &vRight, &vUp );
Vector vecSrc = pPlayer->Weapon_ShootPosition();
Vector vecEnd = vecSrc + vForward * 48;
CTraceFilterSimple filter( pPlayer, COLLISION_GROUP_NONE );
int iTraceMask = MASK_SOLID | CONTENTS_HITBOX | CONTENTS_DEBRIS;
trace_t tr;
UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &filter, &tr );
const float rayExtension = 40.0f;
UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vForward * rayExtension, iTraceMask, &filter, &tr );
if ( tr.fraction >= 1.0 )
{
Vector head_hull_mins( -16, -16, -18 );
Vector head_hull_maxs( 16, 16, 18 );
UTIL_TraceHull( vecSrc, vecEnd, head_hull_mins, head_hull_maxs, MASK_SOLID, &filter, &tr );
if ( tr.fraction < 1.0 )
{
// Calculate the point of intersection of the line (or hull) and the object we hit
// This is and approximation of the "best" intersection
CBaseEntity *pHit = tr.m_pEnt;
if ( !pHit || pHit->IsBSPModel() )
FindHullIntersection( vecSrc, tr, VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX, pPlayer );
vecEnd = tr.endpos; // This is the point on the actual surface (the hull could have hit space)
// Make sure it is in front of us
Vector vecToEnd = vecEnd - vecSrc;
VectorNormalize( vecToEnd );
// if zero length, always hit
if ( vecToEnd.Length() > 0 )
{
float dot = DotProduct( vForward, vecToEnd );
// sanity that our hit is within range
if ( abs(dot) < 0.95 )
{
// fake that we actually missed
tr.fraction = 1.0;
}
}
}
}
bool bDidHit = ( tr.fraction < 1.0f );
bool bDoStrongAttack = false;
if ( bDidHit && tr.m_pEnt->IsPlayer() && tr.m_pEnt->m_takedamage != DAMAGE_YES )
{
bDidHit = 0; // still play the animation, we just dont attempt to damage this player
}
if ( bDidHit ) //if the swing hit
{
// delay the decal a bit
m_trHit = tr;
// Store the ent in an EHANDLE, just in case it goes away by the time we get into our think function.
m_pTraceHitEnt = tr.m_pEnt;
m_iSmackDamage = iDamageAmount;
m_iSmackDamageType = iDamageType;
m_flSmackTime = gpGlobals->curtime + flDmgDelay;
int iOwnerTeam = pPlayer->GetTeamNumber();
int iVictimTeam = tr.m_pEnt->GetTeamNumber();
// do the mega attack if its a player, and we would do damage
if ( tr.m_pEnt->IsPlayer() &&
tr.m_pEnt->m_takedamage == DAMAGE_YES &&
( iVictimTeam != iOwnerTeam || ( iVictimTeam == iOwnerTeam && friendlyfire.GetBool() ) ) )
{
CDODPlayer *pVictim = ToDODPlayer( tr.m_pEnt );
Vector victimForward;
AngleVectors( pVictim->GetAbsAngles(), &victimForward );
if ( DotProduct( victimForward, vForward ) > 0.3 )
{
bDoStrongAttack = true;
}
}
}
if ( bDoStrongAttack )
{
m_iSmackDamage = 300;
flAttackDelay = 0.9f;
m_flSmackTime = gpGlobals->curtime + 0.4f;
m_iSmackDamageType = MELEE_DMG_EDGE | MELEE_DMG_STRONGATTACK;
// play a "Strong" attack
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
}
else
{
WeaponSound( MELEE_MISS );
SendWeaponAnim( GetMeleeActivity() );
}
// player animation
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SECONDARY_ATTACK );
m_flNextPrimaryAttack = gpGlobals->curtime + flAttackDelay;
m_flNextSecondaryAttack = gpGlobals->curtime + flAttackDelay;
m_flTimeWeaponIdle = gpGlobals->curtime + SequenceDuration();
#ifndef CLIENT_DLL
IGameEvent * event = gameeventmanager->CreateEvent( "dod_stats_weapon_attack" );
if ( event )
{
event->SetInt( "attacker", pPlayer->GetUserID() );
event->SetInt( "weapon", GetStatsWeaponID() );
gameeventmanager->FireEvent( event );
}
lagcompensation->FinishLagCompensation( pPlayer );
#endif //CLIENT_DLL
return tr.m_pEnt;
}