summaryrefslogtreecommitdiff
path: root/game/server/tf/bot/behavior/scenario/payload
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf/bot/behavior/scenario/payload
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf/bot/behavior/scenario/payload')
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.cpp151
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.h38
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.cpp283
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.h43
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.cpp155
-rw-r--r--game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.h33
6 files changed, 703 insertions, 0 deletions
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.cpp b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.cpp
new file mode 100644
index 0000000..3f34071
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.cpp
@@ -0,0 +1,151 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_block.cpp
+// Prevent the other team from moving the cart
+// Michael Booth, April 2010
+
+#include "cbase.h"
+#include "nav_mesh.h"
+#include "tf_player.h"
+#include "tf_gamerules.h"
+#include "team_control_point_master.h"
+#include "team_train_watcher.h"
+#include "bot/tf_bot.h"
+#include "bot/behavior/scenario/payload/tf_bot_payload_block.h"
+#include "bot/behavior/medic/tf_bot_medic_heal.h"
+#include "bot/behavior/engineer/tf_bot_engineer_build.h"
+
+
+extern ConVar tf_bot_path_lookahead_range;
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadBlock::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
+{
+ m_path.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
+ m_path.Invalidate();
+
+ m_giveUpTimer.Start( RandomFloat( 3.0f, 5.0f ) );
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadBlock::Update( CTFBot *me, float interval )
+{
+ const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
+ if ( threat && threat->IsVisibleRecently() )
+ {
+ // prepare to fight
+ me->EquipBestWeaponForThreat( threat );
+ }
+
+ if ( m_giveUpTimer.IsElapsed() )
+ {
+ return Done( "Been blocking long enough" );
+ }
+
+ // move toward the point, periodically repathing to account for changing situation
+ if ( m_repathTimer.IsElapsed() )
+ {
+ VPROF_BUDGET( "CTFBotPayloadBlock::Update( repath )", "NextBot" );
+
+ CTeamTrainWatcher *trainWatcher = TFGameRules()->GetPayloadToBlock( me->GetTeamNumber() );
+ if ( !trainWatcher )
+ {
+ return Done( "Train Watcher is missing" );
+ }
+
+ CBaseEntity *cart = trainWatcher->GetTrainEntity();
+ if ( !cart )
+ {
+ return Done( "Cart is missing" );
+ }
+
+ CTFBotPathCost cost( me, DEFAULT_ROUTE );
+ m_path.Compute( me, cart->WorldSpaceCenter(), cost );
+ m_repathTimer.Start( RandomFloat( 0.2f, 0.4f ) );
+ }
+
+ // move towards next capture point
+ m_path.Update( me );
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadBlock::OnResume( CTFBot *me, Action< CTFBot > *interruptingAction )
+{
+ VPROF_BUDGET( "CTFBotPayloadBlock::OnResume", "NextBot" );
+
+ m_repathTimer.Invalidate();
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnStuck( CTFBot *me )
+{
+ VPROF_BUDGET( "CTFBotPayloadBlock::OnStuck", "NextBot" );
+
+ m_repathTimer.Invalidate();
+ me->GetLocomotionInterface()->ClearStuckStatus();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnMoveToSuccess( CTFBot *me, const Path *path )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason )
+{
+ VPROF_BUDGET( "CTFBotPayloadBlock::OnMoveToFailure", "NextBot" );
+
+ m_repathTimer.Invalidate();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnTerritoryContested( CTFBot *me, int territoryID )
+{
+ return TryToSustain( RESULT_IMPORTANT );
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnTerritoryCaptured( CTFBot *me, int territoryID )
+{
+ return TryToSustain( RESULT_IMPORTANT );
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadBlock::OnTerritoryLost( CTFBot *me, int territoryID )
+{
+ return TryToSustain( RESULT_IMPORTANT );
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadBlock::ShouldRetreat( const INextBot *bot ) const
+{
+ return ANSWER_UNDEFINED;
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadBlock::ShouldHurry( const INextBot *bot ) const
+{
+ // hurry and block the cart - don't retreat, etc
+ return ANSWER_YES;
+}
+
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.h b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.h
new file mode 100644
index 0000000..9b934f2
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_block.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_block.h
+// Prevent the other team from moving the cart
+// Michael Booth, April 2010
+
+#ifndef TF_BOT_PAYLOAD_BLOCK_H
+#define TF_BOT_PAYLOAD_BLOCK_H
+
+#include "Path/NextBotPathFollow.h"
+
+class CTFBotPayloadBlock : public Action< CTFBot >
+{
+public:
+ virtual ActionResult< CTFBot > OnStart( CTFBot *me, Action< CTFBot > *priorAction );
+ virtual ActionResult< CTFBot > Update( CTFBot *me, float interval );
+ virtual ActionResult< CTFBot > OnResume( CTFBot *me, Action< CTFBot > *interruptingAction );
+
+ virtual EventDesiredResult< CTFBot > OnStuck( CTFBot *me );
+ virtual EventDesiredResult< CTFBot > OnMoveToSuccess( CTFBot *me, const Path *path );
+ virtual EventDesiredResult< CTFBot > OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason );
+
+ virtual EventDesiredResult< CTFBot > OnTerritoryContested( CTFBot *me, int territoryID );
+ virtual EventDesiredResult< CTFBot > OnTerritoryCaptured( CTFBot *me, int territoryID );
+ virtual EventDesiredResult< CTFBot > OnTerritoryLost( CTFBot *me, int territoryID );
+
+ virtual QueryResultType ShouldRetreat( const INextBot *me ) const; // is it time to retreat?
+ virtual QueryResultType ShouldHurry( const INextBot *me ) const; // are we in a hurry?
+
+ virtual const char *GetName( void ) const { return "PayloadBlock"; };
+
+private:
+ PathFollower m_path;
+ CountdownTimer m_repathTimer;
+
+ CountdownTimer m_giveUpTimer;
+};
+
+#endif // TF_BOT_PAYLOAD_BLOCK_H
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.cpp b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.cpp
new file mode 100644
index 0000000..a09d186
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.cpp
@@ -0,0 +1,283 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_guard.cpp
+// Guard the payload and keep the attackers from getting near it
+// Michael Booth, April 2010
+
+#include "cbase.h"
+#include "nav_mesh.h"
+#include "tf_player.h"
+#include "tf_gamerules.h"
+#include "team_control_point_master.h"
+#include "team_train_watcher.h"
+#include "trigger_area_capture.h"
+#include "bot/tf_bot.h"
+#include "bot/behavior/scenario/payload/tf_bot_payload_guard.h"
+#include "bot/behavior/scenario/payload/tf_bot_payload_block.h"
+#include "bot/behavior/medic/tf_bot_medic_heal.h"
+#include "bot/behavior/engineer/tf_bot_engineer_build.h"
+#include "bot/behavior/demoman/tf_bot_prepare_stickybomb_trap.h"
+
+
+extern ConVar tf_bot_path_lookahead_range;
+
+ConVar tf_bot_payload_guard_range( "tf_bot_payload_guard_range", "1000", FCVAR_CHEAT );
+ConVar tf_bot_debug_payload_guard_vantage_points( "tf_bot_debug_payload_guard_vantage_points", 0, FCVAR_CHEAT );
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadGuard::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
+{
+ m_path.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
+ m_path.Invalidate();
+
+ m_vantagePoint = me->GetAbsOrigin();
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadGuard::Update( CTFBot *me, float interval )
+{
+ const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
+ if ( threat && threat->IsVisibleRecently() )
+ {
+ // prepare to fight
+ me->EquipBestWeaponForThreat( threat );
+ }
+
+ CTeamTrainWatcher *trainWatcher = TFGameRules()->GetPayloadToBlock( me->GetTeamNumber() );
+ if ( !trainWatcher )
+ {
+ return Continue();
+ }
+
+ CBaseEntity *cart = trainWatcher->GetTrainEntity();
+ if ( !cart )
+ {
+ return Continue();
+ }
+
+ if ( !trainWatcher->IsDisabled() && trainWatcher->GetCapturerCount() > 0 )
+ {
+ // the cart is being pushed ahead - block it
+ if ( !m_moveToBlockTimer.HasStarted() )
+ {
+ m_moveToBlockTimer.Start( RandomFloat( 0.5f, 3.0f ) );
+ }
+ }
+
+ if ( m_moveToBlockTimer.HasStarted() && m_moveToBlockTimer.IsElapsed() )
+ {
+ m_moveToBlockTimer.Invalidate();
+
+ if ( trainWatcher->GetCapturerCount() >= 0 )
+ {
+ // the cart is not yet blocked - move to block it!
+ return SuspendFor( new CTFBotPayloadBlock, "Moving to block the cart's forward motion" );
+ }
+ }
+
+ bool isMovingToVantagePoint = ( me->GetAbsOrigin() - m_vantagePoint ).AsVector2D().IsLengthGreaterThan( 25.0f );
+
+ if ( isMovingToVantagePoint )
+ {
+ // en route, don't change the point
+ m_vantagePointTimer.Start( RandomFloat( 3.0f, 15.0f ) );
+ }
+
+ if ( !me->IsLineOfFireClear( cart ) )
+ {
+ // cart is no longer visible from this area, find another one
+ m_vantagePointTimer.Invalidate();
+ }
+
+ if ( m_vantagePointTimer.IsElapsed() )
+ {
+ // find a new vantage point
+ m_vantagePoint = FindVantagePoint( me, cart );
+ m_repathTimer.Invalidate();
+ isMovingToVantagePoint = true;
+ }
+
+ if ( isMovingToVantagePoint )
+ {
+ // update our path periodically
+ if ( m_repathTimer.IsElapsed() )
+ {
+ CTFBotPathCost cost( me, DEFAULT_ROUTE );
+ m_path.Compute( me, m_vantagePoint, cost );
+ m_repathTimer.Start( RandomFloat( 0.5f, 1.0f ) );
+ }
+
+ // move towards our vantage point
+ m_path.Update( me );
+ }
+ else
+ {
+ // at vantage point
+ if ( CTFBotPrepareStickybombTrap::IsPossible( me ) )
+ {
+ return SuspendFor( new CTFBotPrepareStickybombTrap, "Laying sticky bombs!" );
+ }
+ }
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadGuard::OnResume( CTFBot *me, Action< CTFBot > *interruptingAction )
+{
+ VPROF_BUDGET( "CTFBotPayloadGuard::OnResume", "NextBot" );
+
+ m_vantagePointTimer.Invalidate();
+ m_repathTimer.Invalidate();
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnStuck( CTFBot *me )
+{
+ VPROF_BUDGET( "CTFBotPayloadGuard::OnStuck", "NextBot" );
+
+ m_repathTimer.Invalidate();
+ me->GetLocomotionInterface()->ClearStuckStatus();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnMoveToSuccess( CTFBot *me, const Path *path )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason )
+{
+ VPROF_BUDGET( "CTFBotPayloadGuard::OnMoveToFailure", "NextBot" );
+
+ m_vantagePointTimer.Invalidate();
+ m_repathTimer.Invalidate();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+// Invoked when cart is being pushed
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnTerritoryContested( CTFBot *me, int territoryID )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnTerritoryCaptured( CTFBot *me, int territoryID )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+// Invoked when cart hits a checkpoint
+EventDesiredResult< CTFBot > CTFBotPayloadGuard::OnTerritoryLost( CTFBot *me, int territoryID )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadGuard::ShouldRetreat( const INextBot *bot ) const
+{
+ CTFBot *me = ToTFBot( bot->GetEntity() );
+
+ CTeamTrainWatcher *trainWatcher = TFGameRules()->GetPayloadToBlock( me->GetTeamNumber() );
+ if ( trainWatcher && trainWatcher->IsTrainNearCheckpoint() )
+ {
+ // don't retreat if the cart is almost at the next checkpoint
+ return ANSWER_NO;
+ }
+
+ return ANSWER_UNDEFINED;
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadGuard::ShouldHurry( const INextBot *bot ) const
+{
+ return ANSWER_UNDEFINED;
+}
+
+
+//---------------------------------------------------------------------------------------------
+class CCollectPayloadGuardVantagePoints : public ISearchSurroundingAreasFunctor
+{
+public:
+ CCollectPayloadGuardVantagePoints( CTFBot *me, CBaseEntity *cart )
+ {
+ m_me = me;
+ m_cart = cart;
+ }
+
+ virtual bool operator() ( CNavArea *baseArea, CNavArea *priorArea, float travelDistanceSoFar )
+ {
+ CTFNavArea *area = (CTFNavArea *)baseArea;
+
+ // TODO: only use areas that are at/farther along than the payload
+
+ trace_t trace;
+ NextBotTraceFilterIgnoreActors filter( NULL, COLLISION_GROUP_NONE );
+
+ const int tryCount = 3;
+
+ for( int i=0; i<tryCount; ++i )
+ {
+ Vector spot = area->GetRandomPoint();
+ Vector eyeSpot = Vector( spot.x, spot.y, spot.z + HumanEyeHeight );
+
+ UTIL_TraceLine( eyeSpot, m_cart->WorldSpaceCenter(), MASK_SOLID_BRUSHONLY, &filter, &trace );
+
+ if ( !trace.DidHit() || trace.m_pEnt == m_cart )
+ {
+ m_vantagePointVector.AddToTail( spot );
+
+ if ( tf_bot_debug_payload_guard_vantage_points.GetBool() )
+ {
+ NDebugOverlay::Cross3D( spot, 5.0f, 255, 0, 255, true, 120.0f );
+ }
+ }
+ }
+
+ return true;
+ }
+
+ CTFBot *m_me;
+ CBaseEntity *m_cart;
+ CUtlVector< Vector > m_vantagePointVector;
+};
+
+
+//---------------------------------------------------------------------------------------------
+//
+// Find a tactically advantageous area where we can see the payload
+//
+Vector CTFBotPayloadGuard::FindVantagePoint( CTFBot *me, CBaseEntity *cart )
+{
+ CTFNavArea *cartArea = (CTFNavArea *)TheNavMesh->GetNearestNavArea( cart );
+
+ CCollectPayloadGuardVantagePoints collect( me, cart );
+ SearchSurroundingAreas( cartArea, collect, tf_bot_payload_guard_range.GetFloat() );
+
+ if ( collect.m_vantagePointVector.Count() == 0 )
+ return cart->WorldSpaceCenter();
+
+ int which = RandomInt( 0, collect.m_vantagePointVector.Count()-1 );
+ return collect.m_vantagePointVector[ which ];
+}
+
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.h b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.h
new file mode 100644
index 0000000..2d1b03d
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_guard.h
@@ -0,0 +1,43 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_guard.h
+// Guard the payload and keep the attackers from getting near it
+// Michael Booth, April 2010
+
+#ifndef TF_BOT_PAYLOAD_GUARD_H
+#define TF_BOT_PAYLOAD_GUARD_H
+
+#include "Path/NextBotPathFollow.h"
+
+class CTFBotPayloadGuard : public Action< CTFBot >
+{
+public:
+ virtual ActionResult< CTFBot > OnStart( CTFBot *me, Action< CTFBot > *priorAction );
+ virtual ActionResult< CTFBot > Update( CTFBot *me, float interval );
+ virtual ActionResult< CTFBot > OnResume( CTFBot *me, Action< CTFBot > *interruptingAction );
+
+ virtual EventDesiredResult< CTFBot > OnStuck( CTFBot *me );
+ virtual EventDesiredResult< CTFBot > OnMoveToSuccess( CTFBot *me, const Path *path );
+ virtual EventDesiredResult< CTFBot > OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason );
+
+ virtual EventDesiredResult< CTFBot > OnTerritoryContested( CTFBot *me, int territoryID );
+ virtual EventDesiredResult< CTFBot > OnTerritoryCaptured( CTFBot *me, int territoryID );
+ virtual EventDesiredResult< CTFBot > OnTerritoryLost( CTFBot *me, int territoryID );
+
+ virtual QueryResultType ShouldRetreat( const INextBot *me ) const; // is it time to retreat?
+ virtual QueryResultType ShouldHurry( const INextBot *me ) const; // are we in a hurry?
+
+ virtual const char *GetName( void ) const { return "PayloadGuard"; };
+
+private:
+ PathFollower m_path;
+ CountdownTimer m_repathTimer;
+
+ Vector m_vantagePoint;
+ CountdownTimer m_vantagePointTimer;
+ Vector FindVantagePoint( CTFBot *me, CBaseEntity *cart );
+
+ CountdownTimer m_moveToBlockTimer;
+
+};
+
+#endif // TF_BOT_PAYLOAD_GUARD_H
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.cpp b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.cpp
new file mode 100644
index 0000000..79fe667
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.cpp
@@ -0,0 +1,155 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_push.cpp
+// Push the cartTrigger to the goal
+// Michael Booth, April 2010
+
+#include "cbase.h"
+#include "nav_mesh.h"
+#include "tf_player.h"
+#include "tf_gamerules.h"
+#include "team_control_point_master.h"
+#include "team_train_watcher.h"
+#include "trigger_area_capture.h"
+#include "bot/tf_bot.h"
+#include "bot/behavior/scenario/payload/tf_bot_payload_push.h"
+#include "bot/behavior/medic/tf_bot_medic_heal.h"
+#include "bot/behavior/engineer/tf_bot_engineer_build.h"
+
+
+extern ConVar tf_bot_path_lookahead_range;
+ConVar tf_bot_cart_push_radius( "tf_bot_cart_push_radius", "60", FCVAR_CHEAT );
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadPush::OnStart( CTFBot *me, Action< CTFBot > *priorAction )
+{
+ m_path.SetMinLookAheadDistance( me->GetDesiredPathLookAheadRange() );
+ m_path.Invalidate();
+
+ m_hideAngle = 180.0f;
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadPush::Update( CTFBot *me, float interval )
+{
+ const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
+ if ( threat && threat->IsVisibleRecently() )
+ {
+ // prepare to fight
+ me->EquipBestWeaponForThreat( threat );
+ }
+
+ if ( TFGameRules()->InSetup() )
+ {
+ // wait until the gates open, then path
+ m_path.Invalidate();
+ m_repathTimer.Start( RandomFloat( 1.0f, 2.0f ) );
+
+ return Continue();
+ }
+
+ CTeamTrainWatcher *trainWatcher = TFGameRules()->GetPayloadToPush( me->GetTeamNumber() );
+ if ( !trainWatcher )
+ {
+ return Continue();
+ }
+
+ CBaseEntity *cart = trainWatcher->GetTrainEntity();
+ if ( !cart )
+ {
+ return Continue();
+ }
+
+
+ // move toward the point, periodically repathing to account for changing situation
+ if ( m_repathTimer.IsElapsed() )
+ {
+ VPROF_BUDGET( "CTFBotPayloadPush::Update( repath )", "NextBot" );
+
+ Vector cartForward;
+ cart->GetVectors( &cartForward, NULL, NULL );
+
+ // default push position is behind cart
+ Vector pushPos = cart->WorldSpaceCenter() - cartForward * tf_bot_cart_push_radius.GetFloat();
+
+ // try to hide from enemies on other side of cart
+ const CKnownEntity *threat = me->GetVisionInterface()->GetPrimaryKnownThreat();
+ if ( threat )
+ {
+ Vector enemyToCart = cart->WorldSpaceCenter() - threat->GetLastKnownPosition();
+ enemyToCart.z = 0.0f;
+ enemyToCart.NormalizeInPlace();
+
+ pushPos = cart->WorldSpaceCenter() + tf_bot_cart_push_radius.GetFloat() * enemyToCart;
+ }
+
+ CTFBotPathCost cost( me, DEFAULT_ROUTE );
+ m_path.Compute( me, pushPos, cost );
+
+ m_repathTimer.Start( RandomFloat( 0.2f, 0.4f ) );
+ }
+
+ // push the cartTrigger
+ m_path.Update( me );
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+ActionResult< CTFBot > CTFBotPayloadPush::OnResume( CTFBot *me, Action< CTFBot > *interruptingAction )
+{
+ VPROF_BUDGET( "CTFBotPayloadPush::OnResume", "NextBot" );
+
+ m_repathTimer.Invalidate();
+
+ return Continue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadPush::OnStuck( CTFBot *me )
+{
+ VPROF_BUDGET( "CTFBotPayloadPush::OnStuck", "NextBot" );
+
+ m_repathTimer.Invalidate();
+ me->GetLocomotionInterface()->ClearStuckStatus();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadPush::OnMoveToSuccess( CTFBot *me, const Path *path )
+{
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+EventDesiredResult< CTFBot > CTFBotPayloadPush::OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason )
+{
+ VPROF_BUDGET( "CTFBotPayloadPush::OnMoveToFailure", "NextBot" );
+
+ m_repathTimer.Invalidate();
+
+ return TryContinue();
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadPush::ShouldRetreat( const INextBot *bot ) const
+{
+ return ANSWER_UNDEFINED;
+}
+
+
+//---------------------------------------------------------------------------------------------
+QueryResultType CTFBotPayloadPush::ShouldHurry( const INextBot *bot ) const
+{
+ return ANSWER_UNDEFINED;
+}
+
diff --git a/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.h b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.h
new file mode 100644
index 0000000..4499c25
--- /dev/null
+++ b/game/server/tf/bot/behavior/scenario/payload/tf_bot_payload_push.h
@@ -0,0 +1,33 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_payload_push.h
+// Push the cart to the goal
+// Michael Booth, April 2010
+
+#ifndef TF_BOT_PAYLOAD_PUSH_H
+#define TF_BOT_PAYLOAD_PUSH_H
+
+#include "Path/NextBotPathFollow.h"
+
+class CTFBotPayloadPush : public Action< CTFBot >
+{
+public:
+ virtual ActionResult< CTFBot > OnStart( CTFBot *me, Action< CTFBot > *priorAction );
+ virtual ActionResult< CTFBot > Update( CTFBot *me, float interval );
+ virtual ActionResult< CTFBot > OnResume( CTFBot *me, Action< CTFBot > *interruptingAction );
+
+ virtual EventDesiredResult< CTFBot > OnStuck( CTFBot *me );
+ virtual EventDesiredResult< CTFBot > OnMoveToSuccess( CTFBot *me, const Path *path );
+ virtual EventDesiredResult< CTFBot > OnMoveToFailure( CTFBot *me, const Path *path, MoveToFailureType reason );
+
+ virtual QueryResultType ShouldRetreat( const INextBot *me ) const; // is it time to retreat?
+ virtual QueryResultType ShouldHurry( const INextBot *me ) const; // are we in a hurry?
+
+ virtual const char *GetName( void ) const { return "PayloadPush"; };
+
+private:
+ PathFollower m_path;
+ CountdownTimer m_repathTimer;
+ float m_hideAngle;
+};
+
+#endif // TF_BOT_PAYLOAD_PUSH_H