Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

467 lines
13 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "beam_shared.h"
#include "ai_motor.h"
#include "asw_ai_behavior_scuttle.h"
#include "ai_hint.h"
#include "ai_navigator.h"
#include "ai_memory.h"
#include "asw_alien.h"
#include "asw_director.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
BEGIN_DATADESC( CAI_ASW_ScuttleBehavior )
DEFINE_FIELD( m_hTargetEnt, FIELD_EHANDLE ),
DEFINE_FIELD( m_flDeferUntil, FIELD_TIME ),
DEFINE_FIELD( m_flPackRange, FIELD_FLOAT ),
DEFINE_FIELD( m_flPackRangeSquared, FIELD_FLOAT ),
DEFINE_FIELD( m_flMinBackOff, FIELD_FLOAT ),
DEFINE_FIELD( m_flMaxBackOff, FIELD_FLOAT ),
DEFINE_FIELD( m_flMinYawVariation, FIELD_FLOAT ),
DEFINE_FIELD( m_flMaxYawVariation, FIELD_FLOAT ),
DEFINE_FIELD( m_flMinTimeWait, FIELD_FLOAT ),
DEFINE_FIELD( m_flMaxTimeWait, FIELD_FLOAT ),
END_DATADESC();
LINK_BEHAVIOR_TO_CLASSNAME( CAI_ASW_ScuttleBehavior );
//------------------------------------------------------------------------------
// Purpose: constructor
//------------------------------------------------------------------------------
CAI_ASW_ScuttleBehavior::CAI_ASW_ScuttleBehavior( )
{
m_flDeferUntil = gpGlobals->curtime;
m_flPackRange = 800.0f;
m_flPackRangeSquared = m_flPackRange * m_flPackRange;
m_flMinBackOff = 100.0f;
m_flMaxBackOff = 150.0f;
m_flMinYawVariation = 10.0f;
m_flMaxYawVariation = 20.0f;
m_flMinTimeWait = 1.25f;
m_flMaxTimeWait = 2.0f;
}
//------------------------------------------------------------------------------
// Purpose: function to set up parameters
// Input : szKeyName - the name of the key
// szValue - the value to be set
// Output : returns true of we handled this key
//------------------------------------------------------------------------------
bool CAI_ASW_ScuttleBehavior::KeyValue( const char *szKeyName, const char *szValue )
{
if ( V_stricmp( szKeyName, "pack_range" ) == 0 )
{
m_flPackRange = atof( szValue );
m_flPackRangeSquared = m_flPackRange * m_flPackRange;
return true;
}
else if ( V_stricmp( szKeyName, "min_backoff" ) == 0 )
{
m_flMinBackOff = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "max_backoff" ) == 0 )
{
m_flMaxBackOff = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "min_yaw" ) == 0 )
{
m_flMinYawVariation = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "max_yaw" ) == 0 )
{
m_flMaxYawVariation = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "min_wait" ) == 0 )
{
m_flMinTimeWait = atof( szValue );
return true;
}
else if ( V_stricmp( szKeyName, "max_wait" ) == 0 )
{
m_flMaxTimeWait = atof( szValue );
return true;
}
return BaseClass::KeyValue( szKeyName, szValue );
}
//------------------------------------------------------------------------------
// Purpose: precaches any additional assets this behavior needs
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::Precache( void )
{
BaseClass::Precache();
}
//------------------------------------------------------------------------------
// Purpose: determines if we can use this behavior currently
// Output : returns true if this behavior is able to run
//------------------------------------------------------------------------------
bool CAI_ASW_ScuttleBehavior::CanSelectSchedule()
{
if ( !GetOuter()->IsInterruptable() )
{
return false;
}
if ( !HasCondition( COND_SCUTTLE_HAS_DESTINATION ) )
{
return false;
}
if ( m_flDeferUntil > gpGlobals->curtime )
{
return false;
}
return BaseClass::CanSelectSchedule();
}
//------------------------------------------------------------------------------
// Purpose: sets / clears conditions for when the behavior is active. this is
// generally a larger set of conditions to interrupt any tasks.
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::GatherConditions( )
{
BaseClass::GatherConditions();
}
//------------------------------------------------------------------------------
// Purpose: sets / clears conditions for when the behavior is not active. this is
// mainly to have a smaller set of conditions to wake up the behavior.
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::GatherConditionsNotActive( )
{
BaseClass::GatherConditionsNotActive();
}
//------------------------------------------------------------------------------
// Purpose: general purpose routine to collect conditions used both during active
// and non-active states of the behavior.
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::GatherCommonConditions( )
{
BaseClass::GatherCommonConditions();
ClearCondition( COND_SCUTTLE_HAS_DESTINATION );
ClearCondition( COND_SCUTTLE_TARGET_CHANGED );
CBaseEntity *pBestObject = NULL;
bool bFound = false;
float flLength = 0.0f;
AIEnemiesIter_t iter;
Vector vEnemyPos;
for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) )
{
CBaseEntity *pEnemy = pEMemory->hEnemy;
if ( !pEnemy || !pEnemy->IsAlive() )
{
continue;
}
Vector vDiff = GetAbsOrigin() - pEMemory->vLastKnownLocation;
float flTestLength = vDiff.LengthSqr();
if ( !bFound || flTestLength < flLength )
{
bFound = true;
flLength = flTestLength;
vEnemyPos = pEMemory->vLastKnownLocation;
pBestObject = pEnemy;
}
}
int nCount = 0;
CAI_ASW_ScuttleBehavior *pBehavior;
int iAliens = IAlienAutoList::AutoList().Count();
for ( int i = 0; i < iAliens; i++ )
{
CASW_Alien *pAlien = static_cast< CASW_Alien* >( IAlienAutoList::AutoList()[ i ] );
if ( !pAlien || !pAlien->IsAlive() || pAlien->GetBehavior( &pBehavior ) != NULL )
{
continue;
}
if ( GetOuter() != pAlien )
{
Vector vDiffEnemy = pAlien->GetAbsOrigin() - vEnemyPos;
float flEnemyLength = vDiffEnemy.LengthSqr();
Vector vDiffUs = pAlien->GetAbsOrigin() - GetAbsOrigin();
float flUsLength = vDiffUs.LengthSqr();
if ( flEnemyLength < m_flPackRangeSquared && flUsLength < m_flPackRangeSquared )
{
nCount++;
}
}
}
if ( pBestObject && nCount > 0 )
{
m_vDestination = pBestObject->GetAbsOrigin();
SetCondition( COND_SCUTTLE_HAS_DESTINATION );
if ( m_hTargetEnt != NULL && m_hTargetEnt != pBestObject )
{
SetCondition( COND_SCUTTLE_TARGET_CHANGED );
}
m_hTargetEnt = pBestObject;
}
else
{
if ( m_hTargetEnt != NULL && m_hTargetEnt != pBestObject )
{
SetCondition( COND_SCUTTLE_TARGET_CHANGED );
}
m_hTargetEnt = NULL;
}
}
//------------------------------------------------------------------------------
// Purpose: routine called to start when a task initially starts
// Input : pTask - the task structure
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::StartTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_SCUTTLE_SET_PATH:
{
bool bFound = false;
float flLength = 0.0f;
AIEnemiesIter_t iter;
Vector vEnemyPos;
for( AI_EnemyInfo_t *pEMemory = GetEnemies()->GetFirst( &iter ); pEMemory != NULL; pEMemory = GetEnemies()->GetNext( &iter ) )
{
CBaseEntity *pEnemy = pEMemory->hEnemy;
if ( !pEnemy || !pEnemy->IsAlive() )
{
continue;
}
Vector vDiff = GetAbsOrigin() - pEMemory->vLastKnownLocation;
float flTestLength = vDiff.LengthSqr();
if ( !bFound || flTestLength < flLength )
{
bFound = true;
flLength = flTestLength;
vEnemyPos = pEMemory->vLastKnownLocation;
}
}
if ( bFound == false || flLength > m_flPackRangeSquared )
{
TaskFail( FAIL_NO_TARGET );
break;
}
Vector vCenter;
int nCount = 0;
CAI_ASW_ScuttleBehavior *pBehavior;
vCenter.Zero();
int iAliens = IAlienAutoList::AutoList().Count();
for ( int i = 0; i < iAliens; i++ )
{
CASW_Alien *pAlien = static_cast< CASW_Alien* >( IAlienAutoList::AutoList()[ i ] );
if ( !pAlien || !pAlien->IsAlive() || pAlien->GetBehavior( &pBehavior ) != NULL )
{
continue;
}
if ( GetOuter() != pAlien )
{
Vector vDiffEnemy = pAlien->GetAbsOrigin() - vEnemyPos;
float flEnemyLength = vDiffEnemy.LengthSqr();
Vector vDiffUs = pAlien->GetAbsOrigin() - GetAbsOrigin();
float flUsLength = vDiffUs.LengthSqr();
if ( flEnemyLength < m_flPackRangeSquared && flUsLength < m_flPackRangeSquared )
{
nCount++;
vCenter += pAlien->GetAbsOrigin();
}
}
}
if ( nCount == 0 )
{
TaskFail( FAIL_NO_TARGET );
break;
}
vCenter /= nCount;
// NDebugOverlay::Cross3D( vCenter, -Vector(32,32,32), Vector(32,32,32), 0, 255, 0, true, 0.1f );
Vector vDiff = vCenter - vEnemyPos;
// flLength = vDiff.NormalizeInPlace();
flLength = RandomFloat( m_flMinBackOff, m_flMaxBackOff );
float targetYaw = UTIL_VecToYaw( vDiff );
vDiff.z = 0.0f;
float flTestYaw = targetYaw - RandomFloat( m_flMinYawVariation, m_flMaxYawVariation );
vDiff.x = cos( DEG2RAD( flTestYaw ) );
vDiff.y = sin( DEG2RAD( flTestYaw ) );
Vector vPos1 = vCenter + ( vDiff * flLength );
flTestYaw = targetYaw + RandomFloat( m_flMinYawVariation, m_flMaxYawVariation );
vDiff.x = cos( DEG2RAD( flTestYaw ) );
vDiff.y = sin( DEG2RAD( flTestYaw ) );
Vector vPos2 = vCenter + ( vDiff * flLength );
Vector vDiff1 = vPos1 - GetAbsOrigin();
Vector vDiff2 = vPos2 - GetAbsOrigin();
Vector vDestination;
if ( vDiff1.LengthSqr() > vDiff2.LengthSqr() )
{
vDestination = vPos1;
// NDebugOverlay::Cross3D( vPos2, -Vector(32,32,32), Vector(32,32,32), 255, 255, 0, true, 0.1f );
}
else
{
vDestination = vPos2;
// NDebugOverlay::Cross3D( vPos1, -Vector(32,32,32), Vector(32,32,32), 255, 255, 0, true, 0.1f );
}
// NDebugOverlay::Cross3D( vDestination, -Vector(32,32,32), Vector(32,32,32), 255, 255, 255, true, 0.1f );
AI_NavGoal_t goal( GOALTYPE_LOCATION, vDestination, ACT_WALK, 50.0f, AIN_YAW_TO_DEST | AIN_LOCAL_SUCCEEED_ON_WITHIN_TOLERANCE, AIN_DEF_TARGET );
bool bResult = GetNavigator()->SetGoal( goal, AIN_NO_PATH_TASK_FAIL );
if ( bResult == false )
{
flTestYaw = RandomFloat( 0.0f, 360.0f );
vDiff.x = cos( DEG2RAD( flTestYaw ) );
vDiff.y = sin( DEG2RAD( flTestYaw ) );
vDestination = vCenter + ( vDiff * flLength );
AI_NavGoal_t RandomGoal( GOALTYPE_LOCATION, vDestination, ACT_WALK, 50.0f, AIN_YAW_TO_DEST | AIN_LOCAL_SUCCEEED_ON_WITHIN_TOLERANCE, AIN_DEF_TARGET );
bResult = GetNavigator()->SetGoal( RandomGoal, AIN_NO_PATH_TASK_FAIL );
}
GetNavigator()->SetMovementActivity( ACT_WALK );
GetOuter()->SetWait( RandomFloat( m_flMinTimeWait, m_flMaxTimeWait ) );
break;
}
case TASK_SCUTTLE_WAIT:
{
break;
}
default:
BaseClass::StartTask( pTask );
break;
}
}
//------------------------------------------------------------------------------
// Purpose: routine called every frame when a task is running
// Input : pTask - the task structure
//------------------------------------------------------------------------------
void CAI_ASW_ScuttleBehavior::RunTask( const Task_t *pTask )
{
switch( pTask->iTask )
{
case TASK_SCUTTLE_SET_PATH:
{
if ( GetNavigator()->GetGoalType() == GOALTYPE_NONE )
{
TaskComplete();
}
break;
}
case TASK_SCUTTLE_WAIT:
{
if ( GetOuter()->IsWaitFinished() )
{
TaskComplete();
}
break;
}
default:
BaseClass::RunTask( pTask );
break;
}
}
//------------------------------------------------------------------------------
// Purpose: routine called to select what schedule we want to run
// Output : returns the schedule id of the schedule we want to run
//------------------------------------------------------------------------------
int CAI_ASW_ScuttleBehavior::SelectSchedule()
{
if ( HasCondition( COND_SCUTTLE_HAS_DESTINATION ) )
{
return SCHED_SCUTTLE_MOVE_NEAR_TARGET;
}
return BaseClass::SelectSchedule();
}
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_ASW_ScuttleBehavior )
DECLARE_TASK( TASK_SCUTTLE_SET_PATH )
DECLARE_TASK( TASK_SCUTTLE_WAIT )
DECLARE_CONDITION( COND_SCUTTLE_HAS_DESTINATION )
DECLARE_CONDITION( COND_SCUTTLE_TARGET_CHANGED )
//===============================================
//===============================================
DEFINE_SCHEDULE
(
SCHED_SCUTTLE_MOVE_NEAR_TARGET,
" Tasks"
" TASK_SCUTTLE_SET_PATH 0"
" TASK_SET_ACTIVITY ACTIVITY:ACT_IDLE"
" TASK_SCUTTLE_WAIT 0"
// " TASK_WALK_PATH_TIMED 1.5"
// " TASK_WAIT_FOR_MOVEMENT 0"
""
" Interrupts"
""
// " COND_SCUTTLE_TARGET_CHANGED"
);
AI_END_CUSTOM_SCHEDULE_PROVIDER()
#include "tier0/memdbgoff.h"