diff --git a/source/glest_game/ai/ai.cpp b/source/glest_game/ai/ai.cpp index 5b9cebe5..a161971c 100644 --- a/source/glest_game/ai/ai.cpp +++ b/source/glest_game/ai/ai.cpp @@ -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; igetMyUnitCount(); ++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(getCountOfClass(uc))/aiInterface->getMyUnitCount(); + else { + return static_cast(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); + } } } diff --git a/source/glest_game/ai/ai.h b/source/glest_game/ai/ai.h index 126e150f..b709deab 100644 --- a/source/glest_game/ai/ai.h +++ b/source/glest_game/ai/ai.h @@ -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(); diff --git a/source/glest_game/ai/ai_rule.cpp b/source/glest_game/ai/ai_rule.cpp index 5d42cd2b..68394f33 100644 --- a/source/glest_game/ai/ai_rule.cpp +++ b/source/glest_game/ai/ai_rule.cpp @@ -94,8 +94,69 @@ AiRuleRepair::AiRuleRepair(Ai *ai): bool AiRuleRepair::test(){ AiInterface *aiInterface= ai->getAiInterface(); - //look for a damaged unit - for(int i=0; igetMyUnitCount(); ++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(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(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