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.
236 lines
6.0 KiB
236 lines
6.0 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// tf_bot_spy_hide.cpp |
|
// Move to a hiding spot |
|
// Michael Booth, September 2011 |
|
|
|
#include "cbase.h" |
|
#include "tf_player.h" |
|
#include "bot/tf_bot.h" |
|
#include "bot/behavior/spy/tf_bot_spy_hide.h" |
|
#include "bot/behavior/spy/tf_bot_spy_lurk.h" |
|
#include "bot/behavior/spy/tf_bot_spy_attack.h" |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
CTFBotSpyHide::CTFBotSpyHide( CTFPlayer *victim ) |
|
{ |
|
m_initialVictim = victim; |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
ActionResult< CTFBot > CTFBotSpyHide::OnStart( CTFBot *me, Action< CTFBot > *priorAction ) |
|
{ |
|
m_hidingSpot = NULL; |
|
m_findTimer.Invalidate(); |
|
m_isAtGoal = false; |
|
|
|
CTFNavArea *myArea = me->GetLastKnownArea(); |
|
|
|
int enemyTeam = GetEnemyTeam( me->GetTeamNumber() ); |
|
|
|
m_incursionThreshold = myArea ? myArea->GetIncursionDistance( enemyTeam ) : FLT_MAX; |
|
if ( m_incursionThreshold < 0.0f ) |
|
{ |
|
m_incursionThreshold = FLT_MAX; |
|
} |
|
|
|
m_talkTimer.Start( RandomFloat( 5.0f, 10.0f ) ); |
|
|
|
return Continue(); |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
ActionResult< CTFBot > CTFBotSpyHide::Update( CTFBot *me, float interval ) |
|
{ |
|
if ( m_initialVictim != NULL && !me->GetVisionInterface()->IsIgnored( m_initialVictim ) ) |
|
{ |
|
return SuspendFor( new CTFBotSpyAttack( m_initialVictim ), "Going after our initial victim" ); |
|
} |
|
|
|
// go after victims we've gotten behind |
|
const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat(); |
|
if ( threat && threat->GetTimeSinceLastKnown() < 3.0f ) |
|
{ |
|
CTFPlayer *victim = ToTFPlayer( threat->GetEntity() ); |
|
if ( victim ) |
|
{ |
|
const float attackRange = 750.0f; |
|
if ( me->IsRangeLessThan( victim, attackRange ) ) |
|
{ |
|
if ( !victim->IsLookingTowards( me ) || victim->IsFiringWeapon() ) |
|
{ |
|
return SuspendFor( new CTFBotSpyAttack( victim ), "Opportunistic attack or self defense!" ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( m_talkTimer.IsElapsed() ) |
|
{ |
|
m_talkTimer.Start( RandomFloat( 5.0f, 10.0f ) ); |
|
me->EmitSound( "Spy.TeaseVictim" ); |
|
} |
|
|
|
if ( m_isAtGoal ) |
|
{ |
|
// Quiet everyone! We are hiding now! |
|
CTFNavArea *myArea = me->GetLastKnownArea(); |
|
if ( myArea ) |
|
{ |
|
int enemyTeam = GetEnemyTeam( me->GetTeamNumber() ); |
|
|
|
m_incursionThreshold = myArea->GetIncursionDistance( enemyTeam ); |
|
} |
|
|
|
return SuspendFor( new CTFBotSpyLurk, "Reached hiding spot - lurking" ); |
|
} |
|
|
|
if ( m_hidingSpot == NULL && m_findTimer.IsElapsed() ) |
|
{ |
|
FindHidingSpot( me ); |
|
} |
|
|
|
// move to our hiding spot |
|
m_path.Update( me ); |
|
|
|
// path following may invalidate our hiding spot (OnMoveToFailure()) |
|
if ( m_hidingSpot == NULL ) |
|
{ |
|
return Continue(); |
|
} |
|
|
|
if ( m_repathTimer.IsElapsed() ) |
|
{ |
|
m_repathTimer.Start( RandomFloat( 0.3f, 0.5f ) ); |
|
|
|
CTFBotPathCost cost( me, SAFEST_ROUTE ); |
|
m_path.Compute( me, m_hidingSpot->GetPosition(), cost ); |
|
} |
|
|
|
return Continue(); |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
ActionResult< CTFBot > CTFBotSpyHide::OnResume( CTFBot *me, Action< CTFBot > *interruptingAction ) |
|
{ |
|
m_hidingSpot = NULL; |
|
m_isAtGoal = false; |
|
m_initialVictim = NULL; |
|
|
|
return Continue(); |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
EventDesiredResult< CTFBot > CTFBotSpyHide::OnMoveToSuccess( CTFBot *me, const Path *path ) |
|
{ |
|
m_isAtGoal = true; |
|
|
|
return TryContinue( RESULT_CRITICAL ); |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
EventDesiredResult< CTFBot > CTFBotSpyHide::OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason ) |
|
{ |
|
m_hidingSpot = NULL; |
|
m_isAtGoal = false; |
|
|
|
return TryContinue( RESULT_IMPORTANT ); |
|
} |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
QueryResultType CTFBotSpyHide::ShouldAttack( const INextBot *me, const CKnownEntity *them ) const |
|
{ |
|
return ANSWER_NO; |
|
} |
|
|
|
struct IncursionEntry_t |
|
{ |
|
int team; |
|
CTFNavArea *area; |
|
}; |
|
|
|
//--------------------------------------------------------------------------------------------- |
|
class SpyHideIncursionDistanceLess |
|
{ |
|
public: |
|
bool Less( const IncursionEntry_t &src1, const IncursionEntry_t &src2, void *pCtx ) |
|
{ |
|
return src1.area->GetIncursionDistance( src1.team ) < src2.area->GetIncursionDistance( src2.team ); |
|
} |
|
}; |
|
|
|
|
|
//--------------------------------------------------------------------------------------------- |
|
bool CTFBotSpyHide::FindHidingSpot( CTFBot *me ) |
|
{ |
|
CTFNavArea *myArea = me->GetLastKnownArea(); |
|
if ( !myArea ) |
|
{ |
|
return false; |
|
} |
|
|
|
m_hidingSpot = NULL; |
|
|
|
// find a spot to hide |
|
const float maxRange = 3500.0f; |
|
CUtlVector< CNavArea * > nearbyVector; |
|
CollectSurroundingAreas( &nearbyVector, me->GetLastKnownArea(), maxRange, |
|
500.0f, 500.0f ); |
|
|
|
CUtlSortVector< IncursionEntry_t, SpyHideIncursionDistanceLess > hidingSpotVector; |
|
|
|
float maxIncursion = m_incursionThreshold + 1000.0f; |
|
|
|
int enemyTeam = GetEnemyTeam( me->GetTeamNumber() ); |
|
|
|
// if we are standing in an area the defenders can't reach, don't limit |
|
if ( myArea->GetIncursionDistance( enemyTeam ) < 0.0f ) |
|
{ |
|
maxIncursion = 9999999; |
|
} |
|
|
|
for( int i=0; i<nearbyVector.Count(); ++i ) |
|
{ |
|
CTFNavArea *area = (CTFNavArea *)nearbyVector[i]; |
|
|
|
if ( area->GetHidingSpots()->Count() <= 0 ) |
|
{ |
|
continue; |
|
} |
|
|
|
if ( area->GetIncursionDistance( enemyTeam ) < 0 ) |
|
{ |
|
continue; |
|
} |
|
|
|
// keep pushing inwards towards defender's spawn |
|
if ( area->GetIncursionDistance( enemyTeam ) > maxIncursion ) |
|
{ |
|
continue; |
|
} |
|
|
|
IncursionEntry_t entry = { enemyTeam, area }; |
|
hidingSpotVector.Insert( entry ); |
|
} |
|
|
|
if ( hidingSpotVector.Count() <= 0 ) |
|
{ |
|
return false; |
|
} |
|
|
|
// penetrate as far as we can |
|
int which = RandomInt( 0, hidingSpotVector.Count()/2 ); |
|
CTFNavArea *whichArea = hidingSpotVector[ which ].area; |
|
|
|
const HidingSpotVector *hidingSpots = whichArea->GetHidingSpots(); |
|
|
|
m_hidingSpot = hidingSpots->Element( RandomInt( 0, hidingSpots->Count()-1 ) ); |
|
|
|
return true; |
|
}
|
|
|