Team Fortress 2 Source Code as on 22/4/2020
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.

293 lines
7.0 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. // tf_bot_squad.h
  3. // Small groups of TFBot, managed as a unit
  4. // Michael Booth, November 2009
  5. #include "cbase.h"
  6. #include "tf_bot.h"
  7. #include "tf_bot_squad.h"
  8. //----------------------------------------------------------------------
  9. CTFBotSquad::CTFBotSquad( void )
  10. {
  11. m_leader = NULL;
  12. m_formationSize = -1.0f;
  13. m_bShouldPreserveSquad = false;
  14. }
  15. //----------------------------------------------------------------------
  16. void CTFBotSquad::Join( CTFBot *bot )
  17. {
  18. // first member is the leader
  19. if ( m_roster.Count() == 0 )
  20. {
  21. m_leader = bot;
  22. }
  23. else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  24. {
  25. bot->SetFlagTarget( NULL );
  26. }
  27. m_roster.AddToTail( bot );
  28. }
  29. //----------------------------------------------------------------------
  30. void CTFBotSquad::Leave( CTFBot *bot )
  31. {
  32. m_roster.FindAndRemove( bot );
  33. if ( bot == m_leader.Get() )
  34. {
  35. m_leader = NULL;
  36. // pick the next living leader that's left in the squad
  37. if ( m_bShouldPreserveSquad )
  38. {
  39. CUtlVector< CTFBot* > members;
  40. CollectMembers( &members );
  41. if ( members.Count() )
  42. {
  43. m_leader = members[0];
  44. }
  45. }
  46. }
  47. else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  48. {
  49. AssertMsg( !bot->HasFlagTaget(), "Squad member shouldn't have a flag target. Always follow the leader." );
  50. CCaptureFlag *pFlag = bot->GetFlagToFetch();
  51. if ( pFlag )
  52. {
  53. bot->SetFlagTarget( pFlag );
  54. }
  55. }
  56. if ( GetMemberCount() == 0 )
  57. {
  58. DisbandAndDeleteSquad();
  59. }
  60. }
  61. //----------------------------------------------------------------------
  62. INextBotEventResponder *CTFBotSquad::FirstContainedResponder( void ) const
  63. {
  64. return m_roster.Count() ? m_roster[0] : NULL;
  65. }
  66. //----------------------------------------------------------------------
  67. INextBotEventResponder *CTFBotSquad::NextContainedResponder( INextBotEventResponder *current ) const
  68. {
  69. CTFBot *currentBot = (CTFBot *)current;
  70. int i = m_roster.Find( currentBot );
  71. if ( i == m_roster.InvalidIndex() )
  72. return NULL;
  73. if ( ++i >= m_roster.Count() )
  74. return NULL;
  75. return (CTFBot *)m_roster[i];
  76. }
  77. //----------------------------------------------------------------------
  78. CTFBot *CTFBotSquad::GetLeader( void ) const
  79. {
  80. return m_leader;
  81. }
  82. //----------------------------------------------------------------------
  83. void CTFBotSquad::CollectMembers( CUtlVector< CTFBot * > *memberVector ) const
  84. {
  85. for( int i=0; i<m_roster.Count(); ++i )
  86. {
  87. if ( m_roster[i] != NULL && m_roster[i]->IsAlive() )
  88. {
  89. memberVector->AddToTail( m_roster[i] );
  90. }
  91. }
  92. }
  93. //----------------------------------------------------------------------
  94. CTFBotSquad::Iterator CTFBotSquad::GetFirstMember( void ) const
  95. {
  96. // find first non-NULL member
  97. for( int i=0; i<m_roster.Count(); ++i )
  98. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  99. return Iterator( m_roster[i], i );
  100. return InvalidIterator();
  101. }
  102. //----------------------------------------------------------------------
  103. CTFBotSquad::Iterator CTFBotSquad::GetNextMember( const Iterator &it ) const
  104. {
  105. // find next non-NULL member
  106. for( int i=it.m_index+1; i<m_roster.Count(); ++i )
  107. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  108. return Iterator( m_roster[i], i );
  109. return InvalidIterator();
  110. }
  111. //----------------------------------------------------------------------
  112. int CTFBotSquad::GetMemberCount( void ) const
  113. {
  114. // count the non-NULL members
  115. int count = 0;
  116. for( int i=0; i<m_roster.Count(); ++i )
  117. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  118. ++count;
  119. return count;
  120. }
  121. //----------------------------------------------------------------------
  122. // Return the speed of the slowest member of the squad
  123. float CTFBotSquad::GetSlowestMemberSpeed( bool includeLeader ) const
  124. {
  125. float speed = FLT_MAX;
  126. int i = includeLeader ? 0 : 1;
  127. for( ; i<m_roster.Count(); ++i )
  128. {
  129. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  130. {
  131. float memberSpeed = m_roster[i]->MaxSpeed();
  132. if ( memberSpeed < speed )
  133. {
  134. speed = memberSpeed;
  135. }
  136. }
  137. }
  138. return speed;
  139. }
  140. //----------------------------------------------------------------------
  141. // Return the speed of the slowest member of the squad,
  142. // considering their ideal class speed.
  143. float CTFBotSquad::GetSlowestMemberIdealSpeed( bool includeLeader ) const
  144. {
  145. float speed = FLT_MAX;
  146. int i = includeLeader ? 0 : 1;
  147. for( ; i<m_roster.Count(); ++i )
  148. {
  149. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  150. {
  151. float memberSpeed = m_roster[i]->GetPlayerClass()->GetMaxSpeed();
  152. if ( memberSpeed < speed )
  153. {
  154. speed = memberSpeed;
  155. }
  156. }
  157. }
  158. return speed;
  159. }
  160. //----------------------------------------------------------------------
  161. // Return the maximum formation error of the squad's memebers.
  162. float CTFBotSquad::GetMaxSquadFormationError( void ) const
  163. {
  164. float maxError = 0.0f;
  165. // skip the leader since he's what the formation forms around
  166. for( int i=1; i<m_roster.Count(); ++i )
  167. {
  168. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  169. {
  170. float error = m_roster[i]->GetSquadFormationError();
  171. if ( error > maxError )
  172. {
  173. maxError = error;
  174. }
  175. }
  176. }
  177. return maxError;
  178. }
  179. //----------------------------------------------------------------------
  180. // Return true if the squad leader needs to wait for members to catch up, ignoring those who have broken ranks
  181. bool CTFBotSquad::ShouldSquadLeaderWaitForFormation( void ) const
  182. {
  183. // skip the leader since he's what the formation forms around
  184. for( int i=1; i<m_roster.Count(); ++i )
  185. {
  186. // the squad leader should wait if any member is out of position, but not yet broken ranks
  187. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  188. {
  189. if ( m_roster[i]->GetSquadFormationError() >= 1.0f &&
  190. !m_roster[i]->HasBrokenFormation() &&
  191. !m_roster[i]->GetLocomotionInterface()->IsStuck() &&
  192. !m_roster[i]->IsPlayerClass( TF_CLASS_MEDIC ) ) // Medics do their own thing
  193. {
  194. // wait for me!
  195. return true;
  196. }
  197. }
  198. }
  199. return false;
  200. }
  201. //----------------------------------------------------------------------
  202. // Return true if the squad is in formation (everyone is in or nearly in their desired positions)
  203. bool CTFBotSquad::IsInFormation( void ) const
  204. {
  205. // skip the leader since he's what the formation forms around
  206. for( int i=1; i<m_roster.Count(); ++i )
  207. {
  208. if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
  209. {
  210. if ( m_roster[i]->HasBrokenFormation() ||
  211. m_roster[i]->GetLocomotionInterface()->IsStuck() ||
  212. m_roster[i]->IsPlayerClass( TF_CLASS_MEDIC ) ) // Medics do their own thing
  213. {
  214. // I'm not "in formation"
  215. continue;
  216. }
  217. if ( m_roster[i]->GetSquadFormationError() > 0.75f )
  218. {
  219. // I'm not in position yet
  220. return false;
  221. }
  222. }
  223. }
  224. return true;
  225. }
  226. //----------------------------------------------------------------------
  227. // Tell all members to leave the squad and then delete itself
  228. void CTFBotSquad::DisbandAndDeleteSquad( void )
  229. {
  230. // Tell each member of the squad to remove this reference
  231. for( int i=0; i < m_roster.Count(); ++i )
  232. {
  233. if ( m_roster[i].Get() != NULL )
  234. {
  235. m_roster[i]->DeleteSquad();
  236. }
  237. }
  238. delete this;
  239. }