summaryrefslogtreecommitdiff
path: root/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp')
-rw-r--r--game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp236
1 files changed, 236 insertions, 0 deletions
diff --git a/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp b/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp
new file mode 100644
index 0000000..2a35b31
--- /dev/null
+++ b/game/server/tf/bot/behavior/spy/tf_bot_spy_hide.cpp
@@ -0,0 +1,236 @@
+//========= 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;
+}