BWAPI::Unitset WorkerData::getMineralPatchesNearDepot(BWAPI::Unit depot) { // if there are minerals near the depot, add them to the set BWAPI::Unitset mineralsNearDepot; int radius = 300; for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field) && unit->getDistance(depot) < radius) { mineralsNearDepot.insert(unit); } } // if we didn't find any, use the whole map if (mineralsNearDepot.empty()) { for (auto & unit : BWAPI::Broodwar->getAllUnits()) { if ((unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)) { mineralsNearDepot.insert(unit); } } } return mineralsNearDepot; }
bool ScoutManager::immediateThreat() { BWAPI::Unitset enemyAttackingWorkers; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getType().isWorker() && unit->isAttacking()) { enemyAttackingWorkers.insert(unit); } } if (_workerScout->isUnderAttack()) { return true; } for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { double dist = unit->getDistance(_workerScout); double range = unit->getType().groundWeapon().maxRange(); if (unit->getType().canAttack() && !unit->getType().isWorker() && (dist <= range + 32)) { return true; } } return false; }
void BuildingPlacer::computeResourceBox() { BWAPI::Position start(BWAPI::Broodwar->self()->getStartLocation()); BWAPI::Unitset unitsAroundNexus; for (auto & unit : BWAPI::Broodwar->getAllUnits()) { // if the units are less than 400 away add them if they are resources if (unit->getDistance(start) < 300 && unit->getType().isMineralField()) { unitsAroundNexus.insert(unit); } } for (auto & unit : unitsAroundNexus) { int x = unit->getPosition().x; int y = unit->getPosition().y; int left = x - unit->getType().dimensionLeft(); int right = x + unit->getType().dimensionRight() + 1; int top = y - unit->getType().dimensionUp(); int bottom = y + unit->getType().dimensionDown() + 1; _boxTop = top < _boxTop ? top : _boxTop; _boxBottom = bottom > _boxBottom ? bottom : _boxBottom; _boxLeft = left < _boxLeft ? left : _boxLeft; _boxRight = right > _boxRight ? right : _boxRight; } //BWAPI::Broodwar->printf("%d %d %d %d", boxTop, boxBottom, boxLeft, boxRight); }
void GameCommander::assignUnit(BWAPI::Unit unit, BWAPI::Unitset & set) { if (_scoutUnits.contains(unit)) { _scoutUnits.erase(unit); } else if (_combatUnits.contains(unit)) { _combatUnits.erase(unit); } set.insert(unit); }
void MedicManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & medics = getUnits(); // create a set of all medic targets BWAPI::Unitset medicTargets; for (auto & unit : BWAPI::Broodwar->self()->getUnits()) { if (unit->getHitPoints() < unit->getInitialHitPoints() && !unit->getType().isMechanical() && !unit->getType().isBuilding()) { medicTargets.insert(unit); } } BWAPI::Unitset availableMedics(medics); // for each target, send the closest medic to heal it for (auto & target : medicTargets) { // only one medic can heal a target at a time if (target->isBeingHealed()) { continue; } double closestMedicDist = std::numeric_limits<double>::infinity(); BWAPI::Unit closestMedic = nullptr; for (auto & medic : availableMedics) { double dist = medic->getDistance(target); if (!closestMedic || (dist < closestMedicDist)) { closestMedic = medic; closestMedicDist = dist; } } // if we found a medic, send it to heal the target if (closestMedic) { closestMedic->useTech(BWAPI::TechTypes::Healing, target); availableMedics.erase(closestMedic); } // otherwise we didn't find a medic which means they're all in use so break else { break; } } // the remaining medics should head to the squad order position for (auto & medic : availableMedics) { Micro::SmartAttackMove(medic, order.getPosition()); } }
// get a target for the zealot to attack BWAPI::Unit TankManager::getTarget(BWAPI::Unit tank, const BWAPI::Unitset & targets) { int bestPriorityDistance = 1000000; int bestPriority = 0; double bestLTD = 0; BWAPI::Unit bestTargetThreatInRange = nullptr; double bestTargetThreatInRangeLTD = 0; int highPriority = 0; double closestDist = std::numeric_limits<double>::infinity(); BWAPI::Unit closestTarget = nullptr; int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32; BWAPI::Unitset targetsInSiegeRange; for (auto & target : targets) { if (target->getDistance(tank) < siegeTankRange && UnitUtil::CanAttack(tank, target)) { targetsInSiegeRange.insert(target); } } const BWAPI::Unitset & newTargets = targetsInSiegeRange.empty() ? targets : targetsInSiegeRange; // check first for units that are in range of our attack that can cause damage // choose the highest priority one from them at the lowest health for (const auto & target : newTargets) { if (!UnitUtil::CanAttack(tank, target)) { continue; } double distance = tank->getDistance(target); double LTD = UnitUtil::CalculateLTD(target, tank); int priority = getAttackPriority(tank, target); bool targetIsThreat = LTD > 0; BWAPI::Broodwar->drawTextMap(target->getPosition(), "%d", priority); if (!closestTarget || (priority > highPriority) || (priority == highPriority && distance < closestDist)) { closestDist = distance; highPriority = priority; closestTarget = target; } } if (bestTargetThreatInRange) { return bestTargetThreatInRange; } return closestTarget; }
void Squad::addUnitsToMicroManagers() { BWAPI::Unitset meleeUnits; BWAPI::Unitset rangedUnits; BWAPI::Unitset detectorUnits; BWAPI::Unitset transportUnits; BWAPI::Unitset tankUnits; BWAPI::Unitset medicUnits; BWAPI::Unitset scienceVessels; // add _units to micro managers for (auto & unit : _units) { if(unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists()) { // select dector _units if (unit->getType() == BWAPI::UnitTypes::Terran_Medic) { medicUnits.insert(unit); } else if (unit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel) { scienceVessels.insert(unit); } else if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode) { tankUnits.insert(unit); } else if (unit->getType().isDetector() && !unit->getType().isBuilding()) { detectorUnits.insert(unit); } // select transport _units else if (unit->getType() == BWAPI::UnitTypes::Protoss_Shuttle || unit->getType() == BWAPI::UnitTypes::Terran_Dropship) { transportUnits.insert(unit); } // select ranged _units else if ((unit->getType().groundWeapon().maxRange() > 32) || (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) || (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge)) { rangedUnits.insert(unit); } // select melee _units else if (unit->getType().groundWeapon().maxRange() <= 32) { meleeUnits.insert(unit); } } } _meleeManager.setUnits(meleeUnits); _rangedManager.setUnits(rangedUnits); _detectorManager.setUnits(detectorUnits); _transportManager.setUnits(transportUnits); _tankManager.setUnits(tankUnits); _medicManager.setUnits(medicUnits); _sciencevesselManager.setUnits(scienceVessels); }
void InterceptorManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && !(target->getType() == BWAPI::UnitTypes::Buildings) && (target->isTargetable()) && target->isVisible() && target->getType() != BWAPI::UnitTypes::Resource_Vespene_Geyser) { rangedUnitTargets.insert(target); } } auto attacker2target = assignEnemy(rangedUnits, rangedUnitTargets); BWAPI::Position shome = BWAPI::Position(BWTA::getStartLocation(BWAPI::Broodwar->self())->getPosition()); for (auto & rangedUnit : rangedUnits) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); // if the order is to attack or defend if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!rangedUnitTargets.empty()) { // find the best target for this zealot auto targetIdx = attacker2target.find(rangedUnit); BWAPI::Unit target = targetIdx == attacker2target.end() ? getTarget(rangedUnit, rangedUnitTargets) : targetIdx->first; if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(rangedUnit->getPosition(), rangedUnit->getTargetPosition(), BWAPI::Colors::Purple); } Micro::SmartAttackUnit(rangedUnit, target); } // if there are no targets else { // if we're not near the order position if (rangedUnit->getDistance(order.getPosition()) > 100) { // move to it Micro::SmartAttackMove(rangedUnit, order.getPosition()); } } } } }
void Squad::setAllUnits() { // clean up the _units vector just in case one of them died BWAPI::Unitset goodUnits; for (auto & unit : _units) { if( unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists() && unit->getPosition().isValid() && unit->getType() != BWAPI::UnitTypes::Unknown) { goodUnits.insert(unit); } } _units = goodUnits; }
void SquadData::verifySquadUniqueMembership() { BWAPI::Unitset assigned; for (const auto & kv : _squads) { for (auto & unit : kv.second.getUnits()) { if (assigned.contains(unit)) { BWAPI::Broodwar->printf("Unit is in at least two squads: %s", unit->getType().getName().c_str()); } assigned.insert(unit); } } }
// still has bug in it somewhere, use Old version void MeleeManager::assignTargetsNew(const BWAPI::Unitset & targets) { const BWAPI::Unitset & meleeUnits = getUnits(); // figure out targets BWAPI::Unitset meleeUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType().isFlyer()) && !(target->isLifted()) && !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && target->isVisible()) { meleeUnitTargets.insert(target); } } BWAPI::Unitset meleeUnitsToAssign(meleeUnits); std::map<BWAPI::Unit, int> attackersAssigned; for (auto & unit : meleeUnitTargets) { attackersAssigned[unit] = 0; } int smallThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 3 : 1; int bigThreshold = BWAPI::Broodwar->self()->getRace() == BWAPI::Races::Zerg ? 12 : 3; // keep assigning targets while we have attackers and targets remaining while (!meleeUnitsToAssign.empty() && !meleeUnitTargets.empty()) { auto attackerAssignment = findClosestUnitPair(meleeUnitsToAssign, meleeUnitTargets); BWAPI::Unit & attacker = attackerAssignment.first; BWAPI::Unit & target = attackerAssignment.second; UAB_ASSERT_WARNING(attacker, "We should have chosen an attacker!"); if (!attacker) { break; } if (!target) { Micro::SmartMove(attacker, order.getPosition()); continue; } Micro::SmartAttackUnit(attacker, target); // update the number of units assigned to attack the target we found int & assigned = attackersAssigned[attackerAssignment.second]; assigned++; // if it's a small / fast unit and there's more than 2 things attacking it already, don't assign more if ((target->getType().isWorker() || target->getType() == BWAPI::UnitTypes::Zerg_Zergling) && (assigned >= smallThreshold)) { meleeUnitTargets.erase(target); } // if it's a building and there's more than 10 things assigned to it already, don't assign more else if (assigned > bigThreshold) { meleeUnitTargets.erase(target); } meleeUnitsToAssign.erase(attacker); } // if there's no targets left, attack move to the order destination if (meleeUnitTargets.empty()) { for (auto & unit : meleeUnitsToAssign) { if (unit->getDistance(order.getPosition()) > 100) { // move to it Micro::SmartMove(unit, order.getPosition()); BWAPI::Broodwar->drawLineMap(unit->getPosition(), order.getPosition(), BWAPI::Colors::Yellow); } } } }
void Squad::addUnitsToMicroManagers() { BWAPI::Unitset meleeUnits; BWAPI::Unitset rangedUnits; BWAPI::Unitset detectorUnits; BWAPI::Unitset transportUnits; BWAPI::Unitset tankUnits; BWAPI::Unitset medicUnits; BWAPI::Unitset lurkerUnits; BWAPI::Unitset zerglingUnits; // add _units to micro managers for (auto & unit : _units) { if(unit->isCompleted() && unit->getHitPoints() > 0 && unit->exists()) { // Special Unit Types // Medics if (unit->getType() == BWAPI::UnitTypes::Terran_Medic) { medicUnits.insert(unit); } // Tanks else if (unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || unit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode) { tankUnits.insert(unit); } // Lurkers else if (unit->getType() == BWAPI::UnitTypes::Zerg_Lurker) { lurkerUnits.insert(unit); } /*else if (unit->getType() == BWAPI::UnitTypes::Zerg_Zergling) { zerglingUnits.insert(unit); }*/ // Detectors else if (unit->getType().isDetector() && !unit->getType().isBuilding()) { detectorUnits.insert(unit); } // Transporters else if (unit->getType() == BWAPI::UnitTypes::Protoss_Shuttle || unit->getType() == BWAPI::UnitTypes::Terran_Dropship) { transportUnits.insert(unit); } // Ranged Units else if ((unit->getType().groundWeapon().maxRange() > 32) || (unit->getType() == BWAPI::UnitTypes::Protoss_Reaver) || (unit->getType() == BWAPI::UnitTypes::Zerg_Scourge)) { rangedUnits.insert(unit); } // Melee Units else if (unit->getType().groundWeapon().maxRange() <= 32) { meleeUnits.insert(unit); } } } _meleeManager.setUnits(meleeUnits); _rangedManager.setUnits(rangedUnits); _detectorManager.setUnits(detectorUnits); _transportManager.setUnits(transportUnits); _tankManager.setUnits(tankUnits); _medicManager.setUnits(medicUnits); _lurkerManager.setUnits(lurkerUnits); _zerglingManager.setUnits(zerglingUnits); }
void RangedManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && !(target->getType() == BWAPI::UnitTypes::Buildings) && (target->isTargetable()) && target->isVisible() && target->getType() != BWAPI::UnitTypes::Resource_Vespene_Geyser) { rangedUnitTargets.insert(target); } } auto attacker2target = assignEnemy(rangedUnits, rangedUnitTargets); BWAPI::Position shome = BWAPI::Position(BWTA::getStartLocation(BWAPI::Broodwar->self())->getPosition()); BWAPI::Unitset _rangedUnits = rangedUnits; auto _rangedUnitTargets = rangedUnitTargets; int maxChoices = rangedUnits.size() / 3 + 1, i = 0; std::map<BWAPI::Unit, std::pair<BWAPI::Unit, BWAPI::Unit> > dodgeUnits; BWAPI::Unitset threatens; for (BWAPI::Unit threatenClosest = NULL, unitClosetEnemy = NULL;;) { if (i++ > maxChoices) break; double dist = BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge)?96:96; double enerange = BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Singularity_Charge) ? 80 : 80; for (auto & rangedUnit : _rangedUnits) { for (auto target : _rangedUnitTargets) { if (target->getType().isWorker() || (target->getType().isBuilding())) continue; if (target->getType().groundWeapon().maxRange() <= enerange) { if (rangedUnit->getDistance(target) < dist) { threatenClosest = target; unitClosetEnemy = rangedUnit; dist = rangedUnit->getDistance(target); } } } } if (threatenClosest != NULL) { threatens.insert(threatenClosest); BWAPI::Broodwar->drawCircleMap(threatenClosest->getPosition(), 2, BWAPI::Colors::Red, true); auto vec1 = unitClosetEnemy->getPosition() - threatenClosest->getPosition(); dodgeUnits[unitClosetEnemy] = std::make_pair(unitClosetEnemy, threatenClosest); auto __rangedUnits = rangedUnits; for (auto rangedUnit:__rangedUnits) { if (rangedUnit->getDistance(unitClosetEnemy) > unitClosetEnemy->getDistance(threatenClosest)+64) continue; auto vec2 = rangedUnit->getPosition() - threatenClosest->getPosition(); int judge = (vec1.x*vec2.x + vec1.y*vec2.y)*(vec1.x*vec2.x + vec1.y*vec2.y); if (judge * 6 > (vec1.x*vec1.x + vec1.y*vec1.y)*(vec2.x*vec2.x + vec2.y*vec2.y) * 5) { dodgeUnits[rangedUnit] = std::make_pair(unitClosetEnemy, threatenClosest); _rangedUnits.erase(rangedUnit); } } } else break; } BWAPI::Unitset withoutBuildingsAndWorkers = rangedUnitTargets; auto _withoutBuildingsAndWorkers = withoutBuildingsAndWorkers; for (auto target : _withoutBuildingsAndWorkers) if (target->getType().isBuilding() || target->getType().isWorker()) withoutBuildingsAndWorkers.erase(target); for (auto & rangedUnit : rangedUnits) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); // if the order is to attack or defend int chokeZealot = 0; for (const auto & zealot : BWAPI::Broodwar->self()->getUnits()) { // trivial case: unit which exists matches the type if (zealot->getType() != BWAPI::UnitTypes::Protoss_Zealot) continue; if (zealot->isCompleted() == false) continue; auto ckpt = BWTA::getNearestChokepoint(zealot->getPosition()); if (zealot->getDistance(rangedUnit->getPosition()) < 300) { if (ckpt && ckpt->getWidth()<256 && ckpt->getCenter().getDistance(zealot->getPosition()) < 128) chokeZealot += 3; else chokeZealot += 1; } } bool danceMode; if (order.getType() == SquadOrderTypes::Defend) danceMode = chokeZealot < 3 && rangedUnits.size()<20; else danceMode = chokeZealot < 3 && rangedUnits.size()<20; if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!rangedUnitTargets.empty()) { // find the best target for this zealot auto targetIdx = attacker2target.find(rangedUnit); BWAPI::Unit target = targetIdx == attacker2target.end() ? getTarget(rangedUnit, rangedUnitTargets) : targetIdx->second; // attack it if (dodgeUnits.find(rangedUnit) == dodgeUnits.end()) { Micro::SmartAttackUnit(rangedUnit, target); } else { if (danceMode) Micro::SmartKiteTarget(rangedUnit, target, dodgeUnits[rangedUnit].second, withoutBuildingsAndWorkers); else Micro::SmartAttackUnit(rangedUnit, target); //modified //BWAPI::Broodwar->sendText("%s", "old kite"); //Micro::SmartKiteTarget(rangedUnit, dodgeUnits[rangedUnit].second); } } // if there are no targets else { Micro::SmartAttackMove(rangedUnit, order.getPosition()); } } } }
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); }
void MeleeManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & meleeUnits = getUnits(); // figure out targets BWAPI::Unitset meleeUnitTargets; for (auto & target : targets) { // conditions for targeting if (!(target->getType().isFlyer()) && !(target->isLifted()) && !(target->getType() == BWAPI::UnitTypes::Zerg_Larva) && !(target->getType() == BWAPI::UnitTypes::Zerg_Egg) && !(target->getType() == BWAPI::UnitTypes::Buildings)&& (target->isTargetable())&& target->isVisible()) { meleeUnitTargets.insert(target); } } std::unordered_map<BWAPI::Unit, BWAPI::Unit> attacker2target = assignEnemy(meleeUnits,meleeUnitTargets); // for each meleeUnit for (auto & meleeUnit : meleeUnits) { // if the order is to attack or defend if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // run away if we meet the retreat critereon if (meleeUnitShouldRetreat(meleeUnit, targets) && meleeUnit->isUnderAttack()) { BWAPI::Position fleeTo(pullPosition); fleeTo.x = (fleeTo.x - meleeUnit->getPosition().x)*2 + meleeUnit->getPosition().x; fleeTo.y = (fleeTo.y - meleeUnit->getPosition().y)*2 + meleeUnit->getPosition().y; Micro::SmartMove(meleeUnit, fleeTo); } // if there are targets else if (!meleeUnitTargets.empty()) { BWAPI::Unit target; if (attacker2target.find(meleeUnit) != attacker2target.end()) { target = attacker2target[meleeUnit]; } else target = getTarget(meleeUnit, meleeUnitTargets); Micro::SmartAttackUnit(meleeUnit, target); } // if there are no targets else { // if we're not near the order position if (meleeUnit->getDistance(order.getPosition()) > 100) { // move to it Micro::SmartMove(meleeUnit, order.getPosition()); } } } if (Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(meleeUnit->getPosition().x, meleeUnit->getPosition().y, meleeUnit->getTargetPosition().x, meleeUnit->getTargetPosition().y, Config::Debug::ColorLineTarget); } } }
void CombatCommander::updateDefenseSquads() { if (_combatUnits.empty() || BWAPI::Broodwar->self()->allUnitCount(BWAPI::UnitTypes::Terran_Science_Vessel) == 1) { return; } BWTA::BaseLocation * enemyBaseLocation = InformationManager::Instance().getMainBaseLocation(BWAPI::Broodwar->enemy()); BWTA::Region * enemyRegion = nullptr; if (enemyBaseLocation) { enemyRegion = BWTA::getRegion(enemyBaseLocation->getPosition()); } // for each of our occupied regions for (BWTA::Region * myRegion : InformationManager::Instance().getOccupiedRegions(BWAPI::Broodwar->self())) { // don't defend inside the enemy region, this will end badly when we are stealing gas if (myRegion == enemyRegion) { continue; } BWAPI::Position regionCenter = myRegion->getCenter(); if (!regionCenter.isValid()) { continue; } // start off assuming all enemy units in region are just workers int numDefendersPerEnemyUnit = 2; // all of the enemy units in this region BWAPI::Unitset enemyUnitsInRegion; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { // if it's an overlord, don't worry about it for defense, we don't care what they see if (unit->getType() == BWAPI::UnitTypes::Zerg_Overlord) { continue; } if (BWTA::getRegion(BWAPI::TilePosition(unit->getPosition())) == myRegion) { enemyUnitsInRegion.insert(unit); } } // we can ignore the first enemy worker in our region since we assume it is a scout for (auto & unit : enemyUnitsInRegion) { if (unit->getType().isWorker()) { enemyUnitsInRegion.erase(unit); break; } } int numEnemyFlyingInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return u->isFlying(); }); int numEnemyGroundInRegion = std::count_if(enemyUnitsInRegion.begin(), enemyUnitsInRegion.end(), [](BWAPI::Unit u) { return !u->isFlying(); }); std::stringstream squadName; squadName << "Base Defense " << regionCenter.x << " " << regionCenter.y; // if there's nothing in this region to worry about if (enemyUnitsInRegion.empty()) { // if a defense squad for this region exists, remove it if (_squadData.squadExists(squadName.str())) { _squadData.getSquad(squadName.str()).clear(); } // and return, nothing to defend here continue; } else { // if we don't have a squad assigned to this region already, create one if (!_squadData.squadExists(squadName.str())) { SquadOrder defendRegion(SquadOrderTypes::Defend, regionCenter, 32 * 25, "Defend Region!"); _squadData.addSquad(squadName.str(), Squad(squadName.str(), defendRegion, BaseDefensePriority)); } } // assign units to the squad if (_squadData.squadExists(squadName.str())) { Squad & defenseSquad = _squadData.getSquad(squadName.str()); // figure out how many units we need on defense int flyingDefendersNeeded = numDefendersPerEnemyUnit * numEnemyFlyingInRegion; int groundDefensersNeeded = numDefendersPerEnemyUnit * numEnemyGroundInRegion; updateDefenseSquadUnits(defenseSquad, flyingDefendersNeeded, groundDefensersNeeded); } else { UAB_ASSERT_WARNING(false, "Squad should have existed: %s", squadName.str().c_str()); } } // for each of our defense squads, if there aren't any enemy units near the position, remove the squad std::set<std::string> uselessDefenseSquads; for (const auto & kv : _squadData.getSquads()) { const Squad & squad = kv.second; const SquadOrder & order = squad.getSquadOrder(); if (order.getType() != SquadOrderTypes::Defend) { continue; } bool enemyUnitInRange = false; for (auto & unit : BWAPI::Broodwar->enemy()->getUnits()) { if (unit->getPosition().getDistance(order.getPosition()) < order.getRadius()) { enemyUnitInRange = true; break; } } if (!enemyUnitInRange) { _squadData.getSquad(squad.getName()).clear(); } } }
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(); } }
void MicroManager::execute(const SquadOrder & inputOrder) { // Nothing to do if we have no units if (_units.empty() || !(inputOrder.getType() == SquadOrderTypes::Attack || inputOrder.getType() == SquadOrderTypes::Defend)) { return; } order = inputOrder; drawOrderText(); // Discover enemies within region of interest BWAPI::Unitset nearbyEnemies; // if the order is to defend, we only care about units in the radius of the defense if (order.getType() == SquadOrderTypes::Defend) { MapGrid::Instance().GetUnits(nearbyEnemies, order.getPosition(), order.getRadius(), false, true); } // otherwise we want to see everything on the way else if (order.getType() == SquadOrderTypes::Attack) { MapGrid::Instance().GetUnits(nearbyEnemies, order.getPosition(), order.getRadius(), false, true); for (auto & unit : _units) { BWAPI::Unit u = unit; BWAPI::UnitType t = u->getType(); MapGrid::Instance().GetUnits(nearbyEnemies, unit->getPosition(), order.getRadius(), false, true); } } // the following block of code attacks all units on the way to the order position // we want to do this if the order is attack, defend, or harass if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // if this is a worker defense force if (_units.size() == 1 && (*_units.begin())->getType().isWorker()) { executeMicro(nearbyEnemies); } // otherwise it is a normal attack force else { // if this is a defense squad then we care about all units in the area if (order.getType() == SquadOrderTypes::Defend) { executeMicro(nearbyEnemies); } // otherwise we only care about workers if they are in their own region else { // if this is the an attack squad BWAPI::Unitset workersRemoved; for (auto & enemyUnit : nearbyEnemies) { // if its not a worker add it to the targets if (!enemyUnit->getType().isWorker()) { workersRemoved.insert(enemyUnit); } // if it is a worker else { for (BWTA::Region * enemyRegion : InformationManager::Instance().getOccupiedRegions(BWAPI::Broodwar->enemy())) { // only add it if it's in their region if (BWTA::getRegion(BWAPI::TilePosition(enemyUnit->getPosition())) == enemyRegion) { workersRemoved.insert(enemyUnit); } } } } // Allow micromanager to handle enemies executeMicro(workersRemoved); } } } }
//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; } }