summaryrefslogtreecommitdiff
path: root/game/shared/cstrike/bot/bot_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/cstrike/bot/bot_manager.cpp')
-rw-r--r--game/shared/cstrike/bot/bot_manager.cpp402
1 files changed, 402 insertions, 0 deletions
diff --git a/game/shared/cstrike/bot/bot_manager.cpp b/game/shared/cstrike/bot/bot_manager.cpp
new file mode 100644
index 0000000..ce15823
--- /dev/null
+++ b/game/shared/cstrike/bot/bot_manager.cpp
@@ -0,0 +1,402 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+// Author: Michael S. Booth ([email protected]), 2003
+
+#include "cbase.h"
+
+#include "bot.h"
+#include "bot_manager.h"
+#include "nav_area.h"
+#include "bot_util.h"
+#include "basegrenade_shared.h"
+
+#include "cs_bot.h"
+
+#include "tier0/vprof.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+float g_BotUpkeepInterval = 0.0f;
+float g_BotUpdateInterval = 0.0f;
+
+
+//--------------------------------------------------------------------------------------------------------------
+CBotManager::CBotManager()
+{
+ InitBotTrig();
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+CBotManager::~CBotManager()
+{
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Invoked when the round is restarting
+ */
+void CBotManager::RestartRound( void )
+{
+ DestroyAllGrenades();
+ ClearDebugMessages();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Invoked at the start of each frame
+ */
+void CBotManager::StartFrame( void )
+{
+ VPROF_BUDGET( "CBotManager::StartFrame", VPROF_BUDGETGROUP_NPCS );
+
+ ValidateActiveGrenades();
+
+ // debug smoke grenade visualization
+ if (cv_bot_debug.GetInt() == 5)
+ {
+ Vector edge, lastEdge;
+
+ FOR_EACH_LL( m_activeGrenadeList, it )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+
+ const Vector &pos = ag->GetDetonationPosition();
+
+ UTIL_DrawBeamPoints( pos, pos + Vector( 0, 0, 50 ), 1, 255, 100, 0 );
+
+ lastEdge = Vector( ag->GetRadius() + pos.x, pos.y, pos.z );
+ float angle;
+ for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
+ {
+ edge.x = ag->GetRadius() * BotCOS( angle ) + pos.x;
+ edge.y = pos.y;
+ edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
+
+ UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
+
+ lastEdge = edge;
+ }
+
+ lastEdge = Vector( pos.x, ag->GetRadius() + pos.y, pos.z );
+ for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
+ {
+ edge.x = pos.x;
+ edge.y = ag->GetRadius() * BotCOS( angle ) + pos.y;
+ edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
+
+ UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
+
+ lastEdge = edge;
+ }
+ }
+ }
+
+ // set frame duration
+ g_BotUpkeepInterval = m_frameTimer.GetElapsedTime();
+ m_frameTimer.Start();
+
+ g_BotUpdateInterval = (g_BotUpdateSkipCount+1) * g_BotUpkeepInterval;
+
+ //
+ // Process each active bot
+ //
+ for( int i = 1; i <= gpGlobals->maxClients; ++i )
+ {
+ CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
+
+ if (!player)
+ continue;
+
+ // Hack for now so the temp bot code works. The temp bots are very useful for debugging
+ // because they can be setup to mimic the player's usercmds.
+ if (player->IsBot() && IsEntityValid( player ) )
+ {
+ // EVIL: Messes up vtables
+ //CBot< CBasePlayer > *bot = static_cast< CBot< CBasePlayer > * >( player );
+ CCSBot *bot = dynamic_cast< CCSBot * >( player );
+
+ if ( bot )
+ {
+ bot->Upkeep();
+
+ if (((gpGlobals->tickcount + bot->entindex()) % g_BotUpdateSkipCount) == 0)
+ {
+ bot->ResetCommand();
+ bot->Update();
+ }
+
+ bot->UpdatePlayer();
+ }
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Add an active grenade to the bot's awareness
+ */
+void CBotManager::AddGrenade( CBaseGrenade *grenade )
+{
+ ActiveGrenade *ag = new ActiveGrenade( grenade );
+ m_activeGrenadeList.AddToTail( ag );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * The grenade entity in the world is going away
+ */
+void CBotManager::RemoveGrenade( CBaseGrenade *grenade )
+{
+ FOR_EACH_LL( m_activeGrenadeList, it )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+
+ if (ag->IsEntity( grenade ))
+ {
+ ag->OnEntityGone();
+ return;
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * The grenade entity has changed its radius
+ */
+void CBotManager::SetGrenadeRadius( CBaseGrenade *grenade, float radius )
+{
+ FOR_EACH_LL( m_activeGrenadeList, it )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+
+ if (ag->IsEntity( grenade ))
+ {
+ ag->SetRadius( radius );
+ return;
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Destroy any invalid active grenades
+ */
+void CBotManager::ValidateActiveGrenades( void )
+{
+ int it = m_activeGrenadeList.Head();
+
+ while( it != m_activeGrenadeList.InvalidIndex() )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+
+ int current = it;
+ it = m_activeGrenadeList.Next( it );
+
+ // lazy validation
+ if (!ag->IsValid())
+ {
+ m_activeGrenadeList.Remove( current );
+ delete ag;
+ continue;
+ }
+ else
+ {
+ ag->Update();
+ }
+ }
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CBotManager::DestroyAllGrenades( void )
+{
+ m_activeGrenadeList.PurgeAndDeleteElements();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Return true if position is inside a smoke cloud
+ */
+bool CBotManager::IsInsideSmokeCloud( const Vector *pos )
+{
+ int it = m_activeGrenadeList.Head();
+
+ while( it != m_activeGrenadeList.InvalidIndex() )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+
+ int current = it;
+ it = m_activeGrenadeList.Next( it );
+
+ // lazy validation
+ if (!ag->IsValid())
+ {
+ m_activeGrenadeList.Remove( current );
+ delete ag;
+ continue;
+ }
+
+ if (ag->IsSmoke())
+ {
+ const Vector &smokeOrigin = ag->GetDetonationPosition();
+
+ if ((smokeOrigin - *pos).IsLengthLessThan( ag->GetRadius() ))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Return true if line intersects smoke volume
+ * Determine the length of the line of sight covered by each smoke cloud,
+ * and sum them (overlap is additive for obstruction).
+ * If the overlap exceeds the threshold, the bot can't see through.
+ */
+bool CBotManager::IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat )
+{
+ VPROF_BUDGET( "CBotManager::IsLineBlockedBySmoke", VPROF_BUDGETGROUP_NPCS );
+
+ float totalSmokedLength = 0.0f; // distance along line of sight covered by smoke
+
+ // compute unit vector and length of line of sight segment
+ Vector sightDir = to - from;
+ float sightLength = sightDir.NormalizeInPlace();
+
+ FOR_EACH_LL( m_activeGrenadeList, it )
+ {
+ ActiveGrenade *ag = m_activeGrenadeList[ it ];
+ const float smokeRadiusSq = ag->GetRadius() * ag->GetRadius() * grenadeBloat * grenadeBloat;
+
+ if (ag->IsSmoke())
+ {
+ const Vector &smokeOrigin = ag->GetDetonationPosition();
+
+ Vector toGrenade = smokeOrigin - from;
+
+ float alongDist = DotProduct( toGrenade, sightDir );
+
+ // compute closest point to grenade along line of sight ray
+ Vector close;
+
+ // constrain closest point to line segment
+ if (alongDist < 0.0f)
+ close = from;
+ else if (alongDist >= sightLength)
+ close = to;
+ else
+ close = from + sightDir * alongDist;
+
+ // if closest point is within smoke radius, the line overlaps the smoke cloud
+ Vector toClose = close - smokeOrigin;
+ float lengthSq = toClose.LengthSqr();
+
+ if (lengthSq < smokeRadiusSq)
+ {
+ // some portion of the ray intersects the cloud
+
+ float fromSq = toGrenade.LengthSqr();
+ float toSq = (smokeOrigin - to).LengthSqr();
+
+ if (fromSq < smokeRadiusSq)
+ {
+ if (toSq < smokeRadiusSq)
+ {
+ // both 'from' and 'to' lie within the cloud
+ // entire length is smoked
+ totalSmokedLength += (to - from).Length();
+ }
+ else
+ {
+ // 'from' is inside the cloud, 'to' is outside
+ // compute half of total smoked length as if ray crosses entire cloud chord
+ float halfSmokedLength = (float)sqrt( smokeRadiusSq - lengthSq );
+
+ if (alongDist > 0.0f)
+ {
+ // ray goes thru 'close'
+ totalSmokedLength += halfSmokedLength + (close - from).Length();
+ }
+ else
+ {
+ // ray starts after 'close'
+ totalSmokedLength += halfSmokedLength - (close - from).Length();
+ }
+
+ }
+ }
+ else if (toSq < smokeRadiusSq)
+ {
+ // 'from' is outside the cloud, 'to' is inside
+ // compute half of total smoked length as if ray crosses entire cloud chord
+ float halfSmokedLength = (float)sqrt( smokeRadiusSq - lengthSq );
+
+ Vector v = to - smokeOrigin;
+ if (DotProduct( v, sightDir ) > 0.0f)
+ {
+ // ray goes thru 'close'
+ totalSmokedLength += halfSmokedLength + (close - to).Length();
+ }
+ else
+ {
+ // ray ends before 'close'
+ totalSmokedLength += halfSmokedLength - (close - to).Length();
+ }
+ }
+ else
+ {
+ // 'from' and 'to' lie outside of the cloud - the line of sight completely crosses it
+ // determine the length of the chord that crosses the cloud
+ float smokedLength = 2.0f * (float)sqrt( smokeRadiusSq - lengthSq );
+
+ totalSmokedLength += smokedLength;
+ }
+ }
+ }
+ }
+
+ // define how much smoke a bot can see thru
+ const float maxSmokedLength = 0.7f * SmokeGrenadeRadius;
+
+ // return true if the total length of smoke-covered line-of-sight is too much
+ return (totalSmokedLength > maxSmokedLength);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+void CBotManager::ClearDebugMessages( void )
+{
+ m_debugMessageCount = 0;
+ m_currentDebugMessage = -1;
+}
+
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Add a new debug message to the message history
+ */
+void CBotManager::AddDebugMessage( const char *msg )
+{
+ if (++m_currentDebugMessage >= MAX_DBG_MSGS)
+ {
+ m_currentDebugMessage = 0;
+ }
+
+ if (m_debugMessageCount < MAX_DBG_MSGS)
+ {
+ ++m_debugMessageCount;
+ }
+
+ Q_strncpy( m_debugMessage[ m_currentDebugMessage ].m_string, msg, MAX_DBG_MSG_SIZE );
+ m_debugMessage[ m_currentDebugMessage ].m_age.Start();
+}