aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/server/ai_behavior_fear.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/ai_behavior_fear.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/ai_behavior_fear.cpp')
-rw-r--r--mp/src/game/server/ai_behavior_fear.cpp1104
1 files changed, 552 insertions, 552 deletions
diff --git a/mp/src/game/server/ai_behavior_fear.cpp b/mp/src/game/server/ai_behavior_fear.cpp
index 57f1bd7d..ea908ba6 100644
--- a/mp/src/game/server/ai_behavior_fear.cpp
+++ b/mp/src/game/server/ai_behavior_fear.cpp
@@ -1,552 +1,552 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "cbase.h"
-#include "ai_motor.h"
-#include "ai_behavior_fear.h"
-#include "ai_hint.h"
-#include "ai_navigator.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-BEGIN_DATADESC( CAI_FearBehavior )
- DEFINE_FIELD( m_flTimeToSafety, FIELD_TIME ),
- DEFINE_FIELD( m_flTimePlayerLastVisible, FIELD_TIME ),
- DEFINE_FIELD( m_hSafePlaceHint, FIELD_EHANDLE ),
- DEFINE_FIELD( m_hMovingToHint, FIELD_EHANDLE ),
- DEFINE_EMBEDDED( m_SafePlaceMoveMonitor ),
- DEFINE_FIELD( m_flDeferUntil, FIELD_TIME ),
-END_DATADESC();
-
-#define BEHAVIOR_FEAR_SAFETY_TIME 5
-#define FEAR_SAFE_PLACE_TOLERANCE 36.0f
-#define FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR Square(300.0f) // (25 feet)
-#define FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR Square( 60.0f ) // (5 Feet)
-
-ConVar ai_enable_fear_behavior( "ai_enable_fear_behavior", "1" );
-
-ConVar ai_fear_player_dist("ai_fear_player_dist", "720" );
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-CAI_FearBehavior::CAI_FearBehavior()
-{
- ReleaseAllHints();
- m_SafePlaceMoveMonitor.ClearMark();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::Precache( void )
-{
-
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pTask -
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::StartTask( const Task_t *pTask )
-{
- switch( pTask->iTask )
- {
- case TASK_FEAR_IN_SAFE_PLACE:
- // We've arrived! Lock the hint and set the marker. we're safe for now.
- m_hSafePlaceHint = m_hMovingToHint;
- m_hSafePlaceHint->Lock( GetOuter() );
- m_SafePlaceMoveMonitor.SetMark( GetOuter(), FEAR_SAFE_PLACE_TOLERANCE );
- TaskComplete();
- break;
-
- case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
- // Using TaskInterrupt() optimizations. See RunTask().
- break;
-
- case TASK_FEAR_WAIT_FOR_SAFETY:
- m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
- break;
-
- default:
- BaseClass::StartTask( pTask );
- break;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : *pTask -
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::RunTask( const Task_t *pTask )
-{
- switch( pTask->iTask )
- {
- case TASK_FEAR_WAIT_FOR_SAFETY:
- if( HasCondition(COND_SEE_ENEMY) )
- {
- m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
- }
- else
- {
- if( gpGlobals->curtime > m_flTimeToSafety )
- {
- TaskComplete();
- }
- }
- break;
-
- case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
- {
- switch( GetOuter()->GetTaskInterrupt() )
- {
- case 0:// Find the hint node
- {
- ReleaseAllHints();
- CAI_Hint *pHint = FindFearWithdrawalDest();
-
- if( pHint == NULL )
- {
- TaskFail("Fear: Couldn't find hint node\n");
- m_flDeferUntil = gpGlobals->curtime + 3.0f;// Don't bang the hell out of this behavior. If we don't find a node, take a short break and run regular AI.
- }
- else
- {
- m_hMovingToHint.Set( pHint );
- GetOuter()->TaskInterrupt();
- }
- }
- break;
-
- case 1:// Do the pathfinding.
- {
- Assert( m_hMovingToHint != NULL );
-
- AI_NavGoal_t goal(m_hMovingToHint->GetAbsOrigin());
- goal.pTarget = NULL;
- if( GetNavigator()->SetGoal( goal ) == false )
- {
- m_hMovingToHint.Set( NULL );
- // Do whatever we'd want to do if we can't find a path
- /*
- Msg("Can't path to the Fear Hint!\n");
-
- AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hRallyPoint->GetAbsOrigin(), AIN_DEF_ACTIVITY, 256 );
- if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) )
- {
- //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it!
- ClearCondition( COND_TASK_FAILED );
- GetNavigator()->SetArrivalDirection( m_hRallyPoint->GetAbsAngles() );
- TaskComplete();
- return;
- }
- */
- }
- else
- {
- GetNavigator()->SetArrivalDirection( m_hMovingToHint->GetAbsAngles() );
- }
- }
- break;
- }
- }
- break;
-
- default:
- BaseClass::RunTask( pTask );
- break;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : TRUE if I have an enemy and that enemy would attack me if it could
-// Notes : Returns FALSE if the enemy is neutral or likes me.
-//-----------------------------------------------------------------------------
-bool CAI_FearBehavior::EnemyDislikesMe()
-{
- CBaseEntity *pEnemy = GetEnemy();
-
- if( pEnemy == NULL )
- return false;
-
- if( pEnemy->MyNPCPointer() == NULL )
- return false;
-
- Disposition_t disposition = pEnemy->MyNPCPointer()->IRelationType(GetOuter());
-
- Assert(disposition != D_ER);
-
- if( disposition >= D_LI )
- return false;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// This place is definitely no longer safe. Stop picking it for a while.
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::MarkAsUnsafe()
-{
- Assert( m_hSafePlaceHint );
-
- // Disable the node to stop anyone from picking it for a while.
- m_hSafePlaceHint->DisableForSeconds( 5.0f );
-}
-
-//-----------------------------------------------------------------------------
-// Am I in safe place from my enemy?
-//-----------------------------------------------------------------------------
-bool CAI_FearBehavior::IsInASafePlace()
-{
- // No safe place in mind.
- if( !m_SafePlaceMoveMonitor.IsMarkSet() )
- return false;
-
- // I have a safe place, but I'm not there.
- if( m_SafePlaceMoveMonitor.TargetMoved(GetOuter()) )
- return false;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::SpoilSafePlace()
-{
- m_SafePlaceMoveMonitor.ClearMark();
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::ReleaseAllHints()
-{
- if( m_hSafePlaceHint )
- {
- // If I have a safe place, unlock it for others.
- m_hSafePlaceHint->Unlock();
-
- // Don't make it available right away. I probably left for a good reason.
- // We also don't want to oscillate
- m_hSafePlaceHint->DisableForSeconds( 4.0f );
- m_hSafePlaceHint = NULL;
- }
-
- if( m_hMovingToHint )
- {
- m_hMovingToHint->Unlock();
- m_hMovingToHint = NULL;
- }
-
- m_SafePlaceMoveMonitor.ClearMark();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : Returns true on success, false on failure.
-// Notes : This behavior runs when I have an enemy that I fear, but who
-// does NOT hate or fear me (meaning they aren't going to fight me)
-//-----------------------------------------------------------------------------
-bool CAI_FearBehavior::CanSelectSchedule()
-{
- if( !GetOuter()->IsInterruptable() )
- return false;
-
- if( m_flDeferUntil > gpGlobals->curtime )
- return false;
-
- CBaseEntity *pEnemy = GetEnemy();
-
- if( pEnemy == NULL )
- return false;
-
- //if( !HasCondition(COND_SEE_PLAYER) )
- // return false;
-
- if( !ai_enable_fear_behavior.GetBool() )
- return false;
-
- if( GetOuter()->IRelationType(pEnemy) != D_FR )
- return false;
-
- if( !pEnemy->ClassMatches("npc_hunter") )
- return false;
-
- return true;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::GatherConditions()
-{
- BaseClass::GatherConditions();
-
- ClearCondition( COND_FEAR_ENEMY_CLOSE );
- ClearCondition( COND_FEAR_ENEMY_TOO_CLOSE );
- if( GetEnemy() )
- {
- float flEnemyDistSqr = GetAbsOrigin().DistToSqr(GetEnemy()->GetAbsOrigin());
-
- if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR )
- {
- SetCondition( COND_FEAR_ENEMY_TOO_CLOSE );
- if( IsInASafePlace() )
- {
- SpoilSafePlace();
- }
- }
- else if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR && GetEnemy()->GetEnemy() == GetOuter() )
- {
- // Only become scared of an enemy at this range if they're my enemy, too
- SetCondition( COND_FEAR_ENEMY_CLOSE );
- if( IsInASafePlace() )
- {
- SpoilSafePlace();
- }
- }
- }
-
- ClearCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
-
- // Check for separation from the player
- // -The player is farther away than 60 feet
- // -I haven't seen the player in 2 seconds
- //
- // Here's the distance check:
- CBasePlayer *pPlayer = AI_GetSinglePlayer();
- if( pPlayer != NULL && GetAbsOrigin().DistToSqr(pPlayer->GetAbsOrigin()) >= Square( ai_fear_player_dist.GetFloat() * 1.5f ) )
- {
- SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
- }
-
- // Here's the visibility check. We can't skip this because it's time-sensitive
- if( GetOuter()->FVisible(pPlayer) )
- {
- m_flTimePlayerLastVisible = gpGlobals->curtime;
- }
- else
- {
- if( gpGlobals->curtime - m_flTimePlayerLastVisible >= 2.0f )
- {
- SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
- }
- }
-
- if( HasCondition(COND_FEAR_SEPARATED_FROM_PLAYER) )
- {
- //Msg("I am separated from player\n");
-
- if( IsInASafePlace() )
- {
- SpoilSafePlace();
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::BeginScheduleSelection()
-{
- if( m_hSafePlaceHint )
- {
- // We think we're safe. Is it true?
- if( !IsInASafePlace() )
- {
- // no! So mark it so.
- ReleaseAllHints();
- }
- }
-
- m_flTimePlayerLastVisible = gpGlobals->curtime;
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::EndScheduleSelection()
-{
- // We don't have to release our hints or markers or anything here.
- // Just because we ran other AI for a while doesn't mean we aren't still in a safe place.
- //ReleaseAllHints();
-}
-
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : int
-// Notes : If fear behavior is running at all, we know we're afraid of our enemy
-//-----------------------------------------------------------------------------
-int CAI_FearBehavior::SelectSchedule()
-{
- bool bInSafePlace = IsInASafePlace();
-
- if( !HasCondition(COND_HEAR_DANGER) )
- {
- if( !bInSafePlace )
- {
- // Always move to a safe place if we're not running from a danger sound
- return SCHED_FEAR_MOVE_TO_SAFE_PLACE;
- }
- else
- {
- // We ARE in a safe place
- if( HasCondition(COND_CAN_RANGE_ATTACK1) )
- return SCHED_RANGE_ATTACK1;
-
- return SCHED_FEAR_STAY_IN_SAFE_PLACE;
- }
- }
-
- return BaseClass::SelectSchedule();
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CAI_FearBehavior::BuildScheduleTestBits()
-{
- BaseClass::BuildScheduleTestBits();
-
- if( GetOuter()->GetState() != NPC_STATE_SCRIPT )
- {
- // Stop doing ANYTHING if we get scared.
- //GetOuter()->SetCustomInterruptCondition( COND_HEAR_DANGER );
-
- if( !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY, false) && !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE, false) )
- {
- GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal(COND_FEAR_SEPARATED_FROM_PLAYER) );
- }
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-int CAI_FearBehavior::TranslateSchedule( int scheduleType )
-{
- switch( scheduleType )
- {
- case SCHED_FEAR_MOVE_TO_SAFE_PLACE:
- if( HasCondition(COND_FEAR_ENEMY_TOO_CLOSE) )
- {
- // If I'm moving to a safe place AND have an enemy too close to me,
- // make the move to safety while ignoring the condition.
- // this stops an oscillation
- // IS THIS CODE EVER EVEN BEING CALLED? (sjb)
- return SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY;
- }
- break;
- }
-
- return BaseClass::TranslateSchedule( scheduleType );
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-CAI_Hint *CAI_FearBehavior::FindFearWithdrawalDest()
-{
- CAI_Hint *pHint;
- CHintCriteria hintCriteria;
- CAI_BaseNPC *pOuter = GetOuter();
-
- Assert(pOuter != NULL);
-
- hintCriteria.AddHintType( HINT_PLAYER_ALLY_FEAR_DEST );
- hintCriteria.SetFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER | bits_HINT_NOT_CLOSE_TO_ENEMY /*| bits_HINT_NODE_IN_VIEWCONE | bits_HINT_NPC_IN_NODE_FOV*/ );
- hintCriteria.AddIncludePosition( AI_GetSinglePlayer()->GetAbsOrigin(), ( ai_fear_player_dist.GetFloat() ) );
-
- pHint = CAI_HintManager::FindHint( pOuter, hintCriteria );
-
- if( pHint )
- {
- // Reserve this node while I try to get to it. When I get there I will lock it.
- // Otherwise, if I fail to get there, the node will come available again soon.
- pHint->DisableForSeconds( 4.0f );
- }
-#if 0
- else
- {
- Msg("DID NOT FIND HINT\n");
- NDebugOverlay::Cross3D( GetOuter()->WorldSpaceCenter(), 32, 255, 255, 0, false, 10.0f );
- }
-#endif
-
- return pHint;
-}
-
-AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_FearBehavior )
-
- DECLARE_TASK( TASK_FEAR_GET_PATH_TO_SAFETY_HINT )
- DECLARE_TASK( TASK_FEAR_WAIT_FOR_SAFETY )
- DECLARE_TASK( TASK_FEAR_IN_SAFE_PLACE )
-
- DECLARE_CONDITION( COND_FEAR_ENEMY_CLOSE )
- DECLARE_CONDITION( COND_FEAR_ENEMY_TOO_CLOSE )
- DECLARE_CONDITION( COND_FEAR_SEPARATED_FROM_PLAYER )
-
- //===============================================
- //===============================================
- DEFINE_SCHEDULE
- (
- SCHED_FEAR_MOVE_TO_SAFE_PLACE,
-
- " Tasks"
- " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
- " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
- " TASK_RUN_PATH 0"
- " TASK_WAIT_FOR_MOVEMENT 0"
- " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
- " TASK_FEAR_IN_SAFE_PLACE 0"
- " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
- ""
- " Interrupts"
- ""
- " COND_HEAR_DANGER"
- " COND_NEW_ENEMY"
- " COND_FEAR_ENEMY_TOO_CLOSE"
- );
-
- DEFINE_SCHEDULE
- (
- SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY,
-
- " Tasks"
- " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
- " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
- " TASK_RUN_PATH 0"
- " TASK_WAIT_FOR_MOVEMENT 0"
- " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
- " TASK_FEAR_IN_SAFE_PLACE 0"
- " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
- ""
- " Interrupts"
- ""
- " COND_HEAR_DANGER"
- " COND_NEW_ENEMY"
- );
-
- //===============================================
- //===============================================
- DEFINE_SCHEDULE
- (
- SCHED_FEAR_STAY_IN_SAFE_PLACE,
-
- " Tasks"
- " TASK_FEAR_WAIT_FOR_SAFETY 0"
- ""
- " Interrupts"
- ""
- " COND_NEW_ENEMY"
- " COND_HEAR_DANGER"
- " COND_FEAR_ENEMY_CLOSE"
- " COND_FEAR_ENEMY_TOO_CLOSE"
- " COND_CAN_RANGE_ATTACK1"
- " COND_FEAR_SEPARATED_FROM_PLAYER"
- );
-
-
-AI_END_CUSTOM_SCHEDULE_PROVIDER()
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "ai_motor.h"
+#include "ai_behavior_fear.h"
+#include "ai_hint.h"
+#include "ai_navigator.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+BEGIN_DATADESC( CAI_FearBehavior )
+ DEFINE_FIELD( m_flTimeToSafety, FIELD_TIME ),
+ DEFINE_FIELD( m_flTimePlayerLastVisible, FIELD_TIME ),
+ DEFINE_FIELD( m_hSafePlaceHint, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hMovingToHint, FIELD_EHANDLE ),
+ DEFINE_EMBEDDED( m_SafePlaceMoveMonitor ),
+ DEFINE_FIELD( m_flDeferUntil, FIELD_TIME ),
+END_DATADESC();
+
+#define BEHAVIOR_FEAR_SAFETY_TIME 5
+#define FEAR_SAFE_PLACE_TOLERANCE 36.0f
+#define FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR Square(300.0f) // (25 feet)
+#define FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR Square( 60.0f ) // (5 Feet)
+
+ConVar ai_enable_fear_behavior( "ai_enable_fear_behavior", "1" );
+
+ConVar ai_fear_player_dist("ai_fear_player_dist", "720" );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CAI_FearBehavior::CAI_FearBehavior()
+{
+ ReleaseAllHints();
+ m_SafePlaceMoveMonitor.ClearMark();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::Precache( void )
+{
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTask -
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::StartTask( const Task_t *pTask )
+{
+ switch( pTask->iTask )
+ {
+ case TASK_FEAR_IN_SAFE_PLACE:
+ // We've arrived! Lock the hint and set the marker. we're safe for now.
+ m_hSafePlaceHint = m_hMovingToHint;
+ m_hSafePlaceHint->Lock( GetOuter() );
+ m_SafePlaceMoveMonitor.SetMark( GetOuter(), FEAR_SAFE_PLACE_TOLERANCE );
+ TaskComplete();
+ break;
+
+ case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
+ // Using TaskInterrupt() optimizations. See RunTask().
+ break;
+
+ case TASK_FEAR_WAIT_FOR_SAFETY:
+ m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
+ break;
+
+ default:
+ BaseClass::StartTask( pTask );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pTask -
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::RunTask( const Task_t *pTask )
+{
+ switch( pTask->iTask )
+ {
+ case TASK_FEAR_WAIT_FOR_SAFETY:
+ if( HasCondition(COND_SEE_ENEMY) )
+ {
+ m_flTimeToSafety = gpGlobals->curtime + BEHAVIOR_FEAR_SAFETY_TIME;
+ }
+ else
+ {
+ if( gpGlobals->curtime > m_flTimeToSafety )
+ {
+ TaskComplete();
+ }
+ }
+ break;
+
+ case TASK_FEAR_GET_PATH_TO_SAFETY_HINT:
+ {
+ switch( GetOuter()->GetTaskInterrupt() )
+ {
+ case 0:// Find the hint node
+ {
+ ReleaseAllHints();
+ CAI_Hint *pHint = FindFearWithdrawalDest();
+
+ if( pHint == NULL )
+ {
+ TaskFail("Fear: Couldn't find hint node\n");
+ m_flDeferUntil = gpGlobals->curtime + 3.0f;// Don't bang the hell out of this behavior. If we don't find a node, take a short break and run regular AI.
+ }
+ else
+ {
+ m_hMovingToHint.Set( pHint );
+ GetOuter()->TaskInterrupt();
+ }
+ }
+ break;
+
+ case 1:// Do the pathfinding.
+ {
+ Assert( m_hMovingToHint != NULL );
+
+ AI_NavGoal_t goal(m_hMovingToHint->GetAbsOrigin());
+ goal.pTarget = NULL;
+ if( GetNavigator()->SetGoal( goal ) == false )
+ {
+ m_hMovingToHint.Set( NULL );
+ // Do whatever we'd want to do if we can't find a path
+ /*
+ Msg("Can't path to the Fear Hint!\n");
+
+ AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hRallyPoint->GetAbsOrigin(), AIN_DEF_ACTIVITY, 256 );
+ if ( GetNavigator()->SetGoal( nearGoal, AIN_CLEAR_PREVIOUS_STATE ) )
+ {
+ //FIXME: HACK! The internal pathfinding is setting this without our consent, so override it!
+ ClearCondition( COND_TASK_FAILED );
+ GetNavigator()->SetArrivalDirection( m_hRallyPoint->GetAbsAngles() );
+ TaskComplete();
+ return;
+ }
+ */
+ }
+ else
+ {
+ GetNavigator()->SetArrivalDirection( m_hMovingToHint->GetAbsAngles() );
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ default:
+ BaseClass::RunTask( pTask );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : TRUE if I have an enemy and that enemy would attack me if it could
+// Notes : Returns FALSE if the enemy is neutral or likes me.
+//-----------------------------------------------------------------------------
+bool CAI_FearBehavior::EnemyDislikesMe()
+{
+ CBaseEntity *pEnemy = GetEnemy();
+
+ if( pEnemy == NULL )
+ return false;
+
+ if( pEnemy->MyNPCPointer() == NULL )
+ return false;
+
+ Disposition_t disposition = pEnemy->MyNPCPointer()->IRelationType(GetOuter());
+
+ Assert(disposition != D_ER);
+
+ if( disposition >= D_LI )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// This place is definitely no longer safe. Stop picking it for a while.
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::MarkAsUnsafe()
+{
+ Assert( m_hSafePlaceHint );
+
+ // Disable the node to stop anyone from picking it for a while.
+ m_hSafePlaceHint->DisableForSeconds( 5.0f );
+}
+
+//-----------------------------------------------------------------------------
+// Am I in safe place from my enemy?
+//-----------------------------------------------------------------------------
+bool CAI_FearBehavior::IsInASafePlace()
+{
+ // No safe place in mind.
+ if( !m_SafePlaceMoveMonitor.IsMarkSet() )
+ return false;
+
+ // I have a safe place, but I'm not there.
+ if( m_SafePlaceMoveMonitor.TargetMoved(GetOuter()) )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::SpoilSafePlace()
+{
+ m_SafePlaceMoveMonitor.ClearMark();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::ReleaseAllHints()
+{
+ if( m_hSafePlaceHint )
+ {
+ // If I have a safe place, unlock it for others.
+ m_hSafePlaceHint->Unlock();
+
+ // Don't make it available right away. I probably left for a good reason.
+ // We also don't want to oscillate
+ m_hSafePlaceHint->DisableForSeconds( 4.0f );
+ m_hSafePlaceHint = NULL;
+ }
+
+ if( m_hMovingToHint )
+ {
+ m_hMovingToHint->Unlock();
+ m_hMovingToHint = NULL;
+ }
+
+ m_SafePlaceMoveMonitor.ClearMark();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+// Notes : This behavior runs when I have an enemy that I fear, but who
+// does NOT hate or fear me (meaning they aren't going to fight me)
+//-----------------------------------------------------------------------------
+bool CAI_FearBehavior::CanSelectSchedule()
+{
+ if( !GetOuter()->IsInterruptable() )
+ return false;
+
+ if( m_flDeferUntil > gpGlobals->curtime )
+ return false;
+
+ CBaseEntity *pEnemy = GetEnemy();
+
+ if( pEnemy == NULL )
+ return false;
+
+ //if( !HasCondition(COND_SEE_PLAYER) )
+ // return false;
+
+ if( !ai_enable_fear_behavior.GetBool() )
+ return false;
+
+ if( GetOuter()->IRelationType(pEnemy) != D_FR )
+ return false;
+
+ if( !pEnemy->ClassMatches("npc_hunter") )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::GatherConditions()
+{
+ BaseClass::GatherConditions();
+
+ ClearCondition( COND_FEAR_ENEMY_CLOSE );
+ ClearCondition( COND_FEAR_ENEMY_TOO_CLOSE );
+ if( GetEnemy() )
+ {
+ float flEnemyDistSqr = GetAbsOrigin().DistToSqr(GetEnemy()->GetAbsOrigin());
+
+ if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_TOO_CLOSE_DIST_SQR )
+ {
+ SetCondition( COND_FEAR_ENEMY_TOO_CLOSE );
+ if( IsInASafePlace() )
+ {
+ SpoilSafePlace();
+ }
+ }
+ else if( flEnemyDistSqr < FEAR_ENEMY_TOLERANCE_CLOSE_DIST_SQR && GetEnemy()->GetEnemy() == GetOuter() )
+ {
+ // Only become scared of an enemy at this range if they're my enemy, too
+ SetCondition( COND_FEAR_ENEMY_CLOSE );
+ if( IsInASafePlace() )
+ {
+ SpoilSafePlace();
+ }
+ }
+ }
+
+ ClearCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
+
+ // Check for separation from the player
+ // -The player is farther away than 60 feet
+ // -I haven't seen the player in 2 seconds
+ //
+ // Here's the distance check:
+ CBasePlayer *pPlayer = AI_GetSinglePlayer();
+ if( pPlayer != NULL && GetAbsOrigin().DistToSqr(pPlayer->GetAbsOrigin()) >= Square( ai_fear_player_dist.GetFloat() * 1.5f ) )
+ {
+ SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
+ }
+
+ // Here's the visibility check. We can't skip this because it's time-sensitive
+ if( GetOuter()->FVisible(pPlayer) )
+ {
+ m_flTimePlayerLastVisible = gpGlobals->curtime;
+ }
+ else
+ {
+ if( gpGlobals->curtime - m_flTimePlayerLastVisible >= 2.0f )
+ {
+ SetCondition(COND_FEAR_SEPARATED_FROM_PLAYER);
+ }
+ }
+
+ if( HasCondition(COND_FEAR_SEPARATED_FROM_PLAYER) )
+ {
+ //Msg("I am separated from player\n");
+
+ if( IsInASafePlace() )
+ {
+ SpoilSafePlace();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::BeginScheduleSelection()
+{
+ if( m_hSafePlaceHint )
+ {
+ // We think we're safe. Is it true?
+ if( !IsInASafePlace() )
+ {
+ // no! So mark it so.
+ ReleaseAllHints();
+ }
+ }
+
+ m_flTimePlayerLastVisible = gpGlobals->curtime;
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::EndScheduleSelection()
+{
+ // We don't have to release our hints or markers or anything here.
+ // Just because we ran other AI for a while doesn't mean we aren't still in a safe place.
+ //ReleaseAllHints();
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+// Notes : If fear behavior is running at all, we know we're afraid of our enemy
+//-----------------------------------------------------------------------------
+int CAI_FearBehavior::SelectSchedule()
+{
+ bool bInSafePlace = IsInASafePlace();
+
+ if( !HasCondition(COND_HEAR_DANGER) )
+ {
+ if( !bInSafePlace )
+ {
+ // Always move to a safe place if we're not running from a danger sound
+ return SCHED_FEAR_MOVE_TO_SAFE_PLACE;
+ }
+ else
+ {
+ // We ARE in a safe place
+ if( HasCondition(COND_CAN_RANGE_ATTACK1) )
+ return SCHED_RANGE_ATTACK1;
+
+ return SCHED_FEAR_STAY_IN_SAFE_PLACE;
+ }
+ }
+
+ return BaseClass::SelectSchedule();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CAI_FearBehavior::BuildScheduleTestBits()
+{
+ BaseClass::BuildScheduleTestBits();
+
+ if( GetOuter()->GetState() != NPC_STATE_SCRIPT )
+ {
+ // Stop doing ANYTHING if we get scared.
+ //GetOuter()->SetCustomInterruptCondition( COND_HEAR_DANGER );
+
+ if( !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY, false) && !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE, false) )
+ {
+ GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal(COND_FEAR_SEPARATED_FROM_PLAYER) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+int CAI_FearBehavior::TranslateSchedule( int scheduleType )
+{
+ switch( scheduleType )
+ {
+ case SCHED_FEAR_MOVE_TO_SAFE_PLACE:
+ if( HasCondition(COND_FEAR_ENEMY_TOO_CLOSE) )
+ {
+ // If I'm moving to a safe place AND have an enemy too close to me,
+ // make the move to safety while ignoring the condition.
+ // this stops an oscillation
+ // IS THIS CODE EVER EVEN BEING CALLED? (sjb)
+ return SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY;
+ }
+ break;
+ }
+
+ return BaseClass::TranslateSchedule( scheduleType );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+CAI_Hint *CAI_FearBehavior::FindFearWithdrawalDest()
+{
+ CAI_Hint *pHint;
+ CHintCriteria hintCriteria;
+ CAI_BaseNPC *pOuter = GetOuter();
+
+ Assert(pOuter != NULL);
+
+ hintCriteria.AddHintType( HINT_PLAYER_ALLY_FEAR_DEST );
+ hintCriteria.SetFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER | bits_HINT_NOT_CLOSE_TO_ENEMY /*| bits_HINT_NODE_IN_VIEWCONE | bits_HINT_NPC_IN_NODE_FOV*/ );
+ hintCriteria.AddIncludePosition( AI_GetSinglePlayer()->GetAbsOrigin(), ( ai_fear_player_dist.GetFloat() ) );
+
+ pHint = CAI_HintManager::FindHint( pOuter, hintCriteria );
+
+ if( pHint )
+ {
+ // Reserve this node while I try to get to it. When I get there I will lock it.
+ // Otherwise, if I fail to get there, the node will come available again soon.
+ pHint->DisableForSeconds( 4.0f );
+ }
+#if 0
+ else
+ {
+ Msg("DID NOT FIND HINT\n");
+ NDebugOverlay::Cross3D( GetOuter()->WorldSpaceCenter(), 32, 255, 255, 0, false, 10.0f );
+ }
+#endif
+
+ return pHint;
+}
+
+AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_FearBehavior )
+
+ DECLARE_TASK( TASK_FEAR_GET_PATH_TO_SAFETY_HINT )
+ DECLARE_TASK( TASK_FEAR_WAIT_FOR_SAFETY )
+ DECLARE_TASK( TASK_FEAR_IN_SAFE_PLACE )
+
+ DECLARE_CONDITION( COND_FEAR_ENEMY_CLOSE )
+ DECLARE_CONDITION( COND_FEAR_ENEMY_TOO_CLOSE )
+ DECLARE_CONDITION( COND_FEAR_SEPARATED_FROM_PLAYER )
+
+ //===============================================
+ //===============================================
+ DEFINE_SCHEDULE
+ (
+ SCHED_FEAR_MOVE_TO_SAFE_PLACE,
+
+ " Tasks"
+ " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
+ " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
+ " TASK_FEAR_IN_SAFE_PLACE 0"
+ " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
+ ""
+ " Interrupts"
+ ""
+ " COND_HEAR_DANGER"
+ " COND_NEW_ENEMY"
+ " COND_FEAR_ENEMY_TOO_CLOSE"
+ );
+
+ DEFINE_SCHEDULE
+ (
+ SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY,
+
+ " Tasks"
+ " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_RUN_FROM_ENEMY"
+ " TASK_FEAR_GET_PATH_TO_SAFETY_HINT 0"
+ " TASK_RUN_PATH 0"
+ " TASK_WAIT_FOR_MOVEMENT 0"
+ " TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
+ " TASK_FEAR_IN_SAFE_PLACE 0"
+ " TASK_SET_SCHEDULE SCHEDULE:SCHED_FEAR_STAY_IN_SAFE_PLACE"
+ ""
+ " Interrupts"
+ ""
+ " COND_HEAR_DANGER"
+ " COND_NEW_ENEMY"
+ );
+
+ //===============================================
+ //===============================================
+ DEFINE_SCHEDULE
+ (
+ SCHED_FEAR_STAY_IN_SAFE_PLACE,
+
+ " Tasks"
+ " TASK_FEAR_WAIT_FOR_SAFETY 0"
+ ""
+ " Interrupts"
+ ""
+ " COND_NEW_ENEMY"
+ " COND_HEAR_DANGER"
+ " COND_FEAR_ENEMY_CLOSE"
+ " COND_FEAR_ENEMY_TOO_CLOSE"
+ " COND_CAN_RANGE_ATTACK1"
+ " COND_FEAR_SEPARATED_FROM_PLAYER"
+ );
+
+
+AI_END_CUSTOM_SCHEDULE_PROVIDER()