daily pastebin goal
28%
SHARE
TWEET

npc_fire_antlion.cpp

a guest Nov 24th, 2011 34 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:             fireantlion - nasty bug
  4. //
  5. //=============================================================================//
  6.  
  7. #include "cbase.h"
  8. #include "ai_hint.h"
  9. #include "ai_squad.h"
  10. #include "ai_moveprobe.h"
  11. #include "ai_route.h"
  12. #include "npcevent.h"
  13. #include "gib.h"
  14. #include "entitylist.h"
  15. #include "ndebugoverlay.h"
  16. #include "antlion_dust.h"
  17. #include "engine/IEngineSound.h"
  18. #include "globalstate.h"
  19. #include "movevars_shared.h"
  20. #include "te_effect_dispatch.h"
  21. #include "vehicle_base.h"
  22. #include "mapentities.h"
  23. #include "antlion_maker.h"
  24. #include "npc_fireantlion.h"
  25. #include "decals.h"
  26. #include "asw_shareddefs.h"
  27. #include "explode.h"
  28. #include "weapon_physcannon.h"
  29. #include "baseparticleentity.h"
  30. #include "props.h"
  31. #include "particle_parse.h"
  32. #include "ai_tacticalservices.h"
  33.  
  34. #ifdef HL2_EPISODIC
  35. #include "grenade_spit.h"
  36. #endif
  37.  
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40.  
  41. //Debug visualization
  42. ConVar  g_debug_fireantlion( "g_debug_fireantlion", "0" );
  43.  
  44. // base fireantlion stuff
  45. ConVar  sk_fireantlion_health( "sk_fireantlion_health", "0" );
  46. ConVar  sk_fireantlion_swipe_damage( "sk_fireantlion_swipe_damage", "0" );
  47. ConVar  sk_fireantlion_jump_damage( "sk_fireantlion_jump_damage", "0" );
  48. ConVar  sk_fireantlion_air_attack_dmg( "sk_fireantlion_air_attack_dmg", "0" );
  49.  
  50.  
  51. #ifdef HL2_EPISODIC
  52.  
  53. // workers
  54. #define fireantlion_WORKERS_BURST() (true)
  55. #define fireantlion_WORKER_BURST_IS_POISONOUS() (true)
  56.  
  57. ConVar  sk_fireantlion_worker_burst_damage( "sk_fireantlion_worker_burst_damage", "50", FCVAR_NONE, "How much damage is inflicted by an fireantlion worker's death explosion." );
  58. ConVar  sk_fireantlion_worker_health( "sk_fireantlion_worker_health", "0", FCVAR_NONE, "Hitpoints of an fireantlion worker. If 0, will use base fireantlion hitpoints."   );
  59. ConVar  sk_fireantlion_worker_spit_speed( "sk_fireantlion_worker_spit_speed", "0", FCVAR_NONE, "Speed at which an fireantlion spit grenade travels." );
  60.  
  61. // This must agree with the fireantlionWorkerBurstRadius() function!
  62. ConVar  sk_fireantlion_worker_burst_radius( "sk_fireantlion_worker_burst_radius", "160", FCVAR_NONE, "Effect radius of an fireantlion worker's death explosion."  );
  63.  
  64. #endif
  65.  
  66. ConVar  g_test_new_fireantlion_jump( "g_test_new_fireantlion_jump", "1", FCVAR_ARCHIVE );
  67. ConVar  fireantlion_easycrush( "fireantlion_easycrush", "1" );
  68. ConVar g_fireantlion_cascade_push( "g_fireantlion_cascade_push", "1", FCVAR_ARCHIVE );
  69.  
  70. ConVar g_debug_fireantlion_worker( "g_debug_fireantlion_worker", "0" );
  71.  
  72. //extern ConVar bugbait_radius;
  73.  
  74. int AE_fireantlion_WALK_FOOTSTEP;
  75. int AE_fireantlion_MELEE_HIT1;
  76. int AE_fireantlion_MELEE_HIT2;
  77. int AE_fireantlion_MELEE_POUNCE;
  78. int AE_fireantlion_FOOTSTEP_SOFT;
  79. int AE_fireantlion_FOOTSTEP_HEAVY;
  80. int AE_fireantlion_START_JUMP;
  81. int AE_fireantlion_BURROW_IN;
  82. int AE_fireantlion_BURROW_OUT;
  83. int AE_fireantlion_VANISH;
  84. int AE_fireantlion_OPEN_WINGS;
  85. int AE_fireantlion_CLOSE_WINGS;
  86. int AE_fireantlion_MELEE1_SOUND;
  87. int AE_fireantlion_MELEE2_SOUND;
  88. int AE_fireantlion_WORKER_EXPLODE_SCREAM;
  89. int AE_fireantlion_WORKER_EXPLODE_WARN;
  90. int AE_fireantlion_WORKER_EXPLODE;
  91. int AE_fireantlion_WORKER_SPIT;
  92. int AE_fireantlion_WORKER_DONT_EXPLODE;
  93.  
  94.  
  95. //Attack range definitions
  96. #define fireantlion_MELEE1_RANGE                100.0f
  97. #define fireantlion_MELEE2_RANGE                64.0f
  98. #define fireantlion_MELEE2_RANGE_MAX    175.0f
  99. #define fireantlion_MELEE2_RANGE_MIN    64.0f
  100. #define fireantlion_JUMP_MIN                    128.0f
  101.  
  102. #define fireantlion_JUMP_MAX_RISE               512.0f
  103. #define fireantlion_JUMP_MAX                    1024.0f
  104.  
  105. #define fireantlion_MIN_BUGBAIT_GOAL_TARGET_RADIUS      512
  106.  
  107. //Interaction IDs
  108. int g_interactionfireantlionFoundTarget = 0;
  109. int g_interactionfireantlionFiredAtTarget = 0;
  110.  
  111. #define fireantlion_MODEL                       "models/antlion.mdl"
  112. #define fireantlion_WORKER_MODEL        "models/antlion_worker.mdl"
  113.  
  114. #define fireantlion_BURROW_IN   0
  115. #define fireantlion_BURROW_OUT  1
  116.  
  117. #define fireantlion_BUGBAIT_NAV_TOLERANCE       200
  118.  
  119. #define fireantlion_OBEY_FOLLOW_TIME    5.0f
  120.  
  121.  
  122. //==================================================
  123. // fireantlionSquadSlots
  124. //==================================================
  125.  
  126. enum
  127. {      
  128.         SQUAD_SLOT_fireantlion_JUMP = LAST_SHARED_SQUADSLOT,
  129.         SQUAD_SLOT_fireantlion_WORKER_FIRE,
  130. };
  131.  
  132. //==================================================
  133. // fireantlion Activities
  134. //==================================================
  135.  
  136. int ACT_fireantlion_JUMP_START;
  137. int     ACT_fireantlion_DISTRACT;
  138. int ACT_fireantlion_DISTRACT_ARRIVED;
  139. int ACT_fireantlion_BURROW_IN;
  140. int ACT_fireantlion_BURROW_OUT;
  141. int ACT_fireantlion_BURROW_IDLE;
  142. int     ACT_fireantlion_RUN_AGITATED;
  143. int ACT_fireantlion_FLIP;
  144. int ACT_fireantlion_ZAP_FLIP;
  145. int ACT_fireantlion_POUNCE;
  146. int ACT_fireantlion_POUNCE_MOVING;
  147. int ACT_fireantlion_DROWN;
  148. int ACT_fireantlion_LAND;
  149. int ACT_fireantlion_WORKER_EXPLODE;
  150.  
  151.  
  152. //==================================================
  153. // CNPC_fireantlion
  154. //==================================================
  155.  
  156. CNPC_fireantlion::CNPC_fireantlion( void )
  157. {
  158.         m_flIdleDelay   = 0.0f;
  159.         m_flBurrowTime  = 0.0f;
  160.         m_flJumpTime    = 0.0f;
  161.         m_flPounceTime  = 0.0f;
  162.         m_flObeyFollowTime = 0.0f;
  163.         m_iUnBurrowAttempts = 0;
  164.  
  165.         m_flAlertRadius = 256.0f;
  166.         m_flFieldOfView = -0.5f;
  167.  
  168.         m_bStartBurrowed        = false;
  169.         m_bAgitatedSound        = false;
  170.         m_bWingsOpen            = false;
  171.        
  172.         m_flIgnoreSoundTime     = 0.0f;
  173.         m_bHasHeardSound        = false;
  174.  
  175.         m_flNextAcknowledgeTime = 0.0f;
  176.         m_flNextJumpPushTime = 0.0f;
  177.  
  178.         m_vecLastJumpAttempt.Init();
  179.         m_vecSavedJump.Init();
  180.  
  181.         m_hFightGoalTarget = NULL;
  182.         m_hFollowTarget = NULL;
  183.         m_bLoopingStarted = false;
  184.  
  185.         m_bForcedStuckJump = false;
  186.         m_nBodyBone = -1;
  187.         m_bSuppressUnburrowEffects = false;
  188. }
  189.  
  190. LINK_ENTITY_TO_CLASS( npc_fireantlion, CNPC_fireantlion );
  191.  
  192. //==================================================
  193. // CNPC_fireantlion::m_DataDesc
  194. //==================================================
  195.  
  196. BEGIN_DATADESC( CNPC_fireantlion )
  197.  
  198.         DEFINE_KEYFIELD( m_bStartBurrowed,              FIELD_BOOLEAN,  "startburrowed" ),
  199.         DEFINE_KEYFIELD( m_bIgnoreBugbait,              FIELD_BOOLEAN,  "ignorebugbait" ),
  200.         DEFINE_KEYFIELD( m_flAlertRadius,               FIELD_FLOAT,    "radius" ),
  201.         DEFINE_KEYFIELD( m_flEludeDistance,             FIELD_FLOAT,    "eludedist" ),
  202.         DEFINE_KEYFIELD( m_bSuppressUnburrowEffects,    FIELD_BOOLEAN,  "unburroweffects" ),
  203.  
  204.         DEFINE_FIELD( m_vecSaveSpitVelocity,    FIELD_VECTOR ),
  205.         DEFINE_FIELD( m_flIdleDelay,                    FIELD_TIME ),
  206.         DEFINE_FIELD( m_flBurrowTime,                   FIELD_TIME ),
  207.         DEFINE_FIELD( m_flJumpTime,                             FIELD_TIME ),
  208.         DEFINE_FIELD( m_flPounceTime,                   FIELD_TIME ),
  209.         DEFINE_FIELD( m_iUnBurrowAttempts,              FIELD_INTEGER ),
  210.         DEFINE_FIELD( m_iContext,                               FIELD_INTEGER ),
  211.         DEFINE_FIELD( m_vecSavedJump,                   FIELD_VECTOR ),
  212.         DEFINE_FIELD( m_vecLastJumpAttempt,             FIELD_VECTOR ),
  213.         DEFINE_FIELD( m_flIgnoreSoundTime,              FIELD_TIME ),
  214.         DEFINE_FIELD( m_vecHeardSound,                  FIELD_POSITION_VECTOR ),
  215.         DEFINE_FIELD( m_bHasHeardSound,                 FIELD_BOOLEAN ),
  216.         DEFINE_FIELD( m_bAgitatedSound,                 FIELD_BOOLEAN ),
  217.         DEFINE_FIELD( m_bWingsOpen,                             FIELD_BOOLEAN ),
  218.         DEFINE_FIELD( m_flNextAcknowledgeTime,  FIELD_TIME ),
  219.         DEFINE_FIELD( m_hFollowTarget,                  FIELD_EHANDLE ),
  220.         DEFINE_FIELD( m_hFightGoalTarget,               FIELD_EHANDLE ),
  221.         DEFINE_FIELD( m_strParentSpawner,               FIELD_STRING ),
  222.         DEFINE_FIELD( m_flSuppressFollowTime,   FIELD_FLOAT ),
  223.         DEFINE_FIELD( m_MoveState,                              FIELD_INTEGER ),
  224.         DEFINE_FIELD( m_flObeyFollowTime,               FIELD_TIME ),
  225.         DEFINE_FIELD( m_bLeapAttack,                    FIELD_BOOLEAN ),
  226.         DEFINE_FIELD( m_bDisableJump,                   FIELD_BOOLEAN ),
  227.         DEFINE_FIELD( m_flTimeDrown,                    FIELD_TIME ),
  228.         DEFINE_FIELD( m_flTimeDrownSplash,              FIELD_TIME ),
  229.         DEFINE_FIELD( m_bDontExplode,                   FIELD_BOOLEAN ),
  230.         DEFINE_FIELD( m_flNextJumpPushTime,             FIELD_TIME ),
  231.         DEFINE_FIELD( m_bForcedStuckJump,               FIELD_BOOLEAN ),
  232.         DEFINE_FIELD( m_flZapDuration,                  FIELD_TIME ),
  233. #if HL2_EPISODIC
  234.         DEFINE_FIELD( m_bHasDoneAirAttack,              FIELD_BOOLEAN ),
  235. #endif 
  236.         // DEFINE_FIELD( m_bLoopingStarted, FIELD_BOOLEAN ),
  237.         //                        m_FollowBehavior
  238.         //                        m_AssaultBehavior
  239.        
  240.         DEFINE_INPUTFUNC( FIELD_VOID,   "Unburrow", InputUnburrow ),
  241.         DEFINE_INPUTFUNC( FIELD_VOID,   "Burrow",       InputBurrow ),
  242.         DEFINE_INPUTFUNC( FIELD_VOID,   "BurrowAway",   InputBurrowAway ),
  243.         DEFINE_INPUTFUNC( FIELD_STRING, "FightToPosition", InputFightToPosition ),
  244.         DEFINE_INPUTFUNC( FIELD_STRING, "StopFightToPosition", InputStopFightToPosition ),
  245.         DEFINE_INPUTFUNC( FIELD_VOID,   "EnableJump", InputEnableJump ),
  246.         DEFINE_INPUTFUNC( FIELD_VOID,   "DisableJump", InputDisableJump ),
  247.         DEFINE_INPUTFUNC( FIELD_VOID,   "IgnoreBugbait", InputIgnoreBugbait ),
  248.         DEFINE_INPUTFUNC( FIELD_VOID,   "HearBugbait", InputHearBugbait ),
  249.         DEFINE_INPUTFUNC( FIELD_STRING, "JumpAtTarget", InputJumpAtTarget ),
  250.  
  251.         DEFINE_OUTPUT( m_OnReachFightGoal, "OnReachedFightGoal" ),
  252.         DEFINE_OUTPUT( m_OnUnBurrowed, "OnUnBurrowed" ),
  253.  
  254.         // Function Pointers
  255.         DEFINE_ENTITYFUNC( Touch ),
  256.         DEFINE_USEFUNC( BurrowUse ),
  257.         DEFINE_THINKFUNC( ZapThink ),
  258.  
  259.         // DEFINE_FIELD( FIELD_SHORT, m_hFootstep ),
  260. END_DATADESC()
  261.  
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. //-----------------------------------------------------------------------------
  265. void CNPC_fireantlion::Spawn( void )
  266. {
  267.         Precache();
  268.  
  269. #ifdef _XBOX
  270.         // Always fade the corpse
  271.         AddSpawnFlags( SF_NPC_FADE_CORPSE );
  272. #endif // _XBOX
  273.  
  274. #ifdef HL2_EPISODIC
  275.         if ( IsWorker() )
  276.         {
  277.                 SetModel( fireantlion_WORKER_MODEL );
  278.                 AddSpawnFlags( SF_NPC_LONG_RANGE );
  279.                 SetBloodColor( BLOOD_COLOR_fireantlion_WORKER );
  280.         }
  281.         else
  282.         {
  283.                 SetModel( fireantlion_MODEL );
  284.                 SetBloodColor( BLOOD_COLOR_fireantlion );
  285.         }
  286. #else
  287.         SetModel( fireantlion_MODEL );
  288.         SetBloodColor( BLOOD_COLOR_YELLOW );
  289. #endif // HL2_EPISODIC
  290.  
  291.         SetHullType(HULL_MEDIUM);
  292.         SetHullSizeNormal();
  293.         SetDefaultEyeOffset();
  294.        
  295.         SetNavType( NAV_GROUND );
  296.  
  297.         m_NPCState      = NPC_STATE_NONE;
  298.  
  299. #if HL2_EPISODIC
  300.         m_iHealth = ( IsWorker() ) ? sk_fireantlion_worker_health.GetFloat() : sk_fireantlion_health.GetFloat();
  301. #else
  302.         m_iHealth       = sk_fireantlion_health.GetFloat();
  303. #endif // _DEBUG
  304.  
  305.         SetSolid( SOLID_BBOX );
  306.         AddSolidFlags( FSOLID_NOT_STANDABLE );
  307.  
  308.        
  309.         SetMoveType( MOVETYPE_STEP );
  310.  
  311.         //Only do this if a squadname appears in the entity
  312.         if ( m_SquadName != NULL_STRING )
  313.         {
  314.                 CapabilitiesAdd( bits_CAP_SQUAD );
  315.         }
  316.  
  317.         SetCollisionGroup( HL2COLLISION_GROUP_ANTLION );
  318.  
  319.         CapabilitiesAdd( bits_CAP_MOVE_GROUND | bits_CAP_MOVE_JUMP | bits_CAP_INNATE_MELEE_ATTACK1 | bits_CAP_INNATE_MELEE_ATTACK2 );
  320.        
  321.         // Workers shoot projectiles
  322.         if ( IsWorker() )
  323.         {
  324.                 CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 );
  325.                 // CapabilitiesRemove( bits_CAP_INNATE_MELEE_ATTACK2 );
  326.         }
  327.  
  328.         // JAY: Optimize these out for now
  329.         if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == false )
  330.                  CapabilitiesAdd( bits_CAP_SKIP_NAV_GROUND_CHECK );
  331.  
  332.         NPCInit();
  333.  
  334.         if ( IsWorker() )
  335.         {
  336.                 // Bump up the worker's eye position a bit
  337.                 SetViewOffset( Vector( 0, 0, 32 ) );
  338.         }
  339.  
  340.         // fireantlions will always pursue
  341.         m_flDistTooFar = FLT_MAX;
  342.  
  343.         m_bDisableJump = false;
  344.  
  345.         //See if we're supposed to start burrowed
  346.         if ( m_bStartBurrowed )
  347.         {
  348.                 AddEffects( EF_NODRAW );
  349.                 AddFlag( FL_NOTARGET );
  350.                 m_spawnflags |= SF_NPC_GAG;
  351.                 AddSolidFlags( FSOLID_NOT_SOLID );
  352.                 m_takedamage    = DAMAGE_NO;
  353.  
  354.                 SetState( NPC_STATE_IDLE );
  355.                 SetActivity( (Activity) ACT_fireantlion_BURROW_IDLE );
  356.                 SetSchedule( SCHED_fireantlion_WAIT_FOR_UNBORROW_TRIGGER );
  357.  
  358.                 SetUse( &CNPC_fireantlion::BurrowUse );
  359.         }
  360.  
  361.         BaseClass::Spawn();
  362.  
  363.         m_nSkin = random->RandomInt( 0, fireantlion_SKIN_COUNT-1 );
  364. }
  365.  
  366. //-----------------------------------------------------------------------------
  367. // Purpose:
  368. //-----------------------------------------------------------------------------
  369. void CNPC_fireantlion::Activate( void )
  370. {
  371.         // If we're friendly to the player, setup a relationship to reflect it
  372.         if ( IsAllied() )
  373.         {
  374.                 // Handle all clients
  375.                 for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  376.                 {
  377.                         CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  378.  
  379.                         if ( pPlayer != NULL )
  380.                         {
  381.                                 AddEntityRelationship( pPlayer, D_LI, 99 );
  382.                         }
  383.                 }
  384.         }
  385.  
  386.         BaseClass::Activate();
  387. }
  388.  
  389.  
  390. //-----------------------------------------------------------------------------
  391. // Purpose: override this to simplify the physics shadow of the fireantlions
  392. //-----------------------------------------------------------------------------
  393. bool CNPC_fireantlion::CreateVPhysics()
  394. {
  395.         bool bRet = BaseClass::CreateVPhysics();
  396.         return bRet;
  397. }
  398.  
  399. // Use all the gibs
  400. #define NUM_fireantlion_GIBS_UNIQUE     3
  401. const char *pszfireantlionGibs_Unique[NUM_fireantlion_GIBS_UNIQUE] = {
  402.         "models/gibs/fireantlion_gib_large_1.mdl",
  403.         "models/gibs/fireantlion_gib_large_2.mdl",
  404.         "models/gibs/fireantlion_gib_large_3.mdl"
  405. };
  406.  
  407. #define NUM_fireantlion_GIBS_MEDIUM     3
  408. const char *pszfireantlionGibs_Medium[NUM_fireantlion_GIBS_MEDIUM] = {
  409.         "models/gibs/fireantlion_gib_medium_1.mdl",
  410.         "models/gibs/fireantlion_gib_medium_2.mdl",
  411.         "models/gibs/fireantlion_gib_medium_3.mdl"
  412. };
  413.  
  414. // XBox doesn't use the smaller gibs, so don't cache them
  415. #define NUM_fireantlion_GIBS_SMALL      3
  416. const char *pszfireantlionGibs_Small[NUM_fireantlion_GIBS_SMALL] = {
  417.         "models/gibs/fireantlion_gib_small_1.mdl",
  418.         "models/gibs/fireantlion_gib_small_2.mdl",
  419.         "models/gibs/fireantlion_gib_small_3.mdl"
  420. };
  421.  
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. //-----------------------------------------------------------------------------
  425. void CNPC_fireantlion::Precache( void )
  426. {
  427. #ifdef HL2_EPISODIC
  428.         if ( IsWorker() )
  429.         {
  430.                 PrecacheModel( fireantlion_WORKER_MODEL );
  431.                 PropBreakablePrecacheAll( MAKE_STRING( fireantlion_WORKER_MODEL ) );
  432.                 UTIL_PrecacheOther( "grenade_spit" );
  433.                 PrecacheParticleSystem( "blood_impact_fireantlion_worker_01" );
  434.                 PrecacheParticleSystem( "fireantlion_gib_02" );
  435.                 PrecacheParticleSystem( "blood_impact_yellow_01" );
  436.         }
  437.         else
  438. #endif // HL2_EPISODIC
  439.         {
  440.                 PrecacheModel( fireantlion_MODEL );
  441.                 PropBreakablePrecacheAll( MAKE_STRING( fireantlion_MODEL ) );
  442.                 PrecacheParticleSystem( "blood_impact_fireantlion_01" );
  443.                 PrecacheParticleSystem( "fireantlionGib" );
  444.         }
  445.  
  446.         for ( int i = 0; i < NUM_fireantlion_GIBS_UNIQUE; ++i )
  447.         {
  448.                 PrecacheModel( pszfireantlionGibs_Unique[ i ] );
  449.         }
  450.         for ( int i = 0; i < NUM_fireantlion_GIBS_MEDIUM; ++i )
  451.         {
  452.                 PrecacheModel( pszfireantlionGibs_Medium[ i ] );
  453.         }
  454.         for ( int i = 0; i < NUM_fireantlion_GIBS_SMALL; ++i )
  455.         {
  456.                 PrecacheModel( pszfireantlionGibs_Small[ i ] );
  457.         }
  458.  
  459.         PrecacheScriptSound( "NPC_fireantlion.RunOverByVehicle" );
  460.         PrecacheScriptSound( "NPC_fireantlion.MeleeAttack" );
  461.         m_hFootstep = PrecacheScriptSound( "NPC_fireantlion.Footstep" );
  462.         PrecacheScriptSound( "NPC_fireantlion.BurrowIn" );
  463.         PrecacheScriptSound( "NPC_fireantlion.BurrowOut" );
  464.         PrecacheScriptSound( "NPC_fireantlion.FootstepSoft" );
  465.         PrecacheScriptSound( "NPC_fireantlion.FootstepHeavy" );
  466.         PrecacheScriptSound( "NPC_fireantlion.MeleeAttackSingle" );
  467.         PrecacheScriptSound( "NPC_fireantlion.MeleeAttackDouble" );
  468.         PrecacheScriptSound( "NPC_fireantlion.Distracted" );
  469.         PrecacheScriptSound( "NPC_fireantlion.Idle" );
  470.         PrecacheScriptSound( "NPC_fireantlion.Pain" );
  471.         PrecacheScriptSound( "NPC_fireantlion.Land" );
  472.         PrecacheScriptSound( "NPC_fireantlion.WingsOpen" );
  473.         PrecacheScriptSound( "NPC_fireantlion.LoopingAgitated" );
  474.         PrecacheScriptSound( "NPC_fireantlion.Distracted" );
  475.  
  476. #ifdef HL2_EPISODIC
  477.         PrecacheScriptSound( "NPC_fireantlion.PoisonBurstScream" );
  478.         PrecacheScriptSound( "NPC_fireantlion.PoisonBurstScreamSubmerged" );
  479.         PrecacheScriptSound( "NPC_fireantlion.PoisonBurstExplode" );
  480.         PrecacheScriptSound( "NPC_fireantlion.MeleeAttack_Muffled" );
  481.         PrecacheScriptSound( "NPC_fireantlion.TrappedMetal" );
  482.         PrecacheScriptSound( "NPC_fireantlion.ZappedFlip" );
  483.         PrecacheScriptSound( "NPC_fireantlion.PoisonShoot" );
  484.         PrecacheScriptSound( "NPC_fireantlion.PoisonBall" );
  485. #endif
  486.  
  487.         BaseClass::Precache();
  488. }
  489.  
  490. //-----------------------------------------------------------------------------
  491. // Purpose:
  492. // Output : Returns true on success, false on failure.
  493. //-----------------------------------------------------------------------------
  494. inline CBaseEntity *CNPC_fireantlion::EntityToWatch( void )
  495. {
  496.         return ( m_hFollowTarget != NULL ) ? m_hFollowTarget.Get() : GetEnemy();
  497. }
  498.  
  499.  
  500. //-----------------------------------------------------------------------------
  501. // Purpose: Cache whatever pose parameters we intend to use
  502. //-----------------------------------------------------------------------------
  503. void    CNPC_fireantlion::PopulatePoseParameters( void )
  504. {
  505.         m_poseHead_Pitch = LookupPoseParameter("head_pitch");
  506.         m_poseHead_Yaw   = LookupPoseParameter("head_yaw" );
  507.  
  508.         BaseClass::PopulatePoseParameters();
  509. }
  510.  
  511. //-----------------------------------------------------------------------------
  512. // Purpose:
  513. //-----------------------------------------------------------------------------
  514. void CNPC_fireantlion::UpdateHead( void )
  515. {
  516.         float yaw = GetPoseParameter( m_poseHead_Yaw );
  517.         float pitch = GetPoseParameter( m_poseHead_Pitch );
  518.  
  519.         CBaseEntity *pTarget = EntityToWatch();
  520.  
  521.         if ( pTarget != NULL )
  522.         {
  523.                 Vector  enemyDir = pTarget->WorldSpaceCenter() - WorldSpaceCenter();
  524.                 VectorNormalize( enemyDir );
  525.                
  526.                 if ( DotProduct( enemyDir, BodyDirection3D() ) < 0.0f )
  527.                 {
  528.                         SetPoseParameter( m_poseHead_Yaw,       UTIL_Approach( 0, yaw, 10 ) );
  529.                         SetPoseParameter( m_poseHead_Pitch, UTIL_Approach( 0, pitch, 10 ) );
  530.                        
  531.                         return;
  532.                 }
  533.  
  534.                 float facingYaw = VecToYaw( BodyDirection3D() );
  535.                 float yawDiff = VecToYaw( enemyDir );
  536.                 yawDiff = UTIL_AngleDiff( yawDiff, facingYaw + yaw );
  537.  
  538.                 float facingPitch = UTIL_VecToPitch( BodyDirection3D() );
  539.                 float pitchDiff = UTIL_VecToPitch( enemyDir );
  540.                 pitchDiff = UTIL_AngleDiff( pitchDiff, facingPitch + pitch );
  541.  
  542.                 SetPoseParameter( m_poseHead_Yaw, UTIL_Approach( yaw + yawDiff, yaw, 50 ) );
  543.                 SetPoseParameter( m_poseHead_Pitch, UTIL_Approach( pitch + pitchDiff, pitch, 50 ) );
  544.         }
  545.         else
  546.         {
  547.                 SetPoseParameter( m_poseHead_Yaw,       UTIL_Approach( 0, yaw, 10 ) );
  548.                 SetPoseParameter( m_poseHead_Pitch, UTIL_Approach( 0, pitch, 10 ) );
  549.         }
  550. }
  551.  
  552. #define fireantlion_VIEW_FIELD_NARROW   0.85f
  553.  
  554. //-----------------------------------------------------------------------------
  555. // Purpose:
  556. // Input  : *pEntity -
  557. // Output : Returns true on success, false on failure.
  558. //-----------------------------------------------------------------------------
  559. bool CNPC_fireantlion::FInViewCone( CBaseEntity *pEntity )
  560. {
  561.         m_flFieldOfView = ( GetEnemy() != NULL ) ? fireantlion_VIEW_FIELD_NARROW : VIEW_FIELD_WIDE;
  562.  
  563.         return BaseClass::FInViewCone( pEntity );
  564. }
  565.  
  566. //-----------------------------------------------------------------------------
  567. // Purpose:
  568. // Input  : &vecSpot -
  569. // Output : Returns true on success, false on failure.
  570. //-----------------------------------------------------------------------------
  571. bool CNPC_fireantlion::FInViewCone( const Vector &vecSpot )
  572. {
  573.         m_flFieldOfView = ( GetEnemy() != NULL ) ? fireantlion_VIEW_FIELD_NARROW : VIEW_FIELD_WIDE;
  574.  
  575.         return BaseClass::FInViewCone( vecSpot );
  576. }
  577.  
  578.  
  579. //-----------------------------------------------------------------------------
  580. //-----------------------------------------------------------------------------
  581. bool CNPC_fireantlion::CanBecomeRagdoll()
  582. {
  583.         // This prevents us from dying in the regular way. It forces a schedule selection
  584.         // that will select SCHED_DIE, where we can do our poison burst thing.
  585. #ifdef HL2_EPISODIC
  586.         if ( IsWorker() && fireantlion_WORKERS_BURST() )
  587.         {
  588.                 // If we're in a script, we're allowed to ragdoll. This lets the vort's dynamic
  589.                 // interaction ragdoll us.
  590.                 return ( m_NPCState == NPC_STATE_SCRIPT || m_bDontExplode );
  591.         }
  592. #endif 
  593.         return BaseClass::CanBecomeRagdoll();
  594. }
  595.  
  596.  
  597. //-----------------------------------------------------------------------------
  598. // Purpose:
  599. // Input  : *pVictim -
  600. //-----------------------------------------------------------------------------
  601. void CNPC_fireantlion::Event_Killed( const CTakeDamageInfo &info )
  602. {
  603.         //Turn off wings
  604.         SetWings( false );
  605.         VacateStrategySlot();
  606.  
  607.         if ( IsCurSchedule(SCHED_fireantlion_BURROW_IN) || IsCurSchedule(SCHED_fireantlion_BURROW_OUT) )
  608.         {
  609.                 AddEFlags( EF_NOSHADOW );
  610.         }
  611.  
  612.         if ( info.GetDamageType() & DMG_CRUSH )
  613.         {
  614.                 CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, GetAbsOrigin(), 256, 0.5f, this );
  615.         }
  616.  
  617.         BaseClass::Event_Killed( info );
  618.  
  619.         CBaseEntity *pAttacker = info.GetInflictor();
  620.  
  621.         if ( pAttacker && pAttacker->GetServerVehicle() && ShouldGib( info ) == true )
  622.         {
  623.                 trace_t tr;
  624.                 UTIL_TraceLine( GetAbsOrigin() + Vector( 0, 0, 64 ), pAttacker->GetAbsOrigin(), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr );
  625.                 UTIL_DecalTrace( &tr, "fireantlion.Splat" );
  626.  
  627.                 SpawnBlood( GetAbsOrigin(), g_vecAttackDir, BloodColor(), info.GetDamage() );
  628.  
  629.                 CPASAttenuationFilter filter( this );
  630.                 EmitSound( filter, entindex(), "NPC_fireantlion.RunOverByVehicle" );
  631.         }
  632.  
  633.         // Stop our zap effect!
  634.         SetContextThink( NULL, gpGlobals->curtime, "ZapThink" );
  635. }
  636.  
  637. //-----------------------------------------------------------------------------
  638. //-----------------------------------------------------------------------------
  639. void CNPC_fireantlion::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove )
  640. {
  641.         Vector vecForceDir;
  642.  
  643.         // Always hurt bullseyes for now
  644.         if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) )
  645.         {
  646.                 vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin());
  647.                 CTakeDamageInfo info( this, this, damage, DMG_SLASH );
  648.                 CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() );
  649.                 GetEnemy()->TakeDamage( info );
  650.                 return;
  651.         }
  652.  
  653.         CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f );
  654.  
  655.         if ( pHurt )
  656.         {
  657.                 vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() );
  658.  
  659.                 //FIXME: Until the interaction is setup, kill combine soldiers in one hit -- jdw
  660.                 if ( FClassnameIs( pHurt, "npc_combine_s" ) )
  661.                 {
  662.                         CTakeDamageInfo dmgInfo( this, this, pHurt->m_iHealth+25, DMG_SLASH );
  663.                         CalculateMeleeDamageForce( &dmgInfo, vecForceDir, pHurt->GetAbsOrigin() );
  664.                         pHurt->TakeDamage( dmgInfo );
  665.                         return;
  666.                 }
  667.  
  668.                 CBasePlayer *pPlayer = ToBasePlayer( pHurt );
  669.  
  670.                 if ( pPlayer != NULL )
  671.                 {
  672.                         //Kick the player angles
  673.                         if ( !(pPlayer->GetFlags() & FL_GODMODE ) && pPlayer->GetMoveType() != MOVETYPE_NOCLIP )
  674.                         {
  675.                                 pPlayer->ViewPunch( viewPunch );
  676.  
  677.                                 Vector  dir = pHurt->GetAbsOrigin() - GetAbsOrigin();
  678.                                 VectorNormalize(dir);
  679.  
  680.                                 QAngle angles;
  681.                                 VectorAngles( dir, angles );
  682.                                 Vector forward, right;
  683.                                 AngleVectors( angles, &forward, &right, NULL );
  684.  
  685.                                 //Push the target back
  686.                                 pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] );
  687.                         }
  688.                 }
  689.  
  690.                 // Play a random attack hit sound
  691.                 EmitSound( "NPC_fireantlion.MeleeAttack" );
  692.         }
  693. }
  694.  
  695. // Number of times the fireantlions will attempt to generate a random chase position
  696. #define NUM_CHASE_POSITION_ATTEMPTS             3
  697.  
  698. //-----------------------------------------------------------------------------
  699. // Purpose:
  700. // Input  : &targetPos -
  701. //                      &result -
  702. // Output : Returns true on success, false on failure.
  703. //-----------------------------------------------------------------------------
  704. bool CNPC_fireantlion::FindChasePosition( const Vector &targetPos, Vector &result )
  705. {
  706.         if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == true )
  707.         {
  708.                  result = targetPos;
  709.                  return true;
  710.         }
  711.  
  712.         Vector runDir = ( targetPos - GetAbsOrigin() );
  713.         VectorNormalize( runDir );
  714.        
  715.         Vector  vRight, vUp;
  716.         VectorVectors( runDir, vRight, vUp );
  717.  
  718.         for ( int i = 0; i < NUM_CHASE_POSITION_ATTEMPTS; i++ )
  719.         {
  720.                 result  = targetPos;
  721.                 result += -runDir * random->RandomInt( 64, 128 );
  722.                 result += vRight * random->RandomInt( -128, 128 );
  723.                
  724.                 //FIXME: We need to do a more robust search here
  725.                 // Find a ground position and try to get there
  726.                 if ( GetGroundPosition( result, result ) )
  727.                         return true;
  728.         }
  729.        
  730.         //TODO: If we're making multiple inquiries to this, make sure it's evenly spread
  731.  
  732.         if ( g_debug_fireantlion.GetInt() == 1 )
  733.         {
  734.                 NDebugOverlay::Cross3D( result, -Vector(32,32,32), Vector(32,32,32), 255, 255, 0, true, 2.0f );
  735.         }
  736.  
  737.         return false;
  738. }
  739.  
  740. //-----------------------------------------------------------------------------
  741. // Purpose:
  742. // Input  : &testPos -
  743. //-----------------------------------------------------------------------------
  744. bool CNPC_fireantlion::GetGroundPosition( const Vector &testPos, Vector &result )
  745. {
  746.         // Trace up to clear the ground
  747.         trace_t tr;
  748.         AI_TraceHull( testPos, testPos + Vector( 0, 0, 64 ), NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
  749.  
  750.         // If we're stuck in solid, this can't be valid
  751.         if ( tr.allsolid )
  752.         {
  753.                 if ( g_debug_fireantlion.GetInt() == 3 )
  754.                 {
  755.                         NDebugOverlay::BoxDirection( testPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ) + Vector( 0, 0, 128 ), Vector( 0, 0, 1 ), 255, 0, 0, true, 2.0f );
  756.                 }
  757.  
  758.                 return false;
  759.         }
  760.  
  761.         if ( g_debug_fireantlion.GetInt() == 3 )
  762.         {
  763.                 NDebugOverlay::BoxDirection( testPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ) + Vector( 0, 0, 128 ), Vector( 0, 0, 1 ), 0, 255, 0, true, 2.0f );
  764.         }
  765.  
  766.         // Trace down to find the ground
  767.         AI_TraceHull( tr.endpos, tr.endpos - Vector( 0, 0, 128 ), NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
  768.  
  769.         if ( g_debug_fireantlion.GetInt() == 3 )
  770.         {
  771.                 NDebugOverlay::BoxDirection( tr.endpos, NAI_Hull::Mins( GetHullType() ) - Vector( 0, 0, 256 ), NAI_Hull::Maxs( GetHullType() ), Vector( 0, 0, 1 ), 255, 255, 0, true, 2.0f );
  772.         }
  773.  
  774.         // We must end up on the floor with this trace
  775.         if ( tr.fraction < 1.0f )
  776.         {
  777.                 if ( g_debug_fireantlion.GetInt() == 3 )
  778.                 {
  779.                         NDebugOverlay::Cross3D( tr.endpos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), 255, 0, 0, true, 2.0f );
  780.                 }
  781.  
  782.                 result = tr.endpos;
  783.                 return true;
  784.         }
  785.  
  786.         // Ended up in open space
  787.         return false;
  788. }
  789. void CNPC_fireantlion::ManageFleeCapabilities( bool bEnable )
  790. {
  791.         if ( bEnable == false )
  792.         {
  793.                 //Remove the jump capabilty when we build our route.
  794.                 //We'll enable it back again after the route has been built.
  795.                 CapabilitiesRemove( bits_CAP_MOVE_JUMP );
  796.  
  797.                 if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == false  )
  798.                          CapabilitiesRemove( bits_CAP_SKIP_NAV_GROUND_CHECK );
  799.         }
  800.         else
  801.         {
  802.                 if ( m_bDisableJump == false )
  803.                          CapabilitiesAdd( bits_CAP_MOVE_JUMP );
  804.  
  805.                 if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == false  )
  806.                          CapabilitiesAdd( bits_CAP_SKIP_NAV_GROUND_CHECK );
  807.         }
  808. }
  809.  
  810. //-----------------------------------------------------------------------------
  811. // Purpose:
  812. // Input  : soundType -
  813. // Output : Returns true on success, false on failure.
  814. //-----------------------------------------------------------------------------
  815. bool CNPC_fireantlion::GetPathToSoundFleePoint( int soundType )
  816. {
  817.         CSound *pSound = GetLoudestSoundOfType( soundType );
  818.  
  819.         if ( pSound == NULL  )
  820.         {
  821.                 //NOTENOTE: If you're here, there's a disparity between Listen() and GetLoudestSoundOfType() - jdw
  822.                 TaskFail( "Unable to find thumper sound!" );
  823.                 return false;
  824.         }
  825.  
  826.         ManageFleeCapabilities( false );
  827.  
  828.         //Try and find a hint-node first
  829.         CHintCriteria   hintCriteria;
  830.  
  831.         hintCriteria.SetHintType( HINT_ANTLION_THUMPER_FLEE_POINT );
  832.         hintCriteria.SetFlag( bits_HINT_NODE_NEAREST );
  833.         hintCriteria.AddIncludePosition( WorldSpaceCenter(), 2500 );
  834.  
  835.         CAI_Hint *pHint = CAI_HintManager::FindHint( WorldSpaceCenter(), hintCriteria );
  836.  
  837.         Vector vecFleeGoal;
  838.         Vector vecSoundPos = pSound->GetSoundOrigin();
  839.  
  840.         // Put the sound location on the same plane as the fireantlion.
  841.         vecSoundPos.z = GetAbsOrigin().z;
  842.  
  843.         Vector vecFleeDir = GetAbsOrigin() - vecSoundPos;
  844.         VectorNormalize( vecFleeDir );
  845.  
  846.         if ( pHint != NULL )
  847.         {
  848.                 // Get our goal position
  849.                 pHint->GetPosition( this, &vecFleeGoal );
  850.  
  851.                 // Find a route to that position
  852.                 AI_NavGoal_t goal( vecFleeGoal, (Activity) ACT_fireantlion_RUN_AGITATED, 128, AIN_DEF_FLAGS );
  853.  
  854.                 if ( GetNavigator()->SetGoal( goal ) )
  855.                 {
  856.                         pHint->Lock( this );
  857.                         pHint->Unlock( 2.0f );
  858.  
  859.                         GetNavigator()->SetArrivalActivity( (Activity) ACT_fireantlion_DISTRACT_ARRIVED );
  860.                         GetNavigator()->SetArrivalDirection( -vecFleeDir );
  861.  
  862.                         ManageFleeCapabilities( true );
  863.                         return true;
  864.                 }
  865.         }
  866.  
  867.         //Make us offset this a little at least
  868.         float flFleeYaw = VecToYaw( vecFleeDir ) + random->RandomInt( -20, 20 );
  869.  
  870.         vecFleeDir = UTIL_YawToVector( flFleeYaw );
  871.  
  872.         // Move us to the outer radius of the noise (with some randomness)
  873.         vecFleeGoal = vecSoundPos + vecFleeDir * ( pSound->Volume() + random->RandomInt( 32, 64 ) );
  874.  
  875.         // Find a route to that position
  876.         AI_NavGoal_t goal( vecFleeGoal + Vector( 0, 0, 8 ), (Activity) ACT_fireantlion_RUN_AGITATED, 512, AIN_DEF_FLAGS );
  877.  
  878.         if ( GetNavigator()->SetGoal( goal ) )
  879.         {
  880.                 GetNavigator()->SetArrivalActivity( (Activity) ACT_fireantlion_DISTRACT_ARRIVED );
  881.                 GetNavigator()->SetArrivalDirection( -vecFleeDir );
  882.  
  883.                 ManageFleeCapabilities( true );
  884.                 return true;
  885.         }
  886.  
  887.         ManageFleeCapabilities( true );
  888.         return false;
  889. }
  890.  
  891. //-----------------------------------------------------------------------------
  892. // Purpose: Returns whether the enemy has been seen within the time period supplied
  893. // Input  : flTime - Timespan we consider
  894. // Output : Returns true on success, false on failure.
  895. //-----------------------------------------------------------------------------
  896. bool CNPC_fireantlion::SeenEnemyWithinTime( float flTime )
  897. {
  898.         float flLastSeenTime = GetEnemies()->LastTimeSeen( GetEnemy() );
  899.         return ( flLastSeenTime != 0.0f && ( gpGlobals->curtime - flLastSeenTime ) < flTime );
  900. }
  901.  
  902. //-----------------------------------------------------------------------------
  903. // Purpose: Test whether this fireantlion can hit the target
  904. //-----------------------------------------------------------------------------
  905. bool CNPC_fireantlion::InnateWeaponLOSCondition( const Vector &ownerPos, const Vector &targetPos, bool bSetConditions )
  906. {
  907.         if ( GetNextAttack() > gpGlobals->curtime )
  908.                 return false;
  909.  
  910.         // If we can see the enemy, or we've seen them in the last few seconds just try to lob in there
  911.         if ( SeenEnemyWithinTime( 3.0f ) )
  912.         {
  913.                 Vector vSpitPos;
  914.                 GetAttachment( "mouth", vSpitPos );
  915.                
  916.                 return GetSpitVector( vSpitPos, targetPos, &m_vecSaveSpitVelocity );
  917.         }
  918.  
  919.         return BaseClass::InnateWeaponLOSCondition( ownerPos, targetPos, bSetConditions );
  920. }
  921.  
  922. //
  923. //      FIXME: Create this in a better fashion!
  924. //
  925. //
  926. //Vector VecCheckThrowTolerance2( CBaseEntity *pEdict, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flTolerance )
  927. //{
  928. //      flSpeed = MAX( 1.0f, flSpeed );
  929. //
  930. //      float flGravity = sv_gravity.GetFloat();
  931. //
  932. //      Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
  933. //
  934. //      // throw at a constant time
  935. //      float time = vecGrenadeVel.Length( ) / flSpeed;
  936. //      //vecGrenadeVel = vecGrenadeVel * (1.0 / time);
  937. //
  938. //      // adjust upward toss to compensate for gravity loss
  939. //      vecGrenadeVel.z += flGravity * time * 0.5;
  940. //
  941. //      Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
  942. //      vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
  943. //
  944. //
  945. //      trace_t tr;
  946. //      UTIL_TraceLine( vecSpot1, vecApex, MASK_SOLID, pEdict, COLLISION_GROUP_NONE, &tr );
  947. //      if (tr.fraction != 1.0)
  948. //      {
  949. //              // fail!
  950. //              if ( g_debug_fireantlion_worker.GetBool() )
  951. //              {
  952. //                      NDebugOverlay::Line( vecSpot1, vecApex, 255, 0, 0, true, 5.0 );
  953. //              }
  954. //
  955. //              return vec3_origin;
  956. //      }
  957. //
  958. //      if ( g_debug_fireantlion_worker.GetBool() )
  959. //      {
  960. //              NDebugOverlay::Line( vecSpot1, vecApex, 0, 255, 0, true, 5.0 );
  961. //      }
  962. //
  963. //      UTIL_TraceLine( vecApex, vecSpot2, MASK_SOLID_BRUSHONLY, pEdict, COLLISION_GROUP_NONE, &tr );
  964. //      if ( tr.fraction != 1.0 )
  965. //      {
  966. //              bool bFail = true;
  967. //
  968. //              // Didn't make it all the way there, but check if we're within our tolerance range
  969. //              if ( flTolerance > 0.0f )
  970. //              {
  971. //                      float flNearness = ( tr.endpos - vecSpot2 ).LengthSqr();
  972. //                      if ( flNearness < Square( flTolerance ) )
  973. //                      {
  974. //                              if ( g_debug_fireantlion_worker.GetBool() )
  975. //                              {
  976. //                                      NDebugOverlay::Sphere( tr.endpos, vec3_angle, flTolerance, 0, 255, 0, 0, true, 5.0 );
  977. //                              }
  978. //
  979. //                              bFail = false;
  980. //                      }
  981. //              }
  982. //             
  983. //              if ( bFail )
  984. //              {
  985. //                      if ( g_debug_fireantlion_worker.GetBool() )
  986. //                      {
  987. //                              NDebugOverlay::Line( vecApex, vecSpot2, 255, 0, 0, true, 5.0 );
  988. //                              NDebugOverlay::Sphere( tr.endpos, vec3_angle, flTolerance, 255, 0, 0, 0, true, 5.0 );
  989. //                      }
  990. //                      return vec3_origin;
  991. //              }
  992. //      }
  993. //
  994. //      if ( g_debug_fireantlion_worker.GetBool() )
  995. //      {
  996. //              NDebugOverlay::Line( vecApex, vecSpot2, 0, 255, 0, true, 5.0 );
  997. //      }
  998. //
  999. //      return vecGrenadeVel;
  1000. //}
  1001.  
  1002. //-----------------------------------------------------------------------------
  1003. // Purpose: Get a toss direction that will properly lob spit to hit a target
  1004. // Input  : &vecStartPos - Where the spit will start from
  1005. //                      &vecTarget - Where the spit is meant to land
  1006. //                      *vecOut - The resulting vector to lob the spit
  1007. // Output : Returns true on success, false on failure.
  1008. //-----------------------------------------------------------------------------
  1009. bool CNPC_fireantlion::GetSpitVector( const Vector &vecStartPos, const Vector &vecTarget, Vector *vecOut )
  1010. {
  1011.         // fireantlion workers exist only in episodic.
  1012. #if HL2_EPISODIC
  1013.         // Try the most direct route
  1014.         Vector vecToss = VecCheckThrowTolerance( this, vecStartPos, vecTarget, sk_fireantlion_worker_spit_speed.GetFloat(), (10.0f*12.0f) );
  1015.  
  1016.         // If this failed then try a little faster (flattens the arc)
  1017.         if ( vecToss == vec3_origin )
  1018.         {
  1019.                 vecToss = VecCheckThrowTolerance( this, vecStartPos, vecTarget, sk_fireantlion_worker_spit_speed.GetFloat() * 1.5f, (10.0f*12.0f) );
  1020.                 if ( vecToss == vec3_origin )
  1021.                         return false;
  1022.         }
  1023.  
  1024.         // Save out the result
  1025.         if ( vecOut )
  1026.         {
  1027.                 *vecOut = vecToss;
  1028.         }
  1029.  
  1030.         return true;
  1031. #else
  1032.         return false;
  1033. #endif
  1034. }
  1035.  
  1036. //-----------------------------------------------------------------------------
  1037. // Purpose:
  1038. // Input  : flDuration -
  1039. //-----------------------------------------------------------------------------
  1040. void CNPC_fireantlion::DelaySquadAttack( float flDuration )
  1041. {
  1042.         if ( GetSquad() )
  1043.         {
  1044.                 // Reduce the duration by as much as 50% of the total time to make this less robotic
  1045.                 float flAdjDuration = flDuration - random->RandomFloat( 0.0f, (flDuration*0.5f) );
  1046.                 GetSquad()->BroadcastInteraction( g_interactionfireantlionFiredAtTarget, (void *)&flAdjDuration, this );
  1047.         }
  1048. }
  1049.  
  1050. //-----------------------------------------------------------------------------
  1051. // Purpose:
  1052. // Input  : *pEvent -
  1053. //-----------------------------------------------------------------------------
  1054. void CNPC_fireantlion::HandleAnimEvent( animevent_t *pEvent )
  1055. {
  1056. #ifdef HL2_EPISODIC
  1057.                 // Handle the spit event
  1058.                 if ( pEvent->event == AE_fireantlion_WORKER_SPIT )
  1059.                 {
  1060.                         if ( GetEnemy() )
  1061.                         {
  1062.                                 Vector vSpitPos;
  1063.                                 GetAttachment( "mouth", vSpitPos );
  1064.  
  1065.                                 Vector  vTarget;
  1066.                                
  1067.                                 // If our enemy is looking at us and far enough away, lead him
  1068.                                 if ( HasCondition( COND_ENEMY_FACING_ME ) && UTIL_DistApprox( GetAbsOrigin(), GetEnemy()->GetAbsOrigin() ) > (40*12) )
  1069.                                 {
  1070.                                         UTIL_PredictedPosition( GetEnemy(), 0.5f, &vTarget );
  1071.                                         vTarget.z = GetEnemy()->GetAbsOrigin().z;
  1072.                                 }
  1073.                                 else
  1074.                                 {
  1075.                                         // Otherwise he can't see us and he won't be able to dodge
  1076.                                         vTarget = GetEnemy()->BodyTarget( vSpitPos, true );
  1077.                                 }
  1078.                                
  1079.                                 vTarget[2] += random->RandomFloat( 0.0f, 32.0f );
  1080.                                
  1081.                                 // Try and spit at our target
  1082.                                 Vector  vecToss;                               
  1083.                                 if ( GetSpitVector( vSpitPos, vTarget, &vecToss ) == false )
  1084.                                 {
  1085.                                         // Now try where they were
  1086.                                         if ( GetSpitVector( vSpitPos, m_vSavePosition, &vecToss ) == false )
  1087.                                         {
  1088.                                                 // Failing that, just shoot with the old velocity we calculated initially!
  1089.                                                 vecToss = m_vecSaveSpitVelocity;
  1090.                                         }
  1091.                                 }
  1092.  
  1093.                                 // Find what our vertical theta is to estimate the time we'll impact the ground
  1094.                                 Vector vecToTarget = ( vTarget - vSpitPos );
  1095.                                 VectorNormalize( vecToTarget );
  1096.                                 float flVelocity = VectorNormalize( vecToss );
  1097.                                 float flCosTheta = DotProduct( vecToTarget, vecToss );
  1098.                                 float flTime = (vSpitPos-vTarget).Length2D() / ( flVelocity * flCosTheta );
  1099.  
  1100.                                 // Emit a sound where this is going to hit so that targets get a chance to act correctly
  1101.                                 CSoundEnt::InsertSound( SOUND_DANGER, vTarget, (15*12), flTime, this );
  1102.  
  1103.                                 // Don't fire again until this volley would have hit the ground (with some lag behind it)
  1104.                                 SetNextAttack( gpGlobals->curtime + flTime + random->RandomFloat( 0.5f, 2.0f ) );
  1105.  
  1106.                                 // Tell any squadmates not to fire for some portion of the time this volley will be in the air (except on hard)
  1107.                                 if ( g_pGameRules->IsSkillLevel( SKILL_HARD ) == false )
  1108.                                         DelaySquadAttack( flTime );
  1109.  
  1110.                                 for ( int i = 0; i < 6; i++ )
  1111.                                 {
  1112.                                         CGrenadeSpit *pGrenade = (CGrenadeSpit*) CreateEntityByName( "grenade_spit" );
  1113.                                         pGrenade->SetAbsOrigin( vSpitPos );
  1114.                                         pGrenade->SetAbsAngles( vec3_angle );
  1115.                                         DispatchSpawn( pGrenade );
  1116.                                         pGrenade->SetThrower( this );
  1117.                                         pGrenade->SetOwnerEntity( this );
  1118.                                                                                
  1119.                                         if ( i == 0 )
  1120.                                         {
  1121.                                                 pGrenade->SetSpitSize( SPIT_LARGE );
  1122.                                                 pGrenade->SetAbsVelocity( vecToss * flVelocity );
  1123.                                         }
  1124.                                         else
  1125.                                         {
  1126.                                                 pGrenade->SetAbsVelocity( ( vecToss + RandomVector( -0.035f, 0.035f ) ) * flVelocity );
  1127.                                                 pGrenade->SetSpitSize( random->RandomInt( SPIT_SMALL, SPIT_MEDIUM ) );
  1128.                                         }
  1129.  
  1130.                                         // Tumble through the air
  1131.                                         pGrenade->SetLocalAngularVelocity(
  1132.                                                 QAngle( random->RandomFloat( -250, -500 ),
  1133.                                                                 random->RandomFloat( -250, -500 ),
  1134.                                                                 random->RandomFloat( -250, -500 ) ) );
  1135.                                 }
  1136.  
  1137.                                 for ( int i = 0; i < 8; i++ )
  1138.                                 {
  1139.                                         DispatchParticleEffect( "blood_impact_yellow_01", vSpitPos + RandomVector( -12.0f, 12.0f ), RandomAngle( 0, 360 ) );
  1140.                                 }
  1141.  
  1142.                                 EmitSound( "NPC_fireantlion.PoisonShoot" );
  1143.                         }
  1144.                         return;
  1145.                 }
  1146.  
  1147.                 if ( pEvent->event == AE_fireantlion_WORKER_DONT_EXPLODE )
  1148.                 {
  1149.                         m_bDontExplode = true;
  1150.                         return;
  1151.                 }
  1152.  
  1153. #endif // HL2_EPISODIC
  1154.  
  1155.         if ( pEvent->Event() == AE_fireantlion_WALK_FOOTSTEP )
  1156.         {
  1157.                 MakeAIFootstepSound( 240.0f );
  1158.                 EmitSound( "NPC_fireantlion.Footstep", m_hFootstep, pEvent->eventtime );
  1159.                 return;
  1160.         }
  1161.  
  1162.         if ( pEvent->Event() == AE_fireantlion_MELEE_HIT1 )
  1163.         {
  1164.                 MeleeAttack( fireantlion_MELEE1_RANGE, sk_fireantlion_swipe_damage.GetFloat(), QAngle( 20.0f, 0.0f, -12.0f ), Vector( -250.0f, 1.0f, 1.0f ) );
  1165.                 return;
  1166.         }
  1167.  
  1168.         if ( pEvent->Event() == AE_fireantlion_MELEE_HIT2 )
  1169.         {
  1170.                 MeleeAttack( fireantlion_MELEE1_RANGE, sk_fireantlion_swipe_damage.GetFloat(), QAngle( 20.0f, 0.0f, 0.0f ), Vector( -350.0f, 1.0f, 1.0f ) );
  1171.                 return;
  1172.         }
  1173.  
  1174.         if ( pEvent->Event() == AE_fireantlion_MELEE_POUNCE )
  1175.         {
  1176.                 MeleeAttack( fireantlion_MELEE2_RANGE, sk_fireantlion_swipe_damage.GetFloat(), QAngle( 4.0f, 0.0f, 0.0f ), Vector( -250.0f, 1.0f, 1.0f ) );
  1177.                 return;
  1178.         }
  1179.                
  1180.         if (pEvent->Event() == AE_fireantlion_OPEN_WINGS )
  1181.         {
  1182.                 SetWings( true );
  1183.                 return;
  1184.         }
  1185.  
  1186.         if ( pEvent->Event() == AE_fireantlion_CLOSE_WINGS )
  1187.         {
  1188.                 SetWings( false );
  1189.                 return;
  1190.         }
  1191.  
  1192.         if ( pEvent->Event() == AE_fireantlion_VANISH )
  1193.         {
  1194.                 AddSolidFlags( FSOLID_NOT_SOLID );
  1195.                 m_takedamage    = DAMAGE_NO;
  1196.                 AddEffects( EF_NODRAW );
  1197.                 SetWings( false );
  1198.  
  1199.                 return;
  1200.         }
  1201.  
  1202.         if ( pEvent->Event() == AE_fireantlion_BURROW_IN )
  1203.         {
  1204.                 //Burrowing sound
  1205.                 EmitSound( "NPC_fireantlion.BurrowIn" );
  1206.  
  1207.                 //Shake the screen
  1208.                 UTIL_ScreenShake( GetAbsOrigin(), 0.5f, 80.0f, 1.0f, 256.0f, SHAKE_START );
  1209.  
  1210.                 //Throw dust up
  1211.                 CreateDust();
  1212.  
  1213.                 if ( GetHintNode() )
  1214.                 {
  1215.                         GetHintNode()->Unlock( 2.0f );
  1216.                 }
  1217.  
  1218.                 return;
  1219.         }
  1220.  
  1221.         if ( pEvent->Event() == AE_fireantlion_BURROW_OUT )
  1222.         {
  1223.                 EmitSound( "NPC_fireantlion.BurrowOut" );
  1224.  
  1225.                 //Shake the screen
  1226.                 UTIL_ScreenShake( GetAbsOrigin(), 0.5f, 80.0f, 1.0f, 256.0f, SHAKE_START );
  1227.  
  1228.                 //Throw dust up
  1229.                 CreateDust();
  1230.  
  1231.                 RemoveEffects( EF_NODRAW );
  1232.                 RemoveFlag( FL_NOTARGET );
  1233.  
  1234.                 return;
  1235.         }
  1236.  
  1237.         if ( pEvent->Event() == AE_fireantlion_FOOTSTEP_SOFT )
  1238.         {
  1239.                 EmitSound( "NPC_fireantlion.FootstepSoft", pEvent->eventtime );
  1240.                 return;
  1241.         }
  1242.  
  1243.         if ( pEvent->Event() == AE_fireantlion_FOOTSTEP_HEAVY )
  1244.         {
  1245.                 EmitSound( "NPC_fireantlion.FootstepHeavy", pEvent->eventtime );
  1246.                 return;
  1247.         }
  1248.        
  1249.        
  1250.         if ( pEvent->Event() == AE_fireantlion_MELEE1_SOUND )
  1251.         {
  1252.                 EmitSound( "NPC_fireantlion.MeleeAttackSingle" );
  1253.                 return;
  1254.         }
  1255.        
  1256.         if ( pEvent->Event() == AE_fireantlion_MELEE2_SOUND )
  1257.         {
  1258.                 EmitSound( "NPC_fireantlion.MeleeAttackDouble" );
  1259.                 return;
  1260.         }
  1261.  
  1262.         if ( pEvent->Event() == AE_fireantlion_START_JUMP )
  1263.         {
  1264.                 StartJump();
  1265.                 return;
  1266.         }
  1267.  
  1268.         // fireantlion worker events
  1269. #if HL2_EPISODIC
  1270.         if ( pEvent->event == AE_fireantlion_WORKER_EXPLODE_SCREAM )
  1271.         {
  1272.                 if ( GetWaterLevel() < 2 )
  1273.                 {
  1274.                         EmitSound( "NPC_fireantlion.PoisonBurstScream" );
  1275.                 }
  1276.                 else
  1277.                 {
  1278.                         EmitSound( "NPC_fireantlion.PoisonBurstScreamSubmerged" );
  1279.                 }
  1280.                 return;
  1281.         }
  1282.  
  1283.         if ( pEvent->event == AE_fireantlion_WORKER_EXPLODE_WARN )
  1284.         {
  1285.                 CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, GetAbsOrigin(), sk_fireantlion_worker_burst_radius.GetFloat(), 0.5f, this );
  1286.                 return;
  1287.         }
  1288.  
  1289.         if ( pEvent->event == AE_fireantlion_WORKER_EXPLODE )
  1290.         {
  1291.                 CTakeDamageInfo info( this, this, sk_fireantlion_worker_burst_damage.GetFloat(), DMG_BLAST_SURFACE | ( fireantlion_WORKER_BURST_IS_POISONOUS() ? DMG_POISON : DMG_ACID ) );
  1292.                 Event_Gibbed( info );
  1293.                 return;
  1294.         }
  1295. #endif
  1296.        
  1297.         BaseClass::HandleAnimEvent( pEvent );
  1298. }
  1299.  
  1300. bool CNPC_fireantlion::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
  1301. {
  1302.         bool iBaseReturn = BaseClass::IsUnusableNode( iNodeID, pHint );
  1303.  
  1304.         if ( g_test_new_fireantlion_jump.GetBool() == 0 )
  1305.                  return iBaseReturn;
  1306.  
  1307.         CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( iNodeID );
  1308.  
  1309.         if ( pNode )
  1310.         {
  1311.                 if ( pNode->IsLocked() )
  1312.                          return true;
  1313.         }
  1314.  
  1315.         return iBaseReturn;
  1316. }
  1317.  
  1318. void CNPC_fireantlion::LockJumpNode( void )
  1319. {
  1320.         if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == false )
  1321.                  return;
  1322.        
  1323.         if ( GetNavigator()->GetPath() == NULL )
  1324.                  return;
  1325.  
  1326.         if ( g_test_new_fireantlion_jump.GetBool() == false )
  1327.                  return;
  1328.  
  1329.         AI_Waypoint_t *pWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();
  1330.  
  1331.         while ( pWaypoint )
  1332.         {
  1333.                 AI_Waypoint_t *pNextWaypoint = pWaypoint->GetNext();
  1334.                 if ( pNextWaypoint && pNextWaypoint->NavType() == NAV_JUMP && pWaypoint->iNodeID != NO_NODE )
  1335.                 {
  1336.                         CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( pWaypoint->iNodeID );
  1337.  
  1338.                         if ( pNode )
  1339.                         {
  1340.                                 //NDebugOverlay::Box( pNode->GetOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 0, 0, 0, 2 );
  1341.                                 pNode->Lock( 0.5f );
  1342.                                 break;
  1343.                         }
  1344.                 }
  1345.                 else
  1346.                 {
  1347.                         pWaypoint = pWaypoint->GetNext();
  1348.                 }
  1349.         }
  1350. }
  1351.  
  1352. //-----------------------------------------------------------------------------
  1353. //-----------------------------------------------------------------------------
  1354. bool CNPC_fireantlion::OnObstructionPreSteer( AILocalMoveGoal_t *pMoveGoal, float distClear, AIMoveResult_t *pResult )
  1355. {
  1356.         bool iBaseReturn = BaseClass::OnObstructionPreSteer( pMoveGoal, distClear, pResult );
  1357.  
  1358.         if ( g_test_new_fireantlion_jump.GetBool() == false )
  1359.                  return iBaseReturn;
  1360.  
  1361.         if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) == false )
  1362.                  return iBaseReturn;
  1363.  
  1364.         CAI_BaseNPC *pBlocker = pMoveGoal->directTrace.pObstruction->MyNPCPointer();
  1365.  
  1366.         if ( pBlocker && pBlocker->Classify() == CLASS_fireantlion )
  1367.         {
  1368.                 // HACKHACK
  1369.                 CNPC_fireantlion *pfireantlion = dynamic_cast< CNPC_fireantlion * > ( pBlocker );
  1370.  
  1371.                 if ( pfireantlion )
  1372.                 {
  1373.                         if ( pfireantlion->AllowedToBePushed() == true && GetEnemy() == NULL )
  1374.                         {
  1375.                                 //NDebugOverlay::Box( pfireantlion->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 2 );
  1376.                                 pfireantlion->GetMotor()->SetIdealYawToTarget( WorldSpaceCenter() );
  1377.                                 pfireantlion->SetSchedule( SCHED_MOVE_AWAY );
  1378.                                 pfireantlion->m_flNextJumpPushTime = gpGlobals->curtime + 2.0f;
  1379.                         }
  1380.                 }
  1381.         }
  1382.  
  1383.         return iBaseReturn;
  1384. }
  1385.  
  1386. bool NPC_fireantlion_Isfireantlion( CBaseEntity *pEntity )
  1387. {
  1388.         CNPC_fireantlion *pfireantlion = dynamic_cast<CNPC_fireantlion *>(pEntity);
  1389.  
  1390.         return pfireantlion ? true : false;
  1391. }
  1392.  
  1393. class CTraceFilterfireantlion : public CTraceFilterEntitiesOnly
  1394. {
  1395. public:
  1396.         CTraceFilterfireantlion( const CBaseEntity *pEntity ) { m_pIgnore = pEntity; }
  1397.  
  1398.         virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  1399.         {
  1400.                 CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
  1401.  
  1402.                 if ( m_pIgnore == pEntity )
  1403.                          return false;
  1404.                
  1405.                 if ( pEntity->IsNPC() == false )
  1406.                          return false;
  1407.                
  1408.                 if ( NPC_fireantlion_Isfireantlion( pEntity ) )
  1409.                          return true;
  1410.                
  1411.                 return false;
  1412.         }
  1413. private:
  1414.        
  1415.         const CBaseEntity               *m_pIgnore;
  1416. };
  1417.  
  1418.  
  1419. //-----------------------------------------------------------------------------
  1420. // Purpose:  
  1421. //-----------------------------------------------------------------------------
  1422. void CNPC_fireantlion::StartTask( const Task_t *pTask )
  1423. {
  1424.         switch ( pTask->iTask )
  1425.         {
  1426.         case TASK_fireantlion_FIND_COVER_FROM_SAVEPOSITION:
  1427.                 {
  1428.                         Vector coverPos;
  1429.  
  1430.                         if ( GetTacticalServices()->FindCoverPos( m_vSavePosition, EyePosition(), 0, CoverRadius(), &coverPos ) )
  1431.                         {
  1432.                                 AI_NavGoal_t goal(coverPos, ACT_RUN, AIN_HULL_TOLERANCE);
  1433.                                 GetNavigator()->SetGoal( goal );
  1434.  
  1435.                                 m_flMoveWaitFinished = gpGlobals->curtime + pTask->flTaskData;
  1436.                         }
  1437.                         else
  1438.                         {
  1439.                                 // no coverwhatsoever.
  1440.                                 TaskFail(FAIL_NO_COVER);
  1441.                         }
  1442.                 }
  1443.                 break;
  1444.  
  1445.         case TASK_ANNOUNCE_ATTACK:
  1446.                 {
  1447.                         EmitSound( "NPC_fireantlion.MeleeAttackSingle" );
  1448.                         TaskComplete();
  1449.                         break;
  1450.                 }
  1451.  
  1452.         case TASK_fireantlion_FACE_JUMP:
  1453.                 break;
  1454.  
  1455.         case TASK_fireantlion_DROWN:
  1456.         {
  1457.                 // Set the gravity really low here! Sink slowly
  1458.                 SetGravity( 0 );
  1459.                 SetAbsVelocity( vec3_origin );
  1460.                 m_flTimeDrownSplash = gpGlobals->curtime + random->RandomFloat( 0, 0.5 );
  1461.                 m_flTimeDrown = gpGlobals->curtime + 4;
  1462.                 break;
  1463.         }
  1464.  
  1465.         case TASK_fireantlion_REACH_FIGHT_GOAL:
  1466.  
  1467.                 m_OnReachFightGoal.FireOutput( this, this );
  1468.                 TaskComplete();
  1469.                 break;
  1470.  
  1471.         case TASK_fireantlion_DISMOUNT_NPC:
  1472.                 {
  1473.                         CBaseEntity *pGroundEnt = GetGroundEntity();
  1474.                        
  1475.                         if( pGroundEnt != NULL )
  1476.                         {
  1477.                                 trace_t trace;
  1478.                                 CTraceFilterfireantlion traceFilter( this );
  1479.                                 AI_TraceHull( GetAbsOrigin(), GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs(), MASK_SOLID, &traceFilter, &trace );
  1480.  
  1481.                                 if ( trace.m_pEnt )
  1482.                                 {
  1483.                                         m_bDontExplode = true;
  1484.                                         OnTakeDamage( CTakeDamageInfo( this, this, m_iHealth+1, DMG_GENERIC ) );
  1485.                                         return;
  1486.                                 }
  1487.  
  1488.                                 // Jump behind the other NPC so I don't block their path.
  1489.                                 Vector vecJumpDir;
  1490.  
  1491.                                 pGroundEnt->GetVectors( &vecJumpDir, NULL, NULL );
  1492.  
  1493.                                 SetGroundEntity( NULL );
  1494.                                
  1495.                                 // Bump up
  1496.                                 UTIL_SetOrigin( this, GetAbsOrigin() + Vector( 0, 0 , 1 ) );
  1497.                                
  1498.                                 SetAbsVelocity( vecJumpDir * -200 + Vector( 0, 0, 100 ) );
  1499.  
  1500.                                 // Doing ACT_RESET first assures they play the animation, even when in transition
  1501.                                 ResetActivity();
  1502.                                 SetActivity( (Activity) ACT_fireantlion_FLIP );
  1503.                         }
  1504.                         else
  1505.                         {
  1506.                                 // Dead or gone now
  1507.                                 TaskComplete();
  1508.                         }
  1509.                 }
  1510.  
  1511.                 break;
  1512.  
  1513.         case TASK_fireantlion_FACE_BUGBAIT:
  1514.                        
  1515.                 //Must have a saved sound
  1516.                 //FIXME: This isn't assured to be still pointing to the right place, need to protect this
  1517.                 if ( !m_bHasHeardSound )
  1518.                 {
  1519.                         TaskFail( "No remembered bug bait sound to run to!" );
  1520.                         return;
  1521.                 }
  1522.  
  1523.                 GetMotor()->SetIdealYawToTargetAndUpdate( m_vecHeardSound );
  1524.                 SetTurnActivity();
  1525.  
  1526.                 break;
  1527.        
  1528.         case TASK_fireantlion_GET_PATH_TO_BUGBAIT:
  1529.                 {
  1530.                         //Must have a saved sound
  1531.                         //FIXME: This isn't assured to be still pointing to the right place, need to protect this
  1532.                         if ( !m_bHasHeardSound )
  1533.                         {
  1534.                                 TaskFail( "No remembered bug bait sound to run to!" );
  1535.                                 return;
  1536.                         }
  1537.                        
  1538.                         Vector  goalPos;
  1539.  
  1540.                         // Find the position to chase to
  1541.                         if ( FindChasePosition( m_vecHeardSound, goalPos ) )
  1542.                         {
  1543.                                 AI_NavGoal_t goal( goalPos, (Activity) ACT_fireantlion_RUN_AGITATED, fireantlion_BUGBAIT_NAV_TOLERANCE );
  1544.                                
  1545.                                 //Try to run directly there
  1546.                                 if ( GetNavigator()->SetGoal( goal, AIN_DISCARD_IF_FAIL ) == false )
  1547.                                 {
  1548.                                         //Try and get as close as possible otherwise
  1549.                                         AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, goalPos, (Activity) ACT_fireantlion_RUN_AGITATED, fireantlion_BUGBAIT_NAV_TOLERANCE );
  1550.  
  1551.                                         if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) )
  1552.                                         {
  1553.                                                 //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it!
  1554.                                                 ClearCondition( COND_TASK_FAILED );
  1555.  
  1556.                                                 LockJumpNode();
  1557.                                                 TaskComplete();
  1558.                                                 return;
  1559.                                         }
  1560.                                         else
  1561.                                         {
  1562.                                                 TaskFail( "fireantlion failed to find path to bugbait position\n" );
  1563.                                                 return;
  1564.                                         }
  1565.                                 }
  1566.                                 else
  1567.                                 {
  1568.                                         LockJumpNode();
  1569.                                         TaskComplete();
  1570.                                         return;
  1571.                                 }
  1572.                         }
  1573.  
  1574.                         TaskFail( "fireantlion failed to find path to bugbait position\n" );
  1575.                         break;
  1576.                 }
  1577.  
  1578.         case TASK_fireantlion_WAIT_FOR_TRIGGER:
  1579.                 m_flIdleDelay = gpGlobals->curtime + 1.0f;
  1580.  
  1581.                 break;
  1582.  
  1583.         case TASK_fireantlion_JUMP:
  1584.                
  1585.                 if ( CheckLanding() )
  1586.                 {
  1587.                         TaskComplete();
  1588.                 }
  1589.  
  1590.                 break;
  1591.  
  1592.         case TASK_fireantlion_CHECK_FOR_UNBORROW:
  1593.                
  1594.                 m_iUnBurrowAttempts = 0;
  1595.  
  1596.                 if ( ValidBurrowPoint( GetAbsOrigin() ) )
  1597.                 {
  1598.                         m_spawnflags &= ~SF_NPC_GAG;
  1599.                         RemoveSolidFlags( FSOLID_NOT_SOLID );
  1600.                         TaskComplete();
  1601.                 }
  1602.  
  1603.                 break;
  1604.  
  1605.         case TASK_fireantlion_BURROW_WAIT:
  1606.                
  1607.                 if ( pTask->flTaskData == 1.0f )
  1608.                 {
  1609.                         //Set our next burrow time
  1610.                         m_flBurrowTime = gpGlobals->curtime + random->RandomFloat( 1, 6 );
  1611.                 }
  1612.  
  1613.                 break;
  1614.  
  1615.         case TASK_fireantlion_FIND_BURROW_IN_POINT:
  1616.                
  1617.                 if ( FindBurrow( GetAbsOrigin(), pTask->flTaskData, fireantlion_BURROW_IN ) == false )
  1618.                 {
  1619.                         TaskFail( "TASK_fireantlion_FIND_BURROW_IN_POINT: Unable to find burrow in position\n" );
  1620.                 }
  1621.                 else
  1622.                 {
  1623.                         TaskComplete();
  1624.                 }
  1625.  
  1626.                 break;
  1627.  
  1628.         case TASK_fireantlion_FIND_BURROW_OUT_POINT:
  1629.                
  1630.                 if ( FindBurrow( GetAbsOrigin(), pTask->flTaskData, fireantlion_BURROW_OUT ) == false )
  1631.                 {
  1632.                         TaskFail( "TASK_fireantlion_FIND_BURROW_OUT_POINT: Unable to find burrow out position\n" );
  1633.                 }
  1634.                 else
  1635.                 {
  1636.                         TaskComplete();
  1637.                 }
  1638.  
  1639.                 break;
  1640.  
  1641.         case TASK_fireantlion_BURROW:
  1642.                 Burrow();
  1643.                 TaskComplete();
  1644.  
  1645.                 break;
  1646.  
  1647.         case TASK_fireantlion_UNBURROW:
  1648.                 Unburrow();
  1649.                 TaskComplete();
  1650.  
  1651.                 break;
  1652.  
  1653.         case TASK_fireantlion_VANISH:
  1654.                 AddEffects( EF_NODRAW );
  1655.                 AddFlag( FL_NOTARGET );
  1656.                 m_spawnflags |= SF_NPC_GAG;
  1657.                
  1658.                 // If the task parameter is non-zero, remove us when we vanish
  1659.                 if ( pTask->flTaskData )
  1660.                 {
  1661.                         CBaseEntity *pOwner = GetOwnerEntity();
  1662.                        
  1663.                         if( pOwner != NULL )
  1664.                         {
  1665.                                 pOwner->DeathNotice( this );
  1666.                                 SetOwnerEntity( NULL );
  1667.                         }
  1668.  
  1669.                         // NOTE: We can't UTIL_Remove here, because we're in the middle of running our AI, and
  1670.                         //               we'll crash later in the bowels of the AI. Remove ourselves next frame.
  1671.                         SetThink( &CNPC_fireantlion::SUB_Remove );
  1672.                         SetNextThink( gpGlobals->curtime + 0.1 );
  1673.                 }
  1674.  
  1675.                 TaskComplete();
  1676.  
  1677.                 break;
  1678.  
  1679.         case TASK_fireantlion_GET_THUMPER_ESCAPE_PATH:
  1680.                 {
  1681.                         if ( GetPathToSoundFleePoint( SOUND_THUMPER ) )                
  1682.                         {
  1683.                                 TaskComplete();
  1684.                         }
  1685.                         else
  1686.                         {
  1687.                                 TaskFail( FAIL_NO_REACHABLE_NODE );
  1688.                         }
  1689.                 }
  1690.                
  1691.                 break;
  1692.  
  1693.         case TASK_fireantlion_GET_PHYSICS_DANGER_ESCAPE_PATH:
  1694.                 {
  1695.                         if ( GetPathToSoundFleePoint( SOUND_PHYSICS_DANGER ) )
  1696.                         {
  1697.                                 TaskComplete();
  1698.                         }
  1699.                         else
  1700.                         {
  1701.                                 TaskFail( FAIL_NO_REACHABLE_NODE );
  1702.                         }
  1703.                 }
  1704.                
  1705.                 break;
  1706.  
  1707.  
  1708.         default:
  1709.                 BaseClass::StartTask( pTask );
  1710.                 break;
  1711.         }
  1712. }
  1713.  
  1714. //-----------------------------------------------------------------------------
  1715. // Purpose:
  1716. // Input  : *pTask -
  1717. //-----------------------------------------------------------------------------
  1718. void CNPC_fireantlion::RunTask( const Task_t *pTask )
  1719. {
  1720.         // some state that needs be set each frame
  1721. #if HL2_EPISODIC
  1722.         if ( GetFlags() & FL_ONGROUND )
  1723.         {
  1724.                 m_bHasDoneAirAttack = false;
  1725.         }
  1726. #endif
  1727.  
  1728.         switch ( pTask->iTask )
  1729.         {
  1730.         case TASK_fireantlion_FACE_JUMP:
  1731.                 {
  1732.                         Vector  jumpDir = m_vecSavedJump;
  1733.                         VectorNormalize( jumpDir );
  1734.                        
  1735.                         QAngle  jumpAngles;
  1736.                         VectorAngles( jumpDir, jumpAngles );
  1737.  
  1738.                         GetMotor()->SetIdealYawAndUpdate( jumpAngles[YAW], AI_KEEP_YAW_SPEED );
  1739.                         SetTurnActivity();
  1740.                        
  1741.                         if ( GetMotor()->DeltaIdealYaw() < 2 )
  1742.                         {
  1743.                                 TaskComplete();
  1744.                         }
  1745.                 }
  1746.  
  1747.                 break;
  1748.  
  1749.         case TASK_fireantlion_DROWN:
  1750.         {
  1751.                 if ( gpGlobals->curtime > m_flTimeDrownSplash )
  1752.                 {
  1753.                         float flWaterZ = UTIL_FindWaterSurface( GetAbsOrigin(), GetAbsOrigin().z, GetAbsOrigin().z + NAI_Hull::Maxs( GetHullType() ).z );
  1754.  
  1755.                         CEffectData     data;
  1756.                         data.m_fFlags = 0;
  1757.                         data.m_vOrigin = GetAbsOrigin();
  1758.                         data.m_vOrigin.z = flWaterZ;
  1759.                         data.m_vNormal = Vector( 0, 0, 1 );
  1760.                         data.m_flScale = random->RandomFloat( 12.0, 16.0 );
  1761.  
  1762.                         DispatchEffect( "watersplash", data );
  1763.                        
  1764.                         m_flTimeDrownSplash = gpGlobals->curtime + random->RandomFloat( 0.5, 2.5 );
  1765.                 }
  1766.        
  1767.                 if ( gpGlobals->curtime > m_flTimeDrown )
  1768.                 {
  1769.                         m_bDontExplode = true;
  1770.                         OnTakeDamage( CTakeDamageInfo( this, this, m_iHealth+1, DMG_DROWN ) );
  1771.                         TaskComplete();
  1772.                 }
  1773.                 break;
  1774.         }
  1775.  
  1776.         case TASK_fireantlion_REACH_FIGHT_GOAL:
  1777.                 break;
  1778.  
  1779.         case TASK_fireantlion_DISMOUNT_NPC:
  1780.                
  1781.                 if ( GetFlags() & FL_ONGROUND )
  1782.                 {
  1783.                         CBaseEntity *pGroundEnt = GetGroundEntity();
  1784.  
  1785.                         if ( ( pGroundEnt != NULL ) && ( ( pGroundEnt->MyNPCPointer() != NULL ) || pGroundEnt->GetSolidFlags() & FSOLID_NOT_STANDABLE ) )
  1786.                         {
  1787.                                 // Jump behind the other NPC so I don't block their path.
  1788.                                 Vector vecJumpDir;
  1789.  
  1790.                                 pGroundEnt->GetVectors( &vecJumpDir, NULL, NULL );
  1791.  
  1792.                                 SetGroundEntity( NULL );       
  1793.                                
  1794.                                 // Bump up
  1795.                                 UTIL_SetOrigin( this, GetAbsOrigin() + Vector( 0, 0 , 1 ) );
  1796.                                
  1797.                                 Vector vecRandom = RandomVector( -250.0f, 250.0f );
  1798.                                 vecRandom[2] = random->RandomFloat( 100.0f, 200.0f );
  1799.                                 SetAbsVelocity( vecRandom );
  1800.  
  1801.                                 // Doing ACT_RESET first assures they play the animation, even when in transition
  1802.                                 ResetActivity();
  1803.                                 SetActivity( (Activity) ACT_fireantlion_FLIP );
  1804.                         }
  1805.                         else if ( IsActivityFinished() )
  1806.                         {
  1807.                                 TaskComplete();
  1808.                         }
  1809.                 }
  1810.                
  1811.                 break;
  1812.  
  1813.         case TASK_fireantlion_FACE_BUGBAIT:
  1814.                        
  1815.                 //Must have a saved sound
  1816.                 //FIXME: This isn't assured to be still pointing to the right place, need to protect this
  1817.                 if ( !m_bHasHeardSound )
  1818.                 {
  1819.                         TaskFail( "No remembered bug bait sound to run to!" );
  1820.                         return;
  1821.                 }
  1822.  
  1823.                 GetMotor()->SetIdealYawToTargetAndUpdate( m_vecHeardSound );
  1824.  
  1825.                 if ( FacingIdeal() )
  1826.                 {
  1827.                         TaskComplete();
  1828.                 }
  1829.  
  1830.                 break;
  1831.  
  1832.         case TASK_fireantlion_WAIT_FOR_TRIGGER:
  1833.                
  1834.                 if ( ( m_flIdleDelay > gpGlobals->curtime ) || GetEntityName() != NULL_STRING )
  1835.                         return;
  1836.  
  1837.                 TaskComplete();
  1838.  
  1839.                 break;
  1840.  
  1841.         case TASK_fireantlion_JUMP:
  1842.  
  1843.                 if ( CheckLanding() )
  1844.                 {
  1845.                         TaskComplete();
  1846.                 }
  1847.  
  1848.                 break;
  1849.  
  1850.         case TASK_fireantlion_CHECK_FOR_UNBORROW:
  1851.                
  1852.                 //Must wait for our next check time
  1853.                 if ( m_flBurrowTime > gpGlobals->curtime )
  1854.                         return;
  1855.  
  1856.                 //See if we can pop up
  1857.                 if ( ValidBurrowPoint( GetAbsOrigin() ) )
  1858.                 {
  1859.                         m_spawnflags &= ~SF_NPC_GAG;
  1860.                         RemoveSolidFlags( FSOLID_NOT_SOLID );
  1861.  
  1862.                         TaskComplete();
  1863.                         return;
  1864.                 }
  1865.  
  1866.                 //Try again in a couple of seconds
  1867.                 m_flBurrowTime = gpGlobals->curtime + random->RandomFloat( 0.5f, 1.0f );
  1868.                 m_iUnBurrowAttempts++;
  1869.  
  1870.                 // Robin: If we fail 10 times, kill ourself.
  1871.                 // This deals with issues where the game relies out fireantlion spawners
  1872.                 // firing their OnBlocked output, but the spawner isn't attempting to
  1873.                 // spawn because it has multiple live children lying around stuck under
  1874.                 // physics props unable to unburrow.
  1875.                 if ( m_iUnBurrowAttempts >= 10 )
  1876.                 {
  1877.                         m_bDontExplode = true;
  1878.                         m_takedamage = DAMAGE_YES;
  1879.                         OnTakeDamage( CTakeDamageInfo( this, this, m_iHealth+1, DMG_GENERIC ) );
  1880.                 }
  1881.  
  1882.                 break;
  1883.  
  1884.         case TASK_fireantlion_BURROW_WAIT:
  1885.                
  1886.                 //See if enough time has passed
  1887.                 if ( m_flBurrowTime < gpGlobals->curtime )
  1888.                 {
  1889.                         TaskComplete();
  1890.                 }
  1891.                
  1892.                 break;
  1893.  
  1894.         default:
  1895.                 BaseClass::RunTask( pTask );
  1896.                 break;
  1897.         }
  1898. }
  1899.  
  1900. bool CNPC_fireantlion::AllowedToBePushed( void )
  1901. {
  1902.         if ( IsCurSchedule( SCHED_fireantlion_BURROW_WAIT ) ||
  1903.                 IsCurSchedule(SCHED_fireantlion_BURROW_IN) ||
  1904.                 IsCurSchedule(SCHED_fireantlion_BURROW_OUT) ||
  1905.                 IsCurSchedule(SCHED_fireantlion_BURROW_AWAY ) ||
  1906.                 IsCurSchedule( SCHED_fireantlion_RUN_TO_FIGHT_GOAL ) )
  1907.                 return false;
  1908.  
  1909.         if ( IsRunningDynamicInteraction() )
  1910.                 return false;
  1911.  
  1912.         if ( IsMoving() == false && IsCurSchedule( SCHED_fireantlion_FLIP ) == false
  1913.                  && GetNavType() != NAV_JUMP && m_flNextJumpPushTime <= gpGlobals->curtime )
  1914.         {
  1915.                 return true;
  1916.         }
  1917.  
  1918.         return false;
  1919. }
  1920.  
  1921. //-----------------------------------------------------------------------------
  1922. // Purpose: Returns true if a reasonable jumping distance
  1923. // Input  :
  1924. // Output :
  1925. //-----------------------------------------------------------------------------
  1926. bool CNPC_fireantlion::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const
  1927. {
  1928.         const float MAX_JUMP_RISE               = 512;
  1929.         const float MAX_JUMP_DROP               = 512;
  1930.         const float MAX_JUMP_DISTANCE   = 1024;
  1931.         const float MIN_JUMP_DISTANCE   = 128;
  1932.  
  1933.         if ( CfireantlionRepellant::IsPositionRepellantFree( endPos ) == false )
  1934.                  return false;
  1935.        
  1936.         //Adrian: Don't try to jump if my destination is right next to me.
  1937.         if ( ( endPos - GetAbsOrigin()).Length() < MIN_JUMP_DISTANCE )
  1938.                  return false;
  1939.  
  1940.         if ( HasSpawnFlags( SF_fireantlion_USE_GROUNDCHECKS ) && g_test_new_fireantlion_jump.GetBool() == true )
  1941.         {
  1942.                 trace_t tr;
  1943.                 AI_TraceHull( endPos, endPos, GetHullMins(), GetHullMaxs(), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
  1944.                
  1945.                 if ( tr.m_pEnt )
  1946.                 {
  1947.                         CAI_BaseNPC *pBlocker = tr.m_pEnt->MyNPCPointer();
  1948.  
  1949.                         if ( pBlocker && pBlocker->Classify() == CLASS_fireantlion )
  1950.                         {
  1951.                                 // HACKHACK
  1952.                                 CNPC_fireantlion *pfireantlion = dynamic_cast< CNPC_fireantlion * > ( pBlocker );
  1953.  
  1954.                                 if ( pfireantlion )
  1955.                                 {
  1956.                                         if ( pfireantlion->AllowedToBePushed() == true )
  1957.                                         {
  1958.                                         //      NDebugOverlay::Line( GetAbsOrigin(), endPos, 255, 0, 0, 0, 2 );
  1959.                                         //      NDebugOverlay::Box( pfireantlion->GetAbsOrigin(), GetHullMins(), GetHullMaxs(), 0, 0, 255, 0, 2 );
  1960.                                                 pfireantlion->GetMotor()->SetIdealYawToTarget( endPos );
  1961.                                                 pfireantlion->SetSchedule( SCHED_MOVE_AWAY );
  1962.                                                 pfireantlion->m_flNextJumpPushTime = gpGlobals->curtime + 2.0f;
  1963.                                         }
  1964.                                 }
  1965.                         }
  1966.                 }
  1967.         }
  1968.  
  1969.         return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE );
  1970. }
  1971.  
  1972. bool CNPC_fireantlion::IsFirmlyOnGround( void )
  1973. {
  1974.         if( !( GetFlags()&FL_ONGROUND ) )
  1975.                 return false;
  1976.  
  1977.         trace_t tr;
  1978.  
  1979.         float flHeight =  fabs( GetHullMaxs().z - GetHullMins().z );
  1980.        
  1981.         Vector vOrigin = GetAbsOrigin() + Vector( GetHullMins().x, GetHullMins().y, 0 );
  1982. //      NDebugOverlay::Line( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), 255, 0, 0, true, 5 );
  1983.         UTIL_TraceLine( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );
  1984.  
  1985.         if ( tr.fraction != 1.0f )
  1986.                  return true;
  1987.        
  1988.         vOrigin = GetAbsOrigin() - Vector( GetHullMins().x, GetHullMins().y, 0 );
  1989. //      NDebugOverlay::Line( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), 255, 0, 0, true, 5 );
  1990.         UTIL_TraceLine( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );
  1991.  
  1992.         if ( tr.fraction != 1.0f )
  1993.                  return true;
  1994.  
  1995.         vOrigin = GetAbsOrigin() + Vector( GetHullMins().x, -GetHullMins().y, 0 );
  1996. //      NDebugOverlay::Line( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), 255, 0, 0, true, 5 );
  1997.         UTIL_TraceLine( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );
  1998.  
  1999.         if ( tr.fraction != 1.0f )
  2000.                  return true;
  2001.  
  2002.         vOrigin = GetAbsOrigin() + Vector( -GetHullMins().x, GetHullMins().y, 0 );
  2003. //      NDebugOverlay::Line( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), 255, 0, 0, true, 5 );
  2004.         UTIL_TraceLine( vOrigin, vOrigin - Vector( 0, 0, flHeight * 0.5  ), MASK_NPCSOLID, this, GetCollisionGroup(), &tr );
  2005.  
  2006.         if ( tr.fraction != 1.0f )
  2007.                  return true;
  2008.        
  2009.         return false;
  2010. }
  2011.  
  2012. //-----------------------------------------------------------------------------
  2013. // Purpose:
  2014. //-----------------------------------------------------------------------------
  2015. int CNPC_fireantlion::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode )
  2016. {
  2017.         if ( m_FollowBehavior.GetNumFailedFollowAttempts() >= 2 )
  2018.         {
  2019.                 if( IsFirmlyOnGround() == false )
  2020.                 {
  2021.                         Vector vecJumpDir;
  2022.                                
  2023.                         vecJumpDir.z = 0;
  2024.                         vecJumpDir.x = 0;
  2025.                         vecJumpDir.y = 0;
  2026.                        
  2027.                         while( vecJumpDir.x == 0 && vecJumpDir.y == 0 )
  2028.                         {
  2029.                                 vecJumpDir.x = random->RandomInt( -1, 1 );
  2030.                                 vecJumpDir.y = random->RandomInt( -1, 1 );
  2031.                         }
  2032.  
  2033.                         vecJumpDir.NormalizeInPlace();
  2034.  
  2035.                         SetGroundEntity( NULL );
  2036.        
  2037.                         m_vecSavedJump = vecJumpDir * 512 + Vector( 0, 0, 256 );
  2038.                         m_bForcedStuckJump = true;
  2039.        
  2040.                         return SCHED_fireantlion_JUMP;
  2041.                 }
  2042.         }
  2043.  
  2044.         // Catch the LOF failure and choose another route to take
  2045.         if ( failedSchedule == SCHED_ESTABLISH_LINE_OF_FIRE )
  2046.                 return SCHED_fireantlion_WORKER_FLANK_RANDOM;
  2047.  
  2048.         return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode );
  2049. }
  2050.  
  2051. //-----------------------------------------------------------------------------
  2052. // Purpose:
  2053. // Output : Returns true on success, false on failure.
  2054. //-----------------------------------------------------------------------------
  2055. bool CNPC_fireantlion::ShouldJump( void )
  2056. {
  2057.         if ( GetEnemy() == NULL )
  2058.                 return false;
  2059.  
  2060.         //Too soon to try to jump
  2061.         if ( m_flJumpTime > gpGlobals->curtime )
  2062.                 return false;
  2063.  
  2064.         // only jump if you're on the ground
  2065.         if (!(GetFlags() & FL_ONGROUND) || GetNavType() == NAV_JUMP )
  2066.                 return false;
  2067.  
  2068.         // Don't jump if I'm not allowed
  2069.         if ( ( CapabilitiesGet() & bits_CAP_MOVE_JUMP ) == false )
  2070.                 return false;
  2071.  
  2072.         Vector vEnemyForward, vForward;
  2073.  
  2074.         GetEnemy()->GetVectors( &vEnemyForward, NULL, NULL );
  2075.         GetVectors( &vForward, NULL, NULL );
  2076.  
  2077.         float flDot = DotProduct( vForward, vEnemyForward );
  2078.  
  2079.         if ( flDot < 0.5f )
  2080.                  flDot = 0.5f;
  2081.  
  2082.         Vector vecPredictedPos;
  2083.  
  2084.         //Get our likely position in two seconds
  2085.         UTIL_PredictedPosition( GetEnemy(), flDot * 2.5f, &vecPredictedPos );
  2086.  
  2087.         // Don't jump if we're already near the target
  2088.         if ( ( GetAbsOrigin() - vecPredictedPos ).LengthSqr() < (512*512) )
  2089.                 return false;
  2090.  
  2091.         //Don't retest if the target hasn't moved enough
  2092.         //FIXME: Check your own distance from last attempt as well
  2093.         if ( ( ( m_vecLastJumpAttempt - vecPredictedPos ).LengthSqr() ) < (128*128) )
  2094.         {
  2095.                 m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );         
  2096.                 return false;
  2097.         }
  2098.  
  2099.         Vector  targetDir = ( vecPredictedPos - GetAbsOrigin() );
  2100.  
  2101.         float flDist = VectorNormalize( targetDir );
  2102.  
  2103.         // don't jump at target it it's very close
  2104.         if (flDist < fireantlion_JUMP_MIN)
  2105.                 return false;
  2106.  
  2107.         Vector  targetPos = vecPredictedPos + ( targetDir * (GetHullWidth()*4.0f) );
  2108.  
  2109.         if ( CfireantlionRepellant::IsPositionRepellantFree( targetPos ) == false )
  2110.                  return false;
  2111.  
  2112.         // Try the jump
  2113.         AIMoveTrace_t moveTrace;
  2114.         GetMoveProbe()->MoveLimit( NAV_JUMP, GetAbsOrigin(), targetPos, MASK_NPCSOLID, GetNavTargetEntity(), &moveTrace );
  2115.  
  2116.         //See if it succeeded
  2117.         if ( IsMoveBlocked( moveTrace.fStatus ) )
  2118.         {
  2119.                 if ( g_debug_fireantlion.GetInt() == 2 )
  2120.                 {
  2121.                         NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 255, 0, 0, 0, 5 );
  2122.                         NDebugOverlay::Line( GetAbsOrigin(), targetPos, 255, 0, 0, 0, 5 );
  2123.                 }
  2124.  
  2125.                 m_flJumpTime = gpGlobals->curtime + random->RandomFloat( 1.0f, 2.0f );
  2126.                 return false;
  2127.         }
  2128.  
  2129.         if ( g_debug_fireantlion.GetInt() == 2 )
  2130.         {
  2131.                 NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
  2132.                 NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 );
  2133.         }
  2134.  
  2135.         //Save this jump in case the next time fails
  2136.         m_vecSavedJump = moveTrace.vJumpVelocity;
  2137.         m_vecLastJumpAttempt = targetPos;
  2138.  
  2139.         return true;
  2140. }
  2141.  
  2142. //-----------------------------------------------------------------------------
  2143. //-----------------------------------------------------------------------------
  2144. int CNPC_fireantlion::TranslateSchedule( int scheduleType )
  2145. {
  2146.         if ( ( m_hFollowTarget != NULL ) || IsAllied() )
  2147.         {
  2148.                 if ( ( scheduleType == SCHED_IDLE_STAND ) || ( scheduleType == SCHED_ALERT_STAND ) )
  2149.                         return SCHED_fireantlion_BUGBAIT_IDLE_STAND;
  2150.         }
  2151.  
  2152.         return BaseClass::TranslateSchedule( scheduleType );
  2153. }
  2154.  
  2155. //-----------------------------------------------------------------------------
  2156. //-----------------------------------------------------------------------------
  2157. Activity CNPC_fireantlion::NPC_TranslateActivity( Activity baseAct )
  2158. {
  2159.         // Workers explode as long as they didn't drown.
  2160.         if ( IsWorker() && ( baseAct == ACT_DIESIMPLE ) && !m_bDontExplode )
  2161.         {
  2162.                 return ( Activity )ACT_fireantlion_WORKER_EXPLODE;
  2163.         }
  2164.  
  2165.         return BaseClass::NPC_TranslateActivity( baseAct );
  2166. }
  2167.  
  2168. //-----------------------------------------------------------------------------
  2169. // Purpose:
  2170. // Output : int
  2171. //-----------------------------------------------------------------------------
  2172. int CNPC_fireantlion::ChooseMoveSchedule( void )
  2173. {
  2174.         // See if we need to invalidate our fight goal
  2175.         if ( ShouldResumeFollow() )
  2176.         {
  2177.                 // Set us back to following
  2178.                 SetMoveState( fireantlion_MOVE_FOLLOW );
  2179.  
  2180.                 // Tell our parent that we've swapped modes
  2181.                 CAntlionTemplateMaker *pMaker = dynamic_cast<CAntlionTemplateMaker *>(GetOwnerEntity());
  2182.  
  2183.                 if ( pMaker != NULL )
  2184.                 {
  2185.                         pMaker->SetChildMoveState( ANTLION_MOVE_FOLLOW );
  2186.                 }
  2187.         }
  2188.  
  2189.         // Figure out our move state
  2190.         switch( m_MoveState )
  2191.         {
  2192.         case fireantlion_MOVE_FREE:
  2193.                 return SCHED_NONE;      // Let the base class handle us
  2194.                 break;
  2195.  
  2196.         // Fighting to a position
  2197.         case fireantlion_MOVE_FIGHT_TO_GOAL:
  2198.                 {
  2199.                         if ( m_hFightGoalTarget )
  2200.                         {
  2201.                                 float targetDist = UTIL_DistApprox( WorldSpaceCenter(), m_hFightGoalTarget->GetAbsOrigin() );
  2202.  
  2203.                                 if ( targetDist > 256 )
  2204.                                 {
  2205.                                         Vector testPos;
  2206.                                         Vector targetPos = ( m_hFightGoalTarget ) ? m_hFightGoalTarget->GetAbsOrigin() : m_vSavePosition;
  2207.  
  2208.                                         // Find a suitable chase position
  2209.                                         if ( FindChasePosition( targetPos, testPos ) )
  2210.                                         {
  2211.                                                 m_vSavePosition = testPos;
  2212.                                                 return SCHED_fireantlion_RUN_TO_FIGHT_GOAL;
  2213.                                         }
  2214.                                 }
  2215.                         }
  2216.                 }
  2217.                 break;
  2218.  
  2219.         // Following a goal
  2220.         case fireantlion_MOVE_FOLLOW:
  2221.                 {
  2222.                         if ( m_FollowBehavior.CanSelectSchedule() )
  2223.                         {
  2224.                                 // See if we should burrow away if our target it too far off
  2225.                                 if ( ShouldAbandonFollow() )
  2226.                                         return SCHED_fireantlion_BURROW_AWAY;
  2227.  
  2228.                                 DeferSchedulingToBehavior( &m_FollowBehavior );
  2229.                                 return BaseClass::SelectSchedule();
  2230.                         }
  2231.                 }
  2232.                 break;
  2233.         }
  2234.  
  2235.         return SCHED_NONE;
  2236. }
  2237.  
  2238. //-----------------------------------------------------------------------------
  2239. // Purpose:
  2240. //-----------------------------------------------------------------------------
  2241. void CNPC_fireantlion::ZapThink( void )
  2242. {
  2243.         CEffectData     data;
  2244.         data.m_nEntIndex = entindex();
  2245.         data.m_flMagnitude = 4;
  2246.         data.m_flScale = random->RandomFloat( 0.25f, 1.0f );
  2247.  
  2248.         DispatchEffect( "TeslaHitboxes", data );
  2249.        
  2250.         if ( m_flZapDuration > gpGlobals->curtime )
  2251.         {
  2252.                 SetContextThink( &CNPC_fireantlion::ZapThink, gpGlobals->curtime + random->RandomFloat( 0.05f, 0.25f ), "ZapThink" );
  2253.         }
  2254.         else
  2255.         {
  2256.                 SetContextThink( NULL, gpGlobals->curtime, "ZapThink" );
  2257.         }
  2258. }
  2259.  
  2260. //-----------------------------------------------------------------------------
  2261. // Purpose:
  2262. // Output : int
  2263. //-----------------------------------------------------------------------------
  2264. int CNPC_fireantlion::SelectSchedule( void )
  2265. {
  2266.         // Workers explode when killed unless told otherwise by anim events etc.
  2267.         m_bDontExplode = false;
  2268.  
  2269.         // Clear out this condition
  2270.         ClearCondition( COND_fireantlion_RECEIVED_ORDERS );
  2271.  
  2272.         // If we're supposed to be burrowed, stay there
  2273.         if ( m_bStartBurrowed )
  2274.                 return SCHED_fireantlion_WAIT_FOR_UNBORROW_TRIGGER;
  2275.  
  2276.         // See if a friendly player is pushing us away
  2277.         if ( HasCondition( COND_PLAYER_PUSHING ) )
  2278.                 return SCHED_MOVE_AWAY;
  2279.  
  2280.         //Flipped?
  2281.         if ( HasCondition( COND_fireantlion_FLIPPED ) )
  2282.         {
  2283.                 ClearCondition( COND_fireantlion_FLIPPED );
  2284.                
  2285.                 // See if it's a forced, electrical flip
  2286.                 if ( m_flZapDuration > gpGlobals->curtime )
  2287.                 {
  2288.                         SetContextThink( &CNPC_fireantlion::ZapThink, gpGlobals->curtime, "ZapThink" );
  2289.                         return SCHED_fireantlion_ZAP_FLIP;
  2290.                 }
  2291.  
  2292.                 // Regular flip
  2293.                 return SCHED_fireantlion_FLIP;
  2294.         }
  2295.  
  2296.         if( HasCondition( COND_fireantlion_IN_WATER ) )
  2297.         {
  2298.                 // No matter what, drown in water
  2299.                 return SCHED_fireantlion_DROWN;
  2300.         }
  2301.  
  2302.         // If we're flagged to burrow away when eluded, do so
  2303.         if ( ( m_spawnflags & SF_fireantlion_BURROW_ON_ELUDED ) && ( HasCondition( COND_ENEMY_UNREACHABLE ) || HasCondition( COND_ENEMY_TOO_FAR ) ) )
  2304.                 return SCHED_fireantlion_BURROW_AWAY;
  2305.  
  2306.         //Hear a thumper?
  2307.         if ( HasCondition( COND_HEAR_THUMPER ) )
  2308.         {
  2309.                 // Ignore thumpers that aren't visible
  2310.                 CSound *pSound = GetLoudestSoundOfType( SOUND_THUMPER );
  2311.                
  2312.                 if ( pSound )
  2313.                 {
  2314.                         CTakeDamageInfo info;
  2315.                         PainSound( info );
  2316.                         ClearCondition( COND_HEAR_THUMPER );
  2317.  
  2318.                         return SCHED_fireantlion_FLEE_THUMPER;
  2319.                 }
  2320.         }
  2321.  
  2322.         //Hear a physics danger sound?
  2323.         if( HasCondition( COND_HEAR_PHYSICS_DANGER ) )
  2324.         {
  2325.                 CTakeDamageInfo info;
  2326.                 PainSound( info );
  2327.                 return SCHED_fireantlion_FLEE_PHYSICS_DANGER;
  2328.         }
  2329.  
  2330.         //On another NPC's head?
  2331.         if( HasCondition( COND_fireantlion_ON_NPC ) )
  2332.         {
  2333.                 // You're on an NPC's head. Get off.
  2334.                 return SCHED_fireantlion_DISMOUNT_NPC;
  2335.         }
  2336.  
  2337.         // If we're scripted to jump at a target, do so
  2338.         if ( HasCondition( COND_fireantlion_CAN_JUMP_AT_TARGET ) )
  2339.         {
  2340.                 // NDebugOverlay::Cross3D( m_vecSavedJump, 32.0f, 255, 0, 0, true, 2.0f );
  2341.                 ClearCondition( COND_fireantlion_CAN_JUMP_AT_TARGET );
  2342.                 return SCHED_fireantlion_JUMP;
  2343.         }
  2344.  
  2345.         //Hear bug bait splattered?
  2346.         if ( HasCondition( COND_HEAR_BUGBAIT ) && ( m_bIgnoreBugbait == false ) )
  2347.         {
  2348.                 //Play a special sound
  2349.                 if ( m_flNextAcknowledgeTime < gpGlobals->curtime )
  2350.                 {
  2351.                         EmitSound( "NPC_fireantlion.Distracted" );
  2352.                         m_flNextAcknowledgeTime = gpGlobals->curtime + 1.0f;
  2353.                 }
  2354.                
  2355.                 m_flIdleDelay = gpGlobals->curtime + 4.0f;
  2356.  
  2357.                 //If the sound is valid, act upon it
  2358.                 if ( m_bHasHeardSound )
  2359.                 {              
  2360.                         //Mark anything in the area as more interesting
  2361.                         CBaseEntity *pTarget = NULL;
  2362.                         CBaseEntity *pNewEnemy = NULL;
  2363.                         Vector          soundOrg = m_vecHeardSound;
  2364.  
  2365.                         //Find all entities within that sphere
  2366. //                      while ( ( pTarget = gEntList.FindEntityInSphere( pTarget, soundOrg, bugbait_radius.GetInt() ) ) != NULL )
  2367.                         {
  2368.                                 CAI_BaseNPC *pNPC = pTarget->MyNPCPointer();
  2369.  
  2370.                                 if ( pNPC == NULL )
  2371.                                         //continue;
  2372.  
  2373.                                 if ( pNPC->CanBeAnEnemyOf( this ) == false )
  2374.                                         //continue;
  2375.  
  2376.                                 //Check to see if the default relationship is hatred, and if so intensify that
  2377.                                 if ( ( IRelationType( pNPC ) == D_HT ) && ( pNPC->IsPlayer() == false ) )
  2378.                                 {
  2379.                                         AddEntityRelationship( pNPC, D_HT, 99 );
  2380.                                        
  2381.                                         //Try to spread out the enemy distribution
  2382.                                         if ( ( pNewEnemy == NULL ) || ( random->RandomInt( 0, 1 ) ) )
  2383.                                         {
  2384.                                                 pNewEnemy = pNPC;
  2385.                                                 //continue;
  2386.                                         }
  2387.                                 }
  2388.                         }
  2389.                        
  2390.                         // If we have a new enemy, take it
  2391.                         if ( pNewEnemy != NULL )
  2392.                         {
  2393.                                 //Setup our ignore info
  2394.                                 SetEnemy( pNewEnemy );
  2395.                         }
  2396.                        
  2397.                         ClearCondition( COND_HEAR_BUGBAIT );
  2398.  
  2399.                         return SCHED_fireantlion_CHASE_BUGBAIT;
  2400.                 }
  2401.         }
  2402.  
  2403.         if( m_AssaultBehavior.CanSelectSchedule() )
  2404.         {
  2405.                 DeferSchedulingToBehavior( &m_AssaultBehavior );
  2406.                 return BaseClass::SelectSchedule();
  2407.         }
  2408.  
  2409.         //Otherwise do basic state schedule selection
  2410.         switch ( m_NPCState )
  2411.         {      
  2412.         case NPC_STATE_COMBAT:
  2413.                 {
  2414.                         // Worker-only AI
  2415.                         if ( hl2_episodic.GetBool() && IsWorker() )
  2416.                         {
  2417.                                 // Melee attack if we can
  2418.                                 if ( HasCondition( COND_CAN_MELEE_ATTACK1 ) )
  2419.                                         return SCHED_MELEE_ATTACK1;
  2420.  
  2421.                                 // Pounce if they're too near us
  2422.                                 if ( HasCondition( COND_CAN_MELEE_ATTACK2 ) )
  2423.                                 {
  2424.                                         m_flPounceTime = gpGlobals->curtime + 1.5f;
  2425.  
  2426.                                         if ( m_bLeapAttack == true )
  2427.                                                 return SCHED_fireantlion_POUNCE_MOVING;
  2428.  
  2429.                                         return SCHED_fireantlion_POUNCE;
  2430.                                 }
  2431.  
  2432.                                 // A squadmate died, so run away!
  2433.                                 if ( HasCondition( COND_fireantlion_SQUADMATE_KILLED ) )
  2434.                                 {
  2435.                                         SetNextAttack( gpGlobals->curtime + random->RandomFloat( 2.0f, 4.0f ) );
  2436.                                         ClearCondition( COND_fireantlion_SQUADMATE_KILLED );
  2437.                                         return SCHED_fireantlion_TAKE_COVER_FROM_ENEMY;
  2438.                                 }
  2439.  
  2440.                                 // Flee on heavy damage
  2441.                                 if ( HasCondition( COND_HEAVY_DAMAGE ) )
  2442.                                 {
  2443.                                         SetNextAttack( gpGlobals->curtime + random->RandomFloat( 2.0f, 4.0f ) );
  2444.                                         return SCHED_fireantlion_TAKE_COVER_FROM_ENEMY;
  2445.                                 }
  2446.  
  2447.                                 // Range attack if we're able
  2448.                                 if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
  2449.                                 {
  2450.                                         if ( OccupyStrategySlot( SQUAD_SLOT_fireantlion_WORKER_FIRE ) )
  2451.                                         {
  2452.                                                 EmitSound( "NPC_fireantlion.PoisonBurstScream" );
  2453.                                                 SetNextAttack( gpGlobals->curtime + random->RandomFloat( 0.5f, 2.5f ) );
  2454.                                                 if ( GetEnemy() )
  2455.                                                 {
  2456.                                                         m_vSavePosition = GetEnemy()->BodyTarget( GetAbsOrigin() );
  2457.                                                 }
  2458.  
  2459.                                                 return SCHED_fireantlion_WORKER_RANGE_ATTACK1;
  2460.                                         }
  2461.                                 }
  2462.                                
  2463.                                 // Back up, we're too near an enemy or can't see them
  2464.                                 if ( HasCondition( COND_TOO_CLOSE_TO_ATTACK ) || HasCondition( COND_ENEMY_OCCLUDED ) )
  2465.                                         return SCHED_ESTABLISH_LINE_OF_FIRE;
  2466.  
  2467.                                 // See if we need to destroy breakable cover
  2468.                                 if ( HasCondition( COND_WEAPON_SIGHT_OCCLUDED ) )
  2469.                                         return SCHED_SHOOT_ENEMY_COVER;
  2470.  
  2471.                                 // Run around randomly if our target is looking in our direction
  2472.                                 if ( HasCondition( COND_BEHIND_ENEMY ) == false )
  2473.                                         return SCHED_fireantlion_WORKER_FLANK_RANDOM;
  2474.  
  2475.                                 // Face our target and continue to fire
  2476.                                 return SCHED_COMBAT_FACE;
  2477.                         }
  2478.                         else
  2479.                         {
  2480.                                 // Lunge at the enemy
  2481.                                 if ( HasCondition( COND_CAN_MELEE_ATTACK2 ) )
  2482.                                 {
  2483.                                         m_flPounceTime = gpGlobals->curtime + 1.5f;
  2484.  
  2485.                                         if ( m_bLeapAttack == true )
  2486.                                                 return SCHED_fireantlion_POUNCE_MOVING;
  2487.                                         else
  2488.                                                 return SCHED_fireantlion_POUNCE;
  2489.                                 }
  2490.  
  2491.                                 // Try to jump
  2492.                                 if ( HasCondition( COND_fireantlion_CAN_JUMP ) )
  2493.                                         return SCHED_fireantlion_JUMP;
  2494.                         }
  2495.                 }
  2496.                 break;
  2497.  
  2498.         default:
  2499.                 {
  2500.                         int     moveSched = ChooseMoveSchedule();
  2501.  
  2502.                         if ( moveSched != SCHED_NONE )
  2503.                                 return moveSched;
  2504.  
  2505.                         if ( GetEnemy() == NULL && ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) ) )
  2506.                         {
  2507.                                 Vector vecEnemyLKP;
  2508.  
  2509.                                 // Retrieve a memory for the damage taken
  2510.                                 // Fill in where we're trying to look
  2511.                                 if ( GetEnemies()->Find( AI_UNKNOWN_ENEMY ) )
  2512.                                 {
  2513.                                         vecEnemyLKP = GetEnemies()->LastKnownPosition( AI_UNKNOWN_ENEMY );
  2514.                                 }
  2515.                                 else
  2516.                                 {
  2517.                                         // Don't have an enemy, so face the direction the last attack came from (don't face north)
  2518.                                         vecEnemyLKP = WorldSpaceCenter() + ( g_vecAttackDir * 128 );
  2519.                                 }
  2520.                                
  2521.                                 // If we're already facing the attack direction, then take cover from it
  2522.                                 if ( FInViewCone( vecEnemyLKP ) )
  2523.                                 {
  2524.                                         // Save this position for our cover search
  2525.                                         m_vSavePosition = vecEnemyLKP;
  2526.                                         return SCHED_fireantlion_TAKE_COVER_FROM_SAVEPOSITION;
  2527.                                 }
  2528.                                
  2529.                                 // By default, we'll turn to face the attack
  2530.                         }
  2531.                 }
  2532.                 break;
  2533.         }
  2534.  
  2535.         return BaseClass::SelectSchedule();
  2536. }
  2537.  
  2538. void CNPC_fireantlion::Ignite ( float flFlameLifetime, bool bNPCOnly, float flSize, bool bCalledByLevelDesigner )
  2539. {
  2540. #ifdef HL2_EPISODIC
  2541.         float flDamage = m_iHealth + 1;
  2542.  
  2543.         CTakeDamageInfo dmgInfo( this, this, flDamage, DMG_GENERIC );
  2544.         GuessDamageForce( &dmgInfo, Vector( 0, 0, 8 ), GetAbsOrigin() );
  2545.         TakeDamage( dmgInfo );
  2546. #else
  2547.         BaseClass::Ignite( flFlameLifetime, bNPCOnly, flSize, bCalledByLevelDesigner );
  2548. #endif
  2549.  
  2550. }
  2551.  
  2552.  
  2553. //-----------------------------------------------------------------------------
  2554. //-----------------------------------------------------------------------------
  2555. int CNPC_fireantlion::OnTakeDamage_Alive( const CTakeDamageInfo &info )
  2556. {
  2557.         CTakeDamageInfo newInfo = info;
  2558.  
  2559.         if( hl2_episodic.GetBool() && fireantlion_easycrush.GetBool() )
  2560.         {
  2561.                 if( newInfo.GetDamageType() & DMG_CRUSH )
  2562.                 {
  2563.                         if( newInfo.GetInflictor() && newInfo.GetInflictor()->VPhysicsGetObject() )
  2564.                         {
  2565.                                 float flMass = newInfo.GetInflictor()->VPhysicsGetObject()->GetMass();
  2566.  
  2567.                                 if( flMass > 250.0f && newInfo.GetDamage() < GetHealth() )
  2568.                                 {
  2569.                                         newInfo.SetDamage( GetHealth() );
  2570.                                 }
  2571.                         }
  2572.                 }
  2573.         }
  2574.  
  2575.         // If we're being hoisted by a barnacle, we only take damage from that barnacle (otherwise we can die too early!)
  2576.         if ( IsEFlagSet( EFL_IS_BEING_LIFTED_BY_BARNACLE ) )
  2577.         {
  2578.                 if ( info.GetAttacker() && info.GetAttacker()->Classify() != CLASS_BARNACLE )
  2579.                         return 0;
  2580.         }
  2581.  
  2582.         // Find out how much damage we're about to take
  2583.         int nDamageTaken = BaseClass::OnTakeDamage_Alive( newInfo );
  2584.         if ( gpGlobals->curtime - m_flLastDamageTime < 0.5f )
  2585.         {
  2586.                 // Accumulate it
  2587.                 m_nSustainedDamage += nDamageTaken;
  2588.         }
  2589.         else
  2590.         {
  2591.                 // Reset, it's been too long
  2592.                 m_nSustainedDamage = nDamageTaken;
  2593.         }
  2594.  
  2595.         m_flLastDamageTime = gpGlobals->curtime;
  2596.  
  2597.         return nDamageTaken;
  2598. }
  2599.  
  2600. //-----------------------------------------------------------------------------
  2601. // Purpose: fireantlion who are flipped will knock over other fireantlions behind them!
  2602. //-----------------------------------------------------------------------------
  2603. void CNPC_fireantlion::CascadePush( const Vector &vecForce )
  2604. {
  2605.         // Controlled via this convar until this is proven worthwhile
  2606.         if ( hl2_episodic.GetBool() == false /*|| g_fireantlion_cascade_push.GetBool() == false*/ )
  2607.                 return;
  2608.  
  2609.         Vector vecForceDir = vecForce;
  2610.         float flMagnitude = VectorNormalize( vecForceDir );
  2611.         Vector vecPushBack = GetAbsOrigin() + ( vecForceDir * (flMagnitude*0.1f) );
  2612.  
  2613.         // Make fireantlions flip all around us!
  2614.         CBaseEntity *pEnemySearch[32];
  2615.         int nNumEnemies = UTIL_EntitiesInBox( pEnemySearch, ARRAYSIZE(pEnemySearch), vecPushBack-Vector(48,48,0), vecPushBack+Vector(48,48,64), FL_NPC );
  2616.         for ( int i = 0; i < nNumEnemies; i++ )
  2617.         {
  2618.                 // We only care about fireantlions
  2619.                 if ( pEnemySearch[i] == NULL || pEnemySearch[i]->Classify() != CLASS_fireantlion || pEnemySearch[i] == this )
  2620.                         continue;
  2621.  
  2622.                 CNPC_fireantlion *pfireantlion = dynamic_cast<CNPC_fireantlion *>(pEnemySearch[i]);
  2623.                 if ( pfireantlion != NULL )
  2624.                 {
  2625.                         Vector vecDir = ( pfireantlion->GetAbsOrigin() - GetAbsOrigin() );
  2626.                         vecDir[2] = 0.0f;
  2627.                         float flDist = VectorNormalize( vecDir );
  2628.                         float flFalloff = RemapValClamped( flDist, 0, 256, 1.0f, 0.1f );
  2629.  
  2630.                         vecDir *= ( flMagnitude * flFalloff );
  2631.                         vecDir[2] += ( (flMagnitude*0.25f) * flFalloff );
  2632.  
  2633.                         pfireantlion->ApplyAbsVelocityImpulse( vecDir );
  2634.  
  2635.                         // Turn them over
  2636.                         pfireantlion->Flip();
  2637.                 }
  2638.         }
  2639. }
  2640.  
  2641. //-----------------------------------------------------------------------------
  2642. // Purpose:
  2643. // Output : Returns true on success, false on failure.
  2644. //-----------------------------------------------------------------------------
  2645. inline bool CNPC_fireantlion::IsFlipped( void )
  2646. {
  2647.         return ( GetActivity() == ACT_fireantlion_FLIP || GetActivity() == ACT_fireantlion_ZAP_FLIP );
  2648. }
  2649.  
  2650. //-----------------------------------------------------------------------------
  2651. // Purpose:
  2652. //-----------------------------------------------------------------------------
  2653. void CNPC_fireantlion::TraceAttack( const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr )
  2654. {
  2655.         CTakeDamageInfo newInfo = info;
  2656.  
  2657.         Vector  vecShoveDir = vecDir;
  2658.         vecShoveDir.z = 0.0f;
  2659.  
  2660.         //Are we already flipped?
  2661.         if ( IsFlipped() )
  2662.         {
  2663.                 //If we were hit by physics damage, move with it
  2664.                 if ( newInfo.GetDamageType() & (DMG_CRUSH|DMG_PHYSGUN) )
  2665.                 {
  2666.                         PainSound( newInfo );
  2667.                         Vector vecForce = ( vecShoveDir * random->RandomInt( 500.0f, 1000.0f ) ) + Vector(0,0,64.0f);
  2668.                         CascadePush( vecForce );
  2669.                         ApplyAbsVelocityImpulse( vecForce );
  2670.                         SetGroundEntity( NULL );
  2671.                 }
  2672.  
  2673.                 //More vulnerable when flipped
  2674.                 newInfo.ScaleDamage( 4.0f );
  2675.         }
  2676.         else if ( newInfo.GetDamageType() & (DMG_PHYSGUN) ||
  2677.                         ( newInfo.GetDamageType() & (DMG_BLAST|DMG_CRUSH) && newInfo.GetDamage() >= 25.0f ) )
  2678.         {
  2679.                 // Don't do this if we're in an interaction
  2680.                 if ( !IsRunningDynamicInteraction() )
  2681.                 {
  2682.                         //Grenades, physcannons, and physics impacts make us fuh-lip!
  2683.                        
  2684.                         if( hl2_episodic.GetBool() )
  2685.                         {
  2686.                                 PainSound( newInfo );
  2687.  
  2688.                                 if( GetFlags() & FL_ONGROUND )
  2689.                                 {
  2690.                                         // Only flip if on the ground.
  2691.                                         SetCondition( COND_fireantlion_FLIPPED );
  2692.                                 }
  2693.  
  2694.                                 Vector vecForce = ( vecShoveDir * random->RandomInt( 500.0f, 1000.0f ) ) + Vector(0,0,64.0f);
  2695.  
  2696.                                 CascadePush( vecForce );
  2697.                                 ApplyAbsVelocityImpulse( vecForce );
  2698.                                 SetGroundEntity( NULL );
  2699.                         }
  2700.                         else
  2701.                         {
  2702.                                 //Don't flip off the deck
  2703.                                 if ( GetFlags() & FL_ONGROUND )
  2704.                                 {
  2705.                                         PainSound( newInfo );
  2706.  
  2707.                                         SetCondition( COND_fireantlion_FLIPPED );
  2708.  
  2709.                                         //Get tossed!
  2710.                                         ApplyAbsVelocityImpulse( ( vecShoveDir * random->RandomInt( 500.0f, 1000.0f ) ) + Vector(0,0,64.0f) );
  2711.                                         SetGroundEntity( NULL );
  2712.                                 }
  2713.                         }
  2714.                 }
  2715.         }
  2716.  
  2717.         BaseClass::TraceAttack( newInfo, vecDir, ptr );
  2718. }
  2719.  
  2720. void CNPC_fireantlion::StopLoopingSounds( void )
  2721. {
  2722.         if ( m_bLoopingStarted )
  2723.         {
  2724.                 StopSound( "NPC_fireantlion.WingsOpen" );
  2725.                 m_bLoopingStarted = false;
  2726.         }
  2727.         if ( m_bAgitatedSound )
  2728.         {
  2729.                 StopSound( "NPC_fireantlion.LoopingAgitated" );
  2730.                 m_bAgitatedSound = false;
  2731.         }
  2732. }
  2733.  
  2734. //-----------------------------------------------------------------------------
  2735. // Purpose:
  2736. //-----------------------------------------------------------------------------
  2737. void CNPC_fireantlion::IdleSound( void )
  2738. {
  2739.         EmitSound( "NPC_fireantlion.Idle" );
  2740.         m_flIdleDelay = gpGlobals->curtime + 4.0f;
  2741. }
  2742.  
  2743. //-----------------------------------------------------------------------------
  2744. // Purpose:
  2745. //-----------------------------------------------------------------------------
  2746. void CNPC_fireantlion::PainSound( const CTakeDamageInfo &info )
  2747. {
  2748.         EmitSound( "NPC_fireantlion.Pain" );
  2749. }
  2750.  
  2751. //-----------------------------------------------------------------------------
  2752. // Purpose:
  2753. // Output :
  2754. //-----------------------------------------------------------------------------
  2755. float CNPC_fireantlion::GetIdealAccel( void ) const
  2756. {
  2757.         return GetIdealSpeed() * 2.0;
  2758. }
  2759.  
  2760. //-----------------------------------------------------------------------------
  2761. // Purpose:
  2762. // Output : float
  2763. //-----------------------------------------------------------------------------
  2764. float CNPC_fireantlion::MaxYawSpeed( void )
  2765. {
  2766.         switch ( GetActivity() )
  2767.         {
  2768.         case ACT_IDLE:         
  2769.                 return 32.0f;
  2770.                 break;
  2771.        
  2772.         case ACT_WALK:
  2773.                 return 16.0f;
  2774.                 break;
  2775.        
  2776.         default:
  2777.         case ACT_RUN:
  2778.                 return 32.0f;
  2779.                 break;
  2780.         }
  2781.  
  2782.         return 32.0f;
  2783. }
  2784.  
  2785. //-----------------------------------------------------------------------------
  2786. // Purpose:
  2787. // Output : Returns true on success, false on failure.
  2788. //-----------------------------------------------------------------------------
  2789. bool CNPC_fireantlion::ShouldPlayIdleSound( void )
  2790. {
  2791.         //Only do idles in the right states
  2792.         if ( ( m_NPCState != NPC_STATE_IDLE && m_NPCState != NPC_STATE_ALERT ) )
  2793.                 return false;
  2794.  
  2795.         //Gagged monsters don't talk
  2796.         if ( m_spawnflags & SF_NPC_GAG )
  2797.                 return false;
  2798.  
  2799.         //Don't cut off another sound or play again too soon
  2800.         if ( m_flIdleDelay > gpGlobals->curtime )
  2801.                 return false;
  2802.  
  2803.         //Randomize it a bit
  2804.         if ( random->RandomInt( 0, 20 ) )
  2805.                 return false;
  2806.  
  2807.         return true;
  2808. }
  2809.  
  2810. //-----------------------------------------------------------------------------
  2811. // Purpose:
  2812. // Input  : *pFriend -
  2813. //-----------------------------------------------------------------------------
  2814. void CNPC_fireantlion::NotifyDeadFriend( CBaseEntity *pFriend )
  2815. {
  2816.         SetCondition( COND_fireantlion_SQUADMATE_KILLED );
  2817.         BaseClass::NotifyDeadFriend( pFriend );
  2818. }
  2819.  
  2820.  
  2821. //-----------------------------------------------------------------------------
  2822. // Purpose: Determine whether or not to check our attack conditions
  2823. //-----------------------------------------------------------------------------
  2824. bool CNPC_fireantlion::FCanCheckAttacks( void )
  2825. {
  2826.         if ( IsWorker() )
  2827.         {
  2828.                 // Only do this if we've seen our target recently and our schedule can be interrupted
  2829.                 if ( SeenEnemyWithinTime( 3.0f ) && ConditionInterruptsCurSchedule( COND_CAN_RANGE_ATTACK1 ) )
  2830.                         return FInViewCone( GetEnemy() );
  2831.         }
  2832.  
  2833.         return BaseClass::FCanCheckAttacks();
  2834. }
  2835.  
  2836. //-----------------------------------------------------------------------------
  2837. // Purpose:
  2838. //-----------------------------------------------------------------------------
  2839. int CNPC_fireantlion::RangeAttack1Conditions( float flDot, float flDist )
  2840. {
  2841.         if ( GetNextAttack() > gpGlobals->curtime )
  2842.                 return COND_NOT_FACING_ATTACK;
  2843.  
  2844.         if ( flDot < DOT_10DEGREE )
  2845.                 return COND_NOT_FACING_ATTACK;
  2846.        
  2847.         if ( flDist > (150*12) )
  2848.                 return COND_TOO_FAR_TO_ATTACK;
  2849.  
  2850.         if ( flDist < (20*12) )
  2851.                 return COND_TOO_CLOSE_TO_ATTACK;
  2852.  
  2853.         return COND_CAN_RANGE_ATTACK1;
  2854. }
  2855.  
  2856. //-----------------------------------------------------------------------------
  2857. // Purpose:
  2858. //-----------------------------------------------------------------------------
  2859. int CNPC_fireantlion::MeleeAttack1Conditions( float flDot, float flDist )
  2860. {
  2861. #if 1 //NOTENOTE: Use predicted position melee attacks
  2862.  
  2863.         //Get our likely position in one half second
  2864.         Vector vecPrPos;
  2865.         UTIL_PredictedPosition( GetEnemy(), 0.5f, &vecPrPos );
  2866.  
  2867.         //Get the predicted distance and direction
  2868.         float flPrDist = ( vecPrPos - GetAbsOrigin() ).LengthSqr();
  2869.         if ( flPrDist > Square( fireantlion_MELEE1_RANGE ) )
  2870.                 return COND_TOO_FAR_TO_ATTACK;
  2871.  
  2872.         // Compare our target direction to our body facing
  2873.         Vector2D vec2DPrDir     = ( vecPrPos - GetAbsOrigin() ).AsVector2D();
  2874.         Vector2D vec2DBodyDir = BodyDirection2D().AsVector2D();
  2875.        
  2876.         float flPrDot = DotProduct2D ( vec2DPrDir, vec2DBodyDir );
  2877.         if ( flPrDot < 0.5f )
  2878.                 return COND_NOT_FACING_ATTACK;
  2879.  
  2880.         trace_t tr;
  2881.         AI_TraceHull( WorldSpaceCenter(), GetEnemy()->WorldSpaceCenter(), -Vector(8,8,8), Vector(8,8,8), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
  2882.  
  2883.         // If the hit entity isn't our target and we don't hate it, don't hit it
  2884.         if ( tr.m_pEnt != GetEnemy() && tr.fraction < 1.0f && IRelationType( tr.m_pEnt ) != D_HT )
  2885.                 return 0;
  2886.  
  2887. #else
  2888.  
  2889.         if ( flDot < 0.5f )
  2890.                 return COND_NOT_FACING_ATTACK;
  2891.  
  2892.         float flAdjustedDist = fireantlion_MELEE1_RANGE;
  2893.  
  2894.         if ( GetEnemy() )
  2895.         {
  2896.                 // Give us extra space if our enemy is in a vehicle
  2897.                 CBaseCombatCharacter *pCCEnemy = GetEnemy()->MyCombatCharacterPointer();
  2898.                 if ( pCCEnemy != NULL && pCCEnemy->IsInAVehicle() )
  2899.                 {
  2900.                         flAdjustedDist *= 2.0f;
  2901.                 }
  2902.         }
  2903.  
  2904.         if ( flDist > flAdjustedDist )
  2905.                 return COND_TOO_FAR_TO_ATTACK;
  2906.  
  2907.         trace_t tr;
  2908.         AI_TraceHull( WorldSpaceCenter(), GetEnemy()->WorldSpaceCenter(), -Vector(8,8,8), Vector(8,8,8), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  2909.  
  2910.         if ( tr.fraction < 1.0f )
  2911.                 return 0;
  2912.  
  2913. #endif
  2914.  
  2915.         return COND_CAN_MELEE_ATTACK1;
  2916. }
  2917.  
  2918. //-----------------------------------------------------------------------------
  2919. // Purpose:
  2920. // Input  : flDot -
  2921. //                      flDist -
  2922. // Output : int
  2923. //-----------------------------------------------------------------------------
  2924. int CNPC_fireantlion::MeleeAttack2Conditions( float flDot, float flDist )
  2925. {
  2926.         // See if it's too soon to pounce again
  2927.         if ( m_flPounceTime > gpGlobals->curtime )
  2928.                 return 0;
  2929.  
  2930.         float           flPrDist, flPrDot;
  2931.         Vector          vecPrPos;
  2932.         Vector2D        vec2DPrDir;
  2933.  
  2934.         //Get our likely position in one half second
  2935.         UTIL_PredictedPosition( GetEnemy(), 0.25f, &vecPrPos );
  2936.  
  2937.         //Get the predicted distance and direction
  2938.         flPrDist        = ( vecPrPos - GetAbsOrigin() ).Length();
  2939.         vec2DPrDir      = ( vecPrPos - GetAbsOrigin() ).AsVector2D();
  2940.  
  2941.         Vector vecBodyDir = BodyDirection2D();
  2942.  
  2943.         Vector2D vec2DBodyDir = vecBodyDir.AsVector2D();
  2944.        
  2945.         flPrDot = DotProduct2D ( vec2DPrDir, vec2DBodyDir );
  2946.  
  2947.         if ( ( flPrDist > fireantlion_MELEE2_RANGE_MAX ) )
  2948.         {
  2949.                 m_flPounceTime = gpGlobals->curtime + 0.2f;
  2950.                 return COND_TOO_FAR_TO_ATTACK;
  2951.         }
  2952.         else if ( ( flPrDist < fireantlion_MELEE2_RANGE_MIN ) )
  2953.         {
  2954.                 m_flPounceTime = gpGlobals->curtime + 0.2f;
  2955.                 return COND_TOO_CLOSE_TO_ATTACK;
  2956.         }
  2957.  
  2958.         trace_t tr;
  2959.         AI_TraceHull( WorldSpaceCenter(), GetEnemy()->WorldSpaceCenter(), -Vector(8,8,8), Vector(8,8,8), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  2960.  
  2961.         if ( tr.fraction < 1.0f )
  2962.                 return 0;
  2963.  
  2964.         if ( IsMoving() )
  2965.                  m_bLeapAttack = true;
  2966.         else
  2967.                  m_bLeapAttack = false;
  2968.  
  2969.         return COND_CAN_MELEE_ATTACK2;
  2970. }
  2971.  
  2972. //-----------------------------------------------------------------------------
  2973. // Purpose:
  2974. // Input  : interactionType -
  2975. //                      *data -
  2976. //                      *sender -
  2977. // Output : Returns true on success, false on failure.
  2978. //-----------------------------------------------------------------------------
  2979. bool CNPC_fireantlion::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sender )
  2980. {
  2981.         //Check for a target found while burrowed
  2982.         if ( interactionType == g_interactionfireantlionFoundTarget )
  2983.         {
  2984.                 CBaseEntity     *pOther = (CBaseEntity *) data;
  2985.                
  2986.                 //Randomly delay
  2987.                 m_flBurrowTime = gpGlobals->curtime + random->RandomFloat( 0.5f, 1.0f );
  2988.                 BurrowUse( pOther, pOther, USE_ON, 0.0f );
  2989.  
  2990.                 return true;
  2991.         }
  2992.  
  2993.         // fixed for episodic: allow interactions to fall through in the base class. ifdefed away
  2994.         // for mainline in case anything depends on this bug.
  2995. #ifdef HL2_EPISODIC
  2996.        
  2997.         if ( interactionType == g_interactionfireantlionFiredAtTarget )
  2998.         {
  2999.                 // Bump out our attack time
  3000.                 if ( IsWorker() )
  3001.                 {
  3002.                         float flDuration = *((float *)data);
  3003.                         SetNextAttack( gpGlobals->curtime + flDuration );
  3004.                 }
  3005.         }
  3006.  
  3007.         return BaseClass::HandleInteraction( interactionType, data, sender );
  3008. #else
  3009.         return false;
  3010. #endif
  3011. }
  3012.  
  3013. //-----------------------------------------------------------------------------
  3014. // Purpose:
  3015. // Output : Returns true on success, false on failure.
  3016. //-----------------------------------------------------------------------------
  3017. bool CNPC_fireantlion::Alone( void )
  3018. {
  3019.         if ( m_pSquad == NULL )
  3020.                 return true;
  3021.  
  3022.         if ( m_pSquad->NumMembers() <= 1 )
  3023.                 return true;
  3024.  
  3025.         return false;
  3026. }
  3027.  
  3028. //-----------------------------------------------------------------------------
  3029. // Purpose:
  3030. //-----------------------------------------------------------------------------
  3031. void CNPC_fireantlion::StartJump( void )
  3032. {
  3033.         if ( m_bForcedStuckJump == false )
  3034.         {
  3035.                 // FIXME: Why must this be true?
  3036.                 // Must be jumping at an enemy
  3037.                 // if ( GetEnemy() == NULL )
  3038.                 //      return;
  3039.  
  3040.                 //Don't jump if we're not on the ground
  3041.                 if ( ( GetFlags() & FL_ONGROUND ) == false )
  3042.                         return;
  3043.         }
  3044.  
  3045.         //Take us off the ground
  3046.         SetGroundEntity( NULL );
  3047.         SetAbsVelocity( m_vecSavedJump );
  3048.  
  3049.         m_bForcedStuckJump = false;
  3050. #if HL2_EPISODIC
  3051.         m_bHasDoneAirAttack = false;
  3052. #endif
  3053.  
  3054.         //Setup our jump time so that we don't try it again too soon
  3055.         m_flJumpTime = gpGlobals->curtime + random->RandomInt( 2, 6 );
  3056. }
  3057.  
  3058. //-----------------------------------------------------------------------------
  3059. // Purpose:
  3060. // Input  : sHint -
  3061. //                      nNodeNum -
  3062. // Output : bool CAI_BaseNPC::FValidateHintType
  3063. //-----------------------------------------------------------------------------
  3064. bool CNPC_fireantlion::FValidateHintType( CAI_Hint *pHint )
  3065. {
  3066.         switch ( m_iContext )
  3067.         {
  3068.         case fireantlion_BURROW_OUT:
  3069.                 {                      
  3070.                         //See if this is a valid point
  3071.                         Vector vHintPos;
  3072.                         pHint->GetPosition(this,&vHintPos);
  3073.  
  3074.                         if ( ValidBurrowPoint( vHintPos ) == false )
  3075.                                 return false;
  3076.                 }
  3077.                 break;
  3078.         }
  3079.  
  3080.         return true;
  3081. }
  3082.  
  3083. //-----------------------------------------------------------------------------
  3084. // Purpose:
  3085. // Input  : &origin -
  3086. //-----------------------------------------------------------------------------
  3087. void CNPC_fireantlion::ClearBurrowPoint( const Vector &origin )
  3088. {
  3089.         CBaseEntity *pEntity = NULL;
  3090.         float           flDist;
  3091.         Vector          vecSpot, vecCenter, vecForce;
  3092.  
  3093.         bool bPlayerInSphere = false;
  3094.  
  3095.         //Iterate on all entities in the vicinity.
  3096.         for ( CEntitySphereQuery sphere( origin, 128 ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() )
  3097.         {
  3098.                 if ( pEntity->Classify() == CLASS_PLAYER )
  3099.                 {
  3100.                         bPlayerInSphere = true;
  3101.                         continue;
  3102.                 }
  3103.  
  3104.                 if ( pEntity->m_takedamage != DAMAGE_NO && pEntity->Classify() != CLASS_PLAYER && pEntity->VPhysicsGetObject() )
  3105.                 {
  3106.                         vecSpot  = pEntity->BodyTarget( origin );
  3107.                         vecForce = ( vecSpot - origin ) + Vector( 0, 0, 16 );
  3108.  
  3109.                         // decrease damage for an ent that's farther from the bomb.
  3110.                         flDist = VectorNormalize( vecForce );
  3111.  
  3112.                         //float mass = pEntity->VPhysicsGetObject()->GetMass();
  3113.                         CollisionProp()->RandomPointInBounds( vec3_origin, Vector( 1.0f, 1.0f, 1.0f ), &vecCenter );
  3114.  
  3115.                         if ( flDist <= 128.0f )
  3116.                         {
  3117.                                 pEntity->VPhysicsGetObject()->Wake();
  3118.                                 pEntity->VPhysicsGetObject()->ApplyForceOffset( vecForce * 250.0f, vecCenter );
  3119.                         }
  3120.                 }
  3121.         }
  3122.        
  3123.         if ( bPlayerInSphere == false )
  3124.         {
  3125.                 //Cause a ruckus
  3126.                 UTIL_ScreenShake( origin, 1.0f, 80.0f, 1.0f, 256.0f, SHAKE_START );
  3127.         }
  3128. }
  3129.  
  3130. bool NPC_CheckBrushExclude( CBaseEntity *pEntity, CBaseEntity *pBrush );
  3131. //-----------------------------------------------------------------------------
  3132. // traceline methods
  3133. //-----------------------------------------------------------------------------
  3134. class CTraceFilterSimpleNPCExclude : public CTraceFilterSimple
  3135. {
  3136. public:
  3137.         DECLARE_CLASS( CTraceFilterSimpleNPCExclude, CTraceFilterSimple );
  3138.  
  3139.         CTraceFilterSimpleNPCExclude( const IHandleEntity *passentity, int collisionGroup )
  3140.                 : CTraceFilterSimple( passentity, collisionGroup )
  3141.         {
  3142.         }
  3143.  
  3144.         bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  3145.         {
  3146.                 Assert( dynamic_cast<CBaseEntity*>(pHandleEntity) );
  3147.                 CBaseEntity *pTestEntity = static_cast<CBaseEntity*>(pHandleEntity);
  3148.  
  3149.                 if ( GetPassEntity() )
  3150.                 {
  3151.                         CBaseEntity *pEnt = gEntList.GetBaseEntity( GetPassEntity()->GetRefEHandle() );
  3152.  
  3153.                         if ( pEnt->IsNPC() )
  3154.                         {
  3155.                                 if ( NPC_CheckBrushExclude( pEnt, pTestEntity ) == true )
  3156.                                         return false;
  3157.                         }
  3158.                 }
  3159.                 return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask );
  3160.         }
  3161. };
  3162.  
  3163. //-----------------------------------------------------------------------------
  3164. // Purpose: Determine whether a point is valid or not for burrowing up into
  3165. // Input  : &point - point to test for validity
  3166. // Output : Returns true on success, false on failure.
  3167. //-----------------------------------------------------------------------------
  3168. bool CNPC_fireantlion::ValidBurrowPoint( const Vector &point )
  3169. {
  3170.         trace_t tr;
  3171.  
  3172.         CTraceFilterSimpleNPCExclude filter( this, COLLISION_GROUP_NONE );
  3173.         AI_TraceHull( point, point+Vector(0,0,1), GetHullMins(), GetHullMaxs(),
  3174.                 MASK_NPCSOLID, &filter, &tr );
  3175.  
  3176.         //See if we were able to get there
  3177.         if ( ( tr.startsolid ) || ( tr.allsolid ) || ( tr.fraction < 1.0f ) )
  3178.         {
  3179.                 CBaseEntity *pEntity = tr.m_pEnt;
  3180.  
  3181.                 //If it's a physics object, attempt to knock is away, unless it's a car
  3182.                 if ( ( pEntity ) && ( pEntity->VPhysicsGetObject() ) && ( pEntity->GetServerVehicle() == NULL ) )
  3183.                 {
  3184.                         ClearBurrowPoint( point );
  3185.                 }
  3186.  
  3187.                 return false;
  3188.         }
  3189.  
  3190.         return true;
  3191. }
  3192.  
  3193. //-----------------------------------------------------------------------------
  3194. // Purpose: Finds a burrow point for the fireantlion
  3195. // Input  : distance - radius to search for burrow spot in
  3196. // Output : Returns true on success, false on failure.
  3197. //-----------------------------------------------------------------------------
  3198. bool CNPC_fireantlion::FindBurrow( const Vector &origin, float distance, int type, bool excludeNear )
  3199. {
  3200.         //Burrowing in?
  3201.         if ( type == fireantlion_BURROW_IN )
  3202.         {
  3203.                 //Attempt to find a burrowing point
  3204.                 CHintCriteria   hintCriteria;
  3205.  
  3206.                 hintCriteria.SetHintType( HINT_ANTLION_BURROW_POINT );
  3207.                 hintCriteria.SetFlag( bits_HINT_NODE_NEAREST );
  3208.  
  3209.                 hintCriteria.AddIncludePosition( origin, distance );
  3210.                
  3211.                 if ( excludeNear )
  3212.                 {
  3213.                         hintCriteria.AddExcludePosition( origin, 128 );
  3214.                 }
  3215.  
  3216.                 CAI_Hint *pHint = CAI_HintManager::FindHint( this, hintCriteria );
  3217.  
  3218.                 if ( pHint == NULL )
  3219.                         return false;
  3220.  
  3221.                 //Free up the node for use
  3222.                 if ( GetHintNode() )
  3223.                 {
  3224.                         GetHintNode()->Unlock(0);
  3225.                 }
  3226.  
  3227.                 SetHintNode( pHint );
  3228.  
  3229.                 //Lock the node
  3230.                 pHint->Lock(this);
  3231.  
  3232.                 //Setup our path and attempt to run there
  3233.                 Vector vHintPos;
  3234.                 GetHintNode()->GetPosition( this, &vHintPos );
  3235.  
  3236.                 AI_NavGoal_t goal( vHintPos, ACT_RUN );
  3237.  
  3238.                 return GetNavigator()->SetGoal( goal );
  3239.         }
  3240.  
  3241.         //Burrow out
  3242.         m_iContext = fireantlion_BURROW_OUT;
  3243.  
  3244.         CHintCriteria   hintCriteria;
  3245.  
  3246.         hintCriteria.SetHintType( HINT_ANTLION_BURROW_POINT );
  3247.         hintCriteria.SetFlag( bits_HINT_NODE_NEAREST );
  3248.  
  3249.         if ( GetEnemy() != NULL )
  3250.         {
  3251.                 hintCriteria.AddIncludePosition( GetEnemy()->GetAbsOrigin(), distance );
  3252.         }
  3253.  
  3254.         //Attempt to find an open burrow point
  3255.         CAI_Hint *pHint = CAI_HintManager::FindHint( this, hintCriteria );
  3256.  
  3257.         m_iContext = -1;
  3258.  
  3259.         if ( pHint == NULL )
  3260.                 return false;
  3261.  
  3262.         //Free up the node for use
  3263.         if (GetHintNode())
  3264.         {
  3265.                 GetHintNode()->Unlock(0);
  3266.         }
  3267.  
  3268.         SetHintNode( pHint );
  3269.         pHint->Lock(this);
  3270.  
  3271.         Vector burrowPoint;
  3272.         pHint->GetPosition(this,&burrowPoint);
  3273.  
  3274.         UTIL_SetOrigin( this, burrowPoint );
  3275.  
  3276.         //Burrowing out
  3277.         return true;
  3278. }
  3279.  
  3280. //-----------------------------------------------------------------------------
  3281. // Purpose:     Cause the fireantlion to unborrow
  3282. // Input  : *pActivator -
  3283. //                      *pCaller -
  3284. //                      useType -
  3285. //                      value -
  3286. //-----------------------------------------------------------------------------
  3287.  
  3288. void CNPC_fireantlion::BurrowUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  3289. {
  3290.         //Don't allow us to do this again
  3291.         SetUse( NULL );
  3292.        
  3293.         //Allow idle sounds again
  3294.         m_spawnflags &= ~SF_NPC_GAG;
  3295.  
  3296.         //If the player activated this, then take them as an enemy
  3297.         if ( ( pCaller != NULL ) && ( pCaller->IsPlayer() ) )
  3298.         {
  3299.                 SetEnemy( pActivator );
  3300.         }
  3301.  
  3302.         //Start trying to surface
  3303.         SetSchedule( SCHED_fireantlion_WAIT_UNBORROW );
  3304. }
  3305.  
  3306. //-----------------------------------------------------------------------------
  3307. // Purpose: Monitor the fireantlion's jump to play the proper landing sequence
  3308. //-----------------------------------------------------------------------------
  3309. bool CNPC_fireantlion::CheckLanding( void )
  3310. {
  3311.         trace_t tr;
  3312.         Vector  testPos;
  3313.  
  3314.         //Amount of time to predict forward
  3315.         const float     timeStep = 0.1f;
  3316.  
  3317.         //Roughly looks one second into the future
  3318.         testPos = GetAbsOrigin() + ( GetAbsVelocity() * timeStep );
  3319.         testPos[2] -= ( 0.5 * sv_gravity.GetFloat() * GetGravity() * timeStep * timeStep);
  3320.  
  3321.         if ( g_debug_fireantlion.GetInt() == 2 )
  3322.         {
  3323.                 NDebugOverlay::Line( GetAbsOrigin(), testPos, 255, 0, 0, 0, 0.5f );
  3324.                 NDebugOverlay::Cross3D( m_vecSavedJump, -Vector(2,2,2), Vector(2,2,2), 0, 255, 0, true, 0.5f );
  3325.         }
  3326.        
  3327.         // Look below
  3328.         AI_TraceHull( GetAbsOrigin(), testPos, NAI_Hull::Mins( GetHullType() ), NAI_Hull::Maxs( GetHullType() ), MASK_NPCSOLID, this, COLLISION_GROUP_NONE, &tr );
  3329.  
  3330.         //See if we're about to contact, or have already contacted the ground
  3331.         if ( ( tr.fraction != 1.0f ) || ( GetFlags() & FL_ONGROUND ) )
  3332.         {
  3333.                 int     sequence = SelectWeightedSequence( (Activity)ACT_fireantlion_LAND );
  3334.  
  3335.                 if ( GetSequence() != sequence )
  3336.                 {
  3337.                         SetWings( false );
  3338.                         VacateStrategySlot();
  3339.                         SetIdealActivity( (Activity) ACT_fireantlion_LAND );
  3340.  
  3341.                         CreateDust( false );
  3342.                         EmitSound( "NPC_fireantlion.Land" );
  3343.  
  3344.                         if ( GetEnemy() && GetEnemy()->IsPlayer()  )
  3345.                         {
  3346.                                 CBasePlayer *pPlayer = ToBasePlayer( GetEnemy() );
  3347.  
  3348.                                 if ( pPlayer && pPlayer->IsInAVehicle() == false )
  3349.                                          MeleeAttack( fireantlion_MELEE1_RANGE, sk_fireantlion_swipe_damage.GetFloat(), QAngle( 4.0f, 0.0f, 0.0f ), Vector( -250.0f, 1.0f, 1.0f ) );
  3350.                         }
  3351.  
  3352.                         SetAbsVelocity( GetAbsVelocity() * 0.33f );
  3353.                         return false;
  3354.                 }
  3355.  
  3356.                 return IsActivityFinished();
  3357.         }
  3358.  
  3359.         return false;
  3360. }
  3361.  
  3362.  
  3363.  
  3364. //-----------------------------------------------------------------------------
  3365. // Purpose:
  3366. // Input  : *pEntity -
  3367. // Output : Returns true on success, false on failure.
  3368. //-----------------------------------------------------------------------------
  3369. bool CNPC_fireantlion::QuerySeeEntity( CBaseEntity *pEntity, bool bOnlyHateOrFearIfNPC )
  3370. {
  3371.         //If we're under the ground, don't look at enemies
  3372.         if ( IsEffectActive( EF_NODRAW ) )
  3373.                 return false;
  3374.  
  3375.         return BaseClass::QuerySeeEntity(pEntity, bOnlyHateOrFearIfNPC);
  3376. }
  3377.  
  3378. //-----------------------------------------------------------------------------
  3379. // Purpose: Turns the fireantlion's wings on or off
  3380. // Input  : state - on or off
  3381. //-----------------------------------------------------------------------------
  3382. void CNPC_fireantlion::SetWings( bool state )
  3383. {
  3384.         if ( m_bWingsOpen == state )
  3385.                 return;
  3386.  
  3387.         m_bWingsOpen = state;
  3388.  
  3389.         if ( m_bWingsOpen )
  3390.         {
  3391.                 CPASAttenuationFilter filter( this, "NPC_fireantlion.WingsOpen" );
  3392.                 filter.MakeReliable();
  3393.  
  3394.                 EmitSound( filter, entindex(), "NPC_fireantlion.WingsOpen" );
  3395.                 SetBodygroup( 1, 1 );
  3396.                 m_bLoopingStarted = true;
  3397.         }
  3398.         else
  3399.         {
  3400.                 StopSound( "NPC_fireantlion.WingsOpen" );
  3401.                 SetBodygroup( 1, 0 );
  3402.         }
  3403. }
  3404.  
  3405. //-----------------------------------------------------------------------------
  3406. // Purpose:
  3407. //-----------------------------------------------------------------------------
  3408. void CNPC_fireantlion::Burrow( void )
  3409. {
  3410.         SetWings( false );
  3411.  
  3412.         //Stop us from taking damage and being solid
  3413.         m_spawnflags |= SF_NPC_GAG;
  3414. }
  3415.  
  3416. //-----------------------------------------------------------------------------
  3417. // Purpose:
  3418. //-----------------------------------------------------------------------------
  3419. void CNPC_fireantlion::Unburrow( void )
  3420. {
  3421.         m_bStartBurrowed = false;
  3422.         SetWings( false );
  3423.  
  3424.         //Become solid again and visible
  3425.         m_spawnflags &= ~SF_NPC_GAG;
  3426.         RemoveSolidFlags( FSOLID_NOT_SOLID );
  3427.         m_takedamage    = DAMAGE_YES;
  3428.  
  3429.         SetGroundEntity( NULL );
  3430.  
  3431.         //If we have an enemy, come out facing them
  3432.         if ( GetEnemy() )
  3433.         {
  3434.                 Vector  dir = GetEnemy()->GetAbsOrigin() - GetAbsOrigin();
  3435.                 VectorNormalize(dir);
  3436.  
  3437.                 QAngle angles = GetAbsAngles();
  3438.                 angles[ YAW ] = UTIL_VecToYaw( dir );
  3439.                 SetLocalAngles( angles );
  3440.         }
  3441.  
  3442.         //fire output upon unburrowing
  3443.         m_OnUnBurrowed.FireOutput( this, this );
  3444. }
  3445.  
  3446. //-----------------------------------------------------------------------------
  3447. // Purpose:
  3448. // Input  : &inputdata -
  3449. //-----------------------------------------------------------------------------
  3450. void CNPC_fireantlion::InputUnburrow( inputdata_t &inputdata )
  3451. {
  3452.         if ( IsAlive() == false )
  3453.                 return;
  3454.  
  3455.         SetSchedule( SCHED_fireantlion_WAIT_UNBORROW );
  3456. }
  3457.  
  3458. //-----------------------------------------------------------------------------
  3459. // Purpose:
  3460. // Input  : &inputdata -
  3461. //-----------------------------------------------------------------------------
  3462. void CNPC_fireantlion::InputBurrow( inputdata_t &inputdata )
  3463. {
  3464.         if ( IsAlive() == false )
  3465.                 return;
  3466.  
  3467.         SetSchedule( SCHED_fireantlion_BURROW_IN );
  3468. }
  3469.  
  3470. //-----------------------------------------------------------------------------
  3471. // Purpose:
  3472. // Input  : &inputdata -
  3473. //-----------------------------------------------------------------------------
  3474. void CNPC_fireantlion::InputBurrowAway( inputdata_t &inputdata )
  3475. {
  3476.         if ( IsAlive() == false )
  3477.                 return;
  3478.  
  3479.         SetSchedule( SCHED_fireantlion_BURROW_AWAY );
  3480. }
  3481.  
  3482. //-----------------------------------------------------------------------------
  3483. // Purpose:
  3484. //-----------------------------------------------------------------------------
  3485. void CNPC_fireantlion::CreateDust( bool placeDecal )
  3486. {
  3487.         trace_t tr;
  3488.         AI_TraceLine( GetAbsOrigin()+Vector(0,0,1), GetAbsOrigin()-Vector(0,0,64), MASK_SOLID_BRUSHONLY | CONTENTS_PLAYERCLIP | CONTENTS_MONSTERCLIP, this, COLLISION_GROUP_NONE, &tr );
  3489.  
  3490.         if ( tr.fraction < 1.0f )
  3491.         {
  3492.                 const surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps );
  3493.  
  3494.                 if ( hl2_episodic.GetBool() == true || ( pdata->game.material == CHAR_TEX_CONCRETE ) ||
  3495.                          ( pdata->game.material == CHAR_TEX_DIRT ) ||
  3496.                          ( pdata->game.material == CHAR_TEX_SAND ) )
  3497.                 {
  3498.  
  3499.                         if ( !m_bSuppressUnburrowEffects )
  3500.                         {
  3501.                                 UTIL_CreateAntlionDust( tr.endpos + Vector(0,0,24), GetAbsAngles() );
  3502.                                
  3503.                                 if ( placeDecal )
  3504.                                 {
  3505.                                         UTIL_DecalTrace( &tr, "fireantlion.Unburrow" );
  3506.                                 }
  3507.                         }
  3508.                 }
  3509.         }
  3510. }
  3511.  
  3512. //-----------------------------------------------------------------------------
  3513. // Purpose:
  3514. // Input  : *pSound -
  3515. //-----------------------------------------------------------------------------
  3516. bool CNPC_fireantlion::QueryHearSound( CSound *pSound )
  3517. {
  3518.         if ( !BaseClass::QueryHearSound( pSound ) )
  3519.                 return false;
  3520.                
  3521.         if ( pSound->m_iType == SOUND_BUGBAIT )
  3522.         {
  3523.                 //Must be more recent than the current
  3524.                 if ( pSound->SoundExpirationTime() <= m_flIgnoreSoundTime )
  3525.                         return false;
  3526.  
  3527.                 //If we can hear it, store it
  3528.                 m_bHasHeardSound = (pSound != NULL);
  3529.                 if ( m_bHasHeardSound )
  3530.                 {
  3531.                         m_vecHeardSound = pSound->GetSoundOrigin();
  3532.                         m_flIgnoreSoundTime     = pSound->SoundExpirationTime();
  3533.                 }
  3534.         }
  3535.  
  3536.         //Do the normal behavior at this point
  3537.         return true;
  3538. }
  3539.  
  3540. //-----------------------------------------------------------------------------
  3541. // Purpose: Allows for modification of the interrupt mask for the current schedule.
  3542. //                      In the most cases the base implementation should be called first.
  3543. //-----------------------------------------------------------------------------
  3544. void CNPC_fireantlion::BuildScheduleTestBits( void )
  3545. {
  3546.         //Don't allow any modifications when scripted
  3547.         if ( m_NPCState == NPC_STATE_SCRIPT )
  3548.                 return;
  3549.  
  3550.         // If we're allied with the player, don't be startled by him
  3551.         if ( IsAllied() )
  3552.         {
  3553.                 ClearCustomInterruptCondition( COND_HEAR_PLAYER );
  3554.                 SetCustomInterruptCondition( COND_PLAYER_PUSHING );
  3555.         }
  3556.  
  3557.         //Make sure we interrupt a run schedule if we can jump
  3558.         if ( IsCurSchedule(SCHED_CHASE_ENEMY) )
  3559.         {
  3560.                 SetCustomInterruptCondition( COND_fireantlion_CAN_JUMP );
  3561.                 SetCustomInterruptCondition( COND_ENEMY_UNREACHABLE );
  3562.         }
  3563.  
  3564.         if ( !IsCurSchedule( SCHED_fireantlion_DROWN ) )
  3565.         {
  3566.                 // Interrupt any schedule unless already drowning.
  3567.                 SetCustomInterruptCondition( COND_fireantlion_IN_WATER );
  3568.         }
  3569.         else
  3570.         {
  3571.                 // Don't stop drowning just because you're in water!
  3572.                 ClearCustomInterruptCondition( COND_fireantlion_IN_WATER );
  3573.         }
  3574.  
  3575.         // Make sure we don't stop in midair
  3576.         /*
  3577.         if ( GetActivity() == ACT_JUMP || GetActivity() == ACT_GLIDE || GetActivity() == ACT_LAND )
  3578.         {
  3579.                 ClearCustomInterruptCondition( COND_NEW_ENEMY );
  3580.         }
  3581.         */
  3582.        
  3583.         //Interrupt any schedule unless already fleeing, burrowing, burrowed, or unburrowing.
  3584.         if( !IsCurSchedule(SCHED_fireantlion_FLEE_THUMPER)                      &&             
  3585.                 !IsCurSchedule(SCHED_fireantlion_FLEE_PHYSICS_DANGER)   &&             
  3586.                 !IsCurSchedule(SCHED_fireantlion_BURROW_IN)                             &&             
  3587.                 !IsCurSchedule(SCHED_fireantlion_WAIT_UNBORROW)                 &&             
  3588.                 !IsCurSchedule(SCHED_fireantlion_BURROW_OUT)                    &&
  3589.                 !IsCurSchedule(SCHED_fireantlion_BURROW_WAIT)                   &&
  3590.                 !IsCurSchedule(SCHED_fireantlion_WAIT_FOR_UNBORROW_TRIGGER)&&
  3591.                 !IsCurSchedule(SCHED_fireantlion_WAIT_FOR_CLEAR_UNBORROW)&&
  3592.                 !IsCurSchedule(SCHED_fireantlion_WAIT_UNBORROW)                 &&
  3593.                 !IsCurSchedule(SCHED_fireantlion_JUMP)                                  &&
  3594.                 !IsCurSchedule(SCHED_fireantlion_FLIP)                                  &&
  3595.                 !IsCurSchedule(SCHED_fireantlion_DISMOUNT_NPC)                  &&
  3596.                 ( GetFlags() & FL_ONGROUND ) )
  3597.         {
  3598.                 // Only do these if not jumping as well
  3599.                 if (!IsCurSchedule(SCHED_fireantlion_JUMP))
  3600.                 {
  3601.                         if ( GetEnemy() == NULL )
  3602.                         {
  3603.                                 SetCustomInterruptCondition( COND_HEAR_PHYSICS_DANGER );
  3604.                         }
  3605.                        
  3606.                         SetCustomInterruptCondition( COND_HEAR_THUMPER );
  3607.                         SetCustomInterruptCondition( COND_HEAR_BUGBAIT );
  3608.                         SetCustomInterruptCondition( COND_fireantlion_FLIPPED );
  3609.                         SetCustomInterruptCondition( COND_fireantlion_CAN_JUMP_AT_TARGET );
  3610.  
  3611.                         if ( GetNavType() != NAV_JUMP )
  3612.                                  SetCustomInterruptCondition( COND_fireantlion_RECEIVED_ORDERS );
  3613.                 }
  3614.  
  3615.                 SetCustomInterruptCondition( COND_fireantlion_ON_NPC );
  3616.         }
  3617. }
  3618.  
  3619. //-----------------------------------------------------------------------------
  3620. // Purpose:
  3621. // Input  : *pEnemy -
  3622. // Output : Returns true on success, false on failure.
  3623. //-----------------------------------------------------------------------------
  3624. bool CNPC_fireantlion::IsValidEnemy( CBaseEntity *pEnemy )
  3625. {
  3626.         //See if fireantlions are friendly to the player in this map
  3627.         if ( IsAllied() && pEnemy->IsPlayer() )
  3628.                 return false;
  3629.  
  3630.         if ( pEnemy->IsWorld() )
  3631.                 return false;
  3632.  
  3633.         //If we're chasing bugbait, close to within a certain radius before picking up enemies
  3634.         if ( IsCurSchedule( GetGlobalScheduleId( SCHED_fireantlion_CHASE_BUGBAIT ) ) && ( GetNavigator() != NULL ) )
  3635.         {
  3636.                 //If the enemy is without the target radius, then don't allow them
  3637. //              if ( ( GetNavigator()->IsGoalActive() ) && ( GetNavigator()->GetGoalPos() - pEnemy->GetAbsOrigin() ).Length() > bugbait_radius.GetFloat() )
  3638.                         return false;
  3639.         }
  3640.  
  3641.         // If we're following an entity we limit our attack distances
  3642.         if ( m_FollowBehavior.GetFollowTarget() != NULL )
  3643.         {
  3644.                 float enemyDist = ( pEnemy->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr();
  3645.  
  3646.                 if ( m_flObeyFollowTime > gpGlobals->curtime )
  3647.                 {
  3648.                         // Unless we're right next to the enemy, follow our target
  3649.                         if ( enemyDist > (128*128) )
  3650.                                 return false;
  3651.                 }
  3652.                 else
  3653.                 {
  3654.                         // Otherwise don't follow if the target is far
  3655.                         if ( enemyDist > (2000*2000) )
  3656.                                 return false;
  3657.                 }
  3658.         }
  3659.  
  3660.         return BaseClass::IsValidEnemy( pEnemy );
  3661. }
  3662.  
  3663. //-----------------------------------------------------------------------------
  3664. // Purpose:
  3665. //-----------------------------------------------------------------------------
  3666. void CNPC_fireantlion::GatherConditions( void )
  3667. {
  3668.         BaseClass::GatherConditions();
  3669.  
  3670.         // See if I've landed on an NPC!
  3671.         CBaseEntity *pGroundEnt = GetGroundEntity();
  3672.        
  3673.         if ( ( ( pGroundEnt != NULL ) && ( pGroundEnt->GetSolidFlags() & FSOLID_NOT_STANDABLE ) ) && ( GetFlags() & FL_ONGROUND ) && ( !IsEffectActive( EF_NODRAW ) && !pGroundEnt->IsEffectActive( EF_NODRAW ) ) )
  3674.         {
  3675.                 SetCondition( COND_fireantlion_ON_NPC );
  3676.         }
  3677.         else
  3678.         {
  3679.                 ClearCondition( COND_fireantlion_ON_NPC );
  3680.         }
  3681.  
  3682.         // See if our follow target is too far off
  3683. /*      if ( m_hFollowTarget != NULL )
  3684.         {
  3685.                 float targetDist = UTIL_DistApprox( WorldSpaceCenter(), m_hFollowTarget->GetAbsOrigin() );
  3686.  
  3687.                 if ( targetDist > 400 )
  3688.                 {
  3689.                         SetCondition( COND_fireantlion_FOLLOW_TARGET_TOO_FAR );
  3690.                 }
  3691.                 else
  3692.                 {
  3693.                         ClearCondition( COND_fireantlion_FOLLOW_TARGET_TOO_FAR );
  3694.                 }
  3695.         }*/
  3696.  
  3697.         if ( IsCurSchedule( SCHED_fireantlion_BURROW_WAIT ) == false &&
  3698.                  IsCurSchedule(SCHED_fireantlion_BURROW_IN) == false &&
  3699.                  IsCurSchedule(SCHED_fireantlion_BURROW_OUT) == false &&
  3700.                  IsCurSchedule(SCHED_FALL_TO_GROUND ) == false &&
  3701.                  IsEffectActive( EF_NODRAW ) == false )
  3702.         {
  3703.                 if( m_lifeState == LIFE_ALIVE && GetWaterLevel() > 1 )
  3704.                 {
  3705.                         // Start Drowning!
  3706.                         SetCondition( COND_fireantlion_IN_WATER );
  3707.                 }
  3708.         }
  3709.  
  3710.         //Ignore the player pushing me if I'm flipped over!
  3711.         if ( IsCurSchedule( SCHED_fireantlion_FLIP ) )
  3712.                  ClearCondition( COND_PLAYER_PUSHING );
  3713. }
  3714.  
  3715. //-----------------------------------------------------------------------------
  3716. // Purpose:
  3717. //-----------------------------------------------------------------------------
  3718. void CNPC_fireantlion::PrescheduleThink( void )
  3719. {
  3720.         UpdateHead();
  3721.  
  3722.         Activity eActivity = GetActivity();
  3723.  
  3724.         //See if we need to play their agitated sound
  3725.         if ( ( eActivity == ACT_fireantlion_RUN_AGITATED ) && ( m_bAgitatedSound == false ) )
  3726.         {
  3727.                 //Start sound
  3728.                 CPASAttenuationFilter filter( this, "NPC_fireantlion.LoopingAgitated" );
  3729.                 filter.MakeReliable();
  3730.  
  3731.                 EmitSound( filter, entindex(), "NPC_fireantlion.LoopingAgitated" );
  3732.                 m_bAgitatedSound = true;
  3733.         }
  3734.         else if ( ( eActivity != ACT_fireantlion_RUN_AGITATED ) && ( m_bAgitatedSound == true ) )
  3735.         {
  3736.                 //Stop sound
  3737.                 StopSound( "NPC_fireantlion.LoopingAgitated" );
  3738.                 m_bAgitatedSound = false;
  3739.         }
  3740.  
  3741.         //See if our wings got interrupted from being turned off
  3742.         if (    ( m_bWingsOpen ) &&
  3743.                         ( eActivity != ACT_fireantlion_JUMP_START ) &&
  3744.                         ( eActivity != ACT_JUMP ) &&
  3745.                         ( eActivity != ACT_GLIDE ) &&
  3746.                         ( eActivity != ACT_fireantlion_LAND ) &&
  3747.                         ( eActivity != ACT_fireantlion_DISTRACT ))
  3748.         {
  3749.                 SetWings( false );
  3750.         }
  3751.  
  3752.         // Make sure we've turned off our burrow state if we're not in it
  3753.         if ( IsEffectActive( EF_NODRAW ) &&
  3754.                  ( eActivity != ACT_fireantlion_BURROW_IDLE ) &&
  3755.                  ( eActivity != ACT_fireantlion_BURROW_OUT ) &&
  3756.                  ( eActivity != ACT_fireantlion_BURROW_IN) )
  3757.         {
  3758.                 DevMsg( "fireantlion failed to unburrow properly!\n" );
  3759.                 Assert( 0 );
  3760.                 RemoveEffects( EF_NODRAW );
  3761.                 RemoveSolidFlags( FSOLID_NOT_SOLID );
  3762.                 m_takedamage    = DAMAGE_YES;
  3763.                 RemoveFlag( FL_NOTARGET );
  3764.                 m_spawnflags &= ~SF_NPC_GAG;
  3765.         }
  3766.  
  3767.         //New Enemy? Try to jump at him.
  3768.         if ( HasCondition( COND_NEW_ENEMY ) )
  3769.         {
  3770.                 m_flJumpTime = 0.0f;
  3771.         }
  3772.  
  3773.         // See if we should jump because of desirables conditions, or a scripted request
  3774.         if ( ShouldJump() )
  3775.         {
  3776.                 SetCondition( COND_fireantlion_CAN_JUMP );
  3777.         }
  3778.         else
  3779.         {
  3780.                 ClearCondition( COND_fireantlion_CAN_JUMP );
  3781.         }
  3782.  
  3783.         BaseClass::PrescheduleThink();
  3784. }
  3785.  
  3786. //-----------------------------------------------------------------------------
  3787. // Purpose:
  3788. // Input  : flDamage -
  3789. //                      bitsDamageType -
  3790. // Output : Returns true on success, false on failure.
  3791. //-----------------------------------------------------------------------------
  3792. bool CNPC_fireantlion::IsLightDamage( const CTakeDamageInfo &info )
  3793. {
  3794.         if ( ( random->RandomInt( 0, 1 ) ) && ( info.GetDamage() > 3 ) )
  3795.                 return true;
  3796.  
  3797.         return false;
  3798. }
  3799.  
  3800. //-----------------------------------------------------------------------------
  3801. // Purpose:
  3802. // Output : Returns true on success, false on failure.
  3803. //-----------------------------------------------------------------------------
  3804. bool CNPC_fireantlion::IsAllied( void )
  3805. {
  3806.         return ( GlobalEntity_GetState( "fireantlion_allied" ) == GLOBAL_ON );
  3807. }
  3808.  
  3809. //-----------------------------------------------------------------------------
  3810. // Purpose:
  3811. // Output : Returns true on success, false on failure.
  3812. //-----------------------------------------------------------------------------
  3813. bool CNPC_fireantlion::ShouldResumeFollow( void )
  3814. {
  3815.         if ( IsAllied() == false )
  3816.                 return false;
  3817.  
  3818.         if ( m_MoveState == fireantlion_MOVE_FOLLOW || m_hFollowTarget == NULL )
  3819.                 return false;
  3820.  
  3821.         if ( m_flSuppressFollowTime > gpGlobals->curtime )
  3822.                 return false;
  3823.  
  3824.         if ( GetEnemy() != NULL )
  3825.         {
  3826.                 m_flSuppressFollowTime = gpGlobals->curtime + random->RandomInt( 5, 10 );
  3827.                 return false;
  3828.         }
  3829.  
  3830.         //TODO: See if the follow target has wandered off too far from where we last followed them to
  3831.        
  3832.         return true;
  3833. }
  3834.  
  3835. //-----------------------------------------------------------------------------
  3836. // Purpose:
  3837. // Output : Returns true on success, false on failure.
  3838. //-----------------------------------------------------------------------------
  3839. bool CNPC_fireantlion::ShouldAbandonFollow( void )
  3840. {
  3841.         // Never give up if we can see the goal
  3842.         if ( m_FollowBehavior.FollowTargetVisible() )
  3843.                 return false;
  3844.  
  3845.         // Never give up if we're too close
  3846.         float flDistance = UTIL_DistApprox2D( m_FollowBehavior.GetFollowTarget()->WorldSpaceCenter(), WorldSpaceCenter() );
  3847.  
  3848.         if ( flDistance < 1500 )
  3849.                 return false;
  3850.  
  3851.         if ( flDistance > 1500 * 2.0f )
  3852.                 return true;
  3853.  
  3854.         // If we've failed too many times, give up
  3855.         if ( m_FollowBehavior.GetNumFailedFollowAttempts() )
  3856.                 return true;
  3857.  
  3858.         // If the target simply isn't reachable to us, give up
  3859.         if ( m_FollowBehavior.TargetIsUnreachable() )
  3860.                 return true;
  3861.  
  3862.         return false;
  3863. }
  3864.  
  3865. //-----------------------------------------------------------------------------
  3866. // Purpose:
  3867. // Input  : *pTarget -
  3868. //-----------------------------------------------------------------------------
  3869. void CNPC_fireantlion::SetFightTarget( CBaseEntity *pTarget )
  3870. {
  3871.         m_hFightGoalTarget = pTarget;
  3872.  
  3873.         SetCondition( COND_fireantlion_RECEIVED_ORDERS );
  3874. }
  3875.  
  3876. //-----------------------------------------------------------------------------
  3877. // Purpose:
  3878. // Input  : &inputdata -
  3879. //-----------------------------------------------------------------------------
  3880. void CNPC_fireantlion::InputFightToPosition( inputdata_t &inputdata )
  3881. {
  3882.         if ( IsAlive() == false )
  3883.                 return;
  3884.  
  3885.         CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, inputdata.value.String(), NULL, inputdata.pActivator, inputdata.pCaller );
  3886.  
  3887.         if ( pEntity != NULL )
  3888.         {
  3889.                 SetFightTarget( pEntity );
  3890.                 SetFollowTarget( NULL );
  3891.         }
  3892. }
  3893.  
  3894. //-----------------------------------------------------------------------------
  3895. // Purpose:
  3896. // Input  : &inputdata -
  3897. //-----------------------------------------------------------------------------
  3898. void CNPC_fireantlion::InputStopFightToPosition( inputdata_t &inputdata )
  3899. {
  3900.         SetFightTarget( NULL );
  3901. }
  3902.  
  3903. //-----------------------------------------------------------------------------
  3904. // Purpose:
  3905. // Input  : *pEnemy -
  3906. //-----------------------------------------------------------------------------
  3907. void CNPC_fireantlion::GatherEnemyConditions( CBaseEntity *pEnemy )
  3908. {
  3909.         // Do the base class
  3910.         BaseClass::GatherEnemyConditions( pEnemy );
  3911.  
  3912.         // Only continue if we burrow when eluded
  3913.         if ( ( m_spawnflags & SF_fireantlion_BURROW_ON_ELUDED ) == false )
  3914.                 return;
  3915.  
  3916.         // If we're not already too far away, check again
  3917.         //TODO: Check to make sure we don't already have a condition set that removes the need for this
  3918.         if ( HasCondition( COND_ENEMY_UNREACHABLE ) == false )
  3919.         {
  3920.                 Vector  predPosition;
  3921.                 UTIL_PredictedPosition( GetEnemy(), 1.0f, &predPosition );
  3922.  
  3923.                 Vector  predDir = ( predPosition - GetAbsOrigin() );
  3924.                 float   predLength = VectorNormalize( predDir );
  3925.  
  3926.                 // See if we'll be outside our effective target range
  3927.                 if ( predLength > m_flEludeDistance )
  3928.                 {
  3929.                         Vector  predVelDir = ( predPosition - GetEnemy()->GetAbsOrigin() );
  3930.                         float   predSpeed  = VectorNormalize( predVelDir );
  3931.  
  3932.                         // See if the enemy is moving mostly away from us
  3933.                         if ( ( predSpeed > 512.0f ) && ( DotProduct( predVelDir, predDir ) > 0.0f ) )
  3934.                         {
  3935.                                 // Mark the enemy as eluded and burrow away
  3936.                                 ClearEnemyMemory();
  3937.                                 SetEnemy( NULL );
  3938.                                 SetIdealState( NPC_STATE_ALERT );
  3939.                                 SetCondition( COND_ENEMY_UNREACHABLE );
  3940.                         }
  3941.                 }
  3942.         }
  3943. }
  3944.  
  3945. //-----------------------------------------------------------------------------
  3946. // Purpose:
  3947. // Input  : &info -
  3948. // Output : Returns true on success, false on failure.
  3949. //-----------------------------------------------------------------------------
  3950. bool CNPC_fireantlion::ShouldGib( const CTakeDamageInfo &info )
  3951. {
  3952.         // If we're being hoisted, we only want to gib when the barnacle hurts us with his bite!
  3953.         if ( IsEFlagSet( EFL_IS_BEING_LIFTED_BY_BARNACLE ) )
  3954.         {
  3955.                 if ( info.GetAttacker() && info.GetAttacker()->Classify() != CLASS_BARNACLE )
  3956.                         return false;
  3957.  
  3958.                 return true;
  3959.         }
  3960.  
  3961.         if ( info.GetDamageType() & (DMG_NEVERGIB|DMG_DISSOLVE) )
  3962.                 return false;
  3963.  
  3964. #ifdef HL2_EPISODIC
  3965.         if ( IsWorker() && fireantlion_WORKERS_BURST() )
  3966.                 return !m_bDontExplode;
  3967. #endif
  3968.  
  3969.         if ( info.GetDamageType() & (DMG_ALWAYSGIB|DMG_BLAST) )
  3970.                 return true;
  3971.  
  3972.         if ( m_iHealth < -20 )
  3973.                 return true;
  3974.        
  3975.         return false;
  3976. }
  3977.  
  3978. //-----------------------------------------------------------------------------
  3979. // Purpose:
  3980. // Output : Returns true on success, false on failure.
  3981. //-----------------------------------------------------------------------------
  3982. bool CNPC_fireantlion::CorpseGib( const CTakeDamageInfo &info )
  3983. {
  3984. #ifdef HL2_EPISODIC
  3985.  
  3986.         if ( IsWorker() )
  3987.         {
  3988.                 DoPoisonBurst();
  3989.         }
  3990.         else
  3991. #endif // HL2_EPISODIC
  3992.         {
  3993.                 // Use the bone position to handle being moved by an animation (like a dynamic scripted sequence)
  3994.                 static int s_nBodyBone = -1;
  3995.                 if ( s_nBodyBone == -1 )
  3996.                 {
  3997.                         s_nBodyBone = LookupBone( "fireantlion.Body_Bone" );
  3998.                 }
  3999.  
  4000.                 Vector vecOrigin;
  4001.                 QAngle angBone;
  4002.                 GetBonePosition( s_nBodyBone, vecOrigin, angBone );
  4003.  
  4004.                 DispatchParticleEffect( "fireantlionGib", vecOrigin, QAngle( 0, 0, 0 ) );
  4005.         }
  4006.  
  4007.         Vector velocity = vec3_origin;
  4008.         AngularImpulse  angVelocity = RandomAngularImpulse( -150, 150 );
  4009.         breakablepropparams_t params( EyePosition(), GetAbsAngles(), velocity, angVelocity );
  4010.         params.impactEnergyScale = 1.0f;
  4011.         params.defBurstScale = 150.0f;
  4012.         params.defCollisionGroup = COLLISION_GROUP_DEBRIS;
  4013.         PropBreakableCreateAll( GetModelIndex(), NULL, params, this, -1, true, true );
  4014.  
  4015.         return true;
  4016. }
  4017.  
  4018. //-----------------------------------------------------------------------------
  4019. // Purpose:
  4020. // Input  : *pOther -
  4021. //-----------------------------------------------------------------------------
  4022. void CNPC_fireantlion::Touch( CBaseEntity *pOther )
  4023. {
  4024.         //See if the touching entity is a vehicle
  4025.         CBasePlayer *pPlayer = ToBasePlayer( AI_GetSinglePlayer() );
  4026.        
  4027.         // FIXME: Technically we'll want to check to see if a vehicle has touched us with the player OR NPC driver
  4028.  
  4029.         if ( pPlayer && pPlayer->IsInAVehicle() )
  4030.         {
  4031.                 IServerVehicle  *pVehicle = pPlayer->GetVehicle();
  4032.                 CBaseEntity *pVehicleEnt = pVehicle->GetVehicleEnt();
  4033.  
  4034.                 if ( pVehicleEnt == pOther )
  4035.                 {
  4036.                         CPropVehicleDriveable   *pDrivableVehicle = dynamic_cast<CPropVehicleDriveable *>( pVehicleEnt );
  4037.  
  4038.                         if ( pDrivableVehicle != NULL )
  4039.                         {
  4040.                                 //Get tossed!
  4041.                                 Vector  vecShoveDir = pOther->GetAbsVelocity();
  4042.                                 Vector  vecTargetDir = GetAbsOrigin() - pOther->GetAbsOrigin();
  4043.                                
  4044.                                 VectorNormalize( vecShoveDir );
  4045.                                 VectorNormalize( vecTargetDir );
  4046.  
  4047.                                 bool bBurrowingOut = IsCurSchedule( SCHED_fireantlion_BURROW_OUT );
  4048.  
  4049.                                 if ( ( ( pDrivableVehicle->m_nRPM > 75 ) && DotProduct( vecShoveDir, vecTargetDir ) <= 0 ) || bBurrowingOut == true )
  4050.                                 {
  4051.                                         if ( IsFlipped() || bBurrowingOut == true )
  4052.                                         {
  4053.                                                 float flDamage = m_iHealth;
  4054.  
  4055.                                                 if ( random->RandomInt( 0, 10 ) > 4 )
  4056.                                                          flDamage += 25;
  4057.                                                                        
  4058.                                                 CTakeDamageInfo dmgInfo( pVehicleEnt, pPlayer, flDamage, DMG_VEHICLE );
  4059.                                        
  4060.                                                 CalculateMeleeDamageForce( &dmgInfo, vecShoveDir, pOther->GetAbsOrigin() );
  4061.                                                 TakeDamage( dmgInfo );
  4062.                                         }
  4063.                                         else
  4064.                                         {
  4065.                                                 // We're being shoved
  4066.                                                 CTakeDamageInfo dmgInfo( pVehicleEnt, pPlayer, 0, DMG_VEHICLE );
  4067.                                                 PainSound( dmgInfo );
  4068.  
  4069.                                                 SetCondition( COND_fireantlion_FLIPPED );
  4070.  
  4071.                                                 vecTargetDir[2] = 0.0f;
  4072.  
  4073.                                                 ApplyAbsVelocityImpulse( ( vecTargetDir * 250.0f ) + Vector(0,0,64.0f) );
  4074.                                                 SetGroundEntity( NULL );
  4075.  
  4076.                                                 CSoundEnt::InsertSound( SOUND_PHYSICS_DANGER, GetAbsOrigin(), 256, 0.5f, this );
  4077.                                         }
  4078.                                 }
  4079.                         }
  4080.                 }
  4081.         }
  4082.  
  4083.         BaseClass::Touch( pOther );
  4084.  
  4085.         // in episodic, an fireantlion colliding with the player in midair does him damage.
  4086.         // pursuant bugs 58590, 56960, this happens only once per glide.
  4087. #ifdef HL2_EPISODIC
  4088.         if ( GetActivity() == ACT_GLIDE && IsValidEnemy( pOther ) && !m_bHasDoneAirAttack )
  4089.         {
  4090.                 CTakeDamageInfo dmgInfo( this, this, sk_fireantlion_air_attack_dmg.GetInt(), DMG_SLASH );
  4091.  
  4092.                 CalculateMeleeDamageForce( &dmgInfo, Vector( 0, 0, 1 ), GetAbsOrigin() );
  4093.                 pOther->TakeDamage( dmgInfo );
  4094.  
  4095.                 //Kick the player angles
  4096.                 bool bIsPlayer = pOther->IsPlayer();
  4097.                 if ( bIsPlayer && !(pOther->GetFlags() & FL_GODMODE ) && pOther->GetMoveType() != MOVETYPE_NOCLIP )
  4098.                 {
  4099.                         pOther->ViewPunch( QAngle( 4.0f, 0.0f, 0.0f ) );
  4100.                 }
  4101.  
  4102.                 // set my "I have already attacked someone" flag
  4103.                 if ( bIsPlayer || pOther->IsNPC())
  4104.                 {
  4105.                         m_bHasDoneAirAttack = true;
  4106.                 }
  4107.         }
  4108. #endif
  4109.  
  4110.         // Did the player touch me?
  4111.         if ( pOther->IsPlayer() )
  4112.         {
  4113.                 // Don't test for this if the pusher isn't friendly
  4114.                 if ( IsValidEnemy( pOther ) )
  4115.                         return;
  4116.  
  4117.                 // Ignore if pissed at player
  4118.                 if ( m_afMemory & bits_MEMORY_PROVOKED )
  4119.                         return;
  4120.        
  4121.                 if ( !IsCurSchedule( SCHED_MOVE_AWAY ) && !IsCurSchedule( SCHED_fireantlion_BURROW_OUT ) )
  4122.                          TestPlayerPushing( pOther );
  4123.         }
  4124.  
  4125.         //Adrian: Explode if hit by gunship!
  4126.         //Maybe only do this if hit by the propellers?
  4127.         if ( pOther->IsNPC() )
  4128.         {
  4129.                 if ( pOther->Classify() == CLASS_COMBINE_GUNSHIP )
  4130.                 {
  4131.                         float flDamage = m_iHealth + 25;
  4132.                                                
  4133.                         CTakeDamageInfo dmgInfo( pOther, pOther, flDamage, DMG_GENERIC );
  4134.                         GuessDamageForce( &dmgInfo, (pOther->GetAbsOrigin() - GetAbsOrigin()), pOther->GetAbsOrigin() );
  4135.                         TakeDamage( dmgInfo );
  4136.                 }
  4137.         }
  4138. }
  4139.  
  4140. //-----------------------------------------------------------------------------
  4141. // Purpose: turn in the direction of movement
  4142. // Output :
  4143. //-----------------------------------------------------------------------------
  4144. bool CNPC_fireantlion::OverrideMoveFacing( const AILocalMoveGoal_t &move, float flInterval )
  4145. {
  4146.         if ( hl2_episodic.GetBool() )
  4147.         {
  4148.                 if ( IsWorker() && GetEnemy() )
  4149.                 {
  4150.                         AddFacingTarget( GetEnemy(), GetEnemy()->WorldSpaceCenter(), 1.0f, 0.2f );
  4151.                         return BaseClass::OverrideMoveFacing( move, flInterval );
  4152.                 }
  4153.         }
  4154.  
  4155.         //Adrian: Make fireantlions face the thumper while they flee away.
  4156.         if ( IsCurSchedule( SCHED_fireantlion_FLEE_THUMPER ) )
  4157.         {
  4158.                 CSound *pSound = GetLoudestSoundOfType( SOUND_THUMPER );
  4159.  
  4160.                 if ( pSound )
  4161.                 {
  4162.                         AddFacingTarget( pSound->GetSoundOrigin(), 1.0, 0.5f );
  4163.                 }
  4164.         }
  4165.         else if ( GetEnemy() && GetNavigator()->GetMovementActivity() == ACT_RUN )
  4166.         {
  4167.                 // FIXME: this will break scripted sequences that walk when they have an enemy
  4168.                 Vector vecEnemyLKP = GetEnemyLKP();
  4169.                 if ( UTIL_DistApprox( vecEnemyLKP, GetAbsOrigin() ) < 512 )
  4170.                 {
  4171.                         // Only start facing when we're close enough
  4172.                         AddFacingTarget( GetEnemy(), vecEnemyLKP, 1.0, 0.2 );
  4173.                 }
  4174.         }
  4175.  
  4176.         return BaseClass::OverrideMoveFacing( move, flInterval );
  4177. }
  4178.  
  4179. //-----------------------------------------------------------------------------
  4180. // Purpose:
  4181. //-----------------------------------------------------------------------------
  4182. void CNPC_fireantlion::InputDisableJump( inputdata_t &inputdata )
  4183. {
  4184.         m_bDisableJump = true;
  4185.         CapabilitiesRemove( bits_CAP_MOVE_JUMP );
  4186. }
  4187.  
  4188. //-----------------------------------------------------------------------------
  4189. // Purpose:
  4190. //-----------------------------------------------------------------------------
  4191. void CNPC_fireantlion::InputEnableJump( inputdata_t &inputdata )
  4192. {
  4193.         m_bDisableJump = false;
  4194.         CapabilitiesAdd( bits_CAP_MOVE_JUMP );
  4195. }
  4196.  
  4197. //-----------------------------------------------------------------------------
  4198. // Purpose:
  4199. // Input  : *pTarget -
  4200. //-----------------------------------------------------------------------------
  4201. void CNPC_fireantlion::SetFollowTarget( CBaseEntity *pTarget )
  4202. {
  4203.         m_FollowBehavior.SetFollowTarget( pTarget );
  4204.         m_hFollowTarget = pTarget;
  4205.         m_flObeyFollowTime = gpGlobals->curtime + fireantlion_OBEY_FOLLOW_TIME;
  4206.  
  4207.         SetCondition( COND_fireantlion_RECEIVED_ORDERS );
  4208.  
  4209.         // Play an acknowledgement noise
  4210.         if ( m_flNextAcknowledgeTime < gpGlobals->curtime )
  4211.         {
  4212.                 EmitSound( "NPC_fireantlion.Distracted" );
  4213.                 m_flNextAcknowledgeTime = gpGlobals->curtime + 1.0f;
  4214.         }
  4215. }
  4216.  
  4217. //-----------------------------------------------------------------------------
  4218. // Purpose:
  4219. // Output : Returns true on success, false on failure.
  4220. //-----------------------------------------------------------------------------
  4221. bool CNPC_fireantlion::CreateBehaviors( void )
  4222. {
  4223.         AddBehavior( &m_FollowBehavior );
  4224.         AddBehavior( &m_AssaultBehavior );
  4225.  
  4226.         return BaseClass::CreateBehaviors();
  4227. }
  4228.  
  4229. //-----------------------------------------------------------------------------
  4230. // Purpose:
  4231. // Input  : &inputdata -
  4232. //-----------------------------------------------------------------------------
  4233. void CNPC_fireantlion::InputIgnoreBugbait( inputdata_t &inputdata )
  4234. {
  4235.         m_bIgnoreBugbait = true;
  4236. }
  4237.  
  4238. //-----------------------------------------------------------------------------
  4239. // Purpose:
  4240. // Input  : &inputdata -
  4241. //-----------------------------------------------------------------------------
  4242. void CNPC_fireantlion::InputHearBugbait( inputdata_t &inputdata )
  4243. {
  4244.         m_bIgnoreBugbait = false;
  4245. }
  4246.  
  4247. //-----------------------------------------------------------------------------
  4248. // Purpose:
  4249. // Input  : state -
  4250. //-----------------------------------------------------------------------------
  4251. void CNPC_fireantlion::SetMoveState( fireantlionMoveState_e state )
  4252. {
  4253.         m_MoveState = state;
  4254.  
  4255.         switch( m_MoveState )
  4256.         {
  4257.         case fireantlion_MOVE_FOLLOW:
  4258.  
  4259.                 m_FollowBehavior.SetFollowTarget( m_hFollowTarget );
  4260.                
  4261.                 // Clear any previous state
  4262.                 m_flSuppressFollowTime = 0;
  4263.                
  4264.                 break;
  4265.        
  4266.         case fireantlion_MOVE_FIGHT_TO_GOAL:
  4267.                
  4268.                 m_FollowBehavior.SetFollowTarget( NULL );
  4269.  
  4270.                 // Keep the time we started this
  4271.                 m_flSuppressFollowTime = gpGlobals->curtime + random->RandomInt( 10, 15 );
  4272.                 break;
  4273.  
  4274.         default:
  4275.                 break;
  4276.         }
  4277. }
  4278.  
  4279. //-----------------------------------------------------------------------------
  4280. // Purpose: Special version helps other NPCs hit overturned fireantlion
  4281. //-----------------------------------------------------------------------------
  4282. Vector CNPC_fireantlion::BodyTarget( const Vector &posSrc, bool bNoisy /*= true*/ )
  4283. {
  4284.         // Cache the bone away to avoid future lookups
  4285.         if ( m_nBodyBone == -1 )
  4286.         {
  4287.                 CBaseAnimating *pAnimating = GetBaseAnimating();
  4288.                 m_nBodyBone = pAnimating->LookupBone( "fireantlion.Body_Bone" );
  4289.         }
  4290.  
  4291.         // Get the exact position in our center of mass (thorax)
  4292.         Vector vecResult;
  4293.         QAngle vecAngle;
  4294.         GetBonePosition( m_nBodyBone, vecResult, vecAngle );
  4295.        
  4296.         if ( bNoisy )
  4297.                 return vecResult + RandomVector( -8, 8 );
  4298.  
  4299.         return vecResult;
  4300. }
  4301.  
  4302. //-----------------------------------------------------------------------------
  4303. // Purpose: Flip the fireantlion over
  4304. //-----------------------------------------------------------------------------
  4305. void CNPC_fireantlion::Flip( bool bZapped /*= false*/ )
  4306. {
  4307.         // We can't flip an already flipped fireantlion
  4308.         if ( IsFlipped() )
  4309.                 return;
  4310.  
  4311.         // Must be on the ground
  4312.         if ( ( GetFlags() & FL_ONGROUND ) == false )
  4313.                 return;
  4314.  
  4315.         // Can't be in a dynamic interation
  4316.         if ( IsRunningDynamicInteraction() )
  4317.                 return;
  4318.  
  4319.         SetCondition( COND_fireantlion_FLIPPED );
  4320.  
  4321.         if ( bZapped )
  4322.         {
  4323.                 m_flZapDuration = gpGlobals->curtime + SequenceDuration( SelectWeightedSequence( (Activity) ACT_fireantlion_ZAP_FLIP) ) + 0.1f;
  4324.  
  4325.                 EmitSound( "NPC_fireantlion.ZappedFlip"  );
  4326.         }
  4327. }
  4328.  
  4329.  
  4330. //-----------------------------------------------------------------------------
  4331. // Purpose:
  4332. // Input  : &inputdata -
  4333. //-----------------------------------------------------------------------------
  4334. void CNPC_fireantlion::InputJumpAtTarget( inputdata_t &inputdata )
  4335. {
  4336.         CBaseEntity *pJumpTarget = gEntList.FindEntityByName( NULL, inputdata.value.String(), this, inputdata.pActivator, inputdata.pCaller );
  4337.         if ( pJumpTarget == NULL )
  4338.         {
  4339.                 Msg("Unable to find jump target named (%s)\n", inputdata.value.String() );
  4340.                 return;
  4341.         }
  4342.  
  4343. #if HL2_EPISODIC
  4344.  
  4345.         // Try the jump
  4346.         AIMoveTrace_t moveTrace;
  4347.         Vector targetPos = pJumpTarget->GetAbsOrigin();
  4348.  
  4349.         // initialize jump state
  4350.         float minJumpHeight = 0.0;
  4351.         float maxHorzVel = 800.0f;
  4352.  
  4353.         // initial jump, sets baseline for minJumpHeight
  4354.         Vector vecApex;
  4355.         Vector rawJumpVel = GetMoveProbe()->CalcJumpLaunchVelocity(GetAbsOrigin(), targetPos, sv_gravity.GetFloat() * GetJumpGravity(), &minJumpHeight, maxHorzVel, &vecApex );
  4356.  
  4357.         if ( g_debug_fireantlion.GetInt() == 2 )
  4358.         {
  4359.                 NDebugOverlay::Box( targetPos, GetHullMins(), GetHullMaxs(), 0, 255, 0, 0, 5 );
  4360.                 NDebugOverlay::Line( GetAbsOrigin(), targetPos, 0, 255, 0, 0, 5 );
  4361.                 NDebugOverlay::Line( GetAbsOrigin(), rawJumpVel, 255, 255, 0, 0, 5 );
  4362.         }
  4363.  
  4364.         m_vecSavedJump = rawJumpVel;
  4365.  
  4366. #else  
  4367.  
  4368.         // Get the direction and speed to our target
  4369.         Vector vecJumpDir = ( pJumpTarget->GetAbsOrigin() - GetAbsOrigin() );
  4370.         VectorNormalize( vecJumpDir );
  4371.         vecJumpDir *= 800.0f;   // FIXME: We'd like to pass this in as a parameter, but comma delimited lists are bad
  4372.         m_vecSavedJump = vecJumpDir;
  4373.  
  4374. #endif
  4375.  
  4376.         SetCondition( COND_fireantlion_CAN_JUMP_AT_TARGET );
  4377. }
  4378.  
  4379. #if HL2_EPISODIC
  4380. //-----------------------------------------------------------------------------
  4381. // workers can explode.
  4382. //-----------------------------------------------------------------------------
  4383. void CNPC_fireantlion::DoPoisonBurst()
  4384. {
  4385.         if ( GetWaterLevel() < 2 )
  4386.         {
  4387.                 CTakeDamageInfo info( this, this, sk_fireantlion_worker_burst_damage.GetFloat(), DMG_BLAST_SURFACE | ( fireantlion_WORKER_BURST_IS_POISONOUS() ? DMG_POISON : DMG_ACID ) );
  4388.  
  4389.                 RadiusDamage( info, GetAbsOrigin(), sk_fireantlion_worker_burst_radius.GetFloat(), CLASS_NONE, this );
  4390.  
  4391.                 DispatchParticleEffect( "fireantlion_gib_02", WorldSpaceCenter(), GetAbsAngles() );
  4392.         }
  4393.         else
  4394.         {
  4395.                 CEffectData     data;
  4396.  
  4397.                 data.m_vOrigin = WorldSpaceCenter();
  4398.                 data.m_flMagnitude = 100;
  4399.                 data.m_flScale = 128;
  4400.                 data.m_fFlags = ( SF_ENVEXPLOSION_NODAMAGE | SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSMOKE );
  4401.  
  4402.                 DispatchEffect( "WaterSurfaceExplosion", data );
  4403.         }
  4404.  
  4405.         EmitSound( "NPC_fireantlion.PoisonBurstExplode" );
  4406. }
  4407. #endif
  4408.  
  4409. //-----------------------------------------------------------------------------
  4410. // Purpose:
  4411. //-----------------------------------------------------------------------------
  4412. bool CNPC_fireantlion::IsHeavyDamage( const CTakeDamageInfo &info )
  4413. {
  4414.         if ( hl2_episodic.GetBool() && IsWorker() )
  4415.         {
  4416.                 if ( m_nSustainedDamage + info.GetDamage() > 6 )
  4417.                         return true;
  4418.         }
  4419.        
  4420.         return BaseClass::IsHeavyDamage( info );
  4421. }
  4422.  
  4423. //-----------------------------------------------------------------------------
  4424. // Purpose:
  4425. // Input  : bForced -
  4426. // Output : Returns true on success, false on failure.
  4427. //-----------------------------------------------------------------------------
  4428. bool CNPC_fireantlion::CanRunAScriptedNPCInteraction( bool bForced /*= false*/ )
  4429. {
  4430.         // Workers shouldn't do DSS's because they explode
  4431.         if ( IsWorker() )
  4432.                 return false;
  4433.  
  4434.         return BaseClass::CanRunAScriptedNPCInteraction( bForced );
  4435. }
  4436.  
  4437. //---------------------------------------------------------
  4438. // Save/Restore
  4439. //---------------------------------------------------------
  4440. BEGIN_DATADESC( CfireantlionRepellant )
  4441.         DEFINE_KEYFIELD( m_flRepelRadius,       FIELD_FLOAT,    "repelradius" ),
  4442.         DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
  4443.         DEFINE_INPUTFUNC( FIELD_VOID,   "Enable", InputEnable ),
  4444.         DEFINE_INPUTFUNC( FIELD_VOID,   "Disable", InputDisable ),
  4445. END_DATADESC()
  4446.  
  4447. static CUtlVector< CHandle< CfireantlionRepellant > >m_hRepellantList;
  4448.  
  4449.  
  4450. CfireantlionRepellant::~CfireantlionRepellant()
  4451. {
  4452.         m_hRepellantList.FindAndRemove( this );
  4453. }
  4454.  
  4455. void CfireantlionRepellant::Spawn( void )
  4456. {
  4457.         BaseClass::Spawn();
  4458.         m_bEnabled = true;
  4459.  
  4460.         m_hRepellantList.AddToTail( this );
  4461. }
  4462.  
  4463. void CfireantlionRepellant::InputEnable( inputdata_t &inputdata )
  4464. {
  4465.         m_bEnabled = true;
  4466.  
  4467.         if ( m_hRepellantList.HasElement( this ) == false )
  4468.                  m_hRepellantList.AddToTail( this );
  4469. }
  4470.  
  4471. void CfireantlionRepellant::InputDisable( inputdata_t &inputdata )
  4472. {
  4473.         m_bEnabled = false;
  4474.         m_hRepellantList.FindAndRemove( this );
  4475. }
  4476.  
  4477. float CfireantlionRepellant::GetRadius( void )
  4478. {
  4479.         if ( m_bEnabled == false )
  4480.                  return 0.0f;
  4481.  
  4482.         return m_flRepelRadius;
  4483. }
  4484.  
  4485. void CfireantlionRepellant::OnRestore( void )
  4486. {
  4487.         BaseClass::OnRestore();
  4488.  
  4489.         if ( m_bEnabled == true )
  4490.         {
  4491.                 if ( m_hRepellantList.HasElement( this ) == false )
  4492.                          m_hRepellantList.AddToTail( this );
  4493.         }
  4494. }
  4495.  
  4496. bool CfireantlionRepellant::IsPositionRepellantFree( Vector vDesiredPos )
  4497. {
  4498.         for ( int i = 0; i < m_hRepellantList.Count(); i++ )
  4499.         {
  4500.                 if ( m_hRepellantList[i] )
  4501.                 {
  4502.                         CfireantlionRepellant *pRep = m_hRepellantList[i].Get();
  4503.  
  4504.                         if ( pRep )
  4505.                         {
  4506.                                 float flDist = (vDesiredPos - pRep->GetAbsOrigin()).Length();
  4507.  
  4508.                                 if ( flDist <= pRep->GetRadius() )
  4509.                                          return false;
  4510.                         }
  4511.                 }
  4512.         }
  4513.  
  4514.         return true;
  4515. }
  4516.  
  4517. LINK_ENTITY_TO_CLASS( point_fireantlion_repellant, CfireantlionRepellant);
  4518.  
  4519.  
  4520. //-----------------------------------------------------------------------------
  4521. //
  4522. // Schedules
  4523. //
  4524. //-----------------------------------------------------------------------------
  4525.  
  4526. AI_BEGIN_CUSTOM_NPC( npc_fireantlion, CNPC_fireantlion )
  4527.  
  4528.         //Register our interactions
  4529.         DECLARE_INTERACTION( g_interactionfireantlionFoundTarget )
  4530.         DECLARE_INTERACTION( g_interactionfireantlionFiredAtTarget )
  4531.  
  4532.         //Conditions
  4533.         DECLARE_CONDITION( COND_fireantlion_FLIPPED )
  4534.         DECLARE_CONDITION( COND_fireantlion_ON_NPC )
  4535.         DECLARE_CONDITION( COND_fireantlion_CAN_JUMP )
  4536.         DECLARE_CONDITION( COND_fireantlion_FOLLOW_TARGET_TOO_FAR )
  4537.         DECLARE_CONDITION( COND_fireantlion_RECEIVED_ORDERS )
  4538.         DECLARE_CONDITION( COND_fireantlion_IN_WATER )
  4539.         DECLARE_CONDITION( COND_fireantlion_CAN_JUMP_AT_TARGET )
  4540.         DECLARE_CONDITION( COND_fireantlion_SQUADMATE_KILLED )
  4541.                
  4542.         //Squad slots
  4543.         DECLARE_SQUADSLOT( SQUAD_SLOT_fireantlion_JUMP )
  4544.         DECLARE_SQUADSLOT( SQUAD_SLOT_fireantlion_WORKER_FIRE )
  4545.  
  4546.         //Tasks
  4547.         DECLARE_TASK( TASK_fireantlion_SET_CHARGE_GOAL )
  4548.         DECLARE_TASK( TASK_fireantlion_BURROW )
  4549.         DECLARE_TASK( TASK_fireantlion_UNBURROW )
  4550.         DECLARE_TASK( TASK_fireantlion_VANISH )
  4551.         DECLARE_TASK( TASK_fireantlion_FIND_BURROW_IN_POINT )
  4552.         DECLARE_TASK( TASK_fireantlion_FIND_BURROW_OUT_POINT )
  4553.         DECLARE_TASK( TASK_fireantlion_BURROW_WAIT )
  4554.         DECLARE_TASK( TASK_fireantlion_CHECK_FOR_UNBORROW )
  4555.         DECLARE_TASK( TASK_fireantlion_JUMP )
  4556.         DECLARE_TASK( TASK_fireantlion_WAIT_FOR_TRIGGER )
  4557.         DECLARE_TASK( TASK_fireantlion_GET_THUMPER_ESCAPE_PATH )
  4558.         DECLARE_TASK( TASK_fireantlion_GET_PATH_TO_BUGBAIT )
  4559.         DECLARE_TASK( TASK_fireantlion_FACE_BUGBAIT )
  4560.         DECLARE_TASK( TASK_fireantlion_DISMOUNT_NPC )
  4561.         DECLARE_TASK( TASK_fireantlion_REACH_FIGHT_GOAL )
  4562.         DECLARE_TASK( TASK_fireantlion_GET_PHYSICS_DANGER_ESCAPE_PATH )
  4563.         DECLARE_TASK( TASK_fireantlion_FACE_JUMP )
  4564.         DECLARE_TASK( TASK_fireantlion_DROWN )
  4565.         DECLARE_TASK( TASK_fireantlion_GET_PATH_TO_RANDOM_NODE )
  4566.         DECLARE_TASK( TASK_fireantlion_FIND_COVER_FROM_SAVEPOSITION )
  4567.  
  4568.         //Activities
  4569.         DECLARE_ACTIVITY( ACT_fireantlion_DISTRACT )
  4570.         DECLARE_ACTIVITY( ACT_fireantlion_DISTRACT_ARRIVED )
  4571.         DECLARE_ACTIVITY( ACT_fireantlion_JUMP_START )
  4572.         DECLARE_ACTIVITY( ACT_fireantlion_BURROW_IN )
  4573.         DECLARE_ACTIVITY( ACT_fireantlion_BURROW_OUT )
  4574.         DECLARE_ACTIVITY( ACT_fireantlion_BURROW_IDLE )
  4575.         DECLARE_ACTIVITY( ACT_fireantlion_RUN_AGITATED )
  4576.         DECLARE_ACTIVITY( ACT_fireantlion_FLIP )
  4577.         DECLARE_ACTIVITY( ACT_fireantlion_POUNCE )
  4578.         DECLARE_ACTIVITY( ACT_fireantlion_POUNCE_MOVING )
  4579.         DECLARE_ACTIVITY( ACT_fireantlion_DROWN )
  4580.         DECLARE_ACTIVITY( ACT_fireantlion_LAND )
  4581.         DECLARE_ACTIVITY( ACT_fireantlion_WORKER_EXPLODE )
  4582.         DECLARE_ACTIVITY( ACT_fireantlion_ZAP_FLIP )
  4583.  
  4584.         //Events
  4585.         DECLARE_ANIMEVENT( AE_fireantlion_WALK_FOOTSTEP )
  4586.         DECLARE_ANIMEVENT( AE_fireantlion_MELEE_HIT1 )
  4587.         DECLARE_ANIMEVENT( AE_fireantlion_MELEE_HIT2 )
  4588.         DECLARE_ANIMEVENT( AE_fireantlion_MELEE_POUNCE )
  4589.         DECLARE_ANIMEVENT( AE_fireantlion_FOOTSTEP_SOFT )
  4590.         DECLARE_ANIMEVENT( AE_fireantlion_FOOTSTEP_HEAVY )
  4591.         DECLARE_ANIMEVENT( AE_fireantlion_START_JUMP )
  4592.         DECLARE_ANIMEVENT( AE_fireantlion_BURROW_IN )
  4593.         DECLARE_ANIMEVENT( AE_fireantlion_BURROW_OUT )
  4594.         DECLARE_ANIMEVENT( AE_fireantlion_VANISH )
  4595.         DECLARE_ANIMEVENT( AE_fireantlion_OPEN_WINGS )
  4596.         DECLARE_ANIMEVENT( AE_fireantlion_CLOSE_WINGS )
  4597.         DECLARE_ANIMEVENT( AE_fireantlion_MELEE1_SOUND )
  4598.         DECLARE_ANIMEVENT( AE_fireantlion_MELEE2_SOUND )
  4599.         DECLARE_ANIMEVENT( AE_fireantlion_WORKER_EXPLODE_SCREAM )
  4600.         DECLARE_ANIMEVENT( AE_fireantlion_WORKER_EXPLODE_WARN )
  4601.         DECLARE_ANIMEVENT( AE_fireantlion_WORKER_EXPLODE )
  4602.         DECLARE_ANIMEVENT( AE_fireantlion_WORKER_SPIT )
  4603.         DECLARE_ANIMEVENT( AE_fireantlion_WORKER_DONT_EXPLODE )
  4604.  
  4605.         //Schedules
  4606.  
  4607.         //==================================================
  4608.         // Jump
  4609.         //==================================================
  4610.  
  4611.         DEFINE_SCHEDULE
  4612.         (
  4613.                 SCHED_fireantlion_JUMP,
  4614.  
  4615.                 "       Tasks"
  4616.                 "               TASK_STOP_MOVING                                0"
  4617.                 "               TASK_fireantlion_FACE_JUMP                      0"
  4618.                 "               TASK_PLAY_SEQUENCE                              ACTIVITY:ACT_fireantlion_JUMP_START"
  4619.                 "               TASK_fireantlion_JUMP                           0"
  4620.                 ""
  4621.                 "       Interrupts"
  4622.                 "               COND_TASK_FAILED"
  4623.         )
  4624.  
  4625.         //==================================================
  4626.         // Wait for unborrow (once burrow has been triggered)
  4627.         //==================================================
  4628.  
  4629.         DEFINE_SCHEDULE
  4630.         (
  4631.                 SCHED_fireantlion_WAIT_UNBORROW,
  4632.  
  4633.                 "       Tasks"
  4634.                 "               TASK_fireantlion_BURROW_WAIT            0"
  4635.                 "               TASK_SET_SCHEDULE                               SCHEDULE:SCHED_fireantlion_WAIT_FOR_CLEAR_UNBORROW"
  4636.                 ""
  4637.                 "       Interrupts"
  4638.                 "               COND_TASK_FAILED"
  4639.         )
  4640.  
  4641.         //==================================================
  4642.         // Burrow Wait
  4643.         //==================================================
  4644.  
  4645.         DEFINE_SCHEDULE
  4646.         (
  4647.                 SCHED_fireantlion_BURROW_WAIT,
  4648.  
  4649.                 "       Tasks"
  4650.                 "               TASK_SET_FAIL_SCHEDULE                          SCHEDULE:SCHED_fireantlion_BURROW_WAIT"
  4651.                 "               TASK_fireantlion_BURROW_WAIT                    1"
  4652.                 "               TASK_fireantlion_FIND_BURROW_OUT_POINT  1024"
  4653.                 "               TASK_SET_SCHEDULE                                       SCHEDULE:SCHED_fireantlion_WAIT_FOR_CLEAR_UNBORROW"
  4654.                 ""
  4655.                 "       Interrupts"
  4656.                 "               COND_TASK_FAILED"
  4657.         )
  4658.  
  4659.         //==================================================
  4660.         // Burrow In
  4661.         //==================================================
  4662.  
  4663.         DEFINE_SCHEDULE
  4664.         (
  4665.                 SCHED_fireantlion_BURROW_IN,
  4666.  
  4667.                 "       Tasks"
  4668.                 "               TASK_SET_FAIL_SCHEDULE                          SCHEDULE:SCHED_CHASE_ENEMY_FAILED"
  4669.                 "               TASK_fireantlion_BURROW                                 0"
  4670.                 "               TASK_PLAY_SEQUENCE                                      ACTIVITY:ACT_fireantlion_BURROW_IN"
  4671.                 "               TASK_fireantlion_VANISH                                 0"
  4672.                 "               TASK_SET_SCHEDULE                                       SCHEDULE:SCHED_fireantlion_BURROW_WAIT"
  4673.                 ""
  4674.                 "       Interrupts"
  4675.                 "               COND_TASK_FAILED"
  4676.         )
  4677.  
  4678.         //==================================================
  4679.         // Run to burrow in
  4680.         //==================================================
  4681.  
  4682.         DEFINE_SCHEDULE
  4683.         (
  4684.                 SCHED_fireantlion_RUN_TO_BURROW_IN,
  4685.  
  4686.                 "       Tasks"
  4687.                 "               TASK_SET_FAIL_SCHEDULE                          SCHEDULE:SCHED_CHASE_ENEMY_FAILED"
  4688.                 "               TASK_SET_TOLERANCE_DISTANCE                     8"
  4689.                 "               TASK_fireantlion_FIND_BURROW_IN_POINT   512"
  4690.                 "               TASK_RUN_PATH                                           0"
  4691.                 "               TASK_WAIT_FOR_MOVEMENT                          0"
  4692.                 "               TASK_SET_SCHEDULE                                       SCHEDULE:SCHED_fireantlion_BURROW_IN"
  4693.                 ""
  4694.                 "       Interrupts"
  4695.                 "               COND_TASK_FAILED"
  4696.                 "               COND_GIVE_WAY"
  4697.                 "               COND_CAN_MELEE_ATTACK1"
  4698.                 "               COND_CAN_MELEE_ATTACK2"
  4699.         )
  4700.  
  4701.         //==================================================
  4702.         // Burrow Out
  4703.         //==================================================
  4704.  
  4705.         DEFINE_SCHEDULE
  4706.         (
  4707.                 SCHED_fireantlion_BURROW_OUT,
  4708.  
  4709.                 "       Tasks"
  4710.                 "               TASK_SET_FAIL_SCHEDULE                  SCHEDULE:SCHED_fireantlion_BURROW_WAIT"
  4711.                 "               TASK_fireantlion_UNBURROW                       0"
  4712.                 "               TASK_PLAY_SEQUENCE                              ACTIVITY:ACT_fireantlion_BURROW_OUT"
  4713.                 ""
  4714.                 "       Interrupts"
  4715.                 "               COND_TASK_FAILED"
  4716.         )
  4717.  
  4718.         //==================================================
  4719.         // Wait for unborrow (triggered)
  4720.         //==================================================
  4721.  
  4722.         DEFINE_SCHEDULE
  4723.         (
  4724.                 SCHED_fireantlion_WAIT_FOR_UNBORROW_TRIGGER,
  4725.  
  4726.                 "       Tasks"
  4727.                 "               TASK_fireantlion_WAIT_FOR_TRIGGER       0"
  4728.                 ""
  4729.                 "       Interrupts"
  4730.                 "               COND_TASK_FAILED"
  4731.         )
  4732.  
  4733.         //==================================================
  4734.         // Wait for clear burrow spot (triggered)
  4735.         //==================================================
  4736.  
  4737.         DEFINE_SCHEDULE
  4738.         (
  4739.                 SCHED_fireantlion_WAIT_FOR_CLEAR_UNBORROW,
  4740.  
  4741.                 "       Tasks"
  4742.                 "               TASK_SET_FAIL_SCHEDULE                          SCHEDULE:SCHED_fireantlion_BURROW_WAIT"
  4743.                 "               TASK_fireantlion_CHECK_FOR_UNBORROW             1"
  4744.                 "               TASK_SET_SCHEDULE                                       SCHEDULE:SCHED_fireantlion_BURROW_OUT"
  4745.                 ""
  4746.                 "       Interrupts"
  4747.                 "               COND_TASK_FAILED"
  4748.         )
  4749.  
  4750.         //==================================================
  4751.         // Run from the sound of a thumper!
  4752.         //==================================================
  4753.         DEFINE_SCHEDULE
  4754.         (
  4755.                 SCHED_fireantlion_FLEE_THUMPER,
  4756.                
  4757.                 "       Tasks"
  4758.                 "               TASK_SET_FAIL_SCHEDULE                                  SCHEDULE:SCHED_IDLE_STAND"
  4759.                 "               TASK_fireantlion_GET_THUMPER_ESCAPE_PATH        0"
  4760.                 "               TASK_RUN_PATH                                                   0"
  4761.                 "               TASK_WAIT_FOR_MOVEMENT                                  0"
  4762.                 "               TASK_STOP_MOVING                                                0"
  4763.                 "               TASK_PLAY_SEQUENCE                                              ACTIVITY:ACT_fireantlion_DISTRACT_ARRIVED"
  4764.                 ""
  4765.                 "       Interrupts"
  4766.                 "               COND_TASK_FAILED"
  4767.                 "               COND_fireantlion_FLIPPED"
  4768.         )
  4769.  
  4770.         //==================================================
  4771.         // SCHED_fireantlion_CHASE_BUGBAIT
  4772.         //==================================================
  4773.         DEFINE_SCHEDULE
  4774.         (
  4775.                 SCHED_fireantlion_CHASE_BUGBAIT,
  4776.  
  4777.                 "       Tasks"
  4778.                 "               TASK_STOP_MOVING                                        0"
  4779.                 "               TASK_fireantlion_GET_PATH_TO_BUGBAIT    0"
  4780.                 "               TASK_RUN_PATH                                           0"
  4781.                 "               TASK_WAIT_FOR_MOVEMENT                          0"
  4782.                 "               TASK_STOP_MOVING                                        0"
  4783.                 "               TASK_fireantlion_FACE_BUGBAIT                   0"
  4784.                 ""
  4785.                 "       Interrupts"
  4786.                 "               COND_CAN_MELEE_ATTACK1"
  4787.                 "               COND_SEE_ENEMY"
  4788.                 "               COND_LIGHT_DAMAGE"
  4789.                 "               COND_HEAVY_DAMAGE"
  4790.         )
  4791.  
  4792.         //==================================================
  4793.         // SCHED_fireantlion_ZAP_FLIP
  4794.         //==================================================
  4795.         DEFINE_SCHEDULE
  4796.         (
  4797.                 SCHED_fireantlion_ZAP_FLIP,
  4798.  
  4799.                 "       Tasks"
  4800.                 "               TASK_STOP_MOVING        0"
  4801.                 "               TASK_RESET_ACTIVITY             0"
  4802.                 "               TASK_PLAY_SEQUENCE              ACTIVITY:ACT_fireantlion_ZAP_FLIP"
  4803.  
  4804.                 "       Interrupts"
  4805.                 "               COND_TASK_FAILED"
  4806.         )
  4807.        
  4808.         //==================================================
  4809.         // SCHED_fireantlion_FLIP
  4810.         //==================================================
  4811.         DEFINE_SCHEDULE
  4812.         (
  4813.         SCHED_fireantlion_FLIP,
  4814.  
  4815.         "       Tasks"
  4816.         "               TASK_STOP_MOVING        0"
  4817.         "               TASK_RESET_ACTIVITY             0"
  4818.         "               TASK_PLAY_SEQUENCE              ACTIVITY:ACT_fireantlion_FLIP"
  4819.  
  4820.         "       Interrupts"
  4821.         "               COND_TASK_FAILED"
  4822.         )
  4823.  
  4824.         //=========================================================
  4825.         // Headcrab has landed atop another NPC. Get down!
  4826.         //=========================================================
  4827.         DEFINE_SCHEDULE
  4828.         (
  4829.                 SCHED_fireantlion_DISMOUNT_NPC,
  4830.  
  4831.                 "       Tasks"
  4832.                 "               TASK_STOP_MOVING                        0"
  4833.                 "               TASK_fireantlion_DISMOUNT_NPC   0"
  4834.  
  4835.                 "       Interrupts"
  4836.         )
  4837.  
  4838.         DEFINE_SCHEDULE
  4839.         (
  4840.                 SCHED_fireantlion_RUN_TO_FIGHT_GOAL,
  4841.  
  4842.                 "       Tasks"
  4843.                 "               TASK_SET_TOLERANCE_DISTANCE             128"
  4844.                 "               TASK_GET_PATH_TO_SAVEPOSITION   0"
  4845.                 "               TASK_RUN_PATH                                   0"
  4846.                 "               TASK_WAIT_FOR_MOVEMENT                  0"
  4847.                 "               TASK_fireantlion_REACH_FIGHT_GOAL       0"
  4848.  
  4849.                 "       Interrupts"
  4850.                 "               COND_NEW_ENEMY"
  4851.                 "               COND_HEAVY_DAMAGE"
  4852.                 "               COND_LIGHT_DAMAGE"
  4853.                 "               COND_HEAVY_DAMAGE"
  4854.                 "               COND_fireantlion_CAN_JUMP"
  4855.         )
  4856.  
  4857.         DEFINE_SCHEDULE
  4858.         (
  4859.                 SCHED_fireantlion_RUN_TO_FOLLOW_GOAL,
  4860.  
  4861.                 "       Tasks"
  4862.                 "               TASK_SET_TOLERANCE_DISTANCE             128"
  4863.                 "               TASK_GET_PATH_TO_SAVEPOSITION   0"
  4864.                 "               TASK_RUN_PATH                                   0"
  4865.                 "               TASK_WAIT_FOR_MOVEMENT                  0"
  4866.  
  4867.                 "       Interrupts"
  4868.                 "               COND_NEW_ENEMY"
  4869.                 "               COND_HEAVY_DAMAGE"
  4870.                 "               COND_fireantlion_CAN_JUMP"
  4871.                 "               COND_fireantlion_FOLLOW_TARGET_TOO_FAR"
  4872.         )
  4873.  
  4874.         DEFINE_SCHEDULE
  4875.         (
  4876.                 SCHED_fireantlion_BUGBAIT_IDLE_STAND,
  4877.  
  4878.                 "       Tasks"
  4879.                 "               TASK_STOP_MOVING                0"
  4880.                 "               TASK_FACE_PLAYER                0"
  4881.                 "               TASK_SET_ACTIVITY               ACTIVITY:ACT_IDLE"
  4882.                 "               TASK_WAIT                               2"
  4883.  
  4884.                 "       Interrupts"
  4885.                 "               COND_NEW_ENEMY"
  4886.                 "               COND_HEAVY_DAMAGE"
  4887.                 "               COND_LIGHT_DAMAGE"
  4888.                 "               COND_HEAVY_DAMAGE"
  4889.                 "               COND_HEAR_DANGER"
  4890.                 "               COND_HEAR_COMBAT"
  4891.                 "               COND_fireantlion_CAN_JUMP"
  4892.                 "               COND_fireantlion_FOLLOW_TARGET_TOO_FAR"
  4893.                 "               COND_GIVE_WAY"
  4894.         )
  4895.  
  4896.         DEFINE_SCHEDULE
  4897.         (
  4898.                 SCHED_fireantlion_BURROW_AWAY,
  4899.  
  4900.                 "       Tasks"
  4901.                 "               TASK_STOP_MOVING                0"
  4902.                 "               TASK_fireantlion_BURROW         0"
  4903.                 "               TASK_PLAY_SEQUENCE              ACTIVITY:ACT_fireantlion_BURROW_IN"
  4904.                 "               TASK_fireantlion_VANISH         1"
  4905.  
  4906.                 "       Interrupts"
  4907.         )
  4908.  
  4909.         //==================================================
  4910.         // Run from the sound of a physics crash
  4911.         //==================================================
  4912.         DEFINE_SCHEDULE
  4913.         (
  4914.                 SCHED_fireantlion_FLEE_PHYSICS_DANGER,
  4915.                
  4916.                 "       Tasks"
  4917.                 "               TASK_SET_FAIL_SCHEDULE                                          SCHEDULE:SCHED_CHASE_ENEMY"
  4918.                 "               TASK_fireantlion_GET_PHYSICS_DANGER_ESCAPE_PATH 1024"
  4919.                 "               TASK_RUN_PATH                                                           0"
  4920.                 "               TASK_WAIT_FOR_MOVEMENT                                          0"
  4921.                 "               TASK_STOP_MOVING                                                        0"
  4922.                 ""
  4923.                 "       Interrupts"
  4924.                 "               COND_TASK_FAILED"
  4925.         )
  4926.  
  4927.         // Pounce forward at our enemy
  4928.         DEFINE_SCHEDULE
  4929.         (
  4930.                 SCHED_fireantlion_POUNCE,
  4931.  
  4932.                 "       Tasks"
  4933.                 "               TASK_STOP_MOVING                0"
  4934.                 "               TASK_FACE_ENEMY                 0"
  4935.                 "               TASK_ANNOUNCE_ATTACK    1"
  4936.                 "               TASK_RESET_ACTIVITY             0"
  4937.                 "               TASK_PLAY_SEQUENCE              ACTIVITY:ACT_fireantlion_POUNCE"
  4938.  
  4939.                 "       Interrupts"
  4940.                 "               COND_TASK_FAILED"
  4941.         )
  4942.         // Pounce forward at our enemy
  4943.         DEFINE_SCHEDULE
  4944.         (
  4945.                 SCHED_fireantlion_POUNCE_MOVING,
  4946.  
  4947.                 "       Tasks"
  4948.                 "               TASK_STOP_MOVING                0"
  4949.                 "               TASK_FACE_ENEMY                 0"
  4950.                 "               TASK_ANNOUNCE_ATTACK    1"
  4951.                 "               TASK_RESET_ACTIVITY             0"
  4952.                 "               TASK_PLAY_SEQUENCE              ACTIVITY:ACT_fireantlion_POUNCE_MOVING"
  4953.  
  4954.                 "       Interrupts"
  4955.                 "               COND_TASK_FAILED"
  4956.         )
  4957.  
  4958.         //=========================================================
  4959.         // The irreversible process of drowning
  4960.         //=========================================================
  4961.         DEFINE_SCHEDULE
  4962.         (
  4963.                 SCHED_fireantlion_DROWN,
  4964.  
  4965.                 "       Tasks"
  4966.                 "               TASK_SET_ACTIVITY                       ACTIVITY:ACT_fireantlion_DROWN"
  4967.                 "               TASK_fireantlion_DROWN                  0"
  4968.                 ""
  4969.                 "       Interrupts"
  4970.         )
  4971.  
  4972.         DEFINE_SCHEDULE
  4973.         (
  4974.                 SCHED_fireantlion_WORKER_RANGE_ATTACK1,
  4975.  
  4976.                 "       Tasks"
  4977.                 "               TASK_STOP_MOVING                0"
  4978.                 "               TASK_FACE_ENEMY                 0"
  4979.                 "               TASK_ANNOUNCE_ATTACK    1"      // 1 = primary attack
  4980.                 "               TASK_RANGE_ATTACK1              0"
  4981.                 ""
  4982.                 "       Interrupts"
  4983.                 "               COND_TASK_FAILED"
  4984.                 "               COND_NEW_ENEMY"
  4985.                 "               COND_ENEMY_DEAD"
  4986.         )
  4987.  
  4988.         DEFINE_SCHEDULE
  4989.         (
  4990.                 SCHED_fireantlion_WORKER_FLANK_RANDOM,
  4991.  
  4992.                 "       Tasks"
  4993.                 "               TASK_SET_FAIL_SCHEDULE                                  SCHEDULE:SCHED_fireantlion_WORKER_RUN_RANDOM"
  4994.                 "               TASK_SET_TOLERANCE_DISTANCE                             48"
  4995.                 "               TASK_SET_ROUTE_SEARCH_TIME                              1"      // Spend 1 second trying to build a path if stuck
  4996.                 "               TASK_GET_FLANK_ARC_PATH_TO_ENEMY_LOS    30"
  4997.                 "               TASK_RUN_PATH                                                   0"
  4998.                 "               TASK_WAIT_FOR_MOVEMENT                                  0"
  4999.                 ""
  5000.                 "       Interrupts"
  5001.                 "               COND_TASK_FAILED"
  5002.                 "               COND_HEAVY_DAMAGE"
  5003.                 "               COND_fireantlion_SQUADMATE_KILLED"
  5004.                 "               COND_CAN_RANGE_ATTACK1"
  5005.                 "               COND_CAN_MELEE_ATTACK1"
  5006.         )
  5007.  
  5008.         DEFINE_SCHEDULE
  5009.         (
  5010.                 SCHED_fireantlion_WORKER_RUN_RANDOM,
  5011.  
  5012.                 "       Tasks"
  5013.                 "               TASK_SET_FAIL_SCHEDULE                  SCHEDULE:SCHED_fireantlion_TAKE_COVER_FROM_ENEMY"
  5014.                 "               TASK_SET_TOLERANCE_DISTANCE             48"
  5015.                 "               TASK_SET_ROUTE_SEARCH_TIME              1"      // Spend 1 second trying to build a path if stuck
  5016.                 "               TASK_GET_PATH_TO_RANDOM_NODE    128"
  5017.                 "               TASK_RUN_PATH                                   0"
  5018.                 "               TASK_WAIT_FOR_MOVEMENT                  0"
  5019.                 ""
  5020.                 "       Interrupts"
  5021.                 "               COND_TASK_FAILED"
  5022.                 "               COND_CAN_RANGE_ATTACK1"
  5023.         )
  5024.  
  5025.         DEFINE_SCHEDULE
  5026.         (
  5027.                 SCHED_fireantlion_TAKE_COVER_FROM_ENEMY,
  5028.  
  5029.                 "       Tasks"
  5030.                 "               TASK_SET_FAIL_SCHEDULE                  SCHEDULE:SCHED_FAIL_TAKE_COVER"
  5031.                 "               TASK_FIND_COVER_FROM_ENEMY              0"
  5032.                 "               TASK_RUN_PATH                                   0"
  5033.                 "               TASK_WAIT_FOR_MOVEMENT                  0"
  5034.                 "               TASK_STOP_MOVING                                0"
  5035.                 ""
  5036.                 "       Interrupts"
  5037.                 "               COND_TASK_FAILED"
  5038.                 "               COND_NEW_ENEMY"
  5039.         )
  5040.  
  5041.         DEFINE_SCHEDULE
  5042.         (
  5043.                 SCHED_fireantlion_TAKE_COVER_FROM_SAVEPOSITION,
  5044.  
  5045.                 "       Tasks"
  5046.                 "               TASK_SET_FAIL_SCHEDULE                                          SCHEDULE:SCHED_FAIL_TAKE_COVER"
  5047.                 "               TASK_fireantlion_FIND_COVER_FROM_SAVEPOSITION   0"
  5048.                 "               TASK_RUN_PATH                                                           0"
  5049.                 "               TASK_WAIT_FOR_MOVEMENT                                          0"
  5050.                 "               TASK_STOP_MOVING                                                        0"
  5051.                 ""
  5052.                 "       Interrupts"
  5053.                 "               COND_TASK_FAILED"
  5054.                 "               COND_NEW_ENEMY"
  5055.         )
  5056.  
  5057. AI_END_CUSTOM_NPC()
  5058.  
  5059.  
  5060. //-----------------------------------------------------------------------------
  5061. // Purpose: Whether or not the target is a worker class of fireantlion
  5062. // Output : Returns true on success, false on failure.
  5063. //-----------------------------------------------------------------------------
  5064. bool IsfireantlionWorker( CBaseEntity *pEntity )
  5065. {
  5066.         // Must at least be valid and an fireantlion
  5067.         return ( pEntity != NULL &&
  5068.                          pEntity->Classify() == CLASS_fireantlion &&
  5069.                          pEntity->HasSpawnFlags( SF_fireantlion_WORKER ) &&
  5070.                          dynamic_cast<CNPC_fireantlion *>(pEntity) != NULL );   // Save this as the last step
  5071. }
  5072.  
  5073. //-----------------------------------------------------------------------------
  5074. // Purpose: Whether or not the entity is a common fireantlion
  5075. // Output : Returns true on success, false on failure.
  5076. //-----------------------------------------------------------------------------
  5077. bool Isfireantlion( CBaseEntity *pEntity )
  5078. {
  5079.         // Must at least be valid and an fireantlion
  5080.         return ( pEntity != NULL &&
  5081.                          pEntity->Classify() == CLASS_fireantlion &&
  5082.                          dynamic_cast<CNPC_fireantlion *>(pEntity) != NULL );   // Save this as the last step
  5083. }
  5084.  
  5085. #ifdef HL2_EPISODIC
  5086. //-----------------------------------------------------------------------------
  5087. // Purpose: Used by other entities to judge the fireantlion worker's radius of damage
  5088. //-----------------------------------------------------------------------------
  5089. float fireantlionWorkerBurstRadius( void )
  5090. {
  5091.         return sk_fireantlion_worker_burst_radius.GetFloat();
  5092. }
  5093. #endif // HL2_EPISODIC
  5094.  
  5095.  
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top