From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/server/ai_behavior_fear.cpp | 1104 +++++++++++++++---------------- 1 file changed, 552 insertions(+), 552 deletions(-) (limited to 'mp/src/game/server/ai_behavior_fear.cpp') 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() -- cgit v1.2.3