- more AI enhancements, now units that harvest AND attack will be more wise when choosing to attack, (think persian) since they need to harvest more than they need to attack when harvester count is very low.

- AI Units now place higher priority on repairing 'castle' style units when looking for something to repair.
This commit is contained in:
Mark Vejvoda 2011-04-29 23:42:16 +00:00
parent d297a68b36
commit c979ea1254
3 changed files with 123 additions and 25 deletions

View File

@ -202,22 +202,28 @@ int Ai::getCountOfType(const UnitType *ut){
return count; return count;
} }
int Ai::getCountOfClass(UnitClass uc){ int Ai::getCountOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount) {
int count= 0; int count= 0;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){ for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
if(aiInterface->getMyUnit(i)->getType()->isOfClass(uc)){ 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; ++count;
} }
} }
return count; return count;
} }
float Ai::getRatioOfClass(UnitClass uc){ float Ai::getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount) {
if(aiInterface->getMyUnitCount()==0){ if(aiInterface->getMyUnitCount() == 0) {
return 0; return 0;
} }
else{ else {
return static_cast<float>(getCountOfClass(uc))/aiInterface->getMyUnitCount(); return static_cast<float>(getCountOfClass(uc,additionalUnitClassToExcludeFromCount)) / aiInterface->getMyUnitCount();
} }
} }
@ -272,9 +278,9 @@ bool Ai::beingAttacked(Vec2i &pos, Field &field, int radius){
*/ */
} }
bool Ai::isStableBase(){ bool Ai::isStableBase() {
UnitClass ucWorkerType = ucWorker;
if(getCountOfClass(ucWarrior)>minWarriors){ if(getCountOfClass(ucWarrior,&ucWorkerType) > minWarriors) {
aiInterface->printLog(4, "Base is stable\n"); aiInterface->printLog(4, "Base is stable\n");
return true; return true;
} }
@ -436,10 +442,13 @@ void Ai::sendScoutPatrol(){
} }
void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){ void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
const int minWorkerAttackersHarvesting = 3;
int producerWarriorCount=0; int producerWarriorCount=0;
int maxProducerWarriors=random.randRange(1,11); int maxProducerWarriors=random.randRange(1,11);
int unitCount = aiInterface->getMyUnitCount(); int unitCount = aiInterface->getMyUnitCount();
int attackerWorkersHarvestingCount = 0;
for(int i = 0; i < unitCount; ++i) { for(int i = 0; i < unitCount; ++i) {
bool isWarrior=false; bool isWarrior=false;
const Unit *unit= aiInterface->getMyUnit(i); const Unit *unit= aiInterface->getMyUnit(i);
@ -493,24 +502,51 @@ void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
//printf("~~~~~~~~ Unit [%s - %d] found 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()); //printf("~~~~~~~~ Unit [%s - %d] found 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) { if(act_forenemy != NULL) {
//printf("~~~~~~~~ Unit [%s - %d] WILL ATTACK [%s - %d]\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId()); bool shouldAttack = true;
aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos()); if(unit->getType()->hasSkillClass(scHarvest)) {
unitSignalledToAttack = true; shouldAttack = (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false) {
attackerWorkersHarvestingCount++;
}
}
if(shouldAttack) {
//printf("~~~~~~~~ Unit [%s - %d] WILL ATTACK [%s - %d]\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId());
aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos());
unitSignalledToAttack = true;
}
} }
else { else {
const AttackStoppedCommandType *asct_forenemy = unit->getType()->getFirstAttackStoppedCommand(enemy->getCurrField()); 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()); //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) { if(asct_forenemy != NULL) {
//printf("~~~~~~~~ Unit [%s - %d] WILL ATTACK [%s - %d]\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId()); bool shouldAttack = true;
aiInterface->giveCommand(i, asct_forenemy, beingAttacked.second->getCenteredPos()); if(unit->getType()->hasSkillClass(scHarvest)) {
unitSignalledToAttack = true; shouldAttack = (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false) {
attackerWorkersHarvestingCount++;
}
}
if(shouldAttack) {
//printf("~~~~~~~~ Unit [%s - %d] WILL ATTACK [%s - %d]\n",unit->getFullName().c_str(),unit->getId(),enemy->getFullName().c_str(),enemy->getId());
aiInterface->giveCommand(i, asct_forenemy, beingAttacked.second->getCenteredPos());
unitSignalledToAttack = true;
}
} }
} }
} }
} }
if(alreadyAttacking == false && act!=NULL && (ultraAttack || isWarrior) && if(alreadyAttacking == false && act != NULL && (ultraAttack || isWarrior) &&
unitSignalledToAttack == false) { unitSignalledToAttack == false) {
aiInterface->giveCommand(i, act, pos); bool shouldAttack = true;
if(unit->getType()->hasSkillClass(scHarvest)) {
shouldAttack = (attackerWorkersHarvestingCount > minWorkerAttackersHarvesting);
if(shouldAttack == false) {
attackerWorkersHarvestingCount++;
}
}
if(shouldAttack) {
aiInterface->giveCommand(i, act, pos);
}
} }
} }

View File

@ -158,8 +158,8 @@ public:
RandomGen* getRandom() {return &random;} RandomGen* getRandom() {return &random;}
int getCountOfType(const UnitType *ut); int getCountOfType(const UnitType *ut);
int getCountOfClass(UnitClass uc); int getCountOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL);
float getRatioOfClass(UnitClass uc); float getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL);
const ResourceType *getNeededResource(int unitIndex); const ResourceType *getNeededResource(int unitIndex);
bool isStableBase(); bool isStableBase();

View File

@ -94,8 +94,69 @@ AiRuleRepair::AiRuleRepair(Ai *ai):
bool AiRuleRepair::test(){ bool AiRuleRepair::test(){
AiInterface *aiInterface= ai->getAiInterface(); AiInterface *aiInterface= ai->getAiInterface();
//look for a damaged unit const int minUnitsRepairingCastle = 7;
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){ // 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) {
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 &&
ut->getStoredResourceCount() > 0) {
unitCanProduceWorker = true;
}
}
}
}
int candidatedamagedUnitIndex=-1;
if(unitCanProduceWorker == true) {
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) {
if(u1->getCurrSkill()->getClass() == scStop || u1->getCurrSkill()->getClass() == scMove) {
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()) {
unitCountAlreadyRepairingDamagedUnit++;
}
}
}
}
}
if(candidatedamagedUnitIndex >= 0 && unitCountAlreadyRepairingDamagedUnit < minUnitsRepairingCastle) {
damagedUnitIndex = candidatedamagedUnitIndex;
return true;
}
}
}
}
// Normal Repair checking
for(int i = 0; i < aiInterface->getMyUnitCount(); ++i) {
const Unit *u= aiInterface->getMyUnit(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())); //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) { if(u->getHpRatio() < 1.f) {
@ -191,12 +252,13 @@ AiRuleAddTasks::AiRuleAddTasks(Ai *ai):
} }
bool AiRuleAddTasks::test(){ bool AiRuleAddTasks::test(){
return !ai->anyTask() || ai->getCountOfClass(ucWorker)<4; return !ai->anyTask() || ai->getCountOfClass(ucWorker) < 4;
} }
void AiRuleAddTasks::execute(){ void AiRuleAddTasks::execute(){
int buildingCount= ai->getCountOfClass(ucBuilding); int buildingCount= ai->getCountOfClass(ucBuilding);
int warriorCount= ai->getCountOfClass(ucWarrior); UnitClass ucWorkerType = ucWorker;
int warriorCount= ai->getCountOfClass(ucWarrior,&ucWorkerType);
int workerCount= ai->getCountOfClass(ucWorker); int workerCount= ai->getCountOfClass(ucWorker);
int upgradeCount= ai->getAiInterface()->getMyUpgradeCount(); int upgradeCount= ai->getAiInterface()->getMyUpgradeCount();
@ -632,7 +694,7 @@ void AiRuleProduce::produceSpecific(const ProduceTask *pt){
if( aiInterface->getMyUnit(bestIndex)->getCommandSize() > 2) { if( aiInterface->getMyUnit(bestIndex)->getCommandSize() > 2) {
// maybe we need another producer of this kind if possible! // maybe we need another producer of this kind if possible!
if(aiInterface->reqsOk(aiInterface->getMyUnit(bestIndex)->getType())) { if(aiInterface->reqsOk(aiInterface->getMyUnit(bestIndex)->getType())) {
if(ai->getCountOfClass(ucBuilding)>5) if(ai->getCountOfClass(ucBuilding) > 5)
ai->addTask(new BuildTask(aiInterface->getMyUnit(bestIndex)->getType())); ai->addTask(new BuildTask(aiInterface->getMyUnit(bestIndex)->getType()));
} }
// need to calculate another producer, maybe its better to produce another warrior with another producer // need to calculate another producer, maybe its better to produce another warrior with another producer