You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
10 KiB
384 lines
10 KiB
//========= Copyright 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" |
|
#include "gamestats.h" |
|
|
|
// 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 = 1e6f; |
|
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 ); |
|
}
|
|
|