MegaGlest/source/glest_game/ai/ai_rule.cpp
Mark Vejvoda 9de151d975 - added more things to try to improve pathfinding (especially for the AI)
AI players should now detect when units are blocked (surrounded by other units from same faction) and tell the other units to move out of the way
2011-02-25 16:32:27 +00:00

1179 lines
37 KiB
C++

// ==============================================================
// This file is part of Glest (www.glest.org)
//
// Copyright (C) 2001-2008 Martio 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_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 Glest{ 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)
{
}
bool AiRuleRepair::test(){
AiInterface *aiInterface= ai->getAiInterface();
//look for a damaged unit
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const Unit *u= aiInterface->getMyUnit(i);
if(u->getHpRatio()<1.f){
damagedUnitIndex= i;
return true;
}
}
return false;
}
void AiRuleRepair::execute() {
AiInterface *aiInterface= ai->getAiInterface();
const Unit *damagedUnit= aiInterface->getMyUnit(damagedUnitIndex);
//find a repairer and issue command
/*
if(damagedUnit != NULL) {
static std::vector<SkillClass> skillClassList;
if(skillClassList.size() == 0) {
skillClassList.push_back(scStop);
skillClassList.push_back(scMove);
}
Faction *faction = aiInterface->getMyFaction();
Unit *repairer = faction->findClosestUnitWithSkillClass( damagedUnit->getPos(),
ccRepair,
skillClassList,
damagedUnit->getType());
if(repairer != NULL) {
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
const RepairCommandType *rct= static_cast<const RepairCommandType *>(repairer->getType()->getFirstCtOfClass(ccRepair));
aiInterface->giveCommand(repairer, rct, damagedUnit->getPos());
aiInterface->printLog(3, "Repairing order issued");
return;
}
}
*/
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!=NULL && (u->getCurrSkill()->getClass()==scStop || u->getCurrSkill()->getClass()==scMove)){
if(rct->isRepairableUnitType(damagedUnit->getType())){
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
aiInterface->giveCommand(i, rct, damagedUnit->getPos());
aiInterface->printLog(3, "Repairing order issued");
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)
{
}
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(){
int buildingCount= ai->getCountOfClass(ucBuilding);
int warriorCount= ai->getCountOfClass(ucWarrior);
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
//emergency workers
if(workerCount<4){
ai->addPriorityTask(new ProduceTask(ucWorker));
}
else{
if( ai->getAiInterface()->getControlType() == ctCpuMega ||
ai->getAiInterface()->getControlType() == ctNetworkCpuMega)
{
//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));
if(warriorCount<ai->minWarriors+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());
if(buildingCount<10 && workerCount>12) ai->addTask(new BuildTask());
//upgrades
if(upgradeCount==0 && workerCount>5) ai->addTask(new UpgradeTask());
if(upgradeCount==1 && workerCount>10) ai->addTask(new UpgradeTask());
if(upgradeCount==2 && workerCount>15) ai->addTask(new UpgradeTask());
if(ai->isStableBase()) ai->addTask(new UpgradeTask());
}
else if(ai->getAiInterface()->getControlType() == ctCpuEasy ||
ai->getAiInterface()->getControlType() == ctNetworkCpuEasy)
{// Easy CPU
//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());
if(buildingCount<10 && ai->isStableBase()) ai->addTask(new BuildTask());
//upgrades
if(upgradeCount==0 && workerCount>6) ai->addTask(new UpgradeTask());
if(upgradeCount==1 && workerCount>7) ai->addTask(new UpgradeTask());
if(upgradeCount==2 && workerCount>9) ai->addTask(new UpgradeTask());
//if(ai->isStableBase()) ai->addTask(new UpgradeTask());
}
else
{// normal CPU / UltraCPU ...
//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());
if(buildingCount<10 && workerCount>12) ai->addTask(new BuildTask());
//upgrades
if(upgradeCount==0 && workerCount>5) ai->addTask(new UpgradeTask());
if(upgradeCount==1 && workerCount>10) ai->addTask(new UpgradeTask());
if(upgradeCount==2 && workerCount>15) ai->addTask(new UpgradeTask());
if(ai->isStableBase()) ai->addTask(new UpgradeTask());
}
}
}
// =====================================================
// class AiRuleBuildOneFarm
// =====================================================
AiRuleBuildOneFarm::AiRuleBuildOneFarm(Ai *ai):
AiRule(ai)
{
}
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){
farm= ut;
return true;
}
}
}
}
}
return false;
}
void AiRuleBuildOneFarm::execute(){
ai->addPriorityTask(new BuildTask(farm));
}
// =====================================================
// class AiRuleProduceResourceProducer
// =====================================================
AiRuleProduceResourceProducer::AiRuleProduceResourceProducer(Ai *ai):
AiRule(ai)
{
interval= shortInterval;
}
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(rt->getClass()==rcConsumable && r->getBalance()<0){
interval= longInterval;
return true;
}
}
//statics second
for(int i=0; i<aiInterface->getTechTree()->getResourceTypeCount(); ++i){
rt= aiInterface->getTechTree()->getResourceType(i);
const Resource *r= aiInterface->getResource(rt);
if(rt->getClass()==rcStatic && r->getAmount()<minStaticResources){
interval= longInterval;
return true;
}
}
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;
}
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(){
if(produceTask!=NULL){
//generic produce task, produce random unit that has the skill or produces the resource
if(produceTask->getUnitType()==NULL){
produceGeneric(produceTask);
}
//specific produce task, produce if possible, retry if not enough resources
else{
produceSpecific(produceTask);
}
//remove the task
ai->removeTask(produceTask);
}
}
void AiRuleProduce::produceGeneric(const ProduceTask *pt){
typedef vector<const UnitType*> UnitTypes;
UnitTypes ableUnits;
AiInterface *aiInterface= ai->getAiInterface();
//for each unit, produce 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 produce
if(ct->getClass()==ccProduce || ct->getClass()==ccMorph){
const UnitType *producedUnit= static_cast<const UnitType*>(ct->getProduced());
bool produceIt= false;
//if the unit produces the resource
if(pt->getResourceType()!=NULL){
const Resource *r= producedUnit->getCost(pt->getResourceType());
if(r!=NULL && r->getAmount()<0){
produceIt= true;
}
}
else{
//if the unit is from the right class
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()){
//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, ableUnits.size()-1)]));
}
}
void AiRuleProduce::produceSpecific(const ProduceTask *pt){
AiInterface *aiInterface= ai->getAiInterface();
//if unit meets requirements
if(aiInterface->reqsOk(pt->getUnitType())){
//if unit doesnt meet resources retry
if(!aiInterface->checkCosts(pt->getUnitType())){
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){
//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(aiInterface->reqsOk(ct)){
defCt= ct;
producers.push_back(i);
producersDefaultCommandType[i].push_back(ct);
}
}
}
}
}
//produce from random producer
if(!producers.empty()){
if( aiInterface->getControlType() == ctCpuMega ||
aiInterface->getControlType() == ctNetworkCpuMega)
{// mega cpu trys to balance the commands to the producers
int randomstart=ai->getRandom()->randRange(0, 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 - producers.size());
}
currentProducerIndex=producers[prIndex];
if(currentProducerIndex >= aiInterface->getMyUnitCount()) {
char szBuf[1024]="";
printf("In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %d,producers.size() = %lu\n",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,aiInterface->getMyUnitCount(),i,(unsigned long)producers.size());
sprintf(szBuf,"In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %d,producers.size() = %lu",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,aiInterface->getMyUnitCount(),i,(unsigned long)producers.size());
throw runtime_error(szBuf);
}
if(prIndex >= producers.size()) {
char szBuf[1024]="";
printf("In [%s::%s Line: %d] prIndex >= producers.size(), currentProducerIndex = %d, i = %d,producers.size() = %lu \n",__FILE__,__FUNCTION__,__LINE__,prIndex,i,(unsigned long)producers.size());
sprintf(szBuf,"In [%s::%s Line: %d] currentProducerIndex >= producers.size(), currentProducerIndex = %d, i = %d,producers.size() = %lu",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,i,(unsigned long)producers.size());
throw 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( 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, backupProducers.size()-1);
int lowestCommandCount=1000000;
int currentProducerIndex=backupProducers[randomstart];
int bestIndex=-1;
int currentCommandCount=0;
for(unsigned int i=randomstart; i<backupProducers.size()+randomstart; i++)
{
int prIndex = i;
if(i >= backupProducers.size()) {
prIndex = (i - backupProducers.size());
}
currentProducerIndex=backupProducers[prIndex];
if(currentProducerIndex >= aiInterface->getMyUnitCount()) {
char szBuf[1024]="";
printf("In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %d,backupProducers.size() = %lu\n",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,aiInterface->getMyUnitCount(),i,(unsigned long)backupProducers.size());
sprintf(szBuf,"In [%s::%s Line: %d] currentProducerIndex >= aiInterface->getMyUnitCount(), currentProducerIndex = %d, aiInterface->getMyUnitCount() = %d, i = %d,backupProducers.size() = %lu",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,aiInterface->getMyUnitCount(),i,(unsigned long)backupProducers.size());
throw runtime_error(szBuf);
}
if(prIndex >= backupProducers.size()) {
char szBuf[1024]="";
printf("In [%s::%s Line: %d] prIndex >= backupProducers.size(), currentProducerIndex = %d, i = %d,backupProducers.size() = %lu \n",__FILE__,__FUNCTION__,__LINE__,prIndex,i,(unsigned long)backupProducers.size());
sprintf(szBuf,"In [%s::%s Line: %d] currentProducerIndex >= backupProducers.size(), currentProducerIndex = %d, i = %d,backupProducers.size() = %lu",__FILE__,__FUNCTION__,__LINE__,currentProducerIndex,i,(unsigned long)backupProducers.size());
throw 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=currentCommandCount;
bestIndex=currentProducerIndex;
if(lowestCommandCount==0) break;
}
}
// a good producer is found, lets choose a warrior production
vector<int> productionCommandIndexes;
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, productionCommandIndexes.size()-1)];
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
aiInterface->giveCommand(bestIndex, ut->getCommandType(commandIndex));
}
else
{// do it like normal CPU
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
defCt = NULL;
if(producersDefaultCommandType.find(bestIndex) != producersDefaultCommandType.end()) {
int bestCommandTypeCount = producersDefaultCommandType[bestIndex].size();
int bestCommandTypeIndex = ai->getRandom()->randRange(0, bestCommandTypeCount-1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",__FILE__,__FUNCTION__,__LINE__,bestCommandTypeIndex,bestCommandTypeCount);
defCt = producersDefaultCommandType[bestIndex][bestCommandTypeIndex];
}
aiInterface->giveCommand(bestIndex, defCt);
}
}
else
{
if(currentCommandCount==0)
{
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 = producersDefaultCommandType[bestIndex].size();
int bestCommandTypeIndex = ai->getRandom()->randRange(0, bestCommandTypeCount-1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",__FILE__,__FUNCTION__,__LINE__,bestCommandTypeIndex,bestCommandTypeCount);
defCt = producersDefaultCommandType[bestIndex][bestCommandTypeIndex];
}
aiInterface->giveCommand(bestIndex, defCt);
}
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 = producersDefaultCommandType[bestIndex].size();
int bestCommandTypeIndex = ai->getRandom()->randRange(0, bestCommandTypeCount-1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",__FILE__,__FUNCTION__,__LINE__,bestCommandTypeIndex,bestCommandTypeCount);
defCt = producersDefaultCommandType[bestIndex][bestCommandTypeIndex];
}
aiInterface->giveCommand(bestIndex, defCt);
}
}
else
{
int pIndex = ai->getRandom()->randRange(0, producers.size()-1);
int producerIndex= producers[pIndex];
defCt = NULL;
if(producersDefaultCommandType.find(producerIndex) != producersDefaultCommandType.end()) {
//defCt = producersDefaultCommandType[producerIndex];
int bestCommandTypeCount = producersDefaultCommandType[producerIndex].size();
int bestCommandTypeIndex = ai->getRandom()->randRange(0, bestCommandTypeCount-1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",__FILE__,__FUNCTION__,__LINE__,bestCommandTypeIndex,bestCommandTypeCount);
defCt = producersDefaultCommandType[producerIndex][bestCommandTypeIndex];
}
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());
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){
//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();
typedef vector<const UnitType*> UnitTypes;
UnitTypes buildings;
//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)){
buildings.push_back(building);
}
}
}
}
}
}
//add specific build task
buildBestBuilding(buildings);
}
void AiRuleBuild::buildBestBuilding(const vector<const UnitType*> &buildings){
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<buildings.size() && !buildingFound; ++j){
const UnitType *building= buildings[j];
if(ai->getCountOfType(building)<=i+1 && isDefensive(building))
{
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))
{
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))
{
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)
{
ai->addTask(new BuildTask(building));
buildingFound= true;
}
}
}
}
}
void AiRuleBuild::buildSpecific(const BuildTask *bt) {
AiInterface *aiInterface= ai->getAiInterface();
//if reqs ok
if(aiInterface->reqsOk(bt->getUnitType())) {
//retry if not enough resources
if(aiInterface->checkCosts(bt->getUnitType()) == false) {
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, builders.size()-1);
int builderIndex= builders[bIndex];
Vec2i pos;
Vec2i searchPos= bt->getForcePos()? bt->getPos(): ai->getRandomHomePosition();
//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 = buildersDefaultCommandType[builderIndex].size();
int bestCommandTypeIndex = ai->getRandom()->randRange(0, bestCommandTypeCount-1);
SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] bestCommandTypeIndex = %d, bestCommandTypeCount = %d\n",__FILE__,__FUNCTION__,__LINE__,bestCommandTypeIndex,bestCommandTypeCount);
defBct = buildersDefaultCommandType[builderIndex][bestCommandTypeIndex];
}
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;
}
}
}
}
bool AiRuleBuild::isDefensive(const UnitType *building){
return building->hasSkillClass(scAttack);
}
bool AiRuleBuild::isResourceProducer(const UnitType *building){
for(int i= 0; i<building->getCostCount(); i++){
if(building->getCost(i)->getAmount()<0){
return true;
}
}
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)){
return true;
}
}
}
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;
//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, 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())){
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)){
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) {
// 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->getPos().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