BWAPI
Skynet/Skynet/BasicUnitAction.cpp
Go to the documentation of this file.
00001 #include "BasicUnitAction.h"
00002 
00003 #include <limits>
00004 
00005 #include "UnitTracker.h"
00006 #include "AOEThreatTracker.h"
00007 #include "UnitHelper.h"
00008 
00009 void stayAtRange(Unit unit, Position targetPositon, int maxRange, int currentRange)
00010 {
00011         Position current = unit->getPosition();
00012 
00013         Vector direction = current - targetPositon;
00014 
00015         direction.normalise();
00016         direction *= float(maxRange - currentRange);
00017         direction += Vector(current);
00018 
00019         unit->move(direction);
00020 }
00021 
00022 bool BasicUnitAction::update(const Goal &squadGoal, const UnitGroup &squadUnitGroup)
00023 {
00024         const int seekRange = 448;
00025         // TODO: Implement a better system, maybe some PFs and other goodies
00026         // currently a copy paste of 2010 micro
00027 
00028         if(mUnit->isAttackFrame() || mUnit->isStasised() || mUnit->isLockedDown())
00029                 return true;
00030 
00031         const bool isTargetOfThreat = AOEThreatTracker::Instance().isTargetOfThreat(mUnit);
00032         if(!isTargetOfThreat)
00033         {
00034                 const AOEThreat &closestThreat = AOEThreatTracker::Instance().getClosestThreat(mUnit);
00035                 if(closestThreat)
00036                 {
00037                         const int distanceToThreat = mUnit->getDistance(closestThreat->getPosition());
00038                         if(distanceToThreat < closestThreat->getRadius()+32)
00039                         {
00040                                 stayAtRange(mUnit, closestThreat->getPosition(), closestThreat->getRadius() + 64, distanceToThreat);
00041                                 return true;
00042                         }
00043                 }
00044         }
00045 
00046         const BWAPI::UnitType &actionUnitType = mUnit->getType();
00047 
00048         const bool shouldEngage = squadGoal.getActionType() == ActionType::Attack || squadGoal.getActionType() == ActionType::Defend || squadGoal.getActionType() == ActionType::Hold;
00049 
00050         int currentTargetPriority = std::numeric_limits<int>::max();
00051         Unit currentTargetUnit;
00052 
00053         int goalTartgetDistance = std::numeric_limits<int>::max();
00054         int goalTargetPriority = std::numeric_limits<int>::max();
00055         Unit goalTargetUnit;
00056 
00057         int closestUnitDistance = std::numeric_limits<int>::max();
00058         int closestUnitRange = 0;
00059         Unit closestUnit;
00060 
00061         UnitGroup possibleTargets;
00062         for each(Unit unit in UnitTracker::Instance().selectAllEnemy())
00063         {
00064                 if(unit->isStasised())
00065                         continue;
00066 
00067                 const BWAPI::UnitType &type = unit->getType();
00068                 if(type == BWAPI::UnitTypes::Zerg_Egg || type == BWAPI::UnitTypes::Zerg_Larva || type == BWAPI::UnitTypes::Protoss_Scarab)
00069                         continue;
00070 
00071                 if(unit->accessibility() == AccessType::Lost)
00072                         continue;
00073 
00074                 if(mUnit->getPosition().getApproxDistance(unit->getPosition()) > seekRange)
00075                         continue;
00076 
00077                 if(unit->canAttack(mUnit) || type == BWAPI::UnitTypes::Terran_Science_Vessel)
00078                 {
00079                         const int weaponRange = type == BWAPI::UnitTypes::Terran_Science_Vessel ? BWAPI::TechTypes::EMP_Shockwave.getWeapon().maxRange() : type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine ? BWAPI::UnitTypes::Terran_Vulture_Spider_Mine.seekRange() : unit->getWeaponMaxRange(mUnit);
00080                         const int distance = mUnit->getDistance(unit) - weaponRange;
00081                         if(distance < closestUnitDistance)
00082                         {
00083                                 closestUnitRange = weaponRange;
00084                                 closestUnitDistance = distance;
00085                                 closestUnit = unit;
00086                         }
00087                 }
00088 
00089                 if(type == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine && actionUnitType == BWAPI::UnitTypes::Protoss_Zealot)
00090                         continue;
00091 
00092                 if(!mUnit->canAttackNow(unit))
00093                         continue;
00094 
00095                 //TODO: health tracker of some type, if the unit will be dead by the time the bullet hits, continue
00096 
00097                 const bool isActionUnitSlower = actionUnitType.topSpeed()*0.7 < type.topSpeed();
00098                 const bool isUnitGoalWorthy = (shouldEngage && squadGoal.getEngageUnits().count(unit) != 0) || unit->isInRange(mUnit) || mUnit->isInRange(unit);
00099 
00100                 int unitPriority = isUnitGoalWorthy ? 0 : isActionUnitSlower ? 4 : 2;
00101 
00102                 std::list<std::set<BWAPI::UnitType>>::const_iterator it = mTargetPriorities.begin();
00103                 while(it != mTargetPriorities.end())
00104                 {
00105                         if(it->count(type) != 0)
00106                                 break;
00107                         else
00108                                 ++unitPriority;
00109 
00110                         ++it;
00111                 }
00112 
00113                 if(it == mTargetPriorities.end())//Unit not found in the priorities list
00114                 {
00115                         if(UnitHelper::isArmyUnit(type) || UnitHelper::isStaticDefense(type) || type == BWAPI::UnitTypes::Terran_Bunker)
00116                                 unitPriority += 1;
00117                         else if(type.isWorker())
00118                                 unitPriority += 2;
00119                         else if(type.supplyProvided() > 0)
00120                                 unitPriority += 3;
00121                         else
00122                                 unitPriority += 4;
00123 
00124                         if(!unit->isCompleted())
00125                                 unitPriority += 1;
00126                 }
00127 
00128                 if(squadGoal.getActionType() != ActionType::Retreat && mUnit->isInRange(unit))
00129                 {
00130                         if(unitPriority < currentTargetPriority || (unitPriority == currentTargetPriority && unit->totalHitPointFraction() < currentTargetUnit->totalHitPointFraction()))
00131                         {
00132                                 currentTargetPriority = unitPriority;
00133                                 currentTargetUnit = unit;
00134                         }
00135                 }
00136 
00137                 if(!isUnitGoalWorthy && isActionUnitSlower)
00138                         continue;
00139 
00140                 const int distance = mUnit->getDistance(unit);
00141                 if(unitPriority < goalTargetPriority || (unitPriority == goalTargetPriority && distance < goalTartgetDistance))
00142                 {
00143                         goalTartgetDistance = distance;
00144                         goalTargetPriority = unitPriority;
00145                         goalTargetUnit = unit;
00146                 }
00147         }
00148 
00149         // If the target of a threat, dont do anything to cause it to move
00150         if(isTargetOfThreat)
00151         {
00152                 if(currentTargetUnit)
00153                         mUnit->attack(currentTargetUnit);
00154                 else
00155                         mUnit->stop();
00156                 return true;
00157         }
00158         
00159         const int closestDistance = closestUnit ? mUnit->getDistance(closestUnit) : 0;
00160         if(closestUnit)
00161         {
00162                 bool doNotEngageClosest = false;
00163                 if(closestDistance < closestUnitRange + 250)
00164                 {
00165                         if(squadGoal.getAvoidUnits().count(closestUnit) != 0)
00166                                 doNotEngageClosest = true;
00167                         else
00168                                 doNotEngageClosest = !goalTargetUnit && mUnit->getDistance(squadGoal.getPositionForMerge()) < 140;
00169                 }
00170 
00171                 if(doNotEngageClosest)
00172                 {
00173                         stayAtRange(mUnit, closestUnit->getPosition(), closestUnitRange + 290, closestDistance);
00174                         return true;
00175                 }
00176 
00177                 bool canAttack = mUnit->canAttackAir() || mUnit->canAttackGround();
00178                 if(actionUnitType == BWAPI::UnitTypes::Protoss_Arbiter)
00179                         canAttack = false;
00180 
00181                 if(!canAttack && actionUnitType.isSpellcaster())
00182                 {
00183                         for each(BWAPI::TechType tech in mUnit->getType().abilities())
00184                         {
00185                                 if(BWAPI::Broodwar->self()->hasResearched(tech) && mUnit->getEnergy() >= tech.energyUsed())
00186                                         canAttack = true;
00187                         }
00188                 }
00189 
00190                 int rangeToStayAt = 0;
00191                 if(!canAttack)
00192                         rangeToStayAt = closestUnitRange+32;
00193 
00194                 if(actionUnitType.maxEnergy() > 0 && closestUnit->getType() == BWAPI::UnitTypes::Terran_Science_Vessel)
00195                         rangeToStayAt = std::max(rangeToStayAt, BWAPI::TechTypes::EMP_Shockwave.getWeapon().maxRange()+32);
00196 
00197                 if(rangeToStayAt != 0 && closestDistance < rangeToStayAt)
00198                 {
00199                         stayAtRange(mUnit, closestUnit->getPosition(), rangeToStayAt, closestDistance);
00200                         return true;
00201                 }
00202         }
00203 
00204         const bool canAttackCurrentTarget = currentTargetUnit && mUnit->getRemainingCooldown(currentTargetUnit) <= BWAPI::Broodwar->getRemainingLatencyFrames();
00205         const bool isCurrentTargetImportant = currentTargetUnit && (UnitHelper::isArmyUnit(currentTargetUnit->getType()) || UnitHelper::isStaticDefense(currentTargetUnit->getType()));
00206         const bool goalBetterThanCurrent = canAttackCurrentTarget && goalTargetPriority < currentTargetPriority && !isCurrentTargetImportant;
00207 
00208         if(goalBetterThanCurrent)
00209         {
00210                 mUnit->attack(goalTargetUnit);
00211                 return true;
00212         }
00213         else if(canAttackCurrentTarget)
00214         {
00215                 mUnit->attack(currentTargetUnit);
00216                 return true;
00217         }
00218 
00219         if(closestUnit && !goalTargetUnit && closestUnit->getType() == BWAPI::UnitTypes::Terran_Vulture_Spider_Mine)
00220         {
00221                 if(closestDistance < BWAPI::UnitTypes::Terran_Vulture_Spider_Mine.seekRange()+32)
00222                 {
00223                         stayAtRange(mUnit, closestUnit->getPosition(), BWAPI::UnitTypes::Terran_Vulture_Spider_Mine.seekRange()+32, closestDistance);
00224                         return true;
00225                 }
00226         }
00227 
00228         if(closestUnit && closestUnit->exists() && currentTargetUnit)
00229         {
00230                 if(mUnit->canAttack(closestUnit))
00231                 {
00232                         const int myRange = mUnit->getWeaponMaxRange(closestUnit);
00233                         if(closestDistance < myRange && myRange > 60)
00234                         {
00235                                 stayAtRange(mUnit, closestUnit->getPosition(), myRange, closestDistance);
00236                                 return true;
00237                         }
00238                 }
00239         }
00240 
00241         if(goalTargetUnit && goalTargetPriority < currentTargetPriority)
00242         {
00243                 mUnit->attack(goalTargetUnit);
00244                 return true;
00245         }
00246 
00247         if(!canAttackCurrentTarget)
00248         {
00249                 if(squadGoal.getActionType() == ActionType::Attack)
00250                 {
00251                         if(!isCurrentTargetImportant && mUnit->getDistance(currentTargetUnit) > 5)
00252                         {
00253                                 mUnit->move(currentTargetUnit->getPosition());
00254                                 return true;
00255                         }
00256                 }
00257         }
00258 
00259         if(currentTargetUnit)
00260         {
00261                 mUnit->attack(currentTargetUnit);
00262                 return true;
00263         }
00264 
00265         if(closestUnit && mUnit->canAttack(closestUnit))
00266         {
00267                 mUnit->attack(closestUnit);
00268                 return true;
00269         }
00270 
00271         return false;
00272 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines