BWAPI
|
00001 #include "DefenseSquad.h" 00002 00003 #include "UnitTracker.h" 00004 #include "BaseTracker.h" 00005 #include "BorderTracker.h" 00006 #include "BuildOrderManager.h" 00007 #include "PlayerTracker.h" 00008 00009 DefenseSquadTask::DefenseSquadTask(ArmyBehaviour behaviour) 00010 : BaseSquadTask(behaviour) 00011 , mNeededWorkers(0) 00012 , mDefenseGoal() 00013 { 00014 } 00015 00016 int DefenseSquadTask::getEndTime() const 00017 { 00018 return Requirement::maxTime; 00019 } 00020 00021 int DefenseSquadTask::getEndTime(Unit unit) const 00022 { 00023 return Requirement::maxTime; 00024 } 00025 00026 int DefenseSquadTask::getPriority(Unit unit) const 00027 { 00028 if(!unit->getType().isWorker()) 00029 { 00030 bool isNeeded = false; 00031 if(mNeedsAntiAir && unit->canAttackAir()) 00032 isNeeded = true; 00033 00034 if(mNeedsAntiGround && unit->canAttackGround()) 00035 isNeeded = true; 00036 00037 if(isNeeded) 00038 return 30; 00039 else 00040 return 1; 00041 } 00042 00043 int workersToReturn = int(mWorkerDefenders.size()) - mNeededWorkers; 00044 if(workersToReturn > 0) 00045 { 00046 int count = 1; 00047 for each(Unit worker in mWorkerDefenders) 00048 { 00049 if(worker == unit) 00050 { 00051 if(count <= workersToReturn) 00052 return 1; 00053 break; 00054 } 00055 ++count; 00056 } 00057 } 00058 00059 return 30; 00060 } 00061 00062 Position DefenseSquadTask::getStartLocation(Unit unit) const 00063 { 00064 return unit->getPosition(); 00065 } 00066 00067 Position DefenseSquadTask::getEndLocation(Unit unit) const 00068 { 00069 return unit->getPosition(); 00070 } 00071 00072 bool DefenseSquadTask::preUpdate() 00073 { 00074 updateRequirements(); 00075 00076 return hasEnded(); 00077 } 00078 00079 bool DefenseSquadTask::update() 00080 { 00081 if(mDefenseGoal.getActionType() != ActionType::None) 00082 { 00083 Goal enemiesGoal(ActionType::Attack, mDefenseGoal.getBase()->getEnemyThreats()); 00084 for(std::map<Unit, Behaviour>::iterator it = mUnitBehaviours.begin(); it != mUnitBehaviours.end(); ++it) 00085 it->second.update(enemiesGoal, mUnits); 00086 } 00087 00088 return hasEnded() && mUnits.empty(); 00089 } 00090 00091 bool DefenseSquadTask::waitingForUnit(Unit unit) const 00092 { 00093 return false; 00094 } 00095 00096 void DefenseSquadTask::giveUnit(Unit unit) 00097 { 00098 if(unit->getType() == BWAPI::UnitTypes::Protoss_Observer) 00099 mObserver = unit; 00100 else if(unit->getType().isWorker()) 00101 mWorkerDefenders.insert(unit); 00102 00103 mUnits.insert(unit); 00104 00105 mUnitBehaviours[unit] = Behaviour(unit); 00106 } 00107 00108 void DefenseSquadTask::returnUnit(Unit unit) 00109 { 00110 mUnits.erase(unit); 00111 00112 mUnitBehaviours[unit].onDeleted(); 00113 mUnitBehaviours.erase(unit); 00114 00115 mWorkerDefenders.erase(unit); 00116 00117 if(unit == mObserver) 00118 mObserver = StaticUnits::nullunit; 00119 } 00120 00121 bool DefenseSquadTask::morph(Unit unit, BWAPI::UnitType previousType) 00122 { 00123 return false; 00124 } 00125 00126 UnitGroup DefenseSquadTask::getFinishedUnits() 00127 { 00128 return mUnits; 00129 } 00130 00131 void DefenseSquadTask::updateRequirements() 00132 { 00133 clearRequirements(); 00134 mNeededWorkers = 0; 00135 mNeedsAntiAir = false; 00136 mNeedsAntiGround = false; 00137 00138 // Basic idea is to have a defense goal for each base that will take only the amount of units it needs to take out the threat 00139 // and also take workers if it cannot take out the threat with the number of units it has 00140 00141 // This should make it do important things such as kill the threat while the rest of the army in the default squad stay at the choke 00142 // stopping any other units from entering 00143 if(!hasEnded() && mDefenseGoal.getActionType() != ActionType::None) 00144 { 00145 //TODO: currently picks units based on it getting units with a score higher than 100, if its zerg it could get zerglings in which case it wont have enough 00146 // TODO: maybe do some modification based on current units health 00147 int AirThreatScore = 0; 00148 int GroundThreatScore = 0; 00149 int GroundThreatCount = 0; 00150 bool needsDetection = false; 00151 for each(Unit enemy in mDefenseGoal.getBase()->getEnemyThreats()) 00152 { 00153 if(!needsDetection && (enemy->getType().isCloakable() || enemy->getType().hasPermanentCloak() || enemy->isBurrowed() || enemy->getType() == BWAPI::UnitTypes::Zerg_Lurker)) 00154 needsDetection = true; 00155 00156 if(enemy->isLifted() || enemy->getType().isFlyer()) 00157 { 00158 if(enemy->canAttackGround()) 00159 AirThreatScore += enemy->getType().buildScore(); 00160 else if(enemy->getType().spaceProvided() > 0) 00161 { 00162 if(enemy->getPlayer()->getRace() != BWAPI::Races::Zerg) 00163 AirThreatScore += 400; 00164 else if(BWAPI::Broodwar->getFrameCount() > 24*60*6) //TODO: has the player researched drop? 00165 AirThreatScore += 250; 00166 else 00167 AirThreatScore += 50; 00168 } 00169 else 00170 AirThreatScore += 50; 00171 } 00172 else 00173 { 00174 ++GroundThreatCount; 00175 if(enemy->canAttackGround()) 00176 GroundThreatScore += enemy->getType().buildScore(); 00177 else 00178 GroundThreatScore += 50; 00179 } 00180 } 00181 00182 // Temp till defense squad is good enough to use army units and not just workers 00183 if(needsDetection) 00184 return; 00185 00186 if(GroundThreatScore > 0) 00187 mNeedsAntiGround = true; 00188 if(AirThreatScore > 0) 00189 mNeedsAntiAir = true; 00190 00191 int AntiAirScore = 0; 00192 int AntiGroundScore = 0; 00193 for each(Unit unit in mUnits) 00194 { 00195 if(unit->getType().isWorker()) 00196 continue; 00197 00198 if(unit->canAttackGround()) 00199 { 00200 --GroundThreatCount; 00201 AntiGroundScore += unit->getType().buildScore(); 00202 } 00203 if(unit->canAttackAir()) 00204 AntiAirScore += unit->getType().buildScore(); 00205 } 00206 00207 mNeededWorkers = std::max((GroundThreatScore - AntiGroundScore) / 50, 0); 00208 if(mNeededWorkers == 0 && (GroundThreatScore - AntiGroundScore) > 0) 00209 mNeededWorkers = 1; 00210 00211 if(mNeededWorkers < GroundThreatCount) 00212 mNeededWorkers = GroundThreatCount; 00213 00214 int canAttackGroundNeeded = mNeededWorkers / 2; 00215 00216 if(mNeededWorkers > 14) mNeededWorkers = 0; //If we cannot defend with 14 workers, don't try, probably not worth possible losses 00217 if(mNeededWorkers > 1) mNeededWorkers += 1; 00218 if(mNeededWorkers > 2) mNeededWorkers += 1; 00219 if(mNeededWorkers > 14) mNeededWorkers = 14; 00220 00221 int workersNeeded = std::max(mNeededWorkers - int(mWorkerDefenders.size()), 0); 00222 00223 canAttackGroundNeeded -= (int(mWorkerDefenders.size()) / 2); 00224 00225 // Get as many as we can for now 00226 // TODO: maybe check if its our only mining base or do something better 00227 for(int i = 0; i < workersNeeded; ++i) 00228 { 00229 RequirementGroup reqWorkers; 00230 reqWorkers.addUnitFilterRequirement(30, Requirement::maxTime, UnitFilter(UnitFilterFlags::type(UnitFilterFlags::IsWorker | UnitFilterFlags::IsComplete)), mDefenseGoal.getBase()->getCenterLocation()); 00231 addRequirement(reqWorkers); 00232 } 00233 00234 // Temp till defense squad is good enough to use army units and not just workers 00235 // in the below state can cause the bots army to get too seperated and cause the main army to get possibly destroyed engaging a group elsewhere 00236 return; 00237 00238 RequirementGroup reqMain; 00239 if(canAttackGroundNeeded > 0) 00240 reqMain.addUnitFilterRequirement(30, Requirement::maxTime, UnitFilter(UnitFilterFlags::type(UnitFilterFlags::IsArmyUnit | UnitFilterFlags::CanAttackGround | UnitFilterFlags::IsComplete)), canAttackGroundNeeded, mDefenseGoal.getBase()->getCenterLocation()); 00241 00242 int canAttackAirNeeded = std::max((AirThreatScore - AntiAirScore) / 100, 0); 00243 if(canAttackAirNeeded > 0) 00244 reqMain.addUnitFilterRequirement(30, Requirement::maxTime, UnitFilter(UnitFilterFlags::type(UnitFilterFlags::IsArmyUnit | UnitFilterFlags::CanAttackAir | UnitFilterFlags::IsComplete)), canAttackAirNeeded, mDefenseGoal.getBase()->getCenterLocation()); 00245 00246 if(!mObserver && needsDetection) 00247 reqMain.addUnitFilterRequirement(30, Requirement::maxTime, UnitFilter(BWAPI::UnitTypes::Protoss_Observer) && UnitFilter(UnitFilterFlags::IsComplete), mDefenseGoal.getBase()->getCenterLocation()); 00248 00249 addRequirement(reqMain); 00250 00251 Position goalpos = mDefenseGoal.getBase()->getCenterLocation(); 00252 const int x = goalpos.x(); 00253 const int y = goalpos.y(); 00254 00255 BWAPI::Broodwar->drawTextMap(x, y, "canAttackGroundNeeded : %d", canAttackGroundNeeded); 00256 BWAPI::Broodwar->drawTextMap(x, y+10, "canAttackAirNeeded : %d", canAttackAirNeeded); 00257 BWAPI::Broodwar->drawTextMap(x, y+20, "workersNeeded : %d", workersNeeded); 00258 BWAPI::Broodwar->drawTextMap(x, y+30, "workers Have : %d", int(mWorkerDefenders.size())); 00259 BWAPI::Broodwar->drawTextMap(x, y+40, "Units Have : %d", int(mUnits.size())); 00260 if(!mObserver && needsDetection) 00261 BWAPI::Broodwar->drawTextMap(x, y+50, "Needs Observer"); 00262 } 00263 }