diff options
Diffstat (limited to 'game/server/hl2/weapon_alyxgun.cpp')
| -rw-r--r-- | game/server/hl2/weapon_alyxgun.cpp | 326 |
1 files changed, 326 insertions, 0 deletions
diff --git a/game/server/hl2/weapon_alyxgun.cpp b/game/server/hl2/weapon_alyxgun.cpp new file mode 100644 index 0000000..270a503 --- /dev/null +++ b/game/server/hl2/weapon_alyxgun.cpp @@ -0,0 +1,326 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" + +#include "weapon_alyxgun.h" +#include "npcevent.h" +#include "ai_basenpc.h" +#include "globalstate.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +IMPLEMENT_SERVERCLASS_ST(CWeaponAlyxGun, DT_WeaponAlyxGun) +END_SEND_TABLE() + +LINK_ENTITY_TO_CLASS( weapon_alyxgun, CWeaponAlyxGun ); +PRECACHE_WEAPON_REGISTER(weapon_alyxgun); + +BEGIN_DATADESC( CWeaponAlyxGun ) +END_DATADESC() + +acttable_t CWeaponAlyxGun::m_acttable[] = +{ + { ACT_IDLE, ACT_IDLE_PISTOL, true }, + { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_PISTOL, true }, + { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, true }, + { ACT_RELOAD, ACT_RELOAD_PISTOL, true }, + { ACT_WALK_AIM, ACT_WALK_AIM_PISTOL, true }, + { ACT_RUN_AIM, ACT_RUN_AIM_PISTOL, true }, + { ACT_COVER_LOW, ACT_COVER_PISTOL_LOW, true }, + { ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_PISTOL_LOW, true }, + { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_PISTOL,true }, + { ACT_RELOAD_LOW, ACT_RELOAD_PISTOL_LOW, true }, + { ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_PISTOL_LOW, true }, + { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, true }, + + // Readiness activities (not aiming) + { ACT_IDLE_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false }, + { ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false }, + { ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false }, + + { ACT_RUN_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false }, + { ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false }, + + // Readiness activities (aiming) + { ACT_IDLE_AIM_RELAXED, ACT_IDLE_PISTOL, false },//never aims + { ACT_IDLE_AIM_STIMULATED, ACT_IDLE_ANGRY_PISTOL, false }, + { ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims + { ACT_IDLE_AIM_STEALTH, ACT_IDLE_STEALTH_PISTOL, false }, + + { ACT_WALK_AIM_RELAXED, ACT_WALK, false },//never aims + { ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_PISTOL, false }, + { ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims + { ACT_WALK_AIM_STEALTH, ACT_WALK_AIM_STEALTH_PISTOL, false },//always aims + + { ACT_RUN_AIM_RELAXED, ACT_RUN, false },//never aims + { ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_PISTOL, false }, + { ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims + { ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims + //End readiness activities + + // Crouch activities + { ACT_CROUCHIDLE_STIMULATED, ACT_CROUCHIDLE_STIMULATED, false }, + { ACT_CROUCHIDLE_AIM_STIMULATED,ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + { ACT_CROUCHIDLE_AGITATED, ACT_RANGE_AIM_PISTOL_LOW, false },//always aims + + // Readiness translations + { ACT_READINESS_RELAXED_TO_STIMULATED, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED, false }, + { ACT_READINESS_RELAXED_TO_STIMULATED_WALK, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, false }, + { ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false }, + { ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false }, + + +// { ACT_ARM, ACT_ARM_PISTOL, true }, +// { ACT_DISARM, ACT_DISARM_PISTOL, true }, +}; + +IMPLEMENT_ACTTABLE(CWeaponAlyxGun); + +#define TOOCLOSETIMER_OFF 0.0f +#define ALYX_TOOCLOSETIMER 1.0f // Time an enemy must be tooclose before Alyx is allowed to shoot it. + +//========================================================= +CWeaponAlyxGun::CWeaponAlyxGun( ) +{ + m_fMinRange1 = 1; + m_fMaxRange1 = 5000; + + m_flTooCloseTimer = TOOCLOSETIMER_OFF; + +#ifdef HL2_EPISODIC + m_fMinRange1 = 60; + m_fMaxRange1 = 2048; +#endif//HL2_EPISODIC +} + +CWeaponAlyxGun::~CWeaponAlyxGun( ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponAlyxGun::Precache( void ) +{ + BaseClass::Precache(); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CWeaponAlyxGun::Equip( CBaseCombatCharacter *pOwner ) +{ + BaseClass::Equip( pOwner ); +} + +//----------------------------------------------------------------------------- +// Purpose: Try to encourage Alyx not to use her weapon at point blank range, +// but don't prevent her from defending herself if cornered. +// Input : flDot - +// flDist - +// Output : int +//----------------------------------------------------------------------------- +int CWeaponAlyxGun::WeaponRangeAttack1Condition( float flDot, float flDist ) +{ +#ifdef HL2_EPISODIC + + if( flDist < m_fMinRange1 ) + { + // If Alyx is not able to fire because an enemy is too close, start a timer. + // If the condition persists, allow her to ignore it and defend herself. The idea + // is to stop Alyx being content to fire point blank at enemies if she's able to move + // away, without making her defenseless if she's not able to move. + float flTime; + + if( m_flTooCloseTimer == TOOCLOSETIMER_OFF ) + { + m_flTooCloseTimer = gpGlobals->curtime; + } + + flTime = gpGlobals->curtime - m_flTooCloseTimer; + + if( flTime > ALYX_TOOCLOSETIMER ) + { + // Fake the range to allow Alyx to shoot. + flDist = m_fMinRange1 + 1.0f; + } + } + else + { + m_flTooCloseTimer = TOOCLOSETIMER_OFF; + } + + int nBaseCondition = BaseClass::WeaponRangeAttack1Condition( flDot, flDist ); + + // While in a vehicle, we extend our aiming cone (this relies on COND_NOT_FACING_ATTACK + // TODO: This needs to be rolled in at the animation level + if ( GetOwner()->IsInAVehicle() ) + { + Vector vecRoughDirection = ( GetOwner()->GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter() ); + Vector vecRight; + GetVectors( NULL, &vecRight, NULL ); + bool bRightSide = ( DotProduct( vecRoughDirection, vecRight ) > 0.0f ); + float flTargetDot = ( bRightSide ) ? -0.7f : 0.0f; + + if ( nBaseCondition == COND_NOT_FACING_ATTACK && flDot >= flTargetDot ) + { + nBaseCondition = COND_CAN_RANGE_ATTACK1; + } + } + + return nBaseCondition; + +#else + + return BaseClass::WeaponRangeAttack1Condition( flDot, flDist ); + +#endif//HL2_EPISODIC +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flDot - +// flDist - +// Output : int +//----------------------------------------------------------------------------- +int CWeaponAlyxGun::WeaponRangeAttack2Condition( float flDot, float flDist ) +{ + return COND_NONE; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOperator - +//----------------------------------------------------------------------------- +void CWeaponAlyxGun::FireNPCPrimaryAttack( CBaseCombatCharacter *pOperator, bool bUseWeaponAngles ) +{ + Vector vecShootOrigin, vecShootDir; + CAI_BaseNPC *npc = pOperator->MyNPCPointer(); + ASSERT( npc != NULL ); + + if ( bUseWeaponAngles ) + { + QAngle angShootDir; + GetAttachment( LookupAttachment( "muzzle" ), vecShootOrigin, angShootDir ); + AngleVectors( angShootDir, &vecShootDir ); + } + else + { + vecShootOrigin = pOperator->Weapon_ShootPosition(); + vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin ); + } + + WeaponSound( SINGLE_NPC ); + + if( hl2_episodic.GetBool() ) + { + pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 1 ); + } + else + { + pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2 ); + } + + pOperator->DoMuzzleFlash(); + + if( hl2_episodic.GetBool() ) + { + // Never fire Alyx's last bullet just in case there's an emergency + // and she needs to be able to shoot without reloading. + if( m_iClip1 > 1 ) + { + m_iClip1 = m_iClip1 - 1; + } + } + else + { + m_iClip1 = m_iClip1 - 1; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWeaponAlyxGun::Operator_ForceNPCFire( CBaseCombatCharacter *pOperator, bool bSecondary ) +{ + // Ensure we have enough rounds in the clip + m_iClip1++; + + // HACK: We need the gun to fire its muzzle flash + if ( bSecondary == false ) + { + SetActivity( ACT_RANGE_ATTACK_PISTOL, 0.0f ); + } + + FireNPCPrimaryAttack( pOperator, true ); +} + +//----------------------------------------------------------------------------- +void CWeaponAlyxGun::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) +{ + switch( pEvent->event ) + { + case EVENT_WEAPON_PISTOL_FIRE: + { + FireNPCPrimaryAttack( pOperator, false ); + break; + } + + default: + BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Whether or not Alyx is in the injured mode +//----------------------------------------------------------------------------- +bool IsAlyxInInjuredMode( void ) +{ + if ( hl2_episodic.GetBool() == false ) + return false; + + return ( GlobalEntity_GetState("ep2_alyx_injured") == GLOBAL_ON ); +} + +//----------------------------------------------------------------------------- +const Vector& CWeaponAlyxGun::GetBulletSpread( void ) +{ + static const Vector cone = VECTOR_CONE_2DEGREES; + static const Vector injuredCone = VECTOR_CONE_6DEGREES; + + if ( IsAlyxInInjuredMode() ) + return injuredCone; + + return cone; +} + +//----------------------------------------------------------------------------- +float CWeaponAlyxGun::GetMinRestTime( void ) +{ + if ( IsAlyxInInjuredMode() ) + return 1.5f; + + return BaseClass::GetMinRestTime(); +} + +//----------------------------------------------------------------------------- +float CWeaponAlyxGun::GetMaxRestTime( void ) +{ + if ( IsAlyxInInjuredMode() ) + return 3.0f; + + return BaseClass::GetMaxRestTime(); +} |