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