Counter Strike : Global Offensive Source Code
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.

352 lines
8.8 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. // Author: Michael S. Booth ([email protected]), 2003
  8. #include "cbase.h"
  9. #include "bot.h"
  10. #include "bot_manager.h"
  11. #include "nav_area.h"
  12. #include "bot_util.h"
  13. #include "basegrenade_shared.h"
  14. #include "cs_bot.h"
  15. #include "tier0/vprof.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. float g_BotUpkeepInterval = 0.0f;
  19. float g_BotUpdateInterval = 0.0f;
  20. //--------------------------------------------------------------------------------------------------------------
  21. CBotManager::CBotManager()
  22. {
  23. InitBotTrig();
  24. }
  25. //--------------------------------------------------------------------------------------------------------------
  26. CBotManager::~CBotManager()
  27. {
  28. }
  29. //--------------------------------------------------------------------------------------------------------------
  30. /**
  31. * Invoked when the round is restarting
  32. */
  33. void CBotManager::RestartRound( void )
  34. {
  35. DestroyAllGrenades();
  36. ClearDebugMessages();
  37. }
  38. //--------------------------------------------------------------------------------------------------------------
  39. /**
  40. * Invoked at the start of each frame
  41. */
  42. void CBotManager::StartFrame( void )
  43. {
  44. VPROF_BUDGET( "CBotManager::StartFrame", VPROF_BUDGETGROUP_NPCS );
  45. ValidateActiveGrenades();
  46. // debug smoke grenade visualization
  47. if (cv_bot_debug.GetInt() == 5)
  48. {
  49. Vector edge, lastEdge;
  50. FOR_EACH_LL( m_activeGrenadeList, it )
  51. {
  52. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  53. const Vector &pos = ag->GetDetonationPosition();
  54. UTIL_DrawBeamPoints( pos, pos + Vector( 0, 0, 50 ), 1, 255, 100, 0 );
  55. lastEdge = Vector( ag->GetRadius() + pos.x, pos.y, pos.z );
  56. float angle;
  57. for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
  58. {
  59. edge.x = ag->GetRadius() * BotCOS( angle ) + pos.x;
  60. edge.y = pos.y;
  61. edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
  62. UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
  63. lastEdge = edge;
  64. }
  65. lastEdge = Vector( pos.x, ag->GetRadius() + pos.y, pos.z );
  66. for( angle=0.0f; angle <= 180.0f; angle += 22.5f )
  67. {
  68. edge.x = pos.x;
  69. edge.y = ag->GetRadius() * BotCOS( angle ) + pos.y;
  70. edge.z = ag->GetRadius() * BotSIN( angle ) + pos.z;
  71. UTIL_DrawBeamPoints( edge, lastEdge, 1, 255, 50, 0 );
  72. lastEdge = edge;
  73. }
  74. }
  75. }
  76. // set frame duration
  77. g_BotUpkeepInterval = m_frameTimer.GetElapsedTime();
  78. m_frameTimer.Start();
  79. g_BotUpdateInterval = (g_BotUpdateSkipCount+1) * g_BotUpkeepInterval;
  80. //
  81. // Process each active bot
  82. //
  83. for( int i = 1; i <= gpGlobals->maxClients; ++i )
  84. {
  85. CBasePlayer *player = static_cast<CBasePlayer *>( UTIL_PlayerByIndex( i ) );
  86. if (!player)
  87. continue;
  88. // Hack for now so the temp bot code works. The temp bots are very useful for debugging
  89. // because they can be setup to mimic the player's usercmds.
  90. if (player->IsBot() && IsEntityValid( player ) )
  91. {
  92. // EVIL: Messes up vtables
  93. //CBot< CBasePlayer > *bot = static_cast< CBot< CBasePlayer > * >( player );
  94. CCSBot *bot = dynamic_cast< CCSBot * >( player );
  95. if ( bot )
  96. {
  97. {
  98. SNPROF("Upkeep");
  99. bot->Upkeep();
  100. }
  101. if (((gpGlobals->tickcount + bot->entindex()) % g_BotUpdateSkipCount) == 0)
  102. {
  103. {
  104. SNPROF("ResetCommand");
  105. bot->ResetCommand();
  106. }
  107. {
  108. SNPROF("Bot Update");
  109. bot->Update();
  110. }
  111. }
  112. {
  113. SNPROF("UpdatePlayer");
  114. bot->UpdatePlayer();
  115. }
  116. }
  117. }
  118. }
  119. }
  120. //--------------------------------------------------------------------------------------------------------------
  121. /**
  122. * Add an active grenade to the bot's awareness
  123. */
  124. void CBotManager::AddGrenade( CBaseGrenade *grenade )
  125. {
  126. ActiveGrenade *ag = new ActiveGrenade( grenade );
  127. m_activeGrenadeList.AddToTail( ag );
  128. }
  129. //--------------------------------------------------------------------------------------------------------------
  130. /**
  131. * The grenade entity in the world is going away
  132. */
  133. void CBotManager::RemoveGrenade( CBaseGrenade *grenade )
  134. {
  135. FOR_EACH_LL( m_activeGrenadeList, it )
  136. {
  137. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  138. if (ag->IsEntity( grenade ))
  139. {
  140. ag->OnEntityGone();
  141. m_activeGrenadeList.Remove( it );
  142. delete ag;
  143. return;
  144. }
  145. }
  146. }
  147. //--------------------------------------------------------------------------------------------------------------
  148. /**
  149. * The grenade entity has changed its radius
  150. */
  151. void CBotManager::SetGrenadeRadius( CBaseGrenade *grenade, float radius )
  152. {
  153. FOR_EACH_LL( m_activeGrenadeList, it )
  154. {
  155. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  156. if (ag->IsEntity( grenade ))
  157. {
  158. ag->SetRadius( radius );
  159. return;
  160. }
  161. }
  162. }
  163. //--------------------------------------------------------------------------------------------------------------
  164. /**
  165. * Destroy any invalid active grenades
  166. */
  167. void CBotManager::ValidateActiveGrenades( void )
  168. {
  169. int it = m_activeGrenadeList.Head();
  170. while( it != m_activeGrenadeList.InvalidIndex() )
  171. {
  172. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  173. int current = it;
  174. it = m_activeGrenadeList.Next( it );
  175. // lazy validation
  176. if (!ag->IsValid())
  177. {
  178. m_activeGrenadeList.Remove( current );
  179. delete ag;
  180. continue;
  181. }
  182. else
  183. {
  184. ag->Update();
  185. }
  186. }
  187. }
  188. //--------------------------------------------------------------------------------------------------------------
  189. void CBotManager::DestroyAllGrenades( void )
  190. {
  191. int it = m_activeGrenadeList.Head();
  192. while ( it != m_activeGrenadeList.InvalidIndex() )
  193. {
  194. ActiveGrenade *ag = m_activeGrenadeList[it];
  195. int current = it;
  196. it = m_activeGrenadeList.Next( it );
  197. m_activeGrenadeList.Remove( current );
  198. delete ag;
  199. }
  200. m_activeGrenadeList.PurgeAndDeleteElements();
  201. }
  202. //--------------------------------------------------------------------------------------------------------------
  203. /**
  204. * Return true if position is inside a smoke cloud
  205. */
  206. bool CBotManager::IsInsideSmokeCloud( const Vector *pos, float radius )
  207. {
  208. int it = m_activeGrenadeList.Head();
  209. while( it != m_activeGrenadeList.InvalidIndex() )
  210. {
  211. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  212. int current = it;
  213. it = m_activeGrenadeList.Next( it );
  214. // lazy validation
  215. if (!ag->IsValid())
  216. {
  217. m_activeGrenadeList.Remove( current );
  218. delete ag;
  219. continue;
  220. }
  221. if (ag->IsSmoke())
  222. {
  223. const Vector &smokeOrigin = ag->GetDetonationPosition();
  224. if ((smokeOrigin - *pos).IsLengthLessThan( ag->GetRadius() + radius ))
  225. return true;
  226. }
  227. }
  228. return false;
  229. }
  230. //--------------------------------------------------------------------------------------------------------------
  231. /**
  232. * Return true if line intersects smoke volume
  233. * Determine the length of the line of sight covered by each smoke cloud,
  234. * and sum them (overlap is additive for obstruction).
  235. * If the overlap exceeds the threshold, the bot can't see through.
  236. */
  237. bool CBotManager::IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat )
  238. {
  239. VPROF_BUDGET( "CBotManager::IsLineBlockedBySmoke", VPROF_BUDGETGROUP_NPCS );
  240. float totalSmokedLength = 0.0f; // distance along line of sight covered by smoke
  241. // compute unit vector and length of line of sight segment
  242. //Vector sightDir = to - from;
  243. //float sightLength = sightDir.NormalizeInPlace();
  244. FOR_EACH_LL( m_activeGrenadeList, it )
  245. {
  246. ActiveGrenade *ag = m_activeGrenadeList[ it ];
  247. const float smokeRadiusSq = ag->GetRadius() * ag->GetRadius() * grenadeBloat * grenadeBloat;
  248. if ( ag->IsSmoke() && CSGameRules() )
  249. {
  250. float flLengthAdd = CSGameRules()->CheckTotalSmokedLength( smokeRadiusSq, ag->GetDetonationPosition(), from, to );
  251. // get the totalSmokedLength and check to see if the line starts or stops in smoke. If it does this will return -1 and we should just bail early
  252. if ( flLengthAdd == -1 )
  253. return true;
  254. totalSmokedLength += flLengthAdd;
  255. }
  256. }
  257. // define how much smoke a bot can see thru
  258. const float maxSmokedLength = 0.7f * SmokeGrenadeRadius;
  259. // return true if the total length of smoke-covered line-of-sight is too much
  260. return (totalSmokedLength > maxSmokedLength);
  261. }
  262. //--------------------------------------------------------------------------------------------------------------
  263. void CBotManager::ClearDebugMessages( void )
  264. {
  265. m_debugMessageCount = 0;
  266. m_currentDebugMessage = -1;
  267. }
  268. //--------------------------------------------------------------------------------------------------------------
  269. /**
  270. * Add a new debug message to the message history
  271. */
  272. void CBotManager::AddDebugMessage( const char *msg )
  273. {
  274. if (++m_currentDebugMessage >= MAX_DBG_MSGS)
  275. {
  276. m_currentDebugMessage = 0;
  277. }
  278. if (m_debugMessageCount < MAX_DBG_MSGS)
  279. {
  280. ++m_debugMessageCount;
  281. }
  282. Q_strncpy( m_debugMessage[ m_currentDebugMessage ].m_string, msg, MAX_DBG_MSG_SIZE );
  283. m_debugMessage[ m_currentDebugMessage ].m_age.Start();
  284. }