BWAPI
trunk/bwapi/Shared/Templates.h
Go to the documentation of this file.
00001 #pragma once
00002 #include <BWAPI.h>
00003 #include <Util/Foreach.h>
00004 namespace BWAPI
00005 {
00006   namespace Templates
00007   {
00008     //--------------------------------------------- HAS POWER ------------------------------------------------
00009     const bool bPsiFieldMask[10][16] = {
00010       { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 },
00011       { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
00012       { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
00013       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
00014       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
00015       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
00016       { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
00017       { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
00018       { 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0 },
00019       { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 }
00020     };
00021     template < class UnitImpl >
00022     bool hasPower(int x, int y, UnitType unitType, const std::set<UnitImpl*> &pylons)
00023     {
00024       if ( unitType >= 0 && unitType < UnitTypes::None && (!unitType.requiresPsi() || !unitType.isBuilding()) )
00025         return true;
00026 
00027       /* Loop through all pylons for the current player */
00028       foreach (UnitImpl* i, pylons)
00029       {
00030         if ( !i->exists() || !i->isCompleted() )
00031           continue;
00032 
00033         Position p = i->getPosition();
00034         if ( abs(p.x() - x) >= 256 )
00035           continue;
00036 
00037         if ( abs(p.y() - y) >= 160 )
00038           continue;
00039 
00040         if ( bPsiFieldMask[(y - p.y() + 160) / 32][(x - p.x() + 256) / 32] )
00041           return true;
00042       }
00043       return false;
00044     }
00045     //---------------------------------------------- GENERAL -------------------------------------------------
00046     template <class _T>
00047     void swapIfLarger(_T &smaller, _T &larger)
00048     {
00049       if ( smaller > larger )
00050         std::swap(smaller, larger);
00051     }
00052     //-------------------------------------------- UNIT FINDER -----------------------------------------------
00053     template <class finder>
00054     int getUnitFinderIndex(const finder *uf, int value, int start = 0)
00055     {
00056       unsigned int i = start;
00057       while ( uf[i].searchValue < value && uf[i].unitIndex && i < 1700*2 )
00058         ++i;
00059       return i;
00060     }
00061     
00062     template <class finder>
00063     void manageUnitFinder(finder *finder_x, finder *finder_y, DWORD *pdwFinderFlags, int left, int top, int right, int bottom, bool (__fastcall *callback)(Unit *uIterator), std::set<Unit*> &finderSet)
00064     {
00065       // Clear the set
00066       finderSet.clear();
00067 
00068       Templates::swapIfLarger<int>(left, right);
00069       Templates::swapIfLarger<int>(top, bottom);
00070 
00071       // Declare some variables
00072       int r = right, b = bottom;
00073       bool isWidthExtended  = right - left + 1 < UnitTypes::maxUnitWidth();
00074       bool isHeightExtended = top - bottom + 1 < UnitTypes::maxUnitHeight();
00075 
00076       // Check if the location is smaller than the largest unit
00077       if ( isWidthExtended )
00078         r += UnitTypes::maxUnitWidth();
00079       if ( isHeightExtended )
00080         b += UnitTypes::maxUnitHeight();
00081 
00082       // Obtain finder indexes for all bounds
00083       int iLeft   = Templates::getUnitFinderIndex<finder>(finder_x, left);
00084       int iTop    = Templates::getUnitFinderIndex<finder>(finder_y, top);
00085       int iRight  = Templates::getUnitFinderIndex<finder>(finder_x, r + 1, iLeft);
00086       int iBottom = Templates::getUnitFinderIndex<finder>(finder_y, b + 1, iTop);
00087 
00088       // Iterate the X entries of the finder
00089       for ( int x = iLeft; x < iRight; ++x )
00090       {
00091         int iUnitIndex = finder_x[x].unitIndex;
00092         if ( pdwFinderFlags[iUnitIndex] == 1 )
00093           continue;
00094         if ( isWidthExtended )
00095         {
00096           Unit *u = ((GameImpl*)Broodwar)->_unitFromIndex(iUnitIndex);
00097           if ( u && u->getLeft() <= right )
00098             pdwFinderFlags[iUnitIndex] = 1;
00099         }
00100         else
00101           pdwFinderFlags[iUnitIndex] = 1;
00102       }
00103       // Iterate the Y entries of the finder
00104       for ( int y = iTop; y < iBottom; ++y )
00105       {
00106         int iUnitIndex = finder_y[y].unitIndex;
00107         if ( pdwFinderFlags[iUnitIndex] != 1 )
00108           continue;
00109         if ( isHeightExtended )
00110         {
00111           Unit *u = ((GameImpl*)Broodwar)->_unitFromIndex(iUnitIndex);
00112           if ( u && u->getTop() <= bottom )
00113             pdwFinderFlags[iUnitIndex] = 2;
00114         }
00115         else
00116           pdwFinderFlags[iUnitIndex] = 2;
00117       }
00118       // Final Iteration
00119       for ( int x = iLeft; x < iRight; ++x )
00120       {
00121         int iUnitIndex = finder_x[x].unitIndex;
00122         if ( pdwFinderFlags[iUnitIndex] == 2 )
00123         {
00124           Unit *u = ((GameImpl*)Broodwar)->_unitFromIndex(iUnitIndex);
00125           if ( u && u->exists() && callback(u) )
00126             finderSet.insert(u);
00127         }
00128         // Reset finderFlags so it can be reused without incident
00129         pdwFinderFlags[iUnitIndex] = 0;
00130       }
00131     }
00132     //------------------------------------------- CAN BUILD HERE ---------------------------------------------
00133     static inline bool canBuildHere(const Unit* builder, TilePosition position, UnitType type, bool checkExplored)
00134     {
00135       Broodwar->setLastError(Errors::Unbuildable_Location);
00136       int width  = type.tileWidth();
00137       int height = type.tileHeight();
00138 
00139       int left   = position.x();
00140       int top    = position.y();
00141       int right  = left + width;
00142       int bottom = top + height;
00143 
00144       /* Map limit Check */
00145       if (left < 0) // left
00146         return false;
00147       if (top < 0) // top
00148         return false;
00149       if (right > Broodwar->mapWidth()) // right
00150         return false;
00151       if (bottom >= Broodwar->mapHeight()) // bottom
00152         return false;
00153 
00154       //if the unit is a refinery, we just need to check the set of geysers to see if the position
00155       //matches one of them (and the type is still vespene geyser)
00156       if ( type.isRefinery() )
00157       {
00158         foreach (Unit* g, Broodwar->getGeysers())
00159         {
00160           if (g->getTilePosition() == position)
00161           {
00162             if (g->isVisible() && g->getType() != UnitTypes::Resource_Vespene_Geyser)
00163               return false;
00164             return Broodwar->setLastError(Errors::None);
00165           }
00166         }
00167         return false;
00168       }
00169 
00170       /* Tile buildability check */
00171       for(int ix = left; ix < right; ++ix)
00172       {
00173         for(int iy = top; iy < bottom; ++iy)
00174         {
00175           // Check if tile is buildable and explored
00176           if ( !Broodwar->isBuildable(ix, iy, true) || ( checkExplored && !Broodwar->isExplored(ix, iy)) )
00177             return false; // @TODO: Error code for !isExplored ??
00178         }
00179       }
00180 
00181       // Check if builder is capable of reaching the building site
00182       if ( builder && !builder->getType().isFlagBeacon() && !builder->hasPath( (Position)TilePosition(left + width/2, top + height/2) ) )
00183         return false;
00184 
00185       /* Ground unit dimension check */
00186       int targetX = left * 32 + type.tileWidth()  * 32 / 2;
00187       int targetY = top  * 32 + type.tileHeight() * 32 / 2;
00188       for(int ix = left; ix < right; ++ix)
00189       {
00190         for(int iy = top; iy < bottom; ++iy)
00191         {
00192           foreach(Unit *u, Broodwar->getUnitsOnTile(ix,iy))
00193           {
00194             BWAPI::UnitType iterType = u->getType();
00195             if ( !iterType.isBuilding() &&
00196                  !iterType.isFlyer()    &&
00197                  !u->isLoaded()         &&
00198                  u != builder           &&
00199                  u->getLeft()    <= targetX + type.dimensionRight()  &&
00200                  u->getTop()     <= targetY + type.dimensionDown()   &&
00201                  u->getRight()   >= targetX - type.dimensionLeft()   &&
00202                  u->getBottom()  >= targetY - type.dimensionUp()  )
00203             {
00204               if ( !type.isAddon() )
00205                 return false;
00206               else if ( !iterType.canMove() )
00207                 return false;
00208             }
00209           }
00210         }
00211       }
00212 
00213       /* Creep Check */
00214       if ( type.getRace() == Races::Zerg )
00215       { // Creep requirement, or ignore creep if there isn't one
00216         if ( type.requiresCreep() )
00217           for(int ix = left; ix < right; ++ix)
00218             for(int iy = top; iy < bottom; ++iy)
00219               if (!Broodwar->hasCreep(ix, iy))
00220                 return false;
00221       }
00222       else
00223       { // Can't build on the creep
00224         for(int ix = left; ix < right; ++ix)
00225           for(int iy = top; iy < bottom; ++iy)
00226             if (Broodwar->hasCreep(ix, iy))
00227               return false;
00228       }
00229 
00230       /* Power Check */
00231       if ( type.requiresPsi() && !Broodwar->hasPower(left, top, width, height) )
00232         return false;
00233 
00234       /* Resource Check (CC, Nex, Hatch) */
00235       if (type.isResourceDepot())
00236       {
00237         foreach (BWAPI::Unit* m, Broodwar->getStaticMinerals())
00238         {
00239           if (Broodwar->isVisible(m->getInitialTilePosition()) ||
00240               Broodwar->isVisible(m->getInitialTilePosition().x() + 1, m->getInitialTilePosition().y()))
00241             if (!m->isVisible())
00242               continue; // tile position is visible, but mineral is not => mineral does not exist
00243           if (m->getInitialTilePosition().x() > left - 5 &&
00244               m->getInitialTilePosition().y() > top  - 4 &&
00245               m->getInitialTilePosition().x() < left + 7 &&
00246               m->getInitialTilePosition().y() < top  + 6)
00247             return false;
00248         }
00249         foreach (BWAPI::Unit* g, Broodwar->getStaticGeysers())
00250         {
00251           if (g->getInitialTilePosition().x() > left - 7 &&
00252               g->getInitialTilePosition().y() > top  - 5 &&
00253               g->getInitialTilePosition().x() < left + 7 &&
00254               g->getInitialTilePosition().y() < top  + 6)
00255             return false;
00256         }
00257       }
00258       //if the build site passes all these tests, return true.
00259       return Broodwar->setLastError(Errors::None);
00260     }
00261     //------------------------------------------- CAN MAKE ---------------------------------------------------
00262     static inline bool canMake(const Unit* builder, UnitType type)
00263     {
00264       /* Error checking */
00265       Broodwar->setLastError(Errors::None);
00266       if ( !Broodwar->self() )
00267         return Broodwar->setLastError(Errors::Unit_Not_Owned);
00268 
00269       BWAPI::UnitType requiredType = type.whatBuilds().first;
00270 
00271       if ( builder )
00272       {
00273         /* Check if the owner of the unit is you */
00274         if (builder->getPlayer() != Broodwar->self())
00275           return Broodwar->setLastError(Errors::Unit_Not_Owned);
00276 
00277         BWAPI::UnitType builderType = builder->getType();
00278         if ( type == UnitTypes::Zerg_Nydus_Canal && builderType == UnitTypes::Zerg_Nydus_Canal )
00279         {
00280           if ( !builder->isCompleted() )
00281             return Broodwar->setLastError(Errors::Unit_Busy);
00282 
00283           if ( builder->getNydusExit() )
00284             return Broodwar->setLastError(Errors::Unknown);
00285 
00286           return true;
00287         }
00288 
00289         /* Check if this unit can actually build the unit type */
00290         if ( requiredType == UnitTypes::Zerg_Larva && builderType.producesLarva() )
00291         {
00292           if ( builder->getLarva().size() == 0 )
00293             return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00294         }
00295         else if ( builderType != requiredType )
00296           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00297 
00298         /* Carrier space */
00299         if ( builderType == UnitTypes::Protoss_Carrier )
00300         {
00301           int max_amt = 4;
00302           if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Carrier_Capacity) > 0)
00303             max_amt += 4;
00304           if (builder->getInterceptorCount() + (int)builder->getTrainingQueue().size() >= max_amt)
00305             return Broodwar->setLastError(Errors::Insufficient_Space);
00306         }
00307         else if ( builderType == UnitTypes::Hero_Gantrithor )
00308         {
00309           if (builder->getInterceptorCount() + (int)builder->getTrainingQueue().size() >= 8)
00310             return Broodwar->setLastError(Errors::Insufficient_Space);
00311         }
00312 
00313         /* Reaver Space */
00314         if ( builderType == UnitTypes::Protoss_Reaver )
00315         {
00316           int max_amt = 5;
00317           if (Broodwar->self()->getUpgradeLevel(UpgradeTypes::Reaver_Capacity) > 0)
00318             max_amt += 5;
00319           if (builder->getScarabCount() + (int)builder->getTrainingQueue().size() >= max_amt)
00320             return Broodwar->setLastError(Errors::Insufficient_Space);
00321         }
00322         else if ( builderType == UnitTypes::Hero_Warbringer )
00323         {
00324           if (builder->getScarabCount() + (int)builder->getTrainingQueue().size() >= 10)
00325             return Broodwar->setLastError(Errors::Insufficient_Space);
00326         }
00327       } // builder
00328 
00329       /* Check if player has enough minerals */
00330       if ( Broodwar->self()->minerals() < type.mineralPrice() )
00331         return Broodwar->setLastError(Errors::Insufficient_Minerals);
00332 
00333       /* Check if player has enough gas */
00334       if ( Broodwar->self()->gas() < type.gasPrice() )
00335         return Broodwar->setLastError(Errors::Insufficient_Gas);
00336       
00337       /* Check if player has enough supplies */
00338       BWAPI::Race typeRace = type.getRace();
00339       if ( type.supplyRequired() > 0 && Broodwar->self()->supplyTotal(typeRace) < Broodwar->self()->supplyUsed(typeRace) + type.supplyRequired() - (requiredType.getRace() == typeRace ? requiredType.supplyRequired() : 0) )
00340         return Broodwar->setLastError(Errors::Insufficient_Supply);
00341 
00342       UnitType addon = UnitTypes::None;
00343       std::map<UnitType, int>::const_iterator requiredEnd = type.requiredUnits().end();
00344       for(std::map<UnitType, int>::const_iterator i = type.requiredUnits().begin(); i != requiredEnd; ++i)
00345       {
00346         if (i->first.isAddon())
00347           addon = i->first;
00348 
00349         bool pass = false;
00350         if (Broodwar->self()->completedUnitCount(i->first) >= i->second)
00351           pass = true;
00352         if ( i->first == UnitTypes::Zerg_Hatchery &&
00353              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Hatchery) +
00354              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Lair)     +
00355              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Hive)     >= i->second )
00356           pass = true;
00357         if ( i->first == UnitTypes::Zerg_Lair && 
00358              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Lair) + 
00359              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Hive) >= i->second)
00360           pass = true;
00361         if ( i->first == UnitTypes::Zerg_Spire && 
00362              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Spire) +
00363              Broodwar->self()->completedUnitCount(UnitTypes::Zerg_Greater_Spire) >= i->second )
00364           pass = true;
00365         
00366         if ( !pass )
00367           return Broodwar->setLastError(Errors::Insufficient_Tech);
00368       }
00369 
00370       if (type.requiredTech() != TechTypes::None && !Broodwar->self()->hasResearched(type.requiredTech()))
00371         return Broodwar->setLastError(Errors::Insufficient_Tech);
00372 
00373       if ( builder && 
00374            addon != UnitTypes::None &&
00375            addon.whatBuilds().first == type.whatBuilds().first &&
00376            (!builder->getAddon() || builder->getAddon()->getType() != addon) )
00377         return Broodwar->setLastError(Errors::Insufficient_Tech);
00378       return true;
00379     }
00380     //------------------------------------------- CAN RESEARCH -----------------------------------------------
00381     static inline bool canResearch(const Unit* unit, TechType type)
00382     {
00383       /* Error checking */
00384       Broodwar->setLastError(Errors::None);
00385       if ( !Broodwar->self() )
00386         return Broodwar->setLastError(Errors::Unit_Not_Owned);
00387 
00388       if ( unit )
00389       {
00390         if (unit->getPlayer() != Broodwar->self())
00391           return Broodwar->setLastError(Errors::Unit_Not_Owned);
00392 
00393         if (unit->getType() != type.whatResearches())
00394           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00395 
00396         if ( unit->isLifted() || !unit->isIdle() || !unit->isCompleted() )
00397           return Broodwar->setLastError(Errors::Unit_Busy);
00398       }
00399       if (Broodwar->self()->isResearching(type))
00400         return Broodwar->setLastError(Errors::Currently_Researching);
00401 
00402       if (Broodwar->self()->hasResearched(type))
00403         return Broodwar->setLastError(Errors::Already_Researched);
00404 
00405       if (Broodwar->self()->minerals() < type.mineralPrice())
00406         return Broodwar->setLastError(Errors::Insufficient_Minerals);
00407 
00408       if (Broodwar->self()->gas() < type.gasPrice())
00409         return Broodwar->setLastError(Errors::Insufficient_Gas);
00410 
00411       return true;
00412     }
00413     //------------------------------------------- CAN UPGRADE ------------------------------------------------
00414     static inline bool canUpgrade(const Unit* unit, UpgradeType type)
00415     {
00416       Broodwar->setLastError(Errors::None);
00417       Player *self = Broodwar->self();
00418       if ( !self )
00419         return Broodwar->setLastError(Errors::Unit_Not_Owned);
00420 
00421       if ( unit )
00422       {
00423         if (unit->getPlayer() != self)
00424           return Broodwar->setLastError(Errors::Unit_Not_Owned);
00425 
00426         if (unit->getType() != type.whatUpgrades())
00427           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00428 
00429         if ( unit->isLifted() || !unit->isIdle() || !unit->isCompleted() )
00430           return Broodwar->setLastError(Errors::Unit_Busy);
00431       }
00432       int nextLvl = self->getUpgradeLevel(type)+1;
00433       
00434       UnitType what = type.whatUpgrades();
00435       if ( what != UnitTypes::None )
00436       {
00437         if ( what == UnitTypes::Zerg_Hatchery && 
00438              !self->completedUnitCount(UnitTypes::Zerg_Hatchery) &&
00439              !self->completedUnitCount(UnitTypes::Zerg_Lair) &&
00440              !self->completedUnitCount(UnitTypes::Zerg_Hive) )
00441           return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00442         else if ( what == UnitTypes::Zerg_Lair &&
00443                   !self->completedUnitCount(UnitTypes::Zerg_Lair) &&
00444                   !self->completedUnitCount(UnitTypes::Zerg_Hive) )
00445           return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00446         else if ( what == UnitTypes::Zerg_Spire &&
00447                   !self->completedUnitCount(UnitTypes::Zerg_Spire) &&
00448                   !self->completedUnitCount(UnitTypes::Zerg_Greater_Spire) )
00449           return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00450         else if ( !self->completedUnitCount(what) )
00451           return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00452       }
00453       
00454       UnitType req = type.whatsRequired(nextLvl);
00455       if ( req != UnitTypes::None )
00456       {
00457         if ( req == UnitTypes::Zerg_Hatchery && !self->completedUnitCount(UnitTypes::Zerg_Hatchery) )
00458         {
00459           if ( !self->allUnitCount(UnitTypes::Zerg_Lair) &&
00460                !self->allUnitCount(UnitTypes::Zerg_Hive) )
00461             return Broodwar->setLastError(Errors::Insufficient_Tech);
00462         }
00463         else if ( req == UnitTypes::Zerg_Lair && !self->completedUnitCount(UnitTypes::Zerg_Lair) )
00464         {
00465           if ( !self->allUnitCount(UnitTypes::Zerg_Hive) )
00466             return Broodwar->setLastError(Errors::Insufficient_Tech);
00467         }
00468         else if ( req == UnitTypes::Zerg_Spire && !self->completedUnitCount(UnitTypes::Zerg_Spire) )
00469         {
00470           if ( !self->allUnitCount(UnitTypes::Zerg_Greater_Spire) )
00471             return Broodwar->setLastError(Errors::Insufficient_Tech);
00472         }
00473         else if ( !self->completedUnitCount(req) )
00474           return Broodwar->setLastError(Errors::Insufficient_Tech);
00475       }
00476 
00477       if (self->isUpgrading(type))
00478         return Broodwar->setLastError(Errors::Currently_Upgrading);
00479 
00480       if (self->getUpgradeLevel(type) >= type.maxRepeats())
00481         return Broodwar->setLastError(Errors::Fully_Upgraded);
00482 
00483       if ( self->minerals() < type.mineralPrice(nextLvl) )
00484         return Broodwar->setLastError(Errors::Insufficient_Minerals);
00485 
00486       if ( self->gas() < type.gasPrice(nextLvl) )
00487         return Broodwar->setLastError(Errors::Insufficient_Gas);
00488 
00489       return true;
00490     }
00491 
00492     //------------------------------------------- CAN ISSUE COMMAND ------------------------------------------
00493     static inline bool canIssueCommand(const Unit* thisUnit, UnitCommand c)
00494     {
00495       c.unit = (Unit*)thisUnit;
00496       BWAPI::UnitCommandType ct = c.type;
00497       // train/morph helper, get first larva
00498       if (UnitCommandTypes::Train == ct ||
00499           UnitCommandTypes::Morph == ct)
00500       {
00501         if (thisUnit->getType().producesLarva() && c.getUnitType().whatBuilds().first == UnitTypes::Zerg_Larva )
00502         {
00503           if (thisUnit->getLarva().empty())
00504           {
00505             Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00506             return false;
00507           }
00508           c.unit = (UnitImpl*)(*thisUnit->getLarva().begin());
00509           thisUnit = c.unit;
00510         }
00511       }
00512 
00513       // Basic header
00514       Broodwar->setLastError(Errors::None);
00515       if (thisUnit->getPlayer() != Broodwar->self())
00516         return Broodwar->setLastError(Errors::Unit_Not_Owned);
00517 
00518       if (!thisUnit->exists())
00519         return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00520 
00521       // Global can be ordered check
00522       if ( thisUnit->isLockedDown() || 
00523            thisUnit->isMaelstrommed() || 
00524            thisUnit->isStasised()  || 
00525            thisUnit->isUnpowered() ||
00526            thisUnit->getOrder() == Orders::ZergBirth ||
00527            thisUnit->isLoaded() )
00528         return Broodwar->setLastError(Errors::Unit_Busy);
00529 
00530       // Hallucination check
00531       if ( thisUnit->isHallucination()                  &&
00532            UnitCommandTypes::Attack_Move          != ct &&
00533            UnitCommandTypes::Attack_Unit          != ct &&
00534            UnitCommandTypes::Move                 != ct &&
00535            UnitCommandTypes::Patrol               != ct &&
00536            UnitCommandTypes::Hold_Position        != ct &&
00537            UnitCommandTypes::Stop                 != ct &&
00538            UnitCommandTypes::Follow               != ct &&
00539            UnitCommandTypes::Load                 != ct &&
00540            UnitCommandTypes::Right_Click_Position != ct &&
00541            UnitCommandTypes::Right_Click_Unit     != ct )
00542          return Broodwar->setLastError(Errors::Incompatible_UnitType);
00543 
00544       // Can be ordered check
00545       if ( !thisUnit->getType().isBuilding() &&
00546            !thisUnit->isInterruptible() &&
00547            (UnitCommandTypes::Attack_Unit           == ct ||
00548             UnitCommandTypes::Attack_Move           == ct ||
00549             UnitCommandTypes::Build                 == ct ||
00550             UnitCommandTypes::Follow                == ct ||
00551             UnitCommandTypes::Gather                == ct ||
00552             UnitCommandTypes::Load                  == ct ||
00553             UnitCommandTypes::Move                  == ct ||
00554             UnitCommandTypes::Patrol                == ct ||
00555             UnitCommandTypes::Repair                == ct ||
00556             UnitCommandTypes::Return_Cargo          == ct ||
00557             UnitCommandTypes::Right_Click_Position  == ct ||
00558             UnitCommandTypes::Right_Click_Unit      == ct ||
00559             UnitCommandTypes::Unload                == ct ||
00560             UnitCommandTypes::Unload_All            == ct ||
00561             UnitCommandTypes::Unload_All_Position   == ct ||
00562             UnitCommandTypes::Use_Tech              == ct ||
00563             UnitCommandTypes::Use_Tech_Unit         == ct ||
00564             UnitCommandTypes::Use_Tech_Position     == ct ) )
00565         return Broodwar->setLastError(Errors::Unit_Busy);
00566 
00567       // valid target check
00568       if ((!c.target ||
00569           !c.target->exists()) &&
00570           (UnitCommandTypes::Attack_Unit      == ct ||
00571            UnitCommandTypes::Set_Rally_Unit   == ct ||
00572            UnitCommandTypes::Follow           == ct ||
00573            UnitCommandTypes::Gather           == ct ||
00574            UnitCommandTypes::Repair           == ct ||
00575            UnitCommandTypes::Load             == ct ||
00576            UnitCommandTypes::Unload           == ct ||
00577            UnitCommandTypes::Right_Click_Unit == ct ||
00578            UnitCommandTypes::Use_Tech_Unit    == ct) )
00579         return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00580 
00581       // Attack Unit requirements
00582       if ( UnitCommandTypes::Attack_Unit == ct || 
00583           (UnitCommandTypes::Right_Click_Unit == ct && !c.target->getPlayer()->isNeutral() && thisUnit->getPlayer()->isEnemy(c.target->getPlayer())))
00584       {
00585         WeaponType weapon = thisUnit->getType().groundWeapon();
00586         bool targetInAir = (c.target->isLifted() || c.target->getType().isFlyer());
00587         if (targetInAir)
00588           weapon = thisUnit->getType().airWeapon();
00589 
00590         bool canAttack = (weapon != WeaponTypes::None);
00591 
00592         if ( ( (thisUnit->getType() == UnitTypes::Protoss_Reaver || thisUnit->getType() == UnitTypes::Hero_Warbringer) && thisUnit->getScarabCount() > 0 && !targetInAir) || 
00593           ((thisUnit->getType() == UnitTypes::Protoss_Carrier    || thisUnit->getType() == UnitTypes::Hero_Gantrithor) && thisUnit->getInterceptorCount() > 0) )
00594           canAttack = true;
00595 
00596         if (!canAttack)
00597           return Broodwar->setLastError(Errors::Unable_To_Hit);
00598 
00599         if ( !thisUnit->getType().canMove() && !thisUnit->isInWeaponRange(c.target) )
00600           return Broodwar->setLastError(Errors::Out_Of_Range);
00601       }
00602 
00603       // Build/Train requirements
00604       if ( UnitCommandTypes::Build       == ct)
00605       {
00606         if (TilePosition(c.x,c.y).isValid()==false)
00607           return Broodwar->setLastError(Errors::Invalid_Tile_Position);
00608       }
00609 
00610       if ( UnitCommandTypes::Morph       == ct ||
00611            UnitCommandTypes::Train       == ct)
00612       {
00613         UnitType uType = c.getUnitType();
00614         if ( thisUnit->getType().producesLarva() && uType.whatBuilds().first == UnitTypes::Zerg_Larva )
00615         {
00616           if (thisUnit->getLarva().empty())
00617             return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00618           UnitImpl *larva = (UnitImpl*)(*thisUnit->getLarva().begin());
00619           return canIssueCommand( larva, UnitCommand::train(larva,uType) );
00620         }
00621       }
00622       if ( UnitCommandTypes::Build       == ct ||
00623            UnitCommandTypes::Build_Addon == ct ||
00624            UnitCommandTypes::Morph       == ct ||
00625            UnitCommandTypes::Train       == ct )
00626       {
00627         UnitType uType = c.getUnitType();
00628         if ( !Broodwar->canMake(thisUnit, uType) )
00629           return false;
00630 
00631         if ( thisUnit->isConstructing() || 
00632              !thisUnit->isCompleted()   || 
00633              (thisUnit->getType().isFlyingBuilding() && thisUnit->isLifted()) ||
00634              (UnitCommandTypes::Train != ct && thisUnit->getType().isBuilding() && !thisUnit->isIdle()) )
00635           return Broodwar->setLastError(Errors::Unit_Busy);
00636 
00637         if ( UnitCommandTypes::Build == ct )
00638         {
00639           if ( !uType.isBuilding() )
00640             return Broodwar->setLastError(Errors::Incompatible_UnitType);
00641 
00642           if ( !uType.isAddon() && !Broodwar->canBuildHere(thisUnit, BWAPI::TilePosition(c.x, c.y), uType, true) )
00643             return false;
00644         }
00645         else if ( UnitCommandTypes::Build_Addon == ct )
00646         {
00647           if ( !uType.isAddon() )
00648             return Broodwar->setLastError(Errors::Incompatible_UnitType);
00649 
00650           if ( thisUnit->getAddon() )
00651             return Broodwar->setLastError(Errors::Incompatible_State);
00652 
00653           if ( !Broodwar->canBuildHere(thisUnit, BWAPI::TilePosition(thisUnit->getTilePosition().x() + 4, thisUnit->getTilePosition().y() + 1), uType) )
00654             return false;
00655         }
00656         else
00657         {
00658           if ( thisUnit->getType().producesLarva() && uType.whatBuilds().first == UnitTypes::Zerg_Larva && thisUnit->getLarva().size() == 0 )
00659             return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00660         }
00661       } // build/train
00662 
00663       // Research/Upgrade requirements
00664       if ( UnitCommandTypes::Research == ct && !Broodwar->canResearch(thisUnit, c.getTechType()) )
00665         return false;
00666       if ( UnitCommandTypes::Upgrade  == ct && !Broodwar->canUpgrade(thisUnit, c.getUpgradeType()) )
00667         return false;
00668 
00669       // Set Rally 
00670       if ( (UnitCommandTypes::Set_Rally_Position == ct || UnitCommandTypes::Set_Rally_Unit == ct) && !thisUnit->getType().canProduce() )
00671         return Broodwar->setLastError(Errors::Incompatible_UnitType);
00672 
00673       /* Commented out because it breaks RallyTest.
00674       if ( UnitCommandTypes::Set_Rally_Position == ct && thisUnit->getRallyPosition().x() == c.x && thisUnit->getRallyPosition().y() == c.y )
00675         return false;
00676 
00677       if ( UnitCommandTypes::Set_Rally_Unit == ct && thisUnit == c.target )
00678         return false;
00679       */
00680       // Move/stop/standard
00681       if ( (UnitCommandTypes::Move          == ct || 
00682             UnitCommandTypes::Patrol        == ct ||
00683             UnitCommandTypes::Hold_Position == ct ||
00684             UnitCommandTypes::Stop          == ct ||
00685             UnitCommandTypes::Follow        == ct) &&
00686             thisUnit->getType().isBuilding() &&
00687             !thisUnit->isLifted() &&
00688             ct != UnitCommandTypes::Hold_Position &&
00689             ct != UnitCommandTypes::Stop )
00690           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00691 
00692       // Gather
00693       if ( UnitCommandTypes::Gather == ct )
00694       {
00695         UnitType uType = c.target->getType();
00696         if ( !thisUnit->getType().isWorker() ||
00697              !uType.isResourceContainer()    ||
00698              uType == UnitTypes::Resource_Vespene_Geyser )
00699           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00700 
00701         if ( thisUnit->getPowerUp() || !c.target->isCompleted() )
00702           return Broodwar->setLastError(Errors::Unit_Busy);
00703       } // gather
00704 
00705       // return cargo
00706       if ( UnitCommandTypes::Return_Cargo == ct )
00707       {
00708         if ( !thisUnit->getType().isWorker() )
00709           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00710 
00711         if ( !thisUnit->isCarryingGas() && !thisUnit->isCarryingMinerals() )
00712           return Broodwar->setLastError(Errors::Insufficient_Ammo);
00713       } // return
00714 
00715       // Repair
00716       if ( UnitCommandTypes::Repair == ct )
00717       {
00718         UnitType targType = c.target->getType();
00719         if ( thisUnit->getType() != BWAPI::UnitTypes::Terran_SCV ||
00720              targType.getRace()  != BWAPI::Races::Terran         ||
00721              !targType.isMechanical() )
00722           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00723       } // repair
00724 
00725       // Ability requirements
00726       if ( UnitCommandTypes::Use_Tech          == ct ||
00727            UnitCommandTypes::Use_Tech_Position == ct ||
00728            UnitCommandTypes::Use_Tech_Unit     == ct ||
00729            UnitCommandTypes::Burrow            == ct ||
00730            UnitCommandTypes::Cloak             == ct ||
00731            UnitCommandTypes::Siege             == ct )
00732       {
00733         // Retrieve the tech type
00734         BWAPI::TechType tech = TechType(c.extra);
00735         if ( UnitCommandTypes::Use_Tech               == ct)
00736         {
00737           if (tech.targetsUnit() || tech.targetsPosition() || tech == TechTypes::None || tech == TechTypes::Unknown || tech == TechTypes::Lurker_Aspect)
00738             return Broodwar->setLastError(Errors::Incompatible_TechType);
00739         }
00740         else if ( UnitCommandTypes::Use_Tech_Position == ct)
00741         {
00742           if ( !tech.targetsPosition() )
00743             return Broodwar->setLastError(Errors::Incompatible_TechType);
00744         }
00745         else if ( UnitCommandTypes::Use_Tech_Unit     == ct)
00746         {
00747           if ( !tech.targetsUnit() )
00748             return Broodwar->setLastError(Errors::Incompatible_TechType);
00749         }
00750         if ( UnitCommandTypes::Burrow == ct )
00751           tech = BWAPI::TechTypes::Burrowing;
00752         else if ( UnitCommandTypes::Cloak == ct )
00753           tech = thisUnit->getType().cloakingTech();
00754         else if ( UnitCommandTypes::Siege == ct )
00755           tech = BWAPI::TechTypes::Tank_Siege_Mode;
00756 
00757         // researched check
00758         if ( !thisUnit->getType().isHero() && !Broodwar->self()->hasResearched(tech) && thisUnit->getType() != UnitTypes::Zerg_Lurker )
00759           return Broodwar->setLastError(Errors::Insufficient_Tech);
00760 
00761         // energy check
00762         if ( thisUnit->getEnergy() < tech.energyUsed() )
00763           return Broodwar->setLastError(Errors::Insufficient_Energy);
00764 
00765         // unit check
00766         if ( tech != TechTypes::Burrowing && tech.whatUses().find(thisUnit->getType()) == tech.whatUses().end() )
00767           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00768 
00769         // spider mine check
00770         if ( tech == TechTypes::Spider_Mines && thisUnit->getSpiderMineCount() <= 0 )
00771           return Broodwar->setLastError(Errors::Insufficient_Ammo);
00772 
00773         // nuclear missile check
00774         if ( tech == TechTypes::Nuclear_Strike && thisUnit->getPlayer()->completedUnitCount(UnitTypes::Terran_Nuclear_Missile) == 0 )
00775           return Broodwar->setLastError(Errors::Insufficient_Ammo);
00776 
00777         // state checks
00778         if (tech == TechTypes::Burrowing)
00779         {
00780           if ( !thisUnit->getType().isBurrowable() )
00781             return Broodwar->setLastError(Errors::Incompatible_UnitType);
00782 
00783           if ( thisUnit->isBurrowed() || thisUnit->getOrder() == Orders::Burrowing || thisUnit->getOrder() == Orders::Unburrowing )
00784             return Broodwar->setLastError(Errors::Incompatible_State);
00785         }
00786         else if (tech == TechTypes::Tank_Siege_Mode)
00787         {
00788           if ( thisUnit->isSieged() )
00789             return Broodwar->setLastError(Errors::Incompatible_State);
00790 
00791           if ( thisUnit->getOrder() == Orders::Sieging || thisUnit->getOrder() == Orders::Unsieging )
00792             return Broodwar->setLastError(Errors::Unit_Busy);
00793         }
00794         else if (tech == TechTypes::Personnel_Cloaking || tech == TechTypes::Cloaking_Field)
00795         {
00796           if ( thisUnit->getSecondaryOrder() == Orders::Cloak )
00797             return Broodwar->setLastError(Errors::Incompatible_State);
00798         }
00799 
00800         if ( tech == TechTypes::None || tech == TechTypes::Unknown )
00801           return Broodwar->setLastError(Errors::Incompatible_TechType);
00802       } // ability
00803 
00804       // Unburrow
00805       if ( UnitCommandTypes::Unburrow == ct )
00806       {
00807         if ( !thisUnit->getType().isBurrowable() )
00808           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00809         if ( !thisUnit->isBurrowed() || thisUnit->getOrder() == Orders::Unburrowing )
00810           return Broodwar->setLastError(Errors::Incompatible_State);
00811       } // unburrow
00812 
00813       // Decloak
00814       if ( UnitCommandTypes::Decloak == ct )
00815       {
00816         if ( thisUnit->getType().cloakingTech() == TechTypes::None )
00817           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00818 
00819         if ( thisUnit->getSecondaryOrder() != Orders::Cloak )
00820           return Broodwar->setLastError(Errors::Incompatible_State);
00821       } // decloak
00822 
00823       // Unsiege
00824       if ( UnitCommandTypes::Unsiege == ct )
00825       {
00826         if ( !thisUnit->isSieged() )
00827           return Broodwar->setLastError(Errors::Incompatible_State);
00828 
00829         if ( thisUnit->getOrder() == Orders::Sieging || thisUnit->getOrder() == Orders::Unsieging )
00830           return Broodwar->setLastError(Errors::Unit_Busy);
00831       }
00832 
00833       // lift/land
00834       if ( UnitCommandTypes::Lift == ct || UnitCommandTypes::Land == ct )
00835       {
00836         if ( !thisUnit->getType().isFlyingBuilding() )
00837           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00838 
00839         if ( UnitCommandTypes::Lift == ct ? thisUnit->isLifted() : !thisUnit->isLifted() )
00840           return Broodwar->setLastError(Errors::Incompatible_State);
00841       } // lift/land
00842 
00843       // load
00844       if ( UnitCommandTypes::Load == ct)
00845       {
00846         //target must also be owned by self
00847         if (c.target->getPlayer() != Broodwar->self())
00848           return Broodwar->setLastError(Errors::Unit_Not_Owned);
00849 
00850         if ( c.target->isLoaded() ||
00851              !c.target->isCompleted() ||
00852              !thisUnit->isCompleted() )
00853           return Broodwar->setLastError(Errors::Unit_Busy);
00854 
00855         // verify upgrade for Zerg Overlord
00856         int thisUnitSpaceProvided = thisUnit->getType().spaceProvided();
00857         if ( thisUnit->getType() == UnitTypes::Zerg_Overlord && Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ventral_Sacs) == 0 )
00858           return Broodwar->setLastError(Errors::Insufficient_Tech);
00859 
00860         int targetSpaceProvided = c.target->getType().spaceProvided();
00861         if ( c.target->getType() == UnitTypes::Zerg_Overlord && Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ventral_Sacs) == 0 )
00862           return Broodwar->setLastError(Errors::Insufficient_Tech);
00863 
00864         // check if there is space available
00865         int thisUnitFreeSpace = thisUnitSpaceProvided;
00866         int targetFreeSpace   = targetSpaceProvided;
00867         std::set<Unit*> loadedUnits = thisUnit->getLoadedUnits();
00868         foreach(Unit* u, loadedUnits)
00869         {
00870           int r = u->getType().spaceRequired();
00871           if (r > 0 && r < 8)
00872             thisUnitFreeSpace -= r;
00873         }
00874         std::set<Unit*> targetLoadedUnits = c.target->getLoadedUnits();
00875         foreach(Unit* u, targetLoadedUnits)
00876         {
00877           int r = u->getType().spaceRequired();
00878           if (r > 0 && r < 8)
00879             targetFreeSpace -= r;
00880         }
00881         if (thisUnitSpaceProvided > 0)
00882         {
00883           if (c.target->getType().canMove() == false || c.target->getType().isFlyer() || c.target->getType().spaceRequired() > 8)
00884             return Broodwar->setLastError(Errors::Incompatible_UnitType);
00885           if (c.target->getType().spaceRequired() > thisUnitFreeSpace)
00886             return Broodwar->setLastError(Errors::Insufficient_Space);
00887         }
00888         else if (targetSpaceProvided > 0)
00889         {
00890           if (thisUnit->getType().canMove() == false || thisUnit->getType().isFlyer() || thisUnit->getType().spaceRequired() > 8)
00891             return Broodwar->setLastError(Errors::Incompatible_UnitType);
00892           if (thisUnit->getType().spaceRequired() > targetFreeSpace)
00893             return Broodwar->setLastError(Errors::Insufficient_Space);
00894         }
00895         else
00896         {
00897           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00898         }
00899       }
00900 
00901       // unload
00902       if ( UnitCommandTypes::Unload              == ct ||
00903            UnitCommandTypes::Unload_All          == ct ||
00904            UnitCommandTypes::Unload_All_Position == ct )
00905       {
00906         if ( thisUnit->getLoadedUnits().size() == 0 )
00907           return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00908 
00909         // Check overlord tech
00910         int thisUnitSpaceProvided = thisUnit->getType().spaceProvided();
00911         if ( thisUnit->getType() == UnitTypes::Zerg_Overlord && Broodwar->self()->getUpgradeLevel(UpgradeTypes::Ventral_Sacs) == 0)
00912           return Broodwar->setLastError(Errors::Insufficient_Tech);
00913 
00914         if ( thisUnitSpaceProvided <= 0 )
00915           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00916 
00917         if ( UnitCommandTypes::Unload == ct )
00918         {
00919           if ( !c.target )
00920             return Broodwar->setLastError(Errors::Unit_Does_Not_Exist);
00921           if ( !c.target->isLoaded() )
00922             return Broodwar->setLastError(Errors::Incompatible_State);
00923         }
00924 
00925         if ( thisUnit->getType() != UnitTypes::Terran_Bunker && thisUnit )
00926         {
00927           BWAPI::Position targDropPos = (UnitCommandTypes::Unload_All_Position == ct ? c.getTargetPosition() : thisUnit->getPosition());
00928           if ( !Broodwar->isWalkable(targDropPos.x()/8, targDropPos.y()/8) )
00929             return Broodwar->setLastError(Errors::Unreachable_Location);
00930         }
00931       } // unload
00932 
00933       // Halt construction
00934       if ( UnitCommandTypes::Halt_Construction == ct && thisUnit->getOrder() != Orders::ConstructingBuilding )
00935         return false;
00936 
00937       // Cancel construction
00938       if ( UnitCommandTypes::Cancel_Construction == ct )
00939       {
00940         if ( !thisUnit->getType().isBuilding() )
00941           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00942 
00943         if ( thisUnit->isCompleted() || (!thisUnit->isCompleted() && thisUnit->getType() == UnitTypes::Zerg_Nydus_Canal && thisUnit->getNydusExit()) )
00944           return false;
00945       }
00946 
00947       // cancel addon
00948       if ( UnitCommandTypes::Cancel_Addon == ct && (!thisUnit->getAddon() || thisUnit->getAddon()->isCompleted()) )
00949         return Broodwar->setLastError(Errors::Incompatible_UnitType);
00950 
00951       // cancel train
00952       if ( UnitCommandTypes::Cancel_Train == ct && !thisUnit->isTraining() )
00953         return false;
00954 
00955       if ( UnitCommandTypes::Cancel_Train_Slot == ct && (!thisUnit->isTraining() || (thisUnit->getTrainingQueue().size() <= (unsigned int)c.extra && c.extra >= 0)) )
00956         return false;
00957 
00958       // cancel morph
00959       if ( UnitCommandTypes::Cancel_Morph == ct && (!thisUnit->isMorphing() || (!thisUnit->isCompleted() && thisUnit->getType() == UnitTypes::Zerg_Nydus_Canal && thisUnit->getNydusExit())) )
00960         return false;
00961 
00962       // cancel research
00963       if ( UnitCommandTypes::Cancel_Research == ct && thisUnit->getOrder() != Orders::ResearchTech )
00964         return false;
00965 
00966       // cancel upgrade
00967       if ( UnitCommandTypes::Cancel_Upgrade == ct && thisUnit->getOrder() != Orders::Upgrade )
00968         return false;
00969 
00970       // place COP
00971       if ( UnitCommandTypes::Place_COP == ct )
00972       {
00973         if ( !thisUnit->getType().isFlagBeacon() )
00974           return Broodwar->setLastError(Errors::Incompatible_UnitType);
00975 
00976         if ( ((UnitImpl*)thisUnit)->self->buttonset == 228 || thisUnit->getOrder() != BWAPI::Orders::CTFCOPInit )
00977           return Broodwar->setLastError(Errors::Incompatible_State);
00978 
00979         if ( !Broodwar->canBuildHere(thisUnit, BWAPI::TilePosition(c.x, c.y), thisUnit->getType(), true) )
00980           return false;
00981       }
00982       return true;
00983     }
00984   }
00985   //--------------------------------------------- COMPUTE DISTANCE -------------------------------------------
00986   static inline int computeDistance(const Unit *src, const Unit *targ)
00987   {
00988     if ( src == targ || !src || !targ )
00989       return 0;
00990 
00991     int xDist = src->getLeft() - (targ->getRight() + 1);
00992     if ( xDist < 0 )
00993     {
00994       xDist = targ->getLeft() - (src->getRight() + 1);
00995       if ( xDist < 0 )
00996         xDist = 0;
00997     }
00998     int yDist = src->getTop() - (targ->getBottom() + 1);
00999     if ( yDist < 0 )
01000     {
01001       yDist = targ->getTop() - (src->getBottom() + 1);
01002       if ( yDist < 0 )
01003         yDist = 0;
01004     }
01005     return Position(0, 0).getApproxDistance(Position(xDist, yDist));
01006   }
01007   //--------------------------------------------- COMPUTE DISTANCE -------------------------------------------
01008   static inline int computeDistance(const Unit* src, Position targ)
01009   {
01010     if ( !src )
01011       return 0;
01012 
01013     int xDist = src->getLeft() - (targ.x() + 1);
01014     if ( xDist < 0 )
01015     {
01016       xDist = targ.x() - (src->getRight() + 1);
01017       if ( xDist < 0 )
01018         xDist = 0;
01019     }
01020     int yDist = src->getTop() - (targ.y() + 1);
01021     if ( yDist < 0 )
01022     {
01023       yDist = targ.y() - (src->getBottom() + 1);
01024       if ( yDist < 0 )
01025         yDist = 0;
01026     }
01027     return Position(0, 0).getApproxDistance(Position(xDist, yDist));
01028   }
01029 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines