TSubgoal GatherTroops::whatToDoToAchieve() { std::vector<const CGDwelling *> dwellings; for(const CGTownInstance *t : cb->getTownsInfo()) { auto creature = VLC->creh->creatures[objid]; if (t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O { auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1); if(!creatures) continue; int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber); if(upgradeNumber < 0) continue; BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN); if (t->hasBuilt(bid)) //this assumes only creatures with dwellings are assigned to faction { dwellings.push_back(t); } else { return sptr (Goals::BuildThis(bid, t)); } } } for (auto obj : ai->visitableObjs) { if (obj->ID != Obj::CREATURE_GENERATOR1) //TODO: what with other creature generators? continue; auto d = dynamic_cast<const CGDwelling *>(obj); for (auto creature : d->creatures) { if (creature.first) //there are more than 0 creatures avaliabe { for (auto type : creature.second) { if (type == objid && ai->freeResources().canAfford(VLC->creh->creatures[type]->cost)) dwellings.push_back(d); } } } } if (dwellings.size()) { boost::sort(dwellings, isCloser); return sptr (Goals::GetObj(dwellings.front()->id.getNum())); } else return sptr (Goals::Explore()); //TODO: exchange troops between heroes }
TGoalVec GatherArmy::getAllPossibleSubgoals() { //get all possible towns, heroes and dwellings we may use TGoalVec ret; //TODO: include evaluation of monsters gather in calculation for (auto t : cb->getTownsInfo()) { auto pos = t->visitablePos(); if (ai->isAccessibleForHero(pos, hero)) { if(!t->visitingHero && howManyReinforcementsCanGet(hero,t)) { if (!vstd::contains (ai->townVisitsThisWeek[hero], t)) ret.push_back (sptr (Goals::VisitTile(pos).sethero(hero))); } auto bid = ai->canBuildAnyStructure(t, std::vector<BuildingID> (unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 8 - cb->getDate(Date::DAY_OF_WEEK)); if (bid != BuildingID::NONE) ret.push_back (sptr(BuildThis(bid, t))); } } auto otherHeroes = cb->getHeroesInfo(); auto heroDummy = hero; erase_if(otherHeroes, [heroDummy](const CGHeroInstance * h) { return (h == heroDummy.h || !ai->isAccessibleForHero(heroDummy->visitablePos(), h, true) || !ai->canGetArmy(heroDummy.h, h) || ai->getGoal(h)->goalType == Goals::GATHER_ARMY); }); for (auto h : otherHeroes) { ret.push_back (sptr (Goals::VisitHero(h->id.getNum()).setisAbstract(true).sethero(hero))); //go to the other hero if we are faster ret.push_back (sptr (Goals::VisitHero(hero->id.getNum()).setisAbstract(true).sethero(h))); //let the other hero come to us } std::vector <const CGObjectInstance *> objs; for (auto obj : ai->visitableObjs) { if(obj->ID == Obj::CREATURE_GENERATOR1) { auto relationToOwner = cb->getPlayerRelations(obj->getOwner(), ai->playerID); //Use flagged dwellings only when there are available creatures that we can afford if(relationToOwner == PlayerRelations::SAME_PLAYER) { auto dwelling = dynamic_cast<const CGDwelling*>(obj); for(auto & creLevel : dwelling->creatures) { if(creLevel.first) { for(auto & creatureID : creLevel.second) { auto creature = VLC->creh->creatures[creatureID]; if (ai->freeResources().canAfford(creature->cost)) objs.push_back(obj); } } } } } } for(auto h : cb->getHeroesInfo()) { for (auto obj : objs) { //find safe dwelling auto pos = obj->visitablePos(); if (ai->isGoodForVisit(obj, h)) ret.push_back (sptr (Goals::VisitTile(pos).sethero(h))); } } if (ai->canRecruitAnyHero()) //this is not stupid in early phase of game ret.push_back (sptr(Goals::RecruitHero())); if (ret.empty()) { if (hero == ai->primaryHero() || value >= 1.1f) ret.push_back (sptr(Goals::Explore())); else //workaround to break loop - seemingly there are no ways to explore left throw goalFulfilledException (sptr(Goals::GatherArmy(0).sethero(hero))); } return ret; }
TSubgoal GatherTroops::whatToDoToAchieve() { std::vector<const CGDwelling *> dwellings; for(const CGTownInstance *t : cb->getTownsInfo()) { auto creature = VLC->creh->creatures[objid]; if (t->subID == creature->faction) //TODO: how to force AI to build unupgraded creatures? :O { auto creatures = vstd::tryAt(t->town->creatures, creature->level - 1); if(!creatures) continue; int upgradeNumber = vstd::find_pos(*creatures, creature->idNumber); if(upgradeNumber < 0) continue; BuildingID bid(BuildingID::DWELL_FIRST + creature->level - 1 + upgradeNumber * GameConstants::CREATURES_PER_TOWN); if (t->hasBuilt(bid)) //this assumes only creatures with dwellings are assigned to faction { dwellings.push_back(t); } else { return sptr (Goals::BuildThis(bid, t)); } } } for (auto obj : ai->visitableObjs) { if (obj->ID != Obj::CREATURE_GENERATOR1) //TODO: what with other creature generators? continue; auto d = dynamic_cast<const CGDwelling *>(obj); for (auto creature : d->creatures) { if (creature.first) //there are more than 0 creatures avaliabe { for (auto type : creature.second) { if (type == objid && ai->freeResources().canAfford(VLC->creh->creatures[type]->cost)) dwellings.push_back(d); } } } } if (dwellings.size()) { typedef std::map<const CGHeroInstance *, const CGDwelling *> TDwellMap; // sorted helper auto comparator = [](const TDwellMap::value_type & a, const TDwellMap::value_type & b) -> bool { const CGPathNode *ln = ai->myCb->getPathsInfo(a.first)->getPathInfo(a.second->visitablePos()), *rn = ai->myCb->getPathsInfo(b.first)->getPathInfo(b.second->visitablePos()); if(ln->turns != rn->turns) return ln->turns < rn->turns; return (ln->moveRemains > rn->moveRemains); }; // for all owned heroes generate map <hero -> nearest dwelling> TDwellMap nearestDwellings; for (const CGHeroInstance * hero : cb->getHeroesInfo(true)) { nearestDwellings[hero] = *boost::range::min_element(dwellings, CDistanceSorter(hero)); } // find hero who is nearest to a dwelling const CGDwelling * nearest = boost::range::min_element(nearestDwellings, comparator)->second; return sptr (Goals::GetObj(nearest->id.getNum())); } else return sptr (Goals::Explore()); //TODO: exchange troops between heroes }