-
Hannes Jämtner authoredHannes Jämtner authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
BaseLocation.cpp 8.12 KiB
#include "BaseLocation.h"
#include "Util.h"
#include "IDABot.h"
#include <sstream>
#include <iostream>
const int NearBaseLocationTileDistance = 20;
BaseLocation::BaseLocation(IDABot & bot, int baseID, const std::vector<Unit> & resources)
: m_bot(bot)
, m_baseID (baseID)
, m_isStartLocation (false)
, m_left (std::numeric_limits<CCPositionType>::max())
, m_right (std::numeric_limits<CCPositionType>::lowest())
, m_top (std::numeric_limits<CCPositionType>::lowest())
, m_bottom (std::numeric_limits<CCPositionType>::max())
{
m_isPlayerStartLocation[0] = false;
m_isPlayerStartLocation[1] = false;
m_isPlayerOccupying[0] = false;
m_isPlayerOccupying[1] = false;
CCPositionType resourceCenterX = 0;
CCPositionType resourceCenterY = 0;
// add each of the resources to its corresponding container
for (auto & resource : resources)
{
if (resource.getType().isMineral())
{
m_minerals.push_back(resource);
m_mineralPositions.push_back(resource.getPosition());
// add the position of the minerals to the center
resourceCenterX += resource.getPosition().x;
resourceCenterY += resource.getPosition().y;
}
else
{
m_geysers.push_back(resource);
m_geyserPositions.push_back(resource.getPosition());
// pull the resource center toward the geyser if it exists
resourceCenterX += resource.getPosition().x;
resourceCenterY += resource.getPosition().y;
}
// set the limits of the base location bounding box
CCPositionType resWidth = Util::TileToPosition(1);
CCPositionType resHeight = Util::TileToPosition(0.5);
m_left = std::min(m_left, resource.getPosition().x - resWidth);
m_right = std::max(m_right, resource.getPosition().x + resWidth);
m_top = std::max(m_top, resource.getPosition().y + resHeight);
m_bottom = std::min(m_bottom, resource.getPosition().y - resHeight);
}
// calculate the center of the resources
size_t numResources = m_minerals.size() + m_geysers.size();
m_centerOfResources = CCPosition(m_left + (m_right-m_left)/2, m_top + (m_bottom-m_top)/2);
// compute this BaseLocation's DistanceMap, which will compute the ground distance
// from the center of its recourses to every other tile on the map
m_distanceMap = m_bot.Map().getDistanceMap(m_centerOfResources);
// check to see if this is a start location for the map
for (auto & pos : m_bot.GetStartLocations())
{
if (containsPosition(pos))
{
m_isStartLocation = true;
m_depotPosition = Util::GetTilePosition(pos);
}
}
// if this base location position is near our own resource depot, it's our start location
for (auto & unit : m_bot.GetAllUnits())
{
if (unit.getPlayer() == Players::Self && unit.getType().isResourceDepot() && containsPosition(unit.getPosition()))
{
m_isPlayerStartLocation[Players::Self] = true;
m_isStartLocation = true;
m_isPlayerOccupying[Players::Self] = true;
break;
}
}
// if it's not a start location, we need to calculate the depot position
if (!isStartLocation())
{
UnitType depot = Util::GetTownHall(m_bot.GetPlayerRace(Players::Self), m_bot);
#ifdef SC2API
int offsetX = 0;
int offsetY = 0;
#else
int offsetX = 1;
int offsetY = 1;
#endif
// the position of the depot will be the closest spot we can build one from the resource center
for (auto & tile : getClosestTiles())
{
// the build position will be up-left of where this tile is
// this means we are positioning the center of the resouce depot
CCTilePosition buildTile(tile.x - offsetX, tile.y - offsetY);
if (m_bot.Map().canBuildTypeAtPosition(buildTile.x, buildTile.y, depot))
{
m_depotPosition = buildTile;
break;
}
}
}
}
// TODO: calculate the actual depot position
const CCTilePosition & BaseLocation::getDepotPosition() const
{
return m_depotPosition;
}
void BaseLocation::setPlayerOccupying(CCPlayer player, bool occupying)
{
m_isPlayerOccupying[player] = occupying;
// if this base is a start location that's occupied by the enemy, it's that enemy's start location
if (occupying && player == Players::Enemy && isStartLocation() && m_isPlayerStartLocation[player] == false)
{
m_isPlayerStartLocation[player] = true;
}
}
bool BaseLocation::isInResourceBox(int tileX, int tileY) const
{
CCPositionType px = Util::TileToPosition((float)tileX);
CCPositionType py = Util::TileToPosition((float)tileY);
return px >= m_left && px < m_right && py < m_top && py >= m_bottom;
}
bool BaseLocation::isOccupiedByPlayer(CCPlayer player) const
{
return m_isPlayerOccupying.at(player);
}
bool BaseLocation::isExplored() const
{
return m_bot.Map().isExplored(m_centerOfResources);
}
bool BaseLocation::isPlayerStartLocation(CCPlayer player) const
{
return m_isPlayerStartLocation.at(player);
}
bool BaseLocation::containsPosition(const CCPosition & pos) const
{
if (!m_bot.Map().isValidPosition(pos) || (pos.x == 0 && pos.y == 0))
{
return false;
}
return getGroundDistance(pos) < NearBaseLocationTileDistance;
}
const std::vector<Unit> & BaseLocation::getGeysers() const
{
return m_geysers;
}
const std::vector<Unit> & BaseLocation::getMinerals() const
{
return m_minerals;
}
const CCPosition & BaseLocation::getPosition() const
{
return m_centerOfResources;
}
int BaseLocation::getGroundDistance(const CCPosition & pos) const
{
return m_distanceMap.getDistance(pos);
}
int BaseLocation::getGroundDistance(const CCTilePosition & pos) const
{
return m_distanceMap.getDistance(pos);
}
bool BaseLocation::isStartLocation() const
{
return m_isStartLocation;
}
const std::vector<CCTilePosition> & BaseLocation::getClosestTiles() const
{
return m_distanceMap.getSortedTiles();
}
void BaseLocation::draw()
{
CCPositionType radius = Util::TileToPosition(1.0f);
// Take first mineral for the Z-pos.
sc2::Point3D center_pos = sc2::Point3D(m_centerOfResources.x, m_centerOfResources.y, m_minerals[0].getUnitPtr()->pos.z);
m_bot.Map().drawResourceSphere(center_pos, radius, CCColor(255, 255, 0));
std::stringstream ss;
ss << "BaseLocation: " << m_baseID << "\n";
ss << "Start Loc: " << (isStartLocation() ? "true" : "false") << "\n";
ss << "Minerals: " << m_mineralPositions.size() << "\n";
ss << "Geysers: " << m_geyserPositions.size() << "\n";
ss << "Occupied By: ";
if (isOccupiedByPlayer(Players::Self))
{
ss << "Self ";
}
if (isOccupiedByPlayer(Players::Enemy))
{
ss << "Enemy ";
}
m_bot.Map().drawText(CCPosition(m_left, m_top+3), ss.str().c_str());
m_bot.Map().drawText(CCPosition(m_left, m_bottom), ss.str().c_str());
// draw the base bounding box
m_bot.Map().drawBox(m_left, m_top, m_right, m_bottom);
for (CCPositionType x=m_left; x < m_right; x += Util::TileToPosition(1.0f))
{
//m_bot.Map().drawLine(x, m_top, x, m_bottom, CCColor(160, 160, 160));
}
for (CCPositionType y=m_bottom; y<m_top; y += Util::TileToPosition(1.0f))
{
//m_bot.Map().drawLine(m_left, y, m_right, y, CCColor(160, 160, 160));
}
for (auto & mineral : m_minerals)
{
m_bot.Map().drawResourceSphere(mineral.getUnitPtr()->pos, radius, CCColor(0, 128, 128));
}
for (auto & geyser : m_geysers)
{
m_bot.Map().drawResourceSphere(geyser.getUnitPtr()->pos, radius, CCColor(0, 255, 0));
}
if (m_isStartLocation)
{
m_bot.Map().drawCircle(Util::GetPosition(m_depotPosition), radius, CCColor(255, 0, 0));
}
m_bot.Map().drawTile(m_depotPosition.x, m_depotPosition.y, CCColor(0, 0, 255));
//m_distanceMap.draw(m_bot);
}
bool BaseLocation::isMineralOnly() const
{
return getGeysers().empty();
}