#include "Util.h" namespace { auto & map = BWEM::Map::Instance(); } // gets the index of a drone that's currently mining minerals int Util::buildWorkerIndex() { for (size_t i = 0; i < Macro::players.at(Macro::selfID).units.size(); i++) { if (Macro::players.at(Macro::selfID).units.at(i).unit->getType() == UnitTypes::Zerg_Drone && Macro::players.at(Macro::selfID).units.at(i).action == "minerals" && Macro::players.at(Macro::selfID).units.at(i).miningBase > -1) { return i; } } return -1; } // checks if there's at least one complete building of the type specified bool Util::completedBuilding(BWAPI::UnitType unitType) { for (auto u : Macro::players.at(Macro::selfID).units) { if (u.unit->getType() == unitType && u.unit->isCompleted()) return true; if (unitType == UnitTypes::Zerg_Spire && u.unit->getType() == UnitTypes::Zerg_Greater_Spire && u.unit->isCompleted()) return true; if (unitType == UnitTypes::Zerg_Hatchery && u.unit->getType() == UnitTypes::Zerg_Lair && u.unit->isCompleted()) return true; if (unitType == UnitTypes::Zerg_Hatchery && u.unit->getType() == UnitTypes::Zerg_Hive && u.unit->isCompleted()) return true; if (unitType == UnitTypes::Zerg_Lair && u.unit->getType() == UnitTypes::Zerg_Hive && u.unit->isCompleted()) return true; } return false; } int Util::countUnits(int playerID, BWAPI::UnitType unitType) { int count = 0; for (auto u : Macro::players.at(playerID).units) { if (u.unitType == unitType) count++; // if the unit is changing into the target UnitType, // count it else if (u.targetUnit == unitType) count++; // lairs and hives count as hatcheries, // hives count as lairs if (unitType == UnitTypes::Zerg_Hatchery) { if (u.unitType == UnitTypes::Zerg_Lair) count++; if (u.unitType == UnitTypes::Zerg_Hive) count++; } else if (unitType == UnitTypes::Zerg_Lair) if (u.unitType == UnitTypes::Zerg_Hive) count++; } return count; } // draws the queue at the top center of the screen void Util::displayQueue() { int count = 0; for (auto e : Macro::queue) { if (e.unit != UnitTypes::Unknown) Broodwar->drawTextScreen(200, 50 + (count * 20), "%s: %d", e.unit.c_str(), e.inProgress); else Broodwar->drawTextScreen(200, 50 + (count * 20), "%s: %d", e.upgrade.c_str(), e.inProgress); count++; } } // number of units of a particular type being produced int Util::eggCount(BWAPI::UnitType unitType) { int count = 0; for (auto u : Macro::players.at(Macro::selfID).units) { if (u.unit->getBuildType() == unitType && u.unit->isMorphing()) count++; } return count; } // return the index of a building that can research a particular upgrade int Util::findUpgradeBuilding(UpgradeType upgradeType) { for (size_t i = 0; i < Macro::players.at(Macro::selfID).units.size(); i++) { for (auto u : Macro::players.at(Macro::selfID).units.at(i).unit->getType().upgradesWhat()) { if (upgradeType == u) return i; } if (Macro::players.at(Macro::selfID).units.at(i).unit->getType() == UnitTypes::Zerg_Hive) { for (auto u : UnitTypes::Zerg_Lair.upgradesWhat()) { if (upgradeType == u) return i; } for (auto u : UnitTypes::Zerg_Hatchery.upgradesWhat()) { if (upgradeType == u) return i; } } if (Macro::players.at(Macro::selfID).units.at(i).unit->getType() == UnitTypes::Zerg_Lair) { for (auto u : UnitTypes::Zerg_Hatchery.upgradesWhat()) { if (upgradeType == u) return i; } } } return -1; } int Util::getBaseIndex(Unit u) { for (size_t i = 0; i < Macro::players.at(u->getPlayer()->getID()).bases.size(); i++) { if (u->getID() == Macro::players.at(u->getPlayer()->getID()).bases.at(i).base->getID()) { return i; } } return -1; } //@TODO move this to CUnit int Util::getClosestOwnedBase(Unit unit) { unit->getUnitsInRadius(256*32, BWAPI::Filter::IsResourceDepot); double distance = 1000; int index = -1; for (size_t i = 0; i < Macro::players.at(Macro::selfID).bases.size(); i++) { double d = getDistance(unit->getTilePosition(), Macro::players.at(Macro::selfID).bases.at(i).tilePosition); if (d < distance) { distance = d; index = i; } } return index; } // get air distance between two TilePositions double Util::getDistance(TilePosition tp1, TilePosition tp2) { double deltaX = tp1.x - tp2.x; double deltaY = tp1.y - tp2.y; return sqrt(pow(deltaX, 2.0) + pow(deltaY, 2.0)); } // get the index of a Location int Util::getLocation(TilePosition tp) { for (size_t i = 0; i < Macro::locations.size(); i++) { if (Macro::locations.at(i).tilePosition == tp) return i; } return -1; } // on a path from a1 to a2, get the Area adjacent to a1 std::pair Util::getNeighborArea(const BWEM::Area* a1, const BWEM::Area* a2) { const BWEM::Area* area; int count = 0; std::vector< const BWEM::Area*> path = CMap::getPath(a1, a2); if(path.size() > 1) return std::pair(path.at(1), true); return std::pair(area, false); } // things to consider: // how close the base is by ground // how close the base is to the enemy CBase Util::getNextExpand(int playerID) { double distance = 1000; int index = -1; int count = 0; for (auto b : Macro::bases) { if (!b.isOwned()) { CBase home = Macro::players.at(playerID).bases.front(); double dist = getWalkDistance(home.tilePosition, b.tilePosition); if (dist < distance && !(home.tilePosition.x == b.tilePosition.x && home.tilePosition.y == b.tilePosition.y) && map.GetArea(home.tilePosition)->AccessibleFrom(map.GetArea(b.tilePosition))) { distance = dist; index = count; } } count++; } return Macro::bases.at(index); } int Util::getQueueIndex(UnitType ut) { for (size_t i = 0; i < Macro::queue.size(); i++) { if (Macro::queue.at(i).unit == ut) { return i; } } return -1; } int Util::getStaticDCount(int playerID, std::string type = "all") { if (type == "air") { return (countUnits(playerID, UnitTypes::Terran_Missile_Turret) + countUnits(playerID, UnitTypes::Terran_Bunker) + countUnits(playerID, UnitTypes::Protoss_Photon_Cannon) + countUnits(playerID, UnitTypes::Zerg_Spore_Colony)); } else if (type == "ground") { return (countUnits(playerID, UnitTypes::Terran_Bunker) + countUnits(playerID, UnitTypes::Protoss_Photon_Cannon) + countUnits(playerID, UnitTypes::Zerg_Sunken_Colony)); } return (countUnits(playerID, UnitTypes::Terran_Bunker) + countUnits(playerID, UnitTypes::Terran_Missile_Turret) + countUnits(playerID, UnitTypes::Protoss_Photon_Cannon) + countUnits(playerID, UnitTypes::Zerg_Sunken_Colony) + countUnits(playerID, UnitTypes::Zerg_Spore_Colony)); } // return another starting location besides the one provided // for the purpose of pathing / defense placement // //@TODO once the enemy's base is known, just return that std::pair Util::getTargetArea(const BWEM::Area* startingArea, bool startLocation) { const BWEM::Area* area; for (const TilePosition tp : map.StartingLocations()) { const BWEM::Area* nearestArea = map.GetNearestArea(tp); if (!isSameArea(nearestArea, startingArea)); { bool chk = true; if (!startLocation && Macro::players.at(Macro::selfID).bases.size() > 0 && Macro::players.at(Macro::selfID).bases.front().tilePosition == tp) { chk = false; } if (chk) { return std::pair(nearestArea, true); } } } return std::pair(area, false); } int Util::getUnitIndex(Unit unit) { for (size_t i = 0; i < Macro::players.at(unit->getPlayer()->getID()).units.size(); i++) { if (unit->getID() == Macro::players.at(unit->getPlayer()->getID()).units.at(i).unit->getID()) { return i; } } return -1; } double Util::getWalkDistance(TilePosition tp1, TilePosition tp2) { double distance = 0; const BWEM::Area* area = map.GetArea(tp1); const BWEM::Area* targetArea = map.GetArea(tp2); TilePosition currentPosition = tp1; int count = 0; for (auto a : CMap::getPath(area, targetArea)) { if (count > 0) { TilePosition nextPosition = CMap::getAreaAverage(a); distance += getDistance(currentPosition, nextPosition); currentPosition = nextPosition; } count++; } return distance; } bool Util::isAttackingUnit(CUnit u) { return (!u.unit->getType().isBuilding() && u.unit->getType() != UnitTypes::Zerg_Larva && u.unit->getType() != UnitTypes::Zerg_Egg && u.unit->getType() != UnitTypes::Zerg_Drone && u.unit->getType() != UnitTypes::Zerg_Overlord); } // run on hatcheries to see if they're a macro hatch or a mining base bool Util::isBase(Unit unit) { for (auto b : Macro::bases) { if (isSameTilePosition(unit->getTilePosition(), b.tilePosition)) { return true; } } return false; } // determines if a tileposition is a base position bool Util::isBasePosition(TilePosition tp) { for (auto b : Macro::bases) { if (tp == b.tilePosition) return true; } return false; } bool Util::isSameArea(const BWEM::Area* area1, const BWEM::Area* area2) { return (area1->TopLeft().x == area2->TopLeft().x && area1->TopLeft().y == area2->TopLeft().y); } bool Util::isSameTilePosition(TilePosition tp1, TilePosition tp2) { return (tp1.x == tp2.x && tp1.y == tp2.y); } // returns id of player who owns a base at tileposition tp int Util::ownedBy(TilePosition tp) { for (size_t i = 0; i < Macro::players.size(); i++) { for (size_t j = 0; j < Macro::players.at(i).bases.size(); j++) { if (Macro::players.at(i).bases.at(j).tilePosition == tp) return i; } } return -1; } bool Util::unitCounted(Unit unit) { for (auto u : Macro::players.at(unit->getPlayer()->getID()).units) { if (unit->getID() == u.unit->getID()) { return true; } } return false; } // checks number of workers who have been told to build a certain building int Util::workerBuildingTargetCount(UnitType unit) { int i = 0; for (auto u : Macro::players.at(Macro::selfID).units) { if (u.unit->getType() == UnitTypes::Zerg_Drone && u.targetUnit == unit) i++; } return i; }