1 #include <sstream>
2
3 #include "IncCREG.h"
4 #include "IncEngine.h"
5 #include "IncExternAI.h"
6 #include "IncGlobalAI.h"
7
8 CR_BIND(CUnitHandler, (NULL))
9 CR_REG_METADATA(CUnitHandler, (
10 CR_MEMBER(IdleUnits),
11 CR_MEMBER(BuildTasks),
12 CR_MEMBER(TaskPlans),
13 CR_MEMBER(AllUnitsByCat),
14 CR_MEMBER(AllUnitsByType),
15
16 CR_MEMBER(Factories),
17 CR_MEMBER(NukeSilos),
18 CR_MEMBER(MetalExtractors),
19
20 CR_MEMBER(Limbo),
21 CR_MEMBER(BuilderTrackers),
22
23 CR_MEMBER(metalMaker),
24
25 CR_MEMBER(ai),
26 CR_MEMBER(taskPlanCounter),
27 CR_RESERVED(16)
28 ))
29
30
CUnitHandler(AIClasses * ai)31 CUnitHandler::CUnitHandler(AIClasses* ai) {
32 this->ai = ai;
33
34 taskPlanCounter = 1;
35 lastCapturedUnitFrame = -1;
36 lastCapturedUnitID = -1;
37
38 IdleUnits.resize(CAT_LAST);
39 BuildTasks.resize(CAT_LAST);
40 TaskPlans.resize(CAT_LAST);
41 AllUnitsByCat.resize(CAT_LAST);
42
43 if (ai) {
44 AllUnitsByType.resize(ai->cb->GetNumUnitDefs() + 1);
45 metalMaker = new CMetalMaker(ai);
46 }
47 }
48
~CUnitHandler()49 CUnitHandler::~CUnitHandler() {
50 for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
51 delete *i;
52 }
53 }
54
IdleUnitUpdate(int frame)55 void CUnitHandler::IdleUnitUpdate(int frame) {
56 std::list<integer2> limboremoveunits;
57
58 for (std::list<integer2>::iterator i = Limbo.begin(); i != Limbo.end(); i++) {
59 if (i->y > 0) {
60 i->y--;
61 } else {
62 if (ai->cb->GetUnitDef(i->x) == NULL) {
63 // ignore dead unit
64 } else {
65 IdleUnits[ai->ut->GetCategory(i->x)].push_back(i->x);
66 }
67
68 limboremoveunits.push_back(*i);
69 }
70 }
71
72 if (limboremoveunits.size()) {
73 for (std::list<integer2>::iterator i = limboremoveunits.begin(); i != limboremoveunits.end(); i++) {
74 Limbo.remove(*i);
75 }
76 }
77
78 // make sure that all the builders are in action (hack?)
79 if (frame % 15 == 0) {
80 for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
81 BuilderTracker* bTracker = *i;
82
83 if (bTracker->idleStartFrame != -2) {
84 // the brand new builders must be filtered still
85 const bool ans = VerifyOrder(bTracker);
86 const int builderID = bTracker->builderID;
87 const CCommandQueue* myCommands = ai->cb->GetCurrentUnitCommands(builderID);
88
89 // two sec delay is ok
90 if ((bTracker->commandOrderPushFrame + LAG_ACCEPTANCE) < frame) {
91 if (!ans) {
92 //float3 pos = ai->cb->GetUnitPos(builderID);
93
94 std::stringstream msg;
95 msg << "[CUnitHandler::IdleUnitUpdate()][frame=" << frame << "]\n";
96 msg << "\tfailed to verify order for builder " << builderID;
97 msg << " with " << (myCommands->size()) << " remaining commands\n";
98 ai->GetLogger()->Log(msg.str());
99
100 ClearOrder(*i, false);
101
102 // due to the Legacy AI Wrapper inner workings,
103 // the command-queue we fetched above is now invalid,
104 // because it got changed in ClearOrder()
105 myCommands = ai->cb->GetCurrentUnitCommands(builderID);
106
107 if (!myCommands->empty()) {
108 DecodeOrder(bTracker, true);
109 } else {
110 IdleUnitAdd(builderID, frame);
111 }
112 }
113 }
114 }
115 }
116 }
117 }
118
UnitMoveFailed(int unitID)119 void CUnitHandler::UnitMoveFailed(int unitID) {
120 }
121
122 // called when unit nanoframe first created
123 // (CEconomyTracker deals with UnitFinished())
UnitCreated(int unitID)124 void CUnitHandler::UnitCreated(int unitID) {
125 UnitCategory ucat = ai->ut->GetCategory(unitID);
126 const UnitDef* udef = ai->cb->GetUnitDef(unitID);
127
128 if (ucat != CAT_LAST) {
129 assert(ai->GetUnit(unitID)->isDead);
130 ai->GetUnit(unitID)->isDead = false;
131
132 AllUnitsByCat[ucat].push_back(unitID);
133 AllUnitsByType[udef->id].push_back(unitID);
134
135 if (ucat == CAT_FACTORY) {
136 FactoryAdd(unitID);
137 }
138
139 BuildTaskCreate(unitID);
140
141 if (ucat == CAT_BUILDER) {
142 // add the new builder
143 BuilderTracker* builderTracker = new BuilderTracker();
144 builderTracker->builderID = unitID;
145 builderTracker->buildTaskId = 0;
146 builderTracker->taskPlanId = 0;
147 builderTracker->factoryId = 0;
148 builderTracker->stuckCount = 0;
149 // under construction
150 builderTracker->commandOrderPushFrame = -2;
151 builderTracker->categoryMaker = CAT_LAST;
152 // wait for the first idle call, as this unit might be under construction
153 builderTracker->idleStartFrame = -2;
154 BuilderTrackers.push_back(builderTracker);
155 }
156
157 if (ucat == CAT_MMAKER) {
158 MMakerAdd(unitID);
159 }
160 if (ucat == CAT_MEX) {
161 MetalExtractorAdd(unitID);
162 }
163
164 if (ucat == CAT_NUKE) {
165 NukeSiloAdd(unitID);
166 }
167 }
168
169 if (udef->isCommander && udef->canDGun) {
170 ai->dgunConHandler->AddController(unitID);
171 } else {
172 ai->GetUnit(unitID)->SetFireState(2);
173 }
174 }
175
UnitDestroyed(int unitID)176 void CUnitHandler::UnitDestroyed(int unitID) {
177 UnitCategory category = ai->ut->GetCategory(unitID);
178 const UnitDef* unitDef = ai->cb->GetUnitDef(unitID);
179
180 if (category != CAT_LAST) {
181 assert(!ai->GetUnit(unitID)->isDead);
182 ai->GetUnit(unitID)->isDead = true;
183
184 AllUnitsByType[unitDef->id].remove(unitID);
185 AllUnitsByCat[category].remove(unitID);
186 IdleUnitRemove(unitID);
187 BuildTaskRemove(unitID);
188
189 if (category == CAT_DEFENCE) {
190 ai->dm->RemoveDefense(ai->cb->GetUnitPos(unitID), unitDef);
191 }
192 if (category == CAT_MMAKER) {
193 MMakerRemove(unitID);
194 }
195 if (category == CAT_FACTORY) {
196 FactoryRemove(unitID);
197 }
198
199 if (category == CAT_BUILDER) {
200 // remove the builder
201 for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
202 if ((*i)->builderID == unitID) {
203 if ((*i)->buildTaskId)
204 BuildTaskRemove(*i);
205 if ((*i)->taskPlanId)
206 TaskPlanRemove(*i);
207 if ((*i)->factoryId)
208 FactoryBuilderRemove(*i);
209
210 BuilderTracker* builderTracker = *i;
211 BuilderTrackers.erase(i);
212 delete builderTracker;
213 break;
214 }
215 }
216 }
217
218 if (category == CAT_MEX) {
219 MetalExtractorRemove(unitID);
220 }
221 if (category == CAT_NUKE) {
222 NukeSiloRemove(unitID);
223 }
224 }
225 }
226
IdleUnitAdd(int unit,int frame)227 void CUnitHandler::IdleUnitAdd(int unit, int frame) {
228 UnitCategory category = ai->ut->GetCategory(unit);
229
230 if (category != CAT_LAST) {
231 const CCommandQueue* myCommands = ai->cb->GetCurrentUnitCommands(unit);
232
233 if (myCommands->empty()) {
234 if (category == CAT_BUILDER) {
235 BuilderTracker* builderTracker = GetBuilderTracker(unit);
236 // add clear here
237 ClearOrder(builderTracker, true);
238
239 if (builderTracker->idleStartFrame == -2) {
240 // it was in the idle list already?
241 IdleUnitRemove(builderTracker->builderID);
242 }
243
244 builderTracker->idleStartFrame = -2;
245
246 if (builderTracker->commandOrderPushFrame == -2) {
247 // make sure that if the unit was just built
248 // it will have some time to leave the factory
249 builderTracker->commandOrderPushFrame = frame + 30 * 3;
250 }
251 }
252
253 integer2 myunit(unit, LIMBOTIME);
254 Limbo.remove(myunit);
255 Limbo.push_back(myunit);
256 } else {
257 // the unit has orders still, so should not be idle
258 if (category == CAT_BUILDER) {
259 if (false) {
260 // KLOOTNOTE: somehow we are reaching this branch
261 // on initialization when USE_CREG is not defined,
262 // mycommands->size() returns garbage?
263 //
264 // BuilderTracker* builderTracker = GetBuilderTracker(unit);
265 // DecodeOrder(builderTracker, true);
266 }
267 }
268 }
269 }
270 }
271
VerifyOrder(BuilderTracker * builderTracker)272 bool CUnitHandler::VerifyOrder(BuilderTracker* builderTracker) {
273 // if it's without orders then try to find the lost command (TODO)
274 const CCommandQueue* mycommands = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
275 bool commandFound = false;
276 bool hit = false;
277
278 if (!mycommands->empty()) {
279 // it has orders
280 const Command* c = &mycommands->front();
281
282 if (mycommands->size() == 2) {
283 // it might have a reclaim order, or terrain change order
284 // take command nr. 2
285 c = &mycommands->back();
286 }
287
288 if (builderTracker->buildTaskId != 0) {
289 hit = true;
290 // test that this builder is on repair on this unit
291 BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
292
293 commandFound =
294 ((c->id == CMD_REPAIR ) &&
295 (c->params[0] == builderTracker->buildTaskId)) ||
296
297 ((c->id == -buildTask->def->id) &&
298 (c->params[0] == buildTask->pos.x ) &&
299 (c->params[2] == buildTask->pos.z ));
300
301 if (!commandFound) {
302 return false;
303 }
304 }
305
306 if (builderTracker->taskPlanId != 0) {
307 assert(!hit);
308 hit = true;
309 TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);
310
311 if ((c->id == -taskPlan->def->id)
312 && (c->params[0] == taskPlan->pos.x)
313 && (c->params[2] == taskPlan->pos.z))
314 commandFound = true;
315 else
316 return false;
317 }
318
319 if (builderTracker->factoryId != 0) {
320 assert(!hit);
321 hit = true;
322 if (c->id == CMD_GUARD && c->params[0] == builderTracker->factoryId)
323 commandFound = true;
324 else
325 return false;
326 }
327
328 if (!commandFound) {
329 hit = true;
330 commandFound = (c->id == CMD_RECLAIM || c->id == CMD_MOVE || c->id == CMD_REPAIR);
331 }
332
333 if (hit && commandFound) {
334 // it's on the right job
335 return true;
336 }
337 }
338
339 else {
340 if (builderTracker->idleStartFrame == -2) {
341 return true;
342 }
343 }
344
345 return false;
346 }
347
348 // use this only if the unit does not have any orders at the moment
ClearOrder(BuilderTracker * builderTracker,bool reportError)349 void CUnitHandler::ClearOrder(BuilderTracker* builderTracker, bool reportError) {
350 bool hit = false;
351
352 const int frame = ai->cb->GetCurrentFrame();
353 const int builderID = builderTracker->builderID;
354 const int buildTaskID = builderTracker->buildTaskId;
355 const int factoryID = builderTracker->factoryId;
356 const CCommandQueue* q = ai->cb->GetCurrentUnitCommands(builderID);
357
358 assert(q->empty() || !reportError);
359
360 if (buildTaskID != 0) {
361 hit = true;
362 BuildTask* buildTask = GetBuildTask(buildTaskID);
363
364 std::stringstream msg;
365 msg << "[CUnitHandler::ClearOrder()][frame=" << frame << "]\n";
366 msg << "\tbuilder " << builderID << " is reported idle but";
367 msg << " still has a build-task with ID " << (buildTaskID) << "\n";
368 ai->GetLogger()->Log(msg.str());
369
370 if (buildTask->builderTrackers.size() > 1) {
371 BuildTaskRemove(builderTracker);
372 } else {
373 // only builder of this thing, and now idle
374 BuildTaskRemove(builderTracker);
375 }
376 }
377
378 if (builderTracker->taskPlanId != 0) {
379 assert(!hit);
380 hit = true;
381
382 const TaskPlan* taskPlan = GetTaskPlan(builderTracker->taskPlanId);
383 const std::string& taskName = taskPlan->def->humanName;
384
385 std::stringstream msg;
386 msg << "[CUnitHandler::ClearOrder()][frame=" << frame << "]\n";
387 msg << "\tbuilder " << builderID << " is reported idle but";
388 msg << " still has a task-plan named \"" << (taskName) << "\"\n";
389 ai->GetLogger()->Log(msg.str());
390
391 // mask this build-spot as bad
392 ai->dm->MaskBadBuildSpot(taskPlan->pos);
393
394 // TODO: remove all builders from this plan
395 if (reportError) {
396 std::list<BuilderTracker*> builderTrackers = taskPlan->builderTrackers;
397 std::list<BuilderTracker*>::iterator i;
398
399 for (i = builderTrackers.begin(); i != builderTrackers.end(); i++) {
400 TaskPlanRemove(*i);
401 ai->GetUnit((*i)->builderID)->Stop();
402 }
403 } else {
404 TaskPlanRemove(builderTracker);
405 }
406 }
407
408 if (factoryID != 0) {
409 assert(!hit);
410 hit = true;
411
412 std::stringstream msg;
413 msg << "[CUnitHandler::ClearOrder()][frame=" << frame << "]\n";
414 msg << "\tbuilder " << builderID << " is reported idle but";
415 msg << " still has a factory ID of " << factoryID << "\n";
416 ai->GetLogger()->Log(msg.str());
417
418 // remove the builder from its job
419 FactoryBuilderRemove(builderTracker);
420 }
421
422 assert(builderTracker->buildTaskId == 0);
423 assert(builderTracker->taskPlanId == 0);
424 assert(builderTracker->factoryId == 0);
425 }
426
DecodeOrder(BuilderTracker * builderTracker,bool reportError)427 void CUnitHandler::DecodeOrder(BuilderTracker* builderTracker, bool reportError) {
428 const int frame = ai->cb->GetCurrentFrame();
429 const int builderID = builderTracker->builderID;
430 const CCommandQueue* builderQ = ai->cb->GetCurrentUnitCommands(builderID);
431
432 if (builderQ->size() > 0) {
433 // builder has orders
434 const Command* c = &builderQ->front();
435 int n = c->params.size();
436 int cID = c->id;
437
438 if (builderQ->size() == 2 && cID == CMD_MOVE) {
439 // it might have a move order before the real order,
440 // take command nr. 2 if nr. 1 is a move order
441 c = &builderQ->back();
442 n = c->params.size();
443 cID = c->id;
444 }
445
446 if (reportError) {
447 std::stringstream msg;
448 msg << "[CUnitHandler::DecodeOrder()][frame=" << frame << "]\n";
449 msg << "\tbuilder " << builderID << " claimed idle, but has";
450 msg << " command " << cID << " with " << n << " parameters";
451 msg << " (params[0]: " << ((n > 0)? c->params[0]: -1) << ")\n";
452 ai->GetLogger()->Log(msg.str());
453 }
454
455 if (cID < 0) {
456 assert(n >= 3);
457
458 // it's building a unit
459 float3 newUnitPos;
460 newUnitPos.x = c->params[0];
461 newUnitPos.y = c->params[1];
462 newUnitPos.z = c->params[2];
463
464 const UnitDef* newUnitDef = ai->ut->unitTypes[-cID].def;
465 // make sure that no BuildTasks exists there
466 BuildTask* buildTask = BuildTaskExist(newUnitPos, newUnitDef);
467
468 if (buildTask) {
469 BuildTaskAddBuilder(buildTask, builderTracker);
470 } else {
471 // make a new TaskPlan (or join an existing one)
472 TaskPlanCreate(builderID, newUnitPos, newUnitDef);
473 }
474 }
475
476 if (cID == CMD_REPAIR) {
477 assert(n >= 1);
478
479 // it's repairing, find the unit being repaired
480 int guardingID = int(c->params[0]);
481 bool found = false;
482
483 UnitCategory cat = ai->ut->GetCategory(guardingID);
484 std::list<BuildTask>::iterator i;
485
486 if (cat == CAT_LAST) {
487 return;
488 }
489
490 for (i = BuildTasks[cat].begin(); i != BuildTasks[cat].end(); i++) {
491 if (i->id == guardingID) {
492 // whatever the old order was, update it now
493 bool hit = false;
494 if (builderTracker->buildTaskId != 0) {
495 hit = true;
496 // why is this builder idle?
497 BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
498
499 if (buildTask->builderTrackers.size() > 1) {
500 BuildTaskRemove(builderTracker);
501 } else {
502 // only builder of this thing, and now idle?
503 BuildTaskRemove(builderTracker);
504 }
505 }
506 if (builderTracker->taskPlanId != 0) {
507 assert(!hit);
508 hit = true;
509 TaskPlanRemove(builderTracker);
510 }
511 if (builderTracker->factoryId != 0) {
512 assert(!hit);
513 hit = true;
514 FactoryBuilderRemove(builderTracker);
515 }
516
517 BuildTask* bt = &*i;
518 BuildTaskAddBuilder(bt, builderTracker);
519 found = true;
520 }
521 }
522 if (!found) {
523 // not found, just make a custom order
524 builderTracker->idleStartFrame = -1;
525 }
526 }
527 } else {
528 // error: this function needs a builder with orders
529 // should not be possible because IdleUnitUpdate()
530 // calls us only if a unit's command-queue is NOT
531 // empty?
532 // assert(false);
533 std::stringstream msg;
534 msg << "[CUnitHandler::DecodeOrder()][frame=" << frame << "]\n";
535 msg << "\tbuilder " << builderID << " should not have an empty queue!\n";
536 ai->GetLogger()->Log(msg.str());
537 }
538 }
539
IdleUnitRemove(int unit)540 void CUnitHandler::IdleUnitRemove(int unit) {
541 UnitCategory category = ai->ut->GetCategory(unit);
542
543 if (category != CAT_LAST) {
544 IdleUnits[category].remove(unit);
545
546 if (category == CAT_BUILDER) {
547 BuilderTracker* builderTracker = GetBuilderTracker(unit);
548 builderTracker->idleStartFrame = -1;
549
550 if (builderTracker->commandOrderPushFrame == -2) {
551 // bad
552 }
553
554 // update the order start frame
555 builderTracker->commandOrderPushFrame = ai->cb->GetCurrentFrame();
556 // assert(builderTracker->buildTaskId == 0);
557 // assert(builderTracker->taskPlanId == 0);
558 // assert(builderTracker->factoryId == 0);
559 }
560
561 std::list<integer2>::iterator tempunit;
562 bool found = false;
563
564 for (std::list<integer2>::iterator i = Limbo.begin(); i != Limbo.end(); i++) {
565 if (i->x == unit) {
566 tempunit = i;
567 found = true;
568 }
569 }
570
571 if (found) {
572 Limbo.erase(tempunit);
573 }
574 }
575 }
576
GetIU(UnitCategory category)577 int CUnitHandler::GetIU(UnitCategory category) {
578 assert(IdleUnits[category].size() > 0);
579 int unitID = IdleUnits[category].front();
580
581 // move the returned unitID to the back
582 // of the list, so CBuildUp::FactoryCycle()
583 // doesn't keep examining the same factory
584 // if a build order fails and we have more
585 // than one idle factory
586 IdleUnits[category].pop_front();
587 IdleUnits[category].push_back(unitID);
588
589 return unitID;
590 }
591
NumIdleUnits(UnitCategory category)592 int CUnitHandler::NumIdleUnits(UnitCategory category) {
593 assert(category < CAT_LAST);
594 IdleUnits[category].sort();
595 IdleUnits[category].unique();
596 return IdleUnits[category].size();
597 }
598
MMakerAdd(int unit)599 void CUnitHandler::MMakerAdd(int unit) {
600 metalMaker->Add(unit);
601 }
602
MMakerRemove(int unit)603 void CUnitHandler::MMakerRemove(int unit) {
604 metalMaker->Remove(unit);
605 }
606
MMakerUpdate(int frame)607 void CUnitHandler::MMakerUpdate(int frame) {
608 metalMaker->Update(frame);
609 }
610
BuildTaskCreate(int id)611 void CUnitHandler::BuildTaskCreate(int id) {
612 const UnitDef* newUnitDef = ai->cb->GetUnitDef(id);
613 const UnitCategory category = ai->ut->GetCategory(id);
614 const float3 pos = ai->cb->GetUnitPos(id);
615
616 if ((!newUnitDef->movedata || category == CAT_DEFENCE) && !newUnitDef->canfly && category != CAT_LAST) {
617 // this needs to change, so that it can make more stuff
618 if (category >= CAT_LAST) {
619 return;
620 }
621
622 BuildTask bt;
623 bt.id = -1;
624
625 std::list<TaskPlan>::iterator i;
626
627 for (i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
628 if (pos.distance2D(i->pos) < 1.0f && newUnitDef == i->def) {
629 bt.category = category;
630 bt.id = id;
631 bt.pos = i->pos;
632 bt.def = newUnitDef;
633
634 std::list<BuilderTracker*> moveList;
635
636 for (std::list<BuilderTracker*>::iterator builder = i->builderTrackers.begin(); builder != i->builderTrackers.end(); builder++) {
637 moveList.push_back(*builder);
638 }
639
640 for (std::list<BuilderTracker*>::iterator builder = moveList.begin(); builder != moveList.end(); builder++) {
641 TaskPlanRemove(*builder);
642 BuildTaskAddBuilder(&bt, *builder);
643 }
644
645 // there can not be more than one found TaskPlan
646 break;
647 }
648 }
649
650 if (bt.id == -1) {
651 // buildtask creation error (can happen if builder manages
652 // to restart a dead building, or a human has taken control),
653 // make one anyway
654 std::stringstream msg;
655 msg << "[CUnitHandler::BuildTaskCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n";
656 msg << "\tBuildTask Creation Error for task with ID " << id << "\n";
657 ai->GetLogger()->Log(msg.str());
658
659 if (category == CAT_DEFENCE) {
660 ai->dm->AddDefense(pos, newUnitDef);
661 }
662
663 bt.category = category;
664 bt.id = id;
665 bt.pos = pos;
666 bt.def = newUnitDef;
667
668 // if we have any friendly builders
669 for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
670 BuilderTracker* builderTracker = *i;
671
672 // check what builder is doing
673 const CCommandQueue* cq = ai->cb->GetCurrentUnitCommands(builderTracker->builderID);
674
675 if (!cq->empty()) {
676 Command c = cq->front();
677
678 const bool b0 = (c.id == -newUnitDef->id && c.params[0] == pos.x && c.params[2] == pos.z); // at this pos
679 const bool b1 = (c.id == CMD_REPAIR && c.params[0] == id); // at this unit (id)
680 const bool b2 = (c.id == CMD_GUARD && c.params[0] == id); // at this unit (id)
681 const bool b3 = b0 || b1 || b2;
682
683 if (b3) {
684 if (builderTracker->buildTaskId != 0) {
685 BuildTask* buildTask = GetBuildTask(builderTracker->buildTaskId);
686
687 if (buildTask->builderTrackers.size() > 1) {
688 BuildTaskRemove(builderTracker);
689 } else {
690 // only builder of this thing, and now idle
691 BuildTaskRemove(builderTracker);
692 }
693 }
694
695 if (builderTracker->taskPlanId != 0) {
696 GetTaskPlan(builderTracker->taskPlanId);
697 TaskPlanRemove(builderTracker);
698 }
699 if (builderTracker->factoryId != 0) {
700 FactoryBuilderRemove(builderTracker);
701 }
702
703 // this builder is now free
704 if (builderTracker->idleStartFrame == -2) {
705 IdleUnitRemove(builderTracker->builderID);
706 }
707
708 // add it to this task
709 BuildTaskAddBuilder(&bt, builderTracker);
710
711 msg.str("");
712 msg << "\tadded builder " << builderTracker->builderID << " to";
713 msg << " build-task with ID " << builderTracker->buildTaskId << "\n";
714 ai->GetLogger()->Log(msg.str());
715 }
716 }
717 }
718
719 // add the task anyway
720 BuildTasks[category].push_back(bt);
721 }
722 else {
723 if (category == CAT_DEFENCE)
724 ai->dm->AddDefense(pos,newUnitDef);
725
726 BuildTasks[category].push_back(bt);
727 }
728 }
729 }
730
BuildTaskRemove(int id)731 void CUnitHandler::BuildTaskRemove(int id) {
732 UnitCategory category = ai->ut->GetCategory(id);
733
734 if (category < CAT_LAST) {
735 std::list<BuildTask>::iterator killtask;
736 bool found = false;
737
738 for (std::list<BuildTask>::iterator i = BuildTasks[category].begin(); i != BuildTasks[category].end(); i++) {
739 if (i->id == id) {
740 killtask = i;
741 assert(!found);
742 found = true;
743 }
744 }
745 if (found) {
746 // remove the builders from this BuildTask
747 std::list<BuilderTracker*> removeList;
748 for (std::list<BuilderTracker*>::iterator builder = killtask->builderTrackers.begin(); builder != killtask->builderTrackers.end(); builder++) {
749 removeList.push_back(*builder);
750 }
751 for (std::list<BuilderTracker*>::iterator builder = removeList.begin(); builder != removeList.end(); builder++) {
752 BuildTaskRemove(*builder);
753 }
754
755 BuildTasks[category].erase(killtask);
756 }
757 }
758 }
759
GetBuilderTracker(int builderID)760 BuilderTracker* CUnitHandler::GetBuilderTracker(int builderID) {
761 for (std::list<BuilderTracker*>::iterator i = BuilderTrackers.begin(); i != BuilderTrackers.end(); i++) {
762 if ((*i)->builderID == builderID) {
763 return (*i);
764 }
765 }
766
767 return NULL;
768 }
769
BuildTaskRemove(BuilderTracker * builderTracker)770 void CUnitHandler::BuildTaskRemove(BuilderTracker* builderTracker) {
771 if (builderTracker->buildTaskId == 0) {
772 assert(false);
773 return;
774 }
775
776 UnitCategory category = ai->ut->GetCategory(builderTracker->buildTaskId);
777
778 // TODO: Hack fix
779 if (category == CAT_LAST) {
780 return;
781 }
782
783 assert(category >= 0);
784 assert(category < CAT_LAST);
785 assert(builderTracker->buildTaskId != 0);
786 assert(builderTracker->taskPlanId == 0);
787 assert(builderTracker->factoryId == 0);
788
789 bool found = false;
790 bool found2 = false;
791
792 for (std::list<BuildTask>::iterator i = BuildTasks[category].begin(); i != BuildTasks[category].end(); i++) {
793 if (i->id == builderTracker->buildTaskId){
794 // killtask = i;
795 assert(!found);
796 for (std::list<int>::iterator builder = i->builders.begin(); builder != i->builders.end(); builder++) {
797 if (builderTracker->builderID == *builder) {
798 assert(!found2);
799 i->builders.erase(builder);
800 builderTracker->buildTaskId = 0;
801 found2 = true;
802 break;
803 }
804 }
805 for (std::list<BuilderTracker*>::iterator builder = i->builderTrackers.begin(); builder != i->builderTrackers.end(); builder++) {
806 if (builderTracker == *builder) {
807 assert(!found);
808 i->builderTrackers.erase(builder);
809 builderTracker->buildTaskId = 0;
810 // give it time to change command
811 builderTracker->commandOrderPushFrame = ai->cb->GetCurrentFrame();
812 found = true;
813 break;
814 }
815 }
816
817 }
818 }
819
820 assert(found);
821 }
822
BuildTaskAddBuilder(BuildTask * buildTask,BuilderTracker * builderTracker)823 void CUnitHandler::BuildTaskAddBuilder(BuildTask* buildTask, BuilderTracker* builderTracker) {
824 buildTask->builders.push_back(builderTracker->builderID);
825 buildTask->builderTrackers.push_back(builderTracker);
826 buildTask->currentBuildPower += ai->cb->GetUnitDef(builderTracker->builderID)->buildSpeed;
827 assert(builderTracker->buildTaskId == 0);
828 assert(builderTracker->taskPlanId == 0);
829 assert(builderTracker->factoryId == 0);
830
831 builderTracker->buildTaskId = buildTask->id;
832 }
833
GetBuildTask(int buildTaskId)834 BuildTask* CUnitHandler::GetBuildTask(int buildTaskId) {
835 for (int k = 0; k < CAT_LAST; k++) {
836 for (std::list<BuildTask>::iterator i = BuildTasks[k].begin(); i != BuildTasks[k].end(); i++) {
837 if (i->id == buildTaskId)
838 return &*i;
839 }
840 }
841
842 // this better not happen
843 assert(false);
844 return 0;
845 }
846
BuildTaskExist(float3 pos,const UnitDef * builtdef)847 BuildTask* CUnitHandler::BuildTaskExist(float3 pos, const UnitDef* builtdef) {
848 UnitCategory category = ai->ut->GetCategory(builtdef);
849
850 if (category >= CAT_LAST) {
851 return NULL;
852 }
853
854 for (std::list<BuildTask>::iterator i = BuildTasks[category].begin(); i != BuildTasks[category].end(); i++) {
855 if (i->pos.distance2D(pos) < 1 && ai->ut->GetCategory(i->def) == category) {
856 return &*i;
857 }
858 }
859
860 return NULL;
861 }
862
BuildTaskAddBuilder(int builderID,UnitCategory category)863 bool CUnitHandler::BuildTaskAddBuilder(int builderID, UnitCategory category) {
864 assert(category < CAT_LAST);
865 assert(builderID >= 0);
866 assert(ai->GetUnit(builderID) != NULL);
867
868 CUNIT* u = ai->GetUnit(builderID);
869 BuilderTracker* builderTracker = GetBuilderTracker(builderID);
870
871 const UnitDef* builderDef = ai->cb->GetUnitDef(builderID);
872 const int frame = ai->cb->GetCurrentFrame();
873
874 // make sure this builder is free
875 const bool b1 = (builderTracker->taskPlanId == 0);
876 const bool b2 = (builderTracker->buildTaskId == 0);
877 const bool b3 = (builderTracker->factoryId == 0);
878 const bool b4 = builderDef->canAssist;
879 const bool b5 = (category == CAT_FACTORY && frame >= 18000);
880
881 if (!b1 || !b2 || !b3 || !b4) {
882 if (b5) {
883 // note that FactoryBuilderAdd() asserts b1 through b4
884 // immediately after BuildTaskAddBuilder() is tried and
885 // fails in BuildUp(), so at least those must be true
886 // (and so should b5 in most of the *A mods)
887
888 std::stringstream msg;
889 msg << "[CUnitHandler::BuildTaskAddBuilder()][frame=" << frame << "]\n";
890 msg << "\tbuilder " << builderID << " not able to be added to CAT_FACTORY build-task\n";
891 msg << "\tb1: " << b1 << ", b2: " << b2 << ", b3: " << b3;
892 msg << ", b4: " << b4 << ", b5: " << b5;
893 ai->GetLogger()->Log(msg.str());
894 }
895
896 return false;
897 }
898
899 // see if there are any BuildTasks that it can join
900 if (BuildTasks[category].size() > 0) {
901 float largestTime = 0.0f;
902 std::list<BuildTask>::iterator task;
903 std::list<BuildTask>::iterator bestTask;
904
905 for (task = BuildTasks[category].begin(); task != BuildTasks[category].end(); task++) {
906 float buildTime = ai->math->ETT(*task) - ai->math->ETA(builderID, ai->cb->GetUnitPos(task->id));
907
908 if (buildTime > largestTime) {
909 largestTime = buildTime;
910 bestTask = task;
911 }
912 }
913
914 if (largestTime > 0.0f) {
915 BuildTaskAddBuilder(&*bestTask, builderTracker);
916 u->Repair(bestTask->id);
917 return true;
918 }
919 }
920
921 // see if there any joinable TaskPlans
922 if (TaskPlans[category].size() > 0) {
923 float largestTime = 0.0f;
924 std::list<TaskPlan>::iterator plan;
925 std::list<TaskPlan>::iterator bestPlan;
926
927 for (plan = TaskPlans[category].begin(); plan != TaskPlans[category].end(); plan++) {
928 float buildTime = (plan->def->buildTime / plan->currentBuildPower) - ai->math->ETA(builderID, plan->pos);
929
930 // must test if this builder can make this unit/building too
931 if (buildTime > largestTime) {
932 const std::vector<int>* canBuildList = &ai->ut->unitTypes[builderDef->id].canBuildList;
933 const int buildListSize = canBuildList->size();
934
935 for (int j = 0; j < buildListSize; j++) {
936 if (canBuildList->at(j) == plan->def->id) {
937 largestTime = buildTime;
938 bestPlan = plan;
939 break;
940 }
941 }
942 }
943 }
944
945 if (largestTime > 10.0f) {
946 assert(builderID >= 0);
947
948 // bad, CUNIT::Build() uses TaskPlanCreate()
949 // should we really give build orders here?
950 // return u->Build(bestPlan->pos, bestPlan->def, -1);
951 // TaskPlanCreate(builderID, bestPlan->pos, bestPlan->def);
952 return true;
953 }
954 }
955
956 if (b5) {
957 std::stringstream msg;
958 msg << "[CUnitHandler::BuildTaskAddBuilder()][frame=" << frame << "]\n";
959 msg << "\tno joinable CAT_FACTORY build-tasks or task-plans for builder " << builderID;
960 ai->GetLogger()->Log(msg.str());
961 }
962
963 return false;
964 }
965
TaskPlanCreate(int builder,float3 pos,const UnitDef * builtdef)966 void CUnitHandler::TaskPlanCreate(int builder, float3 pos, const UnitDef* builtdef) {
967 UnitCategory category = ai->ut->GetCategory(builtdef);
968
969 // HACK
970 if (category >= CAT_LAST) {
971 return;
972 }
973
974 // find this builder
975 BuilderTracker* builderTracker = GetBuilderTracker(builder);
976
977 // make sure this builder is free
978 bool b1 = (builderTracker->taskPlanId == 0);
979 bool b2 = (builderTracker->buildTaskId == 0);
980 bool b3 = (builderTracker->factoryId == 0);
981
982 if (!b1 || !b2 || !b3) {
983 return;
984 }
985
986
987 bool existingTP = false;
988 for (std::list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
989 if (pos.distance2D(i->pos) < 20.0f && builtdef == i->def) {
990 // make sure there are no other TaskPlans
991 if (!existingTP) {
992 existingTP = true;
993 TaskPlanAdd(&*i, builderTracker);
994 } else {
995 std::stringstream msg;
996 msg << "[CUnitHandler::TaskPlanCreate()][frame=" << ai->cb->GetCurrentFrame() << "]\n";
997 msg << "\ttask-plan for \"" << builtdef->humanName << "\" already present";
998 msg << " at position <" << pos.x << ", " << pos.y << ", " << pos.z << ">\n";
999 ai->GetLogger()->Log(msg.str());
1000 }
1001 }
1002 }
1003 if (!existingTP) {
1004 TaskPlan tp;
1005 tp.pos = pos;
1006 tp.def = builtdef;
1007 tp.defName = builtdef->name;
1008 tp.currentBuildPower = 0;
1009 tp.id = taskPlanCounter++;
1010 TaskPlanAdd(&tp, builderTracker);
1011
1012 if (category == CAT_DEFENCE)
1013 ai->dm->AddDefense(pos, builtdef);
1014
1015 TaskPlans[category].push_back(tp);
1016 }
1017 }
1018
TaskPlanAdd(TaskPlan * taskPlan,BuilderTracker * builderTracker)1019 void CUnitHandler::TaskPlanAdd(TaskPlan* taskPlan, BuilderTracker* builderTracker) {
1020 taskPlan->builders.push_back(builderTracker->builderID);
1021 taskPlan->builderTrackers.push_back(builderTracker);
1022 taskPlan->currentBuildPower += ai->cb->GetUnitDef(builderTracker->builderID)->buildSpeed;
1023 assert(builderTracker->buildTaskId == 0);
1024 assert(builderTracker->taskPlanId == 0);
1025 assert(builderTracker->factoryId == 0);
1026
1027 builderTracker->taskPlanId = taskPlan->id;
1028 }
1029
TaskPlanRemove(BuilderTracker * builderTracker)1030 void CUnitHandler::TaskPlanRemove(BuilderTracker* builderTracker) {
1031 std::list<TaskPlan>::iterator killplan;
1032 std::list<int>::iterator killBuilder;
1033 // make sure this builder is in a TaskPlan
1034 assert(builderTracker->buildTaskId == 0);
1035 assert(builderTracker->taskPlanId != 0);
1036 assert(builderTracker->factoryId == 0);
1037
1038 builderTracker->taskPlanId = 0;
1039 int builder = builderTracker->builderID;
1040 bool found = false;
1041 bool found2 = false;
1042
1043 for (int k = 0; k < CAT_LAST; k++) {
1044 for (std::list<TaskPlan>::iterator i = TaskPlans[k].begin(); i != TaskPlans[k].end(); i++) {
1045 for (std::list<int>::iterator j = i->builders.begin(); j != i->builders.end(); j++) {
1046 if (*j == builder) {
1047 killplan = i;
1048 killBuilder = j;
1049 assert(!found);
1050 found = true;
1051 found2 = true;
1052 }
1053 }
1054 }
1055 if (found2) {
1056 for (std::list<BuilderTracker*>::iterator i = killplan->builderTrackers.begin(); i != killplan->builderTrackers.end(); i++) {
1057 if (builderTracker == *i) {
1058 // give it time to change command
1059 builderTracker->commandOrderPushFrame = ai->cb->GetCurrentFrame();
1060 killplan->builderTrackers.erase(i);
1061 break;
1062 }
1063 }
1064
1065 killplan->builders.erase(killBuilder);
1066
1067 if (killplan->builders.size() == 0) {
1068 // TaskPlan lost all its workers, remove
1069 if (ai->ut->GetCategory(killplan->def) == CAT_DEFENCE)
1070 ai->dm->RemoveDefense(killplan->pos, killplan->def);
1071
1072 TaskPlans[k].erase(killplan);
1073 }
1074
1075 found2 = false;
1076 }
1077 }
1078
1079 if (!found) {
1080 assert(false);
1081 }
1082 }
1083
GetTaskPlan(int taskPlanId)1084 TaskPlan* CUnitHandler::GetTaskPlan(int taskPlanId) {
1085 for (int k = 0; k < CAT_LAST;k++) {
1086 for (std::list<TaskPlan>::iterator i = TaskPlans[k].begin(); i != TaskPlans[k].end(); i++) {
1087 if (i->id == taskPlanId)
1088 return &*i;
1089 }
1090 }
1091
1092 // this better not happen
1093 assert(false);
1094 return 0;
1095 }
1096
TaskPlanExist(float3 pos,const UnitDef * builtdef)1097 bool CUnitHandler::TaskPlanExist(float3 pos, const UnitDef* builtdef) {
1098 UnitCategory category = ai->ut->GetCategory(builtdef);
1099
1100 if (category >= CAT_LAST) {
1101 return false;
1102 }
1103
1104 for (std::list<TaskPlan>::iterator i = TaskPlans[category].begin(); i != TaskPlans[category].end(); i++) {
1105 if (i->pos.distance2D(pos) < 100 && ai->ut->GetCategory(i->def) == category) {
1106 return true;
1107 }
1108 }
1109
1110 return false;
1111 }
1112
MetalExtractorAdd(int extractorID)1113 void CUnitHandler::MetalExtractorAdd(int extractorID) {
1114 if (ai->ut->GetCategory(extractorID) == CAT_MEX) {
1115 MetalExtractor newMex;
1116 newMex.id = extractorID;
1117 newMex.buildFrame = ai->cb->GetCurrentFrame();
1118 MetalExtractors.push_back(newMex);
1119 } else {
1120 assert(false);
1121 }
1122 }
1123
MetalExtractorRemove(int extractorID)1124 void CUnitHandler::MetalExtractorRemove(int extractorID) {
1125 for (std::vector<MetalExtractor>::iterator i = MetalExtractors.begin(); i != MetalExtractors.end(); i++) {
1126 if (i->id == extractorID) {
1127 MetalExtractors.erase(i);
1128 break;
1129 }
1130 }
1131 }
1132
CompareExtractors(const MetalExtractor & l,const MetalExtractor & r)1133 inline bool CompareExtractors(const MetalExtractor& l, const MetalExtractor& r) {
1134 // higher frame means more recently built
1135 return (l.buildFrame < r.buildFrame);
1136 }
1137
1138 // returns the ID of the oldest (in
1139 // frames) metal extractor built
GetOldestMetalExtractor(void)1140 int CUnitHandler::GetOldestMetalExtractor(void) {
1141 std::sort(MetalExtractors.begin(), MetalExtractors.end(), &CompareExtractors);
1142
1143 return (MetalExtractors.size() > 0)? (MetalExtractors.begin())->id: -1;
1144 }
1145
NukeSiloAdd(int siloID)1146 void CUnitHandler::NukeSiloAdd(int siloID) {
1147 if (ai->ut->GetCategory(siloID) == CAT_NUKE) {
1148 NukeSilo newSilo;
1149 newSilo.id = siloID;
1150 newSilo.numNukesReady = 0;
1151 newSilo.numNukesQueued = 0;
1152 NukeSilos.push_back(newSilo);
1153 } else {
1154 assert(false);
1155 }
1156 }
1157
NukeSiloRemove(int siloID)1158 void CUnitHandler::NukeSiloRemove(int siloID) {
1159 for (std::list<NukeSilo>::iterator i = NukeSilos.begin(); i != NukeSilos.end(); i++) {
1160 if (i->id == siloID) {
1161 NukeSilos.erase(i);
1162 break;
1163 }
1164 }
1165 }
1166
1167 // add a new factory
FactoryAdd(int factory)1168 void CUnitHandler::FactoryAdd(int factory) {
1169 if (ai->ut->GetCategory(factory) == CAT_FACTORY) {
1170 Factory newFact;
1171 newFact.id = factory;
1172 Factories.push_back(newFact);
1173 } else {
1174 assert(false);
1175 }
1176 }
1177
FactoryRemove(int id)1178 void CUnitHandler::FactoryRemove(int id) {
1179 std::list<Factory>::iterator iter;
1180 bool factoryFound = false;
1181
1182 for (std::list<Factory>::iterator i = Factories.begin(); i != Factories.end(); i++) {
1183 if (i->id == id) {
1184 iter = i;
1185 factoryFound = true;
1186 break;
1187 }
1188 }
1189 if (factoryFound) {
1190 // remove all builders from this plan
1191 std::list<BuilderTracker*> builderTrackers = iter->supportBuilderTrackers;
1192
1193 for (std::list<BuilderTracker*>::iterator i = builderTrackers.begin(); i != builderTrackers.end(); i++) {
1194 FactoryBuilderRemove(*i);
1195 }
1196
1197 Factories.erase(iter);
1198 }
1199 }
1200
FactoryBuilderAdd(int builderID)1201 bool CUnitHandler::FactoryBuilderAdd(int builderID) {
1202 CUNIT* unit = ai->GetUnit(builderID);
1203 BuilderTracker* builderTracker = GetBuilderTracker(builderID);
1204 return ((unit->def()->canAssist) && FactoryBuilderAdd(builderTracker));
1205 }
1206
FactoryBuilderAdd(BuilderTracker * builderTracker)1207 bool CUnitHandler::FactoryBuilderAdd(BuilderTracker* builderTracker) {
1208 assert(builderTracker->buildTaskId == 0);
1209 assert(builderTracker->taskPlanId == 0);
1210 assert(builderTracker->factoryId == 0);
1211
1212 for (std::list<Factory>::iterator i = Factories.begin(); i != Factories.end(); i++) {
1213 CUNIT* u = ai->GetUnit(i->id);
1214
1215 // don't assist hubs (or factories that cannot be assisted)
1216 if ((u->def())->canBeAssisted && !u->isHub()) {
1217 float totalBuilderCost = 0.0f;
1218
1219 // HACK: get the sum of the heuristic costs of every
1220 // builder that is already assisting this factory
1221 for (std::list<int>::iterator j = i->supportbuilders.begin(); j != i->supportbuilders.end(); j++) {
1222 if ((ai->GetUnit(*j)->def())->isCommander) {
1223 continue;
1224 }
1225
1226 totalBuilderCost += ai->math->GetUnitCost(*j);
1227 }
1228
1229 // if this sum is less than the heuristic cost of the
1230 // factory itself, add the builder to this factory
1231 //
1232 // this is based purely on the metal and energy costs
1233 // of all involved parties, and silently expects that
1234 // building _another_ factory would always be better
1235 // than assisting it further
1236 if (totalBuilderCost < (ai->math->GetUnitCost(i->id) * BUILDERFACTORYCOSTRATIO * 2.5f)) {
1237 builderTracker->factoryId = i->id;
1238 i->supportbuilders.push_back(builderTracker->builderID);
1239 i->supportBuilderTrackers.push_back(builderTracker);
1240 ai->GetUnit(builderTracker->builderID)->Guard(i->id);
1241 return true;
1242 }
1243 }
1244 }
1245
1246 return false;
1247 }
1248
FactoryBuilderRemove(BuilderTracker * builderTracker)1249 void CUnitHandler::FactoryBuilderRemove(BuilderTracker* builderTracker) {
1250 assert(builderTracker->buildTaskId == 0);
1251 assert(builderTracker->taskPlanId == 0);
1252 assert(builderTracker->factoryId != 0);
1253
1254 std::list<Factory>::iterator killfactory;
1255
1256 for (std::list<Factory>::iterator i = Factories.begin(); i != Factories.end(); i++) {
1257 if (builderTracker->factoryId == i->id) {
1258 i->supportbuilders.remove(builderTracker->builderID);
1259 i->supportBuilderTrackers.remove(builderTracker);
1260 builderTracker->factoryId = 0;
1261 // give it time to change command
1262 builderTracker->commandOrderPushFrame = ai->cb->GetCurrentFrame();
1263 }
1264 }
1265 }
1266
BuilderReclaimOrder(int builderId,const float3 &)1267 void CUnitHandler::BuilderReclaimOrder(int builderId, const float3&) {
1268 BuilderTracker* builderTracker = GetBuilderTracker(builderId);
1269 assert(builderTracker->buildTaskId == 0);
1270 assert(builderTracker->taskPlanId == 0);
1271 assert(builderTracker->factoryId == 0);
1272
1273 taskPlanCounter++;
1274 }
1275
CreateUpgradeTask(int oldBuildingID,const float3 & oldBuildingPos,const UnitDef * newBuildingDef)1276 UpgradeTask* CUnitHandler::CreateUpgradeTask(int oldBuildingID, const float3& oldBuildingPos, const UnitDef* newBuildingDef) {
1277 assert(FindUpgradeTask(oldBuildingID) == NULL);
1278
1279 // UpdateTasks() handles the deletion
1280 UpgradeTask* task = new UpgradeTask(oldBuildingID, ai->cb->GetCurrentFrame(), oldBuildingPos, newBuildingDef);
1281 upgradeTasks[oldBuildingID] = task;
1282
1283 return task;
1284 }
1285
FindUpgradeTask(int oldBuildingID)1286 UpgradeTask* CUnitHandler::FindUpgradeTask(int oldBuildingID) {
1287 std::map<int, UpgradeTask*>::iterator it = upgradeTasks.find(oldBuildingID);
1288
1289 if (it != upgradeTasks.end()) {
1290 return (it->second);
1291 }
1292
1293 return NULL;
1294 }
1295
RemoveUpgradeTask(UpgradeTask * task)1296 void CUnitHandler::RemoveUpgradeTask(UpgradeTask* task) {
1297 assert(task != NULL);
1298 assert(FindUpgradeTask(task->oldBuildingID) != NULL);
1299
1300 upgradeTasks.erase(task->oldBuildingID);
1301 delete task;
1302 }
1303
AddUpgradeTaskBuilder(UpgradeTask * task,int builderID)1304 bool CUnitHandler::AddUpgradeTaskBuilder(UpgradeTask* task, int builderID) {
1305 std::set<int>::iterator it = task->builderIDs.find(builderID);
1306
1307 if (it == task->builderIDs.end()) {
1308 task->builderIDs.insert(builderID);
1309 return true;
1310 }
1311
1312 return false;
1313 }
1314
UpdateUpgradeTasks(int frame)1315 void CUnitHandler::UpdateUpgradeTasks(int frame) {
1316 std::map<int, UpgradeTask*>::iterator upgradeTaskIt;
1317
1318 std::list<UpgradeTask*> deadTasks;
1319 std::list<UpgradeTask*>::iterator deadTasksIt;
1320
1321 for (upgradeTaskIt = upgradeTasks.begin(); upgradeTaskIt != upgradeTasks.end(); upgradeTaskIt++) {
1322 UpgradeTask* task = upgradeTaskIt->second;
1323
1324 const int oldBuildingID = task->oldBuildingID;
1325 const bool oldBuildingDead =
1326 (ai->cb->GetUnitDef(oldBuildingID) == NULL) ||
1327 (ai->cb->GetUnitHealth(oldBuildingID) < 0.0f);
1328
1329 std::set<int>::iterator builderIDsIt;
1330 std::list<int> deadBuilderIDs;
1331 std::list<int>::iterator deadBuilderIDsIt;
1332
1333 for (builderIDsIt = task->builderIDs.begin(); builderIDsIt != task->builderIDs.end(); builderIDsIt++) {
1334 const int builderID = *builderIDsIt;
1335 const bool builderDead =
1336 (ai->cb->GetUnitDef(builderID) == NULL) ||
1337 (ai->cb->GetUnitHealth(builderID) <= 0.0f);
1338
1339 if (builderDead) {
1340 deadBuilderIDs.push_back(builderID);
1341 } else {
1342 const CCommandQueue* cq = ai->cb->GetCurrentUnitCommands(builderID);
1343
1344 if (oldBuildingDead) {
1345 if (!task->reclaimStatus) {
1346 task->creationFrame = frame;
1347 task->reclaimStatus = true;
1348 }
1349
1350 // give a build order for the replacement structure
1351 if (cq->size() == 0 || ((cq->front()).id != -task->newBuildingDef->id)) {
1352 std::stringstream msg;
1353 msg << "[CUnitHandler::UpdateUpgradeTasks()][frame=" << frame << "]\n";
1354 msg << "\tgiving build order for \"" << task->newBuildingDef->humanName;
1355 msg << "\" to builder " << builderID << "\n";
1356 ai->GetLogger()->Log(msg.str());
1357
1358 ai->GetUnit(builderID)->Build_ClosestSite(task->newBuildingDef, task->oldBuildingPos);
1359 }
1360 } else {
1361 // give a reclaim order for the original structure
1362 if (cq->size() == 0 || ((cq->front()).id != CMD_RECLAIM)) {
1363 std::stringstream msg;
1364 msg << "[CUnitHandler::UpdateUpgradeTasks()][frame=" << frame << "]\n";
1365 msg << "\tgiving reclaim order for \"" << ai->cb->GetUnitDef(oldBuildingID)->humanName;
1366 msg << "\" to builder " << builderID << "\n";
1367 ai->GetLogger()->Log(msg.str());
1368
1369 ai->GetUnit(builderID)->Reclaim(oldBuildingID);
1370 }
1371 }
1372 }
1373 }
1374
1375
1376 // filter any dead builders from the upgrade task
1377 // (probably should tie this into UnitDestroyed())
1378 for (deadBuilderIDsIt = deadBuilderIDs.begin(); deadBuilderIDsIt != deadBuilderIDs.end(); deadBuilderIDsIt++) {
1379 task->builderIDs.erase(*deadBuilderIDsIt);
1380 }
1381
1382 if (oldBuildingDead) {
1383 // all builders have been given a build order
1384 // for the replacement structure at this point,
1385 // so the task itself is no longer needed
1386 deadTasks.push_back(task);
1387 }
1388 }
1389
1390 for (deadTasksIt = deadTasks.begin(); deadTasksIt != deadTasks.end(); deadTasksIt++) {
1391 RemoveUpgradeTask(*deadTasksIt);
1392 }
1393 }
1394