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.
855 lines
21 KiB
855 lines
21 KiB
//========== Copyright © 2008, Valve Corporation, All rights reserved. ======== |
|
// |
|
// Purpose: |
|
// |
|
//============================================================================= |
|
|
|
#include "cbase.h" |
|
|
|
#include "ai_behavior_fightfromcover.h" |
|
#include "ai_hint.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
BEGIN_DATADESC( CAI_FightFromCoverBehavior ) |
|
DEFINE_FIELD( m_hGoal, FIELD_EHANDLE ), |
|
DEFINE_EMBEDDED( m_FrontMoveMonitor ), |
|
DEFINE_EMBEDDED( m_FrontTimer ), |
|
END_DATADESC(); |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
CAI_FightFromCoverBehavior::CAI_FightFromCoverBehavior() |
|
{ |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::SetGoal( CAI_FightFromCoverGoal *pGoal ) |
|
{ |
|
m_hGoal = pGoal; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::ClearGoal() |
|
{ |
|
m_hGoal = NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::IsPointInZone( const Vector &v ) |
|
{ |
|
if ( !m_hGoal->GetFrontDirection().IsValid() ) |
|
{ |
|
return true; |
|
} |
|
|
|
Vector vCenterZone; |
|
vCenterZone = ( m_hGoal->GetFrontDirection() * -m_hGoal->m_BiasZone ) + m_hGoal->GetFrontPosition(); |
|
|
|
Vector vRelativePos ; |
|
VectorRotate( v - vCenterZone, -m_hGoal->GetFrontAngles(), vRelativePos ); |
|
float w = m_hGoal->m_WidthZone * .5, l = m_hGoal->m_LengthZone * .5, h = m_hGoal->m_HeightZone * .5; |
|
|
|
Vector mins( -l, -w, -h ), maxs( l, w, h ); |
|
|
|
if ( vRelativePos.x < mins.x || vRelativePos.x > maxs.x || |
|
vRelativePos.y < mins.y || vRelativePos.y > maxs.y || |
|
vRelativePos.z < mins.z || vRelativePos.z > maxs.z ) |
|
{ |
|
// NDebugOverlay::Cross3D( v, 36, 255, 0, 0, true, 3 ); |
|
return false; |
|
} |
|
|
|
// NDebugOverlay::Cross3D( v, 36, 0, 255, 0, true, 3 ); |
|
return true; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::FValidateHintType ( CAI_Hint *pHint ) |
|
{ |
|
if ( pHint->HintType() == HINT_GENERIC && pHint->GetGenericType() == m_hGoal->m_GenericHintType ) |
|
{ |
|
return true; |
|
} |
|
return BaseClass::FValidateHintType( pHint ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::HintSearchFilter( void *pContext, CAI_Hint *pCandidate ) |
|
{ |
|
CAI_FightFromCoverBehavior *pThis = (CAI_FightFromCoverBehavior *)pContext; |
|
Vector vHintDir; |
|
if ( pThis->m_hGoal->GetFrontDirection().IsValid() ) |
|
{ |
|
pCandidate->GetVectors( &vHintDir, NULL, NULL ); |
|
if ( vHintDir.Dot( pThis->m_hGoal->GetFrontDirection() ) < DOT_45DEGREE ) |
|
{ |
|
return false; |
|
} |
|
} |
|
return pThis->IsPointInZone( pCandidate->GetAbsOrigin() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::GatherConditions() |
|
{ |
|
BaseClass::GatherConditions(); |
|
|
|
ClearCondition( COND_FFC_HINT_CHANGE ); |
|
if ( !m_hGoal ) |
|
{ |
|
SetCondition( COND_FFC_HINT_CHANGE ); |
|
ClearHintNode(); |
|
return; |
|
} |
|
|
|
if ( GetHintNode() && m_FrontTimer.Expired() && m_FrontMoveMonitor.TargetMoved( m_hGoal->GetFrontPosition() ) ) |
|
{ |
|
float flFastRejectDist = MAX( m_hGoal->m_WidthZone, m_hGoal->m_LengthZone ) + m_hGoal->m_BiasZone; |
|
|
|
if ( ( GetHintNode()->GetAbsOrigin() - m_hGoal->GetFrontPosition() ).LengthSqr() > Square( flFastRejectDist ) || !IsPointInZone( GetHintNode()->GetAbsOrigin() ) ) |
|
{ |
|
GetHintNode()->Unlock(); |
|
SetHintNode( NULL ); |
|
SetCondition( COND_FFC_HINT_CHANGE ); |
|
} |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::CanSelectSchedule() |
|
{ |
|
return ( m_hGoal != NULL ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
int CAI_FightFromCoverBehavior::SelectSchedule() |
|
{ |
|
Assert( m_hGoal != NULL ); |
|
if ( !m_hGoal ) |
|
{ |
|
return BaseClass::SelectSchedule(); |
|
} |
|
|
|
if ( !GetHintNode() ) |
|
{ |
|
if ( m_FrontTimer.Expired() ) |
|
{ |
|
m_FrontTimer.Set( .75, 1.5 ); |
|
|
|
Vector vFront = m_hGoal->GetFrontPosition(); |
|
CHintCriteria hintCriteria; |
|
hintCriteria.SetHintType( HINT_GENERIC ); |
|
hintCriteria.SetGenericType( m_hGoal->m_GenericHintType ); |
|
hintCriteria.SetFlag( bits_HINT_NODE_NEAREST | bits_HINT_NODE_USE_GROUP ); |
|
|
|
// Add the search position |
|
hintCriteria.AddIncludePosition( vFront, MAX( m_hGoal->m_WidthZone, m_hGoal->m_LengthZone ) + m_hGoal->m_BiasZone ); |
|
hintCriteria.AddExcludePosition( m_hGoal->GetGoalEntity()->GetAbsOrigin(), 2.5*12 ); |
|
|
|
hintCriteria.SetFilterFunc( &HintSearchFilter, this ); |
|
|
|
const Vector &vDir = m_hGoal->GetFrontDirection(); |
|
if ( vDir.IsValid() ) |
|
{ |
|
vFront += vDir * m_hGoal->m_LengthZone; |
|
} |
|
|
|
CAI_Hint *pHint = CAI_HintManager::FindHint( GetOuter(), vFront, hintCriteria ); |
|
|
|
if ( !pHint ) |
|
{ |
|
// @HACKHACK [5/21/2008 tom] |
|
float lengthSaved = m_hGoal->m_LengthZone, biasSaved = m_hGoal->m_BiasZone, widthSaved = m_hGoal->m_WidthZone; |
|
m_hGoal->m_LengthZone += 2000; |
|
m_hGoal->m_BiasZone += 1000; |
|
m_hGoal->m_WidthZone += 2000; |
|
pHint = CAI_HintManager::FindHint( GetOuter(), vFront, hintCriteria ); |
|
m_hGoal->m_LengthZone = lengthSaved; |
|
m_hGoal->m_BiasZone = biasSaved; |
|
m_hGoal->m_WidthZone = widthSaved; |
|
} |
|
|
|
if ( pHint ) |
|
{ |
|
SetHintNode( pHint ); |
|
pHint->Lock( GetOuter() ); |
|
m_FrontMoveMonitor.SetMark( vFront, 3*12 ); |
|
} |
|
} |
|
} |
|
|
|
if ( GetHintNode() ) |
|
{ |
|
if ( ( GetHintNode()->GetAbsOrigin() - GetAbsOrigin() ).LengthSqr() > Square( 12.0 ) ) |
|
{ |
|
return SCHED_FFC_RUN_TO_HINT; |
|
} |
|
else if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) && !GetOuter()->GetShotRegulator()->IsInRestInterval() ) |
|
{ |
|
return SCHED_FFC_ATTACK; |
|
} |
|
else if ( HasCondition( COND_NO_PRIMARY_AMMO ) ) |
|
{ |
|
return SCHED_RELOAD; |
|
} |
|
else |
|
{ |
|
GetOuter()->GetShotRegulator()->Reset( true ); |
|
return SCHED_FFC_HOLD_COVER; |
|
} |
|
} |
|
|
|
return BaseClass::SelectSchedule(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::StartTask( const Task_t *pTask ) |
|
{ |
|
switch ( pTask->iTask ) |
|
{ |
|
case TASK_FFC_GET_PATH_TO_HINT: |
|
{ |
|
ChainStartTask( TASK_GET_PATH_TO_HINTNODE ); |
|
|
|
if ( !HasCondition(COND_TASK_FAILED) ) |
|
{ |
|
UpdateAnimationsFromHint(); |
|
} |
|
else |
|
{ |
|
// Should mark hint and try to find another one |
|
ClearHintNode( 5 ); |
|
} |
|
|
|
break; |
|
} |
|
|
|
case TASK_FFC_ATTACK: |
|
{ |
|
CBaseCombatWeapon *pWeapon = GetOuter()->GetActiveWeapon(); |
|
if ( !pWeapon ) |
|
{ |
|
TaskFail( "No weapon" ); |
|
return; |
|
} |
|
int clipSize = pWeapon->GetMaxClip1(); |
|
GetOuter()->GetShotRegulator()->SetBurstShotCountRange( clipSize * .3, clipSize * .6 ); |
|
GetOuter()->GetShotRegulator()->SetRestInterval( INT_MAX, INT_MAX ); |
|
GetOuter()->GetShotRegulator()->Reset(); |
|
StartAnimationTask( m_ShootAnim, true, ACT_RANGE_ATTACK1 ); |
|
GetOuter()->SetLastAttackTime( gpGlobals->curtime ); |
|
GetOuter()->OnRangeAttack1(); |
|
break; |
|
} |
|
|
|
case TASK_RELOAD: |
|
{ |
|
if ( !StartAnimationTask( m_ReloadAnim, true ) ) |
|
{ |
|
BaseClass::StartTask( pTask ); |
|
} |
|
break; |
|
} |
|
|
|
case TASK_FFC_PEEK: |
|
{ |
|
StartAnimationTask( m_PeekAnim ); |
|
break; |
|
} |
|
case TASK_FFC_COVER: |
|
{ |
|
StartAnimationTask( m_CoverAnim ); |
|
break; |
|
} |
|
|
|
default: |
|
BaseClass::StartTask( pTask ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::RunTask( const Task_t *pTask ) |
|
{ |
|
switch ( pTask->iTask ) |
|
{ |
|
case TASK_FFC_ATTACK: |
|
{ |
|
GetOuter()->AutoMovement( ); |
|
|
|
if ( GetOuter()->IsActivityFinished() ) |
|
{ |
|
if ( !GetEnemy() || !GetEnemy()->IsAlive() ) |
|
{ |
|
TaskComplete(); |
|
return; |
|
} |
|
|
|
if ( !GetOuter()->GetShotRegulator()->IsInRestInterval() ) |
|
{ |
|
if ( GetOuter()->GetShotRegulator()->ShouldShoot() ) |
|
{ |
|
GetOuter()->OnRangeAttack1(); |
|
StartAnimationTask( m_ShootAnim, true, ACT_RANGE_ATTACK1 ); |
|
} |
|
return; |
|
} |
|
TaskComplete(); |
|
} |
|
break; |
|
} |
|
case TASK_FFC_PEEK: |
|
case TASK_FFC_COVER: |
|
{ |
|
ChainRunTask( TASK_PLAY_SEQUENCE ); |
|
break; |
|
} |
|
default: |
|
BaseClass::RunTask( pTask); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::OnUpdateShotRegulator() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
void CAI_FightFromCoverBehavior::UpdateAnimationsFromHint() |
|
{ |
|
m_EntryAnim.Reset(); |
|
m_MoveAnim.Reset(); |
|
m_CoverAnim.Reset(); |
|
m_ReloadAnim.Reset(); |
|
m_PeekAnim.Reset(); |
|
m_ShootAnim.Reset(); |
|
m_ExitAnim.Reset(); |
|
|
|
if ( !GetHintNode() ) |
|
{ |
|
return; |
|
} |
|
|
|
CScriptScope &hintScope = GetHintNode()->m_ScriptScope; |
|
ScriptVariant_t animationsVar; |
|
|
|
if ( hintScope.GetValue( "animations", &animationsVar ) ) |
|
{ |
|
if ( animationsVar.m_type == FIELD_HSCRIPT ) |
|
{ |
|
CScriptScope animations; |
|
ScriptVariant_t var; |
|
|
|
animations.Init( animationsVar.m_hScript ); |
|
|
|
GetAnimation( animations, "movement", &m_MoveAnim ); |
|
GetAnimation( animations, "entry", &m_EntryAnim ); |
|
if ( m_EntryAnim.id != ACT_INVALID ) |
|
{ |
|
DevMsg( "entry anim not yet supported!\n" ); |
|
m_EntryAnim.Reset(); |
|
} |
|
GetAnimation( animations, "cover", &m_CoverAnim ); |
|
GetAnimation( animations, "reload", &m_ReloadAnim ); |
|
GetAnimation( animations, "peek", &m_PeekAnim ); |
|
GetAnimation( animations, "shoot", &m_ShootAnim ); |
|
GetAnimation( animations, "exit", &m_ExitAnim ); |
|
if ( m_EntryAnim.id != ACT_INVALID ) |
|
{ |
|
DevMsg( "exit anim not yet supported!\n" ); |
|
m_EntryAnim.Reset(); |
|
} |
|
} |
|
else |
|
{ |
|
DevMsg( "Unexpected type for script value \"animations\"\n" ); |
|
} |
|
hintScope.ReleaseValue( animationsVar ); |
|
} |
|
|
|
if ( m_MoveAnim.id != ACT_INVALID ) |
|
{ |
|
if ( m_MoveAnim.bActivity ) |
|
{ |
|
GetNavigator()->SetMovementActivity( (Activity)m_MoveAnim.id ); |
|
} |
|
else |
|
{ |
|
GetNavigator()->SetMovementSequence( m_MoveAnim.id ); |
|
} |
|
} |
|
else |
|
{ |
|
ChainStartTask( TASK_RUN_PATH ); |
|
} |
|
|
|
if ( m_EntryAnim.id != ACT_INVALID ) |
|
{ |
|
Assert( 0 ); |
|
} |
|
else if ( m_CoverAnim.id != ACT_INVALID ) |
|
{ |
|
if ( m_CoverAnim.bActivity ) |
|
{ |
|
GetNavigator()->SetArrivalActivity( (Activity)m_CoverAnim.id ); |
|
} |
|
else |
|
{ |
|
GetNavigator()->SetArrivalSequence( m_CoverAnim.id ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::GetAnimation( CScriptScope &scope, const char *pszKey, Animation_t *pAnimation ) |
|
{ |
|
ScriptVariant_t var; |
|
bool result = false; |
|
|
|
// Find the movement activity or sequence |
|
if ( scope.GetValue( pszKey, &var ) ) |
|
{ |
|
if ( var.m_type == FIELD_CSTRING ) |
|
{ |
|
pAnimation->bActivity = ( V_strncmp( var, "ACT_", 4 ) == 0 ); |
|
if ( !pAnimation->bActivity ) |
|
{ |
|
pAnimation->id = GetOuter()->LookupSequence( var ); |
|
if ( pAnimation->id < 0 ) |
|
{ |
|
pAnimation->Reset(); |
|
} |
|
} |
|
else |
|
{ |
|
pAnimation->id = CAI_BaseNPC::GetActivityID( var ); |
|
} |
|
|
|
if ( pAnimation->id == ACT_INVALID ) |
|
{ |
|
DevMsg( "Failed to resolve animation \"%s\"\n", var.m_pszString ); |
|
} |
|
} |
|
scope.ReleaseValue( var ); |
|
} |
|
return result; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
//----------------------------------------------------------------------------- |
|
bool CAI_FightFromCoverBehavior::StartAnimationTask( const Animation_t &animation, bool bReset, Activity defaultActivity ) |
|
{ |
|
if ( animation.id != ACT_INVALID ) |
|
{ |
|
if ( animation.bActivity ) |
|
{ |
|
if ( bReset ) |
|
GetOuter()->ResetIdealActivity( (Activity)animation.id ); |
|
else |
|
GetOuter()->SetIdealActivity( (Activity)animation.id ); |
|
} |
|
else |
|
{ |
|
GetOuter()->SetIdealSequence( animation.id, bReset ); |
|
} |
|
return true; |
|
} |
|
else |
|
{ |
|
if ( bReset ) |
|
GetOuter()->SetIdealActivity( defaultActivity ); |
|
return false; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
AI_BEGIN_CUSTOM_SCHEDULE_PROVIDER( CAI_FightFromCoverBehavior ) |
|
|
|
DECLARE_CONDITION( COND_FFC_HINT_CHANGE ) |
|
|
|
DECLARE_TASK( TASK_FFC_GET_PATH_TO_HINT ) |
|
DECLARE_TASK( TASK_FFC_COVER ) |
|
DECLARE_TASK( TASK_FFC_PEEK ) |
|
DECLARE_TASK( TASK_FFC_ATTACK ) |
|
|
|
//--------------------------------- |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_RUN_TO_HINT, |
|
|
|
" Tasks" |
|
" TASK_FFC_GET_PATH_TO_HINT 0" |
|
" TASK_WAIT_FOR_MOVEMENT 0" |
|
" TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_COVER" |
|
"" |
|
" Interrupts" |
|
" COND_FFC_HINT_CHANGE" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_HOLD_COVER, |
|
|
|
" Tasks" |
|
// " TASK_FACE_HINTNODE 0" |
|
" TASK_FFC_COVER 0" |
|
" TASK_WAIT_RANDOM 2.0" |
|
" TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_PEEK" |
|
"" |
|
" Interrupts" |
|
" COND_FFC_HINT_CHANGE" |
|
" COND_NO_PRIMARY_AMMO" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_RELOAD, |
|
|
|
" Tasks" |
|
" TASK_RELOAD 0" |
|
" TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_PEEK" |
|
"" |
|
" Interrupts" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_PEEK, |
|
|
|
" Tasks" |
|
" TASK_FFC_PEEK 0" |
|
" TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_PEEK" |
|
"" |
|
" Interrupts" |
|
" COND_NEW_ENEMY" |
|
" COND_CAN_RANGE_ATTACK1" |
|
" COND_FFC_HINT_CHANGE" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_HOLD_PEEK, |
|
|
|
" Tasks" |
|
" TASK_WAIT_RANDOM 1.0" |
|
" TASK_SET_SCHEDULE SCHEDULE:SCHED_FFC_HOLD_COVER" |
|
"" |
|
" Interrupts" |
|
" COND_FFC_HINT_CHANGE" |
|
" COND_NEW_ENEMY" |
|
" COND_CAN_RANGE_ATTACK1" |
|
" COND_NO_PRIMARY_AMMO" |
|
) |
|
|
|
DEFINE_SCHEDULE |
|
( |
|
SCHED_FFC_ATTACK, |
|
|
|
" Tasks" |
|
" TASK_STOP_MOVING 0" |
|
" TASK_FFC_ATTACK 0" |
|
"" |
|
" Interrupts" |
|
" COND_NEW_ENEMY" |
|
" COND_ENEMY_DEAD" |
|
" COND_LIGHT_DAMAGE" |
|
" COND_HEAVY_DAMAGE" |
|
" COND_ENEMY_OCCLUDED" |
|
" COND_NO_PRIMARY_AMMO" |
|
" COND_HEAR_DANGER" |
|
" COND_WEAPON_BLOCKED_BY_FRIEND" |
|
" COND_WEAPON_SIGHT_OCCLUDED" |
|
) |
|
|
|
AI_END_CUSTOM_SCHEDULE_PROVIDER() |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// |
|
// CAI_FightFromCoverGoal |
|
// |
|
//----------------------------------------------------------------------------- |
|
|
|
BEGIN_DATADESC( CAI_FightFromCoverGoal ) |
|
DEFINE_KEYFIELD( m_DirectionalMarker, FIELD_STRING, "DirectionalMarker" ), |
|
DEFINE_KEYFIELD( m_GenericHintType, FIELD_STRING, "GenericHintType" ), |
|
DEFINE_KEYFIELD( m_WidthZone, FIELD_FLOAT, "width" ), |
|
DEFINE_KEYFIELD( m_LengthZone, FIELD_FLOAT, "length" ), |
|
DEFINE_KEYFIELD( m_HeightZone, FIELD_FLOAT, "height" ), |
|
DEFINE_KEYFIELD( m_BiasZone, FIELD_FLOAT, "bias" ), |
|
DEFINE_FIELD( m_vFront, FIELD_POSITION_VECTOR ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_EHANDLE, "SetDirectionalMarker", InputSetDirectionalMarker ), |
|
DEFINE_THINKFUNC( FrontThink ), |
|
|
|
END_DATADESC() |
|
|
|
//------------------------------------- |
|
|
|
LINK_ENTITY_TO_CLASS( ai_goal_fightfromcover, CAI_FightFromCoverGoal ); |
|
|
|
//------------------------------------- |
|
|
|
CAI_FightFromCoverGoal::CAI_FightFromCoverGoal() |
|
{ |
|
m_vDir.Invalidate(); |
|
m_WidthZone = 50*12; |
|
m_LengthZone = 40*12; |
|
m_BiasZone = 5*12; |
|
m_HeightZone = 200*12; |
|
} |
|
|
|
//------------------------------------- |
|
|
|
const Vector &CAI_FightFromCoverGoal::GetFrontPosition() |
|
{ |
|
if ( m_hDirectionalMarker != NULL ) |
|
{ |
|
return m_vFront; |
|
} |
|
else if ( m_hGoalEntity != NULL ) |
|
{ |
|
return m_hGoalEntity->GetAbsOrigin(); |
|
} |
|
|
|
return GetAbsOrigin(); |
|
} |
|
|
|
//------------------------------------- |
|
|
|
const Vector &CAI_FightFromCoverGoal::GetFrontDirection() |
|
{ |
|
return m_vDir; |
|
} |
|
|
|
//------------------------------------- |
|
|
|
const QAngle &CAI_FightFromCoverGoal::GetFrontAngles() |
|
{ |
|
if ( m_hDirectionalMarker != NULL ) |
|
{ |
|
return m_hDirectionalMarker->GetAbsAngles(); |
|
} |
|
static QAngle invalid( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); |
|
return invalid; |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::BeginMovingFront() |
|
{ |
|
if ( m_hDirectionalMarker != NULL ) |
|
{ |
|
if ( m_hGoalEntity != NULL ) |
|
{ |
|
if ( !m_pfnThink ) |
|
{ |
|
SetThink( &CAI_FightFromCoverGoal::FrontThink ); |
|
SetNextThink( gpGlobals->curtime + .1 ); |
|
} |
|
} |
|
else |
|
{ |
|
m_vFront = m_hDirectionalMarker->GetAbsOrigin(); |
|
} |
|
} |
|
else |
|
{ |
|
EndMovingFront(); |
|
} |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::EndMovingFront() |
|
{ |
|
SetThink( NULL ); |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::OnActivate() |
|
{ |
|
BeginMovingFront(); |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::OnDeactivate() |
|
{ |
|
EndMovingFront(); |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::FrontThink() |
|
{ |
|
if ( m_hDirectionalMarker != NULL && m_hGoalEntity != NULL ) |
|
{ |
|
Vector vClosest; |
|
AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir ); |
|
CalcClosestPointOnLineSegment( m_hGoalEntity->GetAbsOrigin(), m_vFront, m_vFront + m_vDir * 99999, vClosest ); |
|
m_vFront = vClosest; |
|
SetNextThink( gpGlobals->curtime + 0.5 ); |
|
} |
|
else |
|
{ |
|
EndMovingFront(); |
|
} |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::EnableGoal( CAI_BaseNPC *pAI ) |
|
{ |
|
CAI_FightFromCoverBehavior *pBehavior; |
|
if ( !pAI->GetBehavior( &pBehavior ) ) |
|
return; |
|
|
|
CBaseEntity *pGoalEntity = GetGoalEntity(); |
|
if ( pGoalEntity ) |
|
{ |
|
pBehavior->SetGoal( this ); |
|
} |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::DisableGoal( CAI_BaseNPC *pAI ) |
|
{ |
|
CAI_FightFromCoverBehavior *pBehavior; |
|
if ( !pAI || !pAI->GetBehavior( &pBehavior ) ) |
|
return; |
|
|
|
pBehavior->ClearGoal(); |
|
} |
|
|
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::ResolveNames() |
|
{ |
|
BaseClass::ResolveNames(); |
|
|
|
if ( m_hGoalEntity == NULL && AI_IsSinglePlayer() ) |
|
{ |
|
m_hGoalEntity = UTIL_GetLocalPlayer(); |
|
} |
|
|
|
if ( m_DirectionalMarker != NULL_STRING ) |
|
{ |
|
EHANDLE hDirectionalMarker = gEntList.FindEntityByName( NULL, STRING(m_DirectionalMarker) ); |
|
if ( m_hDirectionalMarker != hDirectionalMarker ) |
|
{ |
|
m_hDirectionalMarker = gEntList.FindEntityByName( NULL, STRING(m_DirectionalMarker) ); |
|
m_vFront = m_hDirectionalMarker->GetAbsOrigin(); |
|
AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir ); |
|
} |
|
BeginMovingFront(); |
|
} |
|
else |
|
{ |
|
m_hDirectionalMarker = NULL; |
|
m_vDir.Invalidate(); |
|
EndMovingFront(); |
|
} |
|
} |
|
|
|
//------------------------------------- |
|
|
|
void CAI_FightFromCoverGoal::InputSetDirectionalMarker( inputdata_t &inputdata ) |
|
{ |
|
m_hDirectionalMarker = inputdata.value.Entity(); |
|
if ( m_hDirectionalMarker != NULL ) |
|
{ |
|
m_DirectionalMarker = m_hDirectionalMarker->GetEntityName(); |
|
m_vFront = m_hDirectionalMarker->GetAbsOrigin(); |
|
AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &m_vDir ); |
|
BeginMovingFront(); |
|
} |
|
else |
|
{ |
|
m_DirectionalMarker = NULL_STRING; |
|
m_vDir.Invalidate(); |
|
EndMovingFront(); |
|
} |
|
} |
|
|
|
//------------------------------------- |
|
|
|
int CAI_FightFromCoverGoal::DrawDebugTextOverlays() |
|
{ |
|
int text_offset = BaseClass::DrawDebugTextOverlays(); |
|
|
|
if ( m_debugOverlays & OVERLAY_TEXT_BIT ) |
|
{ |
|
CFmtStr str; |
|
if ( m_hDirectionalMarker != NULL ) |
|
{ |
|
EntityText( text_offset++, str.sprintf( "Dir ent: %s", m_hDirectionalMarker->GetEntityNameAsCStr() ), 0 ); |
|
NDebugOverlay::YawArrow( m_hDirectionalMarker->GetAbsOrigin() + Vector( 0, 0, 6 ), m_hDirectionalMarker->GetAbsAngles().y, 60, 6, 255, 255, 255, 0, true, 0 ); |
|
NDebugOverlay::Cross3DOriented( m_vFront + Vector( 0, 0, 6 ), m_hDirectionalMarker->GetAbsAngles(), 12, 255, 0, 0, true, 0 ); |
|
|
|
Vector vBoxDrawCenter; |
|
AngleVectors( m_hDirectionalMarker->GetAbsAngles(), &vBoxDrawCenter ); |
|
vBoxDrawCenter *= -m_BiasZone; |
|
vBoxDrawCenter += m_vFront; |
|
NDebugOverlay::BoxAngles( vBoxDrawCenter, Vector( -(m_LengthZone/2), -(m_WidthZone/2), -(m_HeightZone/2) ), Vector( m_LengthZone/2, m_WidthZone/2, m_HeightZone/2 ), m_hDirectionalMarker->GetAbsAngles(), 255, 0, 0, 16, 0 ); |
|
|
|
for ( int i = 0; i < m_actors.Count(); i++ ) |
|
{ |
|
if ( m_actors[i] != NULL ) |
|
{ |
|
NDebugOverlay::Line( m_vFront, m_actors[i]->WorldSpaceCenter(), 0, 0, 127, true, 0 ); |
|
} |
|
} |
|
} |
|
|
|
if ( m_hGoalEntity != NULL ) |
|
{ |
|
EntityText( text_offset++, str.sprintf( "Front ent: %s", m_hGoalEntity->GetEntityNameAsCStr() ), 0 ); |
|
} |
|
} |
|
|
|
return text_offset; |
|
}
|
|
|