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 DevAIModule::onSendText(std::string text) { if (text == "/morph") { BWAPI::Unitset larvae = self->getUnits(); larvae.erase_if(Filter::GetType != UnitTypes::Zerg_Larva); if (!larvae.empty()) { if (!(*larvae.begin())->morph(UnitTypes::Zerg_Mutalisk)) { Broodwar << bw->getLastError() << ":" << self->incompleteUnitCount(UnitTypes::Zerg_Greater_Spire) << ":" << self->incompleteUnitCount(UnitTypes::Zerg_Spire) << std::endl; } } } Broodwar->sendText("%s", text.c_str()); }
void LurkerManager::assignTargetsOld(const BWAPI::Unitset & targets) { const BWAPI::Unitset & LurkerUnits = getUnits(); // figure out targets BWAPI::Unitset LurkerUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(LurkerUnitTargets, LurkerUnitTargets.end()), [](BWAPI::Unit u){ return u->isVisible() && !u->isFlying(); }); for (auto & LurkerUnit : LurkerUnits) { /* We don't care what the order is, we just want to attack */ // if the order is to attack or defend //if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) //{ // if there are targets //if (!LurkerUnitTargets.empty()) //{ // find the best target for this lurker BWAPI::Unit target = getTarget(LurkerUnit, LurkerUnitTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(LurkerUnit->getPosition(), LurkerUnit->getTargetPosition(), BWAPI::Colors::Purple); } // burrow and attack it if (targetsInRange(LurkerUnit, targets) > 0) { LurkerUnit->burrow(); Micro::SmartAttackUnit(LurkerUnit, target); } else if (targetsInRange(LurkerUnit,targets) == 0){ LurkerUnit->unburrow(); Micro::SmartMove(LurkerUnit, order.getPosition()); } } // if there are no targets //else //{ // LurkerUnit->unburrow(); // if we're not near the order position //Micro::SmartMove(LurkerUnit, order.getPosition()); //} //} //} }
// still has bug in it somewhere, use Old version void RangedManager::assignTargetsNew(const BWAPI::Unitset & targets) { const BWAPI::Unitset & rangedUnits = getUnits(); // figure out targets BWAPI::Unitset rangedUnitTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(rangedUnitTargets, rangedUnitTargets.end()), [](BWAPI::Unit u){ return u->isVisible(); }); BWAPI::Unitset rangedUnitsToAssign(rangedUnits); std::map<BWAPI::Unit, int> attackersAssigned; for (auto & unit : rangedUnitTargets) { attackersAssigned[unit] = 0; } // keep assigning targets while we have attackers and targets remaining while (!rangedUnitsToAssign.empty() && !rangedUnitTargets.empty()) { auto attackerAssignment = findClosestUnitPair(rangedUnitsToAssign, rangedUnitTargets); 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::SmartAttackMove(attacker, order.getPosition()); continue; } if (Config::Micro::KiteWithRangedUnits) { if (attacker->getType() == BWAPI::UnitTypes::Zerg_Mutalisk || attacker->getType() == BWAPI::UnitTypes::Terran_Vulture) { Micro::SmartAttackUnit(attacker, target); } else { //Micro::MutaDanceTarget(attacker, target); } } else { 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 > 2)) { rangedUnitTargets.erase(target); } // if it's a building and there's more than 10 things assigned to it already, don't assign more else if (target->getType().isBuilding() && (assigned > 10)) { rangedUnitTargets.erase(target); } rangedUnitsToAssign.erase(attacker); } // if there's no targets left, attack move to the order destination if (rangedUnitTargets.empty()) { for (auto & unit : rangedUnitsToAssign) { if (unit->getDistance(order.getPosition()) > 100) { // move to it Micro::SmartAttackMove(unit, 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 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 TankManager::executeMicro(const BWAPI::Unitset & targets) { const BWAPI::Unitset & tanks = getUnits(); // figure out targets BWAPI::Unitset tankTargets; std::copy_if(targets.begin(), targets.end(), std::inserter(tankTargets, tankTargets.end()), [](BWAPI::Unit u){ return u->isVisible() && !u->isFlying(); }); int siegeTankRange = BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode.groundWeapon().maxRange() - 32; bool haveSiege = BWAPI::Broodwar->self()->hasResearched(BWAPI::TechTypes::Tank_Siege_Mode); // for each zealot for (auto & tank : tanks) { // train sub units such as scarabs or interceptors //trainSubUnits(rangedUnit); bool tankNearChokepoint = false; for (auto & choke : BWTA::getChokepoints()) { if (choke->getCenter().getDistance(tank->getPosition()) < 64) { tankNearChokepoint = true; break; } } // if the order is to attack or defend if (order.getType() == SquadOrderTypes::Attack || order.getType() == SquadOrderTypes::Defend) { // if there are targets if (!tankTargets.empty()) { // find the best target for this zealot BWAPI::Unit target = getTarget(tank, tankTargets); if (target && Config::Debug::DrawUnitTargetInfo) { BWAPI::Broodwar->drawLineMap(tank->getPosition(), tank->getTargetPosition(), BWAPI::Colors::Purple); } // if we are within siege range, siege up if (tank->getDistance(target) < siegeTankRange && tank->canSiege() && !tankNearChokepoint) { tank->siege(); } // otherwise unsiege and move in else if ((!target || tank->getDistance(target) > siegeTankRange) && tank->canUnsiege()) { tank->unsiege(); } // if we're in siege mode just attack the target if (tank->isSieged()) { Micro::SmartAttackUnit(tank, target); } // if we're not in siege mode kite the target else { Micro::SmartKiteTarget(tank, target); } } // if there are no targets else { // if we're not near the order position if (tank->getDistance(order.getPosition()) > 100) { if (tank->canUnsiege()) { tank->unsiege(); } else { // move to it Micro::SmartAttackMove(tank, order.getPosition()); } } } } } }
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; }