summaryrefslogtreecommitdiff
path: root/game/server/tf2/npc_bug_hole.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf2/npc_bug_hole.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf2/npc_bug_hole.cpp')
-rw-r--r--game/server/tf2/npc_bug_hole.cpp392
1 files changed, 392 insertions, 0 deletions
diff --git a/game/server/tf2/npc_bug_hole.cpp b/game/server/tf2/npc_bug_hole.cpp
new file mode 100644
index 0000000..98923b3
--- /dev/null
+++ b/game/server/tf2/npc_bug_hole.cpp
@@ -0,0 +1,392 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Bug hole
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "AI_Task.h"
+#include "AI_Default.h"
+#include "AI_Schedule.h"
+#include "AI_Hull.h"
+#include "AI_Hint.h"
+#include "activitylist.h"
+#include "soundent.h"
+#include "game.h"
+#include "NPCEvent.h"
+#include "tf_player.h"
+#include "EntityList.h"
+#include "ndebugoverlay.h"
+#include "shake.h"
+#include "monstermaker.h"
+#include "decals.h"
+#include "vstdlib/random.h"
+#include "tf_obj.h"
+#include "engine/IEngineSound.h"
+#include "IEffects.h"
+#include "npc_bug_warrior.h"
+#include "npc_bug_builder.h"
+#include "npc_bug_hole.h"
+
+LINK_ENTITY_TO_CLASS( npc_bughole, CMaker_BugHole );
+
+IMPLEMENT_SERVERCLASS_ST(CMaker_BugHole, DT_Maker_BugHole)
+END_SEND_TABLE();
+
+BEGIN_DATADESC( CMaker_BugHole )
+
+ DEFINE_KEYFIELD( m_iMaxPool, FIELD_INTEGER, "PoolSize" ),
+ DEFINE_KEYFIELD( m_flPoolRegenTime, FIELD_FLOAT, "PoolRegen" ),
+ DEFINE_KEYFIELD( m_flPatrolTime, FIELD_FLOAT, "PatrolTime" ),
+ DEFINE_KEYFIELD( m_iszPatrolPathName, FIELD_STRING, "PatrolName" ),
+ DEFINE_KEYFIELD( m_iMaxNumberOfPatrollers, FIELD_INTEGER, "MaxPatrollers" ),
+ DEFINE_KEYFIELD( m_iMaxNumberOfBuilders, FIELD_INTEGER, "MaxBuilders" ),
+
+END_DATADESC()
+
+// Maximum speed at which a bughole thinks. Regen/Spawn times faster than this won't make it work faster.
+#define BUGHOLE_THINK_SPEED 3.0
+
+static ConVar npc_bughole_health( "npc_bughole_health","300", FCVAR_NONE, "Bug hole's health." );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CMaker_BugHole::CMaker_BugHole( void)
+{
+ m_iszNPCClassname_Warrior = MAKE_STRING( "npc_bug_warrior" );
+ m_iszNPCClassname_Builder = MAKE_STRING( "npc_bug_builder" );
+ m_iszNPCClassname = m_iszNPCClassname_Warrior;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::Spawn( void )
+{
+ // Set these up before calling base spawn
+ m_spawnflags |= SF_NPCMAKER_INF_CHILD;
+ m_bDisabled = true;
+
+ // Start with a full pool
+ m_iPool = m_iMaxPool;
+
+ BaseClass::Spawn();
+
+ // Bug holes are destroyable
+ SetSolid( SOLID_BBOX );
+ SetModel( "models/npcs/bugs/bug_hole.mdl" );
+ m_takedamage = DAMAGE_YES;
+ m_iHealth = npc_bughole_health.GetInt();
+
+ // Setup spawn & regen times
+ m_flNextSpawnTime = 0;
+ m_flNextRegenTime = gpGlobals->curtime + m_flPoolRegenTime;
+ m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
+
+ // Override the base class think, and think with some random so bugholes don't all think at the same time
+ SetThink ( BugHoleThink );
+ SetNextThink( gpGlobals->curtime + BUGHOLE_THINK_SPEED + random->RandomFloat( -0.5, 0.5 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::Precache( void )
+{
+ BaseClass::Precache();
+
+ PrecacheModel( "models/npcs/bugs/bug_hole.mdl" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::BugHoleThink( void )
+{
+ // Regenerate our bug pool
+ if ( m_flNextRegenTime < gpGlobals->curtime )
+ {
+ if ( m_iPool < m_iMaxPool )
+ {
+ m_iPool++;
+ }
+ m_flNextRegenTime += m_flPoolRegenTime;
+ }
+
+ // Spawn if we're set to
+ if ( m_flNextSpawnTime && m_flNextSpawnTime < gpGlobals->curtime )
+ {
+ m_flNextSpawnTime = 0;
+ MakeNPC();
+ }
+ else
+ {
+ // If I can see a player, try and spawn a bug
+ CBaseEntity *pList[100];
+ Vector vecDelta( 768, 768, 768 );
+ int count = UTIL_EntitiesInBox( pList, 32, GetAbsOrigin() - vecDelta, GetAbsOrigin() + vecDelta, FL_CLIENT|FL_OBJECT );
+ for ( int i = 0; i < count; i++ )
+ {
+ CBaseEntity *pEnt = pList[i];
+ if ( pEnt->IsAlive() && FVisible(pEnt) )
+ {
+ BugHoleUnderAttack();
+ break;
+ }
+ }
+ }
+
+ // Send out a patrol if we haven't spawned anything for a long time
+ if ( m_flNextPatrolTime < gpGlobals->curtime )
+ {
+ m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
+ StartPatrol();
+ CheckBuilder();
+ }
+
+ SetNextThink( gpGlobals->curtime + BUGHOLE_THINK_SPEED );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Spawn a bug, if we're not waiting to spawn one already
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::SpawnBug( float flTime )
+{
+ // If no time was passed in, spawn immediately
+ if ( !flTime )
+ {
+ MakeNPC();
+ }
+ else if ( !m_flNextSpawnTime )
+ {
+ m_flNextSpawnTime = gpGlobals->curtime + flTime;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::SpawnWarrior( float flTime )
+{
+ m_iszNPCClassname = m_iszNPCClassname_Warrior;
+ SpawnBug( flTime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::SpawnBuilder( float flTime )
+{
+ m_iszNPCClassname = m_iszNPCClassname_Builder;
+ SpawnBug( flTime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: BugHole has spotted a player near it
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::BugHoleUnderAttack( void )
+{
+ // Call any patrollers back to defend the base
+ for ( int i = 0; i < m_aWarriorBugs.Size(); i++ )
+ {
+ if ( m_aWarriorBugs[i]->IsPatrolling() )
+ {
+ m_aWarriorBugs[i]->ReturnToBugHole();
+ }
+ }
+
+ // Try and spawn a warrior
+ SpawnWarrior( random->RandomFloat( 1.0, 3.0 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Send a bug out to patrol
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::StartPatrol( void )
+{
+ // Don't patrol if I don't have a patrol name
+ if ( !m_iszPatrolPathName || !m_iMaxNumberOfPatrollers )
+ return;
+
+ // If I don't have any children, spawn one for to patrol with
+ if ( m_nLiveChildren < m_iMaxNumberOfPatrollers )
+ {
+ SpawnWarrior(0);
+
+ // Think again to use the bug we just created
+ m_flNextPatrolTime = gpGlobals->curtime + 2.0;
+ }
+
+ // We might have failed due to having none in the pool
+ if ( !m_aWarriorBugs.Size() )
+ return;
+
+ // Count number of bugs patrolling
+ int i, iCount;
+ iCount = 0;
+ for ( i = 0; i < m_aWarriorBugs.Size(); i++ )
+ {
+ if ( m_aWarriorBugs[i]->IsPatrolling() )
+ {
+ iCount++;
+ }
+ }
+
+ // Find bugs willing to patrol
+ for ( i = 0; i < m_aWarriorBugs.Size(); i++ )
+ {
+ // Make sure we don't have too many
+ if ( iCount >= m_iMaxNumberOfPatrollers )
+ return;
+
+ if ( m_aWarriorBugs[i]->StartPatrolling( m_iszPatrolPathName ) )
+ {
+ iCount++;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: See if we should spawn a builder bug
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::CheckBuilder( void )
+{
+ // If my pool is full, and I have spaw builder spots, spawn a builder bug
+ /*
+ if ( m_iPool == m_iMaxPool && m_aBuilderBugs.Size() < m_iMaxNumberOfBuilders )
+ {
+ SpawnBuilder(0);
+ }
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Bughole makes multiple types of bugs
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::MakeNPC( void )
+{
+ // Don't try and patrol for a while
+ m_flNextPatrolTime = gpGlobals->curtime + m_flPatrolTime;
+
+ // If my pool is empty, don't spawn a bug
+ if ( !m_iPool )
+ return;
+
+ BaseClass::MakeNPC();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hook to allow bugs to move before they spawn
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::ChildPreSpawn( CAI_BaseNPC *pChild )
+{
+ BaseClass::ChildPreSpawn( pChild );
+
+ // Drop the bug down and remove it's onground flag
+ Vector origin = GetLocalOrigin();
+ origin.z -= 64;
+ pChild->SetLocalOrigin( origin );
+ pChild->SetGroundEntity( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hook to allow bugs to pack specific data into their known class fields
+// Input : *pChild - pointer to the spawned entity to work on
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::ChildPostSpawn( CAI_BaseNPC *pChild )
+{
+ BaseClass::ChildPostSpawn( pChild );
+
+ // May be a warrior or a builder
+ CNPC_Bug_Warrior *pWarrior = dynamic_cast<CNPC_Bug_Warrior*>((CAI_BaseNPC*)pChild);
+ if ( pWarrior )
+ {
+ pWarrior->SetBugHole( this );
+
+ // Add him to my bug list
+ WarriorHandle_t hHandle;
+ hHandle = pWarrior;
+ m_aWarriorBugs.AddToTail( hHandle );
+ }
+ else
+ {
+ CNPC_Bug_Builder *pBuilder = dynamic_cast<CNPC_Bug_Builder*>((CAI_BaseNPC*)pChild);
+ ASSERT( pBuilder );
+ pBuilder->SetBugHole( this );
+
+ // Add him to my bug list
+ BuilderHandle_t hHandle;
+ hHandle = pBuilder;
+ m_aBuilderBugs.AddToTail( hHandle );
+ }
+
+ m_iPool--;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove the bug from our list of bugs
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::DeathNotice( CBaseEntity *pVictim )
+{
+ BaseClass::DeathNotice( pVictim );
+
+ // May be a warrior or a builder
+ CNPC_Bug_Warrior *pWarrior = dynamic_cast<CNPC_Bug_Warrior*>((CAI_BaseNPC*)pVictim);
+ if ( pWarrior )
+ {
+ // Remove him from my list
+ WarriorHandle_t hHandle;
+ hHandle = pWarrior;
+ m_aWarriorBugs.FindAndRemove( hHandle );
+ }
+ else
+ {
+ CNPC_Bug_Builder *pBuilder = dynamic_cast<CNPC_Bug_Builder*>((CAI_BaseNPC*)pVictim);
+ ASSERT( pBuilder );
+
+ // Remove him from my list
+ BuilderHandle_t hHandle;
+ hHandle = pBuilder;
+ m_aBuilderBugs.FindAndRemove( hHandle );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: On death, fall to the ground and vanish
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::Event_Killed( const CTakeDamageInfo &info )
+{
+ BaseClass::Event_Killed( info );
+
+ SetMoveType( MOVETYPE_FLYGRAVITY );
+ SetGroundEntity( NULL );
+
+ SetThink( SUB_Remove );
+ SetNextThink( gpGlobals->curtime + 5.0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A bug is fleeing to me, see if I want to do anything
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::IncomingFleeingBug( CAI_BaseNPC *pBug )
+{
+ SpawnWarrior( random->RandomFloat( 3.0, 5.0 ) );
+
+ // If I have available warriors, tell them to engage
+ for ( int i = 0; i < m_aWarriorBugs.Size(); i++ )
+ {
+ m_aWarriorBugs[i]->Assist( pBug );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: One of my bugs has returned to me
+//-----------------------------------------------------------------------------
+void CMaker_BugHole::BugReturned( void )
+{
+ if ( m_iPool < m_iMaxPool )
+ {
+ m_iPool++;
+ }
+}