summaryrefslogtreecommitdiff
path: root/game/server/tf/bot/tf_bot_squad.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/tf/bot/tf_bot_squad.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/server/tf/bot/tf_bot_squad.cpp')
-rw-r--r--game/server/tf/bot/tf_bot_squad.cpp294
1 files changed, 294 insertions, 0 deletions
diff --git a/game/server/tf/bot/tf_bot_squad.cpp b/game/server/tf/bot/tf_bot_squad.cpp
new file mode 100644
index 0000000..91cc914
--- /dev/null
+++ b/game/server/tf/bot/tf_bot_squad.cpp
@@ -0,0 +1,294 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+// tf_bot_squad.h
+// Small groups of TFBot, managed as a unit
+// Michael Booth, November 2009
+
+#include "cbase.h"
+#include "tf_bot.h"
+#include "tf_bot_squad.h"
+
+
+//----------------------------------------------------------------------
+CTFBotSquad::CTFBotSquad( void )
+{
+ m_leader = NULL;
+ m_formationSize = -1.0f;
+ m_bShouldPreserveSquad = false;
+}
+
+
+//----------------------------------------------------------------------
+void CTFBotSquad::Join( CTFBot *bot )
+{
+ // first member is the leader
+ if ( m_roster.Count() == 0 )
+ {
+ m_leader = bot;
+ }
+ else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
+ {
+ bot->SetFlagTarget( NULL );
+ }
+
+ m_roster.AddToTail( bot );
+}
+
+
+//----------------------------------------------------------------------
+void CTFBotSquad::Leave( CTFBot *bot )
+{
+ m_roster.FindAndRemove( bot );
+
+ if ( bot == m_leader.Get() )
+ {
+ m_leader = NULL;
+
+ // pick the next living leader that's left in the squad
+ if ( m_bShouldPreserveSquad )
+ {
+ CUtlVector< CTFBot* > members;
+ CollectMembers( &members );
+ if ( members.Count() )
+ {
+ m_leader = members[0];
+ }
+ }
+ }
+ else if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
+ {
+ AssertMsg( !bot->HasFlagTaget(), "Squad member shouldn't have a flag target. Always follow the leader." );
+ CCaptureFlag *pFlag = bot->GetFlagToFetch();
+ if ( pFlag )
+ {
+ bot->SetFlagTarget( pFlag );
+ }
+ }
+
+ if ( GetMemberCount() == 0 )
+ {
+ DisbandAndDeleteSquad();
+ }
+}
+
+
+//----------------------------------------------------------------------
+INextBotEventResponder *CTFBotSquad::FirstContainedResponder( void ) const
+{
+ return m_roster.Count() ? m_roster[0] : NULL;
+}
+
+
+//----------------------------------------------------------------------
+INextBotEventResponder *CTFBotSquad::NextContainedResponder( INextBotEventResponder *current ) const
+{
+ CTFBot *currentBot = (CTFBot *)current;
+
+ int i = m_roster.Find( currentBot );
+
+ if ( i == m_roster.InvalidIndex() )
+ return NULL;
+
+ if ( ++i >= m_roster.Count() )
+ return NULL;
+
+ return (CTFBot *)m_roster[i];
+}
+
+
+//----------------------------------------------------------------------
+CTFBot *CTFBotSquad::GetLeader( void ) const
+{
+ return m_leader;
+}
+
+
+//----------------------------------------------------------------------
+void CTFBotSquad::CollectMembers( CUtlVector< CTFBot * > *memberVector ) const
+{
+ for( int i=0; i<m_roster.Count(); ++i )
+ {
+ if ( m_roster[i] != NULL && m_roster[i]->IsAlive() )
+ {
+ memberVector->AddToTail( m_roster[i] );
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+CTFBotSquad::Iterator CTFBotSquad::GetFirstMember( void ) const
+{
+ // find first non-NULL member
+ for( int i=0; i<m_roster.Count(); ++i )
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ return Iterator( m_roster[i], i );
+
+ return InvalidIterator();
+}
+
+
+//----------------------------------------------------------------------
+CTFBotSquad::Iterator CTFBotSquad::GetNextMember( const Iterator &it ) const
+{
+ // find next non-NULL member
+ for( int i=it.m_index+1; i<m_roster.Count(); ++i )
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ return Iterator( m_roster[i], i );
+
+ return InvalidIterator();
+}
+
+
+//----------------------------------------------------------------------
+int CTFBotSquad::GetMemberCount( void ) const
+{
+ // count the non-NULL members
+ int count = 0;
+ for( int i=0; i<m_roster.Count(); ++i )
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ ++count;
+
+ return count;
+}
+
+
+//----------------------------------------------------------------------
+// Return the speed of the slowest member of the squad
+float CTFBotSquad::GetSlowestMemberSpeed( bool includeLeader ) const
+{
+ float speed = FLT_MAX;
+
+ int i = includeLeader ? 0 : 1;
+
+ for( ; i<m_roster.Count(); ++i )
+ {
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ {
+ float memberSpeed = m_roster[i]->MaxSpeed();
+ if ( memberSpeed < speed )
+ {
+ speed = memberSpeed;
+ }
+ }
+ }
+
+ return speed;
+}
+
+
+//----------------------------------------------------------------------
+// Return the speed of the slowest member of the squad,
+// considering their ideal class speed.
+float CTFBotSquad::GetSlowestMemberIdealSpeed( bool includeLeader ) const
+{
+ float speed = FLT_MAX;
+
+ int i = includeLeader ? 0 : 1;
+
+ for( ; i<m_roster.Count(); ++i )
+ {
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ {
+ float memberSpeed = m_roster[i]->GetPlayerClass()->GetMaxSpeed();
+ if ( memberSpeed < speed )
+ {
+ speed = memberSpeed;
+ }
+ }
+ }
+
+ return speed;
+}
+
+
+//----------------------------------------------------------------------
+// Return the maximum formation error of the squad's memebers.
+float CTFBotSquad::GetMaxSquadFormationError( void ) const
+{
+ float maxError = 0.0f;
+
+ // skip the leader since he's what the formation forms around
+ for( int i=1; i<m_roster.Count(); ++i )
+ {
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ {
+ float error = m_roster[i]->GetSquadFormationError();
+ if ( error > maxError )
+ {
+ maxError = error;
+ }
+ }
+ }
+
+ return maxError;
+}
+
+
+//----------------------------------------------------------------------
+// Return true if the squad leader needs to wait for members to catch up, ignoring those who have broken ranks
+bool CTFBotSquad::ShouldSquadLeaderWaitForFormation( void ) const
+{
+ // skip the leader since he's what the formation forms around
+ for( int i=1; i<m_roster.Count(); ++i )
+ {
+ // the squad leader should wait if any member is out of position, but not yet broken ranks
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ {
+ if ( m_roster[i]->GetSquadFormationError() >= 1.0f &&
+ !m_roster[i]->HasBrokenFormation() &&
+ !m_roster[i]->GetLocomotionInterface()->IsStuck() &&
+ !m_roster[i]->IsPlayerClass( TF_CLASS_MEDIC ) ) // Medics do their own thing
+ {
+ // wait for me!
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+//----------------------------------------------------------------------
+// Return true if the squad is in formation (everyone is in or nearly in their desired positions)
+bool CTFBotSquad::IsInFormation( void ) const
+{
+ // skip the leader since he's what the formation forms around
+ for( int i=1; i<m_roster.Count(); ++i )
+ {
+ if ( m_roster[i].Get() != NULL && m_roster[i]->IsAlive() )
+ {
+ if ( m_roster[i]->HasBrokenFormation() ||
+ m_roster[i]->GetLocomotionInterface()->IsStuck() ||
+ m_roster[i]->IsPlayerClass( TF_CLASS_MEDIC ) ) // Medics do their own thing
+ {
+ // I'm not "in formation"
+ continue;
+ }
+
+ if ( m_roster[i]->GetSquadFormationError() > 0.75f )
+ {
+ // I'm not in position yet
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+//----------------------------------------------------------------------
+// Tell all members to leave the squad and then delete itself
+void CTFBotSquad::DisbandAndDeleteSquad( void )
+{
+ // Tell each member of the squad to remove this reference
+ for( int i=0; i < m_roster.Count(); ++i )
+ {
+ if ( m_roster[i].Get() != NULL )
+ {
+ m_roster[i]->DeleteSquad();
+ }
+ }
+
+ delete this;
+} \ No newline at end of file