- 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;
}
int Ai::getCountOfClass(UnitClass uc){
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)){
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){
if(aiInterface->getMyUnitCount()==0){
float Ai::getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount) {
if(aiInterface->getMyUnitCount() == 0) {
return 0;
}
else{
return static_cast<float>(getCountOfClass(uc))/aiInterface->getMyUnitCount();
else {
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(){
if(getCountOfClass(ucWarrior)>minWarriors){
bool Ai::isStableBase() {
UnitClass ucWorkerType = ucWorker;
if(getCountOfClass(ucWarrior,&ucWorkerType) > minWarriors) {
aiInterface->printLog(4, "Base is stable\n");
return true;
}
@ -436,10 +442,13 @@ void Ai::sendScoutPatrol(){
}
void Ai::massiveAttack(const Vec2i &pos, Field field, bool ultraAttack){
const int minWorkerAttackersHarvesting = 3;
int producerWarriorCount=0;
int maxProducerWarriors=random.randRange(1,11);
int unitCount = aiInterface->getMyUnitCount();
int attackerWorkersHarvestingCount = 0;
for(int i = 0; i < unitCount; ++i) {
bool isWarrior=false;
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());
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());
aiInterface->giveCommand(i, act_forenemy, beingAttacked.second->getPos());
unitSignalledToAttack = true;
bool shouldAttack = true;
if(unit->getType()->hasSkillClass(scHarvest)) {
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 {
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) {
//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;
bool shouldAttack = true;
if(unit->getType()->hasSkillClass(scHarvest)) {
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) {
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;}
int getCountOfType(const UnitType *ut);
int getCountOfClass(UnitClass uc);
float getRatioOfClass(UnitClass uc);
int getCountOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL);
float getRatioOfClass(UnitClass uc,UnitClass *additionalUnitClassToExcludeFromCount=NULL);
const ResourceType *getNeededResource(int unitIndex);
bool isStableBase();

View File

@ -94,8 +94,69 @@ AiRuleRepair::AiRuleRepair(Ai *ai):
bool AiRuleRepair::test(){
AiInterface *aiInterface= ai->getAiInterface();
//look for a damaged unit
for(int i=0; i<aiInterface->getMyUnitCount(); ++i){
const int minUnitsRepairingCastle = 7;
// 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);
//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) {
@ -191,12 +252,13 @@ AiRuleAddTasks::AiRuleAddTasks(Ai *ai):
}
bool AiRuleAddTasks::test(){
return !ai->anyTask() || ai->getCountOfClass(ucWorker)<4;
return !ai->anyTask() || ai->getCountOfClass(ucWorker) < 4;
}
void AiRuleAddTasks::execute(){
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 upgradeCount= ai->getAiInterface()->getMyUpgradeCount();
@ -632,7 +694,7 @@ void AiRuleProduce::produceSpecific(const ProduceTask *pt){
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)
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