91{
92 if (opponentRaceNotKnown == true) checkForOpponentRace();
93
94 std::vector<Action> actionsToReturn;
95 PossibleRequests unitsWeCanCreate;
96
97
98 const bool buildOrderCompleted = commanderReference->buildOrderCompleted();
99
100
101 spenderManager.OnFrame(resourceRequests);
102
103 updateUnitProductionGoals();
104 updateUpgradeGoals();
105
106 planUnitProduction(unitsWeCanCreate);
107 planUpgradeProduction(unitsWeCanCreate);
108
109
110 planBuildingProduction(resourceRequests, unitsWeCanCreate);
111
112 finalizeProductionPlan(resourceRequests, unitsWeCanCreate);
113
114 if (drawStrategyDebug)
115 {
116 drawUnitProductionGoals();
117 drawUpgradeProductionGoals();
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136 const int frame = BWAPI::Broodwar->getFrameCount();
137 const int totalSeconds = frame / FRAMES_PER_SECOND;
138 const int seconds = totalSeconds % 60;
139 const int minutes = totalSeconds / 60;
140
141
142 ourIncomePerFrameMinerals = workerIncomePerFrameMinerals * activeMiners();
143 outIncomePerFrameGas = workerIncomePerFrameGas * activeDrillers();
144
145
146 std::vector<Squad*> Protobot_IdleSquads = commanderReference->combatManager.IdleSquads;
147 std::vector<Squad*> Protobot_Squads = commanderReference->combatManager.Squads;
148
149
150 int supplyThreshold = SUPPLY_THRESHOLD_EARLYGAME;
151
152 if ((seconds / 60) >= MIDGAME_TIME && (seconds / 60) < LATEGAME_TIME)
153 {
154 supplyThreshold = SUPPLY_THRESHOLD_MIDGAME;
155 }
156 else if ((seconds / 60) >= LATEGAME_TIME)
157 {
158 supplyThreshold = SUPPLY_THRESHOLD_LATEGAME;
159 }
160
161 int numberFullSquads = 0;
162
163 for (const Squad* squad : Protobot_Squads)
164 {
165 if (squad->info.units.size() == MAX_SQUAD_SIZE) numberFullSquads++;
166 }
167
168
169 const std::map<BWAPI::Unit, EnemyBuildingInfo>& enemyBuildingInfo = InformationManager::Instance().getKnownEnemyBuildings();
170
171 std::vector<BWAPI::Position> enemyBaselocations;
172 for (const auto [unit, building] : enemyBuildingInfo)
173 {
174 if (building.type.isResourceDepot())
175 {
176
177 enemyBaselocations.push_back(building.lastKnownPosition);
178 }
179 }
180
181#pragma region Scout
182
183 if (buildOrderCompleted || (BWAPI::Broodwar->self()->supplyUsed() / 2) > 15)
184 {
185
186 if (frame - frameSinceLastScout >= 24 * 20) {
187 frameSinceLastScout = frame;
188
189 Action scout;
190 scout.type = Action::ACTION_SCOUT;
191 actionsToReturn.push_back(scout);
192 }
193 }
194
195#pragma endregion
196
197#pragma region EnemyCheck
198 BWAPI::Unitset unitsOnVisison = BWAPI::Broodwar->enemy()->getUnits();
199 BWAPI::Unit unitToAttack = nullptr;
200 BWAPI::Position StartingLocation = BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation());
201 bool enemyNearFriendlyArea = false;
202 int closest = INT_MAX;
203 for (const BWAPI::Unit unit : unitsOnVisison)
204 {
205 if (!unit->exists() || unit == nullptr) {
206 continue;
207 }
208
209 if (unit->isCloaked()) {
210 continue;
211 }
212
213 const bool isPhantom = phantomPositions.find(unit->getPosition()) != phantomPositions.end();
214 if (isPhantom) {
215 continue;
216 }
217
218 const int dist = unit->getPosition().getApproxDistance(StartingLocation);
219 if (dist < closest) {
220 closest = dist;
221 unitToAttack = unit;
222 }
223 }
224
225 if (unitToAttack != nullptr) {
226 const BWEM::Area* enemyAreaLocation = theMap.GetNearestArea(unitToAttack->getTilePosition());
227 for (const BWEM::Area* area : ProtoBot_Areas)
228 {
229 if (enemyAreaLocation == area) {
230 enemyNearFriendlyArea = true;
231 break;
232 }
233 }
234 }
235#pragma endregion
236
237#pragma region Attack
238
239 const int totalSupply = BWAPI::Broodwar->self()->supplyTotal() / 2;
240 const int supplyUsed = BWAPI::Broodwar->self()->supplyUsed() / 2;
241 const int numUnits = commanderReference->combatManager.allUnits.size();
242 constexpr int targetCount = NUM_SQUADS_TO_ATTACK * MAX_SQUAD_SIZE;
243
244
245 if (supplyUsed >= MINIMUM_SUPPLY_TO_ALL_IN || numUnits > targetCount || (totalSupply == MAX_SUPPLY && supplyUsed + 1 == MAX_SUPPLY))
246 {
247 if (numUnits > (int) floor(targetCount / 3)) {
248 isAttackPhase = true;
249 BWAPI::Position attackPos = BWAPI::Positions::Invalid;
250
251 if (unitToAttack){
252 const bool isPhantom = phantomPositions.find(unitToAttack->getPosition()) != phantomPositions.end();
253
254 if (BWAPI::Broodwar->getFrameCount() % 60 == 0
255 && !isPhantom
256 && BWAPI::Broodwar->isVisible(BWAPI::TilePosition(unitToAttack->getPosition()))
257 && BWAPI::Broodwar->getUnitsOnTile(BWAPI::TilePosition(unitToAttack->getPosition()), BWAPI::Filter::IsEnemy).empty()){
258
259 phantomPositions.insert(unitToAttack->getPosition());
260 }
261 else{
262 attackPos = unitToAttack->getPosition();
263 }
264 }
265
266
267 if (attackPos == BWAPI::Positions::Invalid){
268 int closestDist = INT_MAX;
269 for (const auto& [_, enemyInfo] : InformationManager::Instance().getTrackedEnemies()) {
270 if (enemyInfo.destroyed) {
271 continue;
272 }
273
274 if (enemyInfo.type.hasPermanentCloak()) {
275 continue;
276 }
277
278
279 const bool isPhantom = phantomPositions.find(enemyInfo.lastSeenPos) != phantomPositions.end();
280
281 if (isPhantom) {
282 continue;
283 }
284
285 if (BWAPI::Broodwar->getFrameCount() % 60 == 0
286 && !isPhantom
287 && BWAPI::Broodwar->isVisible(BWAPI::TilePosition(enemyInfo.lastSeenPos))
288 && BWAPI::Broodwar->getUnitsOnTile(BWAPI::TilePosition(enemyInfo.lastSeenPos), BWAPI::Filter::IsEnemy).empty()) {
289
290 phantomPositions.insert(enemyInfo.lastSeenPos);
291 continue;
292 }
293
294 const int dist = StartingLocation.getApproxDistance(enemyInfo.lastSeenPos);
295 if (dist < closestDist) {
296 closestDist = dist;
297 attackPos = enemyInfo.lastSeenPos;
298 }
299 }
300 }
301
302
303 if (attackPos == BWAPI::Positions::Invalid && enemyBaselocations.size() > 0) {
304 attackPos = enemyBaselocations.at(enemyBaselocations.size() - 1);
305 }
306
307
308 if (attackPos != BWAPI::Positions::Invalid && attackPos != lastAttackPos) {
309 Action attack;
310 attack.type = Action::ACTION_ATTACK;
311 attack.attackPosition = attackPos;
312 actionsToReturn.push_back(attack);
313
314 lastAttackPos = attackPos;
315 }
316 }
317 else {
318 lastAttackPos = BWAPI::Positions::Invalid;
319 isAttackPhase = false;
320 }
321 }
322#pragma endregion
323
324#pragma region Defend
325 if (!isAttackPhase) {
326 if (unitToAttack != nullptr && unitToAttack->exists() && enemyNearFriendlyArea) {
327 int closestDist = 0;
328
329 Action attack;
330 attack.type = Action::ACTION_REINFORCE;
331 attack.reinforcePosition = unitToAttack->getPosition();
332 actionsToReturn.push_back(attack);
333 }
334
335 if (Protobot_IdleSquads.size() != 0)
336 {
337 int distanceToClosestChoke = INT_MAX;
338 BWAPI::WalkPosition areaToDefend = BWAPI::WalkPositions::Invalid;
339 const BWEM::ChokePoint* chokeToDefend;
340
341 for (const BWEM::ChokePoint* placement : ProtoBotArea_SquadPlacements)
342 {
343 if (PositionsFilled[placement] == false)
344 {
345 int distanceToChoke = 0;
346 const BWEM::CPPath pathToExpansion = theMap.GetPath(BWAPI::Position(BWAPI::Broodwar->self()->getStartLocation()), BWAPI::Position(placement->Center()), &distanceToChoke);
347
348 if (distanceToChoke == -1) continue;
349
350 if (distanceToChoke < distanceToClosestChoke)
351 {
352 distanceToClosestChoke = distanceToChoke;
353 areaToDefend = placement->Center();
354 chokeToDefend = placement;
355 }
356 }
357 }
358
359 if (areaToDefend != BWAPI::WalkPositions::Invalid)
360 {
361 Action defend;
362 defend.type = Action::ACTION_DEFEND;
363 defend.defendPosition = BWAPI::Position(areaToDefend);
364 actionsToReturn.push_back(defend);
365 PositionsFilled[chokeToDefend] = true;
366 }
367 }
368 }
369#pragma endregion
370
371 return actionsToReturn;
372}