2023-04-10 23:31:02 +00:00
|
|
|
#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;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
2023-04-11 17:56:09 +00:00
|
|
|
unit->getUnitsInRadius(256*32, BWAPI::Filter::IsResourceDepot);
|
2023-04-10 23:31:02 +00:00
|
|
|
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<const BWEM::Area*, bool> Util::getNeighborArea(const BWEM::Area* a1, const BWEM::Area* a2)
|
|
|
|
{
|
|
|
|
const BWEM::Area* area;
|
|
|
|
int count = 0;
|
|
|
|
|
2023-04-11 17:56:09 +00:00
|
|
|
std::vector< const BWEM::Area*> path = CMap::getPath(a1, a2);
|
2023-04-10 23:31:02 +00:00
|
|
|
if(path.size() > 1)
|
|
|
|
return std::pair<const BWEM::Area*, bool>(path.at(1), true);
|
|
|
|
|
|
|
|
return std::pair<const BWEM::Area*, bool>(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;
|
|
|
|
}
|
|
|
|
}
|
2023-04-13 17:49:07 +00:00
|
|
|
|
2023-04-10 23:31:02 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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<const BWEM::Area*, bool> 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<const BWEM::Area*, bool>(nearestArea, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return std::pair<const BWEM::Area*, bool>(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;
|
2023-04-11 17:56:09 +00:00
|
|
|
for (auto a : CMap::getPath(area, targetArea))
|
2023-04-10 23:31:02 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-04-11 17:56:09 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:31:02 +00:00
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2023-04-11 17:56:09 +00:00
|
|
|
bool Util::isSameTilePosition(TilePosition tp1, TilePosition tp2)
|
|
|
|
{
|
|
|
|
return (tp1.x == tp2.x && tp1.y == tp2.y);
|
|
|
|
}
|
|
|
|
|
2023-04-10 23:31:02 +00:00
|
|
|
// returns id of player who owns a base at tileposition tp
|
|
|
|
int Util::ownedBy(TilePosition tp)
|
|
|
|
{
|
2023-04-11 17:56:09 +00:00
|
|
|
for (size_t i = 0; i < Macro::players.size(); i++)
|
2023-04-10 23:31:02 +00:00
|
|
|
{
|
2023-04-11 17:56:09 +00:00
|
|
|
for (size_t j = 0; j < Macro::players.at(i).bases.size(); j++)
|
2023-04-10 23:31:02 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|