diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/ai_behavior_fear.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-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.cpp | 1104 |
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() |