//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Crowbar - an old favorite // // $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 "basebludgeonweapon.h" #include "vstdlib/random.h" #include "npcevent.h" #include "ai_basenpc.h" #include "weapon_crowbar.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" ConVar sk_plr_dmg_crowbar ( "sk_plr_dmg_crowbar","0"); ConVar sk_npc_dmg_crowbar ( "sk_npc_dmg_crowbar","0"); //----------------------------------------------------------------------------- // CWeaponCrowbar //----------------------------------------------------------------------------- IMPLEMENT_SERVERCLASS_ST(CWeaponCrowbar, DT_WeaponCrowbar) END_SEND_TABLE() #ifndef HL2MP LINK_ENTITY_TO_CLASS( weapon_crowbar, CWeaponCrowbar ); PRECACHE_WEAPON_REGISTER( weapon_crowbar ); #endif acttable_t CWeaponCrowbar::m_acttable[] = { { ACT_MELEE_ATTACK1, ACT_MELEE_ATTACK_SWING, true }, { ACT_IDLE, ACT_IDLE_ANGRY_MELEE, false }, { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_MELEE, false }, }; IMPLEMENT_ACTTABLE(CWeaponCrowbar); //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CWeaponCrowbar::CWeaponCrowbar( void ) { } //----------------------------------------------------------------------------- // Purpose: Get the damage amount for the animation we're doing // Input : hitActivity - currently played activity // Output : Damage amount //----------------------------------------------------------------------------- float CWeaponCrowbar::GetDamageForActivity( Activity hitActivity ) { if ( ( GetOwner() != NULL ) && ( GetOwner()->IsPlayer() ) ) return sk_plr_dmg_crowbar.GetFloat(); return sk_npc_dmg_crowbar.GetFloat(); } //----------------------------------------------------------------------------- // Purpose: Add in a view kick for this weapon //----------------------------------------------------------------------------- void CWeaponCrowbar::AddViewKick( void ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); if ( pPlayer == NULL ) return; QAngle punchAng; punchAng.x = random->RandomFloat( 1.0f, 2.0f ); punchAng.y = random->RandomFloat( -2.0f, -1.0f ); punchAng.z = 0.0f; pPlayer->ViewPunch( punchAng ); } //----------------------------------------------------------------------------- // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) //----------------------------------------------------------------------------- ConVar sk_crowbar_lead_time( "sk_crowbar_lead_time", "0.9" ); int CWeaponCrowbar::WeaponMeleeAttack1Condition( float flDot, float flDist ) { // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecVelocity; vecVelocity = pEnemy->GetSmoothedVelocity( ); // Project where the enemy will be in a little while float dt = sk_crowbar_lead_time.GetFloat(); dt += random->RandomFloat( -0.3f, 0.2f ); if ( dt < 0.0f ) dt = 0.0f; Vector vecExtrapolatedPos; VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos ); Vector vecDelta; VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta ); if ( fabs( vecDelta.z ) > 70 ) { return COND_TOO_FAR_TO_ATTACK; } Vector vecForward = pNPC->BodyDirection2D( ); vecDelta.z = 0.0f; float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() ); if ((flDist > 64) && (flExtrapolatedDist > 64)) { return COND_TOO_FAR_TO_ATTACK; } float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() ); if ((flDot < 0.7) && (flExtrapolatedDot < 0.7)) { return COND_NOT_FACING_ATTACK; } return COND_CAN_MELEE_ATTACK1; } //----------------------------------------------------------------------------- // Animation event handlers //----------------------------------------------------------------------------- void CWeaponCrowbar::HandleAnimEventMeleeHit( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { // Trace up or down based on where the enemy is... // But only if we're basically facing that direction Vector vecDirection; AngleVectors( GetAbsAngles(), &vecDirection ); CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL; if ( pEnemy ) { Vector vecDelta; VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta ); VectorNormalize( vecDelta ); Vector2D vecDelta2D = vecDelta.AsVector2D(); Vector2DNormalize( vecDelta2D ); if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f ) { vecDirection = vecDelta; } } Vector vecEnd; VectorMA( pOperator->Weapon_ShootPosition(), 50, vecDirection, vecEnd ); CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd, Vector(-16,-16,-16), Vector(36,36,36), sk_npc_dmg_crowbar.GetFloat(), DMG_CLUB, 0.75 ); // did I hit someone? if ( pHurt ) { // play sound WeaponSound( MELEE_HIT ); // Fake a trace impact, so the effects work out like a player's crowbaw trace_t traceHit; UTIL_TraceLine( pOperator->Weapon_ShootPosition(), pHurt->GetAbsOrigin(), MASK_SHOT_HULL, pOperator, COLLISION_GROUP_NONE, &traceHit ); ImpactEffect( traceHit ); } else { WeaponSound( MELEE_MISS ); } } //----------------------------------------------------------------------------- // Animation event //----------------------------------------------------------------------------- void CWeaponCrowbar::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_MELEE_HIT: HandleAnimEventMeleeHit( pEvent, pOperator ); break; default: BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); break; } }