|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Grigori's personal shotgun (npc_monk)
//
//=============================================================================//
#include "cbase.h"
#include "npcevent.h"
#include "basehlcombatweapon_shared.h"
#include "basecombatcharacter.h"
#include "ai_basenpc.h"
#include "player.h"
#include "gamerules.h" // For g_pGameRules
#include "in_buttons.h"
#include "soundent.h"
#include "vstdlib/random.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
extern ConVar sk_auto_reload_time;
class CWeaponAnnabelle : public CBaseHLCombatWeapon { DECLARE_DATADESC(); public: DECLARE_CLASS( CWeaponAnnabelle, CBaseHLCombatWeapon );
DECLARE_SERVERCLASS();
private: bool m_bNeedPump; // When emptied completely
bool m_bDelayedFire1; // Fire primary when finished reloading
bool m_bDelayedFire2; // Fire secondary when finished reloading
public: void Precache( void );
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
virtual const Vector& GetBulletSpread( void ) { static Vector cone = vec3_origin; return cone; }
virtual int GetMinBurst() { return 1; } virtual int GetMaxBurst() { return 3; }
void ItemHolsterFrame( void ); bool StartReload( void ); bool Reload( void ); void FillClip( void ); void FinishReload( void ); void CheckHolsterReload( void ); void Pump( void ); void DryFire( void ); virtual float GetFireRate( void ) { return 1.5; }; virtual float GetMinRestTime() { return 1.0; } virtual float GetMaxRestTime() { return 1.5; }
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
DECLARE_ACTTABLE();
CWeaponAnnabelle(void); };
IMPLEMENT_SERVERCLASS_ST(CWeaponAnnabelle, DT_WeaponAnnabelle) END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( weapon_annabelle, CWeaponAnnabelle ); #ifndef HL2MP
PRECACHE_WEAPON_REGISTER(weapon_annabelle); #endif
BEGIN_DATADESC( CWeaponAnnabelle ) DEFINE_FIELD( m_bNeedPump, FIELD_BOOLEAN ), DEFINE_FIELD( m_bDelayedFire1, FIELD_BOOLEAN ), DEFINE_FIELD( m_bDelayedFire2, FIELD_BOOLEAN ), END_DATADESC()
acttable_t CWeaponAnnabelle::m_acttable[] = { { ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_SMG1, true }, { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SHOTGUN, true }, { ACT_RELOAD, ACT_RELOAD_SMG1, true }, { ACT_WALK, ACT_WALK_RIFLE, true }, { ACT_WALK_AIM, ACT_WALK_AIM_RIFLE, true }, { ACT_WALK_CROUCH, ACT_WALK_CROUCH_RIFLE, false }, { ACT_WALK_CROUCH_AIM, ACT_WALK_CROUCH_AIM_RIFLE, false }, { ACT_RUN, ACT_RUN_RIFLE, true }, { ACT_RUN_AIM, ACT_RUN_AIM_RIFLE, true }, { ACT_RUN_CROUCH, ACT_RUN_CROUCH_RIFLE, false }, { ACT_RUN_CROUCH_AIM, ACT_RUN_CROUCH_AIM_RIFLE, false }, { ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_SHOTGUN, true }, { ACT_RELOAD_LOW, ACT_RELOAD_SMG1_LOW, false }, { ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, };
IMPLEMENT_ACTTABLE(CWeaponAnnabelle);
void CWeaponAnnabelle::Precache( void ) { CBaseCombatWeapon::Precache(); }
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_SHOTGUN_FIRE: { Vector vecShootOrigin, vecShootDir; vecShootOrigin = pOperator->Weapon_ShootPosition(); CAI_BaseNPC *npc = pOperator->MyNPCPointer(); ASSERT( npc != NULL ); WeaponSound( SINGLE_NPC ); pOperator->DoMuzzleFlash(); m_iClip1 = m_iClip1 - 1;
vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin ); pOperator->FireBullets( 1, vecShootOrigin, vecShootDir, VECTOR_CONE_PRECALCULATED, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0 ); } break;
default: CBaseCombatWeapon::Operator_HandleAnimEvent( pEvent, pOperator ); break; } }
//-----------------------------------------------------------------------------
// Purpose: Override so only reload one shell at a time
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CWeaponAnnabelle::StartReload( void ) { CBaseCombatCharacter *pOwner = GetOwner(); if ( pOwner == NULL ) return false;
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0) return false;
if (m_iClip1 >= GetMaxClip1()) return false;
// If shotgun totally emptied then a pump animation is needed
if (m_iClip1 <= 0) { m_bNeedPump = true; }
int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
if (j <= 0) return false;
SendWeaponAnim( ACT_SHOTGUN_RELOAD_START );
// Make shotgun shell visible
SetBodygroup(1,0);
pOwner->m_flNextAttack = gpGlobals->curtime; m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
m_bInReload = true; return true; }
//-----------------------------------------------------------------------------
// Purpose: Override so only reload one shell at a time
// Input :
// Output :
//-----------------------------------------------------------------------------
bool CWeaponAnnabelle::Reload( void ) { // Check that StartReload was called first
if (!m_bInReload) { Warning("ERROR: Shotgun Reload called incorrectly!\n"); }
CBaseCombatCharacter *pOwner = GetOwner(); if ( pOwner == NULL ) return false;
if (pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0) return false;
if (m_iClip1 >= GetMaxClip1()) return false;
int j = MIN(1, pOwner->GetAmmoCount(m_iPrimaryAmmoType));
if (j <= 0) return false;
FillClip(); // Play reload on different channel as otherwise steals channel away from fire sound
WeaponSound(RELOAD); SendWeaponAnim( ACT_VM_RELOAD );
pOwner->m_flNextAttack = gpGlobals->curtime; m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
return true; }
//-----------------------------------------------------------------------------
// Purpose: Play finish reload anim and fill clip
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::FinishReload( void ) { // Make shotgun shell invisible
SetBodygroup(1,1);
CBaseCombatCharacter *pOwner = GetOwner(); if ( pOwner == NULL ) return;
m_bInReload = false;
// Finish reload animation
SendWeaponAnim( ACT_SHOTGUN_RELOAD_FINISH );
pOwner->m_flNextAttack = gpGlobals->curtime; m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); }
//-----------------------------------------------------------------------------
// Purpose: Play finish reload anim and fill clip
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::FillClip( void ) { CBaseCombatCharacter *pOwner = GetOwner(); if ( pOwner == NULL ) return;
// Add them to the clip
if ( pOwner->GetAmmoCount( m_iPrimaryAmmoType ) > 0 ) { if ( Clip1() < GetMaxClip1() ) { m_iClip1++; pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType ); } } }
//-----------------------------------------------------------------------------
// Purpose: Play weapon pump anim
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::Pump( void ) { CBaseCombatCharacter *pOwner = GetOwner();
if ( pOwner == NULL ) return; m_bNeedPump = false; WeaponSound( SPECIAL1 );
// Finish reload animation
SendWeaponAnim( ACT_SHOTGUN_PUMP );
pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration(); m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); }
//-----------------------------------------------------------------------------
// Purpose:
//
//
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::DryFire( void ) { WeaponSound(EMPTY); SendWeaponAnim( ACT_VM_DRYFIRE ); m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponAnnabelle::ItemHolsterFrame( void ) { // Must be player held
if ( GetOwner() && GetOwner()->IsPlayer() == false ) return;
// We can't be active
if ( GetOwner()->GetActiveWeapon() == this ) return;
// If it's been longer than three seconds, reload
if ( ( gpGlobals->curtime - m_flHolsterTime ) > sk_auto_reload_time.GetFloat() ) { // Reset the timer
m_flHolsterTime = gpGlobals->curtime; if ( GetOwner() == NULL ) return;
if ( m_iClip1 == GetMaxClip1() ) return;
// Just load the clip with no animations
int ammoFill = MIN( (GetMaxClip1() - m_iClip1), GetOwner()->GetAmmoCount( GetPrimaryAmmoType() ) ); GetOwner()->RemoveAmmo( ammoFill, GetPrimaryAmmoType() ); m_iClip1 += ammoFill; } }
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponAnnabelle::CWeaponAnnabelle( void ) { m_bReloadsSingly = true;
m_bNeedPump = false; m_bDelayedFire1 = false; m_bDelayedFire2 = false;
m_fMinRange1 = 0.0; m_fMaxRange1 = 500; m_fMinRange2 = 0.0; m_fMaxRange2 = 200; }
|