1 #include "Build.h"
2
3 #include "../CUnit.h"
4 #include "../CGroup.h"
5 #include "../CUnitTable.h"
6 #include "../CPathfinder.h"
7 #include "../CEconomy.h"
8 #include "../CTaskHandler.h"
9
10
11 std::map<buildType, std::string> BuildTask::buildStr;
12
BuildTask(AIClasses * _ai,buildType build,UnitType * toBuild,CGroup & group,float3 & pos)13 BuildTask::BuildTask(AIClasses *_ai, buildType build, UnitType *toBuild, CGroup &group, float3 &pos): ATask(_ai) {
14 if (buildStr.empty()) {
15 buildStr[BUILD_MPROVIDER] = std::string("MPROVIDER");
16 buildStr[BUILD_EPROVIDER] = std::string("EPROVIDER");
17 buildStr[BUILD_AA_DEFENSE] = std::string("AA_DEFENSE");
18 buildStr[BUILD_AG_DEFENSE] = std::string("AG_DEFENSE");
19 buildStr[BUILD_UW_DEFENSE] = std::string("UW_DEFENSE");
20 buildStr[BUILD_FACTORY] = std::string("FACTORY");
21 buildStr[BUILD_MSTORAGE] = std::string("MSTORAGE");
22 buildStr[BUILD_ESTORAGE] = std::string("ESTORAGE");
23 buildStr[BUILD_MISC_DEFENSE] = std::string("MISC_DEFENSE");
24 buildStr[BUILD_IMP_DEFENSE] = std::string("IMPORTANT_DEFENSE");
25 }
26
27 this->t = TASK_BUILD;
28 this->pos = pos;
29 this->bt = build;
30 this->toBuild = toBuild;
31
32 float eta = ai->pathfinder->getETA(group, pos);
33 if (eta == std::numeric_limits<float>::max())
34 this->eta = 0;
35 else
36 this->eta = int((eta + 100.0f) * 1.2f);
37
38 this->building = false;
39
40 addGroup(group);
41 }
42
onValidate()43 bool BuildTask::onValidate() {
44 if (isMoving) {
45 // decline task if metal spot is occupied by firendly unit
46 if ((toBuild->cats&MEXTRACTOR).any()) {
47 int numUnits = ai->cb->GetFriendlyUnits(&ai->unitIDs[0], pos, 1.1f * ai->cb->GetExtractorRadius());
48 for (int i = 0; i < numUnits; i++) {
49 const int uid = ai->unitIDs[i];
50 const UnitDef *ud = ai->cb->GetUnitDef(uid);
51 if ((UC(ud->id)&MEXTRACTOR).any()) {
52 return false;
53 }
54 }
55 }
56 }
57 else {
58 CGroup *group = firstGroup();
59 if (ai->economy->hasFinishedBuilding(*group))
60 return false;
61 if (lifeFrames() > eta && !ai->economy->hasBegunBuilding(*group)) {
62 LOG_WW("BuildTask::update assuming buildpos blocked for group " << (*group))
63 return false;
64 }
65 }
66
67 return true;
68 }
69
onUpdate()70 void BuildTask::onUpdate() {
71 CGroup *group = firstGroup();
72
73 if (group->isMicroing()) {
74 if (group->isIdle()) {
75 CUnit* unit = group->firstUnit();
76 group->micro(false); // if idle, our micro is done
77 eta += unit->microingFrames;
78 unit->microingFrames = 0; // reset
79 }
80 else
81 return; // if microing, break
82 }
83
84 if (!building) {
85 if (isMoving) {
86 if (!resourceScan()) {
87 const float3 gpos = group->pos();
88 if (gpos.distance2D(pos) <= group->buildRange) {
89 isMoving = false;
90 ai->pathfinder->remove(*group);
91 }
92 else
93 repairScan();
94 }
95 }
96
97 if (!isMoving && !group->isMicroing()) {
98 if (group->build(pos, toBuild)) {
99 building = true;
100 group->micro(true);
101 }
102 }
103 }
104
105 if (group->isIdle()) {
106 // make builder react faster when job is finished
107 if (!onValidate())
108 remove();
109 }
110 }
111
assistable(CGroup & assister,float & travelTime) const112 bool BuildTask::assistable(CGroup &assister, float &travelTime) const {
113 if (!toBuild->def->canBeAssisted)
114 return false;
115 if (isMoving)
116 return false;
117 if (assisters.size() > 1 && (bt == BUILD_AG_DEFENSE || bt == BUILD_AA_DEFENSE || bt == BUILD_MISC_DEFENSE))
118 return false;
119
120 CGroup *group = firstGroup();
121
122 float buildSpeed = group->buildSpeed;
123 std::list<ATask*>::const_iterator it;
124 for (it = assisters.begin(); it != assisters.end(); ++it)
125 buildSpeed += (*it)->firstGroup()->buildSpeed;
126
127 // NOTE: we should calculate distance to group position instead of target
128 // position because build place can be reachable within build range only
129 float3 gpos = group->pos();
130 float buildTime = (toBuild->def->buildTime / buildSpeed) * 32.0f;
131
132 /* travelTime + 5 seconds to make it worth the trip */
133 travelTime = ai->pathfinder->getETA(assister, gpos) + 150.0f;
134
135 return (buildTime > travelTime);
136 }
137
onUnitDestroyed(int uid,int attacker)138 void BuildTask::onUnitDestroyed(int uid, int attacker) {
139 if (ai->cb->UnitBeingBuilt(uid)) {
140 CUnit* unit = ai->unittable->getUnit(uid);
141 if (unit && unit->builtBy == firstGroup()->firstUnit()->key)
142 remove();
143 }
144 }
145
toStream(std::ostream & out) const146 void BuildTask::toStream(std::ostream& out) const {
147 out << "BuildTask(" << key << ") " << buildStr[bt];
148 out << "(" << toBuild->def->humanName << ") ETA(" << eta << ")";
149 out << " lifetime(" << lifeFrames() << ") ";
150 CGroup *group = firstGroup();
151 if (group)
152 out << (*group);
153 }
154