source-engine/game/server/hl2/weapon_annabelle.cpp

351 lines
9.2 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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;
}