summaryrefslogtreecommitdiff
path: root/game/server/cstrike/bot/states/cs_bot_move_to.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/cstrike/bot/states/cs_bot_move_to.cpp')
-rw-r--r--game/server/cstrike/bot/states/cs_bot_move_to.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/game/server/cstrike/bot/states/cs_bot_move_to.cpp b/game/server/cstrike/bot/states/cs_bot_move_to.cpp
new file mode 100644
index 0000000..eafba40
--- /dev/null
+++ b/game/server/cstrike/bot/states/cs_bot_move_to.cpp
@@ -0,0 +1,366 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+// Author: Michael S. Booth ([email protected]), 2003
+
+#include "cbase.h"
+#include "cs_simple_hostage.h"
+#include "cs_bot.h"
+#include "cs_gamerules.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Move to a potentially far away position.
+ */
+void MoveToState::OnEnter( CCSBot *me )
+{
+ if (me->IsUsingKnife() && me->IsWellPastSafe() && !me->IsHurrying())
+ {
+ me->Walk();
+ }
+ else
+ {
+ me->Run();
+ }
+
+
+ // if we need to find the bomb, get there as quick as we can
+ RouteType route;
+ switch (me->GetTask())
+ {
+ case CCSBot::FIND_TICKING_BOMB:
+ case CCSBot::DEFUSE_BOMB:
+ case CCSBot::MOVE_TO_LAST_KNOWN_ENEMY_POSITION:
+ route = FASTEST_ROUTE;
+ break;
+
+ default:
+ route = SAFEST_ROUTE;
+ break;
+ }
+
+ // build path to, or nearly to, goal position
+ me->ComputePath( m_goalPosition, route );
+
+ m_radioedPlan = false;
+ m_askedForCover = false;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Move to a potentially far away position.
+ */
+void MoveToState::OnUpdate( CCSBot *me )
+{
+ Vector myOrigin = GetCentroid( me );
+
+ // assume that we are paying attention and close enough to know our enemy died
+ if (me->GetTask() == CCSBot::MOVE_TO_LAST_KNOWN_ENEMY_POSITION)
+ {
+ /// @todo Account for reaction time so we take some time to realized the enemy is dead
+ CBasePlayer *victim = static_cast<CBasePlayer *>( me->GetTaskEntity() );
+ if (victim == NULL || !victim->IsAlive())
+ {
+ me->PrintIfWatched( "The enemy I was chasing was killed - giving up.\n" );
+ me->Idle();
+ return;
+ }
+ }
+
+ // look around
+ me->UpdateLookAround();
+
+ //
+ // Scenario logic
+ //
+ switch (TheCSBots()->GetScenario())
+ {
+ case CCSBotManager::SCENARIO_DEFUSE_BOMB:
+ {
+ // if the bomb has been planted, find it
+ // NOTE: This task is used by both CT and T's to find the bomb
+ if (me->GetTask() == CCSBot::FIND_TICKING_BOMB)
+ {
+ if (!me->GetGameState()->IsBombPlanted())
+ {
+ // the bomb is not planted - give up this task
+ me->Idle();
+ return;
+ }
+
+ if (me->GetGameState()->GetPlantedBombsite() != CSGameState::UNKNOWN)
+ {
+ // we know where the bomb is planted, stop searching
+ me->Idle();
+ return;
+ }
+
+ // check off bombsites that we explore or happen to stumble into
+ for( int z=0; z<TheCSBots()->GetZoneCount(); ++z )
+ {
+ // don't re-check zones
+ if (me->GetGameState()->IsBombsiteClear( z ))
+ continue;
+
+ if (TheCSBots()->GetZone(z)->m_extent.Contains( myOrigin ))
+ {
+ // note this bombsite is clear
+ me->GetGameState()->ClearBombsite( z );
+
+ if (me->GetTeamNumber() == TEAM_CT)
+ {
+ // tell teammates this bombsite is clear
+ me->GetChatter()->BombsiteClear( z );
+ }
+
+ // find another zone to check
+ me->Idle();
+
+ return;
+ }
+ }
+
+ // move to a bombsite
+ break;
+ }
+
+
+ if (me->GetTeamNumber() == TEAM_CT)
+ {
+ if (me->GetGameState()->IsBombPlanted())
+ {
+ switch( me->GetTask() )
+ {
+ case CCSBot::DEFUSE_BOMB:
+ {
+ // if we are near the bombsite and there is time left, sneak in (unless all enemies are dead)
+ if (me->GetEnemiesRemaining())
+ {
+ const float plentyOfTime = 15.0f;
+ if (TheCSBots()->GetBombTimeLeft() > plentyOfTime)
+ {
+ // get distance remaining on our path until we reach the bombsite
+ float range = me->GetPathDistanceRemaining();
+
+ const float closeRange = 1500.0f;
+ if (range < closeRange)
+ {
+ me->Walk();
+ }
+ else
+ {
+ me->Run();
+ }
+ }
+ }
+ else
+ {
+ // everyone is dead - run!
+ me->Run();
+ }
+
+ // if we are trying to defuse the bomb, and someone has started defusing, guard them instead
+ if (me->CanSeePlantedBomb() && TheCSBots()->GetBombDefuser())
+ {
+ me->GetChatter()->Say( "CoveringFriend" );
+ me->Idle();
+ return;
+ }
+
+
+ // if we are near the bomb, defuse it (if we are reloading, don't try to defuse until we finish)
+ const Vector *bombPos = me->GetGameState()->GetBombPosition();
+ if (bombPos && !me->IsReloading())
+ {
+ const float defuseRange = 100.0f; // 50
+ if ((*bombPos - me->EyePosition()).IsLengthLessThan( defuseRange ))
+ {
+ // make sure we can see the bomb
+ if (me->IsVisible( *bombPos ))
+ {
+ me->DefuseBomb();
+ return;
+ }
+ }
+ }
+
+ break;
+ }
+
+ default:
+ {
+ // we need to find the bomb
+ me->Idle();
+ return;
+ }
+ }
+ }
+ }
+ else // TERRORIST
+ {
+ if (me->GetTask() == CCSBot::PLANT_BOMB )
+ {
+ if ( me->GetFriendsRemaining() )
+ {
+ // if we are about to plant, radio for cover
+ if (!m_askedForCover)
+ {
+ const float nearPlantSite = 50.0f;
+ if (me->IsAtBombsite() && me->GetPathDistanceRemaining() < nearPlantSite)
+ {
+ // radio to the team
+ me->GetChatter()->PlantingTheBomb( me->GetPlace() );
+ m_askedForCover = true;
+ }
+
+ // after we have started to move to the bombsite, tell team we're going to plant, and where
+ // don't do this if we have already radioed that we are starting to plant
+ if (!m_radioedPlan)
+ {
+ const float radioTime = 2.0f;
+ if (gpGlobals->curtime - me->GetStateTimestamp() > radioTime)
+ {
+ // radio to the team if we're more than 10 seconds (2400 units) out
+ const float nearPlantSite = 2400.0f;
+ if ( me->GetPathDistanceRemaining() >= nearPlantSite )
+ {
+ me->GetChatter()->GoingToPlantTheBomb( TheNavMesh->GetPlace( m_goalPosition ) );
+ }
+ m_radioedPlan = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ //--------------------------------------------------------------------------------------------------
+ case CCSBotManager::SCENARIO_RESCUE_HOSTAGES:
+ {
+ if (me->GetTask() == CCSBot::COLLECT_HOSTAGES)
+ {
+ //
+ // Since CT's have a radar, they can directly look at the actual hostage state
+ //
+
+ // check if someone else collected our hostage, or the hostage died or was rescued
+ CHostage *hostage = static_cast<CHostage *>( me->GetGoalEntity() );
+ if (hostage == NULL || !hostage->IsValid() || hostage->IsFollowingSomeone())
+ {
+ me->Idle();
+ return;
+ }
+
+ Vector hostageOrigin = GetCentroid( hostage );
+
+ // if our hostage has moved, repath
+ const float repathToleranceSq = 75.0f * 75.0f;
+ float error = (hostageOrigin - m_goalPosition).LengthSqr();
+ if (error > repathToleranceSq)
+ {
+ m_goalPosition = hostageOrigin;
+ me->ComputePath( m_goalPosition, SAFEST_ROUTE );
+ }
+
+ /// @todo Generalize ladder priorities over other tasks
+ if (!me->IsUsingLadder())
+ {
+ Vector pos = hostage->EyePosition();
+ Vector to = pos - me->EyePosition(); // "Use" checks from eye position, so we should too
+
+ // look at the hostage as we approach
+ const float watchHostageRange = 100.0f;
+ if (to.IsLengthLessThan( watchHostageRange ))
+ {
+ me->SetLookAt( "Hostage", pos, PRIORITY_LOW, 0.5f );
+
+ // randomly move just a bit to avoid infinite use loops from bad hostage placement
+ NavRelativeDirType dir = (NavRelativeDirType)RandomInt( 0, 3 );
+ switch( dir )
+ {
+ case LEFT: me->StrafeLeft(); break;
+ case RIGHT: me->StrafeRight(); break;
+ case FORWARD: me->MoveForward(); break;
+ case BACKWARD: me->MoveBackward(); break;
+ }
+
+ // check if we are close enough to the hostage to talk to him
+ const float useRange = PLAYER_USE_RADIUS - 10.0f; // shave off a fudge factor to make sure we're within range
+ if (to.IsLengthLessThan( useRange ))
+ {
+ me->UseEntity( me->GetGoalEntity() );
+ return;
+ }
+ }
+ }
+ }
+ else if (me->GetTask() == CCSBot::RESCUE_HOSTAGES)
+ {
+ // periodically check if we lost all our hostages
+ if (me->GetHostageEscortCount() == 0)
+ {
+ // lost our hostages - go get 'em
+ me->Idle();
+ return;
+ }
+ }
+
+ break;
+ }
+ }
+
+
+ if (me->UpdatePathMovement() != CCSBot::PROGRESSING)
+ {
+ // reached destination
+ switch( me->GetTask() )
+ {
+ case CCSBot::PLANT_BOMB:
+ // if we are at bombsite with the bomb, plant it
+ if (me->IsAtBombsite() && me->HasC4())
+ {
+ me->PlantBomb();
+ return;
+ }
+ break;
+
+ case CCSBot::MOVE_TO_LAST_KNOWN_ENEMY_POSITION:
+ {
+ CBasePlayer *victim = static_cast<CBasePlayer *>( me->GetTaskEntity() );
+ if (victim && victim->IsAlive())
+ {
+ // if we got here and haven't re-acquired the enemy, we lost him
+ BotStatement *say = new BotStatement( me->GetChatter(), REPORT_ENEMY_LOST, 8.0f );
+
+ say->AppendPhrase( TheBotPhrases->GetPhrase( "LostEnemy" ) );
+ say->SetStartTime( gpGlobals->curtime + RandomFloat( 3.0f, 5.0f ) );
+
+ me->GetChatter()->AddStatement( say );
+ }
+ break;
+ }
+ }
+
+ // default behavior when destination is reached
+ me->Idle();
+ return;
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void MoveToState::OnExit( CCSBot *me )
+{
+ // reset to run in case we were walking near our goal position
+ me->Run();
+ me->SetDisposition( CCSBot::ENGAGE_AND_INVESTIGATE );
+ //me->StopAiming();
+}