BWAPI
|
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 ¤tPosition = 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 }