BWAPI
BasicAIModule/source/Managers/BuildManager.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines