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.

380 lines
8.6 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 "cs_bot.h"
  10. #include "usermessages.h"
  11. // memdbgon must be the last include file in a .cpp file!!!
  12. #include "tier0/memdbgon.h"
  13. extern int gmsgBotVoice;
  14. //--------------------------------------------------------------------------------------------------------------
  15. /**
  16. * Returns true if the radio message is an order to do something
  17. * NOTE: "Report in" is not considered a "command" because it doesnt ask the bot to go somewhere, or change its mind
  18. */
  19. bool CCSBot::IsRadioCommand( RadioType event ) const
  20. {
  21. if (event == RADIO_AFFIRMATIVE ||
  22. event == RADIO_NEGATIVE ||
  23. event == RADIO_ENEMY_SPOTTED ||
  24. event == RADIO_SECTOR_CLEAR ||
  25. event == RADIO_REPORTING_IN ||
  26. event == RADIO_REPORT_IN_TEAM ||
  27. event == RADIO_ENEMY_DOWN ||
  28. event == RADIO_INVALID )
  29. return false;
  30. return true;
  31. }
  32. //--------------------------------------------------------------------------------------------------------------
  33. /**
  34. * Respond to radio commands from HUMAN players
  35. */
  36. void CCSBot::RespondToRadioCommands( void )
  37. {
  38. // bots use the chatter system to respond to each other
  39. if (m_radioSubject != NULL && m_radioSubject->IsPlayer())
  40. {
  41. CCSPlayer *player = m_radioSubject;
  42. if (player->IsBot())
  43. {
  44. m_lastRadioCommand = RADIO_INVALID;
  45. return;
  46. }
  47. }
  48. if (m_lastRadioCommand == RADIO_INVALID)
  49. return;
  50. // a human player has issued a radio command
  51. GetChatter()->ResetRadioSilenceDuration();
  52. // if we are doing something important, ignore the radio
  53. // unless it is a "report in" request - we can do that while we continue to do other things
  54. /// @todo Create "uninterruptable" flag
  55. if (m_lastRadioCommand != RADIO_REPORT_IN_TEAM)
  56. {
  57. if (IsBusy())
  58. {
  59. // consume command
  60. m_lastRadioCommand = RADIO_INVALID;
  61. return;
  62. }
  63. }
  64. // wait for reaction time before responding
  65. // delay needs to be long enough for the radio message we're responding to to finish
  66. float respondTime = 1.0f + 2.0f * GetProfile()->GetReactionTime();
  67. if (IsRogue())
  68. respondTime += 2.0f;
  69. if (gpGlobals->curtime - m_lastRadioRecievedTimestamp < respondTime)
  70. return;
  71. // rogues won't follow commands, unless already following the player
  72. if (!IsFollowing() && IsRogue())
  73. {
  74. if (IsRadioCommand( m_lastRadioCommand ))
  75. {
  76. GetChatter()->Negative();
  77. }
  78. // consume command
  79. m_lastRadioCommand = RADIO_INVALID;
  80. return;
  81. }
  82. CCSPlayer *player = m_radioSubject;
  83. if (player == NULL)
  84. return;
  85. // respond to command
  86. bool canDo = false;
  87. const float inhibitAutoFollowDuration = 60.0f;
  88. switch( m_lastRadioCommand )
  89. {
  90. case RADIO_REPORT_IN_TEAM:
  91. {
  92. GetChatter()->ReportingIn();
  93. break;
  94. }
  95. case RADIO_FOLLOW_ME:
  96. case RADIO_COVER_ME:
  97. case RADIO_STICK_TOGETHER_TEAM:
  98. case RADIO_REGROUP_TEAM:
  99. {
  100. if (!IsFollowing())
  101. {
  102. Follow( player );
  103. player->AllowAutoFollow();
  104. canDo = true;
  105. }
  106. break;
  107. }
  108. case RADIO_ENEMY_SPOTTED:
  109. case RADIO_NEED_BACKUP:
  110. case RADIO_TAKING_FIRE:
  111. if (!IsFollowing())
  112. {
  113. Follow( player );
  114. GetChatter()->Say( "OnMyWay" );
  115. player->AllowAutoFollow();
  116. canDo = false;
  117. }
  118. break;
  119. case RADIO_TEAM_FALL_BACK:
  120. {
  121. if (TryToRetreat())
  122. canDo = true;
  123. break;
  124. }
  125. case RADIO_HOLD_THIS_POSITION:
  126. {
  127. // find the leader's area
  128. SetTask( HOLD_POSITION );
  129. StopFollowing();
  130. player->InhibitAutoFollow( inhibitAutoFollowDuration );
  131. Hide( TheNavMesh->GetNearestNavArea( m_radioPosition ) );
  132. canDo = true;
  133. break;
  134. }
  135. case RADIO_GO_GO_GO:
  136. case RADIO_STORM_THE_FRONT:
  137. StopFollowing();
  138. Hunt();
  139. canDo = true;
  140. player->InhibitAutoFollow( inhibitAutoFollowDuration );
  141. break;
  142. case RADIO_GET_OUT_OF_THERE:
  143. if (TheCSBots()->IsBombPlanted())
  144. {
  145. EscapeFromBomb();
  146. player->InhibitAutoFollow( inhibitAutoFollowDuration );
  147. canDo = true;
  148. }
  149. break;
  150. case RADIO_SECTOR_CLEAR:
  151. {
  152. // if this is a defusal scenario, and the bomb is planted,
  153. // and a human player cleared a bombsite, check it off our list too
  154. if (TheCSBots()->GetScenario() == CCSBotManager::SCENARIO_DEFUSE_BOMB)
  155. {
  156. if (GetTeamNumber() == TEAM_CT && TheCSBots()->IsBombPlanted())
  157. {
  158. const CCSBotManager::Zone *zone = TheCSBots()->GetClosestZone( player );
  159. if (zone)
  160. {
  161. GetGameState()->ClearBombsite( zone->m_index );
  162. // if we are huting for the planted bomb, re-select bombsite
  163. if (GetTask() == FIND_TICKING_BOMB)
  164. Idle();
  165. canDo = true;
  166. }
  167. }
  168. }
  169. break;
  170. }
  171. default:
  172. // ignore all other radio commands for now
  173. return;
  174. }
  175. if (canDo)
  176. {
  177. // affirmative
  178. GetChatter()->Affirmative();
  179. // if we agreed to follow a new command, put away our grenade
  180. if (IsRadioCommand( m_lastRadioCommand ) && IsUsingGrenade())
  181. {
  182. EquipBestWeapon();
  183. }
  184. }
  185. // consume command
  186. m_lastRadioCommand = RADIO_INVALID;
  187. }
  188. //--------------------------------------------------------------------------------------------------------------
  189. /**
  190. * Decide if we should move to help the player, return true if we will
  191. */
  192. bool CCSBot::RespondToHelpRequest( CCSPlayer *them, Place place, float maxRange )
  193. {
  194. if (IsRogue())
  195. return false;
  196. // if we're busy, ignore
  197. if (IsBusy())
  198. return false;
  199. Vector themOrigin = GetCentroid( them );
  200. // if we are too far away, ignore
  201. if (maxRange > 0.0f)
  202. {
  203. // compute actual travel distance
  204. PathCost cost(this);
  205. float travelDistance = NavAreaTravelDistance( m_lastKnownArea, TheNavMesh->GetNearestNavArea( themOrigin ), cost );
  206. if (travelDistance < 0.0f)
  207. return false;
  208. if (travelDistance > maxRange)
  209. return false;
  210. }
  211. if (place == UNDEFINED_PLACE)
  212. {
  213. // if we have no "place" identifier, go directly to them
  214. // if we are already there, ignore
  215. float rangeSq = (them->GetAbsOrigin() - GetAbsOrigin()).LengthSqr();
  216. const float close = 750.0f * 750.0f;
  217. if (rangeSq < close)
  218. return true;
  219. MoveTo( themOrigin, FASTEST_ROUTE );
  220. }
  221. else
  222. {
  223. // if we are already there, ignore
  224. if (GetPlace() == place)
  225. return true;
  226. // go to where help is needed
  227. Vector pos;
  228. if ( GetRandomSpotAtPlace( place, &pos ) )
  229. {
  230. MoveTo( pos, FASTEST_ROUTE );
  231. }
  232. else
  233. {
  234. MoveTo( themOrigin, FASTEST_ROUTE );
  235. }
  236. }
  237. // acknowledge
  238. GetChatter()->Say( "OnMyWay" );
  239. return true;
  240. }
  241. //--------------------------------------------------------------------------------------------------------------
  242. /**
  243. * Send a radio message
  244. */
  245. void CCSBot::SendRadioMessage( RadioType event )
  246. {
  247. // make sure this is a radio event
  248. if (event <= RADIO_START_1 || event >= RADIO_END)
  249. return;
  250. PrintIfWatched( "%3.1f: SendRadioMessage( %s )\n", gpGlobals->curtime, RadioEventName[ event ] );
  251. // note the time the message was sent
  252. TheCSBots()->SetRadioMessageTimestamp( event, GetTeamNumber() );
  253. m_lastRadioSentTimestamp = gpGlobals->curtime;
  254. char slot[2];
  255. slot[1] = '\000';
  256. if (event > RADIO_START_1 && event < RADIO_START_2)
  257. {
  258. HandleMenu_Radio1( event );
  259. }
  260. else if (event > RADIO_START_2 && event < RADIO_START_3)
  261. {
  262. HandleMenu_Radio2( event );
  263. }
  264. else
  265. {
  266. HandleMenu_Radio3( event );
  267. }
  268. }
  269. //--------------------------------------------------------------------------------------------------------------
  270. /**
  271. * Send voice chatter. Also sends the entindex and duration for voice feedback.
  272. */
  273. void CCSBot::SpeakAudio( const char *voiceFilename, float duration, int pitch )
  274. {
  275. if( !IsAlive() )
  276. return;
  277. if ( IsObserver() )
  278. return;
  279. CRecipientFilter filter;
  280. ConstructRadioFilter( filter );
  281. CCSUsrMsg_RawAudio msg;
  282. msg.set_pitch( pitch );
  283. msg.set_entidx( entindex() );
  284. msg.set_duration( duration );
  285. msg.set_voice_filename( voiceFilename );
  286. SendUserMessage ( filter, CS_UM_RawAudio, msg );
  287. GetChatter()->ResetRadioSilenceDuration();
  288. m_voiceEndTimestamp = gpGlobals->curtime + duration;
  289. }
  290. //--------------------------------------------------------------------------------------------------------------
  291. /**
  292. * Send voice chatter through the response rules system.
  293. */
  294. bool CCSBot::SpeakAudioResponseRules( const char *pConcept, AI_CriteriaSet *criteria, float duration )
  295. {
  296. if( !IsAlive() )
  297. return false;
  298. if ( IsObserver() )
  299. return false;
  300. CRecipientFilter filter;
  301. ConstructRadioFilter( filter );
  302. AI_CriteriaSet local;
  303. if ( !criteria )
  304. criteria = &local;
  305. AIConcept_t concept( pConcept );
  306. if ( Speak( concept, criteria, NULL, 0, &filter ) )
  307. {
  308. GetChatter()->ResetRadioSilenceDuration();
  309. m_voiceEndTimestamp = gpGlobals->curtime + duration;
  310. return true;
  311. }
  312. return false;
  313. }