BWAPI
Skynet/Skynet/Unit.cpp
Go to the documentation of this file.
00001 #include "Unit.h"
00002 
00003 #include <cassert>
00004 
00005 #include "MapHelper.h"
00006 #include "UnitTracker.h"
00007 #include "DrawingHelper.h"
00008 #include "Requirement.h"
00009 #include "LatencyTracker.h"
00010 #include "Logger.h"
00011 #include "UnitHelper.h"
00012 
00013 const Unit StaticUnits::nullunit;
00014 
00015 UnitClass::UnitClass(BWAPI::Unit* unit)
00016         : mUnit(unit)
00017         , mStoredPosition(BWAPI::Positions::Unknown)
00018         , mStoredTargetPosition(BWAPI::Positions::None)
00019         , mStoredAccessType(AccessType::Full)
00020         , mStoredPlayer(BWAPI::Broodwar->neutral())
00021         , mStoredBoolOne(false)
00022         , mStoredCompleted(false)
00023         , mStoredMorphing(false)
00024         , mStoredCompletedTime(0)
00025         , mStoredTime(0)
00026         , mStoredInt(0)
00027         , mStoredExistsTime(Requirement::maxTime)
00028         , mStoredHealth(0)
00029         , mStoredShield(0)
00030         , mLastOrderExecuteTime(0)
00031 {
00032         if(exists())
00033         {
00034                 mStoredCompleted = unit->isCompleted();
00035                 mStoredMorphing = unit->isMorphing();
00036         }
00037         update();
00038         if(exists())
00039         {
00040                 if(!isCompleted())
00041                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount() + unit->getType().buildTime();
00042                 else if(isMorphing())
00043                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount() + unit->getBuildType().buildTime();
00044         }
00045 }
00046 
00047 UnitClass::UnitClass(Position pos, BWAPI::UnitType type, int startTime)
00048         : mUnit(NULL)
00049         , mStoredPosition(pos)
00050         , mStoredTargetPosition(pos)
00051         , mStoredType(type)
00052         , mStoredAccessType(AccessType::Prediction)
00053         , mStoredPlayer(BWAPI::Broodwar->self())
00054         , mStoredBoolOne(false)
00055         , mStoredCompleted(false)
00056         , mStoredMorphing(false)
00057         , mStoredCompletedTime(startTime + type.buildTime())
00058         , mStoredTime(BWAPI::Broodwar->getFrameCount())
00059         , mStoredInt(0)
00060         , mStoredExistsTime(startTime)
00061         , mStoredHealth(0)
00062         , mStoredShield(0)
00063         , mLastOrderExecuteTime(0)
00064 {
00065 }
00066 
00067 void UnitClass::onDestroy()
00068 {
00069         mStoredAccessType = AccessType::Dead;
00070 }
00071 
00072 TilePosition UnitClass::getTilePosition()
00073 {
00074         if(exists())
00075         {
00076                 if(mUnit->isLoaded())
00077                         return mUnit->getTransport()->getTilePosition();
00078                 else
00079                         return mUnit->getTilePosition();
00080         }
00081 
00082         const BWAPI::UnitType &type = getType();
00083         const Position &pos = getPosition();
00084 
00085         return TilePosition(Position(pos.x() - (type.tileWidth() * 16), pos.y() - (type.tileHeight() * 16)));
00086 }
00087 
00088 Position UnitClass::getPosition()
00089 {
00090         if(exists())
00091         {
00092                 if(mUnit->isLoaded())
00093                         return mUnit->getTransport()->getPosition();
00094                 else
00095                         return mUnit->getPosition();
00096         }
00097 
00098         const BWAPI::UnitType &type = getType();
00099         
00100         if(type.topSpeed() != 0.0)
00101         {
00102                 int travelTime = int(mStoredPosition.getApproxDistance(mStoredTargetPosition) / type.topSpeed());
00103                 int timeDifference = BWAPI::Broodwar->getFrameCount() - mStoredTime;
00104 
00105                 if(timeDifference > travelTime)
00106                         return mStoredTargetPosition;
00107 
00108                 if(travelTime != 0)
00109                 {
00110                         float traveled = float(timeDifference) / float(travelTime);
00111 
00112                         Vector currentPosition = mStoredTargetPosition - mStoredPosition;
00113 
00114                         currentPosition *= traveled;
00115                         currentPosition += Vector(mStoredPosition);
00116 
00117                         return currentPosition;
00118                 }
00119         }
00120 
00121         return mStoredPosition;
00122 }
00123 
00124 Position UnitClass::getPosition(int inFramesTime)
00125 {
00126         const Position &currentPosition = getPosition();
00127         const BWAPI::UnitType &type = getType();
00128 
00129         if(type.topSpeed() != 0.0)
00130         {
00131                 const Position &targetPosition = getTargetPosition();
00132 
00133                 int travelTime = int(currentPosition.getApproxDistance(targetPosition) / type.topSpeed());
00134 
00135                 if(inFramesTime > travelTime)
00136                         return targetPosition;
00137 
00138                 if(travelTime != 0)
00139                 {
00140                         float traveled = float(inFramesTime) / float(travelTime);
00141 
00142                         Vector direction = targetPosition - currentPosition;
00143 
00144                         direction *= traveled;
00145                         direction += Vector(mStoredPosition);
00146 
00147                         return direction;
00148                 }
00149         }
00150 
00151         return currentPosition;
00152 }
00153 
00154 Position UnitClass::getTargetPosition()
00155 {
00156         if(exists())
00157         {
00158                 const BWAPI::UnitType &type = getType();
00159                 if(type.canMove() || type.isFlyingBuilding())
00160                 {
00161                         if(mUnit->isLoaded())
00162                                 return mUnit->getTransport()->getTargetPosition();
00163                         else
00164                                 return mUnit->getTargetPosition();
00165                 }
00166                 else
00167                         return mUnit->getPosition();
00168         }
00169 
00170         return mStoredTargetPosition;
00171 }
00172 
00173 Player UnitClass::getPlayer()
00174 {
00175         if(exists())
00176                 return mUnit->getPlayer();
00177 
00178         return mStoredPlayer;
00179 }
00180 
00181 BWAPI::UnitType UnitClass::getType()
00182 {
00183         if(exists())
00184                 return mUnit->getType();
00185 
00186         return mStoredType;
00187 }
00188 
00189 BWAPI::Order UnitClass::getOrder()
00190 {
00191         if(exists())
00192                 return mUnit->getOrder();
00193 
00194         return BWAPI::Orders::None;
00195 }
00196 
00197 BWAPI::Order UnitClass::getSecondaryOrder()
00198 {
00199         if(exists())
00200                 return mUnit->getSecondaryOrder();
00201 
00202         return BWAPI::Orders::None;
00203 }
00204 
00205 bool UnitClass::isLifted()
00206 {
00207         if(exists())
00208                 return mUnit->isLifted();
00209 
00210         return getType().isFlyingBuilding() && mStoredBoolOne;
00211 }
00212 
00213 bool UnitClass::isSieged()
00214 {
00215         if(exists())
00216                 return mUnit->isSieged();
00217 
00218         return (getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode) && mStoredBoolOne;
00219 }
00220 
00221 bool UnitClass::isCarryingGas()
00222 {
00223         if(exists())
00224                 return mUnit->isCarryingGas();
00225 
00226         return false;
00227 }
00228 
00229 bool UnitClass::isCarryingMinerals()
00230 {
00231         if(exists())
00232                 return mUnit->isCarryingMinerals();
00233 
00234         return false;
00235 }
00236 
00237 int UnitClass::getLastSeenTime()
00238 {
00239         if(exists())
00240                 return BWAPI::Broodwar->getFrameCount();
00241 
00242         return mStoredTime;
00243 }
00244 
00245 AccessType UnitClass::accessibility()
00246 {
00247         if(mUnit)
00248         {
00249                 if(mUnit->exists())
00250                 {
00251                         if(mUnit->getPlayer() == BWAPI::Broodwar->self() || (!mUnit->isCloaked() && !mUnit->isBurrowed()) || mUnit->isDetected())
00252                                 return AccessType::Full;
00253                         else
00254                                 return AccessType::Partial;
00255                 }
00256 
00257                 // If it doesn't exist but its ours it must be dead, is also possible to check if the player has left the game
00258                 // but in some game modes they don't disappear when player->leftGame() returns true, noticed in protoss champaign
00259                 if(getPlayer() == BWAPI::Broodwar->self())
00260                         return AccessType::Dead;
00261 
00262                 const BWAPI::UnitType &type = getType();
00263                 if(MapHelper::isAnyVisible(getTilePosition(), type))
00264                 {
00265                         if(type.canMove() || type.isFlyingBuilding() || type == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode)
00266                                 mStoredAccessType = AccessType::Lost;
00267                         else
00268                                 mStoredAccessType = AccessType::Dead;
00269                 }
00270                 else if(mStoredAccessType != AccessType::Lost)
00271                         mStoredAccessType = AccessType::Guess;
00272         }
00273 
00274         return mStoredAccessType;
00275 }
00276 
00277 void UnitClass::drawUnitPosition()
00278 {
00279         const Position &pos = getPosition();
00280         const BWAPI::UnitType &type = getType();
00281         Player player = getPlayer();
00282 
00283         const int barHeight = 4;
00284 
00285         if((!isCompleted() || isMorphing()) && accessibility() != AccessType::Prediction)
00286         {
00287                 double progress = getCompletedTime() - BWAPI::Broodwar->getFrameCount();
00288 
00289                 if(isMorphing())
00290                         progress /= getBuildType().buildTime();
00291                 else
00292                         progress /= type.buildTime();
00293 
00294                 progress = 1.0 - progress;
00295 
00296                 BWAPI::Color barColour = isMorphing() ? BWAPI::Colors::Red : BWAPI::Colors::Purple;
00297 
00298                 Position bottomLeft(pos.x() - type.dimensionLeft(), pos.y() + type.dimensionDown() + barHeight - 1);
00299 
00300                 DrawingHelper::Instance().drawProgressBar(bottomLeft, type.dimensionLeft()+type.dimensionRight(), barHeight, progress, barColour, player->getColor());
00301         }
00302 
00303         if(type.maxShields() > 0)
00304         {
00305                 double progress = getShield();
00306                 progress /= type.maxShields();
00307 
00308                 Position bottomLeft(pos.x() - type.dimensionLeft(), pos.y() - type.dimensionUp() - barHeight + 2);
00309 
00310                 DrawingHelper::Instance().drawProgressBar(bottomLeft, type.dimensionLeft()+type.dimensionRight(), barHeight, progress, BWAPI::Colors::Blue, player->getColor());
00311         }
00312 
00313         if(type.maxHitPoints() > 0)
00314         {
00315                 double progress = getHealth();
00316                 progress /= type.maxHitPoints();
00317 
00318                 Position bottomLeft(pos.x() - type.dimensionLeft(), pos.y() - type.dimensionUp() + 1);
00319 
00320                 DrawingHelper::Instance().drawProgressBar(bottomLeft, type.dimensionLeft()+type.dimensionRight(), barHeight, progress, BWAPI::Colors::Green, player->getColor());
00321         }
00322 
00323         BWAPI::Broodwar->drawBox(BWAPI::CoordinateType::Map, pos.x() - type.dimensionLeft(), pos.y() - type.dimensionUp(), pos.x() + type.dimensionRight(), pos.y() + type.dimensionDown(), player->getColor());
00324 
00325         BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y(), "%s", player->getName().c_str());
00326 
00327         AccessType access = accessibility();
00328         BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y()+10, "%s", AccessType::getName(access.underlying()).c_str());
00329 
00330         BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y()+20, "%d", (getExistTime() - BWAPI::Broodwar->getFrameCount()));
00331         BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y()+30, "%d", (getCompletedTime() - BWAPI::Broodwar->getFrameCount()));
00332 
00333         if(isMorphing())
00334                 BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y()+40, "Morphing");
00335 
00336         if(isCompleted())
00337                 BWAPI::Broodwar->drawTextMap(pos.x() + type.dimensionRight(), pos.y()+50, "Completed");
00338 
00339         Position target = getTargetPosition();
00340         BWAPI::Broodwar->drawLine(BWAPI::CoordinateType::Map, pos.x(), pos.y(), target.x(), target.y(), player->getColor());
00341 }
00342 
00343 void UnitClass::drawUnitTilePosition()
00344 {
00345         TilePosition tile = getTilePosition();
00346         BWAPI::UnitType type = getType();
00347         Player player = getPlayer();
00348 
00349         BWAPI::Broodwar->drawBox(BWAPI::CoordinateType::Map, tile.x()*32, tile.y()*32, (tile.x()+type.tileWidth())*32, (tile.y()+type.tileHeight())*32, player->getColor());
00350 }
00351 
00352 bool UnitClass::exists()
00353 {
00354         return mUnit && mUnit->exists();
00355 }
00356 
00357 int UnitClass::getExistTime()
00358 {
00359         if(mUnit)
00360                 return BWAPI::Broodwar->getFrameCount();
00361 
00362         return std::max(mStoredExistsTime, BWAPI::Broodwar->getFrameCount() + 1);
00363 }
00364 
00365 bool UnitClass::isMorphing()
00366 {
00367         if(exists())
00368         {
00369                 if(!mUnit->isMorphing())
00370                         return false;
00371 
00372                 if(mUnit->getPlayer() == BWAPI::Broodwar->self())
00373                         return mUnit->getRemainingBuildTime() > 0;
00374 
00375                 return true;
00376         }
00377 
00378         if(!mStoredMorphing)
00379                 return false;
00380 
00381         return mStoredCompletedTime > BWAPI::Broodwar->getFrameCount();
00382 }
00383 
00384 bool UnitClass::isCompleted()
00385 {
00386         if(exists())
00387         {
00388                 if(mUnit->isCompleted())
00389                         return true;
00390 
00391                 if(mUnit->getPlayer() == BWAPI::Broodwar->self())
00392                         return mUnit->getRemainingBuildTime() == 0;
00393 
00394                 return false;
00395         }
00396 
00397         if(accessibility() == AccessType::Prediction)
00398                 return false;
00399 
00400         if(mStoredCompleted)
00401                 return true;
00402 
00403         return mStoredCompletedTime <= BWAPI::Broodwar->getFrameCount();
00404 }
00405 
00406 int UnitClass::getCompletedTime()
00407 {
00408         if(isCompleted())
00409                 return BWAPI::Broodwar->getFrameCount();
00410 
00411         if(exists())
00412         {
00413                 if(mUnit->getPlayer() == BWAPI::Broodwar->self())
00414                         return BWAPI::Broodwar->getFrameCount() + mUnit->getRemainingBuildTime();
00415         }
00416         else
00417         {
00418                 const int existsTime = getExistTime();
00419                 const int completeTime = existsTime + getType().buildTime();
00420 
00421                 if(completeTime < existsTime)
00422                         return std::numeric_limits<int>::max();
00423                 else
00424                         return completeTime;
00425         }
00426 
00427         return std::max(mStoredCompletedTime, BWAPI::Broodwar->getFrameCount() + 1);
00428 }
00429 
00430 bool UnitClass::isTraining()
00431 {
00432         if(exists())
00433                 return mUnit->isTraining();
00434 
00435         return false;
00436 }
00437 
00438 bool UnitClass::isResearching()
00439 {
00440         if(exists())
00441                 return mUnit->isResearching();
00442 
00443         return false;
00444 }
00445 
00446 bool UnitClass::isConstructing()
00447 {
00448         if(exists())
00449                 return mUnit->isConstructing();
00450 
00451         return false;
00452 }
00453 
00454 bool UnitClass::isBeingConstructed()
00455 {
00456         if(exists())
00457                 return mUnit->isBeingConstructed();
00458 
00459         return false;
00460 }
00461 
00462 int UnitClass::getRemainingTrainTime()
00463 {
00464         if(exists() && mUnit->getPlayer() == BWAPI::Broodwar->self())
00465                 return mUnit->getRemainingTrainTime();
00466 
00467         return 0;
00468 }
00469 
00470 int UnitClass::getRemainingUpgradeTime()
00471 {
00472         if(exists() && mUnit->getPlayer() == BWAPI::Broodwar->self())
00473                 return mUnit->getRemainingUpgradeTime();
00474 
00475         return 0;
00476 }
00477 
00478 int UnitClass::getRemainingResearchTime()
00479 {
00480         if(exists() && mUnit->getPlayer() == BWAPI::Broodwar->self())
00481                 return mUnit->getRemainingResearchTime();
00482 
00483         return 0;
00484 }
00485 
00486 void UnitClass::train(BWAPI::UnitType type)
00487 {
00488         if(exists())
00489         {
00490                 if(mUnit->getSecondaryOrder() == BWAPI::Orders::Train)
00491                 {
00492                         const std::list<BWAPI::UnitType> &queue = mUnit->getTrainingQueue();
00493                         if(queue.size() > 1 || (queue.size() == 1 && *queue.begin() != type))
00494                         {
00495                                 cancel();
00496                                 return;
00497                         }
00498 
00499                         return;
00500                 }
00501 
00502                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Train && mUnit->getLastCommand().getUnitType() == type)
00503                 {
00504                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00505                                 return;
00506                 }
00507 
00508                 if(mUnit->train(type))
00509                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00510         }
00511 }
00512 
00513 Unit UnitClass::getBuildUnit()
00514 {
00515         if(exists())
00516                 return UnitTracker::Instance().getUnit(mUnit->getBuildUnit());
00517 
00518         return StaticUnits::nullunit;
00519 }
00520 
00521 Unit UnitClass::getTarget()
00522 {
00523         if(exists())
00524         {
00525                 if(mUnit->getOrderTarget())
00526                         return UnitTracker::Instance().getUnit(mUnit->getOrderTarget());
00527                 else
00528                         return UnitTracker::Instance().getUnit(mUnit->getTarget());
00529         }
00530 
00531         return StaticUnits::nullunit;
00532 }
00533 
00534 void UnitClass::build(TilePosition target, BWAPI::UnitType type)
00535 {
00536         if(exists())
00537         {
00538                 const Position targetPosition(target.x()*32+type.tileWidth()*16, target.y()*32+type.tileHeight()*16);
00539                 if(getDistance(type, targetPosition) > 48 || !MapHelper::isAllVisible(target, type))
00540                 {
00541                         move(targetPosition, 0);
00542                         return;
00543                 }
00544 
00545                 if(mUnit->getOrder() == BWAPI::Orders::PlaceBuilding)
00546                 {
00547                         if(mUnit->getBuildType() == type && mUnit->getOrderTargetPosition() == targetPosition)
00548                                 return;
00549                 }
00550 
00551                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Build && mUnit->getLastCommand().getUnitType() == type && mUnit->getLastCommand().getTargetTilePosition() == target)
00552                 {
00553                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00554                                 return;
00555                 }
00556 
00557                 if(mUnit->build(target, type))
00558                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00559                 else
00560                         move(targetPosition, 0);
00561         }
00562 }
00563 
00564 void UnitClass::build(Unit unit)
00565 {
00566         if(exists() && unit && unit->exists())
00567         {
00568                 mUnit->rightClick(unit->mUnit);
00569                 unit->mUnit->rightClick(mUnit);
00570         }
00571 }
00572 
00573 bool UnitClass::hasAddon()
00574 {
00575         if(exists())
00576                 return mUnit->getAddon() != NULL;
00577 
00578         return false;
00579 }
00580 
00581 void UnitClass::morph(BWAPI::UnitType type)
00582 {
00583         if(exists())
00584                 mUnit->morph(type);
00585 }
00586 
00587 BWAPI::UnitType UnitClass::getBuildType()
00588 {
00589         if(mUnit)
00590         {
00591                 if(mUnit->exists())
00592                         return mUnit->getBuildType();
00593                 else
00594                         return BWAPI::UnitTypes::Unknown;
00595         }
00596 
00597         return BWAPI::UnitTypes::None;
00598 }
00599 
00600 int UnitClass::getID()
00601 {
00602         if(mUnit)
00603                 return mUnit->getID();
00604 
00605         return 0;
00606 }
00607 
00608 int UnitClass::getResources()
00609 {
00610         if(exists())
00611                 return mUnit->getResources();
00612 
00613         return mStoredInt;
00614 }
00615 
00616 bool UnitClass::isUpgrading()
00617 {
00618         if(exists())
00619                 return mUnit->isUpgrading();
00620 
00621         return false;
00622 }
00623 
00624 BWAPI::UpgradeType UnitClass::getUpgrade()
00625 {
00626         if(exists())
00627                 return mUnit->getUpgrade();
00628         
00629         return BWAPI::UpgradeTypes::None;
00630 }
00631 
00632 void UnitClass::upgrade(BWAPI::UpgradeType type)
00633 {
00634         if(exists())
00635                 mUnit->upgrade(type);
00636 }
00637 
00638 BWAPI::TechType UnitClass::getTech()
00639 {
00640         if(exists())
00641                 return mUnit->getTech();
00642 
00643         return BWAPI::TechTypes::None;
00644 }
00645 
00646 bool UnitClass::cancel(int slot)
00647 {
00648         if(exists())
00649         {
00650                 if(mUnit->isResearching())
00651                         mUnit->cancelResearch();
00652                 else if(mUnit->isUpgrading())
00653                         mUnit->cancelUpgrade();
00654                 else if(mUnit->isTraining())
00655                         mUnit->cancelTrain(slot);
00656                 else if(mUnit->isMorphing())
00657                         mUnit->cancelMorph();
00658                 else if(mUnit->isBeingConstructed() || !mUnit->isCompleted())
00659                         mUnit->cancelConstruction();
00660                 else if(mUnit->isConstructing())
00661                         mUnit->haltConstruction();
00662                 else
00663                         return false;
00664 
00665                 return true;
00666         }
00667 
00668         return false;
00669 }
00670 
00671 void UnitClass::research(BWAPI::TechType mType)
00672 {
00673         if(exists())
00674                 mUnit->research(mType);
00675 }
00676 
00677 void UnitClass::move(Position target, int accuracy)
00678 {
00679         if(exists())
00680         {
00681                 if(mUnit->getOrder() == BWAPI::Orders::Move)
00682                 {
00683                         if(mUnit->getOrderTargetPosition().getApproxDistance(target) <= accuracy)
00684                                 return;
00685                 }
00686                 
00687                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Move && mUnit->getLastCommand().getTargetPosition().getApproxDistance(target) <= accuracy)
00688                 {
00689                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00690                                 return;
00691                         else if((mUnit->getOrder() == BWAPI::Orders::Guard || mUnit->getOrder() == BWAPI::Orders::PlayerGuard) && getPosition().getApproxDistance(target) <= accuracy*4)
00692                                 return;
00693                 }
00694 
00695                 if(mUnit->move(target))
00696                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00697         }
00698 }
00699 
00700 void UnitClass::attack(Unit unit)
00701 {
00702         if(exists() && unit)
00703         {
00704                 if(!unit->exists())
00705                 {
00706                         move(unit->getPosition());
00707                         return;
00708                 }
00709 
00710                 if(mUnit->getOrder() == BWAPI::Orders::AttackUnit)
00711                 {
00712                         if(mUnit->getOrderTarget() == unit->mUnit)
00713                                 return;
00714                 }
00715 
00716                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Unit && mUnit->getLastCommand().getTarget() == unit->mUnit)
00717                 {
00718                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00719                                 return;
00720                 }
00721 
00722                 if(mUnit->attack(unit->mUnit))
00723                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00724         }
00725 }
00726 
00727 void UnitClass::attack(Position target, int accuracy)
00728 {
00729         if(exists())
00730         {
00731                 if(mUnit->getOrder() == BWAPI::Orders::AttackMove)
00732                 {
00733                         if(mUnit->getOrderTargetPosition().getApproxDistance(target) <= accuracy)
00734                                 return;
00735                 }
00736 
00737                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Attack_Move && mUnit->getLastCommand().getTargetPosition().getApproxDistance(target) <= accuracy)
00738                 {
00739                         if(mUnit->getOrder() == BWAPI::Orders::Guard || mUnit->getOrder() == BWAPI::Orders::PlayerGuard)
00740                                 return;
00741                         else if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00742                                 return;
00743                 }
00744 
00745                 if(mUnit->attack(target))
00746                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00747         }
00748 }
00749 
00750 void UnitClass::gather(Unit unit)
00751 {
00752         if(exists() && unit)
00753         {
00754                 if(!unit->exists())
00755                 {
00756                         move(unit->getPosition());
00757                         return;
00758                 }
00759         
00760                 if(unit->getType() == BWAPI::UnitTypes::Resource_Mineral_Field)
00761                 {
00762                         if(mUnit->getOrder() == BWAPI::Orders::MoveToMinerals || mUnit->getOrder() == BWAPI::Orders::WaitForMinerals || mUnit->getOrder() == BWAPI::Orders::MiningMinerals)
00763                         {
00764                                 if(mUnit->getOrderTarget() == unit->mUnit)
00765                                         return;
00766                         }
00767                 }
00768                 else if(unit->getType().isRefinery())
00769                 {
00770                         if(mUnit->getOrder() == BWAPI::Orders::Harvest1)
00771                                 return;
00772                         else if(mUnit->getOrder() == BWAPI::Orders::MoveToGas || mUnit->getOrder() == BWAPI::Orders::WaitForGas || mUnit->getOrder() == BWAPI::Orders::HarvestGas)
00773                         {
00774                                 if(mUnit->getOrderTarget() == unit->mUnit)
00775                                         return;
00776                         }
00777                 }
00778                 else
00779                         return;
00780 
00781                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Gather && mUnit->getLastCommand().getTarget() == unit->mUnit)
00782                 {
00783                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00784                                 return;
00785                 }
00786 
00787                 if(mUnit->gather(unit->mUnit))
00788                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00789         }
00790 }
00791 
00792 void UnitClass::returnCargo()
00793 {
00794         if(exists())
00795         {
00796                 if(mUnit->getOrder() == BWAPI::Orders::ReturnGas || mUnit->getOrder() == BWAPI::Orders::ReturnMinerals)
00797                         return;
00798 
00799                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Return_Cargo)
00800                 {
00801                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00802                                 return;
00803                 }
00804 
00805                 if(mUnit->returnCargo())
00806                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00807         }
00808 }
00809 
00810 void UnitClass::returnCargo(Unit unit)
00811 {
00812         if(!unit)
00813                 return;
00814 
00815         if(!unit->exists() || !unit->isCompleted())
00816         {
00817                 move(unit->getPosition());
00818                 return;
00819         }
00820 
00821         if(exists())
00822         {
00823                 if(mUnit->getOrder() == BWAPI::Orders::ResetCollision)
00824                         return;
00825                 
00826                 if(mUnit->getOrder() == BWAPI::Orders::ReturnGas || mUnit->getOrder() == BWAPI::Orders::ReturnMinerals)
00827                 {
00828                         if(mUnit->getOrderTarget() == unit->mUnit)
00829                                 return;
00830                 }
00831 
00832                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Right_Click_Unit && mUnit->getLastCommand().getTarget() == unit->mUnit)
00833                 {
00834                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00835                                 return;
00836                 }
00837 
00838                 if(mUnit->rightClick(unit->mUnit))
00839                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00840         }
00841 }
00842 
00843 void UnitClass::stop()
00844 {
00845         if(exists())
00846         {
00847                 if(mUnit->getOrder() == BWAPI::Orders::Stop)
00848                         return;
00849 
00850                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Stop)
00851                 {
00852                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
00853                                 return;
00854                 }
00855 
00856                 if(mUnit->stop())
00857                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
00858         }
00859 }
00860 
00861 void UnitClass::promote(BWAPI::Unit* unit)
00862 {
00863         mUnit = unit;
00864         mStoredAccessType = AccessType::Full;
00865         update();
00866 }
00867 
00868 void UnitClass::setBuildTime(int time)
00869 {
00870         mStoredExistsTime = time;
00871 
00872         mStoredCompletedTime = time + getType().buildTime();
00873         if(mStoredCompletedTime < time)
00874                 mStoredCompletedTime = std::numeric_limits<int>::max();
00875 }
00876 
00877 double UnitClass::totalHitPointFraction()
00878 {
00879         double currentHealth = totalHitPoints();
00880 
00881         return currentHealth / double(getType().maxHitPoints() + getType().maxShields());
00882 }
00883 
00884 int UnitClass::totalHitPoints()
00885 {
00886         return getHealth() + getShield() + getDefenseMatrixPoints(); 
00887 }
00888 
00889 int UnitClass::getHealth()
00890 {
00891         if(exists())
00892                 return mUnit->getHitPoints();
00893 
00894         return mStoredHealth;
00895 }
00896 
00897 int UnitClass::getShield()
00898 {
00899         if(exists())
00900                 return mUnit->getShields();
00901 
00902         return mStoredShield;
00903 }
00904 
00905 int UnitClass::getDefenseMatrixPoints()
00906 {
00907         if(exists())
00908                 return mUnit->getDefenseMatrixPoints();
00909 
00910         return 0;
00911 }
00912 
00913 void UnitClass::setPosition(Position position)
00914 {
00915         mStoredPosition = position;
00916         mStoredTargetPosition = position;
00917 }
00918 
00919 bool UnitClass::isSelected()
00920 {
00921         if(exists())
00922                 return mUnit->isSelected();
00923 
00924         return false;
00925 }
00926 
00927 bool UnitClass::hasPath(Position position)
00928 {
00929         if(exists())
00930                 return mUnit->hasPath(position);
00931 
00932         return BWAPI::Broodwar->hasPath(getPosition(), position);
00933 }
00934 
00935 bool UnitClass::isStasised()
00936 {
00937         if(exists())
00938                 if(mUnit->isStasised())
00939                         return true;
00940 
00941         return LatencyTracker::Instance().isStasisInRange(shared_from_this());
00942 }
00943 
00944 bool UnitClass::isLockedDown()
00945 {
00946         if(exists())
00947                 return mUnit->isLockedDown();
00948 
00949         return false;
00950 }
00951 
00952 bool UnitClass::isCloaked()
00953 {
00954         if(exists())
00955                 return mUnit->isCloaked();
00956 
00957         return false;
00958 }
00959 
00960 bool UnitClass::isBurrowed()
00961 {
00962         if(exists())
00963                 return mUnit->isBurrowed();
00964 
00965         return false;
00966 }
00967 
00968 bool UnitClass::isDetected()
00969 {
00970         if(exists())
00971                 return mUnit->isDetected();
00972 
00973         return false;
00974 }
00975 
00976 bool UnitClass::isStuck()
00977 {
00978         if(exists())
00979                 return mUnit->isStuck();
00980 
00981         return false;
00982 }
00983 
00984 bool UnitClass::isUnderStorm()
00985 {
00986         if(exists())
00987                 if(mUnit->isUnderStorm())
00988                         return true;
00989 
00990         return LatencyTracker::Instance().isStormInRange(shared_from_this());
00991 }
00992 
00993 bool UnitClass::isUnderDarkSwarm()
00994 {
00995         if(exists())
00996                 if(mUnit->isUnderDarkSwarm())
00997                         return true;
00998 
00999         return false;
01000 }
01001 
01002 bool UnitClass::isLoaded()
01003 {
01004         if(exists())
01005                 return mUnit->isLoaded();
01006 
01007         return false;
01008 }
01009 
01010 bool UnitClass::canAttackNow(Unit unit)
01011 {
01012         if(!unit || !exists() || !unit->exists())
01013                 return false;
01014 
01015         return canAttack(unit);
01016 }
01017 
01018 bool UnitClass::canAttack(Unit unit)
01019 {
01020         if(!unit)
01021                 return false;
01022 
01023         if(mUnit->isLockedDown() || mUnit->isStasised() || unit->isStasised())
01024                 return false;
01025 
01026         if((unit->isCloaked() || unit->isBurrowed()) && !unit->isDetected())
01027                 return false;
01028 
01029         if(unit->getType().isFlyer() || unit->isLifted())
01030                 return canAttackAir();
01031         else
01032                 return canAttackGround();
01033 }
01034 
01035 bool UnitClass::isInRange(Unit unit)
01036 {
01037         int weaponMaxRange = getWeaponMaxRange(unit);
01038 
01039         if(weaponMaxRange <= 0)
01040                 return false;
01041 
01042         int distance = getDistance(unit);
01043         int weaponMinRange = getWeaponMinRange(unit);
01044         
01045         if(weaponMinRange != 0 && distance <= weaponMinRange)
01046                 return false;
01047 
01048         return weaponMaxRange >= distance;
01049 }
01050 
01051 
01052 int UnitClass::getGroundWeaponMaxRange()
01053 {
01054         if(getType() == BWAPI::UnitTypes::Protoss_Reaver)
01055                 return 256;
01056         else
01057                 return getPlayer()->weaponMaxRange(getType().groundWeapon());
01058 }
01059 
01060 int UnitClass::getAirWeaponMaxRange()
01061 {
01062         return getPlayer()->weaponMaxRange(getType().airWeapon());
01063 }
01064 
01065 int UnitClass::getWeaponMaxRange(Unit unit)
01066 {
01067         if(!unit)
01068                 return 0;
01069 
01070         if(unit->getType().isFlyer() || unit->isLifted())
01071                 return getAirWeaponMaxRange();
01072         else
01073                 return getGroundWeaponMaxRange();
01074 }
01075 
01076 int UnitClass::getWeaponMinRange(Unit unit)
01077 {
01078         if(!unit)
01079                 return 0;
01080 
01081         if(unit->getType().isFlyer() || unit->isLifted())
01082                 return getType().airWeapon().minRange();
01083         else
01084                 return getType().groundWeapon().minRange();
01085 }
01086 
01087 int UnitClass::getWeaponCooldown(Unit unit)
01088 {
01089         if(!unit)
01090                 return 0;
01091 
01092         if(getType() == BWAPI::UnitTypes::Protoss_Reaver)
01093                 return 60;
01094 
01095         if(unit->getType().isFlyer() || unit->isLifted())
01096                 return getType().airWeapon().damageCooldown();
01097         else
01098                 return getType().groundWeapon().damageCooldown();
01099 }
01100 
01101 int UnitClass::getRemainingCooldown(Unit unit)
01102 {
01103         if(!unit)
01104                 return 0;
01105 
01106         if(unit->getType().isFlyer() || unit->isLifted())
01107                 return getRemainingAirCooldown();
01108         else
01109                 return getRemainingGroundCooldown();
01110 }
01111 
01112 int UnitClass::getRemainingGroundCooldown()
01113 {
01114         if(exists())
01115                 return mUnit->getGroundWeaponCooldown();
01116 
01117         return 0;
01118 }
01119 
01120 int UnitClass::getRemainingAirCooldown()
01121 {
01122         if(exists())
01123                 return mUnit->getAirWeaponCooldown();
01124 
01125         return 0;
01126 }
01127 
01128 int UnitClass::getSpellCooldown()
01129 {
01130         if(exists())
01131                 return mUnit->getSpellCooldown();
01132 
01133         return 0;
01134 }
01135 
01136 int UnitClass::getTimeToKill(Unit unit)
01137 {
01138         int health = unit->totalHitPoints();
01139 
01140         BWAPI::WeaponType weapon = getWeapon(unit);
01141 
01142         int weaponDamage = weapon.damageAmount() + (weapon.damageFactor() * getPlayer()->getUpgradeLevel(weapon.upgradeType()));
01143         if(weaponDamage == 0)
01144                 return 5000;
01145 
01146         int thisNumberOfShots = health / weaponDamage;
01147 
01148         if(weapon.damageType() == BWAPI::DamageTypes::Concussive)
01149         {
01150                 if(unit->getType().size() == BWAPI::UnitSizeTypes::Large)
01151                         thisNumberOfShots *= 4;
01152                 else if(unit->getType().size() == BWAPI::UnitSizeTypes::Medium)
01153                         thisNumberOfShots += thisNumberOfShots;
01154         }
01155         else if(weapon.damageType() == BWAPI::DamageTypes::Explosive)
01156         {
01157                 if(unit->getType().size() == BWAPI::UnitSizeTypes::Small)
01158                         thisNumberOfShots += thisNumberOfShots;
01159                 else if(unit->getType().size() == BWAPI::UnitSizeTypes::Medium)
01160                         thisNumberOfShots += thisNumberOfShots / 2;
01161         }
01162 
01163         if((BWAPI::Broodwar->getGroundHeight(getTilePosition()) - BWAPI::Broodwar->getGroundHeight(unit->getTilePosition())) < 0)
01164                 thisNumberOfShots += thisNumberOfShots;
01165 
01166         return thisNumberOfShots * weapon.damageCooldown();
01167 }
01168 
01169 BWAPI::WeaponType UnitClass::getWeapon(Unit unit)
01170 {
01171         if(!unit)
01172                 return BWAPI::WeaponTypes::None;
01173 
01174         if(unit->getType().isFlyer() || unit->isLifted())
01175                 return getType().airWeapon();
01176         else
01177         {
01178                 if(getType() == BWAPI::UnitTypes::Protoss_Reaver)
01179                         return BWAPI::WeaponTypes::Scarab;
01180                 else
01181                         return getType().groundWeapon();
01182         }
01183 }
01184 
01185 bool UnitClass::canAttackGround()
01186 {
01187         const BWAPI::UnitType &type = getType();
01188         if(type == BWAPI::UnitTypes::Protoss_Reaver)
01189                 return getScarabCount() != 0;
01190 
01191         if(type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine)
01192                 return true;
01193 
01194         return type.groundWeapon() != BWAPI::WeaponTypes::None;
01195 }
01196 
01197 bool UnitClass::canAttackAir()
01198 {
01199         return getType().airWeapon() != BWAPI::WeaponTypes::None;
01200 }
01201 
01202 bool UnitClass::isAttackFrame()
01203 {
01204         if(exists())
01205                 return mUnit->isAttackFrame();
01206 
01207         return false;
01208 }
01209 
01210 int UnitClass::getScarabCount()
01211 {
01212         if(exists())
01213                 return mUnit->getScarabCount();
01214 
01215         return 0;
01216 }
01217 
01218 bool UnitClass::isRepairing()
01219 {
01220         if(exists())
01221                 return mUnit->isRepairing();
01222 
01223         return false;
01224 }
01225 
01226 bool UnitClass::isHealing()
01227 {
01228         if(exists())
01229                 return mUnit->getOrder() == BWAPI::Orders::MedicHeal1 || mUnit->getOrder() == BWAPI::Orders::MedicHeal2;
01230 
01231         return false;
01232 }
01233 
01234 BWAPI::UnitCommand UnitClass::getLastCommand()
01235 {
01236         if(exists())
01237                 return mUnit->getLastCommand();
01238 
01239         return BWAPI::UnitCommand();
01240 }
01241 
01242 bool UnitClass::isBeingHealed()
01243 {
01244         if(exists())
01245                 return mUnit->isBeingHealed();
01246 
01247         return false;
01248 }
01249 
01250 bool UnitClass::isBeingRepaired()
01251 {
01252         //TODO: implement
01253         return false;
01254 }
01255 
01256 int UnitClass::getDistance(BWAPI::UnitType targType, Position position)
01257 {
01258         return UnitHelper::getDistance(getPosition(), getType(), position, targType);
01259 }
01260 
01261 int UnitClass::getDistance(Unit unit)
01262 {
01263         if(!unit)
01264                 return 0;
01265 
01266         return getDistance(unit->getType(), unit->getPosition());
01267 }
01268 
01269 int UnitClass::getDistance(Position position)
01270 {
01271         return UnitHelper::getDistance(getPosition(), getType(), position);
01272 }
01273 
01274 int UnitClass::getDistance(Position position, int inFramesTime)
01275 {
01276         return UnitHelper::getDistance(getPosition(inFramesTime), getType(), position);
01277 }
01278 
01279 std::list<BWAPI::UnitType> UnitClass::getTrainingQueue()
01280 {
01281         if(exists())
01282                 return mUnit->getTrainingQueue();
01283 
01284         return std::list<BWAPI::UnitType>();
01285 }
01286 
01287 int UnitClass::getEnergy()
01288 {
01289         if(exists())
01290                 return mUnit->getEnergy();
01291 
01292         return 0;
01293 }
01294 
01295 BWAPI::Order getTechCastOrder(BWAPI::TechType tech)
01296 {
01297         if(tech == BWAPI::TechTypes::Psionic_Storm)
01298                 return BWAPI::Orders::CastPsionicStorm;
01299         else if(tech == BWAPI::TechTypes::Archon_Warp)
01300                 return BWAPI::Orders::ArchonWarp;
01301         else if(tech == BWAPI::TechTypes::Stasis_Field)
01302                 return BWAPI::Orders::CastStasisField;
01303         else if(tech == BWAPI::TechTypes::Recall)
01304                 return BWAPI::Orders::CastRecall;
01305 
01306         return BWAPI::Orders::None;
01307 }
01308 
01309 void UnitClass::useTech(BWAPI::TechType tech, BWAPI::Position target)
01310 {
01311         if(exists())
01312         {
01313                 if(mUnit->getOrder() == getTechCastOrder(tech))
01314                 {
01315                         if(mUnit->getOrderTargetPosition() == target)
01316                                 return;
01317                 }
01318 
01319                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Use_Tech_Position && mUnit->getLastCommand().getTechType() == tech && mUnit->getLastCommand().getTargetPosition() == target)
01320                 {
01321                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
01322                                 return;
01323                 }
01324 
01325                 if(mUnit->useTech(tech, target))
01326                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
01327         }
01328 }
01329 
01330 void UnitClass::useTech(BWAPI::TechType tech, Unit target)
01331 {
01332         if(exists() && target)
01333         {
01334                 if(!target->exists())
01335                 {
01336                         move(target->getPosition());
01337                         return;
01338                 }
01339 
01340                 if(mUnit->getOrder() == getTechCastOrder(tech))//TODO: in latest revision, the tech knows the relating order
01341                 {
01342                         if(mUnit->getOrderTarget() == target->mUnit)
01343                                 return;
01344                 }
01345 
01346                 if(mUnit->getLastCommand().getType() == BWAPI::UnitCommandTypes::Use_Tech_Unit && mUnit->getLastCommand().getTechType() == tech && mUnit->getLastCommand().getTarget() == target->mUnit)
01347                 {
01348                         if(mLastOrderExecuteTime >= BWAPI::Broodwar->getFrameCount())
01349                                 return;
01350                 }
01351 
01352                 if(mUnit->useTech(tech, target->mUnit))
01353                         mLastOrderExecuteTime = BWAPI::Broodwar->getFrameCount() + BWAPI::Broodwar->getRemainingLatencyFrames();
01354         }
01355 }
01356 
01357 bool UnitClass::hasOrder(BWAPI::Order order)
01358 {
01359         if(getOrder() == order)
01360                 return true;
01361         else if(getSecondaryOrder() == order)
01362                 return true;
01363         else
01364                 return false;
01365 }
01366 
01367 void UnitClass::update()
01368 {
01369         if(exists())
01370         {
01371                 mStoredTime = BWAPI::Broodwar->getFrameCount();
01372 
01373                 mStoredPosition = mUnit->getPosition();
01374                 mStoredType = mUnit->getType();
01375                 mStoredPlayer = mUnit->getPlayer();
01376                 mStoredInt = mUnit->getResources();
01377 
01378                 if(mStoredCompleted && !mUnit->isCompleted())
01379                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount() + mUnit->getType().buildTime();
01380                 mStoredCompleted = mUnit->isCompleted();
01381 
01382                 if(!mStoredMorphing && mUnit->isMorphing())
01383                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount() + mUnit->getBuildType().buildTime();
01384                 mStoredMorphing = mUnit->isMorphing();
01385 
01386                 if(mUnit->getPlayer() == BWAPI::Broodwar->self())
01387                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount() + mUnit->getRemainingBuildTime();
01388                 else if(mUnit->isCompleted() && !mUnit->isMorphing())
01389                         mStoredCompletedTime = BWAPI::Broodwar->getFrameCount();
01390 
01391                 mStoredTargetPosition = mUnit->getTargetPosition();
01392 
01393                 mStoredHealth = mUnit->getHitPoints();
01394                 mStoredShield = mUnit->getShields();
01395 
01396                 if(mUnit->getType().isFlyingBuilding())
01397                         mStoredBoolOne = mUnit->isLifted();
01398                 else if(mUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Siege_Mode || mUnit->getType() == BWAPI::UnitTypes::Terran_Siege_Tank_Tank_Mode)
01399                         mStoredBoolOne = mUnit->isSieged();
01400 
01401                 mStoredAccessType = accessibility();
01402         }
01403 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines