BWAPI
Skynet/Skynet/Base.cpp
Go to the documentation of this file.
00001 #include "Base.h"
00002 
00003 #include <boost/bind.hpp>
00004 
00005 #include "DrawBuffer.h"
00006 #include "UnitTracker.h"
00007 #include "Chokepoint.h"
00008 #include "MapHelper.h"
00009 #include "UnitHelper.h"
00010 
00011 BaseClass::BaseClass(Region region, std::set<TilePosition> tiles, bool startLocation)
00012         : mCenterTilePosition(BWAPI::TilePositions::None)
00013         , mCenterPosition(region->getCenter())
00014         , mMinedOut(true)
00015         , mRegion(region)
00016         , mIsStartLocation(startLocation)
00017         , mPlayer(NULL)
00018         , mBuildings()
00019         , mTiles(tiles)
00020         , mIsUnderAttack(false)
00021         , mIsContested(false)
00022         , mTechBuildings(0)
00023 {
00024 }
00025 
00026 BaseClass::BaseClass(TilePosition position, const UnitGroup &resources, Region region, std::set<TilePosition> tiles, bool startLocation)
00027         : mCenterTilePosition(position)
00028         , mCenterPosition(Position(position.x()*32+64, position.y()*32+48))
00029         , mMinedOut(false)
00030         , mRegion(region)
00031         , mIsStartLocation(startLocation)
00032         , mPlayer(NULL)
00033         , mBuildings()
00034         , mTiles(tiles)
00035         , mIsUnderAttack(false)
00036         , mIsContested(false)
00037         , mTechBuildings(0)
00038 {
00039         for each(Unit resource in resources)
00040         {
00041                 if(resource->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)
00042                         mMinerals.insert(resource);
00043                 else
00044                         mGeysers.insert(resource);
00045         }
00046 }
00047 
00048 void BaseClass::update()
00049 {
00050         if(!mMinedOut)
00051         {
00052                 bool noGas = true;
00053                 for each(Unit geyser in mGeysers)
00054                 {
00055                         if(geyser->getResources() > 0)
00056                                 noGas = false;
00057                 }
00058                 for each(Unit geyser in mRefineries)
00059                 {
00060                         if(geyser->getResources() > 0)
00061                                 noGas = false;
00062                 }
00063 
00064                 if(mMinerals.empty() && noGas)
00065                         mMinedOut = true;
00066         }
00067 
00068         for(UnitGroup::iterator it = mBuildings.begin(); it != mBuildings.end();)
00069         {
00070                 if((*it)->isLifted() || (*it)->accessibility() == AccessType::Lost)
00071                 {
00072                         Unit unit = *it;
00073                         ++it;
00074                         removeUnit(unit, unit->getPlayer(), unit->getType());
00075                 }
00076                 else
00077                         ++it;
00078         }
00079 
00080         // TODO: Move this to the base manager and make a generic add building and remove building
00081         for each(Unit unit in mLiftedBuildings)
00082         {
00083                 if(!unit->isLifted() && unit->exists())
00084                         addUnit(unit);
00085         }
00086 
00087         mLiftedBuildings.clear();
00088         for each(Unit unit in UnitTracker::Instance().getAllUnits())
00089         {
00090                 if(unit->getType().isBuilding() && unit->isLifted())
00091                         mLiftedBuildings.insert(unit);
00092         }
00093 
00094         mAllThreats.clear();
00095         mThreatTypes.clear();
00096         mAllDefenders.clear();
00097         int workerCount = 0;
00098 
00099         if(mPlayer && mPlayer != BWAPI::Broodwar->neutral())
00100         {
00101                 for each(Unit defender in UnitTracker::Instance().selectAllUnits(mPlayer))
00102                 {
00103                         if(!defender->isCompleted())
00104                                 continue;
00105 
00106                         const BWAPI::UnitType &type = defender->getType();
00107                         if(!UnitHelper::isArmyUnit(type) && !type.isWorker())
00108                                 continue;
00109 
00110                         if(mTiles.count(defender->getTilePosition()) == 0)
00111                                 continue;
00112 
00113                         if(type.isWorker())
00114                         {
00115                                 if(workerCount > 14)//Only count 14 as thats the only amount it will pull from the mineral line
00116                                         continue;
00117                                 else
00118                                         ++workerCount;
00119                         }
00120 
00121                         mAllDefenders.insert(defender);
00122                 }
00123 
00124                 for each(Unit enemy in UnitTracker::Instance().selectAllEnemy(mPlayer))
00125                 {
00126                         if(enemy->getType().isBuilding() && !enemy->isLifted())
00127                                 continue;
00128 
00129                         if(enemy->accessibility() == AccessType::Lost)
00130                                 continue;
00131 
00132                         if(mTiles.count(enemy->getTilePosition()) != 0)
00133                         {
00134                                 mAllThreats.insert(enemy);
00135                                 mThreatTypes[UnitThreatType::Scout].insert(enemy);
00136                         }
00137 
00138                         if(enemy->getType().isWorker())
00139                                 continue;
00140 
00141                         const int maxRange = std::max(48, 24 + std::max(enemy->getGroundWeaponMaxRange(), enemy->getAirWeaponMaxRange()));
00142 
00143                         for each(Unit building in mBuildings)
00144                         {
00145                                 if(enemy->getDistance(building) <= maxRange)
00146                                 {
00147                                         mAllThreats.insert(enemy);
00148 
00149                                         if(enemy->getType().isFlyer() || enemy->isLifted())
00150                                         {
00151                                                 if(enemy->canAttackGround())
00152                                                         mThreatTypes[UnitThreatType::AirToGround].insert(enemy);
00153                                                 if(enemy->canAttackAir())
00154                                                         mThreatTypes[UnitThreatType::AirToAir].insert(enemy);
00155                                         }
00156                                         else
00157                                         {
00158                                                 if(enemy->canAttackGround())
00159                                                         mThreatTypes[UnitThreatType::GroundToGround].insert(enemy);
00160                                                 if(enemy->canAttackAir())
00161                                                         mThreatTypes[UnitThreatType::GroundToAir].insert(enemy);
00162                                         }
00163 
00164                                         break;
00165                                 }
00166                         }
00167                 }
00168         }
00169 
00170         mActive = false;
00171         mActiveInFuture = false;
00172         mActivateTime = std::numeric_limits<int>::max();
00173         mIsUnderAttack = !mThreatTypes[UnitThreatType::AirToGround].empty() || !mThreatTypes[UnitThreatType::GroundToGround].empty();
00174         if(!mResourceDepots.empty())
00175         {
00176                 if(!mMinedOut)
00177                 {
00178                         if(!mIsUnderAttack && mResourceDepots[0]->isCompleted())
00179                         {
00180                                 mActive = true;
00181                                 mActiveInFuture = true;
00182                                 mActivateTime = 0;
00183                         }
00184                         else if(!mIsUnderAttack || (mAllDefenders.size() > 6 && mAllDefenders.ratingDifference(mThreatTypes[UnitThreatType::AirToGround] + mThreatTypes[UnitThreatType::GroundToGround]) >= 150))
00185                         {
00186                                 mActiveInFuture = true;
00187                                 mActivateTime = mResourceDepots[0]->getCompletedTime();
00188                         }
00189                 }
00190         }
00191 
00192         //drawDebugInfo();
00193 }
00194 
00195 bool BaseClass::depotCompare(const Unit &depotOne, const Unit &depotTwo)
00196 {
00197         int thisDistance = depotOne->getPosition().getApproxDistance(mCenterPosition);
00198         int currentDistance = depotTwo->getPosition().getApproxDistance(mCenterPosition);
00199 
00200         return thisDistance < currentDistance;
00201 }
00202 
00203 void BaseClass::onDiscover(Unit unit)
00204 {
00205         addUnit(unit);
00206 }
00207 
00208 void BaseClass::onMorphRenegade(Unit unit, Player previousPlayer, BWAPI::UnitType previousType)
00209 {
00210         removeUnit(unit, previousPlayer != NULL ? previousPlayer : unit->getPlayer(), previousType != BWAPI::UnitTypes::None ? previousType : unit->getType());
00211         addUnit(unit);
00212 }
00213 
00214 void BaseClass::onDestroy(Unit unit)
00215 {
00216         removeUnit(unit, unit->getPlayer(), unit->getType());
00217 }
00218 
00219 void BaseClass::drawDebugInfo() const
00220 {
00221         if(mPlayer != NULL)
00222                 BWAPI::Broodwar->drawCircle(BWAPI::CoordinateType::Map, mCenterPosition.x(), mCenterPosition.y(), 78, mPlayer->getColor(), false);
00223         else
00224                 BWAPI::Broodwar->drawCircle(BWAPI::CoordinateType::Map, mCenterPosition.x(), mCenterPosition.y(), 78, BWAPI::Broodwar->neutral()->getColor(), false);
00225 
00226         bool showtitle = false;
00227         int ypos = 30;
00228 
00229         if(mIsStartLocation)
00230         {
00231                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Start Location");
00232                 ypos -= 10;
00233                 showtitle = true;
00234         }
00235 
00236         if(!mBuildings.empty())
00237         {
00238                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Buildings: %u", mBuildings.size());
00239                 ypos -= 10;
00240                 showtitle = true;
00241         }
00242 
00243         if(mTechBuildings > 0)
00244         {
00245                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Number of Tech Buildings: %d", mTechBuildings);
00246                 ypos -= 10;
00247                 showtitle = true;
00248         }
00249 
00250         if(mPlayer != NULL)
00251         {
00252                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Owner: %s", mPlayer->getName().c_str());
00253                 ypos -= 10;
00254                 showtitle = true;
00255         }
00256 
00257         if(isEnemyBase())
00258         {
00259                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Is Enemy");
00260                 ypos -= 10;
00261                 showtitle = true;
00262         }
00263 
00264         if(isAllyBase())
00265         {
00266                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Is Ally");
00267                 ypos -= 10;
00268                 showtitle = true;
00269         }
00270 
00271         if(isMyBase())
00272         {
00273                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Is Mine");
00274                 ypos -= 10;
00275                 showtitle = true;
00276         }
00277 
00278         if(mIsContested)
00279         {
00280                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Base is Contested");
00281                 ypos -= 10;
00282                 showtitle = true;
00283         }
00284 
00285         if(mIsUnderAttack)
00286         {
00287                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Base is Under Attack");
00288                 ypos -= 10;
00289                 showtitle = true;
00290         }
00291 
00292         if(mActive)
00293         {
00294                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Base is Active");
00295                 ypos -= 10;
00296                 showtitle = true;
00297         }
00298         else if(mActiveInFuture)
00299         {
00300                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Base is Active In Future");
00301                 ypos -= 10;
00302                 showtitle = true;
00303         }
00304 
00305         if(mMinedOut)
00306         {
00307                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - ypos, "Base is mined out");
00308                 ypos -= 10;
00309                 showtitle = true;
00310         }
00311 
00312         if(showtitle)
00313                 BWAPI::Broodwar->drawTextMap(mCenterPosition.x() + 60, mCenterPosition.y() - 40, "Base Info:");
00314 
00315         for each(Unit unit in mAllThreats)
00316         {
00317                 BWAPI::Broodwar->drawLineMap(unit->getPosition().x(), unit->getPosition().y(), mCenterPosition.x(), mCenterPosition.y(), BWAPI::Colors::Red);
00318         }
00319         for each(Unit building in mBuildings)
00320         {
00321                 BWAPI::Broodwar->drawLine(BWAPI::CoordinateType::Map, building->getPosition().x(), building->getPosition().y(), mCenterPosition.x(), mCenterPosition.y(), building->getPlayer()->getColor());
00322         }
00323 
00324         for each(Unit mineral in mMinerals)
00325         {
00326                 BWAPI::Broodwar->drawCircleMap(mineral->getPosition().x(), mineral->getPosition().y(), 32, BWAPI::Colors::Blue);
00327                 BWAPI::Broodwar->drawLineMap(mineral->getPosition().x(), mineral->getPosition().y(), mCenterPosition.x(), mCenterPosition.y(), BWAPI::Colors::Blue);
00328         }
00329         for each(Unit geyser in mGeysers)
00330         {
00331                 BWAPI::Broodwar->drawCircleMap(geyser->getPosition().x(), geyser->getPosition().y(), 32, BWAPI::Colors::Green);
00332                 BWAPI::Broodwar->drawLineMap(geyser->getPosition().x(), geyser->getPosition().y(), mCenterPosition.x(), mCenterPosition.y(), BWAPI::Colors::Green);
00333         }
00334         for each(Unit geyser in mRefineries)
00335         {
00336                 BWAPI::Broodwar->drawCircleMap(geyser->getPosition().x(), geyser->getPosition().y(), 32, BWAPI::Colors::Orange);
00337                 BWAPI::Broodwar->drawLineMap(geyser->getPosition().x(), geyser->getPosition().y(), mCenterPosition.x(), mCenterPosition.y(), BWAPI::Colors::Green);
00338         }
00339 }
00340 
00341 Unit BaseClass::getClosestEnemyBuilding(Position pos)
00342 {
00343         int minDist = std::numeric_limits<int>::max();
00344         Unit bestBuilding;
00345 
00346         for each(Unit unit in mBuildings)
00347         {
00348                 if(!BWAPI::Broodwar->self()->isEnemy(unit->getPlayer()))
00349                         continue;
00350 
00351                 int thisDist = pos.getApproxDistance(unit->getPosition());
00352                 if(thisDist < minDist)
00353                 {
00354                         minDist = thisDist;
00355                         bestBuilding = unit;
00356                 }
00357         }
00358 
00359         return bestBuilding;
00360 }
00361 
00362 void BaseClass::updatePlayer()
00363 {
00364         mIsContested = false;
00365         if(mPlayerBuildingNumbers.empty())
00366                 mPlayer = NULL;
00367         else if(mPlayerBuildingNumbers.size() == 1)
00368                 mPlayer = mPlayerBuildingNumbers.begin()->first;
00369         else
00370         {
00371                 mIsContested = true;
00372                 if(!mResourceDepots.empty())
00373                         mPlayer = mResourceDepots[0]->getPlayer();
00374                 else
00375                 {
00376                         mPlayer = NULL;
00377                         int number = 0;
00378                         for each(std::pair<Player, int> pair in mPlayerBuildingNumbers)
00379                         {
00380                                 if(pair.second > number)
00381                                 {
00382                                         mPlayer = pair.first;
00383                                         number = pair.second;
00384                                 }
00385                         }
00386                 }
00387         }
00388 }
00389 
00390 void BaseClass::addUnit(Unit unit)
00391 {
00392         if(mTiles.count(unit->getTilePosition()) == 0)
00393                 return;
00394 
00395         const BWAPI::UnitType &type = unit->getType();
00396 
00397         if(type == BWAPI::UnitTypes::Resource_Vespene_Geyser)
00398                 mGeysers.insert(unit);
00399 
00400         if(type.isBuilding() && unit->getPlayer() != BWAPI::Broodwar->neutral() && !unit->isLifted())
00401         {
00402                 mBuildings.insert(unit);
00403                 ++mPlayerBuildingNumbers[unit->getPlayer()];
00404 
00405                 if(type.isResourceDepot())
00406                 {
00407                         mResourceDepots.push_front(unit);
00408                         if(mResourceDepots.size() > 1)
00409                                 std::sort(mResourceDepots.begin(), mResourceDepots.end(), boost::bind<bool>(&BaseClass::depotCompare, this, _1, _2));
00410                 }
00411 
00412                 if(!type.isResourceDepot() && type.supplyProvided() == 0 && !UnitHelper::isStaticDefense(type) && !type.isRefinery())
00413                         ++mTechBuildings;
00414 
00415                 updatePlayer();
00416         }
00417 
00418         if(type.isRefinery())
00419                 mRefineries.insert(unit);
00420 }
00421 
00422 void BaseClass::removeUnit(Unit unit, Player playerToRemove, BWAPI::UnitType typeToRemove)
00423 {
00424         mRefineries.erase(unit);
00425         mGeysers.erase(unit);
00426         mMinerals.erase(unit);
00427 
00428         std::set<Unit>::iterator it = mBuildings.find(unit);
00429         if(it != mBuildings.end())
00430         {
00431                 mBuildings.erase(it);
00432                 --mPlayerBuildingNumbers[playerToRemove];
00433                 if(mPlayerBuildingNumbers[playerToRemove] == 0)
00434                         mPlayerBuildingNumbers.erase(playerToRemove);
00435 
00436                 mResourceDepots.erase(std::remove(mResourceDepots.begin(), mResourceDepots.end(), unit), mResourceDepots.end());
00437 
00438                 if(!typeToRemove.isResourceDepot() && typeToRemove.supplyProvided() == 0 && !UnitHelper::isStaticDefense(typeToRemove) && !typeToRemove.isRefinery())
00439                         --mTechBuildings;
00440 
00441                 updatePlayer();
00442         }
00443 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines