ProtoBot
Loading...
Searching...
No Matches
ScoutingManager Class Reference

ScoutingManager Manages all scouting units and their behaviors. Assigns units to the appropriate scouting behavior, updates them each frame, tracks enemy locations, and coordinates transitions between scouting and combat. More...

#include <ScoutingManager.h>

Public Member Functions

 ScoutingManager (ProtoBotCommander *commander=nullptr)
 Manages all scouting behavior in ProtoBot.
void onStart ()
 Called once at game start.
void onFrame ()
 Main update loop executed every frame.
void assignScout (BWAPI::Unit unit)
 Assigns a unit as a scout and attaches the appropriate behavior.
bool hasScout () const
 Checks if any scouting units are currently active.
void setEnemyMain (const BWAPI::TilePosition &tp)
 Sets the enemy main base location and broadcasts it to all scouts.
void setEnemyNatural (const BWAPI::TilePosition &tp)
 Sets the enemy natural expansion location.
void onUnitDestroy (BWAPI::Unit unit)
 Handles cleanup when a unit is destroyed.
std::optional< BWAPI::TilePosition > getEnemyMain () const
std::optional< BWAPI::TilePosition > getEnemyNatural () const
void markScout (BWAPI::Unit u)
 Marks a unit as a scout and tracks it by type.
void unmarkScout (BWAPI::Unit u)
 Removes a unit from scout tracking structures.
bool isScout (BWAPI::Unit u) const
 Checks whether a unit is currently assigned as a scout.
bool isCombatScout (BWAPI::Unit u) const
 Checks if a unit is a combat scout (Zealot or Dragoon).
bool hasWorkerScout () const
void drawDebug () const
 Draws debug information for all scouting behaviors.
void drawGlobalDebugPanel () const
void drawKnownEnemyLocations () const
void drawScoutDebugFor (BWAPI::Unit unit) const
void drawScoutTags () const
void setCombatScoutingStarted (bool v)
bool combatScoutingStarted () const
bool canAcceptWorkerScout () const
bool combatScoutLockActive () const
int combatScoutLockFramesRemaining () const
void maybeReturnCombatScoutsToCombat ()
bool tryReturnScoutToCombat (BWAPI::Unit unit)
 Returns a combat scout unit back to combat control.
bool isNearActiveCombatSquad (BWAPI::Unit unit) const
void lockCombatScoutAssignments (int frames)
bool canAcceptCombatScout (BWAPI::UnitType t) const
bool canAcceptObserverScout () const
int numCombatScouts () const
BWAPI::Unit getAvaliableDetectors ()
 Retrieves an available observer and removes it from scouting.

Public Attributes

bool scoutingDebugEnabled_ = false
int combatScoutLockUntilFrame_ = 0

Static Public Attributes

static constexpr int kScoutReturnToCombatDistPx_ = 10 * 32
static constexpr int kCombatScoutLockFrames_ = 24 * 10

Private Member Functions

BehaviorVariant constructBehaviorFor (BWAPI::Unit unit)
 Creates the appropriate scouting behavior for a unit.
int reserveObserverSlot (int unitId)
void releaseObserverSlot (int unitId)

Static Private Member Functions

static BWAPI::Unit findUnitById (int id)

Private Attributes

ProtoBotCommandercommanderRef = nullptr
std::unordered_map< int, BehaviorVariant > behaviors_
std::vector< BWAPI::Unit > scouts_
BWAPI::Unit workerScout_ { nullptr }
bool combatScoutingStarted_ { false }
std::optional< BWAPI::TilePosition > enemyMainCache_
std::optional< BWAPI::TilePosition > enemyNaturalCache_
bool inBehaviorFrame_ = false
std::optional< BWAPI::TilePosition > pendingEnemyMain_
int maxZealotScouts_ { 2 }
int maxDragoonScouts_ { 2 }
int maxObserverScouts_ { 4 }
int proxyPatrolZealotId_ = -1
std::vector< BWAPI::Unit > combatZealots_
std::vector< BWAPI::Unit > combatDragoons_
std::vector< BWAPI::Unit > observerScouts_
int observerSlotOwner_ [4] = { -1, -1, -1, -1 }
std::vector< BWAPI::Unit > darkTemplarScouts_

Detailed Description

ScoutingManager Manages all scouting units and their behaviors. Assigns units to the appropriate scouting behavior, updates them each frame, tracks enemy locations, and coordinates transitions between scouting and combat.

Definition at line 44 of file ScoutingManager.h.

Constructor & Destructor Documentation

◆ ScoutingManager()

ScoutingManager::ScoutingManager ( ProtoBotCommander * commander = nullptr)
explicit

Manages all scouting behavior in ProtoBot.

Responsibilities:

  • Assign scouting units and attach behaviors
  • Manage scouting state and unit roles
  • Track enemy main and natural locations
  • Coordinate transitions between scouting and combat

Uses a BehaviorVariant system to support multiple scout types:

  • Probe
  • Zealot / Dragoon
  • Observer
  • Dark Templar

Initializes the ScoutingManager with a reference to the commander.

Parameters
commanderPointer to ProtoBotCommander

Definition at line 25 of file ScoutingManager.cpp.

26 : commanderRef(commander)
27{
28}

Member Function Documentation

◆ assignScout()

void ScoutingManager::assignScout ( BWAPI::Unit unit)

Assigns a unit as a scout and attaches the appropriate behavior.

Handles different unit types:

  • Worker (Probe scout)
  • Observer (detector scouting)
  • Combat units (Zealot / Dragoon scouting)

Also removes the unit from combat control.

Parameters
unitUnit to assign as a scout

Definition at line 134 of file ScoutingManager.cpp.

135{
136 if (!unit || !unit->exists()) return;
137
138 const auto t = unit->getType();
139
140 if (t.isWorker())
141 {
142 if (workerScout_ && workerScout_->exists()) return;
143 }
144 else if (t == BWAPI::UnitTypes::Protoss_Observer)
145 {
146 if (!canAcceptObserverScout()) return;
147 int slot = reserveObserverSlot(unit->getID());
148 if (slot < 0) return;
149 }
150 else
151 {
152 // zealot or dragoon
153 if (!canAcceptCombatScout(unit->getType()))
154 {
155 return;
156 }
157 }
158 // build a behavior instance for THIS unit and store by id
159 BehaviorVariant sb = constructBehaviorFor(unit);
160
161 if (t == BWAPI::UnitTypes::Protoss_Zealot)
162 {
163 if (proxyPatrolZealotId_ == -1)
164 {
165 proxyPatrolZealotId_ = unit->getID();
166 }
167
168 if (auto* z = std::get_if<ScoutingZealot>(&sb))
169 {
170 z->setProxyPatroller(unit->getID() == proxyPatrolZealotId_);
171 }
172 }
173
174 if (t == BWAPI::UnitTypes::Protoss_Observer)
175 {
176 // find slot we reserved (it’s in observerSlotOwner_)
177 int slot = -1;
178 for (int i = 0; i < 4; ++i) if (observerSlotOwner_[i] == unit->getID()) { slot = i; break; }
179 if (slot >= 0) {
180 if (auto* ob = std::get_if<ScoutingObserver>(&sb))
181 {
182 ob->setObserverSlot(slot);
183 }
184 observerScouts_.push_back(unit);
185 }
186 }
187
188 visit_start(sb);
189 visit_assign(sb, unit);
190
191 // cache into the map (overwrite if re-assigning the same id)
192 behaviors_[unit->getID()] = std::move(sb);
193
194 if (commanderRef)
195 {
196 commanderRef->combatManager.detachUnit(unit);
197 }
198
199 // bookkeeping
200 markScout(unit);
201}
void markScout(BWAPI::Unit u)
Marks a unit as a scout and tracks it by type.
BehaviorVariant constructBehaviorFor(BWAPI::Unit unit)
Creates the appropriate scouting behavior for a unit.

◆ canAcceptCombatScout()

bool ScoutingManager::canAcceptCombatScout ( BWAPI::UnitType t) const
inline

Definition at line 92 of file ScoutingManager.h.

93 {
94 if (t == BWAPI::UnitTypes::Protoss_Dark_Templar)
95 {
96 return true;
97 }
98
99 if (combatScoutLockActive())
100 {
101 return false;
102 }
103
104 if (t == BWAPI::UnitTypes::Protoss_Zealot)
105 {
106 return int(combatZealots_.size()) < maxZealotScouts_;
107 }
108
109 if (t == BWAPI::UnitTypes::Protoss_Dragoon)
110 {
111 return int(combatDragoons_.size()) < maxDragoonScouts_;
112 }
113
114 return false;
115 }

◆ canAcceptObserverScout()

bool ScoutingManager::canAcceptObserverScout ( ) const
inline

Definition at line 117 of file ScoutingManager.h.

117{ return (int)observerScouts_.size() < maxObserverScouts_; }

◆ canAcceptWorkerScout()

bool ScoutingManager::canAcceptWorkerScout ( ) const
inline

Definition at line 78 of file ScoutingManager.h.

78{ return !combatScoutingStarted_ && !workerScout_; }

◆ combatScoutingStarted()

bool ScoutingManager::combatScoutingStarted ( ) const
inline

Definition at line 76 of file ScoutingManager.h.

76{ return combatScoutingStarted_; }

◆ combatScoutLockActive()

bool ScoutingManager::combatScoutLockActive ( ) const

Definition at line 758 of file ScoutingManager.cpp.

759{
760 return BWAPI::Broodwar->getFrameCount() < combatScoutLockUntilFrame_;
761}

◆ combatScoutLockFramesRemaining()

int ScoutingManager::combatScoutLockFramesRemaining ( ) const

Definition at line 763 of file ScoutingManager.cpp.

764{
765 const int remaining = combatScoutLockUntilFrame_ - BWAPI::Broodwar->getFrameCount();
766 return remaining > 0 ? remaining : 0;
767}

◆ constructBehaviorFor()

BehaviorVariant ScoutingManager::constructBehaviorFor ( BWAPI::Unit unit)
private

Creates the appropriate scouting behavior for a unit.

Supports:

  • Probe
  • Zealot / Dragoon
  • Observer
  • Dark Templar

Falls back to Probe behavior if type is unsupported.

Parameters
unitUnit to create behavior for
Returns
BehaviorVariant representing the unit's scouting logic

Definition at line 377 of file ScoutingManager.cpp.

378{
379 const auto t = unit->getType();
380
381 if (t == BWAPI::UnitTypes::Protoss_Probe)
382 {
383 ScoutingProbe probe(commanderRef, this);
384 // pass cache if we already know main
385 if (enemyMainCache_) probe.setEnemyMain(*enemyMainCache_);
386 //BWAPI::Broodwar->printf("[SM] behavior = Probe for id=%d", unit->getID());
387 return probe;
388 }
389
390 if (t == BWAPI::UnitTypes::Protoss_Zealot || t == BWAPI::UnitTypes::Protoss_Dragoon)
391 {
392 ScoutingZealot z(commanderRef, this);
393 if (enemyMainCache_) z.setEnemyMain(*enemyMainCache_);
394 //BWAPI::Broodwar->printf("[SM] behavior = ZealotBehavior for %s id=%d",
395 // t.c_str(), unit->getID());
396 return z;
397 }
398
399 if (t == BWAPI::UnitTypes::Protoss_Observer)
400 {
401 ScoutingObserver o(commanderRef, this);
402 if (enemyMainCache_) o.setEnemyMain(*enemyMainCache_);
403 //BWAPI::Broodwar->printf("[SM] behavior = Observer for id=%d", unit->getID());
404 return o;
405 }
406
407 if (t == BWAPI::UnitTypes::Protoss_Dark_Templar)
408 {
409 DarkTemplar dt(commanderRef, this);
410
411 if (enemyMainCache_)
412 {
413 dt.setEnemyMain(*enemyMainCache_);
414 }
415
416 return dt;
417 }
418
419 // fallback
420 ScoutingProbe fallback(commanderRef, this);
421 if (enemyMainCache_) fallback.setEnemyMain(*enemyMainCache_);
422 // BWAPI::Broodwar->printf("[SM] behavior = Fallback->Probe for id=%d", unit->getID());
423 return fallback;
424}

◆ drawDebug()

void ScoutingManager::drawDebug ( ) const

Draws debug information for all scouting behaviors.

Includes:

  • Global scouting info
  • Enemy locations
  • Per-unit debug visuals

Definition at line 601 of file ScoutingManager.cpp.

602{
603 if (!scoutingDebugEnabled_)
604 {
605 return;
606 }
607
608 drawGlobalDebugPanel();
609 drawKnownEnemyLocations();
610
611 for (const auto& [id, sb] : behaviors_)
612 {
613 std::visit(DrawBehaviorDebugVisitor{}, sb);
614 }
615}

◆ drawGlobalDebugPanel()

void ScoutingManager::drawGlobalDebugPanel ( ) const

Definition at line 617 of file ScoutingManager.cpp.

618{
619
620 int x = 10;
621 int y = 30;
622
623 BWAPI::Broodwar->drawTextScreen(x, y, "\x07Scouting Debug");
624 y += 14;
625
626 BWAPI::Broodwar->drawTextScreen(
627 x,
628 y,
629 "Enemy Main: %s",
630 enemyMainCache_.has_value() ? "\x07Known" : "\x08Unknown"
631 );
632 y += 12;
633
634 BWAPI::Broodwar->drawTextScreen(
635 x,
636 y,
637 "Worker Scout: %s",
638 (workerScout_ && workerScout_->exists()) ? "\x07 Active" : "\x08None"
639 );
640 y += 12;
641
642 BWAPI::Broodwar->drawTextScreen(x, y, "Combat Scouts: %d", numCombatScouts());
643 y += 12;
644
645 BWAPI::Broodwar->drawTextScreen(x, y, "Observer Scouts: %d", (int)observerScouts_.size());
646 y += 12;
647
648 const int totalScouts =
649 (workerScout_ && workerScout_->exists() ? 1 : 0) +
650 (int)combatZealots_.size() +
651 (int)combatDragoons_.size() +
652 (int)observerScouts_.size() +
653 (int)darkTemplarScouts_.size();
654
655 BWAPI::Broodwar->drawTextScreen(x, y, "All Scouts: %d", totalScouts);
656 y += 12;
657
658 BWAPI::Broodwar->drawTextScreen(
659 x,
660 y,
661 "Combat Scouting Started: %s",
662 combatScoutingStarted_ ? "\x07Yes" : "\x08No"
663 );
664}

◆ drawKnownEnemyLocations()

void ScoutingManager::drawKnownEnemyLocations ( ) const

Definition at line 666 of file ScoutingManager.cpp.

667{
668
669 if (enemyMainCache_.has_value())
670 {
671 BWAPI::Position p(enemyMainCache_.value());
672 BWAPI::Broodwar->drawCircleMap(p, 96, BWAPI::Colors::Cyan, false);
673 BWAPI::Broodwar->drawTextMap(p.x, p.y - 18, "\x0f Enemy Main");
674 }
675
676}

◆ drawScoutDebugFor()

void ScoutingManager::drawScoutDebugFor ( BWAPI::Unit unit) const

Definition at line 678 of file ScoutingManager.cpp.

679{
680 if (!unit || !unit->exists())
681 {
682 return;
683 }
684
685 const BWAPI::Position p = unit->getPosition();
686
687 BWAPI::Broodwar->drawCircleMap(p, 18, BWAPI::Colors::Green, false);
688
689 const BWAPI::UnitType t = unit->getType();
690
691 const char* role = "Scout";
692
693 if (t == BWAPI::UnitTypes::Protoss_Probe)
694 {
695 role = "Probe Scout";
696 }
697 else if (t == BWAPI::UnitTypes::Protoss_Zealot)
698 {
699 role = "Zealot Scout";
700 }
701 else if (t == BWAPI::UnitTypes::Protoss_Dragoon)
702 {
703 role = "Dragoon Scout";
704 }
705 else if (t == BWAPI::UnitTypes::Protoss_Observer)
706 {
707 role = "Observer Scout";
708 }
709 else if (t == BWAPI::UnitTypes::Protoss_Dark_Templar)
710 {
711 role = "DT Scout";
712 }
713
714 BWAPI::Broodwar->drawTextMap(p.x - 28, p.y - 30, "\x07%s", role);
715
716 if (enemyMainCache_.has_value())
717 {
718 BWAPI::Position mainPos(enemyMainCache_.value());
719 BWAPI::Broodwar->drawLineMap(p, mainPos, BWAPI::Colors::Green);
720 }
721
722 if (enemyNaturalCache_.has_value())
723 {
724 BWAPI::Position natPos(enemyNaturalCache_.value());
725 BWAPI::Broodwar->drawCircleMap(natPos, 16, BWAPI::Colors::Orange, false);
726 }
727}

◆ drawScoutTags()

void ScoutingManager::drawScoutTags ( ) const

Definition at line 731 of file ScoutingManager.cpp.

732{
733 if (workerScout_ && workerScout_->exists())
734 {
735 const auto p = workerScout_->getPosition();
736 //BWAPI::Broodwar->drawTextMap(p.x - 16, p.y + 20, "\x07SCOUT (Worker)");
737 }
738 for (auto u : combatZealots_)
739 {
740 if (!u || !u->exists()) continue;
741 const auto p = u->getPosition();
742 //BWAPI::Broodwar->drawTextMap(p.x - 16, p.y + 20, "\x07SCOUT (Zealot)");
743 }
744 for (auto u : combatDragoons_)
745 {
746 if (!u || !u->exists()) continue;
747 const auto p = u->getPosition();
748 //BWAPI::Broodwar->drawTextMap(p.x - 16, p.y + 20, "\x07SCOUT (Dragoon)");
749 }
750 for (auto u : observerScouts_)
751 {
752 if (!u || !u->exists()) continue;
753 const auto p = u->getPosition();
754 //BWAPI::Broodwar->drawTextMap(p.x - 16, p.y + 32, "\x10SCOUT (Observer)");
755 }
756}

◆ findUnitById()

BWAPI::Unit ScoutingManager::findUnitById ( int id)
staticprivate

Definition at line 426 of file ScoutingManager.cpp.

427{
428 for (auto u : BWAPI::Broodwar->self()->getUnits())
429 if (u && u->exists() && u->getID() == id) return u;
430 return nullptr;
431}

◆ getAvaliableDetectors()

BWAPI::Unit ScoutingManager::getAvaliableDetectors ( )

Retrieves an available observer and removes it from scouting.

Transfers control back to combat systems.

Returns
Observer unit if available, otherwise nullptr

Definition at line 915 of file ScoutingManager.cpp.

916{
917 for (auto it = observerScouts_.begin(); it != observerScouts_.end(); ++it)
918 {
919 BWAPI::Unit obs = *it;
920 if (!obs || !obs->exists())
921 continue;
922
923 const int id = obs->getID();
924
925 // 1) Remove behavior so ScoutingManager stops controlling it
926 auto bIt = behaviors_.find(id);
927 if (bIt != behaviors_.end())
928 {
929 // Let the behavior clean itself up
930 visit_onUnitDestroy(bIt->second, obs);
931 behaviors_.erase(bIt);
932 }
933
934 // 2) Release observer slot
935 releaseObserverSlot(id);
936
937 // 3) Remove from scout bookkeeping
938 observerScouts_.erase(it);
939
940 // 4) Done: return unit to combat
941 //BWAPI::Broodwar->printf("[SM] Reassigning Observer %d to combat", id);
942 return obs;
943 }
944
945 // No available observers
946 return nullptr;
947}

◆ getEnemyMain()

std::optional< BWAPI::TilePosition > ScoutingManager::getEnemyMain ( ) const
inline

Definition at line 60 of file ScoutingManager.h.

60{ return enemyMainCache_; }

◆ getEnemyNatural()

std::optional< BWAPI::TilePosition > ScoutingManager::getEnemyNatural ( ) const
inline

Definition at line 61 of file ScoutingManager.h.

61{ return enemyNaturalCache_; }

◆ hasScout()

bool ScoutingManager::hasScout ( ) const

Checks if any scouting units are currently active.

Returns
True if at least one scout exists

Definition at line 208 of file ScoutingManager.cpp.

209{
210 if (workerScout_ && workerScout_->exists())
211 {
212 return true;
213 }
214
215 for (auto u : combatZealots_)
216 {
217 if (u && u->exists())
218 {
219 return true;
220 }
221 }
222
223 for (auto u : combatDragoons_)
224 {
225 if (u && u->exists())
226 {
227 return true;
228 }
229 }
230
231 for (auto u : observerScouts_)
232 {
233 if (u && u->exists())
234 {
235 return true;
236 }
237 }
238
239 for (auto u : darkTemplarScouts_)
240 {
241 if (u && u->exists())
242 {
243 return true;
244 }
245 }
246
247 return false;
248}

◆ hasWorkerScout()

bool ScoutingManager::hasWorkerScout ( ) const

Definition at line 560 of file ScoutingManager.cpp.

560{ return workerScout_ && workerScout_->exists(); }

◆ isCombatScout()

bool ScoutingManager::isCombatScout ( BWAPI::Unit u) const

Checks if a unit is a combat scout (Zealot or Dragoon).

Parameters
uUnit to check
Returns
True if unit is a combat scout

Definition at line 550 of file ScoutingManager.cpp.

551{
552 if (!u) return false;
553 if (std::find(combatZealots_.begin(), combatZealots_.end(), u) != combatZealots_.end())
554 return true;
555 if (std::find(combatDragoons_.begin(), combatDragoons_.end(), u) != combatDragoons_.end())
556 return true;
557 return false;
558}

◆ isNearActiveCombatSquad()

bool ScoutingManager::isNearActiveCombatSquad ( BWAPI::Unit unit) const

Definition at line 863 of file ScoutingManager.cpp.

864{
865 if (!unit || !unit->exists() || !commanderRef)
866 {
867 return false;
868 }
869
870 auto nearAnySquad =
871 [&](const std::vector<Squad*>& squads) -> bool
872 {
873 for (const Squad* squad : squads)
874 {
875 if (!squad || !squad->leader || !squad->leader->exists())
876 {
877 continue;
878 }
879
880 if (unit->getDistance(squad->leader) <= kScoutReturnToCombatDistPx_)
881 {
882 return true;
883 }
884 }
885
886 return false;
887 };
888
889 if (nearAnySquad(CombatManager::AttackingSquads))
890 {
891 return true;
892 }
893
894 if (nearAnySquad(CombatManager::ReinforcingSquads))
895 {
896 return true;
897 }
898
899 return false;
900}

◆ isScout()

bool ScoutingManager::isScout ( BWAPI::Unit u) const

Checks whether a unit is currently assigned as a scout.

Parameters
uUnit to check
Returns
True if the unit is a scout

Definition at line 533 of file ScoutingManager.cpp.

534{
535 if (!u) return false;
536 if (workerScout_ == u) return true;
537 if (std::find(combatZealots_.begin(), combatZealots_.end(), u) != combatZealots_.end()) return true;
538 if (std::find(combatDragoons_.begin(), combatDragoons_.end(), u) != combatDragoons_.end()) return true;
539 if (std::find(observerScouts_.begin(), observerScouts_.end(), u) != observerScouts_.end()) return true;
540 if (std::find(darkTemplarScouts_.begin(), darkTemplarScouts_.end(), u) != darkTemplarScouts_.end()) return true;
541 return false;
542}

◆ lockCombatScoutAssignments()

void ScoutingManager::lockCombatScoutAssignments ( int frames)

Definition at line 902 of file ScoutingManager.cpp.

903{
904 const int now = BWAPI::Broodwar->getFrameCount();
905 combatScoutLockUntilFrame_ = std::max(combatScoutLockUntilFrame_, now + frames);
906}

◆ markScout()

void ScoutingManager::markScout ( BWAPI::Unit u)

Marks a unit as a scout and tracks it by type.

Adds the unit to the appropriate scouting collection.

Parameters
uUnit to mark as scout

Definition at line 440 of file ScoutingManager.cpp.

441{
442 if (!u || !u->exists()) return;
443
444 const auto t = u->getType();
445
446 if (t.isWorker()) {
447 if (!workerScout_) workerScout_ = u;
448 return;
449 }
450
451 if (t == BWAPI::UnitTypes::Protoss_Observer)
452 {
453 if (std::find(observerScouts_.begin(), observerScouts_.end(), u) == observerScouts_.end())
454 {
455 observerScouts_.push_back(u);
456 }
457 return;
458 }
459 if (t == BWAPI::UnitTypes::Protoss_Zealot) {
460 if ((int)combatZealots_.size() < maxZealotScouts_ &&
461 std::find(combatZealots_.begin(), combatZealots_.end(), u) == combatZealots_.end()) {
462 combatZealots_.push_back(u);
463 }
464 return;
465 }
466
467 if (t == BWAPI::UnitTypes::Protoss_Dragoon) {
468 if ((int)combatDragoons_.size() < maxDragoonScouts_ &&
469 std::find(combatDragoons_.begin(), combatDragoons_.end(), u) == combatDragoons_.end()) {
470 combatDragoons_.push_back(u);
471 }
472 return;
473 }
474 if (t == BWAPI::UnitTypes::Protoss_Dark_Templar)
475 {
476 if (std::find(darkTemplarScouts_.begin(), darkTemplarScouts_.end(), u) == darkTemplarScouts_.end())
477 {
478 darkTemplarScouts_.push_back(u);
479 }
480 return;
481 }
482}

◆ maybeReturnCombatScoutsToCombat()

void ScoutingManager::maybeReturnCombatScoutsToCombat ( )

Definition at line 769 of file ScoutingManager.cpp.

770{
771 std::vector<BWAPI::Unit> candidates;
772
773 candidates.reserve(combatZealots_.size() + combatDragoons_.size());
774
775 for (BWAPI::Unit u : combatZealots_)
776 {
777 if (u && u->exists())
778 {
779 candidates.push_back(u);
780 }
781 }
782
783 for (BWAPI::Unit u : combatDragoons_)
784 {
785 if (u && u->exists())
786 {
787 candidates.push_back(u);
788 }
789 }
790
791 for (BWAPI::Unit u : candidates)
792 {
793 if (!u || !u->exists())
794 {
795 continue;
796 }
797
798 if (isNearActiveCombatSquad(u))
799 {
801 }
802 }
803}
bool tryReturnScoutToCombat(BWAPI::Unit unit)
Returns a combat scout unit back to combat control.

◆ numCombatScouts()

int ScoutingManager::numCombatScouts ( ) const
inline

Definition at line 120 of file ScoutingManager.h.

121 {
122 return int(combatZealots_.size() + combatDragoons_.size());
123 }

◆ onFrame()

void ScoutingManager::onFrame ( )

Main update loop executed every frame.

Updates all active scouting behaviors and handles:

  • Deferred enemy main detection
  • Returning scouts to combat
  • Debug drawing

Definition at line 97 of file ScoutingManager.cpp.

98{
99 // iterate all active behaviors; each owns its own state
100 inBehaviorFrame_ = true;
101 for (auto& [id, sb] : behaviors_)
102 {
103 visit_frame(sb);
104 }
105 inBehaviorFrame_ = false;
106
107 if (!enemyMainCache_.has_value() && pendingEnemyMain_.has_value())
108 {
109 const auto tp = *pendingEnemyMain_;
110 pendingEnemyMain_.reset();
111 setEnemyMain(tp); // now it is safe to broadcast
112 }
113
114 maybeReturnCombatScoutsToCombat();
115
116 if (scoutingDebugEnabled_)
117 {
118 drawDebug();
119 }
120}
void drawDebug() const
Draws debug information for all scouting behaviors.
void setEnemyMain(const BWAPI::TilePosition &tp)
Sets the enemy main base location and broadcasts it to all scouts.

◆ onStart()

void ScoutingManager::onStart ( )

Called once at game start.

Used to initialize scouting systems.

Definition at line 36 of file ScoutingManager.cpp.

37{
38 //std::cout << "Scouting Manager Initialized\n";
39 //drawScoutTags();
40}

◆ onUnitDestroy()

void ScoutingManager::onUnitDestroy ( BWAPI::Unit unit)

Handles cleanup when a unit is destroyed.

Removes scouting behavior and updates tracking structures.

Parameters
unitDestroyed unit

Definition at line 310 of file ScoutingManager.cpp.

311{
312 if (!unit)
313 {
314 return;
315 }
316
317 const int id = unit->getID();
318
319 // Only do anything if it was a scout or had a behavior.
320 const bool hadBehavior = behaviors_.find(id) != behaviors_.end();
321 const bool wasScout = isScout(unit);
322
323 if (!hadBehavior && !wasScout)
324 {
325 return;
326 }
327
328 unmarkScout(unit);
329
330 if (id == proxyPatrolZealotId_)
331 {
332 proxyPatrolZealotId_ = -1;
333 }
334
335 auto it = behaviors_.find(id);
336 if (it != behaviors_.end())
337 {
338 visit_onUnitDestroy(it->second, unit);
339 behaviors_.erase(it);
340 }
341
342 releaseObserverSlot(id);
343 observerScouts_.erase(std::remove(observerScouts_.begin(), observerScouts_.end(), unit),
344 observerScouts_.end());
345
346}
void unmarkScout(BWAPI::Unit u)
Removes a unit from scout tracking structures.
bool isScout(BWAPI::Unit u) const
Checks whether a unit is currently assigned as a scout.

◆ releaseObserverSlot()

void ScoutingManager::releaseObserverSlot ( int unitId)
private

Definition at line 358 of file ScoutingManager.cpp.

359{
360 for (int i = 0; i < 4; ++i) if (observerSlotOwner_[i] == unitId) observerSlotOwner_[i] = -1;
361}

◆ reserveObserverSlot()

int ScoutingManager::reserveObserverSlot ( int unitId)
private

Definition at line 348 of file ScoutingManager.cpp.

349{
350 // priority order is 0..3; pick first free
351 for (int i = 0; i < 4; ++i)
352 {
353 if (observerSlotOwner_[i] == -1) { observerSlotOwner_[i] = unitId; return i; }
354 }
355 return -1;
356}

◆ setCombatScoutingStarted()

void ScoutingManager::setCombatScoutingStarted ( bool v)
inline

Definition at line 75 of file ScoutingManager.h.

75{ combatScoutingStarted_ = v; }

◆ setEnemyMain()

void ScoutingManager::setEnemyMain ( const BWAPI::TilePosition & tp)

Sets the enemy main base location and broadcasts it to all scouts.

If called during a behavior frame, the update is deferred to avoid modifying state mid-iteration.

Parameters
tpEnemy main tile position

Definition at line 258 of file ScoutingManager.cpp.

259{
260 if (!tp.isValid())
261 {
262 return;
263 }
264
265 // Already known: ignore duplicates
266 if (enemyMainCache_.has_value())
267 {
268 return;
269 }
270
271 // If called from inside behavior onFrame, defer the broadcast
272 if (inBehaviorFrame_)
273 {
274 pendingEnemyMain_ = tp;
275 return;
276 }
277
278 // Commit + broadcast
279 enemyMainCache_ = tp;
280
281 if (commanderRef)
282 {
283 commanderRef->onEnemyMainFound(tp);
284 }
285
286 for (auto& [id, sb] : behaviors_)
287 {
288 visit_setEnemyMain(sb, tp);
289 }
290}

◆ setEnemyNatural()

void ScoutingManager::setEnemyNatural ( const BWAPI::TilePosition & tp)

Sets the enemy natural expansion location.

Parameters
tpEnemy natural tile position

Definition at line 297 of file ScoutingManager.cpp.

298{
299 enemyNaturalCache_ = tp;
300 if (commanderRef) commanderRef->onEnemyNaturalFound(tp);
301}

◆ tryReturnScoutToCombat()

bool ScoutingManager::tryReturnScoutToCombat ( BWAPI::Unit unit)

Returns a combat scout unit back to combat control.

Removes scouting behavior and reassigns the unit to CombatManager.

Parameters
unitUnit to return
Returns
True if reassignment succeeded

Definition at line 813 of file ScoutingManager.cpp.

814{
815 if (!unit || !unit->exists() || !commanderRef)
816 {
817 return false;
818 }
819
820 const BWAPI::UnitType t = unit->getType();
821
822 // ONLY ScoutingZealot units (Zealot + Dragoon)
823 if (t != BWAPI::UnitTypes::Protoss_Zealot &&
824 t != BWAPI::UnitTypes::Protoss_Dragoon)
825 {
826 return false;
827 }
828
829 if (!isScout(unit))
830 {
831 return false;
832 }
833
834 const int id = unit->getID();
835
836 // If this was the proxy patrol unit, clear it
837 if (id == proxyPatrolZealotId_)
838 {
839 proxyPatrolZealotId_ = -1;
840 }
841
842 // Remove behavior
843 auto it = behaviors_.find(id);
844 if (it != behaviors_.end())
845 {
846 visit_onUnitDestroy(it->second, unit);
847 behaviors_.erase(it);
848 }
849
850 // Remove from scout tracking
851 unmarkScout(unit);
852
853 // Give back to combat
854 if (commanderRef->combatManager.assignUnit(unit))
855 {
856 lockCombatScoutAssignments(kCombatScoutLockFrames_);
857 return true;
858 }
859
860 return false;
861}

◆ unmarkScout()

void ScoutingManager::unmarkScout ( BWAPI::Unit u)

Removes a unit from scout tracking structures.

Parameters
uUnit to remove

Definition at line 489 of file ScoutingManager.cpp.

490{
491 if (!u) return;
492
493 if (workerScout_ == u) {
494 workerScout_ = nullptr;
495 return;
496 }
497
498 if (u->getType() == BWAPI::UnitTypes::Protoss_Zealot) {
499 combatZealots_.erase(std::remove(combatZealots_.begin(), combatZealots_.end(), u),
500 combatZealots_.end());
501 return;
502 }
503
504 if (u->getType() == BWAPI::UnitTypes::Protoss_Dragoon) {
505 combatDragoons_.erase(std::remove(combatDragoons_.begin(), combatDragoons_.end(), u),
506 combatDragoons_.end());
507 return;
508 }
509
510 if (u->getType() == BWAPI::UnitTypes::Protoss_Dark_Templar)
511 {
512 darkTemplarScouts_.erase(std::remove(darkTemplarScouts_.begin(), darkTemplarScouts_.end(), u),
513 darkTemplarScouts_.end());
514 return;
515 }
516
517 combatZealots_.erase(std::remove(combatZealots_.begin(), combatZealots_.end(), u),
518 combatZealots_.end());
519 combatDragoons_.erase(std::remove(combatDragoons_.begin(), combatDragoons_.end(), u),
520 combatDragoons_.end());
521 observerScouts_.erase(std::remove(observerScouts_.begin(), observerScouts_.end(), u),
522 observerScouts_.end());
523 darkTemplarScouts_.erase(std::remove(darkTemplarScouts_.begin(), darkTemplarScouts_.end(), u),
524 darkTemplarScouts_.end());
525}

Member Data Documentation

◆ behaviors_

std::unordered_map<int, BehaviorVariant> ScoutingManager::behaviors_
private

Definition at line 131 of file ScoutingManager.h.

◆ combatDragoons_

std::vector<BWAPI::Unit> ScoutingManager::combatDragoons_
private

Definition at line 154 of file ScoutingManager.h.

◆ combatScoutingStarted_

bool ScoutingManager::combatScoutingStarted_ { false }
private

Definition at line 139 of file ScoutingManager.h.

139{ false };

◆ combatScoutLockUntilFrame_

int ScoutingManager::combatScoutLockUntilFrame_ = 0

Definition at line 88 of file ScoutingManager.h.

◆ combatZealots_

std::vector<BWAPI::Unit> ScoutingManager::combatZealots_
private

Definition at line 153 of file ScoutingManager.h.

◆ commanderRef

ProtoBotCommander* ScoutingManager::commanderRef = nullptr
private

Definition at line 128 of file ScoutingManager.h.

◆ darkTemplarScouts_

std::vector<BWAPI::Unit> ScoutingManager::darkTemplarScouts_
private

Definition at line 165 of file ScoutingManager.h.

◆ enemyMainCache_

std::optional<BWAPI::TilePosition> ScoutingManager::enemyMainCache_
private

Definition at line 140 of file ScoutingManager.h.

◆ enemyNaturalCache_

std::optional<BWAPI::TilePosition> ScoutingManager::enemyNaturalCache_
private

Definition at line 141 of file ScoutingManager.h.

◆ inBehaviorFrame_

bool ScoutingManager::inBehaviorFrame_ = false
private

Definition at line 143 of file ScoutingManager.h.

◆ kCombatScoutLockFrames_

int ScoutingManager::kCombatScoutLockFrames_ = 24 * 10
staticconstexpr

Definition at line 90 of file ScoutingManager.h.

◆ kScoutReturnToCombatDistPx_

int ScoutingManager::kScoutReturnToCombatDistPx_ = 10 * 32
staticconstexpr

Definition at line 89 of file ScoutingManager.h.

◆ maxDragoonScouts_

int ScoutingManager::maxDragoonScouts_ { 2 }
private

Definition at line 148 of file ScoutingManager.h.

148{ 2 };

◆ maxObserverScouts_

int ScoutingManager::maxObserverScouts_ { 4 }
private

Definition at line 149 of file ScoutingManager.h.

149{ 4 };

◆ maxZealotScouts_

int ScoutingManager::maxZealotScouts_ { 2 }
private

Definition at line 147 of file ScoutingManager.h.

147{ 2 };

◆ observerScouts_

std::vector<BWAPI::Unit> ScoutingManager::observerScouts_
private

Definition at line 158 of file ScoutingManager.h.

◆ observerSlotOwner_

int ScoutingManager::observerSlotOwner_[4] = { -1, -1, -1, -1 }
private

Definition at line 159 of file ScoutingManager.h.

159{ -1, -1, -1, -1 }; // unitID or -1

◆ pendingEnemyMain_

std::optional<BWAPI::TilePosition> ScoutingManager::pendingEnemyMain_
private

Definition at line 144 of file ScoutingManager.h.

◆ proxyPatrolZealotId_

int ScoutingManager::proxyPatrolZealotId_ = -1
private

Definition at line 151 of file ScoutingManager.h.

◆ scoutingDebugEnabled_

bool ScoutingManager::scoutingDebugEnabled_ = false

Definition at line 46 of file ScoutingManager.h.

◆ scouts_

std::vector<BWAPI::Unit> ScoutingManager::scouts_
private

Definition at line 137 of file ScoutingManager.h.

◆ workerScout_

BWAPI::Unit ScoutingManager::workerScout_ { nullptr }
private

Definition at line 138 of file ScoutingManager.h.

138{ nullptr };

The documentation for this class was generated from the following files: