1 #include "ATask.h"
2 
3 #include "CGroup.h"
4 #include "CEconomy.h"
5 #include "CUnit.h"
6 
7 int ATask::counter = 0;
8 
ATask(AIClasses * _ai)9 ATask::ATask(AIClasses *_ai):ARegistrar(++counter) {
10 	t = TASK_UNDEFINED;
11 	ai = _ai;
12 	active = false;
13 	suspended = false;
14 	isMoving = true;
15 	pos = ZEROVECTOR;
16 	initFrame = ai->cb->GetCurrentFrame();
17 	validateInterval = 5 * 30; // 5 sec by default
18 	nextValidateFrame = validateInterval;
19 	priority = NORMAL;
20 	queueID = 0;
21 }
22 
remove()23 void ATask::remove() {
24 	LOG_II("ATask::remove " << (*this))
25 
26 	// NOTE: removal order below is VERY important
27 
28 	// remove current task from CTaskHandler, so it will mark this task
29 	// to be killed on next update
30 	std::list<ARegistrar*>::iterator j = records.begin();
31 	while (j != records.end()) {
32 		ARegistrar *regobj = *j; ++j;
33 		regobj->remove(*this);
34 	}
35 
36 	// remove all assisting tasks...
37 	std::list<ATask*>::iterator i = assisters.begin();
38 	while (i != assisters.end()) {
39 		ATask *task = *i; ++i;
40 		task->remove();
41 	}
42 	assert(assisters.size() == 0);
43 
44 	// detach task from groups...
45 	std::list<CGroup*>::iterator itGroup = groups.begin();
46 	while(itGroup != groups.end()) {
47 		CGroup *g = *itGroup; ++itGroup;
48 		removeGroup(*g);
49 	}
50 
51 	active = false;
52 }
53 
54 // called on Group removing
remove(ARegistrar & group)55 void ATask::remove(ARegistrar &group) {
56 	CGroup *g = dynamic_cast<CGroup*>(&group);
57 
58 	assert(g != NULL);
59 
60 	removeGroup(*g);
61 
62 	if (groups.empty()) {
63 		LOG_II("ATask::remove " << (*g))
64 
65 		remove();
66 	}
67 }
68 
firstGroup() const69 CGroup* ATask::firstGroup() const {
70 	if (groups.empty())
71 		return NULL;
72 	return groups.front();
73 }
74 
addGroup(CGroup & g)75 void ATask::addGroup(CGroup &g) {
76 	// FIXME: remove this when task queue will be supported
77 	assert(!g.busy);
78 	/*
79 	if (g->busy) {
80 		ATask *task = ai->tasks->getTask(g);
81 		assert(task != NULL && task != this);
82 		task->suspended = true;
83 		// TODO: nextTask = task;
84 	}
85 	*/
86 	g.reg(*this);
87 	g.busy = true;
88 	g.micro(false);
89 	//g.abilities(true);
90 
91 	if ((g.cats&STATIC).any())
92 		isMoving = false;
93 
94 	groups.push_back(&g);
95 }
96 
removeGroup(CGroup & g)97 void ATask::removeGroup(CGroup &g) {
98 	g.unreg(*this);
99 
100 	if (!suspended) {
101 		g.busy = false;
102 		g.unwait();
103 		g.micro(false);
104 		//g.abilities(false);
105 		if (isMoving) g.stop();
106 	}
107 
108 	groups.remove(&g);
109 }
110 
enemyScan(int & target)111 bool ATask::enemyScan(int& target) {
112 	CGroup *group = firstGroup();
113 	bool scout = (group->cats&SCOUTER).any();
114 	bool aircraft = (group->cats&AIR).any();
115 	TargetsFilter tf;
116 
117 	if (scout) {
118 		tf.threatCeiling = 1.1f;
119 		tf.threatRadius = 300.0f;
120 	}
121 	else {
122 		if (aircraft) {
123 			if ((group->cats&ASSAULT).any()) {
124 				tf.exclude = AIR;
125 				tf.threatCeiling = group->strength;
126 			}
127 			else {
128 				tf.threatCeiling = 1.1f;
129 				if((group->cats&ANTIAIR).any()) {
130 					tf.exclude = LAND|SEA|SUB;
131 				}
132 			}
133 			// TODO: replace with maneuvering radius?
134 			tf.threatRadius = 300.0f;
135 		}
136 		else {
137 			tf.exclude = SCOUTER;
138 			tf.threatFactor = 0.001f;
139 			tf.threatCeiling = group->strength;
140 			tf.threatRadius = 0.0f;
141 		}
142 	}
143 
144 	// do not chase after aircraft with non-aircraft groups...
145 	if (!aircraft)
146 		tf.exclude |= AIR;
147 
148 	target = group->selectTarget(group->getScanRange(), tf);
149 
150 	if (target >= 0) {
151 		group->attack(target);
152 		group->micro(true);
153 		if (scout)
154 			LOG_II("ATask::enemyScan scout " << (*group) << " is microing enemy target Unit(" << target << ") (threat = " << tf.threatValue << ")")
155 		else
156 			LOG_II("ATask::enemyScan engage " << (*group) << " is microing enemy target Unit(" << target << ") (threat = " << tf.threatValue << ")")
157 		return true;
158 	}
159 
160 	return false;
161 }
162 
resourceScan()163 bool ATask::resourceScan() {
164 	bool isFeature = true;
165 	int bestFeature = -1;
166 	float bestDist = std::numeric_limits<float>::max();
167 	CGroup *group = firstGroup();
168 	// NOTE: do not use group->los because it is too small and does not
169 	// correspond to real map units
170 	float radius = group->buildRange;
171 	float3 gpos = group->pos();
172 
173 	assert(radius > EPS);
174 
175 	// reclaim features when we can store metal only...
176 	if (!ai->economy->mexceeding) {
177 		const int numFeatures = ai->cb->GetFeatures(&ai->unitIDs[0], MAX_FEATURES, gpos, 1.5f * radius);
178 		for (int i = 0; i < numFeatures; i++) {
179 			const int uid = ai->unitIDs[i];
180 			const FeatureDef *fd = ai->cb->GetFeatureDef(uid);
181 			if (fd->metal > 0.0f) {
182 				float3 fpos = ai->cb->GetFeaturePos(uid);
183 				float dist = gpos.distance2D(fpos);
184 				if (dist < bestDist) {
185 					bestFeature = uid;
186 					bestDist = dist;
187 				}
188 			}
189 		}
190 	}
191 
192 	// if there is no feature available then reclaim enemy unarmed building,
193 	// hehe :)
194 	if (bestFeature == -1) {
195 		std::map<int, bool> occupied;
196 		TargetsFilter tf;
197 		tf.include = STATIC;
198 		tf.exclude = ATTACKER;
199 		tf.threatCeiling = 1.1f;
200 		tf.threatRadius = radius;
201 
202 		bestFeature = group->selectTarget(radius, tf);
203 
204 		isFeature = false;
205 	}
206 
207 	if (bestFeature != -1) {
208 		group->reclaim(bestFeature, isFeature);
209 		group->micro(true);
210 		LOG_II("ATask::resourceScan group " << (*group) << " is reclaiming")
211 		return true;
212 	}
213 
214 	return false;
215 }
216 
repairScan()217 bool ATask::repairScan() {
218 	if (ai->economy->mstall || ai->economy->estall)
219 		return false;
220 
221 	int bestUnit = -1;
222 	float bestScore = 0.0f;
223 	CGroup *group = firstGroup();
224 	float radius = group->buildRange;
225 	float3 gpos = group->pos();
226 
227 	const int numUnits = ai->cb->GetFriendlyUnits(&ai->unitIDs[0], gpos, 2.0f * radius, MAX_FEATURES);
228 	for (int i = 0; i < numUnits; i++) {
229 		const int uid = ai->unitIDs[i];
230 
231 		if (ai->cb->UnitBeingBuilt(uid) || group->firstUnit()->key == uid)
232 			continue;
233 
234 		const float healthDamage = ai->cb->GetUnitMaxHealth(uid) - ai->cb->GetUnitHealth(uid);
235 		if (healthDamage > EPS) {
236 			// TODO: somehow limit number of repairing builders per unit
237 			const UnitDef *ud = ai->cb->GetUnitDef(uid);
238 			const unitCategory cats = UC(ud->id);
239 
240 			if ((cats&AIR).any())
241 				continue;
242 
243 			const float score = healthDamage + (CUnit::isDefense(ud) ? 10000.0f: 0.0f) + (CUnit::isStatic(ud) ? 5000.0f: 0.0f);
244 			if (score > bestScore) {
245 				bestUnit = uid;
246 				bestScore = score;
247 			}
248 		}
249 	}
250 
251 	if (bestUnit != -1) {
252 		group->repair(bestUnit);
253 		group->micro(true);
254 		LOG_II("ATask::repairScan group " << (*group) << " is repairing")
255 		return true;
256 	}
257 
258 	return false;
259 }
260 
lifeFrames() const261 int ATask::lifeFrames() const {
262 	return ai->cb->GetCurrentFrame() - initFrame;
263 }
264 
lifeTime() const265 float ATask::lifeTime() const {
266 	return (float)(ai->cb->GetCurrentFrame() - initFrame) / 30.0f;
267 }
268 
update()269 void ATask::update() {
270 	if (!active) return;
271 
272 	if (validateInterval > 0) {
273 		int lifetime = lifeFrames();
274 		if (lifetime >= nextValidateFrame) {
275 			if (!onValidate()) {
276 				remove();
277 				return;
278 			}
279 			else
280 				nextValidateFrame = lifetime + validateInterval;
281 		}
282 	}
283 
284 	if (suspended) return;
285 
286 	onUpdate();
287 }
288 
operator <<(std::ostream & out,const ATask & atask)289 std::ostream& operator<<(std::ostream &out, const ATask &atask) {
290 	atask.toStream(out);
291 
292 	if (atask.assisters.size() > 0) {
293 		out << " Assisters: amount(" << atask.assisters.size() << ") [";
294 		std::list<ATask*>::const_iterator i;
295 		for (i = atask.assisters.begin(); i != atask.assisters.end(); ++i) {
296 			CGroup *group = (*i)->firstGroup();
297 			if (group)
298 				out << (*group);
299 		}
300 		out << "]";
301 	}
302 
303 	return out;
304 }
305