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