diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/hl2/ai_behavior_operator.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/hl2/ai_behavior_operator.cpp')
| -rw-r--r-- | game/server/hl2/ai_behavior_operator.cpp | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/game/server/hl2/ai_behavior_operator.cpp b/game/server/hl2/ai_behavior_operator.cpp new file mode 100644 index 0000000..f350529 --- /dev/null +++ b/game/server/hl2/ai_behavior_operator.cpp @@ -0,0 +1,478 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "entitylist.h" +#include "ai_navigator.h" +#include "ai_behavior_operator.h" + + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//============================================================================= +//============================================================================= +// >OPERATOR BEHAVIOR +//============================================================================= +//============================================================================= +BEGIN_DATADESC( CAI_OperatorBehavior ) + DEFINE_FIELD( m_hGoalEntity, FIELD_EHANDLE ), + DEFINE_FIELD( m_hPositionEnt, FIELD_EHANDLE ), + DEFINE_FIELD( m_hContextTarget, FIELD_EHANDLE ), + DEFINE_EMBEDDED( m_WatchSeeEntity ), +END_DATADESC(); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CAI_OperatorBehavior::CAI_OperatorBehavior() +{ + m_hPositionEnt.Set(NULL); + m_hGoalEntity.Set(NULL); + m_hContextTarget.Set(NULL); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +#define POSITION_ENT_ALWAYS_SEE_DIST Square(120) +bool CAI_OperatorBehavior::CanSeePositionEntity() +{ + CAI_BaseNPC *pOuter = GetOuter(); + + Assert( m_hPositionEnt.Get() != NULL ); + + // early out here. + if( !pOuter->QuerySeeEntity(m_hPositionEnt) ) + { + m_WatchSeeEntity.Stop(); + return false; + } + + bool bSpotted = (pOuter->EyePosition().DistToSqr(m_hPositionEnt->GetAbsOrigin()) <= POSITION_ENT_ALWAYS_SEE_DIST); + if ( !bSpotted ) + { + bSpotted = ( pOuter->FInViewCone(m_hPositionEnt) && pOuter->FVisible(m_hPositionEnt) ); + } + + if (bSpotted ) + { + // If we haven't seen it up until now, start a timer. If we have seen it, wait for the + // timer to finish. This prevents edge cases where turning on the flashlight makes + // NPC spot the position entity a frame before she spots an enemy. + if ( !m_WatchSeeEntity.IsRunning() ) + { + m_WatchSeeEntity.Start( 0.3,0.31 ); + return false; + } + + if ( !m_WatchSeeEntity.Expired() ) + return false; + + return true; + } + + m_WatchSeeEntity.Stop(); + return false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CAI_OperatorBehavior::IsAtPositionEntity() +{ + Vector myPos = GetAbsOrigin(); + Vector objectPos = m_hPositionEnt->GetAbsOrigin(); + + Vector vecDir = objectPos - myPos; + + return (vecDir.Length2D() <= 12.0f); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CAI_OperatorBehavior::GatherConditionsNotActive() +{ + if( m_hPositionEnt ) + { + // If we're not currently the active behavior, we have a position ent, and the + // NPC can see it, coax the AI out of IDLE/ALERT schedules with this condition. + if( CanSeePositionEntity() ) + { + SetCondition( COND_IDLE_INTERRUPT ); + } + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CAI_OperatorBehavior::GatherConditions( void ) +{ + if( GetGoalEntity() ) + { + if( GetGoalEntity()->GetState() == OPERATOR_STATE_FINISHED ) + { + if( IsCurSchedule(SCHED_OPERATOR_OPERATE) ) + { + // Break us out of the operator schedule if the operation completes. + SetCondition(COND_PROVOKED); + } + + m_hGoalEntity.Set(NULL); + m_hPositionEnt.Set(NULL); + } + else + { + if( CanSeePositionEntity() ) + { + ClearCondition( COND_OPERATOR_LOST_SIGHT_OF_POSITION ); + } + else + { + SetCondition( COND_OPERATOR_LOST_SIGHT_OF_POSITION ); + } + } + } + + BaseClass::GatherConditions(); + + // Ignore player pushing. + ClearCondition( COND_PLAYER_PUSHING ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pTask - +//----------------------------------------------------------------------------- +void CAI_OperatorBehavior::StartTask( const Task_t *pTask ) +{ + switch( pTask->iTask ) + { + case TASK_OPERATOR_OPERATE: + { + // Fire the appropriate output! + switch( GetGoalEntity()->GetState() ) + { + case OPERATOR_STATE_NOT_READY: + GetGoalEntity()->m_OnMakeReady.FireOutput(NULL, NULL, 0); + break; + + case OPERATOR_STATE_READY: + GetGoalEntity()->m_OnBeginOperating.FireOutput(NULL, NULL, 0); + break; + + default: + //!!!HACKHACK + Assert(0); + break; + } + } + TaskComplete(); + break; + + case TASK_OPERATOR_START_PATH: + { + ChainStartTask(TASK_WALK_PATH); + } + break; + + case TASK_OPERATOR_GET_PATH_TO_POSITION: + { + CBaseEntity *pGoal = m_hPositionEnt; + + if( !pGoal ) + { + TaskFail("ai_goal_operator has no location entity\n"); + break; + } + + AI_NavGoal_t goal( pGoal->GetAbsOrigin() ); + goal.pTarget = pGoal; + + if ( GetNavigator()->SetGoal( goal ) == false ) + { + TaskFail( "Can't build path\n" ); + /* + // Try and get as close as possible otherwise + AI_NavGoal_t nearGoal( GOALTYPE_LOCATION_NEAREST_NODE, m_hTargetObject->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_hTargetObject->GetAbsAngles() ); + TaskComplete(); + return; + } + */ + } + + GetNavigator()->SetArrivalDirection( pGoal->GetAbsAngles() ); + } + break; + + default: + BaseClass::StartTask( pTask ); + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pTask - +//----------------------------------------------------------------------------- +void CAI_OperatorBehavior::RunTask( const Task_t *pTask ) +{ +/* + switch( pTask->iTask ) + { + default: + BaseClass::RunTask( pTask ); + break; + } +*/ + BaseClass::RunTask( pTask ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +CAI_OperatorGoal *CAI_OperatorBehavior::GetGoalEntity() +{ + CAI_OperatorGoal *pGoal = dynamic_cast<CAI_OperatorGoal*>(m_hGoalEntity.Get()); + + // NULL is OK. + return pGoal; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CAI_OperatorBehavior::IsGoalReady() +{ + if( GetGoalEntity()->GetState() == OPERATOR_STATE_READY ) + { + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CAI_OperatorBehavior::SetParameters( CAI_OperatorGoal *pGoal, CBaseEntity *pPositionEnt, CBaseEntity *pContextTarget ) +{ + m_hGoalEntity.Set( pGoal ); + m_hPositionEnt.Set( pPositionEnt ); + m_hContextTarget.Set( pContextTarget ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CAI_OperatorBehavior::CanSelectSchedule() +{ + if ( m_hGoalEntity.Get() == NULL ) + return false; + + if ( m_hPositionEnt.Get() == NULL ) + return false; + + if( GetGoalEntity()->GetState() == OPERATOR_STATE_FINISHED ) + { + m_hGoalEntity.Set(NULL); + m_hPositionEnt.Set(NULL); + return false; + } + + if ( !GetOuter()->IsInterruptable() ) + return false; + + if ( GetOuter()->m_NPCState == NPC_STATE_COMBAT || GetOuter()->m_NPCState == NPC_STATE_SCRIPT ) + return false; + + // Don't grab NPCs who have been in combat recently + if ( GetOuter()->GetLastEnemyTime() && (gpGlobals->curtime - GetOuter()->GetLastEnemyTime()) < 3.0 ) + return false; + + if( !CanSeePositionEntity() ) + return false; + + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CAI_OperatorBehavior::SelectSchedule() +{ + if( !IsAtPositionEntity() ) + { + GetGoalEntity()->m_OnBeginApproach.FireOutput( GetOuter(), GetOuter(), 0 ); + return SCHED_OPERATOR_APPROACH_POSITION; + } + + if( GetGoalEntity() && GetGoalEntity()->GetState() != OPERATOR_STATE_FINISHED) + { + if( GetOuter()->GetActiveWeapon() && !GetOuter()->IsWeaponHolstered() ) + { + GetOuter()->SetDesiredWeaponState( DESIREDWEAPONSTATE_HOLSTERED ); + return SCHED_OPERATOR_WAIT_FOR_HOLSTER; + } + + return SCHED_OPERATOR_OPERATE; + } + + return BaseClass::SelectSchedule(); +} + + +//============================================================================= +//============================================================================= +// >AI_GOAL_OPERATOR +//============================================================================= +//============================================================================= +LINK_ENTITY_TO_CLASS( ai_goal_operator, CAI_OperatorGoal ); + +BEGIN_DATADESC( CAI_OperatorGoal ) + DEFINE_KEYFIELD( m_iState, FIELD_INTEGER, "state" ), + DEFINE_KEYFIELD( m_iMoveTo, FIELD_INTEGER, "moveto" ), + DEFINE_KEYFIELD( m_iszContextTarget, FIELD_STRING, "contexttarget" ), + + // Inputs + DEFINE_INPUTFUNC( FIELD_VOID, "SetStateReady", InputSetStateReady ), + DEFINE_INPUTFUNC( FIELD_VOID, "SetStateFinished", InputSetStateFinished ), + DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ), + + // Outputs + DEFINE_OUTPUT( m_OnBeginApproach, "OnBeginApproach" ), + DEFINE_OUTPUT( m_OnMakeReady, "OnMakeReady" ), + DEFINE_OUTPUT( m_OnBeginOperating, "OnBeginOperating" ), + DEFINE_OUTPUT( m_OnFinished, "OnFinished" ), +END_DATADESC() + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CAI_OperatorGoal::EnableGoal( CAI_BaseNPC *pAI ) +{ + CAI_OperatorBehavior *pBehavior; + + if ( !pAI->GetBehavior( &pBehavior ) ) + { + return; + } + + CBaseEntity *pPosition = gEntList.FindEntityByName(NULL, m_target); + + if( !pPosition ) + { + DevMsg("ai_goal_operator called %s with invalid position ent!\n", GetDebugName() ); + return; + } + + + CBaseEntity *pContextTarget = NULL; + + if( m_iszContextTarget != NULL_STRING ) + { + pContextTarget = gEntList.FindEntityByName( NULL, m_iszContextTarget ); + } + + pBehavior->SetParameters(this, pPosition, pContextTarget); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CAI_OperatorGoal::InputActivate( inputdata_t &inputdata ) +{ + BaseClass::InputActivate( inputdata ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &inputdata - +//----------------------------------------------------------------------------- +void CAI_OperatorGoal::InputDeactivate( inputdata_t &inputdata ) +{ + BaseClass::InputDeactivate( inputdata ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CAI_OperatorGoal::InputSetStateReady( inputdata_t &inputdata ) +{ + m_iState = OPERATOR_STATE_READY; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +void CAI_OperatorGoal::InputSetStateFinished( inputdata_t &inputdata ) +{ + m_iState = OPERATOR_STATE_FINISHED; + m_OnFinished.FireOutput( NULL, NULL, 0 ); +} + +//============================================================================= +//============================================================================= +// >SCHEDULES +//============================================================================= +//============================================================================= +AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_OperatorBehavior ) + +DECLARE_TASK( TASK_OPERATOR_GET_PATH_TO_POSITION ) +DECLARE_TASK( TASK_OPERATOR_START_PATH ) +DECLARE_TASK( TASK_OPERATOR_OPERATE ) + +DECLARE_CONDITION( COND_OPERATOR_LOST_SIGHT_OF_POSITION ) + +//========================================================= +//========================================================= +DEFINE_SCHEDULE +( + SCHED_OPERATOR_APPROACH_POSITION, + " Tasks" + " TASK_OPERATOR_GET_PATH_TO_POSITION 0" + " TASK_OPERATOR_START_PATH 0" + " TASK_WAIT_FOR_MOVEMENT 0" + " TASK_STOP_MOVING 0" + + " " + " Interrupts" + " COND_NEW_ENEMY" + " COND_HEAR_DANGER" + " COND_OPERATOR_LOST_SIGHT_OF_POSITION" + ) + + //========================================================= + //========================================================= + DEFINE_SCHEDULE + ( + SCHED_OPERATOR_OPERATE, + " Tasks" + " TASK_WAIT 0.2" // Allow pending entity I/O to settle + " TASK_OPERATOR_OPERATE 0" + " TASK_WAIT_INDEFINITE 0" + " " + " Interrupts" + " COND_PROVOKED" + ) + +//========================================================= +//========================================================= +DEFINE_SCHEDULE +( + SCHED_OPERATOR_WAIT_FOR_HOLSTER, + " Tasks" + " TASK_WAIT 1.0" + " " + " Interrupts" + " " + ) + + AI_END_CUSTOM_SCHEDULE_PROVIDER() |