BWAPI::Unit ProductionManager::getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo) { if (units.size() == 0) { return nullptr; } // if we don't care where the unit is return the first one we have if (closestTo == BWAPI::Positions::None) { return *(units.begin()); } BWAPI::Unit closestUnit = nullptr; double minDist(1000000); for (auto & unit : units) { UAB_ASSERT(unit != nullptr, "Unit was null"); double distance = unit->getDistance(closestTo); if (!closestUnit || distance < minDist) { closestUnit = unit; minDist = distance; } } return closestUnit; }
void CombatCommander::StayPut() { Squad & stayPut = _squadData.getSquad("StayPut"); // defend untill we have a science vessel if (_combatUnits.empty() || BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Science_Vessel) == 1) { return; } for (auto & unit : _combatUnits) { // get every unit of a lower priority and put it into the defense squad if (!unit->getType().isWorker() && (unit->getType() != BWAPI::UnitTypes::Zerg_Overlord) && _squadData.canAssignUnitToSquad(unit, stayPut)) { // if theres a bunker with room, go into it for (auto unit2 : BWAPI::Broodwar->self()->getUnits()){ if ((*unit2).getType() == BWAPI::UnitTypes::Terran_Bunker){ BWAPI::Unit bunker = BWAPI::Broodwar->getUnit((*unit2).getID()); BWAPI::Unitset set = bunker->getLoadedUnits(); if (set.size() < 4) { (*unit).rightClick(bunker); } } } // add units to squad _squadData.assignUnitToSquad(unit, stayPut); } } // fufill squad order SquadOrder mainAttackOrder(SquadOrderTypes::Defend, defensePos, 300, "Attack Enemy Base"); stayPut.setSquadOrder(mainAttackOrder); }
bool Squad::unitNearEnemy(BWAPI::Unit unit) { assert(unit); BWAPI::Unitset enemyNear; MapGrid::Instance().GetUnits(enemyNear, unit->getPosition(), 400, false, true); return enemyNear.size() > 0; }
std::unordered_map<BWAPI::Unit, BWAPI::Unit> RangedManager::assignEnemy(const BWAPI::Unitset &meleeUnits, BWAPI::Unitset & meleeUnitTargets) { std::unordered_map<BWAPI::Unit, BWAPI::Unit> attacker2target; std::vector<PairEdge> edges(meleeUnits.size()*meleeUnitTargets.size()); int top = 0; for (auto &attacker : meleeUnits) { for (auto &target : meleeUnitTargets) { if (!target) continue; edges[top].attacker = attacker; edges[top].target = target; int groundWeaponRange = attacker->getType().groundWeapon().maxRange(); edges[top++].distance = -getRealPriority(attacker, target); } } sort(edges.begin(), edges.end()); sort(edges.begin(), edges.end(), [](PairEdge a, PairEdge b) { return a.target->getID() <b.target->getID(); }); PairEdge dummy; dummy.target = nullptr; edges.push_back(dummy); BWAPI::Unit p = nullptr; int sum = 0; for (auto idx = edges.begin(); idx!=edges.end(); idx++) { if (!idx->target) continue; double Health = (((double)idx->target->getHitPoints() + idx->target->getShields())); if (idx->target->getType().size() == BWAPI::UnitSizeTypes::Small) Health *= 2; if (idx->target->getType().size() == BWAPI::UnitSizeTypes::Medium) Health *= 1.5; if (p != idx->target) { sum = 0; p = idx->target; } else { sum++; //assign at most 7 units attack //BWAPI::Broodwar <<( idx->target->getHitPoints()+idx->target->getShields()) / idx->attacker->getType().groundWeapon().damageAmount() << std::endl; if (sum>std::min(8, 1+(int)(Health / idx->attacker->getType().groundWeapon().damageAmount()))) { idx->attacker = nullptr; if (meleeUnitTargets.find(idx->target) != meleeUnitTargets.end()) meleeUnitTargets.erase(idx->target); } } } int t = 0; for (bool halt=false; halt == false; halt = true) { halt= true; auto tmpRangeStart = edges.begin(); auto maxRangeStart = tmpRangeStart, maxRangeEnd = tmpRangeStart; double tmpsum = 0, tmpres = INT_MIN; for (auto idx = edges.begin(); idx->target != nullptr; idx++) { if (attacker2target.find(idx->attacker) != attacker2target.end()) continue; if (idx->target != (idx + 1)->target) { if (tmpsum > tmpres) { tmpres = tmpsum; maxRangeStart = tmpRangeStart; maxRangeEnd = idx + 1; } tmpsum = 0; tmpRangeStart = idx + 1; } else tmpsum += getRealPriority(idx->attacker, idx->target); } for (auto kdx = maxRangeStart; kdx < maxRangeEnd; kdx++) { if (attacker2target.find(kdx->attacker) != attacker2target.end()) continue; attacker2target[kdx->attacker] = kdx->target; halt = false; } t++; } return attacker2target; }
BWAPI::Unit ProductionManager::getProducer(MetaType t, BWAPI::Position closestTo) { // get the type of unit that builds this BWAPI::UnitType producerType = t.whatBuilds(); // make a set of all candidate producers BWAPI::Unitset candidateProducers; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { UAB_ASSERT(unit != nullptr, "Unit was null"); // reasons a unit can not train the desired type if (unit->getType() != producerType) { continue; } if (!unit->isCompleted()) { continue; } if (unit->isTraining()) { continue; } if (unit->isLifted()) { continue; } if (!unit->isPowered()) { continue; } // if the type is an addon, some special cases if (t.getUnitType().isAddon()) { // if the unit already has an addon, it can't make one if (unit->getAddon() != nullptr) { continue; } // if we just told this unit to build an addon, then it will not be building another one // this deals with the frame-delay of telling a unit to build an addon and it actually starting to build if (unit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Build_Addon && (BWAPI::Broodwar->getFrameCount() - unit->getLastCommandFrame() < 10)) { continue; } bool isBlocked = false; // if the unit doesn't have space to build an addon, it can't make one BWAPI::TilePosition addonPosition(unit->getTilePosition().x + unit->getType().tileWidth(), unit->getTilePosition().y + unit->getType().tileHeight() - t.getUnitType().tileHeight()); BWAPI::Broodwar->drawBoxMap(addonPosition.x*32, addonPosition.y*32, addonPosition.x*32 + 64, addonPosition.y*32 + 64, BWAPI::Colors::Red); for (int i=0; i<unit->getType().tileWidth() + t.getUnitType().tileWidth(); ++i) { for (int j=0; j<unit->getType().tileHeight(); ++j) { BWAPI::TilePosition tilePos(unit->getTilePosition().x + i, unit->getTilePosition().y + j); // if the map won't let you build here, we can't build it if (!BWAPI::Broodwar->isBuildable(tilePos)) { isBlocked = true; BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red); } // if there are any units on the addon tile, we can't build it BWAPI::Unitset uot = BWAPI::Broodwar->getUnitsOnTile(tilePos.x, tilePos.y); if (uot.size() > 0 && !(uot.size() == 1 && *(uot.begin()) == unit)) { isBlocked = true;; BWAPI::Broodwar->drawBoxMap(tilePos.x*32, tilePos.y*32, tilePos.x*32 + 32, tilePos.y*32 + 32, BWAPI::Colors::Red); } } } if (isBlocked) { continue; } } // if the type requires an addon and the producer doesn't have one typedef std::pair<BWAPI::UnitType, int> ReqPair; for (const ReqPair & pair : t.getUnitType().requiredUnits()) { BWAPI::UnitType requiredType = pair.first; if (requiredType.isAddon()) { if (!unit->getAddon() || (unit->getAddon()->getType() != requiredType)) { continue; } } } // if we haven't cut it, add it to the set of candidates candidateProducers.insert(unit); } return getClosestUnitToPosition(candidateProducers, closestTo); }
int LurkerManager::targetsInRange(BWAPI::Unit LurkerUnit, const BWAPI::Unitset & targets) { BWAPI::Unitset nearbyEnemies; MapGrid::Instance().GetUnits(nearbyEnemies, LurkerUnit->getPosition() , BWAPI::UnitTypes::Zerg_Lurker.seekRange() + 10, false, true); return nearbyEnemies.size(); }
std::unordered_map<BWAPI::Unit, BWAPI::Unit> InterceptorManager::assignEnemy(const BWAPI::Unitset &meleeUnits, const BWAPI::Unitset & meleeUnitTargets) { std::unordered_map<BWAPI::Unit, BWAPI::Unit> attacker2target; std::vector<PairEdge> edges(meleeUnits.size()*meleeUnitTargets.size()); int top = 0; for (auto &attacker : meleeUnits) { for (auto &target : meleeUnitTargets) { edges[top].attacker = attacker; edges[top].target = target; int groundWeaponRange = attacker->getType().groundWeapon().maxRange(); edges[top++].distance = -getRealPriority(attacker, target); } } sort(edges.begin(), edges.end()); edges.resize(edges.size()*3/4); sort(edges.begin(), edges.end(), [](PairEdge a, PairEdge b) { return (int)a.target < (int)b.target; }); PairEdge dummy; dummy.target = nullptr; edges.push_back(dummy); BWAPI::Unit p = nullptr; int sum = 0; for (auto idx = edges.begin(); idx->target != nullptr; idx++) { if (p != idx->target) { sum = 0; p = idx->target; } else { sum++; //assign at most 7 units attack //BWAPI::Broodwar <<( idx->target->getHitPoints()+idx->target->getShields()) / idx->attacker->getType().groundWeapon().damageAmount() << std::endl; int damagePerUnit = idx->attacker->getType().groundWeapon().damageAmount(); if (sum<std::min(6, std::max(2*idx->target->getHitPoints() / idx->attacker->getType().groundWeapon().damageAmount() - 1, 1))) { idx->attacker = nullptr; } } } for (bool halt = true; halt == false; halt = true) { auto tmpRangeStart = edges.begin(); auto maxRangeStart = tmpRangeStart, maxRangeEnd = tmpRangeStart; double tmpsum = 0, tmpres = INT_MIN; for (auto idx = edges.begin(); idx->target != nullptr; idx++) { if (attacker2target.find(idx->attacker) != attacker2target.end()) continue; if (idx->target != (idx + 1)->target) { if (tmpsum > tmpres) { tmpres = tmpsum; maxRangeStart = tmpRangeStart; maxRangeEnd = idx + 1; } tmpsum = 0; tmpRangeStart = idx + 1; } else tmpsum += getRealPriority(idx->attacker, idx->target); } for (auto kdx = maxRangeStart; kdx != maxRangeEnd; kdx++) { if (attacker2target.find(kdx->attacker) != attacker2target.end()) continue; attacker2target[kdx->attacker] = kdx->target; halt = false; } } return attacker2target; }
void CombatCommander::updateScoutDefenseSquad() { if (_combatUnits.empty()) { return; } // if the current squad has units in it then we can ignore this Squad & scoutDefenseSquad = _squadData.getSquad("ScoutDefense"); // get the region that our base is located in BWTA::Region * myRegion = BWTA::getRegion(BWAPI::Broodwar->self()->getStartLocation()); if (!myRegion && myRegion->getCenter().isValid()) { return; } // get all of the enemy units in this region BWAPI::Unitset enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (BWTA::getRegion(BWAPI::TilePosition(unit->getPosition())) == myRegion) { enemyUnitsInRegion.insert(unit); } } // if there's an enemy worker in our region then assign someone to chase him bool assignScoutDefender = enemyUnitsInRegion.size() == 1 && (*enemyUnitsInRegion.begin())->getType().isWorker(); // if our current squad is empty and we should assign a worker, do it if (scoutDefenseSquad.isEmpty() && assignScoutDefender) { // the enemy worker that is attacking us BWAPI::Unit enemyWorker = *enemyUnitsInRegion.begin(); // get our worker unit that is mining that is closest to it BWAPI::Unit workerDefender = findClosestWorkerToTarget(_combatUnits, enemyWorker); if (enemyWorker && workerDefender) { // grab it from the worker manager and put it in the squad if (_squadData.canAssignUnitToSquad(workerDefender, scoutDefenseSquad)) { WorkerManager::Instance().setCombatWorker(workerDefender); _squadData.assignUnitToSquad(workerDefender, scoutDefenseSquad); } } } // if our squad is not empty and we shouldn't have a worker chasing then take him out of the squad else if (!scoutDefenseSquad.isEmpty() && !assignScoutDefender) { for (auto & unit : scoutDefenseSquad.getUnits()) { unit->stop(); if (unit->getType().isWorker()) { WorkerManager::Instance().finishedWithWorker(unit); } } scoutDefenseSquad.clear(); } }
//dist is distance between middle unit and target gravity center, interval is length of arc between two units bool MicroManager::formSquad(const BWAPI::Unitset & targets, int dist, int radius, double angle, int interval) { const BWAPI::Unitset & meleeUnits = getUnits(); bool attacked = false; BWAPI::Position tpos = targets.getPosition(); BWAPI::Position mpos = meleeUnits.getPosition(); //do not from squad when fighting or close to enemy for (auto & unit : meleeUnits){ if (unit->isUnderAttack() || unit->isAttackFrame() || targets.size() == 0|| unit->getDistance(tpos) < 80) attacked = true; } if (attacked) { BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Attacked or No targets, Stop Formation"); return false; } //if there is a building near the unit, do not form for (auto & target : targets){ auto type = target->getType(); if (type.isBuilding()){ return false; } } //Formation is set false by Squad for 5 seconds after formation finished once if (!getFormation()){ BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Finished Formation"); return false; } //BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Forming"); const double PI = 3.14159265; double ang = angle / 180 * PI; //the angle of mid_point on arc double m_ang = atan2(mpos.y - tpos.y, mpos.x - tpos.x); //circle center int cx = (int)(tpos.x - (radius-dist) * cos(m_ang)); int cy = (int)(tpos.y - (radius-dist) * sin(m_ang)); BWAPI::Position c; c.x = cx; c.y = cy; //mid_point on arc BWAPI::Position m; m.x = (int)(cx + radius*cos(m_ang)); m.y = (int)(cy + radius*sin(m_ang)); BWAPI::Broodwar->drawLineMap(c, m, BWAPI::Colors::Yellow); BWAPI::Unitset unassigned; for (auto & unit : meleeUnits){ unassigned.insert(unit); } //move every positions on the arc to the closest unit BWAPI::Position tmp; int try_time = 0; int r = radius; int total_dest_dist = 0; int num_assigned = 0; while (unassigned.size() > 0 && try_time < 5){ double ang_interval = interval * 1.0 / r; double final_ang; int num_to_assign; int max_units = (int)(ang / ang_interval) + 1; if (unassigned.size() < (unsigned)max_units){ num_to_assign = unassigned.size(); final_ang = ang_interval * num_to_assign; } else { num_to_assign = max_units; final_ang = ang; } for (int i = 0; i < num_to_assign; i++) { //assign from two ends to middle double a = m_ang + pow(-1, i % 2)*(final_ang / 2 - (i / 2)*ang_interval); int min_dist = MAXINT; BWAPI::Unit closest_unit = nullptr; tmp.x = (int)(cx + r * cos(a)); tmp.y = (int)(cy + r * sin(a)); for (auto & unit : unassigned){ int d = unit->getDistance(tmp); if (d < min_dist){ min_dist = d; closest_unit = unit; } } //if it's a unit far away from fight, do not assign it to a position if (closest_unit && min_dist > 300){ unassigned.erase(closest_unit); continue; } if (tmp.isValid() && closest_unit){ BWAPI::Broodwar->drawLineMap(closest_unit->getPosition(), tmp, BWAPI::Colors::Red); Micro::SmartMove(closest_unit, tmp); unassigned.erase(closest_unit); //find the total distance between unit and destination total_dest_dist += min_dist; num_assigned++; } } r += 40; try_time++; } //if max destination distance less than 32, means forming has been finished if (num_assigned > 0 && total_dest_dist / num_assigned <= 32){ return true; } else { BWAPI::Broodwar->drawTextScreen(200, 340, "%s", "Forming"); return false; } }
BWAPI::Unit ProductionManager::getClosestUnitToPosition(const BWAPI::Unitset & units, BWAPI::Position closestTo) { if (units.size() == 0) { return nullptr; } // if we don't care where the unit is return the first one we have if (closestTo == BWAPI::Positions::None) { return *(units.begin()); } BWAPI::Unit closestUnit = nullptr; double minDist(1000000); /* bool makeFirstSunken = false; if (!BuildingManager::Instance().isCreepStarted()) { BWAPI::TilePosition myHatchPos = BuildingManager::Instance().createdHatcheriesVector[0]; if (closestTo == BWAPI::Position(myHatchPos)) { makeFirstSunken = true; BWAPI::Unitset myUnits = BWAPI::Broodwar->self()->getUnits(); for (auto & unit : myUnits) { if (unit->getID() == BuildingManager::Instance().sunkenID) { return unit; } } //return BWAPI::Unit(BuildingManager::Instance().sunkenID); } } /* std::vector<BWAPI::TilePosition> myUnitsTile; std::vector<BWAPI::Position> myUnitsPosition; std::vector<BWAPI::TilePosition> myUnitsTile2; std::vector<BWAPI::Position> myUnitsPosition2; for (auto & unit : units) { myUnitsTile.push_back(unit->getTilePosition()); myUnitsPosition.push_back(unit->getPosition()); } BWAPI::Unitset myUnits = BWAPI::Broodwar->self()->getUnits(); for (BWAPI::Unit p : myUnits) { if (p->getType().isWorker()) { myUnitsTile2.push_back(p->getTilePosition()); myUnitsPosition2.push_back(p->getPosition()); } } */ for (auto & unit : units) { /** if (makeFirstSunken) { BWAPI::TilePosition myHatchPos = BuildingManager::Instance().createdHatcheriesVector[0]; BWAPI::TilePosition tempPosition; tempPosition.x = myHatchPos.x+2; tempPosition.y = myHatchPos.y+2; if (tempPosition == unit->getTilePosition()) { return unit; } } */ UAB_ASSERT(unit != nullptr, "Unit was null"); double distance = unit->getDistance(closestTo); if (!closestUnit || distance < minDist) { closestUnit = unit; minDist = distance; } } //BWAPI::TilePosition myHatchPos = BuildingManager::Instance().createdHatcheriesVector[0]; //BWAPI::TilePosition finalTilePos = closestUnit->getTilePosition(); return closestUnit; }