BWAPI
|
00001 /* 00002 * BuildManager.cpp 00003 * 00004 * Used to produce new units, buildings and add-ons 00005 * Passes tasks down to the Construction or Production Managers 00006 */ 00007 #include "BuildManager.h" 00008 #include "ResourceManager.h" 00009 #include "Common.h" 00010 #include "Agent.h" 00011 #include "State.h" 00012 00013 #include <BWAPI.h> 00014 #include <BWTA.h> 00015 00016 #include <deque> 00017 #include <map> 00018 00019 using namespace BWAPI; 00020 00021 using std::deque; 00022 using std::map; 00023 00024 00025 void BuildManager::update() 00026 { 00027 // Update Agents 00028 Manager::update(); 00029 00030 // Done with the current request? 00031 if (buildStack.empty()) 00032 { 00033 // Try to start a new request 00034 if (!buildQueue.empty()) 00035 { 00036 buildStack.push(buildQueue.front()); 00037 buildQueue.pop(); 00038 } 00039 } 00040 00041 // Process requests if there are any 00042 if (buildStack.empty()) 00043 return; 00044 00045 BuildReq &req = buildStack.top(); 00046 UnitType type = req.type; 00047 00048 switch (req.state) 00049 { 00050 case NEW: 00051 { 00052 //Broodwar->sendText("Trying to build: %s", type.c_str()); 00053 00054 // Check reqs 00055 int mineralsNeeded = type.mineralPrice(); 00056 int gasNeeded = type.gasPrice(); 00057 int mineralsOwned = Broodwar->self()->minerals(); 00058 int gasOwned = Broodwar->self()->gas(); 00059 00060 // Required supply? 00061 int supplyOwned = Broodwar->self()->supplyTotal() - Broodwar->self()->supplyUsed(); 00062 if (supplyOwned < type.supplyRequired()) 00063 { 00064 break; 00065 } 00066 00067 // Required units? 00068 map<UnitType, int> requiredUnits = type.requiredUnits(); 00069 for (map<UnitType, int>::iterator i = requiredUnits.begin(); i != requiredUnits.end(); i++) 00070 { 00071 UnitType rt = (*i).first; 00072 int rc = (*i).second; 00073 if (Broodwar->self()->visibleUnitCount(rt) < rc) 00074 { 00075 build(rt, true); 00076 Broodwar->sendText("%s pushed: prereq to build %s", rt.c_str(), type.c_str()); 00077 break; 00078 } 00079 } 00080 00081 // Required builder? 00082 UnitType builderType = type.whatBuilds().first; 00083 if (Broodwar->self()->visibleUnitCount(builderType) < 1) 00084 { 00085 build(builderType, true); 00086 // TODO: I've had several crashes here... 00087 // they seem to stem from the calls to c_str(), they must be returning a bad pointer... 00088 // commenting it out has stopped the crashes here for me so far. 00089 // Broodwar->sendText("%s pushed: Need a %s to build %s", builderType.c_str(), type.c_str()); 00090 break; 00091 } 00092 00093 // Required resources? 00094 if (mineralsOwned < mineralsNeeded || 00095 gasOwned < gasNeeded) 00096 { 00097 break; 00098 } 00099 00100 // OK - requirements met, let's build it! 00101 // Find an idle builder 00102 for (AgentSetIter i = agents.begin(); i != agents.end(); i++) 00103 { 00104 if ((*i)->getUnit().getType().getID() == builderType.getID() 00105 && (*i)->getState() != BuildState 00106 && (*i)->getState() != TrainState) 00107 { 00108 // Found one, build it (this works for addons too) 00109 if (type.isBuilding()) 00110 (*i)->setState(BuildState); 00111 else 00112 (*i)->setState(TrainState); 00113 (*i)->setUnitTypeTarget(type); 00114 // Remember we issued the command 00115 req.builder = &(*i)->getUnit(); 00116 req.state = ISSUED; 00117 Broodwar->sendText("BM: Worker found, building %s", type.c_str()); 00118 break; 00119 } 00120 } 00121 // Wait if we didn't find a builder 00122 if (req.builder == NULL) 00123 { 00124 break; 00125 } 00126 } 00127 break; 00128 00129 case ISSUED: 00130 { 00131 /* We need to determine if the order has been started (i.e. resources spent) */ 00132 Unit* builder = req.builder; 00133 00134 if (builder->getType().isBuilding()) 00135 { 00136 if (builder->isTraining()) 00137 { 00138 req.state = STARTED; 00139 } 00140 } 00141 else if (builder->getType().isWorker()) 00142 { 00143 /* 00144 * We can't check if a builder is *really* building using ->isConstructing(), 00145 * but we can see if a structure is being built by our builder 00146 */ 00147 UnitSet ownedUnits = Broodwar->self()->getUnits(); 00148 for (UnitSetConstIter i = ownedUnits.begin(); i != ownedUnits.end(); i++) 00149 { 00150 if ((*i)->getBuildUnit() == builder && 00151 (*i)->isVisible()) 00152 { 00153 req.state = STARTED; 00154 } 00155 } 00156 } 00157 break; 00158 } 00159 00160 case STARTED: 00161 /* 00162 * TODO: Monitor the orders we have started, and verify them to completion. 00163 * In the case of a killed SCV doing a build, we may want to restart the 00164 * order. 00165 */ 00166 buildStack.pop(); 00167 break; 00168 00169 case COMPLETE: 00170 break; 00171 } 00172 00173 // Keep our workers busy when they aren't building 00174 AgentSet workers(getAgentsOfType(UnitTypes::Terran_SCV)); 00175 for(AgentSetIter worker = workers.begin(); worker != workers.end(); ++worker) 00176 { 00177 Agent& agent = **worker; 00178 if( agent.getState() == IdleState ) 00179 { 00180 ResourceManager::makeAgentGatherMinerals(agent); 00181 } 00182 } 00183 } 00184 00185 void BuildManager::build(UnitType type, bool immediate) 00186 { 00187 TilePosition defaultLocation = Broodwar->self()->getStartLocation(); 00188 build(type, defaultLocation, immediate); 00189 } 00190 00191 void BuildManager::build(UnitType type, TilePosition goalPosition, bool immediate) 00192 { 00193 BuildReq req; 00194 // Internal 00195 req.type = type; 00196 req.goalPosition = goalPosition; 00197 req.count = 1; 00198 // External 00199 req.state = NEW; 00200 req.builder = NULL; 00201 00202 // DEBUG // 00203 Broodwar->sendText("BM: Rcvd order for %s", type.c_str()); 00204 00205 if (immediate) 00206 buildStack.push(req); 00207 else 00208 buildQueue.push(req); 00209 } 00210 00211 // Note: this is ugly because in order to print its elements 00212 // we have to break down the queue and stack and rebuild them 00213 // in the right order when we're done 00214 void BuildManager::drawDebugText() 00215 { 00216 const int starty = 60; 00217 int x = 2; 00218 int y = starty; 00219 00220 Broodwar->drawTextScreen(x, y, "BuildMgr - queue (%d)", (int)buildQueue.size()); 00221 00222 deque<BuildReq> tempq; 00223 while(!buildQueue.empty()) 00224 { 00225 BuildReq req = buildQueue.front(); 00226 buildQueue.pop(); 00227 Broodwar->drawTextScreen(x, y += 10, "-%s", UnitTypeStrings[req.type.getID()]); 00228 tempq.push_back(req); 00229 } 00230 while(!tempq.empty()) 00231 { 00232 BuildReq req = tempq.front(); 00233 tempq.pop_front(); 00234 buildQueue.push(req); 00235 } 00236 00237 tempq.clear(); 00238 00239 x = 150; 00240 y = starty; 00241 00242 Broodwar->drawTextScreen(x, y, "BuildMgr - stack (%d)", (int)buildStack.size()); 00243 while(!buildStack.empty()) 00244 { 00245 BuildReq req = buildStack.top(); 00246 buildStack.pop(); 00247 Broodwar->drawTextScreen(x, y += 10, "-%s", UnitTypeStrings[req.type.getID()]); 00248 tempq.push_front(req); 00249 } 00250 while(!tempq.empty()) 00251 { 00252 BuildReq req = tempq.front(); 00253 tempq.pop_front(); 00254 buildStack.push(req); 00255 } 00256 } 00257 00258 void BuildManager::draw() 00259 { 00260 Broodwar->drawTextScreen(2, 40, "\x07 BM : (SCV=%d) (CC=%d)", 00261 numAgents(UnitTypes::Terran_SCV), 00262 numAgents(UnitTypes::Terran_Command_Center)); 00263 00264 drawDebugText(); 00265 00266 Manager::draw(); 00267 }