MegaGlest/source/glest_game/ai/ai.cpp

1321 lines
50 KiB
C++

// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2008 Martiño Figueroa
//
// You can redistribute this code and/or modify it under
// the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version
// ==============================================================
#include "ai.h"
#include "ai_interface.h"
#include "ai_rule.h"
#include "unit_type.h"
#include "unit.h"
#include "map.h"
#include "faction_type.h"
#include "leak_dumper.h"
using namespace Shared::Graphics;
using namespace Shared::Util;
namespace Glest { namespace Game {
Task::Task() {
taskClass = tcProduce;
}
//void Task::saveGame(XmlNode *rootNode) const {
// std::map<string,string> mapTagReplacements;
// XmlNode *taskNode = rootNode->addChild("Task");
//}
// =====================================================
// class ProduceTask
// =====================================================
ProduceTask::ProduceTask() : Task() {
taskClass= tcProduce;
unitType= NULL;
resourceType= NULL;
unitClass = ucWarrior;
}
ProduceTask::ProduceTask(UnitClass unitClass) : Task() {
taskClass= tcProduce;
this->unitClass= unitClass;
unitType= NULL;
resourceType= NULL;
}
ProduceTask::ProduceTask(const UnitType *unitType) : Task() {
taskClass= tcProduce;
this->unitType= unitType;
resourceType= NULL;
unitClass = ucWarrior;
}
ProduceTask::ProduceTask(const ResourceType *resourceType) : Task() {
taskClass= tcProduce;
unitType= NULL;
unitClass = ucWarrior;
this->resourceType= resourceType;
}
string ProduceTask::toString() const{
string str= "Produce ";
if(unitType!=NULL){
str+= unitType->getName(false);
}
return str;
}
void ProduceTask::saveGame(XmlNode *rootNode) const {
std::map<string,string> mapTagReplacements;
XmlNode *taskNode = rootNode->addChild("Task");
taskNode->addAttribute("taskClass",intToStr(taskClass), mapTagReplacements);
XmlNode *produceTaskNode = taskNode->addChild("ProduceTask");
// UnitClass unitClass;
produceTaskNode->addAttribute("unitClass",intToStr(unitClass), mapTagReplacements);
// const UnitType *unitType;
if(unitType != NULL) {
produceTaskNode->addAttribute("unitType",unitType->getName(false), mapTagReplacements);
}
// const ResourceType *resourceType;
if(resourceType != NULL) {
produceTaskNode->addAttribute("resourceType",resourceType->getName(false), mapTagReplacements);
}
}
ProduceTask * ProduceTask::loadGame(const XmlNode *rootNode, Faction *faction) {
const XmlNode *produceTaskNode = rootNode->getChild("ProduceTask");
ProduceTask *newTask = new ProduceTask();
// UnitClass unitClass;
newTask->unitClass = static_cast<UnitClass>(produceTaskNode->getAttribute("unitClass")->getIntValue());
// const UnitType *unitType;
if(produceTaskNode->hasAttribute("unitType")) {
string unitTypeName = produceTaskNode->getAttribute("unitType")->getValue();
newTask->unitType = faction->getType()->getUnitType(unitTypeName);
}
// const ResourceType *resourceType;
if(produceTaskNode->hasAttribute("resourceType")) {
string resourceTypeName = produceTaskNode->getAttribute("resourceType")->getValue();
newTask->resourceType = faction->getTechTree()->getResourceType(resourceTypeName);
}
return newTask;
}
// =====================================================
// class BuildTask
// =====================================================
BuildTask::BuildTask() {
taskClass= tcBuild;
this->unitType= NULL;
resourceType= NULL;
forcePos= false;
}
BuildTask::BuildTask(const UnitType *unitType){
taskClass= tcBuild;
this->unitType= unitType;
resourceType= NULL;
forcePos= false;
}
BuildTask::BuildTask(const ResourceType *resourceType){
taskClass= tcBuild;
unitType= NULL;
this->resourceType= resourceType;
forcePos= false;
}
BuildTask::BuildTask(const UnitType *unitType, const Vec2i &pos){
taskClass= tcBuild;
this->unitType= unitType;
resourceType= NULL;
forcePos= true;
this->pos= pos;
}
string BuildTask::toString() const{
string str= "Build ";
if(unitType!=NULL){
str+= unitType->getName(false);
}
return str;
}
void BuildTask::saveGame(XmlNode *rootNode) const {
std::map<string,string> mapTagReplacements;
XmlNode *taskNode = rootNode->addChild("Task");
taskNode->addAttribute("taskClass",intToStr(taskClass), mapTagReplacements);
XmlNode *buildTaskNode = taskNode->addChild("BuildTask");
// const UnitType *unitType;
if(unitType != NULL) {
buildTaskNode->addAttribute("unitType",unitType->getName(false), mapTagReplacements);
}
// const ResourceType *resourceType;
if(resourceType != NULL) {
buildTaskNode->addAttribute("resourceType",resourceType->getName(), mapTagReplacements);
}
// bool forcePos;
buildTaskNode->addAttribute("forcePos",intToStr(forcePos), mapTagReplacements);
// Vec2i pos;
buildTaskNode->addAttribute("pos",pos.getString(), mapTagReplacements);
}
BuildTask * BuildTask::loadGame(const XmlNode *rootNode, Faction *faction) {
const XmlNode *buildTaskNode = rootNode->getChild("BuildTask");
BuildTask *newTask = new BuildTask();
if(buildTaskNode->hasAttribute("unitType")) {
string unitTypeName = buildTaskNode->getAttribute("unitType")->getValue();
newTask->unitType = faction->getType()->getUnitType(unitTypeName);
}
if(buildTaskNode->hasAttribute("resourceType")) {
string resourceTypeName = buildTaskNode->getAttribute("resourceType")->getValue();
newTask->resourceType = faction->getTechTree()->getResourceType(resourceTypeName);
}
newTask->forcePos = buildTaskNode->getAttribute("forcePos")->getIntValue() != 0;
newTask->pos = Vec2i::strToVec2(buildTaskNode->getAttribute("pos")->getValue());
return newTask;
}
// =====================================================
// class UpgradeTask
// =====================================================
UpgradeTask::UpgradeTask() {
taskClass= tcUpgrade;
this->upgradeType= NULL;
}
UpgradeTask::UpgradeTask(const UpgradeType *upgradeType){
taskClass= tcUpgrade;
this->upgradeType= upgradeType;
}
string UpgradeTask::toString() const{
string str= "Build ";
if(upgradeType!=NULL){
str+= upgradeType->getName();
}
return str;
}
void UpgradeTask::saveGame(XmlNode *rootNode) const {
std::map<string,string> mapTagReplacements;
XmlNode *taskNode = rootNode->addChild("Task");
taskNode->addAttribute("taskClass",intToStr(taskClass), mapTagReplacements);
XmlNode *upgradeTaskNode = taskNode->addChild("UpgradeTask");
if(upgradeType != NULL) {
//upgradeType->saveGame(upgradeTaskNode);
upgradeTaskNode->addAttribute("upgradeType",upgradeType->getName(), mapTagReplacements);
}
}
UpgradeTask * UpgradeTask::loadGame(const XmlNode *rootNode, Faction *faction) {
const XmlNode *upgradeTaskNode = rootNode->getChild("UpgradeTask");
UpgradeTask *newTask = new UpgradeTask();
if(upgradeTaskNode->hasAttribute("upgradeType")) {
string upgradeTypeName = upgradeTaskNode->getAttribute("upgradeType")->getValue();
newTask->upgradeType = faction->getType()->getUpgradeType(upgradeTypeName);
}
return newTask;
}
// =====================================================
// class Ai
// =====================================================
void Ai::init(AiInterface *aiInterface, int useStartLocation) {
this->aiInterface= aiInterface;
Faction *faction = this->aiInterface->getMyFaction();
if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxBuildRadius) != INT_MAX) {
maxBuildRadius = faction->getAIBehaviorStaticOverideValue(aibsvcMaxBuildRadius);
//printf("Discovered overriden static value for AI, maxBuildRadius = %d\n",maxBuildRadius);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriors) != INT_MAX) {
minMinWarriors = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriors);
//printf("Discovered overriden static value for AI, minMinWarriors = %d\n",minMinWarriors);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuEasy) != INT_MAX) {
minMinWarriorsExpandCpuEasy = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuEasy);
//printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuEasy = %d\n",minMinWarriorsExpandCpuEasy);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuMega) != INT_MAX) {
minMinWarriorsExpandCpuMega = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuMega);
//printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuMega = %d\n",minMinWarriorsExpandCpuMega);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuUltra) != INT_MAX) {
minMinWarriorsExpandCpuUltra = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuUltra);
//printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuUltra = %d\n",minMinWarriorsExpandCpuUltra);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuNormal) != INT_MAX) {
minMinWarriorsExpandCpuNormal = faction->getAIBehaviorStaticOverideValue(aibsvcMinMinWarriorsExpandCpuNormal);
//printf("Discovered overriden static value for AI, minMinWarriorsExpandCpuNormal = %d\n",minMinWarriorsExpandCpuNormal);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxMinWarriors) != INT_MAX) {
maxMinWarriors = faction->getAIBehaviorStaticOverideValue(aibsvcMaxMinWarriors);
//printf("Discovered overriden static value for AI, maxMinWarriors = %d\n",maxMinWarriors);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMaxExpansions) != INT_MAX) {
maxExpansions = faction->getAIBehaviorStaticOverideValue(aibsvcMaxExpansions);
//printf("Discovered overriden static value for AI, maxExpansions = %d\n",maxExpansions);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcVillageRadius) != INT_MAX) {
villageRadius = faction->getAIBehaviorStaticOverideValue(aibsvcVillageRadius);
//printf("Discovered overriden static value for AI, villageRadius = %d\n",villageRadius);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcScoutResourceRange) != INT_MAX) {
scoutResourceRange = faction->getAIBehaviorStaticOverideValue(aibsvcScoutResourceRange);
//printf("Discovered overriden static value for AI, scoutResourceRange = %d\n",scoutResourceRange);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinWorkerAttackersHarvesting) != INT_MAX) {
minWorkerAttackersHarvesting = faction->getAIBehaviorStaticOverideValue(aibsvcMinWorkerAttackersHarvesting);
//printf("Discovered overriden static value for AI, scoutResourceRange = %d\n",scoutResourceRange);
}
if(faction->getAIBehaviorStaticOverideValue(aibsvcMinBuildSpacing) != INT_MAX) {
minBuildSpacing = faction->getAIBehaviorStaticOverideValue(aibsvcMinBuildSpacing);
//printf("Discovered overriden static value for AI, scoutResourceRange = %d\n",scoutResourceRange);
}
if(useStartLocation == -1) {
startLoc = random.randRange(0, aiInterface->getMapMaxPlayers()-1);
}
else {
startLoc = useStartLocation;
}
minWarriors= minMinWarriors;
randomMinWarriorsReached= false;
//add ai rules
aiRules.clear();
aiRules.push_back(new AiRuleWorkerHarvest(this));
aiRules.push_back(new AiRuleRefreshHarvester(this));
aiRules.push_back(new AiRuleScoutPatrol(this));
aiRules.push_back(new AiRuleUnBlock(this));
aiRules.push_back(new AiRuleReturnBase(this));
aiRules.push_back(new AiRuleMassiveAttack(this));
aiRules.push_back(new AiRuleAddTasks(this));
aiRules.push_back(new AiRuleProduceResourceProducer(this));
aiRules.push_back(new AiRuleBuildOneFarm(this));
aiRules.push_back(new AiRuleProduce(this));
aiRules.push_back(new AiRuleBuild(this));
aiRules.push_back(new AiRuleUpgrade(this));
aiRules.push_back(new AiRuleExpand(this));
aiRules.push_back(new AiRuleRepair(this));
aiRules.push_back(new AiRuleRepair(this));
}
Ai::~Ai() {
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
deleteValues(tasks.begin(), tasks.end());
tasks.clear();
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
deleteValues(aiRules.begin(), aiRules.end());
aiRules.clear();
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] deleting AI aiInterface [%p]\n",__FILE__,__FUNCTION__,__LINE__,aiInterface);
aiInterface = NULL;
}
RandomGen* Ai::getRandom() {
// if(Thread::isCurrentThreadMainThread() == false) {
// throw megaglest_runtime_error("Invalid access to AI random from outside main thread current id = " +
// intToStr(Thread::getCurrentThreadId()) + " main = " + intToStr(Thread::getMainThreadId()));
// }
return &random;
}
void Ai::update() {
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(aiInterface->getMyFaction()->getFirstSwitchTeamVote() != NULL) {
const SwitchTeamVote *vote = aiInterface->getMyFaction()->getFirstSwitchTeamVote();
aiInterface->getMyFaction()->setCurrentSwitchTeamVoteFactionIndex(vote->factionIndex);
factionSwitchTeamRequestCount[vote->factionIndex]++;
int factionSwitchTeamRequestCountCurrent = factionSwitchTeamRequestCount[vote->factionIndex];
//int allowJoinTeam = random.randRange(0, 100);
//srand(time(NULL) + aiInterface->getMyFaction()->getIndex());
Chrono seed(true);
srand((unsigned int)seed.getCurTicks() + aiInterface->getMyFaction()->getIndex());
int allowJoinTeam = rand() % 100;
SwitchTeamVote *voteResult = aiInterface->getMyFaction()->getSwitchTeamVote(vote->factionIndex);
voteResult->voted = true;
voteResult->allowSwitchTeam = false;
const GameSettings *settings = aiInterface->getWorld()->getGameSettings();
// If AI player already lost game they cannot vote
if(aiInterface->getWorld()->factionLostGame(aiInterface->getFactionIndex()) == true) {
voteResult->allowSwitchTeam = true;
}
else {
// Can only ask the AI player 2 times max per game
if(factionSwitchTeamRequestCountCurrent <= 2) {
// x% chance the AI will answer yes
if(settings->getAiAcceptSwitchTeamPercentChance() >= 100) {
voteResult->allowSwitchTeam = true;
}
else if(settings->getAiAcceptSwitchTeamPercentChance() <= 0) {
voteResult->allowSwitchTeam = false;
}
else {
voteResult->allowSwitchTeam = (allowJoinTeam >= (100 - settings->getAiAcceptSwitchTeamPercentChance()));
}
}
}
char szBuf[8096]="";
snprintf(szBuf,8096,"AI for faction# %d voted %s [%d] CountCurrent [%d] PercentChance [%d]",aiInterface->getMyFaction()->getIndex(),(voteResult->allowSwitchTeam ? "Yes" : "No"),allowJoinTeam,factionSwitchTeamRequestCountCurrent,settings->getAiAcceptSwitchTeamPercentChance());
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
aiInterface->printLog(3, szBuf);
aiInterface->giveCommandSwitchTeamVote(aiInterface->getMyFaction(),voteResult);
}
//process ai rules
for(unsigned int ruleIdx = 0; ruleIdx < aiRules.size(); ++ruleIdx) {
AiRule *rule = aiRules[ruleIdx];
if(rule == NULL) {
throw megaglest_runtime_error("rule == NULL");
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [ruleIdx = %d]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),ruleIdx);
if((aiInterface->getTimer() % (rule->getTestInterval() * GameConstants::updateFps / 1000)) == 0) {
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [ruleIdx = %d, before rule->test()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),ruleIdx);
//printf("Testing AI Faction # %d RULE Name[%s]\n",aiInterface->getFactionIndex(),rule->getName().c_str());
if(rule->test()) {
if(outputAIBehaviourToConsole()) printf("\n\nYYYYY Executing AI Faction # %d RULE Name[%s]\n\n",aiInterface->getFactionIndex(),rule->getName().c_str());
aiInterface->printLog(3, intToStr(1000 * aiInterface->getTimer() / GameConstants::updateFps) + ": Executing rule: " + rule->getName() + '\n');
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [ruleIdx = %d, before rule->execute() [%s]]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),ruleIdx,rule->getName().c_str());
rule->execute();
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [ruleIdx = %d, after rule->execute() [%s]]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),ruleIdx,rule->getName().c_str());
}
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [END]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
// ==================== state requests ====================
int Ai::getCountOfType(const UnitType *ut){
int count= 0;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
if(ut == aiInterface->getMyUnit(i)->getType()){
count++;
}
}
return count;
}
int Ai::getCountOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount) {
int count= 0;
for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
if(aiInterface->getMyUnit(i)->getType()->isOfClass(uc)) {
// Skip unit if it ALSO contains the exclusion unit class type
if(additionalUnitClassToExcludeFromCount != NULL) {
if(aiInterface->getMyUnit(i)->getType()->isOfClass(*additionalUnitClassToExcludeFromCount)) {
continue;
}
}
++count;
}
}
return count;
}
float Ai::getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount) {
if(aiInterface->getMyUnitCount() == 0) {
return 0;
}
else {
//return static_cast<float>(getCountOfClass(uc,additionalUnitClassToExcludeFromCount)) / aiInterface->getMyUnitCount();
return truncateDecimal<float>(static_cast<float>(getCountOfClass(uc,additionalUnitClassToExcludeFromCount)) / aiInterface->getMyUnitCount(),6);
}
}
const ResourceType *Ai::getNeededResource(int unitIndex) {
int amount = INT_MAX;
const ResourceType *neededResource= NULL;
const TechTree *tt= aiInterface->getTechTree();
const Unit *unit = aiInterface->getMyUnit(unitIndex);
for(int i = 0; i < tt->getResourceTypeCount(); ++i) {
const ResourceType *rt= tt->getResourceType(i);
const Resource *r= aiInterface->getResource(rt);
if( rt->getClass() != rcStatic && rt->getClass() != rcConsumable) {
char szBuf[8096]="";
snprintf(szBuf,8096,"Examining resource [%s] amount [%d] (previous amount [%d]",rt->getName().c_str(),r->getAmount(),amount);
aiInterface->printLog(3, szBuf);
}
if( rt->getClass() != rcStatic && rt->getClass() != rcConsumable &&
r->getAmount() < amount) {
// Only have up to x units going for this resource so we can focus
// on other needed resources for other units
const int maxUnitsToHarvestResource = 5;
vector<int> unitsGettingResource = findUnitsHarvestingResourceType(rt);
if((int)unitsGettingResource.size() <= maxUnitsToHarvestResource) {
// Now MAKE SURE the unit has a harvest command for this resource
// AND that the resource is within eye-sight to avoid units
// standing around doing nothing.
const HarvestCommandType *hct= unit->getType()->getFirstHarvestCommand(rt,unit->getFaction());
Vec2i resPos;
if(hct != NULL && aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), resPos, false)) {
amount= r->getAmount();
neededResource= rt;
}
}
}
}
char szBuf[8096]="";
snprintf(szBuf,8096,"Unit [%d - %s] looking for resources (not static or consumable)",unit->getId(),unit->getType()->getName(false).c_str());
aiInterface->printLog(3, szBuf);
snprintf(szBuf,8096,"[resource type count %d] Needed resource [%s].",tt->getResourceTypeCount(),(neededResource != NULL ? neededResource->getName().c_str() : "<none>"));
aiInterface->printLog(3, szBuf);
return neededResource;
}
bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){
const Unit *enemy = aiInterface->getFirstOnSightEnemyUnit(pos, field, radius);
return (enemy != NULL);
}
bool Ai::isStableBase() {
UnitClass ucWorkerType = ucWorker;
if(getCountOfClass(ucWarrior,&ucWorkerType) > minWarriors) {
char szBuf[8096]="";
snprintf(szBuf,8096,"Base is stable [minWarriors = %d found = %d]",minWarriors,ucWorkerType);
aiInterface->printLog(4, szBuf);
return true;
}
else{
char szBuf[8096]="";
snprintf(szBuf,8096,"Base is NOT stable [minWarriors = %d found = %d]",minWarriors,ucWorkerType);
aiInterface->printLog(4, szBuf);
return false;
}
}
bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, bool idleOnly){
vector<int> units;
*unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const Unit *unit= aiInterface->getMyUnit(i);
if(unit->getType()->isCommandable() && unit->getType()->hasCommandClass(ability)){
if(!idleOnly || !unit->anyCommand() || unit->getCurrCommand()->getCommandType()->getClass()==ccStop){
units.push_back(i);
}
}
}
if(units.empty()){
return false;
}
else{
*unitIndex= units[random.randRange(0, (int)units.size()-1)];
return true;
}
}
vector<int> Ai::findUnitsHarvestingResourceType(const ResourceType *rt) {
vector<int> units;
Map *map= aiInterface->getMap();
for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
const Unit *unit= aiInterface->getMyUnit(i);
if(unit->getType()->isCommandable()) {
if(unit->getType()->hasCommandClass(ccHarvest)) {
if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass() == ccHarvest) {
Command *command= unit->getCurrCommand();
const HarvestCommandType *hct= dynamic_cast<const HarvestCommandType*>(command->getCommandType());
if(hct != NULL) {
const Vec2i unitTargetPos = unit->getTargetPos();
SurfaceCell *sc= map->getSurfaceCell(Map::toSurfCoords(unitTargetPos));
Resource *r= sc->getResource();
if (r != NULL && r->getType() == rt) {
units.push_back(i);
}
}
}
}
else if(unit->getType()->hasCommandClass(ccProduce)) {
if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass() == ccProduce) {
Command *command= unit->getCurrCommand();
const ProduceCommandType *pct= dynamic_cast<const ProduceCommandType*>(command->getCommandType());
if(pct != NULL) {
const UnitType *ut = pct->getProducedUnit();
if(ut != NULL) {
const Resource *r = ut->getCost(rt);
if(r != NULL) {
if (r != NULL && r->getAmount() < 0) {
units.push_back(i);
}
}
}
}
}
}
else if(unit->getType()->hasCommandClass(ccBuild)) {
if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass() == ccBuild) {
Command *command= unit->getCurrCommand();
const BuildCommandType *bct= dynamic_cast<const BuildCommandType*>(command->getCommandType());
if(bct != NULL) {
for(int j = 0; j < bct->getBuildingCount(); ++j) {
const UnitType *ut = bct->getBuilding(j);
if(ut != NULL) {
const Resource *r = ut->getCost(rt);
if(r != NULL) {
if (r != NULL && r->getAmount() < 0) {
units.push_back(i);
break;
}
}
}
}
}
}
}
}
}
return units;
}
//vector<int> Ai::findUnitsDoingCommand(CommandClass currentCommand) {
// vector<int> units;
//
// for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
// const Unit *unit= aiInterface->getMyUnit(i);
// if(unit->getType()->isCommandable() && unit->getType()->hasCommandClass(currentCommand)) {
// if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass() == currentCommand) {
// units.push_back(i);
// }
// }
// }
//
// return units;
//}
bool Ai::findAbleUnit(int *unitIndex, CommandClass ability, CommandClass currentCommand){
vector<int> units;
*unitIndex= -1;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const Unit *unit= aiInterface->getMyUnit(i);
if(unit->getType()->isCommandable() && unit->getType()->hasCommandClass(ability)){
if(unit->anyCommand() && unit->getCurrCommand()->getCommandType()->getClass()==currentCommand){
units.push_back(i);
}
}
}
if(units.empty()){
return false;
}
else{
*unitIndex= units[random.randRange(0, (int)units.size()-1)];
return true;
}
}
bool Ai::findPosForBuilding(const UnitType* building, const Vec2i &searchPos, Vec2i &outPos){
for(int currRadius = 0; currRadius < maxBuildRadius; ++currRadius) {
for(int i=searchPos.x - currRadius; i < searchPos.x + currRadius; ++i) {
for(int j=searchPos.y - currRadius; j < searchPos.y + currRadius; ++j) {
outPos= Vec2i(i, j);
if(aiInterface->isFreeCells(outPos - Vec2i(minBuildSpacing), building->getAiBuildSize() + minBuildSpacing * 2, fLand)) {
int aiBuildSizeDiff= building->getAiBuildSize()- building->getSize();
if( aiBuildSizeDiff>0){
int halfSize=aiBuildSizeDiff/2;
outPos.x+=halfSize;
outPos.y+=halfSize;
}
return true;
}
}
}
}
return false;
}
// ==================== tasks ====================
void Ai::addTask(const Task *task){
tasks.push_back(task);
aiInterface->printLog(2, "Task added: " + task->toString());
}
void Ai::addPriorityTask(const Task *task){
deleteValues(tasks.begin(), tasks.end());
tasks.clear();
tasks.push_back(task);
aiInterface->printLog(2, "Priority Task added: " + task->toString());
}
bool Ai::anyTask(){
return !tasks.empty();
}
const Task *Ai::getTask() const{
if(tasks.empty()){
return NULL;
}
else{
return tasks.front();
}
}
void Ai::removeTask(const Task *task){
aiInterface->printLog(2, "Task removed: " + task->toString());
tasks.remove(task);
delete task;
}
void Ai::retryTask(const Task *task){
tasks.remove(task);
tasks.push_back(task);
}
// ==================== expansions ====================
void Ai::addExpansion(const Vec2i &pos) {
//check if there is a nearby expansion
for(Positions::iterator it = expansionPositions.begin(); it != expansionPositions.end(); ++it) {
if((*it).dist(pos) < villageRadius) {
return;
}
}
//add expansion
expansionPositions.push_front(pos);
//remove expansion if queue is list is full
if((int)expansionPositions.size() > maxExpansions){
expansionPositions.pop_back();
}
}
Vec2i Ai::getRandomHomePosition() {
if(expansionPositions.empty() || random.randRange(0, 1) == 0){
return aiInterface->getHomeLocation();
}
return expansionPositions[random.randRange(0, (int)expansionPositions.size()-1)];
}
// ==================== actions ====================
void Ai::sendScoutPatrol(){
Vec2i pos;
int unit;
bool possibleTargetFound= false;
bool ultraResourceAttack= (aiInterface->getControlType() == ctCpuUltra || aiInterface->getControlType() == ctNetworkCpuUltra)
&& random.randRange(0, 2) == 1;
bool megaResourceAttack=(aiInterface->getControlType() == ctCpuMega || aiInterface->getControlType() == ctNetworkCpuMega)
&& random.randRange(0, 1) == 1;
if(megaResourceAttack || ultraResourceAttack) {
Map *map= aiInterface->getMap();
const TechTree *tt= aiInterface->getTechTree();
const ResourceType *rt= tt->getResourceType(0);
int tryCount= 0;
int height= map->getH();
int width= map->getW();
for(int i= 0; i < tt->getResourceTypeCount(); ++i){
const ResourceType *rt_= tt->getResourceType(i);
//const Resource *r= aiInterface->getResource(rt);
if(rt_->getClass() == rcTech){
rt=rt_;
break;
}
}
//printf("looking for resource %s\n",rt->getName().c_str());
while(possibleTargetFound == false){
tryCount++;
if(tryCount == 4){
//printf("no target found\n");
break;
}
pos= Vec2i(random.randRange(2, width - 2), random.randRange(2, height - 2));
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))){
//printf("is inside map\n");
// find first resource in this area
Vec2i resPos;
if(aiInterface->isResourceInRegion(pos, rt, resPos, scoutResourceRange)){
// found a possible target.
pos= resPos;
//printf("lets try the new target\n");
possibleTargetFound= true;
break;
}
}
//else printf("is outside map\n");
}
}
std::vector<Vec2i> warningEnemyList = aiInterface->getEnemyWarningPositionList();
if( (possibleTargetFound == false) && (warningEnemyList.empty() == false)) {
//for(int i = (int)warningEnemyList.size() - 1; i <= 0; --i) {
//Vec2i &checkPos = warningEnemyList[i];
Vec2i &checkPos = warningEnemyList[0];
if (random.randRange(0, 1) == 1 ) {
pos = checkPos;
possibleTargetFound = true;
warningEnemyList.clear();
} else {
aiInterface->removeEnemyWarningPositionFromList(checkPos);
}
//break;
//}
}
if(possibleTargetFound == false){
startLoc= (startLoc + 1) % aiInterface->getMapMaxPlayers();
pos= aiInterface->getStartLocation(startLoc);
//printf("normal target used\n");
}
if(aiInterface->getHomeLocation() != pos){
if(findAbleUnit(&unit, ccAttack, false)){
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled)
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
aiInterface->giveCommand(unit, ccAttack, pos);
aiInterface->printLog(2, "Scout patrol sent to: " + intToStr(pos.x) + "," + intToStr(pos.y) + "\n");
}
}
}
void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
int producerWarriorCount=0;
int maxProducerWarriors=random.randRange(1,11);
int unitCount = aiInterface->getMyUnitCount();
int unitGroupCommandId = -1;
int attackerWorkersHarvestingCount = 0;
for(int i = 0; i < unitCount; ++i) {
bool isWarrior=false;
bool productionInProgress=false;
const Unit *unit= aiInterface->getMyUnit(i);
const AttackCommandType *act= unit->getType()->getFirstAttackCommand(field);
if( aiInterface->getControlType() == ctCpuMega ||
aiInterface->getControlType() == ctNetworkCpuMega) {
if(producerWarriorCount > maxProducerWarriors) {
if(
unit->getCommandSize()>0 &&
unit->getCurrCommand()->getCommandType()!=NULL && (
unit->getCurrCommand()->getCommandType()->getClass()==ccBuild ||
unit->getCurrCommand()->getCommandType()->getClass()==ccMorph ||
unit->getCurrCommand()->getCommandType()->getClass()==ccProduce
)
) {
productionInProgress=true;
isWarrior=false;
producerWarriorCount++;
}
else {
isWarrior =! unit->getType()->hasCommandClass(ccHarvest);
}
}
else {
isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce);
}
}
else {
isWarrior= !unit->getType()->hasCommandClass(ccHarvest) && !unit->getType()->hasCommandClass(ccProduce);
}
bool alreadyAttacking= (unit->getCurrSkill()->getClass() == scAttack);
bool unitSignalledToAttack = false;
if(alreadyAttacking == false && unit->getType()->hasSkillClass(scAttack) && (aiInterface->getControlType()
== ctCpuUltra || aiInterface->getControlType() == ctCpuMega || aiInterface->getControlType()
== ctNetworkCpuUltra || aiInterface->getControlType() == ctNetworkCpuMega)){
//printf("~~~~~~~~ Unit [%s - %d] checking if unit is being attacked\n",unit->getFullName().c_str(),unit->getId());
std::pair<bool, Unit *> beingAttacked= aiInterface->getWorld()->getUnitUpdater()->unitBeingAttacked(unit);
if(beingAttacked.first == true){
Unit *enemy= beingAttacked.second;
const AttackCommandType *act_forenemy= unit->getType()->getFirstAttackCommand(enemy->getCurrField());
//printf("~~~~~~~~ Unit [%s - %d] attacked by enemy [%s - %d] act_forenemy [%p] enemy->getCurrField() = %d\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId(),act_forenemy,enemy->getCurrField());
if(act_forenemy != NULL){
bool shouldAttack= true;
if(unit->getType()->hasSkillClass(scHarvest)){
shouldAttack= (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false){
attackerWorkersHarvestingCount++;
}
}
if(shouldAttack) {
if(unitGroupCommandId == -1) {
unitGroupCommandId = aiInterface->getWorld()->getNextCommandGroupId();
}
aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos(), unitGroupCommandId);
unitSignalledToAttack= true;
}
}
else{
const AttackStoppedCommandType *asct_forenemy= unit->getType()->getFirstAttackStoppedCommand(
enemy->getCurrField());
//printf("~~~~~~~~ Unit [%s - %d] found enemy [%s - %d] asct_forenemy [%p] enemy->getCurrField() = %d\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId(),asct_forenemy,enemy->getCurrField());
if(asct_forenemy != NULL){
bool shouldAttack= true;
if(unit->getType()->hasSkillClass(scHarvest)){
shouldAttack= (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false){
attackerWorkersHarvestingCount++;
}
}
if(shouldAttack){
// printf("~~~~~~~~ Unit [%s - %d] WILL AttackStoppedCommand [%s - %d]\n", unit->getFullName().c_str(),
// unit->getId(), enemy->getFullName().c_str(), enemy->getId());
if(unitGroupCommandId == -1) {
unitGroupCommandId = aiInterface->getWorld()->getNextCommandGroupId();
}
aiInterface->giveCommand(i, asct_forenemy, beingAttacked.second->getCenteredPos(), unitGroupCommandId);
unitSignalledToAttack= true;
}
}
}
}
}
if(alreadyAttacking == false && act != NULL && (ultraAttack || isWarrior) &&
unitSignalledToAttack == false) {
bool shouldAttack = true;
if(unit->getType()->hasSkillClass(scHarvest)) {
shouldAttack = (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false) {
attackerWorkersHarvestingCount++;
}
}
// Mega CPU does not send ( far away ) units which are currently producing something
if(aiInterface->getControlType() == ctCpuMega || aiInterface->getControlType() == ctNetworkCpuMega){
if(!isWarrior ){
if(!productionInProgress){
shouldAttack= false;
//printf("no attack \n ");
}
}
}
if(shouldAttack) {
if(unitGroupCommandId == -1) {
unitGroupCommandId = aiInterface->getWorld()->getNextCommandGroupId();
}
aiInterface->giveCommand(i, act, pos, unitGroupCommandId);
}
}
}
if( aiInterface->getControlType() == ctCpuEasy ||
aiInterface->getControlType() == ctNetworkCpuEasy) {
minWarriors += minMinWarriorsExpandCpuEasy;
}
else if(aiInterface->getControlType() == ctCpuMega ||
aiInterface->getControlType() == ctNetworkCpuMega) {
minWarriors += minMinWarriorsExpandCpuMega;
if(minWarriors > maxMinWarriors-1 || randomMinWarriorsReached) {
randomMinWarriorsReached=true;
minWarriors=random.randRange(maxMinWarriors-10, maxMinWarriors*2);
}
}
else if(minWarriors < maxMinWarriors) {
if(aiInterface->getControlType() == ctCpuUltra ||
aiInterface->getControlType() == ctNetworkCpuUltra) {
minWarriors += minMinWarriorsExpandCpuUltra;
}
else {
minWarriors+= minMinWarriorsExpandCpuNormal;
}
}
aiInterface->printLog(2, "Massive attack to pos: "+ intToStr(pos.x)+", "+intToStr(pos.y)+"\n");
}
void Ai::returnBase(int unitIndex) {
Vec2i pos;
//std::pair<CommandResult,string> r(crFailUndefined,"");
//aiInterface->getFactionIndex();
pos= Vec2i(
random.randRange(-villageRadius, villageRadius),
random.randRange(-villageRadius, villageRadius)) +
getRandomHomePosition();
if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
//r= aiInterface->giveCommand(unitIndex, ccMove, pos);
aiInterface->giveCommand(unitIndex, ccMove, pos);
//aiInterface->printLog(1, "Order return to base pos:" + intToStr(pos.x)+", "+intToStr(pos.y)+": "+rrToStr(r)+"\n");
}
void Ai::harvest(int unitIndex) {
const ResourceType *rt= getNeededResource(unitIndex);
if(rt != NULL) {
const HarvestCommandType *hct= aiInterface->getMyUnit(unitIndex)->getType()->getFirstHarvestCommand(rt,aiInterface->getMyUnit(unitIndex)->getFaction());
Vec2i resPos;
if(hct != NULL && aiInterface->getNearestSightedResource(rt, aiInterface->getHomeLocation(), resPos, false)) {
resPos= resPos+Vec2i(random.randRange(-2, 2), random.randRange(-2, 2));
aiInterface->giveCommand(unitIndex, hct, resPos, -1);
//aiInterface->printLog(4, "Order harvest pos:" + intToStr(resPos.x)+", "+intToStr(resPos.y)+": "+rrToStr(r)+"\n");
}
}
}
bool Ai::haveBlockedUnits() {
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
int unitCount = aiInterface->getMyUnitCount();
Map *map = aiInterface->getMap();
//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(u->isAlive() && ut->isMobile() && u->getPath() != NULL && (u->getPath()->isBlocked() || u->getPath()->getBlockCount())) {
Vec2i unitPos = u->getPosNotThreadSafe();
//printf("#1 AI found blocked unit [%d - %s]\n",u->getId(),u->getFullName().c_str());
int failureCount = 0;
int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
bool canUnitMoveToCell = map->aproxCanMove(u, unitPos, pos);
if(canUnitMoveToCell == false) {
failureCount++;
}
cellCount++;
}
}
}
}
bool unitImmediatelyBlocked = (failureCount == cellCount);
//printf("#1 unitImmediatelyBlocked = %d, failureCount = %d, cellCount = %d\n",unitImmediatelyBlocked,failureCount,cellCount);
if(unitImmediatelyBlocked) {
//printf("#1 AI unit IS BLOCKED [%d - %s]\n",u->getId(),u->getFullName().c_str());
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
return true;
}
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
return false;
}
bool Ai::getAdjacentUnits(std::map<float, std::map<int, const Unit *> > &signalAdjacentUnits, const Unit *unit) {
//printf("In getAdjacentUnits...\n");
bool result = false;
Map *map = aiInterface->getMap();
Vec2i unitPos = unit->getPosNotThreadSafe();
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
Unit *adjacentUnit = map->getCell(pos)->getUnit(unit->getCurrField());
if(adjacentUnit != NULL && adjacentUnit->getFactionIndex() == unit->getFactionIndex()) {
if(adjacentUnit->getType()->isMobile() && adjacentUnit->getPath() != NULL) {
//signalAdjacentUnits.push_back(adjacentUnit);
float dist = unitPos.dist(adjacentUnit->getPos());
std::map<float, std::map<int, const Unit *> >::iterator iterFind1 = signalAdjacentUnits.find(dist);
if(iterFind1 == signalAdjacentUnits.end()) {
signalAdjacentUnits[dist][adjacentUnit->getId()] = adjacentUnit;
getAdjacentUnits(signalAdjacentUnits, adjacentUnit);
result = true;
}
else {
std::map<int, const Unit *>::iterator iterFind2 = iterFind1->second.find(adjacentUnit->getId());
if(iterFind2 == iterFind1->second.end()) {
signalAdjacentUnits[dist][adjacentUnit->getId()] = adjacentUnit;
getAdjacentUnits(signalAdjacentUnits, adjacentUnit);
result = true;
}
}
}
}
}
}
}
}
return result;
}
void Ai::unblockUnits() {
Chrono chrono;
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start();
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
int unitCount = aiInterface->getMyUnitCount();
Map *map = aiInterface->getMap();
// Find blocked units and move surrounding units out of the way
std::map<float, std::map<int, const Unit *> > signalAdjacentUnits;
for(int idx=0; idx < unitCount; ++idx) {
const Unit *u= aiInterface->getMyUnit(idx);
const UnitType *ut= u->getType();
// If this building is a store
if(u->isAlive() && ut->isMobile() && u->getPath() != NULL && (u->getPath()->isBlocked() || u->getPath()->getBlockCount())) {
Vec2i unitPos = u->getPosNotThreadSafe();
//printf("#2 AI found blocked unit [%d - %s]\n",u->getId(),u->getFullName().c_str());
//int failureCount = 0;
//int cellCount = 0;
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
Vec2i pos = unitPos + Vec2i(i, j);
if(map->isInside(pos) && map->isInsideSurface(map->toSurfCoords(pos))) {
if(pos != unitPos) {
bool canUnitMoveToCell = map->aproxCanMove(u, unitPos, pos);
if(canUnitMoveToCell == false) {
//failureCount++;
getAdjacentUnits(signalAdjacentUnits, u);
}
//cellCount++;
}
}
}
}
//bool unitImmediatelyBlocked = (failureCount == cellCount);
//printf("#2 unitImmediatelyBlocked = %d, failureCount = %d, cellCount = %d, signalAdjacentUnits.size() = %d\n",unitImmediatelyBlocked,failureCount,cellCount,signalAdjacentUnits.size());
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
if(signalAdjacentUnits.empty() == false) {
//printf("#2 AI units ARE BLOCKED about to unblock\n");
int unitGroupCommandId = -1;
for(std::map<float, std::map<int, const Unit *> >::reverse_iterator iterMap = signalAdjacentUnits.rbegin();
iterMap != signalAdjacentUnits.rend(); ++iterMap) {
for(std::map<int, const Unit *>::iterator iterMap2 = iterMap->second.begin();
iterMap2 != iterMap->second.end(); ++iterMap2) {
//int idx = iterMap2->first;
const Unit *adjacentUnit = iterMap2->second;
if(adjacentUnit != NULL && adjacentUnit->getType()->getFirstCtOfClass(ccMove) != NULL) {
const CommandType *ct = adjacentUnit->getType()->getFirstCtOfClass(ccMove);
for(int moveAttempt = 1; moveAttempt <= villageRadius; ++moveAttempt) {
Vec2i pos= Vec2i(
random.randRange(-villageRadius*2, villageRadius*2),
random.randRange(-villageRadius*2, villageRadius*2)) +
adjacentUnit->getPosNotThreadSafe();
bool canUnitMoveToCell = map->aproxCanMove(adjacentUnit, adjacentUnit->getPosNotThreadSafe(), pos);
if(canUnitMoveToCell == true) {
if(ct != NULL) {
if(unitGroupCommandId == -1) {
unitGroupCommandId = aiInterface->getWorld()->getNextCommandGroupId();
}
//std::pair<CommandResult,string> r = aiInterface->giveCommand(adjacentUnit,ct, pos, unitGroupCommandId);
aiInterface->giveCommand(adjacentUnit,ct, pos, unitGroupCommandId);
}
}
}
}
}
}
}
if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took msecs: %lld [START]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis());
}
bool Ai::outputAIBehaviourToConsole() const {
return false;
}
void Ai::saveGame(XmlNode *rootNode) const {
std::map<string,string> mapTagReplacements;
XmlNode *aiNode = rootNode->addChild("Ai");
// AiInterface *aiInterface;
// AiRules aiRules;
// int startLoc;
aiNode->addAttribute("startLoc",intToStr(startLoc), mapTagReplacements);
// bool randomMinWarriorsReached;
aiNode->addAttribute("randomMinWarriorsReached",intToStr(randomMinWarriorsReached), mapTagReplacements);
// Tasks tasks;
for(Tasks::const_iterator it = tasks.begin(); it != tasks.end(); ++it) {
(*it)->saveGame(aiNode);
}
// Positions expansionPositions;
for(Positions::const_iterator it = expansionPositions.begin(); it != expansionPositions.end(); ++it) {
XmlNode *expansionPositionsNode = aiNode->addChild("expansionPositions");
expansionPositionsNode->addAttribute("pos",(*it).getString(), mapTagReplacements);
}
// RandomGen random;
aiNode->addAttribute("random",intToStr(random.getLastNumber()), mapTagReplacements);
// std::map<int,int> factionSwitchTeamRequestCount;
// int maxBuildRadius;
aiNode->addAttribute("maxBuildRadius",intToStr(maxBuildRadius), mapTagReplacements);
// int minMinWarriors;
aiNode->addAttribute("minMinWarriors",intToStr(minMinWarriors), mapTagReplacements);
// int minMinWarriorsExpandCpuEasy;
aiNode->addAttribute("minMinWarriorsExpandCpuEasy",intToStr(minMinWarriorsExpandCpuEasy), mapTagReplacements);
// int minMinWarriorsExpandCpuMega;
aiNode->addAttribute("minMinWarriorsExpandCpuMega",intToStr(minMinWarriorsExpandCpuMega), mapTagReplacements);
// int minMinWarriorsExpandCpuUltra;
aiNode->addAttribute("minMinWarriorsExpandCpuUltra",intToStr(minMinWarriorsExpandCpuUltra), mapTagReplacements);
// int minMinWarriorsExpandCpuNormal;
aiNode->addAttribute("minMinWarriorsExpandCpuNormal",intToStr(minMinWarriorsExpandCpuNormal), mapTagReplacements);
// int maxMinWarriors;
aiNode->addAttribute("maxMinWarriors",intToStr(maxMinWarriors), mapTagReplacements);
// int maxExpansions;
aiNode->addAttribute("maxExpansions",intToStr(maxExpansions), mapTagReplacements);
// int villageRadius;
aiNode->addAttribute("villageRadius",intToStr(villageRadius), mapTagReplacements);
// int scoutResourceRange;
aiNode->addAttribute("scoutResourceRange",intToStr(scoutResourceRange), mapTagReplacements);
// int minWorkerAttackersHarvesting;
aiNode->addAttribute("minWorkerAttackersHarvesting",intToStr(minWorkerAttackersHarvesting), mapTagReplacements);
}
void Ai::loadGame(const XmlNode *rootNode, Faction *faction) {
const XmlNode *aiNode = rootNode->getChild("Ai");
startLoc = aiNode->getAttribute("startLoc")->getIntValue();
randomMinWarriorsReached = aiNode->getAttribute("randomMinWarriorsReached")->getIntValue() != 0;
vector<XmlNode *> taskNodeList = aiNode->getChildList("Task");
for(unsigned int i = 0; i < taskNodeList.size(); ++i) {
XmlNode *taskNode = taskNodeList[i];
TaskClass taskClass = static_cast<TaskClass>(taskNode->getAttribute("taskClass")->getIntValue());
switch(taskClass) {
case tcProduce:
{
ProduceTask *newTask = ProduceTask::loadGame(taskNode, faction);
tasks.push_back(newTask);
}
break;
case tcBuild:
{
BuildTask *newTask = BuildTask::loadGame(taskNode, faction);
tasks.push_back(newTask);
}
break;
case tcUpgrade:
{
UpgradeTask *newTask = UpgradeTask::loadGame(taskNode, faction);
tasks.push_back(newTask);
}
break;
}
}
vector<XmlNode *> expansionPositionsNodeList = aiNode->getChildList("expansionPositions");
for(unsigned int i = 0; i < expansionPositionsNodeList.size(); ++i) {
XmlNode *expansionPositionsNode = expansionPositionsNodeList[i];
Vec2i pos = Vec2i::strToVec2(expansionPositionsNode->getAttribute("pos")->getValue());
expansionPositions.push_back(pos);
}
// RandomGen random;
random.setLastNumber(aiNode->getAttribute("random")->getIntValue());
// std::map<int,int> factionSwitchTeamRequestCount;
// int maxBuildRadius;
maxBuildRadius = aiNode->getAttribute("maxBuildRadius")->getIntValue();
// int minMinWarriors;
minMinWarriors = aiNode->getAttribute("minMinWarriors")->getIntValue();
// int minMinWarriorsExpandCpuEasy;
minMinWarriorsExpandCpuEasy = aiNode->getAttribute("minMinWarriorsExpandCpuEasy")->getIntValue();
// int minMinWarriorsExpandCpuMega;
minMinWarriorsExpandCpuMega = aiNode->getAttribute("minMinWarriorsExpandCpuMega")->getIntValue();
// int minMinWarriorsExpandCpuUltra;
minMinWarriorsExpandCpuUltra = aiNode->getAttribute("minMinWarriorsExpandCpuUltra")->getIntValue();
// int minMinWarriorsExpandCpuNormal;
minMinWarriorsExpandCpuNormal = aiNode->getAttribute("minMinWarriorsExpandCpuNormal")->getIntValue();
// int maxMinWarriors;
maxMinWarriors = aiNode->getAttribute("maxMinWarriors")->getIntValue();
// int maxExpansions;
maxExpansions = aiNode->getAttribute("maxExpansions")->getIntValue();
// int villageRadius;
villageRadius = aiNode->getAttribute("villageRadius")->getIntValue();
// int scoutResourceRange;
scoutResourceRange = aiNode->getAttribute("scoutResourceRange")->getIntValue();
// int minWorkerAttackersHarvesting;
minWorkerAttackersHarvesting = aiNode->getAttribute("minWorkerAttackersHarvesting")->getIntValue();
}
}}//end namespace