summaryrefslogtreecommitdiff
path: root/game/server/tf2/npc_bug_builder.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_builder.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'game/server/tf2/npc_bug_builder.cpp')
-rw-r--r--game/server/tf2/npc_bug_builder.cpp577
1 files changed, 577 insertions, 0 deletions
diff --git a/game/server/tf2/npc_bug_builder.cpp b/game/server/tf2/npc_bug_builder.cpp
new file mode 100644
index 0000000..e2bdfe2
--- /dev/null
+++ b/game/server/tf2/npc_bug_builder.cpp
@@ -0,0 +1,577 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: The builder bug
+//
+// $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 "AI_Navigator.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_builder.h"
+#include "npc_bug_hole.h"
+
+ConVar npc_bug_builder_health( "npc_bug_builder_health", "100" );
+
+BEGIN_DATADESC( CNPC_Bug_Builder )
+
+ DEFINE_FIELD( m_flIdleDelay, FIELD_FLOAT ),
+
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( npc_bug_builder, CNPC_Bug_Builder );
+IMPLEMENT_CUSTOM_AI( npc_bug_builder, CNPC_Bug_Builder );
+
+// Dawdling details
+// Max & Min distances for dawdle forward movement
+#define DAWDLE_MIN_DIST 64
+#define DAWDLE_MAX_DIST 1024
+
+//==================================================
+// Bug Conditions
+//==================================================
+enum BugConditions
+{
+ COND_BBUG_RETURN_TO_BUGHOLE = LAST_SHARED_CONDITION,
+};
+
+//==================================================
+// Bug Schedules
+//==================================================
+
+enum BugSchedules
+{
+ SCHED_BBUG_FLEE_ENEMY = LAST_SHARED_SCHEDULE,
+ SCHED_BBUG_RETURN_TO_BUGHOLE,
+ SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE,
+ SCHED_BBUG_DAWDLE,
+};
+
+//==================================================
+// Bug Tasks
+//==================================================
+
+enum BugTasks
+{
+ TASK_BBUG_GET_PATH_TO_FLEE = LAST_SHARED_TASK,
+ TASK_BBUG_GET_PATH_TO_BUGHOLE,
+ TASK_BBUG_HOLE_REMOVE,
+ TASK_BBUG_GET_PATH_TO_DAWDLE,
+ TASK_BBUG_FACE_DAWDLE,
+};
+
+//==================================================
+// Bug Activities
+//==================================================
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CNPC_Bug_Builder::CNPC_Bug_Builder( void )
+{
+ m_flFieldOfView = 0.5f;
+ m_flIdleDelay = 0.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup our schedules and tasks, etc.
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::InitCustomSchedules( void )
+{
+ INIT_CUSTOM_AI( CNPC_Bug_Builder );
+
+ // Schedules
+ ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_FLEE_ENEMY );
+ ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE );
+ ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE );
+ ADD_CUSTOM_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_DAWDLE );
+
+ // Conditions
+ ADD_CUSTOM_CONDITION( CNPC_Bug_Builder, COND_BBUG_RETURN_TO_BUGHOLE );
+
+ // Tasks
+ ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_FLEE );
+ ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_BUGHOLE );
+ ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_HOLE_REMOVE );
+ ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_GET_PATH_TO_DAWDLE );
+ ADD_CUSTOM_TASK( CNPC_Bug_Builder, TASK_BBUG_FACE_DAWDLE );
+
+ // Activities
+ //ADD_CUSTOM_ACTIVITY( CNPC_Bug_Builder, ACT_BUG_WARRIOR_DISTRACT );
+
+ AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_FLEE_ENEMY );
+ AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE );
+ AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE );
+ AI_LOAD_SCHEDULE( CNPC_Bug_Builder, SCHED_BBUG_DAWDLE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::Spawn( void )
+{
+ Precache();
+
+ SetModel( BUG_BUILDER_MODEL );
+
+ SetHullType(HULL_TINY);
+ SetHullSizeNormal();
+ SetDefaultEyeOffset();
+ SetViewOffset( (WorldAlignMins() + WorldAlignMaxs()) * 0.5 ); // See from my center
+ SetDistLook( 1024.0 );
+ m_flNextDawdle = 0;
+
+ SetNavType(NAV_GROUND);
+ m_NPCState = NPC_STATE_NONE;
+ SetBloodColor( BLOOD_COLOR_YELLOW );
+ m_iHealth = npc_bug_builder_health.GetFloat();
+
+ SetSolid( SOLID_BBOX );
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+ SetMoveType( MOVETYPE_STEP );
+
+ CapabilitiesAdd( bits_CAP_MOVE_GROUND );
+
+ NPCInit();
+
+ BaseClass::Spawn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::Precache( void )
+{
+ PrecacheModel( BUG_BUILDER_MODEL );
+
+ PrecacheScriptSound( "NPC_Bug_Builder.Idle" );
+ PrecacheScriptSound( "NPC_Bug_Builder.Pain" );
+
+ BaseClass::Precache();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CNPC_Bug_Builder::SelectSchedule( void )
+{
+ // If I'm not in idle anymore, don't idle
+ if ( m_NPCState != NPC_STATE_IDLE )
+ {
+ m_flNextDawdle = 0;
+ }
+
+ switch ( m_NPCState )
+ {
+ case NPC_STATE_IDLE:
+ {
+ // BugHole might be requesting help
+ if ( HasCondition( COND_BBUG_RETURN_TO_BUGHOLE ) )
+ return SCHED_BBUG_RETURN_TO_BUGHOLE;
+
+ // Setup to dawdle a bit from now
+ if ( !m_flNextDawdle )
+ {
+ m_flNextDawdle = gpGlobals->curtime + random->RandomFloat( 3.0, 5.0 );
+ }
+ else if ( m_flNextDawdle < gpGlobals->curtime )
+ {
+ m_flNextDawdle = 0;
+ return SCHED_BBUG_DAWDLE;
+ }
+
+ // When I take damage, I flee
+ if ( HasCondition( COND_LIGHT_DAMAGE | COND_HEAVY_DAMAGE ) )
+ return SCHED_BBUG_FLEE_ENEMY;
+
+ // Return to my bughole
+ //return SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE;
+ break;
+ }
+ case NPC_STATE_ALERT:
+ {
+ // BugHole might be requesting help
+ if ( HasCondition( COND_BBUG_RETURN_TO_BUGHOLE ) )
+ return SCHED_BBUG_RETURN_TO_BUGHOLE;
+
+ // When I take damage, I flee
+ if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
+ return SCHED_BBUG_FLEE_ENEMY;
+
+ break;
+ }
+ case NPC_STATE_COMBAT:
+ {
+ // Did I lose my enemy?
+ if ( HasCondition ( COND_LOST_ENEMY ) || HasCondition ( COND_ENEMY_UNREACHABLE ) )
+ {
+ SetEnemy( NULL );
+ SetState(NPC_STATE_IDLE);
+ return BaseClass::SelectSchedule();
+ }
+
+ // When I take damage, I flee
+ if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) )
+ return SCHED_BBUG_FLEE_ENEMY;
+ }
+ break;
+ }
+
+ return BaseClass::SelectSchedule();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTask -
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::StartTask( const Task_t *pTask )
+{
+ switch ( pTask->iTask )
+ {
+ case TASK_BBUG_GET_PATH_TO_FLEE:
+ {
+ // Always tell our bughole that we're under attack
+ if ( m_hMyBugHole )
+ {
+ m_hMyBugHole->IncomingFleeingBug( this );
+ }
+
+ // If we have no squad, or we couldn't get a path to our squadmate, move to our bughole
+ if ( m_hMyBugHole )
+ {
+ SetTarget( m_hMyBugHole );
+ AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN );
+ if ( GetNavigator()->SetGoal( goal ) )
+ {
+ TaskComplete();
+ return;
+ }
+ }
+
+ TaskComplete();
+ }
+ break;
+
+ case TASK_BBUG_GET_PATH_TO_BUGHOLE:
+ {
+ // Get a path back to my bughole
+ // If we have no squad, or we couldn't get a path to our squadmate, look for a bughole
+ if ( m_hMyBugHole )
+ {
+ SetTarget( m_hMyBugHole );
+ AI_NavGoal_t goal( GOALTYPE_TARGETENT, vec3_origin, ACT_RUN );
+ if ( GetNavigator()->SetGoal( goal ) )
+ {
+ TaskComplete();
+ return;
+ }
+ }
+
+ TaskFail( "Couldn't get to bughole." );
+ }
+ break;
+
+ case TASK_BBUG_HOLE_REMOVE:
+ {
+ TaskComplete();
+
+ // Crawl inside the bughole and remove myself
+ AddEffects( EF_NODRAW );
+ AddSolidFlags( FSOLID_NOT_SOLID );
+ Event_Killed( CTakeDamageInfo( this, this, 200, DMG_CRUSH ) );
+
+ // Tell the bughole
+ if ( m_hMyBugHole )
+ {
+ m_hMyBugHole->BugReturned();
+ }
+ }
+ break;
+
+ case TASK_BBUG_GET_PATH_TO_DAWDLE:
+ {
+ // Get a dawdle point ahead of us
+ Vector vecForward, vecTarget;
+ AngleVectors( GetAbsAngles(), &vecForward );
+ VectorMA( GetAbsOrigin(), random->RandomFloat( DAWDLE_MIN_DIST, DAWDLE_MAX_DIST ), vecForward, vecTarget );
+
+ // See how far we could move ahead
+ trace_t tr;
+ UTIL_TraceEntity( this, GetAbsOrigin(), vecTarget, MASK_SOLID, &tr);
+ float flDistance = tr.fraction * (vecTarget - GetAbsOrigin()).Length();
+ if ( flDistance >= DAWDLE_MIN_DIST )
+ {
+ AI_NavGoal_t goal( tr.endpos );
+ GetNavigator()->SetGoal( goal );
+ }
+
+ TaskComplete();
+ }
+ break;
+
+ case TASK_BBUG_FACE_DAWDLE:
+ {
+ // Turn a random amount to the right
+ float flYaw = GetMotor()->GetIdealYaw();
+ flYaw = flYaw + random->RandomFloat( 45, 135 );
+ GetMotor()->SetIdealYaw( UTIL_AngleMod(flYaw) );
+ SetTurnActivity();
+ break;
+ }
+ break;
+
+ default:
+ BaseClass::StartTask( pTask );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTask -
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::RunTask( const Task_t *pTask )
+{
+ switch ( pTask->iTask )
+ {
+ case TASK_BBUG_FACE_DAWDLE:
+ {
+ GetMotor()->UpdateYaw();
+ if ( FacingIdeal() )
+ {
+ TaskComplete();
+ }
+ break;
+ }
+
+ default:
+ BaseClass::RunTask( pTask );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CNPC_Bug_Builder::FValidateHintType(CAI_Hint *pHint)
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pVictim -
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::Event_Killed( const CTakeDamageInfo &info )
+{
+ BaseClass::Event_Killed( info );
+
+ // Remove myself in a minute
+ if ( !ShouldFadeOnDeath() )
+ {
+ SetThink( SUB_Remove );
+ SetNextThink( gpGlobals->curtime + 20 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pEvent -
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::HandleAnimEvent( animevent_t *pEvent )
+{
+ BaseClass::HandleAnimEvent( pEvent );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+float CNPC_Bug_Builder::MaxYawSpeed( void )
+{
+ return 2.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::IdleSound( void )
+{
+ EmitSound( "NPC_Bug_Builder.Idle" );
+ m_flIdleDelay = gpGlobals->curtime + 4.0f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::PainSound( const CTakeDamageInfo &info )
+{
+ EmitSound( "NPC_Bug_Builder.Pain" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CNPC_Bug_Builder::ShouldPlayIdleSound( void )
+{
+ //Only do idles in the right states
+ if ( ( m_NPCState != NPC_STATE_IDLE && m_NPCState != NPC_STATE_ALERT ) )
+ return false;
+
+ //Gagged monsters don't talk
+ if ( HasSpawnFlags( SF_NPC_GAG ) )
+ return false;
+
+ //Don't cut off another sound or play again too soon
+ if ( m_flIdleDelay > gpGlobals->curtime )
+ return false;
+
+ //Randomize it a bit
+ if ( random->RandomInt( 0, 20 ) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::SetBugHole( CMaker_BugHole *pBugHole )
+{
+ m_hMyBugHole = pBugHole;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: BugHole is calling me home to defend it
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::ReturnToBugHole( void )
+{
+ SetCondition( COND_BBUG_RETURN_TO_BUGHOLE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CNPC_Bug_Builder::AlertSound( void )
+{
+ if ( GetEnemy() )
+ {
+ //FIXME: We need a better solution for inner-squad alerts!!
+ //SOUND_DANGER is designed to frighten NPC's away. Need a different SOUND_ type.
+ CSoundEnt::InsertSound( SOUND_DANGER, GetEnemy()->GetAbsOrigin(), 1024, 0.5f, this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Overridden for team handling
+//-----------------------------------------------------------------------------
+Disposition_t CNPC_Bug_Builder::IRelationType( CBaseEntity *pTarget )
+{
+ // Builders ignore everything
+ return D_NU;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// Schedules
+//
+//-----------------------------------------------------------------------------
+
+//=========================================================
+// Dawdle around
+//=========================================================
+AI_DEFINE_SCHEDULE
+(
+ SCHED_BBUG_DAWDLE,
+
+ " Tasks"
+ " TASK_SET_TOLERANCE_DISTANCE 32"
+ " TASK_BBUG_GET_PATH_TO_DAWDLE 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " TASK_BBUG_FACE_DAWDLE 0"
+ " "
+ " Interrupts"
+ " COND_LIGHT_DAMAGE"
+ " COND_HEAVY_DAMAGE"
+);
+
+//=========================================================
+// Flee from our enemy
+//=========================================================
+AI_DEFINE_SCHEDULE
+(
+ SCHED_BBUG_FLEE_ENEMY,
+
+ " Tasks"
+ " TASK_SET_TOLERANCE_DISTANCE 128"
+ " TASK_BBUG_GET_PATH_TO_FLEE 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " TASK_TURN_RIGHT 180"
+ " "
+ " Interrupts"
+ " COND_ENEMY_DEAD"
+ " COND_LOST_ENEMY"
+);
+
+//=========================================================
+// Retreat to a bughole
+//=========================================================
+AI_DEFINE_SCHEDULE
+(
+ SCHED_BBUG_RETURN_TO_BUGHOLE,
+
+ " Tasks"
+ " TASK_SET_TOLERANCE_DISTANCE 128"
+ " TASK_BBUG_GET_PATH_TO_BUGHOLE 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " "
+ " Interrupts"
+ " COND_NEW_ENEMY"
+ " COND_HEAR_COMBAT"
+ " COND_HEAR_DANGER"
+);
+
+//=========================================================
+// Return to a bughole and remove myself
+//=========================================================
+AI_DEFINE_SCHEDULE
+(
+ SCHED_BBUG_RETURN_TO_BUGHOLE_AND_REMOVE,
+
+ " Tasks"
+ " TASK_WAIT 5" // Wait for 5-10 seconds to see if anything happens
+ " TASK_WAIT_RANDOM 5"
+ " TASK_SET_TOLERANCE_DISTANCE 128"
+ " TASK_BBUG_GET_PATH_TO_BUGHOLE 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " TASK_BBUG_HOLE_REMOVE 0"
+ " "
+ " Interrupts"
+ " COND_NEW_ENEMY"
+ " COND_HEAR_COMBAT"
+ " COND_HEAR_DANGER"
+);
+