BWAPI
|
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 }