BWAPI
|
00001 #include "DefaultSquad.h" 00002 00003 #include "UnitTracker.h" 00004 #include "BaseTracker.h" 00005 #include "BorderTracker.h" 00006 #include "BuildOrderManager.h" 00007 #include "PlayerTracker.h" 00008 #include "UnitHelper.h" 00009 #include "GameProgressDetection.h" 00010 00011 DefaultSquadTask::DefaultSquadTask(ArmyBehaviour behaviour) 00012 : BaseSquadTask(behaviour) 00013 , mEngageFull(false) 00014 { 00015 } 00016 00017 int DefaultSquadTask::getEndTime() const 00018 { 00019 return Requirement::maxTime; 00020 } 00021 00022 int DefaultSquadTask::getEndTime(Unit unit) const 00023 { 00024 return Requirement::maxTime; 00025 } 00026 00027 int DefaultSquadTask::getPriority(Unit unit) const 00028 { 00029 return unit->getType().isWorker() ? 5 : 20; 00030 } 00031 00032 Position DefaultSquadTask::getStartLocation(Unit unit) const 00033 { 00034 return unit->getPosition(); 00035 } 00036 00037 Position DefaultSquadTask::getEndLocation(Unit unit) const 00038 { 00039 return unit->getPosition(); 00040 } 00041 00042 bool DefaultSquadTask::preUpdate() 00043 { 00044 updateRequirements(); 00045 00046 return hasEnded(); 00047 } 00048 00049 BorderPosition getLargestChoke(const std::set<BorderPosition> &chokes) 00050 { 00051 int largestChokeSize = 0; 00052 BorderPosition largestChoke; 00053 for each(BorderPosition border in chokes) 00054 { 00055 int chokeSize = border.mChoke->getClearance(); 00056 if(chokeSize > largestChokeSize) 00057 { 00058 largestChoke = border; 00059 largestChokeSize = chokeSize; 00060 } 00061 } 00062 00063 return largestChoke; 00064 } 00065 00066 bool DefaultSquadTask::update() 00067 { 00068 Goal squadsGoal; 00069 00070 // Just attack if its not mining anywhere 00071 bool hasMiningBases = false; 00072 int techStructures = 0; 00073 Base baseToDefend; 00074 bool baseUnderAttack = false; 00075 const int mySupply = BWAPI::Broodwar->self()->supplyUsed(); 00076 for each(Base base in BaseTracker::Instance().getPlayerBases()) 00077 { 00078 const int techBuildings = base->getNumberOfTechBuildings(); 00079 if(!base->getEnemyThreats().empty() && (techBuildings > 0 || (!base->isMinedOut() && base->getResourceDepot()))) 00080 { 00081 bool thisUnderAttack = base->isUnderAttack(); 00082 if((thisUnderAttack && !baseUnderAttack) || (thisUnderAttack == baseUnderAttack && techBuildings > techStructures)) 00083 { 00084 baseUnderAttack = thisUnderAttack; 00085 baseToDefend = base; 00086 techStructures = techBuildings; 00087 } 00088 } 00089 00090 if(!base->getMinerals().empty() && base->getResourceDepot() && base->getResourceDepot()->exists()) 00091 hasMiningBases = true; 00092 } 00093 00094 UnitGroup avoidGroup; 00095 UnitGroup engageGroup; 00096 for each(const UnitGroup &unitGroup in PlayerTracker::Instance().getEnemyClusters()) 00097 { 00098 if(!hasMiningBases && mUnits.canMajorityAttack(unitGroup)) 00099 { 00100 engageGroup += unitGroup; 00101 continue; 00102 } 00103 00104 if(mUnits.minDistanceBetween(unitGroup) > 540) 00105 continue; 00106 00107 const int rating = mUnits.ratingDifference(unitGroup); 00108 if(mySupply < 360 && ((!mEngageFull && rating < -350) || rating < -1000)) 00109 avoidGroup += unitGroup; 00110 else if(mUnits.canMajorityAttack(unitGroup) && (mUnits.isWorthEngaging(unitGroup) || unitGroup.isAnyInRange(mUnits))) 00111 engageGroup += unitGroup; 00112 } 00113 00114 mEngageFull = !engageGroup.empty(); 00115 if(mEngageFull) 00116 squadsGoal = Goal(ActionType::Attack, engageGroup, avoidGroup); 00117 else if(baseUnderAttack) 00118 { 00119 const int rating = mUnits.ratingDifference(baseToDefend->getEnemyThreats()); 00120 if(rating >= 0 || (rating > -1000 && baseUnderAttack)) 00121 squadsGoal = Goal(ActionType::Defend, baseToDefend->getEnemyThreats(), avoidGroup); 00122 } 00123 00124 if(squadsGoal.getGoalType() == GoalType::None) 00125 { 00126 for each(Base base in BaseTracker::Instance().getPlayerBases()) 00127 { 00128 if(base->isContested()) 00129 { 00130 for each(Unit building in base->getBuildings()) 00131 { 00132 if(BWAPI::Broodwar->self()->isEnemy(building->getPlayer())) 00133 { 00134 squadsGoal = Goal(ActionType::Attack, building, engageGroup, avoidGroup); 00135 break; 00136 } 00137 } 00138 } 00139 00140 if(squadsGoal.getGoalType() != GoalType::None) 00141 break; 00142 } 00143 } 00144 00145 if(squadsGoal.getGoalType() == GoalType::None) 00146 { 00147 int enemyKnownSupply = 0; 00148 int enemyGuessSupply = 0; 00149 00150 for each(Unit unit in UnitTracker::Instance().selectAllEnemy()) 00151 { 00152 int supply = unit->getType().supplyRequired(); 00153 if(UnitHelper::isStaticDefense(unit->getType())) 00154 supply = 7; 00155 00156 if(unit->accessibility() != AccessType::Lost) 00157 enemyKnownSupply += supply; 00158 00159 enemyGuessSupply += supply; 00160 } 00161 00162 int alliesSize = 1; 00163 std::map<BWAPI::Force*, int> enemyForces; 00164 for each(Player player in BWAPI::Broodwar->getPlayers()) 00165 { 00166 if(player == BWAPI::Broodwar->self()) 00167 continue; 00168 00169 if(BWAPI::Broodwar->self()->isAlly(player)) 00170 ++alliesSize; 00171 00172 if(BWAPI::Broodwar->self()->isEnemy(player)) 00173 ++enemyForces[player->getForce()]; 00174 } 00175 00176 int maxEnemiesSize = 0; 00177 for each(std::pair<BWAPI::Force*, int> force in enemyForces) 00178 { 00179 if(force.second > maxEnemiesSize) 00180 maxEnemiesSize = force.second; 00181 } 00182 00183 bool shouldAttackBase = !hasMiningBases; 00184 if(mUnits.size() >= 3) 00185 { 00186 if(mySupply > 380) 00187 shouldAttackBase = true; 00188 else if(GameProgressDetection::Instance().getState() != StateType::TechHigh) 00189 { 00190 // If its a terran with siege tanks don't attack a base without leg speed and also ensure we are better matched as siege tanks can hurt 00191 bool isTerranWithSiege = PlayerTracker::Instance().isEnemyRace(BWAPI::Races::Terran) && PlayerTracker::Instance().enemyHasReseached(BWAPI::TechTypes::Tank_Siege_Mode); 00192 if(isTerranWithSiege && BWAPI::Broodwar->self()->getUpgradeLevel(BWAPI::UpgradeTypes::Leg_Enhancements) > 0 && mUnits.size() > 45 && mySupply > (enemyGuessSupply * 4)) 00193 shouldAttackBase = true; 00194 else if(!isTerranWithSiege && mUnits.size() > 35 && mySupply > (enemyKnownSupply * 4)) 00195 shouldAttackBase = true; 00196 else if(mArmyBehaviour <= ArmyBehaviour::Aggresive) 00197 { 00198 if(maxEnemiesSize <= alliesSize) 00199 shouldAttackBase = true; 00200 } 00201 00202 // Agains't weak opponents it can usually attack when these pass 00203 // how ever against stronger opponents, or terran with siege tanks it will just lose a few units time and again then lose to a push 00204 // easier to just sit back and turtle alittle 00205 /*else if(mArmyBehaviour <= ArmyBehaviour::Default) 00206 { 00207 if(mySupply > (enemyGuessSupply * 4)) 00208 shouldAttackBase = true; 00209 } 00210 else if(mArmyBehaviour == ArmyBehaviour::Defensive) 00211 { 00212 if(mySupply > (enemyGuessSupply * 5)) 00213 shouldAttackBase = true; 00214 }*/ 00215 } 00216 } 00217 00218 if(shouldAttackBase) 00219 { 00220 Base bestBaseToAttack; 00221 if(mLastGoal.getGoalType() == GoalType::Base && mLastGoal.getActionType() == ActionType::Attack && mLastGoal.getBase()->isEnemyBase()) 00222 bestBaseToAttack = mLastGoal.getBase(); 00223 00224 for each(Base base in BaseTracker::Instance().getEnemyBases()) 00225 { 00226 if(!bestBaseToAttack || base->getBuildings().size() < bestBaseToAttack->getBuildings().size()) 00227 bestBaseToAttack = base; 00228 } 00229 00230 if(bestBaseToAttack) 00231 squadsGoal = Goal(ActionType::Attack, bestBaseToAttack, engageGroup, avoidGroup); 00232 } 00233 } 00234 00235 if(squadsGoal.getGoalType() == GoalType::None && baseToDefend && mUnits.canMajorityAttack(baseToDefend->getEnemyThreats())) 00236 squadsGoal = Goal(ActionType::Defend, baseToDefend->getCenterLocation(), engageGroup, avoidGroup); 00237 00238 if(squadsGoal.getGoalType() == GoalType::None) 00239 { 00240 if(!BorderTracker::Instance().getBorderPositions(PositionType::TechDefenseChokepoint).empty()) 00241 squadsGoal = Goal(ActionType::Hold, getLargestChoke(BorderTracker::Instance().getBorderPositions(PositionType::TechDefenseChokepoint)).mChoke->getCenter(), engageGroup, avoidGroup); 00242 } 00243 00244 if(squadsGoal.getGoalType() == GoalType::None) 00245 { 00246 if(!BorderTracker::Instance().getBorderPositions(PositionType::DefenseChokepoint).empty()) 00247 squadsGoal = Goal(ActionType::Hold, getLargestChoke(BorderTracker::Instance().getBorderPositions(PositionType::DefenseChokepoint)).mChoke->getCenter(), engageGroup, avoidGroup); 00248 } 00249 00250 if(squadsGoal.getGoalType() == GoalType::None) 00251 squadsGoal = Goal(ActionType::Attack, Position(BWAPI::Broodwar->mapWidth()*24, BWAPI::Broodwar->mapHeight()*16), engageGroup, avoidGroup); 00252 00253 if(!mEngageFull && !avoidGroup.empty() && squadsGoal.getActionType() == ActionType::Attack && squadsGoal.getGoalType() == GoalType::Base) 00254 squadsGoal = Goal(ActionType::Attack, avoidGroup.getCenter(), engageGroup, avoidGroup); 00255 00256 mLastGoal = squadsGoal; 00257 if(squadsGoal.getGoalType() != GoalType::None) 00258 { 00259 for(std::map<Unit, Behaviour>::iterator it = mUnitBehaviours.begin(); it != mUnitBehaviours.end(); ++it) 00260 it->second.update(squadsGoal, mUnits); 00261 } 00262 00263 return hasEnded() && mUnits.empty(); 00264 } 00265 00266 bool DefaultSquadTask::waitingForUnit(Unit unit) const 00267 { 00268 return false; 00269 } 00270 00271 void DefaultSquadTask::giveUnit(Unit unit) 00272 { 00273 if(unit->getType() == BWAPI::UnitTypes::Protoss_Observer) 00274 mObserver = unit; 00275 00276 mUnits.insert(unit); 00277 00278 mUnitBehaviours[unit] = Behaviour(unit); 00279 } 00280 00281 void DefaultSquadTask::returnUnit(Unit unit) 00282 { 00283 mUnits.erase(unit); 00284 00285 mUnitBehaviours[unit].onDeleted(); 00286 mUnitBehaviours.erase(unit); 00287 00288 if(unit == mObserver) 00289 mObserver = StaticUnits::nullunit; 00290 } 00291 00292 bool DefaultSquadTask::morph(Unit unit, BWAPI::UnitType previousType) 00293 { 00294 return false; 00295 } 00296 00297 UnitGroup DefaultSquadTask::getFinishedUnits() 00298 { 00299 return mUnits; 00300 } 00301 00302 void DefaultSquadTask::updateRequirements() 00303 { 00304 clearRequirements(); 00305 00306 if(!hasEnded()) 00307 { 00308 for each(Unit unit in UnitTracker::Instance().selectAllUnits()) 00309 { 00310 if(!unit->isCompleted()) 00311 continue; 00312 00313 if(mUnits.count(unit) != 0) 00314 continue; 00315 00316 const BWAPI::UnitType &type = unit->getType(); 00317 if(type.isBuilding()) 00318 continue; 00319 if(type.isAddon()) 00320 continue; 00321 if(type == BWAPI::Broodwar->self()->getRace().getSupplyProvider()) 00322 continue; 00323 if(type == BWAPI::UnitTypes::Zerg_Egg) 00324 continue; 00325 if(type == BWAPI::UnitTypes::Protoss_Interceptor) 00326 continue; 00327 if(type == BWAPI::UnitTypes::Zerg_Larva) 00328 continue; 00329 if(type == BWAPI::UnitTypes::Protoss_Scarab) 00330 continue; 00331 if(type == BWAPI::UnitTypes::Protoss_Observer) 00332 continue; 00333 00334 RequirementGroup req; 00335 00336 req.addUnitRequirement(unit, type.isWorker() ? 5 : 20, Requirement::maxTime); 00337 00338 addRequirement(req); 00339 } 00340 00341 if(!mObserver) 00342 { 00343 RequirementGroup req; 00344 00345 req.addUnitFilterRequirement(20, Requirement::maxTime, UnitFilter(BWAPI::UnitTypes::Protoss_Observer) && UnitFilter(UnitFilterFlags::IsComplete)); 00346 00347 addRequirement(req); 00348 } 00349 } 00350 }