mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user