TGoalVec VisitTile::getAllPossibleSubgoals() { assert(cb->isInTheMap(tile)); TGoalVec ret; if (!cb->isVisible(tile)) ret.push_back (sptr(Goals::Explore())); //what sense does it make? else { std::vector<const CGHeroInstance *> heroes; if (hero) heroes.push_back(hero.h); //use assigned hero if any else heroes = cb->getHeroesInfo(); //use most convenient hero for (auto h : heroes) { if (ai->isAccessibleForHero(tile, h)) ret.push_back (sptr(Goals::VisitTile(tile).sethero(h))); } if (ai->canRecruitAnyHero()) ret.push_back (sptr(Goals::RecruitHero())); } if (ret.empty()) { auto obj = frontOrNull(cb->getVisitableObjs(tile)); if (obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile ret.push_back (sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true))); else ret.push_back (sptr(Goals::ClearWayTo(tile))); } //important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile) return ret; }
TSubgoal ClearWayTo::whatToDoToAchieve() { assert(cb->isInTheMap(tile)); //set tile if(!cb->isVisible(tile)) { logAi->errorStream() << "Clear way should be used with visible tiles!"; return sptr (Goals::Explore()); } return (fh->chooseSolution(getAllPossibleSubgoals())); }
void getVisibleNeighbours(const std::vector<int3> &tiles, std::vector<int3> &out) { for(const int3 &tile : tiles) { foreach_neighbour(tile, [&](int3 neighbour) { if(cb->isVisible(neighbour)) out.push_back(neighbour); }); } }
int howManyTilesWillBeDiscovered(const int3 &pos, int radious) { //TODO: do not explore dead-end boundaries int ret = 0; for(int x = pos.x - radious; x <= pos.x + radious; x++) { for(int y = pos.y - radious; y <= pos.y + radious; y++) { int3 npos = int3(x,y,pos.z); if(cb->isInTheMap(npos) && pos.dist2d(npos) - 0.5 < radious && !cb->isVisible(npos)) { if (!boundaryBetweenTwoPoints (pos, npos)) ret++; } } } return ret; }
bool boundaryBetweenTwoPoints (int3 pos1, int3 pos2) //determines if two points are separated by known barrier { int xMin = std::min (pos1.x, pos2.x); int xMax = std::max (pos1.x, pos2.x); int yMin = std::min (pos1.y, pos2.y); int yMax = std::max (pos1.y, pos2.y); for (int x = xMin; x <= xMax; ++x) { for (int y = yMin; y <= yMax; ++y) { int3 tile = int3(x, y, pos1.z); //use only on same level, ofc if (abs(pos1.dist2d(tile) - pos2.dist2d(tile)) < 1.5) { if (!(cb->isVisible(tile) && cb->getTile(tile)->blocked)) //if there's invisible or unblocked tile inbetween, it's good return false; } } } return true; //if all are visible and blocked, we're at dead end }
TGoalVec VisitTile::getAllPossibleSubgoals() { assert(cb->isInTheMap(tile)); TGoalVec ret; if (!cb->isVisible(tile)) ret.push_back (sptr(Goals::Explore())); //what sense does it make? else { std::vector<const CGHeroInstance *> heroes; if (hero) heroes.push_back(hero.h); //use assigned hero if any else heroes = cb->getHeroesInfo(); //use most convenient hero for (auto h : heroes) { if (ai->isAccessibleForHero(tile, h)) ret.push_back (sptr(Goals::VisitTile(tile).sethero(h))); } if (ai->canRecruitAnyHero()) ret.push_back (sptr(Goals::RecruitHero())); } if(ret.empty()) { auto obj = vstd::frontOrNull(cb->getVisitableObjs(tile)); if(obj && obj->ID == Obj::HERO && obj->tempOwner == ai->playerID) //our own hero stands on that tile { if (hero.get(true) && hero->id == obj->id) //if it's assigned hero, visit tile. If it's different hero, we can't visit tile now ret.push_back(sptr(Goals::VisitTile(tile).sethero(dynamic_cast<const CGHeroInstance *>(obj)).setisElementar(true))); else throw cannotFulfillGoalException("Tile is already occupied by another hero "); //FIXME: we should give up this tile earlier } else ret.push_back (sptr(Goals::ClearWayTo(tile))); } //important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile) return ret; }