1 // ==============================================================
2 // This file is part of Glest (www.glest.org)
3 //
4 // Copyright (C) 2001-2008 Marti�o Figueroa
5 //
6 // You can redistribute this code and/or modify it under
7 // the terms of the GNU General Public License as published
8 // by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version
10 // ==============================================================
11 #include "ai_rule.h"
12
13 #include <algorithm>
14
15 #include "ai.h"
16 #include "ai_interface.h"
17 #include "unit.h"
18 #include "leak_dumper.h"
19 #include <climits>
20
21 using Shared::Graphics::Vec2i;
22
23 namespace Glest{ namespace Game{
24
25 // =====================================================
26 // class AiRule
27 // =====================================================
28
AiRule(Ai * ai)29 AiRule::AiRule(Ai *ai){
30 this->ai= ai;
31 }
32
33 // =====================================================
34 // class AiRuleWorkerHarvest
35 // =====================================================
36
AiRuleWorkerHarvest(Ai * ai)37 AiRuleWorkerHarvest::AiRuleWorkerHarvest(Ai *ai):
38 AiRule(ai)
39 {
40 stoppedWorkerIndex= -1;
41 }
42
test()43 bool AiRuleWorkerHarvest::test(){
44 return ai->findAbleUnit(&stoppedWorkerIndex, ccHarvest, true);
45 }
46
execute()47 void AiRuleWorkerHarvest::execute(){
48 ai->harvest(stoppedWorkerIndex);
49 }
50
51 // =====================================================
52 // class AiRuleRefreshHarvester
53 // =====================================================
54
AiRuleRefreshHarvester(Ai * ai)55 AiRuleRefreshHarvester::AiRuleRefreshHarvester(Ai *ai):
56 AiRule(ai)
57 {
58 workerIndex= -1;
59 }
60
test()61 bool AiRuleRefreshHarvester::test(){
62 return ai->findAbleUnit(&workerIndex, ccHarvest, ccHarvest);
63 }
64
execute()65 void AiRuleRefreshHarvester::execute(){
66 ai->harvest(workerIndex);
67 }
68
69 // =====================================================
70 // class AiRuleScoutPatrol
71 // =====================================================
72
AiRuleScoutPatrol(Ai * ai)73 AiRuleScoutPatrol::AiRuleScoutPatrol(Ai *ai):
74 AiRule(ai)
75 {
76 }
77
test()78 bool AiRuleScoutPatrol::test(){
79 return ai->isStableBase();
80 }
81
execute()82 void AiRuleScoutPatrol::execute(){
83 ai->sendScoutPatrol();
84 }
85 // =====================================================
86 // class AiRuleRepair
87 // =====================================================
88
AiRuleRepair(Ai * ai)89 AiRuleRepair::AiRuleRepair(Ai *ai):
90 AiRule(ai)
91 {
92 }
93
test()94 bool AiRuleRepair::test(){
95 AiInterface *aiInterface= ai->getAiInterface();
96
97 //look for a damaged unit
98 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
99 const Unit *u= aiInterface->getMyUnit(i);
100 if(u->getHpRatio()<1.f){
101 damagedUnitIndex= i;
102 return true;
103 }
104 }
105 return false;
106 }
107
execute()108 void AiRuleRepair::execute(){
109 AiInterface *aiInterface= ai->getAiInterface();
110 const Unit *damagedUnit= aiInterface->getMyUnit(damagedUnitIndex);
111
112 //find a repairer and issue command
113 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
114 const Unit *u= aiInterface->getMyUnit(i);
115 const RepairCommandType *rct= static_cast<const RepairCommandType *>(u->getType()->getFirstCtOfClass(ccRepair));
116 if(rct!=NULL && (u->getCurrSkill()->getClass()==scStop || u->getCurrSkill()->getClass()==scMove)){
117 if(rct->isRepairableUnitType(damagedUnit->getType())){
118 aiInterface->giveCommand(i, rct, damagedUnit->getPos());
119 aiInterface->printLog(3, "Repairing order issued");
120 return;
121 }
122 }
123 }
124 }
125
126 // =====================================================
127 // class AiRuleReturnBase
128 // =====================================================
129
AiRuleReturnBase(Ai * ai)130 AiRuleReturnBase::AiRuleReturnBase(Ai *ai):
131 AiRule(ai)
132 {
133 stoppedUnitIndex= -1;
134 }
135
test()136 bool AiRuleReturnBase::test(){
137 return ai->findAbleUnit(&stoppedUnitIndex, ccMove, true);
138 }
139
execute()140 void AiRuleReturnBase::execute(){
141 ai->returnBase(stoppedUnitIndex);
142 }
143
144 // =====================================================
145 // class AiRuleMassiveAttack
146 // =====================================================
147
AiRuleMassiveAttack(Ai * ai)148 AiRuleMassiveAttack::AiRuleMassiveAttack(Ai *ai):
149 AiRule(ai)
150 {
151 }
152
test()153 bool AiRuleMassiveAttack::test(){
154
155 if(ai->isStableBase()){
156 ultraAttack= false;
157 return ai->beingAttacked(attackPos, field, INT_MAX);
158 }
159 else{
160 ultraAttack= true;
161 return ai->beingAttacked(attackPos, field, baseRadius);
162 }
163 }
164
execute()165 void AiRuleMassiveAttack::execute(){
166 ai->massiveAttack(attackPos, field, ultraAttack);
167 }
168 // =====================================================
169 // class AiRuleAddTasks
170 // =====================================================
171
AiRuleAddTasks(Ai * ai)172 AiRuleAddTasks::AiRuleAddTasks(Ai *ai):
173 AiRule(ai)
174 {
175 }
176
test()177 bool AiRuleAddTasks::test(){
178 return !ai->anyTask() || ai->getCountOfClass(ucWorker)<4;
179 }
180
execute()181 void AiRuleAddTasks::execute(){
182 int buildingCount= ai->getCountOfClass(ucBuilding);
183 int warriorCount= ai->getCountOfClass(ucWarrior);
184 int workerCount= ai->getCountOfClass(ucWorker);
185 int upgradeCount= ai->getAiInterface()->getMyUpgradeCount();
186
187 float buildingRatio= ai->getRatioOfClass(ucBuilding);
188 float warriorRatio= ai->getRatioOfClass(ucWarrior);
189 float workerRatio= ai->getRatioOfClass(ucWorker);
190
191 //standard tasks
192
193 //emergency workers
194 if(workerCount<4){
195 ai->addPriorityTask(new ProduceTask(ucWorker));
196 }
197 else{
198 //workers
199 if(workerCount<5) ai->addTask(new ProduceTask(ucWorker));
200 if(workerCount<10) ai->addTask(new ProduceTask(ucWorker));
201 if(workerRatio<0.20) ai->addTask(new ProduceTask(ucWorker));
202 if(workerRatio<0.30) ai->addTask(new ProduceTask(ucWorker));
203
204 //warriors
205 if(warriorCount<10) ai->addTask(new ProduceTask(ucWarrior));
206 if(warriorRatio<0.20) ai->addTask(new ProduceTask(ucWarrior));
207 if(warriorRatio<0.30) ai->addTask(new ProduceTask(ucWarrior));
208 if(workerCount>=10) ai->addTask(new ProduceTask(ucWarrior));
209 if(workerCount>=15) ai->addTask(new ProduceTask(ucWarrior));
210
211 //buildings
212 if(buildingCount<6 || buildingRatio<0.20) ai->addTask(new BuildTask());
213 if(buildingCount<10 && workerCount>12) ai->addTask(new BuildTask());
214
215 //upgrades
216 if(upgradeCount==0 && workerCount>5) ai->addTask(new UpgradeTask());
217 if(upgradeCount==1 && workerCount>10) ai->addTask(new UpgradeTask());
218 if(upgradeCount==2 && workerCount>15) ai->addTask(new UpgradeTask());
219 if(ai->isStableBase()) ai->addTask(new UpgradeTask());
220 }
221 }
222
223 // =====================================================
224 // class AiRuleBuildOneFarm
225 // =====================================================
226
AiRuleBuildOneFarm(Ai * ai)227 AiRuleBuildOneFarm::AiRuleBuildOneFarm(Ai *ai):
228 AiRule(ai)
229 {
230 }
231
test()232 bool AiRuleBuildOneFarm::test(){
233 AiInterface *aiInterface= ai->getAiInterface();
234
235 //for all units
236 for(int i=0; i<aiInterface->getMyFactionType()->getUnitTypeCount(); ++i){
237 const UnitType *ut= aiInterface->getMyFactionType()->getUnitType(i);
238
239 //for all production commands
240 for(int j=0; j<ut->getCommandTypeCount(); ++j){
241 const CommandType *ct= ut->getCommandType(j);
242 if(ct->getClass()==ccProduce){
243 const UnitType *producedType= static_cast<const ProduceCommandType*>(ct)->getProducedUnit();
244
245 //for all resources
246 for(int k=0; k<producedType->getCostCount(); ++k){
247 const Resource *r= producedType->getCost(k);
248
249 //find a food producer in the farm produced units
250 if(r->getAmount()<0 && r->getType()->getClass()==rcConsumable && ai->getCountOfType(ut)==0){
251 farm= ut;
252 return true;
253 }
254 }
255 }
256 }
257 }
258 return false;
259 }
260
execute()261 void AiRuleBuildOneFarm::execute(){
262 ai->addPriorityTask(new BuildTask(farm));
263 }
264
265 // =====================================================
266 // class AiRuleProduceResourceProducer
267 // =====================================================
268
AiRuleProduceResourceProducer(Ai * ai)269 AiRuleProduceResourceProducer::AiRuleProduceResourceProducer(Ai *ai):
270 AiRule(ai)
271 {
272 interval= shortInterval;
273 }
274
test()275 bool AiRuleProduceResourceProducer::test(){
276 //emergency tasks: resource buildings
277 AiInterface *aiInterface= ai->getAiInterface();
278
279 //consumables first
280 for(int i=0; i<aiInterface->getTechTree()->getResourceTypeCount(); ++i){
281 rt= aiInterface->getTechTree()->getResourceType(i);
282 const Resource *r= aiInterface->getResource(rt);
283 if(rt->getClass()==rcConsumable && r->getBalance()<0){
284 interval= longInterval;
285 return true;
286
287 }
288 }
289
290 //statics second
291 for(int i=0; i<aiInterface->getTechTree()->getResourceTypeCount(); ++i){
292 rt= aiInterface->getTechTree()->getResourceType(i);
293 const Resource *r= aiInterface->getResource(rt);
294 if(rt->getClass()==rcStatic && r->getAmount()<minStaticResources){
295 interval= longInterval;
296 return true;
297
298 }
299 }
300
301 interval= shortInterval;
302 return false;
303 }
304
execute()305 void AiRuleProduceResourceProducer::execute(){
306 ai->addPriorityTask(new ProduceTask(rt));
307 ai->addTask(new BuildTask(rt));
308 }
309
310 // =====================================================
311 // class AiRuleProduce
312 // =====================================================
313
AiRuleProduce(Ai * ai)314 AiRuleProduce::AiRuleProduce(Ai *ai):
315 AiRule(ai)
316 {
317 produceTask= NULL;
318 }
319
test()320 bool AiRuleProduce::test(){
321 const Task *task= ai->getTask();
322
323 if(task==NULL || task->getClass()!=tcProduce){
324 return false;
325 }
326
327 produceTask= static_cast<const ProduceTask*>(task);
328 return true;
329 }
330
execute()331 void AiRuleProduce::execute(){
332 if(produceTask!=NULL){
333
334 //generic produce task, produce random unit that has the skill or produces the resource
335 if(produceTask->getUnitType()==NULL){
336 produceGeneric(produceTask);
337 }
338
339 //specific produce task, produce if possible, retry if not enough resources
340 else{
341 produceSpecific(produceTask);
342 }
343
344 //remove the task
345 ai->removeTask(produceTask);
346 }
347 }
348
produceGeneric(const ProduceTask * pt)349 void AiRuleProduce::produceGeneric(const ProduceTask *pt){
350 typedef vector<const UnitType*> UnitTypes;
351 UnitTypes ableUnits;
352 AiInterface *aiInterface= ai->getAiInterface();
353
354 //for each unit, produce it if possible
355 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
356
357 //for each command
358 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
359 for(int j=0; j<ut->getCommandTypeCount(); ++j){
360 const CommandType *ct= ut->getCommandType(j);
361
362 //if the command is produce
363 if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){
364
365 const UnitType *producedUnit= static_cast<const UnitType*>(ct->getProduced());
366 bool produceIt= false;
367
368 //if the unit produces the resource
369 if(pt->getResourceType()!=NULL){
370 const Resource *r= producedUnit->getCost(pt->getResourceType());
371 if(r!=NULL && r->getAmount()<0){
372 produceIt= true;
373 }
374 }
375
376 else{
377 //if the unit is from the right class
378 if(producedUnit->isOfClass(pt->getUnitClass())){
379 if(aiInterface->reqsOk(ct) && aiInterface->reqsOk(producedUnit)){
380 produceIt= true;
381 }
382 }
383 }
384
385 if(produceIt){
386 //if the unit is not already on the list
387 if(find(ableUnits.begin(), ableUnits.end(), producedUnit)==ableUnits.end()){
388 ableUnits.push_back(producedUnit);
389 }
390 }
391 }
392 }
393 }
394
395 //add specific produce task
396 if(!ableUnits.empty()){
397
398 //priority for non produced units
399 for(int i=0; i<ableUnits.size(); ++i){
400 if(ai->getCountOfType(ableUnits[i])==0){
401 if(ai->getRandom()->randRange(0, 1)==0){
402 ai->addTask(new ProduceTask(ableUnits[i]));
403 return;
404 }
405 }
406 }
407
408 //normal case
409 ai->addTask(new ProduceTask(ableUnits[ai->getRandom()->randRange(0, ableUnits.size()-1)]));
410 }
411 }
412
produceSpecific(const ProduceTask * pt)413 void AiRuleProduce::produceSpecific(const ProduceTask *pt){
414
415 AiInterface *aiInterface= ai->getAiInterface();
416
417 //if unit meets requirements
418 if(aiInterface->reqsOk(pt->getUnitType())){
419
420 //if unit doesnt meet resources retry
421 if(!aiInterface->checkCosts(pt->getUnitType())){
422 ai->retryTask(pt);
423 return;
424 }
425
426 //produce specific unit
427 vector<int> producers;
428 const CommandType *defCt= NULL;
429
430 //for each unit
431 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
432
433 //for each command
434 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
435 for(int j=0; j<ut->getCommandTypeCount(); ++j){
436 const CommandType *ct= ut->getCommandType(j);
437
438 //if the command is produce
439 if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){
440 const UnitType *producedUnit= static_cast<const UnitType*>(ct->getProduced());
441
442 //if units match
443 if(producedUnit == pt->getUnitType()){
444 if(aiInterface->reqsOk(ct)){
445 defCt= ct;
446 producers.push_back(i);
447 }
448 }
449 }
450 }
451 }
452
453 //produce from random producer
454 if(!producers.empty()){
455 int producerIndex= producers[ai->getRandom()->randRange(0, producers.size()-1)];
456 aiInterface->giveCommand(producerIndex, defCt);
457 }
458 }
459 }
460
461 // ========================================
462 // class AiRuleBuild
463 // ========================================
464
AiRuleBuild(Ai * ai)465 AiRuleBuild::AiRuleBuild(Ai *ai):
466 AiRule(ai)
467 {
468 buildTask= NULL;
469 }
470
test()471 bool AiRuleBuild::test(){
472 const Task *task= ai->getTask();
473
474 if(task==NULL || task->getClass()!=tcBuild){
475 return false;
476 }
477
478 buildTask= static_cast<const BuildTask*>(task);
479 return true;
480 }
481
482
execute()483 void AiRuleBuild::execute(){
484
485 if(buildTask!=NULL){
486
487 //generic build task, build random building that can be built
488 if(buildTask->getUnitType()==NULL){
489 buildGeneric(buildTask);
490 }
491 //specific building task, build if possible, retry if not enough resources or not position
492 else{
493 buildSpecific(buildTask);
494 }
495
496 //remove the task
497 ai->removeTask(buildTask);
498 }
499 }
500
buildGeneric(const BuildTask * bt)501 void AiRuleBuild::buildGeneric(const BuildTask *bt){
502
503 //find buildings that can be built
504 AiInterface *aiInterface= ai->getAiInterface();
505 typedef vector<const UnitType*> UnitTypes;
506 UnitTypes buildings;
507
508 //for each unit
509 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
510
511 //for each command
512 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
513 for(int j=0; j<ut->getCommandTypeCount(); ++j){
514 const CommandType *ct= ut->getCommandType(j);
515
516 //if the command is build
517 if(ct->getClass()==ccBuild){
518 const BuildCommandType *bct= static_cast<const BuildCommandType*>(ct);
519
520 //for each building
521 for(int k=0; k<bct->getBuildingCount(); ++k){
522 const UnitType *building= bct->getBuilding(k);
523 if(aiInterface->reqsOk(bct) && aiInterface->reqsOk(building)){
524
525 //if any building, or produces resource
526 const ResourceType *rt= bt->getResourceType();
527 const Resource *cost= building->getCost(rt);
528 if(rt==NULL || (cost!=NULL && cost->getAmount()<0)){
529 buildings.push_back(building);
530 }
531 }
532 }
533 }
534 }
535 }
536
537 //add specific build task
538 buildBestBuilding(buildings);
539 }
540
buildBestBuilding(const vector<const UnitType * > & buildings)541 void AiRuleBuild::buildBestBuilding(const vector<const UnitType*> &buildings){
542
543 if(!buildings.empty()){
544
545 //build the least built building
546 bool buildingFound= false;
547 for(int i=0; i<10 && !buildingFound; ++i){
548
549 if(i>0){
550
551 //Defensive buildings have priority
552 for(int j=0; j<buildings.size() && !buildingFound; ++j){
553 const UnitType *building= buildings[j];
554 if(ai->getCountOfType(building)<=i+1 && isDefensive(building))
555 {
556 ai->addTask(new BuildTask(building));
557 buildingFound= true;
558 }
559 }
560
561 //Warrior producers next
562 for(int j=0; j<buildings.size() && !buildingFound; ++j){
563 const UnitType *building= buildings[j];
564 if(ai->getCountOfType(building)<=i+1 && isWarriorProducer(building))
565 {
566 ai->addTask(new BuildTask(building));
567 buildingFound= true;
568 }
569 }
570
571 //Resource producers next
572 for(int j=0; j<buildings.size() && !buildingFound; ++j){
573 const UnitType *building= buildings[j];
574 if(ai->getCountOfType(building)<=i+1 && isResourceProducer(building))
575 {
576 ai->addTask(new BuildTask(building));
577 buildingFound= true;
578 }
579 }
580 }
581
582 //Any building
583 for(int j=0; j<buildings.size() && !buildingFound; ++j){
584 const UnitType *building= buildings[j];
585 if(ai->getCountOfType(building)<=i)
586 {
587 ai->addTask(new BuildTask(building));
588 buildingFound= true;
589 }
590 }
591 }
592 }
593 }
594
buildSpecific(const BuildTask * bt)595 void AiRuleBuild::buildSpecific(const BuildTask *bt){
596 AiInterface *aiInterface= ai->getAiInterface();
597 //if reqs ok
598 if(aiInterface->reqsOk(bt->getUnitType())){
599
600 //retry if not enough resources
601 if(!aiInterface->checkCosts(bt->getUnitType())){
602 ai->retryTask(bt);
603 return;
604 }
605
606 vector<int> builders;
607 const BuildCommandType *defBct= NULL;
608
609 //for each unit
610 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
611
612 //if the unit is not going to build
613 const Unit *u= aiInterface->getMyUnit(i);
614 if(!u->anyCommand() || u->getCurrCommand()->getCommandType()->getClass()!=ccBuild){
615
616 //for each command
617 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
618 for(int j=0; j<ut->getCommandTypeCount(); ++j){
619 const CommandType *ct= ut->getCommandType(j);
620
621 //if the command is build
622 if(ct->getClass()==ccBuild){
623 const BuildCommandType *bct= static_cast<const BuildCommandType*>(ct);
624
625 //for each building
626 for(int k=0; k<bct->getBuildingCount(); ++k){
627 const UnitType *building= bct->getBuilding(k);
628
629 //if building match
630 if(bt->getUnitType()==building){
631 if(aiInterface->reqsOk(bct)){
632 builders.push_back(i);
633 defBct= bct;
634 }
635 }
636 }
637 }
638 }
639 }
640 }
641
642 //use random builder to build
643 if(!builders.empty()){
644 int builderIndex= builders[ai->getRandom()->randRange(0, builders.size()-1)];
645 Vec2i pos;
646 Vec2i searchPos= bt->getForcePos()? bt->getPos(): ai->getRandomHomePosition();
647
648 //if free pos give command, else retry
649 if(ai->findPosForBuilding(bt->getUnitType(), searchPos, pos)){
650 aiInterface->giveCommand(builderIndex, defBct, pos, bt->getUnitType());
651 }
652 else{
653 ai->retryTask(bt);
654 return;
655 }
656 }
657 }
658 }
659
isDefensive(const UnitType * building)660 bool AiRuleBuild::isDefensive(const UnitType *building){
661 return building->hasSkillClass(scAttack);
662 }
663
isResourceProducer(const UnitType * building)664 bool AiRuleBuild::isResourceProducer(const UnitType *building){
665 for(int i= 0; i<building->getCostCount(); i++){
666 if(building->getCost(i)->getAmount()<0){
667 return true;
668 }
669 }
670 return false;
671 }
672
isWarriorProducer(const UnitType * building)673 bool AiRuleBuild::isWarriorProducer(const UnitType *building){
674 for(int i= 0; i < building->getCommandTypeCount(); i++){
675 const CommandType *ct= building->getCommandType(i);
676 if(ct->getClass() == ccProduce){
677 const UnitType *ut= static_cast<const ProduceCommandType*>(ct)->getProducedUnit();
678
679 if(ut->isOfClass(ucWarrior)){
680 return true;
681 }
682 }
683 }
684 return false;
685 }
686
687 // ========================================
688 // class AiRuleUpgrade
689 // ========================================
690
AiRuleUpgrade(Ai * ai)691 AiRuleUpgrade::AiRuleUpgrade(Ai *ai):
692 AiRule(ai)
693 {
694 upgradeTask= NULL;
695 }
696
test()697 bool AiRuleUpgrade::test(){
698 const Task *task= ai->getTask();
699
700 if(task==NULL || task->getClass()!=tcUpgrade){
701 return false;
702 }
703
704 upgradeTask= static_cast<const UpgradeTask*>(task);
705 return true;
706 }
707
execute()708 void AiRuleUpgrade::execute(){
709
710 //upgrade any upgrade
711 if(upgradeTask->getUpgradeType()==NULL){
712 upgradeGeneric(upgradeTask);
713 }
714 //upgrade specific upgrade
715 else{
716 upgradeSpecific(upgradeTask);
717 }
718
719 //remove the task
720 ai->removeTask(upgradeTask);
721 }
722
upgradeGeneric(const UpgradeTask * upgt)723 void AiRuleUpgrade::upgradeGeneric(const UpgradeTask *upgt){
724
725 typedef vector<const UpgradeType*> UpgradeTypes;
726 AiInterface *aiInterface= ai->getAiInterface();
727
728 //find upgrades that can be upgraded
729 UpgradeTypes upgrades;
730
731 //for each upgrade, upgrade it if possible
732 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
733
734 //for each command
735 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
736 for(int j=0; j<ut->getCommandTypeCount(); ++j){
737 const CommandType *ct= ut->getCommandType(j);
738
739 //if the command is upgrade
740 if(ct->getClass()==ccUpgrade){
741 const UpgradeCommandType *upgct= static_cast<const UpgradeCommandType*>(ct);
742 const UpgradeType *upgrade= upgct->getProducedUpgrade();
743 if(aiInterface->reqsOk(upgct)){
744 upgrades.push_back(upgrade);
745 }
746 }
747 }
748 }
749
750 //add specific upgrade task
751 if(!upgrades.empty()){
752 ai->addTask(new UpgradeTask(upgrades[ai->getRandom()->randRange(0, upgrades.size()-1)]));
753 }
754 }
755
upgradeSpecific(const UpgradeTask * upgt)756 void AiRuleUpgrade::upgradeSpecific(const UpgradeTask *upgt){
757
758 AiInterface *aiInterface= ai->getAiInterface();
759
760 //if reqs ok
761 if(aiInterface->reqsOk(upgt->getUpgradeType())){
762
763 //if resources dont meet retry
764 if(!aiInterface->checkCosts(upgt->getUpgradeType())){
765 ai->retryTask(upgt);
766 return;
767 }
768
769 //for each unit
770 for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
771
772 //for each command
773 const UnitType *ut= aiInterface->getMyUnit(i)->getType();
774 for(int j=0; j<ut->getCommandTypeCount(); ++j){
775 const CommandType *ct= ut->getCommandType(j);
776
777 //if the command is upgrade
778 if(ct->getClass()==ccUpgrade){
779 const UpgradeCommandType *uct= static_cast<const UpgradeCommandType*>(ct);
780 const UpgradeType *producedUpgrade= uct->getProducedUpgrade();
781
782 //if upgrades match
783 if(producedUpgrade == upgt->getUpgradeType()){
784 if(aiInterface->reqsOk(uct)){
785 aiInterface->giveCommand(i, uct);
786 }
787 }
788 }
789 }
790 }
791
792 }
793 }
794
795 // ========================================
796 // class AiRuleExpand
797 // ========================================
798
AiRuleExpand(Ai * ai)799 AiRuleExpand::AiRuleExpand(Ai *ai):
800 AiRule(ai)
801 {
802 storeType= NULL;
803 }
804
test()805 bool AiRuleExpand::test(){
806 AiInterface *aiInterface = ai->getAiInterface();
807
808 for(int i= 0; i<aiInterface->getTechTree()->getResourceTypeCount(); ++i){
809 const ResourceType *rt = aiInterface->getTechTree()->getResourceType(i);
810
811 if(rt->getClass()==rcTech){
812
813 // If any resource sighted
814 if(aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), expandPos)){
815
816 int minDistance= INT_MAX;
817 storeType= NULL;
818
819 //If there is no close store
820 for(int j=0; j<aiInterface->getMyUnitCount(); ++j){
821 const Unit *u= aiInterface->getMyUnit(j);
822 const UnitType *ut= aiInterface->getMyUnit(j)->getType();
823
824 // If this building is a store
825 if(ut->getStore(rt)>0){
826 storeType = ut;
827 int distance= static_cast<int> (u->getPos().dist(expandPos));
828
829 if(distance < minDistance){
830 minDistance = distance;
831 }
832 }
833 }
834
835 if(minDistance>expandDistance)
836 {
837 return true;
838 }
839 }
840 else{
841 // send patrol to look for resource
842 ai->sendScoutPatrol();
843 }
844 }
845 }
846
847 return false;
848 }
849
execute()850 void AiRuleExpand::execute(){
851 ai->addExpansion(expandPos);
852 ai->addPriorityTask(new BuildTask(storeType, expandPos));
853 }
854
855 }}//end namespace
856