|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Crowbar - an old favorite
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "hl1mp_basecombatweapon_shared.h"
#ifdef CLIENT_DLL
#include "c_baseplayer.h"
#include "fx_impact.h"
#include "fx.h"
#else
#include "player.h"
#include "soundent.h"
#endif
#include "gamerules.h"
#include "ammodef.h"
#include "mathlib/mathlib.h"
#include "in_buttons.h"
#include "vstdlib/random.h"
extern ConVar sk_plr_dmg_crowbar;
#define CROWBAR_RANGE 64.0f
#define CROWBAR_REFIRE_MISS 0.5f
#define CROWBAR_REFIRE_HIT 0.25f
#ifdef CLIENT_DLL
#define CWeaponCrowbar C_WeaponCrowbar
#endif
//-----------------------------------------------------------------------------
// CWeaponCrowbar
//-----------------------------------------------------------------------------
class CWeaponCrowbar : public CBaseHL1MPCombatWeapon { DECLARE_CLASS( CWeaponCrowbar, CBaseHL1MPCombatWeapon ); public: DECLARE_NETWORKCLASS(); DECLARE_PREDICTABLE(); #ifndef CLIENT_DLL
DECLARE_DATADESC(); #endif
CWeaponCrowbar();
void Precache( void ); virtual void ItemPostFrame( void ); void PrimaryAttack( void );
public: trace_t m_traceHit; Activity m_nHitActivity;
private: virtual void Swing( void ); virtual void Hit( void ); virtual void ImpactEffect( void ); void ImpactSound( CBaseEntity *pHitEntity ); virtual Activity ChooseIntersectionPointAndActivity( trace_t &hitTrace, const Vector &mins, const Vector &maxs, CBasePlayer *pOwner );
public:
};
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCrowbar, DT_WeaponCrowbar );
BEGIN_NETWORK_TABLE( CWeaponCrowbar, DT_WeaponCrowbar ) /// what
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CWeaponCrowbar ) END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( weapon_crowbar, CWeaponCrowbar ); PRECACHE_WEAPON_REGISTER( weapon_crowbar );
#ifndef CLIENT_DLL
BEGIN_DATADESC( CWeaponCrowbar )
// DEFINE_FIELD( m_trLineHit, trace_t ),
// DEFINE_FIELD( m_trHullHit, trace_t ),
// DEFINE_FIELD( m_nHitActivity, FIELD_INTEGER ),
// DEFINE_FIELD( m_traceHit, trace_t ),
// Class CWeaponCrowbar:
// DEFINE_FIELD( m_nHitActivity, FIELD_INTEGER ),
// Function Pointers
DEFINE_FUNCTION( Hit ),
END_DATADESC() #endif
#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
//-----------------------------------------------------------------------------
CWeaponCrowbar::CWeaponCrowbar() { m_bFiresUnderwater = true; }
//-----------------------------------------------------------------------------
// Purpose: Precache the weapon
//-----------------------------------------------------------------------------
void CWeaponCrowbar::Precache( void ) { //Call base class first
BaseClass::Precache(); }
//------------------------------------------------------------------------------
// Purpose : Update weapon
//------------------------------------------------------------------------------
void CWeaponCrowbar::ItemPostFrame( void ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( pOwner == NULL ) return;
if ( (pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) ) { PrimaryAttack(); } else { WeaponIdle(); return; } }
//------------------------------------------------------------------------------
// Purpose :
// Input :
// Output :
//------------------------------------------------------------------------------
void CWeaponCrowbar::PrimaryAttack() { Swing(); }
//------------------------------------------------------------------------------
// Purpose: Implement impact function
//------------------------------------------------------------------------------
void CWeaponCrowbar::Hit( void ) { //Make sound for the AI
#ifndef CLIENT_DLL
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, m_traceHit.endpos, 400, 0.2f, pPlayer );
CBaseEntity *pHitEntity = m_traceHit.m_pEnt;
//Apply damage to a hit target
if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection );
ClearMultiDamage(); CTakeDamageInfo info( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB ); CalculateMeleeDamageForce( &info, hitDirection, m_traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &m_traceHit ); ApplyMultiDamage();
// Now hit all triggers along the ray that...
TraceAttackToTriggers( CTakeDamageInfo( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB ), m_traceHit.startpos, m_traceHit.endpos, hitDirection );
//Play an impact sound
ImpactSound( pHitEntity ); } #endif
//Apply an impact effect
ImpactEffect(); }
//-----------------------------------------------------------------------------
// Purpose: Play the impact sound
// Input : pHitEntity - entity that we hit
// assumes pHitEntity is not null
//-----------------------------------------------------------------------------
void CWeaponCrowbar::ImpactSound( CBaseEntity *pHitEntity ) { bool bIsWorld = ( pHitEntity->entindex() == 0 ); #ifndef CLIENT_DLL
if ( !bIsWorld ) { bIsWorld |= pHitEntity->Classify() == CLASS_NONE || pHitEntity->Classify() == CLASS_MACHINE; } #endif
if( bIsWorld ) { WeaponSound( MELEE_HIT_WORLD ); } else { WeaponSound( MELEE_HIT ); } }
Activity CWeaponCrowbar::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; }
#ifdef HL1MP_CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: Handle jeep impacts
//-----------------------------------------------------------------------------
void ImpactCrowbarCallback( const CEffectData &data ) { trace_t tr; Vector vecOrigin, vecStart, vecShotDir; int iMaterial, iDamageType, iHitbox; short nSurfaceProp; C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox );
bool bIsWorld = ( pEntity->entindex() == 0 );
if ( !pEntity ) { // This happens for impacts that occur on an object that's then destroyed.
// Clear out the fraction so it uses the server's data
tr.fraction = 1.0; GetActiveWeapon()->WeaponSound( bIsWorld ? MELEE_HIT_WORLD : MELEE_HIT ); return; }
// If we hit, perform our custom effects and play the sound
if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) { // Check for custom effects based on the Decal index
PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 2 ); }
GetActiveWeapon()->WeaponSound( bIsWorld ? MELEE_HIT_WORLD : MELEE_HIT ); }
DECLARE_CLIENT_EFFECT( "ImpactCrowbar", ImpactCrowbarCallback );
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponCrowbar::ImpactEffect( void ) { //FIXME: need new decals
#ifdef HL1MP_CLIENT_DLL
// in hl1mp force the basic crowbar sound
UTIL_ImpactTrace( &m_traceHit, DMG_CLUB, "ImpactCrowbar" ); #else
UTIL_ImpactTrace( &m_traceHit, DMG_CLUB ); #endif
}
//------------------------------------------------------------------------------
// Purpose : Starts the swing of the weapon and determines the animation
//------------------------------------------------------------------------------
void CWeaponCrowbar::Swing( void ) { // Try a ray
CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return;
Vector swingStart = pOwner->Weapon_ShootPosition( ); Vector forward;
pOwner->EyeVectors( &forward, NULL, NULL );
Vector swingEnd = swingStart + forward * CROWBAR_RANGE;
UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &m_traceHit ); m_nHitActivity = ACT_VM_HITCENTER;
if ( m_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, &m_traceHit ); if ( m_traceHit.fraction < 1.0 ) { m_nHitActivity = ChooseIntersectionPointAndActivity( m_traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner ); } }
// -------------------------
// Miss
// -------------------------
if ( m_traceHit.fraction == 1.0f ) { m_nHitActivity = ACT_VM_MISSCENTER;
//Play swing sound
WeaponSound( SINGLE );
//Setup our next attack times
m_flNextPrimaryAttack = gpGlobals->curtime + CROWBAR_REFIRE_MISS; } else { Hit();
//Setup our next attack times
m_flNextPrimaryAttack = gpGlobals->curtime + CROWBAR_REFIRE_HIT; }
//Send the anim
SendWeaponAnim( m_nHitActivity ); pOwner->SetAnimation( PLAYER_ATTACK1 ); }
|