Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

326 lines
9.3 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Bugbait weapon to summon and direct antlions
//
//=============================================================================//
#include "cbase.h"
#include "grenade_bugbait.h"
#include "decals.h"
#include "smoke_trail.h"
#include "soundent.h"
#include "engine/IEngineSound.h"
#include "npc_bullseye.h"
#include "entitylist.h"
#include "antlion_maker.h"
#include "eventqueue.h"
#ifdef PORTAL
#include "portal_util_shared.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
// Setup the sensor list template
CEntityClassList<CBugBaitSensor> g_BugBaitSensorList;
template <> CBugBaitSensor *CEntityClassList<CBugBaitSensor>::m_pClassList = NULL;
CBugBaitSensor* GetBugBaitSensorList()
{
return g_BugBaitSensorList.m_pClassList;
}
CBugBaitSensor::CBugBaitSensor( void )
{
g_BugBaitSensorList.Insert( this );
}
CBugBaitSensor::~CBugBaitSensor( void )
{
g_BugBaitSensorList.Remove( this );
}
BEGIN_DATADESC( CBugBaitSensor )
// This is re-set up in the constructor
//DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ),
DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "Enabled" ),
DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
// Function Pointers
DEFINE_OUTPUT( m_OnBaited, "OnBaited" ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( point_bugbait, CBugBaitSensor );
//=============================================================================
// Bugbait grenade
//=============================================================================
#define GRENADE_MODEL "models/weapons/w_bugbait.mdl"
BEGIN_DATADESC( CGrenadeBugBait )
DEFINE_FIELD( m_flGracePeriodEndsAt, FIELD_TIME ),
DEFINE_FIELD( m_pSporeTrail, FIELD_CLASSPTR ),
// Function Pointers
DEFINE_ENTITYFUNC( BugBaitTouch ),
DEFINE_THINKFUNC( ThinkBecomeSolid ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( npc_grenade_bugbait, CGrenadeBugBait );
//Radius of the bugbait's effect on other creatures
ConVar bugbait_radius( "bugbait_radius", "512" );
ConVar bugbait_hear_radius( "bugbait_hear_radius", "2500" );
ConVar bugbait_distract_time( "bugbait_distract_time", "5" );
ConVar bugbait_grenade_radius( "bugbait_grenade_radius", "150" );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeBugBait::Spawn( void )
{
Precache();
SetModel( GRENADE_MODEL );
SetCollisionGroup( COLLISION_GROUP_PROJECTILE );
SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_DEFAULT );
SetSolid( SOLID_BBOX );
UTIL_SetSize( this, Vector( -2, -2, -2), Vector( 2, 2, 2 ) );
SetTouch( &CGrenadeBugBait::BugBaitTouch );
m_takedamage = DAMAGE_NO;
m_pSporeTrail = NULL;
/*
m_pSporeTrail = SporeTrail::CreateSporeTrail();
m_pSporeTrail->m_bEmit = true;
m_pSporeTrail->m_flSpawnRate = 100.0f;
m_pSporeTrail->m_flParticleLifetime = 1.0f;
m_pSporeTrail->m_flStartSize = 1.0f;
m_pSporeTrail->m_flEndSize = 1.0f;
m_pSporeTrail->m_flSpawnRadius = 8.0f;
m_pSporeTrail->m_vecEndColor = Vector( 0, 0, 0 );
*/
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeBugBait::Precache( void )
{
PrecacheModel( GRENADE_MODEL );
PrecacheScriptSound( "GrenadeBugBait.Splat" );
BaseClass::Precache();
}
#define NUM_SPLASHES 6
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeBugBait::BugBaitTouch( CBaseEntity *pOther )
{
// Don't hit triggers or water
Assert( pOther );
if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER|FSOLID_VOLUME_CONTENTS) )
return;
if ( m_pSporeTrail != NULL )
{
m_pSporeTrail->m_bEmit = false;
}
//Do effect for the hit
SporeExplosion *pSporeExplosion = SporeExplosion::CreateSporeExplosion();
if ( pSporeExplosion )
{
Vector dir = -GetAbsVelocity();
VectorNormalize( dir );
QAngle angles;
VectorAngles( dir, angles );
pSporeExplosion->SetLocalAngles( angles );
pSporeExplosion->SetLocalOrigin( GetAbsOrigin() );
pSporeExplosion->m_flSpawnRate = 8.0f;
pSporeExplosion->m_flParticleLifetime = 2.0f;
pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f, 0.15f );
pSporeExplosion->m_flStartSize = 32.0f;
pSporeExplosion->m_flEndSize = 64.0f;
pSporeExplosion->m_flSpawnRadius = 32.0f;
pSporeExplosion->SetLifetime( bugbait_distract_time.GetFloat() );
}
trace_t tr;
Vector traceDir = GetAbsVelocity();
VectorNormalize( traceDir );
UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + traceDir * 64, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
if ( tr.fraction < 1.0f )
{
UTIL_DecalTrace( &tr, "BeerSplash" ); //TODO: Use real decal
}
//Make a splat sound
CPASAttenuationFilter filter( this );
EmitSound( filter, entindex(), "GrenadeBugBait.Splat" );
//Make sure we want to call antlions
if ( ActivateBugbaitTargets( GetThrower(), GetAbsOrigin(), false ) == false )
{
//Alert any antlions around
CSoundEnt::InsertSound( SOUND_BUGBAIT, GetAbsOrigin(), bugbait_hear_radius.GetInt(), bugbait_distract_time.GetFloat(), GetThrower() );
}
// Tell all spawners to now fight to this position
g_AntlionMakerManager.BroadcastFightGoal( GetAbsOrigin() );
//Go away
UTIL_Remove( this );
}
//-----------------------------------------------------------------------------
// Purpose: Activate any nearby bugbait targets
// Returns true if the bugbait target wants to suppress the call.
//-----------------------------------------------------------------------------
bool CGrenadeBugBait::ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOrigin, bool bSqueezed )
{
//Attempt to activate any spawners in a radius around the bugbait
CBaseEntity* pList[100];
Vector delta( bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat() );
bool suppressCall = false;
int count = UTIL_EntitiesInBox( pList, 100, vecOrigin - delta, vecOrigin + delta, 0 );
// If the bugbait's been thrown, look for nearby targets to affect
if ( !bSqueezed )
{
for ( int i = 0; i < count; i++ )
{
// If close enough, make combine soldiers freak out when hit
if ( UTIL_DistApprox( pList[i]->WorldSpaceCenter(), vecOrigin ) < bugbait_grenade_radius.GetFloat() )
{
// Must be a soldier
if ( FClassnameIs( pList[i], "npc_combine_s") )
{
CAI_BaseNPC *pCombine = pList[i]->MyNPCPointer();
if ( pCombine != NULL )
{
trace_t tr;
UTIL_TraceLine( vecOrigin, pCombine->EyePosition(), MASK_ALL, pOwner, COLLISION_GROUP_NONE, &tr);
if ( tr.fraction == 1.0 || tr.m_pEnt == pCombine )
{
// Randomize the start time a little so multiple combine hit by
// the same bugbait don't all dance in synch.
g_EventQueue.AddEvent( pCombine, "HitByBugbait", RandomFloat(0, 0.5), pOwner, pOwner );
}
}
}
}
}
}
// Iterate over all sensors to see if they detected this impact
for ( CBugBaitSensor *pSensor = GetBugBaitSensorList(); pSensor != NULL; pSensor = pSensor->m_pNext )
{
if ( pSensor == NULL )
continue;
if ( pSensor->IsDisabled() )
continue;
if ( bSqueezed && pSensor->DetectsSqueeze() == false )
continue;
if ( !bSqueezed && pSensor->DetectsThrown() == false )
continue;
//Make sure we're within range of the sensor
if ( pSensor->GetRadius() > ( pSensor->GetAbsOrigin() - vecOrigin ).Length() )
{
//Tell the sensor it's been hit
if ( pSensor->Baited( pOwner ) )
{
//If we're suppressing the call to antlions, then don't make a bugbait sound
if ( pSensor->SuppressCall() )
{
suppressCall = true;
}
}
}
}
return suppressCall;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CGrenadeBugBait::ThinkBecomeSolid( void )
{
SetThink( NULL );
RemoveSolidFlags( FSOLID_NOT_SOLID );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : duration -
//-----------------------------------------------------------------------------
void CGrenadeBugBait::SetGracePeriod( float duration )
{
SetThink( &CGrenadeBugBait::ThinkBecomeSolid );
SetNextThink( gpGlobals->curtime + duration );
// Become unsolid
AddSolidFlags( FSOLID_NOT_SOLID );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &position -
// &angles -
// &velocity -
// &angVelocity -
// *owner -
// Output : CBaseGrenade
//-----------------------------------------------------------------------------
CGrenadeBugBait *BugBaitGrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const QAngle &angVelocity, CBaseEntity *owner )
{
CGrenadeBugBait *pGrenade = (CGrenadeBugBait *) CBaseEntity::Create( "npc_grenade_bugbait", position, angles, owner );
if ( pGrenade != NULL )
{
pGrenade->SetLocalAngularVelocity( angVelocity );
pGrenade->SetAbsVelocity( velocity );
pGrenade->SetThrower( ToBaseCombatCharacter( owner ) );
}
return pGrenade;
}