// STEP 3: ISSUE CONSTRUCTION ORDERS TO ASSIGN BUILDINGS AS NEEDED void BuildingManager::constructAssignedBuildings() { // for each of the buildings which have been assigned a worker buildingData.begin(ConstructionData::Assigned); while(buildingData.hasNextBuilding(ConstructionData::Assigned)) { // get a handy reference to the worker Building & b = buildingData.getNextBuilding(ConstructionData::Assigned); // if that worker is not currently constructing if (!b.builderUnit->isConstructing()) { // if we haven't explored the build position, go there if (!isBuildingPositionExplored(b)) { b.builderUnit->move(BWAPI::Position(b.finalPosition)); //BWAPI::Broodwar->printf("Can't see build position, walking there"); } // if this is not the first time we've sent this guy to build this // it must be the case that something was in the way of building else if (b.buildCommandGiven) { //BWAPI::Broodwar->printf("A builder got stuck"); // tell worker manager the unit we had is not needed now, since we might not be able // to get a valid location soon enough WorkerManager::Instance().finishedWithWorker(b.builderUnit); // free the previous location in reserved BuildingPlacer::Instance().freeTiles(b.finalPosition, b.type.tileWidth(), b.type.tileHeight()); // nullify its current builder unit b.builderUnit = NULL; // reset the build command given flag b.buildCommandGiven = false; // add the building back to be assigned buildingData.addBuilding(ConstructionData::Unassigned, b); // remove the building from Assigned buildingData.removeCurrentBuilding(ConstructionData::Assigned); } else { if (debugMode) { BWAPI::Broodwar->printf("Issuing Build Command To %s", b.type.getName().c_str()); } // issue the build order! b.builderUnit->build(b.finalPosition, b.type); // set the flag to true b.buildCommandGiven = true; } } } }
// STEP 3: ISSUE CONSTRUCTION ORDERS TO ASSIGN BUILDINGS AS NEEDED void BuildingManager::constructAssignedBuildings() { for (auto & b : m_buildings) { if (b.status != BuildingStatus::Assigned) { continue; } // TODO: not sure if this is the correct way to tell if the building is constructing sc2::AbilityID buildAbility = m_bot.Data(b.type).buildAbility; const sc2::Unit * builderUnit = m_bot.GetUnit(b.builderUnitTag); bool isConstructing = false; // if we're zerg and the builder unit is null, we assume it morphed into the building if (m_bot.GetPlayerRace(Players::Self) == sc2::Race::Zerg) { if (!builderUnit) { isConstructing = true; } } else { BOT_ASSERT(builderUnit, "null builder unit"); isConstructing = (builderUnit->orders.size() > 0) && (builderUnit->orders[0].ability_id == buildAbility); } // if that worker is not currently constructing if (!isConstructing) { // if we haven't explored the build position, go there if (!isBuildingPositionExplored(b)) { Micro::SmartMove(*builderUnit, b.finalPosition, m_bot); } // if this is not the first time we've sent this guy to build this // it must be the case that something was in the way of building else if (b.buildCommandGiven) { // TODO: in here is where we would check to see if the builder died on the way // or if things are taking too long, or the build location is no longer valid } else { // if it's a refinery, the build command has to be on the geyser unit tag if (Util::IsRefineryType(b.type)) { // first we find the geyser at the desired location UnitTag geyserTag = 0; for (auto & unit : m_bot.Observation()->GetUnits()) { if (Util::IsGeyser(unit) && Util::Dist(b.finalPosition, unit.pos) < 3) { geyserTag = unit.tag; break; } } if (geyserTag) { Micro::SmartBuildTag(b.builderUnitTag, b.type, geyserTag, m_bot); } else { std::cout << "WARNING: NO VALID GEYSER UNIT FOUND TO BUILD ON, SKIPPING REFINERY\n"; } } // if it's not a refinery, we build right on the position else { Micro::SmartBuild(b.builderUnitTag, b.type, b.finalPosition, m_bot); } // set the flag to true b.buildCommandGiven = true; } } } }