// This file is part of ZetaGlest <https://github.com/ZetaGlest>
//
// Copyright (C) 2018  The ZetaGlest team
//
// ZetaGlest is a fork of MegaGlest <https://megaglest.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>

#include "ai_rule.h"

#include <algorithm>
#include <limits.h>

#include "ai.h"
#include "ai_interface.h"
#include "unit.h"
#include "leak_dumper.h"

using Shared::Graphics::Vec2i;

namespace Game {
	// =====================================================
	//      class AiRule
	// =====================================================

	AiRule::AiRule(Ai * ai) {
		this->ai = ai;
	}

	// =====================================================
	//      class AiRuleWorkerHarvest
	// =====================================================

	AiRuleWorkerHarvest::AiRuleWorkerHarvest(Ai * ai) :
		AiRule(ai) {
		stoppedWorkerIndex = -1;
	}

	bool
		AiRuleWorkerHarvest::test() {
		return ai->findAbleUnit(&stoppedWorkerIndex, ccHarvest, true);
	}

	void
		AiRuleWorkerHarvest::execute() {
		ai->harvest(stoppedWorkerIndex);
	}

	// =====================================================
	//      class AiRuleRefreshHarvester
	// =====================================================

	AiRuleRefreshHarvester::AiRuleRefreshHarvester(Ai * ai) :
		AiRule(ai) {
		workerIndex = -1;
	}

	bool
		AiRuleRefreshHarvester::test() {
		return ai->findAbleUnit(&workerIndex, ccHarvest, ccHarvest);
	}

	void
		AiRuleRefreshHarvester::execute() {
		ai->harvest(workerIndex);
	}

	// =====================================================
	//      class AiRuleScoutPatrol
	// =====================================================

	AiRuleScoutPatrol::AiRuleScoutPatrol(Ai * ai) :
		AiRule(ai) {
	}

	bool
		AiRuleScoutPatrol::test() {
		return ai->isStableBase();
	}

	void
		AiRuleScoutPatrol::execute() {
		ai->sendScoutPatrol();
	}
	// =====================================================
	//      class AiRuleRepair
	// =====================================================

	AiRuleRepair::AiRuleRepair(Ai * ai) :
		AiRule(ai) {
		damagedUnitIndex = 0;
		damagedUnitIsCastle = false;
	}

	double
		AiRuleRepair::getMinCastleHpRatio() const {
		return
			0.6;
	}

	int
		AiRuleRepair::getMinUnitsToRepairCastle() {
		/*
		* Gets the minimum units needed to repair a castle
		*
		* Attributes:
		*	none
		*
		* Documentation Author: Bennett Dixon
		*/
		int
			minUnitsRepairingCastle = 7;
		if (ai->getCountOfClass(ucWorker) <= 6) {
			minUnitsRepairingCastle = 1;
		} else if (ai->getCountOfClass(ucWorker) <= 8) {
			minUnitsRepairingCastle = 2;
		} else if (ai->getCountOfClass(ucWorker) <= 10) {
			minUnitsRepairingCastle = 3;
		} else if (ai->getCountOfClass(ucWorker) <= 12) {
			minUnitsRepairingCastle = 5;
		}
		return minUnitsRepairingCastle;
	}

	bool
		AiRuleRepair::test() {
		AiInterface *
			aiInterface = ai->getAiInterface();

		int
			minUnitsRepairingCastle = getMinUnitsToRepairCastle();
		const double
			minCastleHpRatio = getMinCastleHpRatio();

		// look for a damaged unit and give priority to the factions bases
		// (units that produce workers and store resources)
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
			const Unit *
				u = aiInterface->getMyUnit(i);
			//printf("\n\n\n\n!!!!!! Is damaged unit [%d - %s] u->getHpRatio() = %f, hp = %d, mapHp = %d\n",u->getId(),u->getType()->getName().c_str(),u->getHpRatio(),u->getHp(),u->getType()->getTotalMaxHp(u->getTotalUpgrade()));
			if (u->getHpRatio() < 1.f) {
				//printf("\n\n\n\n!!!!!! Is damaged unit [%d - %s] u->getHpRatio() = %f, hp = %d, mapHp = %d\n",u->getId(),u->getType()->getName().c_str(),u->getHpRatio(),u->getHp(),u->getType()->getTotalMaxHp(u->getTotalUpgrade()));

				bool
					unitCanProduceWorker = false;
				for (int j = 0; unitCanProduceWorker == false &&
					j < u->getType()->getCommandTypeCount(); ++j) {
					const CommandType *
						ct = u->getType()->getCommandType(j);

					//if the command is produce
					if (ct->getClass() == ccProduce
						|| ct->getClass() == ccMorph) {
						const ProducibleType *
							pt = ct->getProduced();
						if (pt != NULL) {
							const UnitType *
								ut = dynamic_cast <const
								UnitType *>(pt);
							if (ut != NULL
								&& ut->hasCommandClass(ccHarvest) == true
								&& u->getType()->getStoredResourceCount() > 0) {
								//printf("\n\n\n\n!!!!!! found candidate castle unit to repair [%d - %s]\n",u->getId(),u->getType()->getName().c_str());
								unitCanProduceWorker = true;
							}
						}
					}
				}

				if (unitCanProduceWorker == true) {
					int
						candidatedamagedUnitIndex = -1;
					int
						unitCountAlreadyRepairingDamagedUnit = 0;
					// Now check if any other unit is able to repair this unit
					for (int i1 = 0; i1 < aiInterface->getMyUnitCount(); ++i1) {
						const Unit *
							u1 = aiInterface->getMyUnit(i1);
						const RepairCommandType *
							rct = static_cast <const
							RepairCommandType *
							>(u1->getType()->getFirstCtOfClass(ccRepair));
						//if(rct) printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can reapir damaged unit [%d]\n",u1->getId(),u1->getType()->getName().c_str(),u->getCurrSkill()->getClass(),rct->isRepairableUnitType(u->getType()));

						if (rct != NULL) {
							//printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can repair damaged unit [%d] Castles hp-ratio = %f\n",u1->getId(),u1->getType()->getName().c_str(),u1->getCurrSkill()->getClass(),rct->isRepairableUnitType(u->getType()),u->getHpRatio());

							if (u1->getCurrSkill()->getClass() == scStop
								|| u1->getCurrSkill()->getClass() == scMove
								|| u->getHpRatio() <= minCastleHpRatio) {
								if (rct->isRepairableUnitType(u->getType())) {
									candidatedamagedUnitIndex = i;
									//return true;
								}
							} else if (u1->getCurrSkill()->getClass() ==
								scRepair) {
								Command *
									cmd = u1->getCurrCommand();
								if (cmd != NULL
									&& cmd->getCommandType()->getClass() ==
									ccRepair) {
									if (cmd->getUnit() != NULL
										&& cmd->getUnit()->getId() ==
										u->getId()) {
										//printf("\n\n\n\n^^^^^^^^^^ unit is ALREADY repairer unit [%d - %s]\n",u1->getId(),u1->getType()->getName().c_str());
										unitCountAlreadyRepairingDamagedUnit++;
									}
								}
							}
						}
					}

					if (candidatedamagedUnitIndex >= 0
						&& unitCountAlreadyRepairingDamagedUnit <
						minUnitsRepairingCastle) {
						//printf("\n\n\n\n^^^^^^^^^^ AI test will repair damaged unit [%d - %s]\n",u->getId(),u->getType()->getName().c_str());
						damagedUnitIndex = candidatedamagedUnitIndex;
						damagedUnitIsCastle = true;
						return true;
					}
				}
			}
		}
		damagedUnitIsCastle = false;
		damagedUnitIndex = -1;
		// Normal Repair checking
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
			const Unit *
				u = aiInterface->getMyUnit(i);
			//printf("\n\n\n\n!!!!!! Is damaged unit [%d - %s] u->getHpRatio() = %f, hp = %d, mapHp = %d\n",u->getId(),u->getType()->getName().c_str(),u->getHpRatio(),u->getHp(),u->getType()->getTotalMaxHp(u->getTotalUpgrade()));
			if (u->getHpRatio() < 1.f) {
				// Now check if any other unit is able to repair this unit
				for (int i1 = 0; i1 < aiInterface->getMyUnitCount(); ++i1) {
					const Unit *
						u1 = aiInterface->getMyUnit(i1);
					const RepairCommandType *
						rct = static_cast <const
						RepairCommandType *
						>(u1->getType()->getFirstCtOfClass(ccRepair));
					//if(rct) printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can reapir damaged unit [%d]\n",u1->getId(),u1->getType()->getName().c_str(),u->getCurrSkill()->getClass(),rct->isRepairableUnitType(u->getType()));

					if (rct != NULL
						&& (u1->getCurrSkill()->getClass() == scStop
							|| u1->getCurrSkill()->getClass() == scMove)) {
						if (rct->isRepairableUnitType(u->getType())) {
							damagedUnitIndex = i;
							//random if return or not so we get different targets from time to time
							if (ai->getRandom()->randRange(0, 1) == 0)
								return true;
						}
					}
				}
			}
		}
		if (damagedUnitIndex != -1) {
			return true;
		}
		return false;
	}

	void
		AiRuleRepair::execute() {
		AiInterface *
			aiInterface = ai->getAiInterface();
		const Unit *
			damagedUnit = aiInterface->getMyUnit(damagedUnitIndex);
		//printf("\n\n\n\n###^^^^^^^^^^ Looking for repairer for damaged unit [%d - %s]\n",damagedUnit->getId(),damagedUnit->getType()->getName().c_str());

		int
			minUnitsRepairingCastle = getMinUnitsToRepairCastle();
		const double
			minCastleHpRatio = getMinCastleHpRatio();

		if (minUnitsRepairingCastle > 2) {
			if (damagedUnit->getCurrSkill()->getClass() == scBeBuilt) {                   // if build is still be build 2 helpers are enough
				minUnitsRepairingCastle = 2;
			}

			if (!damagedUnitIsCastle) {
				minUnitsRepairingCastle = 2;
			}
		}
		if (aiInterface->getControlType() == ctCpuEasy) {
			if (!damagedUnitIsCastle) {
				// cpu easy does not repair!
				minUnitsRepairingCastle = 0;
			}
		}
		if (aiInterface->getControlType() == ctCpu) {
			if (!damagedUnitIsCastle) {
				// cpu does only repair with one unit!
				minUnitsRepairingCastle = 1;
			}
		}
		int
			unitCountAlreadyRepairingDamagedUnit = 0;
		//printf("team %d has damaged unit\n", damagedUnit->getTeam());
		// Now check if any other unit is able to repair this unit
		for (int i1 = 0; i1 < aiInterface->getMyUnitCount(); ++i1) {
			const Unit *
				u1 = aiInterface->getMyUnit(i1);
			const RepairCommandType *
				rct = static_cast <const
				RepairCommandType *
				>(u1->getType()->getFirstCtOfClass(ccRepair));
			//if(rct) printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can reapir damaged unit [%d]\n",u1->getId(),u1->getType()->getName().c_str(),u1->getCurrSkill()->getClass(),rct->isRepairableUnitType(u1->getType()));
			Command *
				cmd = u1->getCurrCommand();
			if (cmd != NULL && cmd->getCommandType()->getClass() == ccRepair) {
				//if(cmd->getUnit() != NULL && cmd->getUnit()->getId() == damagedUnit->getId())
				//if(cmd->getUnit() != NULL && cmd->getPos() == damagedUnit->getPosWithCellMapSet())

				if (rct != NULL) {
					//printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can repair damaged unit [%d] Castles hp-ratio = %f\n",u1->getId(),u1->getType()->getName().c_str(),u1->getCurrSkill()->getClass(),rct->isRepairableUnitType(u->getType()),u->getHpRatio());

					if (((RepairCommandType *) (cmd->getCommandType()))->
						isRepairableUnitType(damagedUnit->getType())) {
						//printf("^^^^test^^^^^^ unit is ALREADY repairer unit [%d - %s]\nminUnitsRepairingCastle=%d\n",u1->getId(), u1->getType()->getName().c_str(), minUnitsRepairingCastle);
						unitCountAlreadyRepairingDamagedUnit++;
					}
				}
			}
		}

		if (unitCountAlreadyRepairingDamagedUnit >= minUnitsRepairingCastle) {
			return;
		}

		int
			unitGroupCommandId = -1;

		//find a repairer and issue command
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
			const Unit *
				u = aiInterface->getMyUnit(i);
			const RepairCommandType *
				rct = static_cast <const
				RepairCommandType *
				>(u->getType()->getFirstCtOfClass(ccRepair));
			//if(rct) printf("\n\n\n\n^^^^^^^^^^ possible repairer unit [%d - %s] current skill [%d] can reapir damaged unit [%d]\n",u->getId(),u->getType()->getName().c_str(),u->getCurrSkill()->getClass(),rct->isRepairableUnitType(damagedUnit->getType()));

			if (rct != NULL) {
				//printf("\n\n\n\n^^^^^^^^^^ possible excute repairer unit [%d - %s] current skill [%d] can repair damaged unit [%d] Castles hp-ratio = %f\n",u->getId(),u->getType()->getName().c_str(),u->getCurrSkill()->getClass(),rct->isRepairableUnitType(damagedUnit->getType()),damagedUnit->getHpRatio());

				if ((u->getCurrSkill()->getClass() == scStop
					|| u->getCurrSkill()->getClass() == scMove
					|| damagedUnit->getHpRatio() <= minCastleHpRatio)) {
					if ((u->getCurrCommand() == NULL
						|| (u->getCurrCommand()->getCommandType()->
							getClass() != ccBuild
							&& u->getCurrCommand()->getCommandType()->
							getClass() != ccProduce))
						&& rct->isRepairableUnitType(damagedUnit->getType())) {
						//if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
						//printf("\n\n\n\n^^^^^^^^^^ AI execute will repair damaged unit [%d - %s] at pos [%s] cellmapPos [%s] using unit [%d -%s]\n",damagedUnit->getId(),damagedUnit->getType()->getName().c_str(),damagedUnit->getPos().getString().c_str(),damagedUnit->getPosWithCellMapSet().getString().c_str(),u->getId(),u->getType()->getName().c_str());

						/*
							Map *map= aiInterface->getWorld()->getMap();
							Cell *cell = map->getCell(damagedUnit->getPosWithCellMapSet());
							if(cell != NULL) {
							printf("\n\n\n\n^^^^^^^^^^ cell is ok\n");

							Unit *cellUnit = cell->getUnit(damagedUnit->getCurrField());
							if(cellUnit != NULL) {
							printf("\n\n\n\n^^^^^^^^^^ cell unit [%d - %s] at pos [%s]\n",cellUnit->getId(),cellUnit->getType()->getName().c_str(),cellUnit->getPos().getString().c_str());
							}
							}
							*/

							//aiInterface->giveCommand(i, rct, damagedUnit->getPos());
						if (unitCountAlreadyRepairingDamagedUnit <
							minUnitsRepairingCastle) {

							if (unitGroupCommandId == -1) {
								unitGroupCommandId =
									aiInterface->getWorld()->
									getNextCommandGroupId();
							}

							aiInterface->giveCommand(i, rct,
								damagedUnit->
								getPosWithCellMapSet(),
								unitGroupCommandId);
							if (aiInterface->isLogLevelEnabled(3) == true)
								aiInterface->printLog(3,
									"Repairing order issued");
							unitCountAlreadyRepairingDamagedUnit++;
							//                                              printf(
							//                                                      "^^^^^^^^^^adding one unit to repair ... unitCountAlreadyRepairingDamagedUnit/minUnitsRepairingCastle=%d/%d\n",
							//                                                      unitCountAlreadyRepairingDamagedUnit, minUnitsRepairingCastle);
						}

						if (!damagedUnitIsCastle
							|| unitCountAlreadyRepairingDamagedUnit >=
							minUnitsRepairingCastle) {
							return;
						}
					}
				}
			}
		}
	}

	// =====================================================
	//      class AiRuleReturnBase
	// =====================================================

	AiRuleReturnBase::AiRuleReturnBase(Ai * ai) :
		AiRule(ai) {
		stoppedUnitIndex = -1;
	}

	bool
		AiRuleReturnBase::test() {
		return ai->findAbleUnit(&stoppedUnitIndex, ccMove, true);
	}

	void
		AiRuleReturnBase::execute() {
		ai->returnBase(stoppedUnitIndex);
	}

	// =====================================================
	//      class AiRuleMassiveAttack
	// =====================================================

	AiRuleMassiveAttack::AiRuleMassiveAttack(Ai * ai) :
		AiRule(ai) {
		ultraAttack = false;
		field = fLand;
	}

	bool
		AiRuleMassiveAttack::test() {

		if (ai->isStableBase()) {
			ultraAttack = false;
			return ai->beingAttacked(attackPos, field, INT_MAX);
		} else {
			ultraAttack = true;
			return ai->beingAttacked(attackPos, field, baseRadius);
		}
	}

	void
		AiRuleMassiveAttack::execute() {
		ai->massiveAttack(attackPos, field, ultraAttack);
	}
	// =====================================================
	//      class AiRuleAddTasks
	// =====================================================

	AiRuleAddTasks::AiRuleAddTasks(Ai * ai) :
		AiRule(ai) {
	}

	bool
		AiRuleAddTasks::test() {
		return !ai->anyTask() || ai->getCountOfClass(ucWorker) < 4;
	}

	void
		AiRuleAddTasks::execute() {
		/*
		* triggers AI to create new units, differs based on Control Type of AIInterface
		* if ai->outputAIBehaviourToConsole() it will print debug lines to console
		*
		* Attributes:
		*	none
		*
		* Documentation Author: Bennett Dixon
		*/
		int
			buildingCount = ai->getCountOfClass(ucBuilding);
		UnitClass
			ucWorkerType = ucWorker;
		int
			warriorCount = ai->getCountOfClass(ucWarrior, &ucWorkerType);
		int
			workerCount = ai->getCountOfClass(ucWorker);
		int
			upgradeCount = ai->getAiInterface()->getMyUpgradeCount();

		float
			buildingRatio = ai->getRatioOfClass(ucBuilding);
		float
			warriorRatio = ai->getRatioOfClass(ucWarrior);
		float
			workerRatio = ai->getRatioOfClass(ucWorker);

		//standard tasks
		if (ai->outputAIBehaviourToConsole())
			printf
			("Add a TASK - AiRuleAddTasks adding ProduceTask(ucWorker) workerCount = %d, RULE Name[%s]\n",
				workerCount, this->getName().c_str());

		//emergency workers
		if (workerCount < 4) {
			if (ai->outputAIBehaviourToConsole())
				printf
				("AAA AiRuleAddTasks adding ProduceTask(ucWorker) workerCount = %d, RULE Name[%s]\n",
					workerCount, this->getName().c_str());

			ai->addPriorityTask(new ProduceTask(ucWorker));
		}
		// The following rules are specific creation rules for different AI.
		else {
			if (ai->getAiInterface()->getControlType() == ctCpuZeta) {
				if (ai->outputAIBehaviourToConsole())
					printf
					("AAA AiRuleAddTasks adding #1 workerCount = %d[%.2f], buildingCount = %d[%.2f] warriorCount = %d[%.2f] upgradeCount = %d RULE Name[%s]\n",
						workerCount, workerRatio, buildingCount, buildingRatio,
						warriorCount, warriorRatio, upgradeCount,
						this->getName().c_str());

				//workers
				if (workerCount < 5)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerCount < 100)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerRatio < 0.20)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerRatio < 0.30)
					ai->addTask(new ProduceTask(ucWorker));

				//warriors
				if (warriorCount < 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.20)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.30)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 15)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorCount < ai->getMinWarriors() + 2) {
					ai->addTask(new ProduceTask(ucWarrior));
					if (buildingCount > 9) {
						ai->addTask(new ProduceTask(ucWarrior));
						ai->addTask(new ProduceTask(ucWarrior));
					}
					if (buildingCount > 12) {
						ai->addTask(new ProduceTask(ucWarrior));
						ai->addTask(new ProduceTask(ucWarrior));
					}
				}

				//buildings
				if (buildingCount < 6 || buildingRatio < 0.20)
					ai->addTask(new BuildTask((UnitType *) NULL));
				if (buildingCount < 10 && workerCount > 12)
					ai->addTask(new BuildTask((UnitType *) NULL));
				//upgrades
				if (upgradeCount == 0 && workerCount > 5)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 1 && workerCount > 10)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 2 && workerCount > 15)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (ai->isStableBase())
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
			} else if (ai->getAiInterface()->getControlType() == ctCpuEasy) {                   // Easy CPU

				if (ai->outputAIBehaviourToConsole())
					printf
					("AAA AiRuleAddTasks adding #2 workerCount = %d[%.2f], buildingCount = %d[%.2f] warriorCount = %d[%.2f] upgradeCount = %d RULE Name[%s]\n",
						workerCount, workerRatio, buildingCount, buildingRatio,
						warriorCount, warriorRatio, upgradeCount,
						this->getName().c_str());

				//workers
				if (workerCount < buildingCount + 2)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerCount > 5 && workerRatio < 0.20)
					ai->addTask(new ProduceTask(ucWorker));

				//warriors
				if (warriorCount < 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.20)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.30)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 15)
					ai->addTask(new ProduceTask(ucWarrior));

				//buildings
				if (buildingCount < 6 || buildingRatio < 0.20)
					ai->addTask(new BuildTask((UnitType *) NULL));
				if (buildingCount < 10 && ai->isStableBase())
					ai->addTask(new BuildTask((UnitType *) NULL));

				//upgrades
				if (upgradeCount == 0 && workerCount > 6)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 1 && workerCount > 7)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 2 && workerCount > 9)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				//if(ai->isStableBase()) ai->addTask(new UpgradeTask());
			} else {                   // normal CPU / UltraCPU ...
				if (ai->outputAIBehaviourToConsole())
					printf
					("AAA AiRuleAddTasks adding #3 workerCount = %d[%.2f], buildingCount = %d[%.2f] warriorCount = %d[%.2f] upgradeCount = %d RULE Name[%s]\n",
						workerCount, workerRatio, buildingCount, buildingRatio,
						warriorCount, warriorRatio, upgradeCount,
						this->getName().c_str());

				//workers
				if (workerCount < 5)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerCount < 10)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerRatio < 0.20)
					ai->addTask(new ProduceTask(ucWorker));
				if (workerRatio < 0.30)
					ai->addTask(new ProduceTask(ucWorker));

				//warriors
				if (warriorCount < 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.20)
					ai->addTask(new ProduceTask(ucWarrior));
				if (warriorRatio < 0.30)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 10)
					ai->addTask(new ProduceTask(ucWarrior));
				if (workerCount >= 15)
					ai->addTask(new ProduceTask(ucWarrior));

				//buildings
				if (buildingCount < 6 || buildingRatio < 0.20)
					ai->addTask(new BuildTask((UnitType *) NULL));
				if (buildingCount < 10 && workerCount > 12)
					ai->addTask(new BuildTask((UnitType *) NULL));

				//upgrades
				if (upgradeCount == 0 && workerCount > 5)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 1 && workerCount > 10)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (upgradeCount == 2 && workerCount > 15)
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
				if (ai->isStableBase())
					ai->addTask(new UpgradeTask((const UpgradeType *) NULL));
			}
		}
	}

	// =====================================================
	//      class AiRuleBuildOneFarm
	// =====================================================

	AiRuleBuildOneFarm::AiRuleBuildOneFarm(Ai * ai) :
		AiRule(ai) {
		farm = NULL;
	}

	bool
		AiRuleBuildOneFarm::test() {
		AiInterface *
			aiInterface = ai->getAiInterface();

		//for all units
		for (int i = 0;
			i < aiInterface->getMyFactionType()->getUnitTypeCount(); ++i) {
			const UnitType *
				ut = aiInterface->getMyFactionType()->getUnitType(i);

			//for all production commands
			for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
				const CommandType *
					ct = ut->getCommandType(j);
				if (ct->getClass() == ccProduce) {
					const UnitType *
						producedType = static_cast <const
						ProduceCommandType *>(ct)->
						getProducedUnit();

					//for all resources
					for (int k = 0; k < producedType->getCostCount(); ++k) {
						const Resource *
							r = producedType->getCost(k);

						//find a food producer in the farm produced units
						if (r->getAmount() < 0
							&& r->getType()->getClass() == rcConsumable
							&& ai->getCountOfType(ut) == 0) {
							if (aiInterface->reqsOk(ct)
								&& aiInterface->getMyFaction()->
								canCreateUnit(ut, true, true, true) == true) {
								farm = ut;
								//printf("AiRuleBuildOneFarm returning true, RULE Name[%s] ut [%s] producedType [%s]\n",this->getName().c_str(),ut->getName().c_str(),producedType->getName().c_str());

								if (ai->outputAIBehaviourToConsole())
									printf
									("AiRuleBuildOneFarm returning true, RULE Name[%s]\n",
										this->getName().c_str());

								return true;
							}
						}
					}
				}
			}
		}
		return false;
	}

	void
		AiRuleBuildOneFarm::execute() {
		ai->addPriorityTask(new BuildTask(farm));
	}

	// =====================================================
	//      class AiRuleProduceResourceProducer
	// =====================================================

	AiRuleProduceResourceProducer::AiRuleProduceResourceProducer(Ai * ai) :
		AiRule(ai) {
		interval = shortInterval;
		rt = NULL;
		newResourceBehaviour =
			Config::getInstance().getBool("NewResourceBehaviour", "false");;
	}

	bool
		AiRuleProduceResourceProducer::test() {
		//emergency tasks: resource buildings
		AiInterface *
			aiInterface = ai->getAiInterface();

		//consumables first
		for (int i = 0;
			i < aiInterface->getTechTree()->getResourceTypeCount(); ++i) {
			rt = aiInterface->getTechTree()->getResourceType(i);
			const Resource *
				r = aiInterface->getResource(rt);

			if (ai->outputAIBehaviourToConsole())
				printf("CONSUMABLE [%s][%d] Testing AI RULE Name[%s]\n",
					rt->getName().c_str(), r->getBalance(),
					this->getName().c_str());

			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"CONSUMABLE [%s][%d] Testing AI RULE Name[%s]",
					rt->getName().c_str(), r->getBalance(),
					this->getName().c_str());
				aiInterface->printLog(4, szBuf);
			}

			bool
				factionUsesResourceType =
				aiInterface->factionUsesResourceType(aiInterface->
					getMyFactionType(), rt);
			if (factionUsesResourceType == true
				&& rt->getClass() == rcConsumable) {
				// The consumable balance is negative
				if (r->getBalance() < 0) {
					if (newResourceBehaviour == true) {
						interval = shortInterval;
					} else {
						interval = longInterval;
					}

					return true;
				}
				// If the consumable balance is down to 1/3 of what we need
				else {
					if (r->getBalance() * 3 + r->getAmount() < 0) {
						if (newResourceBehaviour == true) {
							interval = shortInterval;
						} else {
							interval = longInterval;
						}

						return true;
					}
				}
			}
		}

		int
			targetStaticResourceCount = minStaticResources;
		if (aiInterface->getMyFactionType()->
			getAIBehaviorStaticOverideValue(aibsvcMinStaticResourceCount) !=
			INT_MAX) {
			targetStaticResourceCount =
				aiInterface->getMyFactionType()->
				getAIBehaviorStaticOverideValue(aibsvcMinStaticResourceCount);
		}

		//statics second
		for (int i = 0;
			i < aiInterface->getTechTree()->getResourceTypeCount(); ++i) {
			rt = aiInterface->getTechTree()->getResourceType(i);
			const Resource *
				r = aiInterface->getResource(rt);

			if (ai->outputAIBehaviourToConsole())
				printf("STATIC [%s][%d] [min %d] Testing AI RULE Name[%s]\n",
					rt->getName().c_str(), r->getAmount(),
					targetStaticResourceCount, this->getName().c_str());
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"STATIC resource check [%s][%d] [min %d] Testing AI RULE Name[%s]",
					rt->getName().c_str(), r->getAmount(),
					targetStaticResourceCount, this->getName().c_str());
				aiInterface->printLog(4, szBuf);
			}

			if (rt->getClass() == rcStatic
				&& r->getAmount() < targetStaticResourceCount) {
				bool
					factionUsesResourceType =
					aiInterface->factionUsesResourceType(aiInterface->
						getMyFactionType(),
						rt);
				if (factionUsesResourceType == true) {
					if (newResourceBehaviour == true)
						interval = shortInterval;
					else
						interval = longInterval;
					return true;
				}
			}
		}

		if (ai->outputAIBehaviourToConsole())
			printf("STATIC returning FALSE\n");
		if (aiInterface->isLogLevelEnabled(4) == true)
			aiInterface->printLog(4, "Static Resource check returning FALSE");

		if (newResourceBehaviour == true)
			interval = longInterval;
		else
			interval = shortInterval;
		return false;
	}

	void
		AiRuleProduceResourceProducer::execute() {
		ai->addPriorityTask(new ProduceTask(rt));
		ai->addTask(new BuildTask(rt));
	}

	// =====================================================
	//      class AiRuleProduce
	// =====================================================

	AiRuleProduce::AiRuleProduce(Ai * ai) :
		AiRule(ai) {
		produceTask = NULL;
		newResourceBehaviour =
			Config::getInstance().getBool("NewResourceBehaviour", "false");
	}

	bool
		AiRuleProduce::test() {
		const Task *
			task = ai->getTask();

		if (task == NULL || task->getClass() != tcProduce) {
			return false;
		}

		produceTask = static_cast <const ProduceTask *>(task);
		return true;
	}

	void
		AiRuleProduce::execute() {
		AiInterface *
			aiInterface = ai->getAiInterface();
		if (produceTask != NULL) {

			if (ai->outputAIBehaviourToConsole())
				printf("AiRuleProduce producing [%s]\n",
				(produceTask->getUnitType() !=
					NULL ? produceTask->getUnitType()->getName(false).
					c_str() : "null"));
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096, "AiRuleProduce producing [%s]",
					(produceTask->getUnitType() !=
						NULL ? produceTask->getUnitType()->getName(false).
						c_str() : "null"));
				aiInterface->printLog(4, szBuf);
			}

			//generic produce task, produce random unit that has the skill or produces the resource
			if (produceTask->getUnitType() == NULL) {
				if (newResourceBehaviour) {
					produceGenericNew(produceTask);
				} else
					produceGeneric(produceTask);
			}

			//specific produce task, produce if possible, retry if not enough resources
			else {
				produceSpecific(produceTask);
			}

			//remove the task
			ai->removeTask(produceTask);
		}
	}

	bool
		AiRuleProduce::canUnitTypeOfferResourceType(const UnitType * ut,
			const ResourceType * rt) {
		bool
			unitTypeOffersResourceType = false;

		AiInterface *
			aiInterface = ai->getAiInterface();

		if (ut != NULL && rt != NULL && aiInterface != NULL
			&& aiInterface->reqsOk(ut)) {
			// Check of the unit 'gives' the resource
			// if the unit produces the resource
			const Resource *
				r = ut->getCost(rt);
			if (r != NULL) {
				if (ai->outputAIBehaviourToConsole())
					printf
					("#2 produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",
						r->getDescription(false).c_str(), r->getAmount(),
						this->getName().c_str());
			}

			if (r != NULL && r->getAmount() < 0) {
				unitTypeOffersResourceType = true;
			} else {
				// for each command check if we produce a unit that handles the resource
				for (int commandIndex = 0;
					commandIndex < ut->getCommandTypeCount(); ++commandIndex) {
					const CommandType *
						ct = ut->getCommandType(commandIndex);

					//if the command is produce
					if (ct->getClass() == ccProduce
						|| ct->getClass() == ccMorph) {
						const UnitType *
							producedUnit = static_cast <const
							UnitType *>(ct->getProduced());

						if (ai->outputAIBehaviourToConsole())
							printf
							("produceGeneric [%p] Testing AI RULE Name[%s]\n",
								rt, this->getName().c_str());

						//if the unit produces the resource
						const Resource *
							r = producedUnit->getCost(rt);
						if (r != NULL) {
							if (ai->outputAIBehaviourToConsole())
								printf
								("produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",
									r->getDescription(false).c_str(),
									r->getAmount(), this->getName().c_str());
						}

						if (r != NULL && r->getAmount() < 0) {
							unitTypeOffersResourceType = true;
							break;
						}
					}
				}
			}
		}

		if (aiInterface != NULL && aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"canUnitTypeOfferResourceType for unit type [%s] for resource type [%s] returned: %d",
				(ut != NULL ? ut->getName(false).c_str() : "n/a"),
				(rt != NULL ? rt->getName(false).c_str() : "n/a"),
				unitTypeOffersResourceType);
			aiInterface->printLog(4, szBuf);
		}

		return unitTypeOffersResourceType;
	}

	bool
		AiRuleProduce::setAIProduceTaskForResourceType(const ProduceTask * pt,
			AiInterface * aiInterface) {
		bool
			taskAdded = false;
		if (aiInterface->getMyFactionType()->
			getAIBehaviorUnits(aibcResourceProducerUnits).size() > 0) {
			const
				std::vector <
				FactionType::PairPUnitTypeInt > &
				unitList =
				aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcResourceProducerUnits);
			for (unsigned int i = 0; i < unitList.size(); ++i) {
				const
					FactionType::PairPUnitTypeInt &
					priorityUnit = unitList[i];
				const UnitType *
					ut = priorityUnit.first;
				if (ai->getCountOfType(ut) < priorityUnit.second &&
					canUnitTypeOfferResourceType(ut,
						pt->getResourceType()) ==
					true
					&& aiInterface->getMyFaction()->
					canCreateUnit(priorityUnit.first, false, true,
						true) == true) {
					ai->addTask(new ProduceTask(priorityUnit.first));
					taskAdded = true;
					break;
				}
			}
		}

		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"setAIProduceTaskForResourceType for resource type [%s] returned: %d",
				pt->getResourceType()->getName(false).c_str(),
				taskAdded);
			aiInterface->printLog(4, szBuf);
		}

		return taskAdded;
	}

	void
		AiRuleProduce::addUnitTypeToCandidates(const UnitType * producedUnit,
			UnitTypes & ableUnits,
			UnitTypesGiveBack &
			ableUnitsGiveBack,
			bool unitCanGiveBackResource) {
		// if the unit is not already on the list
		if (find(ableUnits.begin(), ableUnits.end(), producedUnit) ==
			ableUnits.end()) {
			ableUnits.push_back(producedUnit);
			ableUnitsGiveBack.push_back(unitCanGiveBackResource);

			AiInterface *
				aiInterface = ai->getAiInterface();
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"addUnitTypeToCandidates for unit type [%s] unitCanGiveBackResource = %d",
					producedUnit->getName(false).c_str(),
					unitCanGiveBackResource);
				aiInterface->printLog(4, szBuf);
			}

		}
	}

	void
		AiRuleProduce::produceGenericNew(const ProduceTask * pt) {
		UnitTypes
			ableUnits;
		UnitTypesGiveBack
			ableUnitsGiveBack;

		AiInterface *
			aiInterface = ai->getAiInterface();
		if (pt->getResourceType() != NULL) {
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"****START: produceGeneric for resource type [%s]",
					pt->getResourceType()->getName(false).c_str());
				aiInterface->printLog(4, szBuf);
			}

			if (setAIProduceTaskForResourceType(pt, aiInterface) == true) {
				return;
			}
		} else if (pt->getUnitClass() == ucWorker) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcWorkerUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcWorkerUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, false, true,
							true) == true) {
						ai->addTask(new ProduceTask(priorityUnit.first));
						return;
					}
				}
			}
		} else if (pt->getUnitClass() == ucWarrior) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcWarriorUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcWarriorUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, false, true,
							true) == true) {
						ai->addTask(new ProduceTask(priorityUnit.first));
						return;
					}
				}
			}
		}

		//for each unit, produce it if possible
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
			if (aiInterface->getMyUnit(i)->getCurrCommand() != NULL
				&& aiInterface->getMyUnit(i)->getCurrCommand()->
				getCommandType()->getClass() == ccBuild) {
				//skip this units as it is currently building something
				continue;
			}
			//for each command
			const UnitType *
				ut = aiInterface->getMyUnit(i)->getType();

			//bool produceIt= false;
			for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
				const CommandType *
					ct = ut->getCommandType(j);

				//if the command is produce
				//bool produceIt= false;
				if (ct->getClass() == ccProduce || ct->getClass() == ccMorph) {
					const UnitType *
						producedUnit = static_cast <const
						UnitType *>(ct->getProduced());

					if (ai->outputAIBehaviourToConsole())
						printf("produceGeneric [%p] Testing AI RULE Name[%s]\n",
							pt->getResourceType(),
							this->getName().c_str());

					//if the unit produces the resource
					if (pt->getResourceType() != NULL) {
						const Resource *
							r = producedUnit->getCost(pt->getResourceType());
						if (r != NULL) {
							if (ai->outputAIBehaviourToConsole())
								printf
								("produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",
									r->getDescription(false).c_str(),
									r->getAmount(), this->getName().c_str());
						}

						if (r != NULL && r->getAmount() < 0) {
							if (aiInterface->reqsOk(ct)
								&& aiInterface->reqsOk(producedUnit)) {
								//produceIt= true;
								addUnitTypeToCandidates(producedUnit,
									ableUnits,
									ableUnitsGiveBack,
									false);
							}
						}
					} else {
						//if the unit is from the right class
						if (ai->outputAIBehaviourToConsole())
							printf
							("produceGeneric right class = [%d] Testing AI RULE Name[%s]\n",
								producedUnit->isOfClass(pt->getUnitClass()),
								this->getName().c_str());

						if (producedUnit->isOfClass(pt->getUnitClass())) {
							if (aiInterface->reqsOk(ct)
								&& aiInterface->reqsOk(producedUnit)) {
								//produceIt= true;
								addUnitTypeToCandidates(producedUnit,
									ableUnits,
									ableUnitsGiveBack,
									false);
							}
						}
					}
				}
			}
			// Now check of the unit 'gives' the resource
	// This is likely a unit that it BUILT by another and that is handled by a different AI task type: Build
	//              if(produceIt == false && pt->getResourceType() != NULL) {
	//                      const Resource *r= ut->getCost(pt->getResourceType());
	//                      if(r != NULL) {
	//                              if(ai->outputAIBehaviourToConsole()) printf("#2 produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",r->getDescription(false).c_str(),r->getAmount(), this->getName().c_str());
	//                      }
	//
	//                      if(r != NULL && r->getAmount() < 0) {
	//                              if(aiInterface->reqsOk(ut)){
	//                                      produceIt= true;
	//                                      addUnitTypeToCandidates(ut, ableUnits,ableUnitsGiveBack, true);
	//                              }
	//                      }
	//              }

		}

		//add specific produce task
		if (ableUnits.empty() == false) {

			if (ai->outputAIBehaviourToConsole())
				printf
				("produceGeneric !ableUnits.empty(), ableUnits.size() = [%d] Testing AI RULE Name[%s]\n",
				(int) ableUnits.size(), this->getName().c_str());

			// Now check if we already have at least 2 produce or morph
			// resource based units, if so prefer units that give back the resource
			if (pt->getResourceType() != NULL && ableUnits.size() > 1) {
				//priority for non produced units
				UnitTypes
					newAbleUnits;
				bool
					haveEnoughProducers = true;
				bool
					haveNonProducers = false;
				for (unsigned int i = 0; i < ableUnits.size(); ++i) {
					const UnitType *
						ut = ableUnits[i];
					bool
						givesBack = ableUnitsGiveBack[i];
					if (givesBack == false && ai->getCountOfType(ut) < 2) {
						haveEnoughProducers = false;
					} else if (givesBack == true) {
						haveNonProducers = true;
						newAbleUnits.push_back(ut);
					}

					if (aiInterface->isLogLevelEnabled(4) == true) {
						char
							szBuf[8096] = "";
						snprintf(szBuf, 8096,
							"In produceGeneric for unit type [%s] givesBack: %d count of unit type: %d",
							ut->getName(false).c_str(), givesBack,
							ai->getCountOfType(ut));
						aiInterface->printLog(4, szBuf);
					}

				}

				if (aiInterface->isLogLevelEnabled(4) == true) {
					char
						szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"haveEnoughProducers [%d] haveNonProducers [%d]",
						haveEnoughProducers, haveNonProducers);
					aiInterface->printLog(4, szBuf);

					for (unsigned int i = 0; i < ableUnits.size(); ++i) {
						const UnitType *
							ut = ableUnits[i];
						snprintf(szBuf, 8096, "i: %u unit type [%s]", i,
							ut->getName(false).c_str());
						aiInterface->printLog(4, szBuf);
					}
					for (unsigned int i = 0; i < newAbleUnits.size(); ++i) {
						const UnitType *
							ut = newAbleUnits[i];
						snprintf(szBuf, 8096, "i: %u new unit type [%s]", i,
							ut->getName(false).c_str());
						aiInterface->printLog(4, szBuf);
					}
				}

				if (haveEnoughProducers == true && haveNonProducers == true) {
					ableUnits = newAbleUnits;
				}
			}

			//priority for non produced units
			for (unsigned int i = 0; i < ableUnits.size(); ++i) {
				if (ai->getCountOfType(ableUnits[i]) == 0) {
					if (ai->getRandom()->randRange(0, 1) == 0) {
						if (aiInterface->isLogLevelEnabled(4) == true) {
							char
								szBuf[8096] = "";
							snprintf(szBuf, 8096,
								"In produceGeneric priority adding produce task: %d of "
								SIZE_T_SPECIFIER " for unit type [%s]",
								i, ableUnits.size(),
								ableUnits[i]->getName(false).c_str());
							aiInterface->printLog(4, szBuf);
						}

						ai->addTask(new ProduceTask(ableUnits[i]));
						return;
					}
				}
			}

			//normal case
			int
				randomUnitTypeIndex =
				ai->getRandom()->randRange(0, (int) ableUnits.size() - 1);
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"In produceGeneric randomUnitTypeIndex = %d of "
					SIZE_T_SPECIFIER " equals unit type [%s]",
					randomUnitTypeIndex, ableUnits.size() - 1,
					ableUnits[randomUnitTypeIndex]->getName(false).
					c_str());
				aiInterface->printLog(4, szBuf);
			}

			const UnitType *
				ut = ableUnits[randomUnitTypeIndex];

			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"== END In produceGeneric normal adding produce task for unit type [%s]",
					ut->getName(false).c_str());
				aiInterface->printLog(4, szBuf);
			}

			ai->addTask(new ProduceTask(ut));
		}
	}

	void
		AiRuleProduce::produceGeneric(const ProduceTask * pt) {
		typedef
			vector < const UnitType *>
			UnitTypes;
		UnitTypes
			ableUnits;
		AiInterface *
			aiInterface = ai->getAiInterface();

		if (pt->getResourceType() != NULL) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcResourceProducerUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcResourceProducerUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, false, true,
							true) == true) {
						//if(ai->getRandom()->randRange(0, 1)==0) {
						ai->addTask(new ProduceTask(priorityUnit.first));
						return;
						//}
					}
				}
			}
		} else if (pt->getUnitClass() == ucWorker) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcWorkerUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcWorkerUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, false, true,
							true) == true) {
						//if(ai->getRandom()->randRange(0, 1)==0) {
						ai->addTask(new ProduceTask(priorityUnit.first));
						return;
						//}
					}
				}
			}
		} else if (pt->getUnitClass() == ucWarrior) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcWarriorUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcWarriorUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, false, true,
							true) == true) {
						//if(ai->getRandom()->randRange(0, 1)==0) {
						ai->addTask(new ProduceTask(priorityUnit.first));
						return;
						//}
					}
				}
			}
		}

		//for each unit, produce it if possible
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
			if (aiInterface->getMyUnit(i)->getCurrCommand() != NULL
				&& aiInterface->getMyUnit(i)->getCurrCommand()->
				getCommandType()->getClass() == ccBuild) {
				//skip this units as it is currently building something
				continue;
			}
			//for each command
			const UnitType *
				ut = aiInterface->getMyUnit(i)->getType();
			for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
				const CommandType *
					ct = ut->getCommandType(j);

				//if the command is produce
				if (ct->getClass() == ccProduce || ct->getClass() == ccMorph) {

					const UnitType *
						producedUnit = static_cast <const
						UnitType *>(ct->getProduced());
					bool
						produceIt = false;

					if (ai->outputAIBehaviourToConsole())
						printf("produceGeneric [%p] Testing AI RULE Name[%s]\n",
							pt->getResourceType(),
							this->getName().c_str());

					//if the unit produces the resource
					if (pt->getResourceType() != NULL) {
						const Resource *
							r = producedUnit->getCost(pt->getResourceType());

						if (r != NULL) {
							if (ai->outputAIBehaviourToConsole())
								printf
								("produceGeneric r = [%s][%d] Testing AI RULE Name[%s]\n",
									r->getDescription(false).c_str(),
									r->getAmount(), this->getName().c_str());
						}

						if (r != NULL && r->getAmount() < 0) {
							produceIt = true;
						}
					}

					else {
						//if the unit is from the right class
						if (ai->outputAIBehaviourToConsole())
							printf
							("produceGeneric right class = [%d] Testing AI RULE Name[%s]\n",
								producedUnit->isOfClass(pt->getUnitClass()),
								this->getName().c_str());

						if (producedUnit->isOfClass(pt->getUnitClass())) {
							if (aiInterface->reqsOk(ct)
								&& aiInterface->reqsOk(producedUnit)) {
								produceIt = true;
							}
						}
					}

					if (produceIt) {
						//if the unit is not already on the list
						if (find
						(ableUnits.begin(), ableUnits.end(),
							producedUnit) == ableUnits.end()) {
							ableUnits.push_back(producedUnit);
						}
					}
				}
			}
		}

		//add specific produce task
		if (ableUnits.empty() == false) {

			if (ai->outputAIBehaviourToConsole())
				printf
				("produceGeneric !ableUnits.empty(), ableUnits.size() = [%d] Testing AI RULE Name[%s]\n",
				(int) ableUnits.size(), this->getName().c_str());

			//priority for non produced units
			for (unsigned int i = 0; i < ableUnits.size(); ++i) {
				if (ai->getCountOfType(ableUnits[i]) == 0) {
					if (ai->getRandom()->randRange(0, 1) == 0) {
						ai->addTask(new ProduceTask(ableUnits[i]));
						return;
					}
				}
			}

			//normal case
			ai->
				addTask(new
					ProduceTask(ableUnits
						[ai->getRandom()->
						randRange(0,
						(int) ableUnits.size() - 1)]));
		}
	}

	void
		AiRuleProduce::produceSpecific(const ProduceTask * pt) {

		AiInterface *
			aiInterface = ai->getAiInterface();

		if (ai->outputAIBehaviourToConsole())
			printf
			("produceSpecific aiInterface->reqsOk(pt->getUnitType()) = [%s][%d] Testing AI RULE Name[%s]\n",
				pt->getUnitType()->getName().c_str(),
				aiInterface->reqsOk(pt->getUnitType()),
				this->getName().c_str());
		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"== START produceSpecific aiInterface->reqsOk(pt->getUnitType()) = [%s][%d] Testing AI RULE Name[%s]",
				pt->getUnitType()->getName().c_str(),
				aiInterface->reqsOk(pt->getUnitType()),
				this->getName().c_str());
			aiInterface->printLog(4, szBuf);
		}

		//if unit meets requirements
		if (aiInterface->reqsOk(pt->getUnitType())) {

			const CommandType *
				ctypeForCostCheck = NULL;
			//for each unit
			for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
				//don't use units which are currently building
				if (aiInterface->getMyUnit(i)->getCurrCommand() != NULL
					&& aiInterface->getMyUnit(i)->getCurrCommand()->
					getCommandType()->getClass() == ccBuild) {
					//skip this units as it is currently building something
					continue;
				}
				//for each command
				const UnitType *
					ut = aiInterface->getMyUnit(i)->getType();
				for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
					const CommandType *
						ct = ut->getCommandType(j);

					//if the command is produce
					if (ct->getClass() == ccProduce
						|| ct->getClass() == ccMorph) {
						const UnitType *
							producedUnit = static_cast <const
							UnitType *>(ct->getProduced());

						//if units match
						if (producedUnit == pt->getUnitType()) {

							if (ai->outputAIBehaviourToConsole())
								printf
								("produceSpecific aiInterface->reqsOk(ct) = [%d] Testing AI RULE Name[%s]\n",
									aiInterface->reqsOk(ct),
									this->getName().c_str());

							if (aiInterface->reqsOk(ct)) {
								if (ctypeForCostCheck == NULL
									|| ct->getClass() == ccMorph) {
									if (ctypeForCostCheck != NULL
										&& ct->getClass() == ccMorph) {
										const MorphCommandType *
											mct = dynamic_cast <const
											MorphCommandType *>(ct);
										if (mct == NULL) {
											throw
												game_runtime_error
												("mct == NULL");
										}
										if (mct->
											getIgnoreResourceRequirements() ==
											true) {
											ctypeForCostCheck = ct;
										}
									} else {
										ctypeForCostCheck = ct;
									}
								}
							}
						}
					}
				}
			}

			if (ai->outputAIBehaviourToConsole())
				printf
				("produceSpecific aiInterface->checkCosts(pt->getUnitType()) = [%d] Testing AI RULE Name[%s]\n",
					aiInterface->checkCosts(pt->getUnitType(),
						ctypeForCostCheck),
					this->getName().c_str());
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"produceSpecific aiInterface->checkCosts(pt->getUnitType()) = [%d] Testing AI RULE Name[%s]",
					aiInterface->checkCosts(pt->getUnitType(),
						ctypeForCostCheck),
					this->getName().c_str());
				aiInterface->printLog(4, szBuf);
			}

			//if unit doesnt meet resources retry
			if (aiInterface->
				checkCosts(pt->getUnitType(), ctypeForCostCheck) == false) {
				if (aiInterface->isLogLevelEnabled(4) == true) {
					char
						szBuf[8096] = "";
					snprintf(szBuf, 8096, "Check costs FAILED.");
					aiInterface->printLog(4, szBuf);
				}

				ai->retryTask(pt);
				return;
			}

			//produce specific unit
			vector < int >
				producers;
			// Hold a list of units which can produce or morph
			// then a list of commandtypes for each unit
			map < int,
				vector < const CommandType *> >
				producersDefaultCommandType;
			const CommandType *
				defCt = NULL;

			//for each unit
			for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
				if (aiInterface->getMyUnit(i)->getCurrCommand() != NULL
					&& aiInterface->getMyUnit(i)->getCurrCommand()->
					getCommandType()->getClass() == ccBuild) {
					//skip this units as it is currently building something
					continue;
				}
				//for each command
				const UnitType *
					ut = aiInterface->getMyUnit(i)->getType();
				for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
					const CommandType *
						ct = ut->getCommandType(j);

					//if the command is produce
					if (ct->getClass() == ccProduce
						|| ct->getClass() == ccMorph) {
						const UnitType *
							producedUnit = static_cast <const
							UnitType *>(ct->getProduced());

						//if units match
						if (producedUnit == pt->getUnitType()) {

							if (ai->outputAIBehaviourToConsole())
								printf
								("produceSpecific aiInterface->reqsOk(ct) = [%d] Testing AI RULE Name[%s]\n",
									aiInterface->reqsOk(ct),
									this->getName().c_str());

							if (aiInterface->reqsOk(ct)) {
								//defCt= ct;
								producers.push_back(i);
								producersDefaultCommandType[i].push_back(ct);
							}
						}
					}
				}
			}

			//produce from random producer
			if (producers.empty() == false) {

				if (ai->outputAIBehaviourToConsole())
					printf
					("produceSpecific producers.empty() = [%d] Testing AI RULE Name[%s]\n",
						producers.empty(), this->getName().c_str());
				if (aiInterface->isLogLevelEnabled(4) == true) {
					char
						szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"produceSpecific producers.empty() = [%d] Testing AI RULE Name[%s]",
						producers.empty(), this->getName().c_str());
					aiInterface->printLog(4, szBuf);
				}

				// Narrow down producers list to those who are not busy if possible
				vector < int >
					idle_producers;
				for (unsigned int i = 0; i < producers.size(); ++i) {
					int
						currentProducerIndex = producers[i];
					if (currentProducerIndex >= aiInterface->getMyUnitCount()) {
						char
							szBuf[8096] = "";
						printf
						("In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %u,producers.size() = "
							SIZE_T_SPECIFIER "\n", __FILE__, __FUNCTION__,
							__LINE__, currentProducerIndex,
							aiInterface->getMyUnitCount(), i,
							producers.size());
						snprintf(szBuf, 8096,
							"In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %u, i = %u,producers.size() = "
							SIZE_T_SPECIFIER "", __FILE__,
							__FUNCTION__, __LINE__, currentProducerIndex,
							aiInterface->getMyUnitCount(), i,
							producers.size());
						throw
							game_runtime_error(szBuf);
					}

					const Unit *
						unit = aiInterface->getMyUnit(currentProducerIndex);
					if (unit->anyCommand() == false) {
						idle_producers.push_back(currentProducerIndex);
					}
				}
				if (idle_producers.empty() == false) {
					producers = idle_producers;
				}

				if (aiInterface->getControlType() == ctCpuZeta) {               // zeta cpu trys to balance the commands to the producers
					int
						randomstart =
						ai->getRandom()->randRange(0,
						(int) producers.size() - 1);
					int
						lowestCommandCount = 1000000;
					int
						currentProducerIndex = producers[randomstart];
					int
						bestIndex = -1;
					//int besti=0;
					int
						currentCommandCount = 0;
					for (unsigned int i = randomstart;
						i < producers.size() + randomstart; i++) {
						int
							prIndex = i;
						if (i >= producers.size()) {
							prIndex = (i - (int) producers.size());
						}
						currentProducerIndex = producers[prIndex];

						if (currentProducerIndex >=
							aiInterface->getMyUnitCount()) {
							char
								szBuf[8096] = "";
							printf
							("In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %u,producers.size() = "
								SIZE_T_SPECIFIER "\n", __FILE__, __FUNCTION__,
								__LINE__, currentProducerIndex,
								aiInterface->getMyUnitCount(), i,
								producers.size());
							snprintf(szBuf, 8096,
								"In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %u, i = %u,producers.size() = "
								SIZE_T_SPECIFIER "", __FILE__,
								__FUNCTION__, __LINE__,
								currentProducerIndex,
								aiInterface->getMyUnitCount(), i,
								producers.size());
							throw
								game_runtime_error(szBuf);
						}
						if (prIndex >= (int) producers.size()) {
							char
								szBuf[8096] = "";
							printf
							("In [%s::%s Line: %d] prIndex >= producers.size(), currentProducerIndex = %d, i = %u,producers.size() = "
								SIZE_T_SPECIFIER " \n", __FILE__,
								__FUNCTION__, __LINE__, prIndex, i,
								producers.size());
							snprintf(szBuf, 8096,
								"In [%s::%s Line: %d] currentProducerIndex >= producers.size(), currentProducerIndex = %d, i = %u,producers.size() = "
								SIZE_T_SPECIFIER "", __FILE__,
								__FUNCTION__, __LINE__,
								currentProducerIndex, i,
								producers.size());
							throw
								game_runtime_error(szBuf);
						}

						currentCommandCount =
							aiInterface->getMyUnit(currentProducerIndex)->
							getCommandSize();
						if (currentCommandCount == 1
							&& aiInterface->getMyUnit(currentProducerIndex)->
							getCurrCommand()->getCommandType()->getClass() ==
							ccStop) {       // special for non buildings
							currentCommandCount = 0;
						}
						if (lowestCommandCount > currentCommandCount) {
							lowestCommandCount =
								aiInterface->getMyUnit(currentProducerIndex)->
								getCommandSize();
							bestIndex = currentProducerIndex;
							//besti=i%(producers.size());
						}
					}
					if (bestIndex >= 0) {
						if (aiInterface->getMyUnit(bestIndex)->
							getCommandSize() > 2) {
							// maybe we need another producer of this kind if possible!
							if (aiInterface->
								reqsOk(aiInterface->getMyUnit(bestIndex)->
									getType())) {
								if (ai->getCountOfClass(ucBuilding) > 5) {
									ai->
										addTask(new
											BuildTask(aiInterface->
												getMyUnit
												(bestIndex)->
												getType()));
								}
							}
							// need to calculate another producer, maybe its better to produce another warrior with another producer
							vector < int >
								backupProducers;
							// find another producer unit which is free and produce any kind of warrior.
							//for each unit
							for (int i = 0; i < aiInterface->getMyUnitCount();
								++i) {
								const UnitType *
									ut = aiInterface->getMyUnit(i)->getType();
								//for each command
								for (int j = 0; j < ut->getCommandTypeCount();
									++j) {
									const CommandType *
										ct = ut->getCommandType(j);
									//if the command is produce
									if (ct->getClass() == ccProduce) {
										const UnitType *
											unitType = static_cast <const
											UnitType *>(ct->getProduced());
										if (unitType->hasSkillClass(scAttack)
											&& !unitType->
											hasCommandClass(ccHarvest)
											&& aiInterface->reqsOk(ct)) {       //this can produce a warrior
											backupProducers.push_back(i);
										}
									}
								}
							}
							if (!backupProducers.empty()) {
								int
									randomstart =
									ai->getRandom()->randRange(0,
									(int)
										backupProducers.
										size() - 1);
								int
									lowestCommandCount = 1000000;
								int
									currentProducerIndex =
									backupProducers[randomstart];
								int
									bestIndex = -1;
								for (unsigned int i = randomstart;
									i < backupProducers.size() + randomstart;
									i++) {
									int
										prIndex = i;
									if (i >= backupProducers.size()) {
										prIndex =
											(i - (int) backupProducers.size());
									}

									currentProducerIndex =
										backupProducers[prIndex];

									if (currentProducerIndex >=
										aiInterface->getMyUnitCount()) {
										char
											szBuf[8096] = "";
										printf
										("In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %u,backupProducers.size() = "
											SIZE_T_SPECIFIER "\n", __FILE__,
											__FUNCTION__, __LINE__,
											currentProducerIndex,
											aiInterface->getMyUnitCount(), i,
											backupProducers.size());
										snprintf(szBuf, 8096,
											"In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %u,backupProducers.size() = "
											SIZE_T_SPECIFIER "",
											__FILE__, __FUNCTION__,
											__LINE__,
											currentProducerIndex,
											aiInterface->
											getMyUnitCount(), i,
											backupProducers.size());
										throw
											game_runtime_error(szBuf);
									}
									if (prIndex >=
										(int) backupProducers.size()) {
										char
											szBuf[8096] = "";
										printf
										("In [%s::%s Line: %d] prIndex >= backupProducers.size(), currentProducerIndex = %d, i = %u,backupProducers.size() = "
											SIZE_T_SPECIFIER " \n", __FILE__,
											__FUNCTION__, __LINE__, prIndex, i,
											backupProducers.size());
										snprintf(szBuf, 8096,
											"In [%s::%s Line: %d] currentProducerIndex >= backupProducers.size(), currentProducerIndex = %d, i = %u,backupProducers.size() = "
											SIZE_T_SPECIFIER "",
											__FILE__, __FUNCTION__,
											__LINE__,
											currentProducerIndex, i,
											backupProducers.size());
										throw
											game_runtime_error(szBuf);
									}

									int
										currentCommandCount =
										aiInterface->
										getMyUnit(currentProducerIndex)->
										getCommandSize();
									if (currentCommandCount == 1
										&& aiInterface->
										getMyUnit(currentProducerIndex)->
										getCurrCommand()->getCommandType()->
										getClass() == ccStop) {   // special for non buildings
										currentCommandCount = 0;
									}
									if (lowestCommandCount >
										currentCommandCount) {
										lowestCommandCount =
											currentCommandCount;
										bestIndex = currentProducerIndex;
										if (lowestCommandCount == 0)
											break;
									}
								}
								// a good producer is found, lets choose a warrior production
								vector < int >
									productionCommandIndexes;
								if (bestIndex >= 0) {
									const UnitType *
										ut =
										aiInterface->getMyUnit(bestIndex)->
										getType();
									for (int j = 0;
										j < ut->getCommandTypeCount(); ++j) {
										const CommandType *
											ct = ut->getCommandType(j);

										//if the command is produce
										if (ct->getClass() == ccProduce) {
											const UnitType *
												unitType = static_cast <const
												UnitType *>(ct->getProduced());
											if (unitType->
												hasSkillClass(scAttack)
												&& !unitType->
												hasCommandClass(ccHarvest)
												&& aiInterface->reqsOk(ct)) {   //this can produce a warrior
												productionCommandIndexes.
													push_back(j);
											}
										}
									}

									int
										commandIndex =
										productionCommandIndexes[ai->
										getRandom()->
										randRange(0,
										(int)
											productionCommandIndexes.
											size
											() -
											1)];
									if (SystemFlags::
										getSystemSettingType(SystemFlags::
											debugSystem).
										enabled)
										SystemFlags::OutputDebug(SystemFlags::
											debugSystem,
											"In [%s::%s Line: %d]\n",
											__FILE__,
											__FUNCTION__,
											__LINE__);

									if (ai->outputAIBehaviourToConsole())
										printf
										("zeta #1 produceSpecific giveCommand to unit [%s] commandType [%s]\n",
											aiInterface->getMyUnit(bestIndex)->
											getType()->getName().c_str(),
											ut->getCommandType(commandIndex)->
											getName().c_str());
									if (aiInterface->isLogLevelEnabled(4) ==
										true) {
										char
											szBuf[8096] = "";
										snprintf(szBuf, 8096,
											"zeta #1 produceSpecific giveCommand to unit [%s] commandType [%s]",
											aiInterface->
											getMyUnit(bestIndex)->
											getType()->getName().
											c_str(),
											ut->
											getCommandType
											(commandIndex)->getName().
											c_str());
										aiInterface->printLog(4, szBuf);
									}

									aiInterface->giveCommand(bestIndex,
										ut->
										getCommandType
										(commandIndex));
								}
							} else {   // do it like normal CPU
								if (SystemFlags::
									getSystemSettingType(SystemFlags::
										debugSystem).enabled)
									SystemFlags::OutputDebug(SystemFlags::
										debugSystem,
										"In [%s::%s Line: %d]\n",
										__FILE__,
										__FUNCTION__,
										__LINE__);
								defCt = NULL;
								if (producersDefaultCommandType.
									find(bestIndex) !=
									producersDefaultCommandType.end()) {
									int
										bestCommandTypeCount =
										(int)
										producersDefaultCommandType[bestIndex].
										size();
									int
										bestCommandTypeIndex =
										ai->getRandom()->randRange(0,
											bestCommandTypeCount
											- 1);

									if (SystemFlags::
										getSystemSettingType(SystemFlags::
											debugSystem).
										enabled)
										SystemFlags::OutputDebug(SystemFlags::
											debugSystem,
											"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",
											__FILE__,
											__FUNCTION__,
											__LINE__,
											bestCommandTypeIndex,
											bestCommandTypeCount);

									defCt =
										producersDefaultCommandType[bestIndex]
										[bestCommandTypeIndex];
								}

								if (ai->outputAIBehaviourToConsole())
									printf
									("zeta #2 produceSpecific giveCommand to unit [%s] commandType [%s]\n",
										aiInterface->getMyUnit(bestIndex)->
										getType()->getName().c_str(),
										(defCt !=
											NULL ? defCt->getName().
											c_str() : "n/a"));
								if (aiInterface->isLogLevelEnabled(4) == true) {
									char
										szBuf[8096] = "";
									snprintf(szBuf, 8096,
										"zeta #2 produceSpecific giveCommand to unit [%s] commandType [%s]",
										aiInterface->
										getMyUnit(bestIndex)->
										getType()->getName().c_str(),
										(defCt !=
											NULL ? defCt->getName().
											c_str() : "n/a"));
									aiInterface->printLog(4, szBuf);
								}
								if (defCt != NULL)
									aiInterface->giveCommand(bestIndex, defCt);
							}
						} else {
							if (currentCommandCount == 0) {
								if (SystemFlags::
									getSystemSettingType(SystemFlags::
										debugSystem).enabled)
									SystemFlags::OutputDebug(SystemFlags::
										debugSystem,
										"In [%s::%s Line: %d]\n",
										__FILE__,
										__FUNCTION__,
										__LINE__);
								defCt = NULL;
								if (producersDefaultCommandType.
									find(bestIndex) !=
									producersDefaultCommandType.end()) {
									//defCt = producersDefaultCommandType[bestIndex];
									int
										bestCommandTypeCount =
										(int)
										producersDefaultCommandType[bestIndex].
										size();
									int
										bestCommandTypeIndex =
										ai->getRandom()->randRange(0,
											bestCommandTypeCount
											- 1);

									if (SystemFlags::
										getSystemSettingType(SystemFlags::
											debugSystem).
										enabled)
										SystemFlags::OutputDebug(SystemFlags::
											debugSystem,
											"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",
											__FILE__,
											__FUNCTION__,
											__LINE__,
											bestCommandTypeIndex,
											bestCommandTypeCount);

									defCt =
										producersDefaultCommandType[bestIndex]
										[bestCommandTypeIndex];
								}

								if (ai->outputAIBehaviourToConsole())
									printf
									("zeta #3 produceSpecific giveCommand to unit [%s] commandType [%s]\n",
										aiInterface->getMyUnit(bestIndex)->
										getType()->getName().c_str(),
										(defCt !=
											NULL ? defCt->getName().
											c_str() : "n/a"));
								if (aiInterface->isLogLevelEnabled(4) == true) {
									char
										szBuf[8096] = "";
									snprintf(szBuf, 8096,
										"zeta #3 produceSpecific giveCommand to unit [%s] commandType [%s]",
										aiInterface->
										getMyUnit(bestIndex)->
										getType()->getName().c_str(),
										(defCt !=
											NULL ? defCt->getName().
											c_str() : "n/a"));
									aiInterface->printLog(4, szBuf);
								}
								if (defCt != NULL)
									aiInterface->giveCommand(bestIndex, defCt);
							}
							if (SystemFlags::
								getSystemSettingType(SystemFlags::debugSystem).
								enabled)
								SystemFlags::OutputDebug(SystemFlags::
									debugSystem,
									"In [%s::%s Line: %d]\n",
									__FILE__, __FUNCTION__,
									__LINE__);
							defCt = NULL;
							if (producersDefaultCommandType.find(bestIndex) !=
								producersDefaultCommandType.end()) {
								//defCt = producersDefaultCommandType[bestIndex];
								int
									bestCommandTypeCount =
									(int) producersDefaultCommandType[bestIndex].
									size();
								int
									bestCommandTypeIndex =
									ai->getRandom()->randRange(0,
										bestCommandTypeCount
										- 1);

								if (SystemFlags::
									getSystemSettingType(SystemFlags::
										debugSystem).enabled)
									SystemFlags::OutputDebug(SystemFlags::
										debugSystem,
										"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",
										__FILE__,
										__FUNCTION__,
										__LINE__,
										bestCommandTypeIndex,
										bestCommandTypeCount);

								defCt =
									producersDefaultCommandType[bestIndex]
									[bestCommandTypeIndex];
							}
							if (ai->outputAIBehaviourToConsole())
								printf
								("zeta #4 produceSpecific giveCommand to unit [%s] commandType [%s]\n",
									aiInterface->getMyUnit(bestIndex)->
									getType()->getName().c_str(),
									(defCt !=
										NULL ? defCt->getName().c_str() : "n/a"));
							if (aiInterface->isLogLevelEnabled(4) == true) {
								char
									szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"zeta #4 produceSpecific giveCommand to unit [%s] commandType [%s]",
									aiInterface->getMyUnit(bestIndex)->
									getType()->getName().c_str(),
									(defCt !=
										NULL ? defCt->getName().
										c_str() : "n/a"));
								aiInterface->printLog(4, szBuf);
							}
							if (defCt != NULL)
								aiInterface->giveCommand(bestIndex, defCt);
						}
					}
				} else {
					int
						pIndex =
						ai->getRandom()->randRange(0,
						(int) producers.size() - 1);
					int
						producerIndex = producers[pIndex];
					defCt = NULL;
					if (producersDefaultCommandType.find(producerIndex) !=
						producersDefaultCommandType.end()) {
						//defCt = producersDefaultCommandType[producerIndex];
						int
							bestCommandTypeCount =
							(int) producersDefaultCommandType[producerIndex].
							size();
						int
							bestCommandTypeIndex =
							ai->getRandom()->randRange(0,
								bestCommandTypeCount -
								1);

						if (SystemFlags::
							getSystemSettingType(SystemFlags::debugSystem).
							enabled)
							SystemFlags::OutputDebug(SystemFlags::debugSystem,
								"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",
								__FILE__, __FUNCTION__,
								__LINE__,
								bestCommandTypeIndex,
								bestCommandTypeCount);

						defCt =
							producersDefaultCommandType[producerIndex]
							[bestCommandTypeIndex];
					}

					if (SystemFlags::
						getSystemSettingType(SystemFlags::debugSystem).enabled)
						SystemFlags::OutputDebug(SystemFlags::debugSystem,
							"In [%s::%s Line: %d] producers.size() = %d, producerIndex = %d, pIndex = %d, producersDefaultCommandType.size() = %d\n",
							__FILE__, __FUNCTION__,
							__LINE__, producers.size(),
							producerIndex, pIndex,
							producersDefaultCommandType.
							size());

					if (ai->outputAIBehaviourToConsole())
						printf
						("produceSpecific giveCommand to unit [%s] commandType [%s]\n",
							aiInterface->getMyUnit(producerIndex)->getType()->
							getName().c_str(),
							(defCt != NULL ? defCt->getName().c_str() : "n/a"));
					if (aiInterface->isLogLevelEnabled(4) == true) {
						char
							szBuf[8096] = "";
						snprintf(szBuf, 8096,
							"produceSpecific giveCommand to unit [%s] commandType [%s]",
							aiInterface->getMyUnit(producerIndex)->
							getType()->getName().c_str(),
							(defCt !=
								NULL ? defCt->getName().
								c_str() : "(null)"));
						aiInterface->printLog(4, szBuf);
					}
					if (defCt != NULL)
						aiInterface->giveCommand(producerIndex, defCt);
				}
			}
		}
	}

	// ========================================
	//      class AiRuleBuild
	// ========================================

	AiRuleBuild::AiRuleBuild(Ai * ai) :
		AiRule(ai) {
		buildTask = NULL;
	}

	bool
		AiRuleBuild::test() {
		const Task *
			task = ai->getTask();

		if (task == NULL || task->getClass() != tcBuild) {
			return false;
		}

		buildTask = static_cast <const BuildTask *>(task);
		return true;
	}


	void
		AiRuleBuild::execute() {
		if (buildTask != NULL) {
			if (ai->outputAIBehaviourToConsole())
				printf("BUILD AiRuleBuild Unit Name[%s]\n",
				(buildTask->getUnitType() !=
					NULL ? buildTask->getUnitType()->getName(false).
					c_str() : "null"));

			//generic build task, build random building that can be built
			if (buildTask->getUnitType() == NULL) {
				buildGeneric(buildTask);
			}
			//specific building task, build if possible, retry if not enough resources or not position
			else {
				buildSpecific(buildTask);
			}

			//remove the task
			ai->removeTask(buildTask);
		}
	}

	void
		AiRuleBuild::buildGeneric(const BuildTask * bt) {

		//find buildings that can be built
		AiInterface *
			aiInterface = ai->getAiInterface();

		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"== START: buildGeneric for resource type [%s]",
				(bt->getResourceType() !=
					NULL ? bt->getResourceType()->getName().
					c_str() : "null"));
			aiInterface->printLog(4, szBuf);
		}

		typedef
			vector < const UnitType *>
			UnitTypes;
		UnitTypes
			buildings;

		if (bt->getResourceType() != NULL) {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcResourceProducerUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcResourceProducerUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, true, false,
							false) == true) {
						//if(ai->getRandom()->randRange(0, 1)==0) {

						if (aiInterface->isLogLevelEnabled(4) == true) {
							char
								szBuf[8096] = "";
							snprintf(szBuf, 8096,
								"In buildGeneric for resource type [%s] aibcResourceProducerUnits = "
								SIZE_T_SPECIFIER
								" priorityUnit.first: [%s]\n",
								bt->getResourceType()->getName().
								c_str(), unitList.size(),
								priorityUnit.first->getName().c_str());
							aiInterface->printLog(4, szBuf);
						}

						ai->addTask(new BuildTask(priorityUnit.first));
						return;
						//}
					}
				}
			}
		} else {
			if (aiInterface->getMyFactionType()->
				getAIBehaviorUnits(aibcBuildingUnits).size() > 0) {
				const
					std::vector <
					FactionType::PairPUnitTypeInt > &
					unitList =
					aiInterface->getMyFactionType()->
					getAIBehaviorUnits(aibcBuildingUnits);
				for (unsigned int i = 0; i < unitList.size(); ++i) {
					const
						FactionType::PairPUnitTypeInt &
						priorityUnit = unitList[i];
					if (ai->getCountOfType(priorityUnit.first) <
						priorityUnit.second
						&& aiInterface->getMyFaction()->
						canCreateUnit(priorityUnit.first, true, false,
							false) == true) {
						//if(ai->getRandom()->randRange(0, 1)==0) {

						if (aiInterface->isLogLevelEnabled(4) == true) {
							char
								szBuf[8096] = "";
							snprintf(szBuf, 8096,
								"In buildGeneric for resource type [%s] aibcBuildingUnits = "
								SIZE_T_SPECIFIER
								" priorityUnit.first: [%s]\n",
								bt->getResourceType()->getName().
								c_str(), unitList.size(),
								priorityUnit.first->getName().c_str());
							aiInterface->printLog(4, szBuf);
						}

						ai->addTask(new BuildTask(priorityUnit.first));
						return;
						//}
					}
				}
			}
		}

		//for each unit
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {

			//for each command
			const UnitType *
				ut = aiInterface->getMyUnit(i)->getType();
			for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
				const CommandType *
					ct = ut->getCommandType(j);

				//if the command is build
				if (ct->getClass() == ccBuild) {
					const BuildCommandType *
						bct = static_cast <const
						BuildCommandType *>(ct);

					//for each building
					for (int k = 0; k < bct->getBuildingCount(); ++k) {
						const UnitType *
							building = bct->getBuilding(k);
						if (aiInterface->reqsOk(bct)
							&& aiInterface->reqsOk(building)) {

							//if any building, or produces resource
							const ResourceType *
								rt = bt->getResourceType();
							const Resource *
								cost = building->getCost(rt);
							if (rt == NULL
								|| (cost != NULL && cost->getAmount() < 0)) {
								if (find
								(buildings.begin(), buildings.end(),
									building) == buildings.end()) {
									buildings.push_back(building);
								}
							}
						}
					}
				}
			}
		}

		if (aiInterface->isLogLevelEnabled(4) == true) {
			for (int i = 0; i < (int) buildings.size(); ++i) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"In buildGeneric i = %d unit type: [%s]\n", i,
					buildings[i]->getName().c_str());
				aiInterface->printLog(4, szBuf);
			}
		}

		//add specific build task
		buildBestBuilding(buildings);
	}

	void
		AiRuleBuild::buildBestBuilding(const vector <
			const UnitType * >&buildings) {

		AiInterface *
			aiInterface = ai->getAiInterface();
		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"==> START buildBestBuilding buildings.size = "
				SIZE_T_SPECIFIER "\n", buildings.size());
			aiInterface->printLog(4, szBuf);
		}

		if (!buildings.empty()) {

			//build the least built building
			bool
				buildingFound = false;
			for (int i = 0; i < 10 && !buildingFound; ++i) {

				if (i > 0) {

					//Defensive buildings have priority
					for (int j = 0;
						j < (int) buildings.size() && buildingFound == false;
						++j) {
						const UnitType *
							building = buildings[j];
						if (ai->getCountOfType(building) <= i + 1
							&& isDefensive(building)) {

							if (aiInterface->isLogLevelEnabled(4) == true) {
								char
									szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"In buildBestBuilding defensive building unit type: [%s] i = %d j = %d\n",
									building->getName().c_str(), i, j);
								aiInterface->printLog(4, szBuf);
							}

							ai->addTask(new BuildTask(building));
							buildingFound = true;
						}
					}

					//Warrior producers next
					for (unsigned int j = 0;
						j < buildings.size() && !buildingFound; ++j) {
						const UnitType *
							building = buildings[j];
						if (ai->getCountOfType(building) <= i + 1
							&& isWarriorProducer(building)) {

							if (aiInterface->isLogLevelEnabled(4) == true) {
								char
									szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"In buildBestBuilding warriorproducer building unit type: [%s] i = %d j = %u\n",
									building->getName().c_str(), i, j);
								aiInterface->printLog(4, szBuf);
							}

							ai->addTask(new BuildTask(building));
							buildingFound = true;
						}
					}

					//Resource producers next
					for (unsigned int j = 0;
						j < buildings.size() && !buildingFound; ++j) {
						const UnitType *
							building = buildings[j];
						if (ai->getCountOfType(building) <= i + 1
							&& isResourceProducer(building)) {

							if (aiInterface->isLogLevelEnabled(4) == true) {
								char
									szBuf[8096] = "";
								snprintf(szBuf, 8096,
									"In buildBestBuilding resourceproducer building unit type: [%s] i = %d j = %u\n",
									building->getName().c_str(), i, j);
								aiInterface->printLog(4, szBuf);
							}

							ai->addTask(new BuildTask(building));
							buildingFound = true;
						}
					}
				}

				//Any building
				for (unsigned int j = 0;
					j < buildings.size() && !buildingFound; ++j) {
					const UnitType *
						building = buildings[j];
					if (ai->getCountOfType(building) <= i) {

						if (aiInterface->isLogLevelEnabled(4) == true) {
							char
								szBuf[8096] = "";
							snprintf(szBuf, 8096,
								"In buildBestBuilding ANY building unit type: [%s] i = %d j = %u\n",
								building->getName().c_str(), i, j);
							aiInterface->printLog(4, szBuf);
						}

						ai->addTask(new BuildTask(building));
						buildingFound = true;
					}
				}
			}
		}

		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"==> END buildBestBuilding buildings.size = "
				SIZE_T_SPECIFIER "\n", buildings.size());
			aiInterface->printLog(4, szBuf);
		}
	}

	void
		AiRuleBuild::buildSpecific(const BuildTask * bt) {
		AiInterface *
			aiInterface = ai->getAiInterface();

		if (aiInterface->isLogLevelEnabled(4) == true) {
			char
				szBuf[8096] = "";
			snprintf(szBuf, 8096,
				"== START: buildSpecific for resource type [%s] bt->getUnitType() [%s]",
				(bt->getResourceType() !=
					NULL ? bt->getResourceType()->getName().
					c_str() : "null"),
					(bt->getUnitType() !=
						NULL ? bt->getUnitType()->getName(false).
						c_str() : "null"));
			aiInterface->printLog(4, szBuf);
		}

		//if reqs ok
		if (aiInterface->reqsOk(bt->getUnitType())) {

			//retry if not enough resources
			if (aiInterface->checkCosts(bt->getUnitType(), NULL) == false) {
				if (aiInterface->isLogLevelEnabled(4) == true) {
					char
						szBuf[8096] = "";
					snprintf(szBuf, 8096,
						"In buildSpecific for resource type [%s] checkcosts == false RETRYING",
						(bt->getResourceType() !=
							NULL ? bt->getResourceType()->getName().
							c_str() : "null"));
					aiInterface->printLog(4, szBuf);
				}

				ai->retryTask(bt);
				return;
			}

			vector < int >
				builders;
			// Hold a list of units which can build
			// then a list of build commandtypes for each unit
			map < int,
				vector < const BuildCommandType *> >
				buildersDefaultCommandType;
			const BuildCommandType *
				defBct = NULL;

			//for each unit
			for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {

				//if the unit is not going to build
				const Unit *
					u = aiInterface->getMyUnit(i);
				if (u->anyCommand() == false
					|| u->getCurrCommand()->getCommandType()->getClass() !=
					ccBuild) {

					//for each command
					const UnitType *
						ut = aiInterface->getMyUnit(i)->getType();
					for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
						const CommandType *
							ct = ut->getCommandType(j);

						//if the command is build
						if (ct->getClass() == ccBuild) {
							const BuildCommandType *
								bct = static_cast <const
								BuildCommandType *>(ct);

							//for each building
							for (int k = 0; k < bct->getBuildingCount(); ++k) {
								const UnitType *
									building = bct->getBuilding(k);

								//if building match
								if (bt->getUnitType() == building) {
									if (aiInterface->reqsOk(bct)) {
										builders.push_back(i);
										buildersDefaultCommandType[i].
											push_back(bct);
										//defBct= bct;
									}
								}
							}
						}
					}
				}
			}

			//use random builder to build
			if (builders.empty() == false) {
				int
					bIndex =
					ai->getRandom()->randRange(0, (int) builders.size() - 1);
				int
					builderIndex = builders[bIndex];
				Vec2i
					pos;
				Vec2i
					searchPos =
					bt->getForcePos() ? bt->getPos() : ai->
					getRandomHomePosition();
				if (bt->getForcePos() == false) {
					const int
						enemySightDistanceToAvoid = 18;
					vector < Unit * >enemies;
					ai->getAiInterface()->getWorld()->getUnitUpdater()->
						findEnemiesForCell(searchPos,
							bt->getUnitType()->getSize(),
							enemySightDistanceToAvoid,
							ai->getAiInterface()->
							getMyFaction(), enemies, true);
					if (enemies.empty() == false) {
						for (int i1 = 0; i1 < 25 && enemies.empty() == false;
							++i1) {
							for (int j1 = 0;
								j1 < 25 && enemies.empty() == false; ++j1) {
								Vec2i
									tryPos = searchPos + Vec2i(i1, j1);

								const int
									spacing = 1;
								if (ai->getAiInterface()->
									isFreeCells(tryPos - Vec2i(spacing),
										bt->getUnitType()->
										getSize() + spacing * 2,
										fLand)) {
									enemies.clear();
									ai->getAiInterface()->getWorld()->
										getUnitUpdater()->
										findEnemiesForCell(tryPos,
											bt->getUnitType()->
											getSize(),
											enemySightDistanceToAvoid,
											ai->
											getAiInterface()->
											getMyFaction(),
											enemies, true);
									if (enemies.empty() == true) {
										searchPos = tryPos;
									}
								}
							}
						}
					}
					if (enemies.empty() == false) {
						for (int i1 = -1;
							i1 >= -25 && enemies.empty() == false; --i1) {
							for (int j1 = -1;
								j1 >= -25 && enemies.empty() == false; --j1) {
								Vec2i
									tryPos = searchPos + Vec2i(i1, j1);

								const int
									spacing = 1;
								if (ai->getAiInterface()->
									isFreeCells(tryPos - Vec2i(spacing),
										bt->getUnitType()->
										getSize() + spacing * 2,
										fLand)) {
									enemies.clear();
									ai->getAiInterface()->getWorld()->
										getUnitUpdater()->
										findEnemiesForCell(tryPos,
											bt->getUnitType()->
											getSize(),
											enemySightDistanceToAvoid,
											ai->
											getAiInterface()->
											getMyFaction(),
											enemies, true);
									if (enemies.empty() == true) {
										searchPos = tryPos;
									}
								}
							}
						}
					}
				}

				//if free pos give command, else retry
				if (ai->findPosForBuilding(bt->getUnitType(), searchPos, pos)) {
					defBct = NULL;
					if (buildersDefaultCommandType.find(builderIndex) !=
						buildersDefaultCommandType.end()) {
						//defBct = buildersDefaultCommandType[builderIndex];
						int
							bestCommandTypeCount =
							(int) buildersDefaultCommandType[builderIndex].
							size();
						int
							bestCommandTypeIndex =
							ai->getRandom()->randRange(0,
								bestCommandTypeCount -
								1);

						if (SystemFlags::
							getSystemSettingType(SystemFlags::debugSystem).
							enabled)
							SystemFlags::OutputDebug(SystemFlags::debugSystem,
								"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",
								__FILE__, __FUNCTION__,
								__LINE__,
								bestCommandTypeIndex,
								bestCommandTypeCount);

						defBct =
							buildersDefaultCommandType[builderIndex]
							[bestCommandTypeIndex];
					}
					if (SystemFlags::
						getSystemSettingType(SystemFlags::debugSystem).enabled)
						SystemFlags::OutputDebug(SystemFlags::debugSystem,
							"In [%s::%s Line: %d] builderIndex = %d, bIndex = %d, defBct = %p\n",
							__FILE__, __FUNCTION__,
							__LINE__, builderIndex, bIndex,
							defBct);

					aiInterface->giveCommand(builderIndex, defBct, pos,
						bt->getUnitType());
				} else {
					ai->retryTask(bt);
					return;
				}
			}
		} else {
			if (aiInterface->isLogLevelEnabled(4) == true) {
				char
					szBuf[8096] = "";
				snprintf(szBuf, 8096,
					"In buildSpecific for resource type [%s] reqsok == false",
					(bt->getResourceType() !=
						NULL ? bt->getResourceType()->getName().
						c_str() : "null"));
				aiInterface->printLog(4, szBuf);
			}

		}
	}

	bool
		AiRuleBuild::isDefensive(const UnitType * building) {
		if (ai->outputAIBehaviourToConsole())
			printf("BUILD isDefensive check for Unit Name[%s] result = %d\n",
				building->getName(false).c_str(),
				building->hasSkillClass(scAttack));

		return building->hasSkillClass(scAttack);
	}

	bool
		AiRuleBuild::isResourceProducer(const UnitType * building) {
		for (int i = 0; i < building->getCostCount(); i++) {
			if (building->getCost(i)->getAmount() < 0) {
				if (ai->outputAIBehaviourToConsole())
					printf
					("BUILD isResourceProducer check for Unit Name[%s] result = true\n",
						building->getName(false).c_str());

				return true;
			}
		}
		if (ai->outputAIBehaviourToConsole())
			printf
			("BUILD isResourceProducer check for Unit Name[%s] result = false\n",
				building->getName(false).c_str());

		return false;
	}

	bool
		AiRuleBuild::isWarriorProducer(const UnitType * building) {
		for (int i = 0; i < building->getCommandTypeCount(); i++) {
			const CommandType *
				ct = building->getCommandType(i);
			if (ct->getClass() == ccProduce) {
				const UnitType *
					ut = static_cast <const
					ProduceCommandType *>(ct)->
					getProducedUnit();

				if (ut->isOfClass(ucWarrior)) {
					if (ai->outputAIBehaviourToConsole())
						printf
						("BUILD isWarriorProducer check for Unit Name[%s] result = true\n",
							building->getName(false).c_str());

					return true;
				}
			}
		}
		if (ai->outputAIBehaviourToConsole())
			printf
			("BUILD isWarriorProducer check for Unit Name[%s] result = false\n",
				building->getName(false).c_str());

		return false;
	}

	// ========================================
	//      class AiRuleUpgrade
	// ========================================

	AiRuleUpgrade::AiRuleUpgrade(Ai * ai) :
		AiRule(ai) {
		upgradeTask = NULL;
	}

	bool
		AiRuleUpgrade::test() {
		const Task *
			task = ai->getTask();

		if (task == NULL || task->getClass() != tcUpgrade) {
			return false;
		}

		upgradeTask = static_cast <const UpgradeTask *>(task);
		return true;
	}

	void
		AiRuleUpgrade::execute() {

		//upgrade any upgrade
		if (upgradeTask->getUpgradeType() == NULL) {
			upgradeGeneric(upgradeTask);
		}
		//upgrade specific upgrade
		else {
			upgradeSpecific(upgradeTask);
		}

		//remove the task
		ai->removeTask(upgradeTask);
	}

	void
		AiRuleUpgrade::upgradeGeneric(const UpgradeTask * upgt) {

		typedef
			vector < const UpgradeType *>
			UpgradeTypes;
		AiInterface *
			aiInterface = ai->getAiInterface();

		//find upgrades that can be upgraded
		UpgradeTypes
			upgrades;

		if (aiInterface->getMyFactionType()->getAIBehaviorUpgrades().size() >
			0) {
			const
				std::vector < const UpgradeType *>&
				upgradeList =
				aiInterface->getMyFactionType()->getAIBehaviorUpgrades();
			for (unsigned int i = 0; i < upgradeList.size(); ++i) {
				const UpgradeType *
					priorityUpgrade = upgradeList[i];

				//for each upgrade, upgrade it if possible
				for (int k = 0; k < aiInterface->getMyUnitCount(); ++k) {

					//for each command
					const UnitType *
						ut = aiInterface->getMyUnit(k)->getType();
					for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
						const CommandType *
							ct = ut->getCommandType(j);

						//if the command is upgrade
						if (ct->getClass() == ccUpgrade) {
							const UpgradeCommandType *
								upgct = dynamic_cast <const
								UpgradeCommandType *>(ct);
							if (upgct != NULL) {
								const UpgradeType *
									upgrade = upgct->getProducedUpgrade();
								if (upgrade == priorityUpgrade) {
									if (aiInterface->reqsOk(upgct) == true &&
										aiInterface->getMyFaction()->
										getUpgradeManager()->
										isUpgradingOrUpgraded(priorityUpgrade)
										== false) {
										//if(ai->getRandom()->randRange(0, 1)==0) {
										ai->
											addTask(new
												UpgradeTask
												(priorityUpgrade));
										return;
										//}
									}
								}
							}
						}
					}
				}
			}
		}

		//for each upgrade, upgrade it if possible
		for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {

			//for each command
			const UnitType *
				ut = aiInterface->getMyUnit(i)->getType();
			for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
				const CommandType *
					ct = ut->getCommandType(j);

				//if the command is upgrade
				if (ct->getClass() == ccUpgrade) {
					const UpgradeCommandType *
						upgct = static_cast <const
						UpgradeCommandType *>(ct);
					const UpgradeType *
						upgrade = upgct->getProducedUpgrade();
					if (aiInterface->reqsOk(upgct)) {
						upgrades.push_back(upgrade);
					}
				}
			}
		}

		//add specific upgrade task
		if (!upgrades.empty()) {
			ai->
				addTask(new
					UpgradeTask(upgrades
						[ai->getRandom()->
						randRange(0,
						(int) upgrades.size() - 1)]));
		}
	}

	void
		AiRuleUpgrade::upgradeSpecific(const UpgradeTask * upgt) {

		AiInterface *
			aiInterface = ai->getAiInterface();

		//if reqs ok
		if (aiInterface->reqsOk(upgt->getUpgradeType())) {

			//if resources dont meet retry
			if (!aiInterface->checkCosts(upgt->getUpgradeType(), NULL)) {
				ai->retryTask(upgt);
				return;
			}

			//for each unit
			for (int i = 0; i < aiInterface->getMyUnitCount(); ++i) {

				//for each command
				const UnitType *
					ut = aiInterface->getMyUnit(i)->getType();
				for (int j = 0; j < ut->getCommandTypeCount(); ++j) {
					const CommandType *
						ct = ut->getCommandType(j);

					//if the command is upgrade
					if (ct->getClass() == ccUpgrade) {
						const UpgradeCommandType *
							uct = static_cast <const
							UpgradeCommandType *>(ct);
						const UpgradeType *
							producedUpgrade = uct->getProducedUpgrade();

						//if upgrades match
						if (producedUpgrade == upgt->getUpgradeType()) {
							if (aiInterface->reqsOk(uct)) {
								if (SystemFlags::
									getSystemSettingType(SystemFlags::
										debugSystem).enabled)
									SystemFlags::OutputDebug(SystemFlags::
										debugSystem,
										"In [%s::%s Line: %d]\n",
										__FILE__,
										__FUNCTION__,
										__LINE__);
								aiInterface->giveCommand(i, uct);
							}
						}
					}
				}
			}

		}
	}

	// ========================================
	//      class AiRuleExpand
	// ========================================

	AiRuleExpand::AiRuleExpand(Ai * ai) :
		AiRule(ai) {
		storeType = NULL;
	}

	bool
		AiRuleExpand::test() {
		AiInterface *
			aiInterface = ai->getAiInterface();

		int
			unitCount = aiInterface->getMyUnitCount();
		for (int i = 0;
			i < aiInterface->getTechTree()->getResourceTypeCount(); ++i) {
			const ResourceType *
				rt = aiInterface->getTechTree()->getResourceType(i);
			if (rt->getClass() == rcTech) {
				bool
					factionUsesResourceType =
					aiInterface->factionUsesResourceType(aiInterface->
						getMyFactionType(),
						rt);
				if (factionUsesResourceType == true) {
					// If any resource sighted
					if (aiInterface->
						getNearestSightedResource(rt,
							aiInterface->
							getHomeLocation(),
							expandPos, true)) {
						int
							minDistance = INT_MAX;
						storeType = NULL;

						//If there is no close store
						for (int j = 0; j < unitCount; ++j) {
							const Unit *
								u = aiInterface->getMyUnit(j);
							const UnitType *
								ut = u->getType();

							// If this building is a store
							if (ut->getStore(rt) > 0) {
								storeType = ut;
								int
									distance =
									static_cast <
									int>(u->getPosNotThreadSafe().
										dist(expandPos));
								if (distance < minDistance) {
									minDistance = distance;
								}
							}
						}

						if (minDistance > expandDistance) {
							return true;
						}
					} else {
						// send patrol to look for resource
						ai->sendScoutPatrol();
					}
				}
			}
		}

		return false;
	}

	void
		AiRuleExpand::execute() {
		ai->addExpansion(expandPos);
		ai->addPriorityTask(new BuildTask(storeType, expandPos));
	}


	// ========================================
	//      class AiRuleUnBlock
	// ========================================

	AiRuleUnBlock::AiRuleUnBlock(Ai * ai) :
		AiRule(ai) {

	}

	bool
		AiRuleUnBlock::test() {
		return ai->haveBlockedUnits();
	}

	void
		AiRuleUnBlock::execute() {
		ai->unblockUnits();
	}

} //end namespace
