2008-09-15 01:07:45 -05:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
# include "cbase.h"
# include "basehlcombatweapon.h"
# include "player.h"
# include "gamerules.h"
# include "ammodef.h"
# include "mathlib/mathlib.h"
# include "in_buttons.h"
# include "soundent.h"
# include "animation.h"
# include "ai_condition.h"
# include "basebludgeonweapon.h"
# include "ndebugoverlay.h"
# include "te_effect_dispatch.h"
# include "rumble_shared.h"
2008-09-15 02:50:57 -05:00
# include "GameStats.h"
2008-09-15 01:07:45 -05:00
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
IMPLEMENT_SERVERCLASS_ST ( CBaseHLBludgeonWeapon , DT_BaseHLBludgeonWeapon )
END_SEND_TABLE ( )
# define BLUDGEON_HULL_DIM 16
static const Vector g_bludgeonMins ( - BLUDGEON_HULL_DIM , - BLUDGEON_HULL_DIM , - BLUDGEON_HULL_DIM ) ;
static const Vector g_bludgeonMaxs ( BLUDGEON_HULL_DIM , BLUDGEON_HULL_DIM , BLUDGEON_HULL_DIM ) ;
//-----------------------------------------------------------------------------
// Constructor
//-----------------------------------------------------------------------------
CBaseHLBludgeonWeapon : : CBaseHLBludgeonWeapon ( )
{
m_bFiresUnderwater = true ;
}
//-----------------------------------------------------------------------------
// Purpose: Spawn the weapon
//-----------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : Spawn ( void )
{
m_fMinRange1 = 0 ;
m_fMinRange2 = 0 ;
m_fMaxRange1 = 64 ;
m_fMaxRange2 = 64 ;
//Call base class first
BaseClass : : Spawn ( ) ;
}
//-----------------------------------------------------------------------------
// Purpose: Precache the weapon
//-----------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : Precache ( void )
{
//Call base class first
BaseClass : : Precache ( ) ;
}
int CBaseHLBludgeonWeapon : : CapabilitiesGet ( )
{
return bits_CAP_WEAPON_MELEE_ATTACK1 ;
}
int CBaseHLBludgeonWeapon : : WeaponMeleeAttack1Condition ( float flDot , float flDist )
{
if ( flDist > 64 )
{
return COND_TOO_FAR_TO_ATTACK ;
}
else if ( flDot < 0.7 )
{
return COND_NOT_FACING_ATTACK ;
}
return COND_CAN_MELEE_ATTACK1 ;
}
//------------------------------------------------------------------------------
// Purpose : Update weapon
//------------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : ItemPostFrame ( void )
{
CBasePlayer * pOwner = ToBasePlayer ( GetOwner ( ) ) ;
if ( pOwner = = NULL )
return ;
if ( ( pOwner - > m_nButtons & IN_ATTACK ) & & ( m_flNextPrimaryAttack < = gpGlobals - > curtime ) )
{
PrimaryAttack ( ) ;
}
else if ( ( pOwner - > m_nButtons & IN_ATTACK2 ) & & ( m_flNextSecondaryAttack < = gpGlobals - > curtime ) )
{
SecondaryAttack ( ) ;
}
else
{
WeaponIdle ( ) ;
return ;
}
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : PrimaryAttack ( )
{
Swing ( false ) ;
}
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : SecondaryAttack ( )
{
Swing ( true ) ;
}
//------------------------------------------------------------------------------
// Purpose: Implement impact function
//------------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : Hit ( trace_t & traceHit , Activity nHitActivity , bool bIsSecondary )
{
CBasePlayer * pPlayer = ToBasePlayer ( GetOwner ( ) ) ;
//Do view kick
AddViewKick ( ) ;
//Make sound for the AI
CSoundEnt : : InsertSound ( SOUND_BULLET_IMPACT , traceHit . endpos , 400 , 0.2f , pPlayer ) ;
// This isn't great, but it's something for when the crowbar hits.
pPlayer - > RumbleEffect ( RUMBLE_AR2 , 0 , RUMBLE_FLAG_RESTART ) ;
CBaseEntity * pHitEntity = traceHit . m_pEnt ;
//Apply damage to a hit target
if ( pHitEntity ! = NULL )
{
Vector hitDirection ;
pPlayer - > EyeVectors ( & hitDirection , NULL , NULL ) ;
VectorNormalize ( hitDirection ) ;
CTakeDamageInfo info ( GetOwner ( ) , GetOwner ( ) , GetDamageForActivity ( nHitActivity ) , DMG_CLUB ) ;
if ( pPlayer & & pHitEntity - > IsNPC ( ) )
{
// If bonking an NPC, adjust damage.
info . AdjustPlayerDamageInflictedForSkillLevel ( ) ;
}
CalculateMeleeDamageForce ( & info , hitDirection , traceHit . endpos ) ;
pHitEntity - > DispatchTraceAttack ( info , hitDirection , & traceHit ) ;
ApplyMultiDamage ( ) ;
// Now hit all triggers along the ray that...
TraceAttackToTriggers ( info , traceHit . startpos , traceHit . endpos , hitDirection ) ;
if ( ToBaseCombatCharacter ( pHitEntity ) )
{
gamestats - > Event_WeaponHit ( pPlayer , ! bIsSecondary , GetClassname ( ) , info ) ;
}
}
// Apply an impact effect
ImpactEffect ( traceHit ) ;
}
Activity CBaseHLBludgeonWeapon : : ChooseIntersectionPointAndActivity ( trace_t & hitTrace , const Vector & mins , const Vector & maxs , CBasePlayer * pOwner )
{
int i , j , k ;
float distance ;
const float * minmaxs [ 2 ] = { mins . Base ( ) , maxs . Base ( ) } ;
trace_t tmpTrace ;
Vector vecHullEnd = hitTrace . endpos ;
Vector vecEnd ;
distance = 1e6 f ;
Vector vecSrc = hitTrace . startpos ;
vecHullEnd = vecSrc + ( ( vecHullEnd - vecSrc ) * 2 ) ;
UTIL_TraceLine ( vecSrc , vecHullEnd , MASK_SHOT_HULL , pOwner , COLLISION_GROUP_NONE , & tmpTrace ) ;
if ( tmpTrace . fraction = = 1.0 )
{
for ( i = 0 ; i < 2 ; i + + )
{
for ( j = 0 ; j < 2 ; j + + )
{
for ( k = 0 ; k < 2 ; k + + )
{
vecEnd . x = vecHullEnd . x + minmaxs [ i ] [ 0 ] ;
vecEnd . y = vecHullEnd . y + minmaxs [ j ] [ 1 ] ;
vecEnd . z = vecHullEnd . z + minmaxs [ k ] [ 2 ] ;
UTIL_TraceLine ( vecSrc , vecEnd , MASK_SHOT_HULL , pOwner , COLLISION_GROUP_NONE , & tmpTrace ) ;
if ( tmpTrace . fraction < 1.0 )
{
float thisDistance = ( tmpTrace . endpos - vecSrc ) . Length ( ) ;
if ( thisDistance < distance )
{
hitTrace = tmpTrace ;
distance = thisDistance ;
}
}
}
}
}
}
else
{
hitTrace = tmpTrace ;
}
return ACT_VM_HITCENTER ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &traceHit -
//-----------------------------------------------------------------------------
bool CBaseHLBludgeonWeapon : : ImpactWater ( const Vector & start , const Vector & end )
{
//FIXME: This doesn't handle the case of trying to splash while being underwater, but that's not going to look good
// right now anyway...
// We must start outside the water
if ( UTIL_PointContents ( start ) & ( CONTENTS_WATER | CONTENTS_SLIME ) )
return false ;
// We must end inside of water
if ( ! ( UTIL_PointContents ( end ) & ( CONTENTS_WATER | CONTENTS_SLIME ) ) )
return false ;
trace_t waterTrace ;
UTIL_TraceLine ( start , end , ( CONTENTS_WATER | CONTENTS_SLIME ) , GetOwner ( ) , COLLISION_GROUP_NONE , & waterTrace ) ;
if ( waterTrace . fraction < 1.0f )
{
CEffectData data ;
data . m_fFlags = 0 ;
data . m_vOrigin = waterTrace . endpos ;
data . m_vNormal = waterTrace . plane . normal ;
data . m_flScale = 8.0f ;
// See if we hit slime
if ( waterTrace . contents & CONTENTS_SLIME )
{
data . m_fFlags | = FX_WATER_IN_SLIME ;
}
DispatchEffect ( " watersplash " , data ) ;
}
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : ImpactEffect ( trace_t & traceHit )
{
// See if we hit water (we don't do the other impact effects in this case)
if ( ImpactWater ( traceHit . startpos , traceHit . endpos ) )
return ;
//FIXME: need new decals
UTIL_ImpactTrace ( & traceHit , DMG_CLUB ) ;
}
//------------------------------------------------------------------------------
// Purpose : Starts the swing of the weapon and determines the animation
// Input : bIsSecondary - is this a secondary attack?
//------------------------------------------------------------------------------
void CBaseHLBludgeonWeapon : : Swing ( int bIsSecondary )
{
trace_t traceHit ;
// Try a ray
CBasePlayer * pOwner = ToBasePlayer ( GetOwner ( ) ) ;
if ( ! pOwner )
return ;
pOwner - > RumbleEffect ( RUMBLE_CROWBAR_SWING , 0 , RUMBLE_FLAG_RESTART ) ;
Vector swingStart = pOwner - > Weapon_ShootPosition ( ) ;
Vector forward ;
forward = pOwner - > GetAutoaimVector ( AUTOAIM_SCALE_DEFAULT , GetRange ( ) ) ;
Vector swingEnd = swingStart + forward * GetRange ( ) ;
UTIL_TraceLine ( swingStart , swingEnd , MASK_SHOT_HULL , pOwner , COLLISION_GROUP_NONE , & traceHit ) ;
Activity nHitActivity = ACT_VM_HITCENTER ;
// Like bullets, bludgeon traces have to trace against triggers.
CTakeDamageInfo triggerInfo ( GetOwner ( ) , GetOwner ( ) , GetDamageForActivity ( nHitActivity ) , DMG_CLUB ) ;
triggerInfo . SetDamagePosition ( traceHit . startpos ) ;
triggerInfo . SetDamageForce ( forward ) ;
TraceAttackToTriggers ( triggerInfo , traceHit . startpos , traceHit . endpos , forward ) ;
if ( traceHit . fraction = = 1.0 )
{
float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM ; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point
// Back off by hull "radius"
swingEnd - = forward * bludgeonHullRadius ;
UTIL_TraceHull ( swingStart , swingEnd , g_bludgeonMins , g_bludgeonMaxs , MASK_SHOT_HULL , pOwner , COLLISION_GROUP_NONE , & traceHit ) ;
if ( traceHit . fraction < 1.0 & & traceHit . m_pEnt )
{
Vector vecToTarget = traceHit . m_pEnt - > GetAbsOrigin ( ) - swingStart ;
VectorNormalize ( vecToTarget ) ;
float dot = vecToTarget . Dot ( forward ) ;
// YWB: Make sure they are sort of facing the guy at least...
if ( dot < 0.70721f )
{
// Force amiss
traceHit . fraction = 1.0f ;
}
else
{
nHitActivity = ChooseIntersectionPointAndActivity ( traceHit , g_bludgeonMins , g_bludgeonMaxs , pOwner ) ;
}
}
}
if ( ! bIsSecondary )
{
m_iPrimaryAttacks + + ;
}
else
{
m_iSecondaryAttacks + + ;
}
gamestats - > Event_WeaponFired ( pOwner , ! bIsSecondary , GetClassname ( ) ) ;
// -------------------------
// Miss
// -------------------------
if ( traceHit . fraction = = 1.0f )
{
nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER ;
// We want to test the first swing again
Vector testEnd = swingStart + forward * GetRange ( ) ;
// See if we happened to hit water
ImpactWater ( swingStart , testEnd ) ;
}
else
{
Hit ( traceHit , nHitActivity , bIsSecondary ? true : false ) ;
}
// Send the anim
SendWeaponAnim ( nHitActivity ) ;
//Setup our next attack times
m_flNextPrimaryAttack = gpGlobals - > curtime + GetFireRate ( ) ;
m_flNextSecondaryAttack = gpGlobals - > curtime + SequenceDuration ( ) ;
//Play swing sound
WeaponSound ( SINGLE ) ;
}