mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-23 22:56:50 +00:00
351 lines
9.2 KiB
C++
351 lines
9.2 KiB
C++
|
//========= 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;
|
||
|
}
|