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

444 lines
12 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basehlcombatweapon.h"
#include "engine/IEngineSound.h"
#include "npcevent.h"
#include "in_buttons.h"
#include "antlion_maker.h"
#include "grenade_bugbait.h"
#include "gamestats.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//
// Bug Bait Weapon
//
class CWeaponBugBait : public CBaseHLCombatWeapon
{
DECLARE_CLASS( CWeaponBugBait, CBaseHLCombatWeapon );
public:
DECLARE_SERVERCLASS();
CWeaponBugBait( void );
void Spawn( void );
void FallInit( void );
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
void Drop( const Vector &vecVelocity );
void BugbaitStickyTouch( CBaseEntity *pOther );
void OnPickedUp( CBaseCombatCharacter *pNewOwner );
bool Deploy( void );
bool Holster( CBaseCombatWeapon *pSwitchingTo );
void ItemPostFrame( void );
void Precache( void );
void PrimaryAttack( void );
void SecondaryAttack( void );
void ThrowGrenade( CBasePlayer *pPlayer );
bool HasAnyAmmo( void ) { return true; }
bool Reload( void );
void SetSporeEmitterState( bool state = true );
bool ShouldDisplayHUDHint() { return true; }
DECLARE_DATADESC();
protected:
bool m_bDrawBackFinished;
bool m_bRedraw;
bool m_bEmitSpores;
EHANDLE m_hSporeTrail;
};
IMPLEMENT_SERVERCLASS_ST(CWeaponBugBait, DT_WeaponBugBait)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( weapon_bugbait, CWeaponBugBait );
#ifndef HL2MP
PRECACHE_WEAPON_REGISTER( weapon_bugbait );
#endif
BEGIN_DATADESC( CWeaponBugBait )
DEFINE_FIELD( m_hSporeTrail, FIELD_EHANDLE ),
DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bEmitSpores, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bDrawBackFinished, FIELD_BOOLEAN ),
DEFINE_FUNCTION( BugbaitStickyTouch ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CWeaponBugBait::CWeaponBugBait( void )
{
m_bDrawBackFinished = false;
m_bRedraw = false;
m_hSporeTrail = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::Spawn( void )
{
BaseClass::Spawn();
// Increase the bugbait's pickup volume. It spawns inside the antlion guard's body,
// and playtesters seem to be wary about moving into the body.
SetSize( Vector( -4, -4, -4), Vector(4, 4, 4) );
CollisionProp()->UseTriggerBounds( true, 100 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::FallInit( void )
{
// Bugbait shouldn't be physics, because it musn't roll/move away from it's spawnpoint.
// The game will break if the player can't pick it up, so it must stay still.
SetModel( GetWorldModel() );
VPhysicsDestroyObject();
SetMoveType( MOVETYPE_FLYGRAVITY );
SetSolid( SOLID_BBOX );
AddSolidFlags( FSOLID_TRIGGER );
SetPickupTouch();
SetThink( &CBaseCombatWeapon::FallThink );
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::Precache( void )
{
BaseClass::Precache();
UTIL_PrecacheOther( "npc_grenade_bugbait" );
PrecacheScriptSound( "Weapon_Bugbait.Splat" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::Drop( const Vector &vecVelocity )
{
BaseClass::Drop( vecVelocity );
// On touch, stick & stop moving. Increase our thinktime a bit so we don't stomp the touch for a bit
SetNextThink( gpGlobals->curtime + 3.0 );
SetTouch( &CWeaponBugBait::BugbaitStickyTouch );
m_hSporeTrail = SporeExplosion::CreateSporeExplosion();
if ( m_hSporeTrail )
{
SporeExplosion *pSporeExplosion = (SporeExplosion *)m_hSporeTrail.Get();
QAngle angles;
VectorAngles( Vector(0,0,1), angles );
pSporeExplosion->SetAbsAngles( angles );
pSporeExplosion->SetAbsOrigin( GetAbsOrigin() );
pSporeExplosion->SetParent( this );
pSporeExplosion->m_flSpawnRate = 16.0f;
pSporeExplosion->m_flParticleLifetime = 0.5f;
pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f, 0.15f );
pSporeExplosion->m_flStartSize = 32;
pSporeExplosion->m_flEndSize = 48;
pSporeExplosion->m_flSpawnRadius = 4;
pSporeExplosion->SetLifetime( 9999 );
}
}
//-----------------------------------------------------------------------------
// Purpose: Stick to the world when we touch it
//-----------------------------------------------------------------------------
void CWeaponBugBait::BugbaitStickyTouch( CBaseEntity *pOther )
{
if ( !pOther->IsWorld() )
return;
// Stop moving, wait for pickup
SetMoveType( MOVETYPE_NONE );
SetThink( NULL );
SetPickupTouch();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPicker -
//-----------------------------------------------------------------------------
void CWeaponBugBait::OnPickedUp( CBaseCombatCharacter *pNewOwner )
{
BaseClass::OnPickedUp( pNewOwner );
if ( m_hSporeTrail )
{
UTIL_Remove( m_hSporeTrail );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::PrimaryAttack( void )
{
if ( m_bRedraw )
return;
CBaseCombatCharacter *pOwner = GetOwner();
if ( pOwner == NULL )
return;
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( pPlayer == NULL )
return;
SendWeaponAnim( ACT_VM_HAULBACK );
m_flTimeWeaponIdle = FLT_MAX;
m_flNextPrimaryAttack = FLT_MAX;
m_iPrimaryAttacks++;
gamestats->Event_WeaponFired( pPlayer, true, GetClassname() );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::SecondaryAttack( void )
{
// Squeeze!
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "Weapon_Bugbait.Splat" );
if ( CGrenadeBugBait::ActivateBugbaitTargets( GetOwner(), GetAbsOrigin(), true ) == false )
{
g_AntlionMakerManager.BroadcastFollowGoal( GetOwner() );
}
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner )
{
m_iSecondaryAttacks++;
gamestats->Event_WeaponFired( pOwner, false, GetClassname() );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pPlayer -
//-----------------------------------------------------------------------------
void CWeaponBugBait::ThrowGrenade( CBasePlayer *pPlayer )
{
Vector vForward, vRight, vUp, vThrowPos, vThrowVel;
pPlayer->EyeVectors( &vForward, &vRight, &vUp );
vThrowPos = pPlayer->EyePosition();
vThrowPos += vForward * 18.0f;
vThrowPos += vRight * 12.0f;
pPlayer->GetVelocity( &vThrowVel, NULL );
vThrowVel += vForward * 1000;
CGrenadeBugBait *pGrenade = BugBaitGrenade_Create( vThrowPos, vec3_angle, vThrowVel, QAngle(600,random->RandomInt(-1200,1200),0), pPlayer );
if ( pGrenade != NULL )
{
// If the shot is clear to the player, give the missile a grace period
trace_t tr;
UTIL_TraceLine( pPlayer->EyePosition(), pPlayer->EyePosition() + ( vForward * 128 ), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction == 1.0 )
{
pGrenade->SetGracePeriod( 0.1f );
}
}
m_bRedraw = true;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pEvent -
// *pOperator -
//-----------------------------------------------------------------------------
void CWeaponBugBait::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
switch( pEvent->event )
{
case EVENT_WEAPON_SEQUENCE_FINISHED:
m_bDrawBackFinished = true;
break;
case EVENT_WEAPON_THROW:
ThrowGrenade( pOwner );
break;
default:
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CWeaponBugBait::Reload( void )
{
if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) )
{
//Redraw the weapon
SendWeaponAnim( ACT_VM_DRAW );
//Update our times
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
//Mark this as done
m_bRedraw = false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponBugBait::ItemPostFrame( void )
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
// See if we're cocked and ready to throw
if ( m_bDrawBackFinished )
{
if ( ( pOwner->m_nButtons & IN_ATTACK ) == false )
{
SendWeaponAnim( ACT_VM_THROW );
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
m_bDrawBackFinished = false;
}
}
else
{
//See if we're attacking
if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) )
{
PrimaryAttack();
}
else if ( ( pOwner->m_nButtons & IN_ATTACK2 ) && ( m_flNextSecondaryAttack < gpGlobals->curtime ) )
{
SecondaryAttack();
}
}
if ( m_bRedraw )
{
if ( IsViewModelSequenceFinished() )
{
Reload();
}
}
WeaponIdle();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponBugBait::Deploy( void )
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return false;
/*
if ( m_hSporeTrail == NULL )
{
m_hSporeTrail = SporeTrail::CreateSporeTrail();
m_hSporeTrail->m_bEmit = true;
m_hSporeTrail->m_flSpawnRate = 100.0f;
m_hSporeTrail->m_flParticleLifetime = 2.0f;
m_hSporeTrail->m_flStartSize = 1.0f;
m_hSporeTrail->m_flEndSize = 4.0f;
m_hSporeTrail->m_flSpawnRadius = 8.0f;
m_hSporeTrail->m_vecEndColor = Vector( 0, 0, 0 );
CBaseViewModel *vm = pOwner->GetViewModel();
if ( vm != NULL )
{
m_hSporeTrail->FollowEntity( vm );
}
}
*/
m_bRedraw = false;
m_bDrawBackFinished = false;
return BaseClass::Deploy();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CWeaponBugBait::Holster( CBaseCombatWeapon *pSwitchingTo )
{
m_bRedraw = false;
m_bDrawBackFinished = false;
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : true -
//-----------------------------------------------------------------------------
void CWeaponBugBait::SetSporeEmitterState( bool state )
{
m_bEmitSpores = state;
}