diff --git a/AI/VCAI/Goals.cpp b/AI/VCAI/Goals.cpp index 8f63750de..81db79adc 100644 --- a/AI/VCAI/Goals.cpp +++ b/AI/VCAI/Goals.cpp @@ -191,7 +191,7 @@ TSubgoal FindObj::whatToDoToAchieve() } } } - if (o && isReachable(o)) + if (o && isReachable(o)) //we don't use isAccessibleForHero as we don't know which hero it is return sptr (Goals::GetObj(o->id.getNum())); else return sptr (Goals::Explore()); @@ -210,6 +210,14 @@ TSubgoal GetObj::whatToDoToAchieve() return sptr (Goals::VisitTile(pos)); } +bool GetObj::fulfillsMe (shared_ptr goal) +{ + if (cb->getObj(ObjectInstanceID(objid))->visitablePos() == goal->tile) + return true; + else + return false; +} + std::string VisitHero::completeMessage() const { return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast(objid); @@ -231,6 +239,14 @@ TSubgoal VisitHero::whatToDoToAchieve() return sptr (Goals::Invalid()); } +bool VisitHero::fulfillsMe (shared_ptr goal) +{ + if (cb->getObj(ObjectInstanceID(objid))->visitablePos() == goal->tile) + return true; + else + return false; +} + TSubgoal GetArtOfType::whatToDoToAchieve() { TSubgoal alternativeWay = CGoal::lookForArtSmart(aid); //TODO: use @@ -718,7 +734,7 @@ TSubgoal GatherArmy::whatToDoToAchieve() { if(!t->visitingHero && howManyReinforcementsCanGet(hero,t)) { - if(isReachable(t) && !vstd::contains (ai->townVisitsThisWeek[hero], t)) + if (ai->isAccessibleForHero(t->pos, hero) && !vstd::contains (ai->townVisitsThisWeek[hero], t)) townsReachable.push_back(t); } } diff --git a/AI/VCAI/Goals.h b/AI/VCAI/Goals.h index 45c385b84..4b3b850aa 100644 --- a/AI/VCAI/Goals.h +++ b/AI/VCAI/Goals.h @@ -22,6 +22,7 @@ class VCAI; namespace Goals { struct AbstractGoal; + class VisitTile; typedef std::shared_ptr TSubgoal; typedef std::vector TGoalVec; @@ -108,6 +109,14 @@ public: { return false; } + virtual bool fulfillsMe (Goals::TSubgoal goal) + { + return false; + } + virtual bool fulfillsMe (shared_ptr goal) + { + return false; + } //template void serialize(Handler &h, const int version) @@ -259,6 +268,7 @@ public: GetObj(int Objid) : CGoal(Goals::GET_OBJ) {objid = Objid;}; TSubgoal whatToDoToAchieve() override; bool operator== (GetObj &g) {return g.objid == objid;} + bool fulfillsMe (shared_ptr goal) override; std::string completeMessage() const override; }; class FindObj : public CGoal @@ -278,6 +288,7 @@ public: VisitHero(int hid) : CGoal (Goals::VISIT_HERO){objid = hid;}; TSubgoal whatToDoToAchieve() override; bool operator== (VisitHero &g) {return g.objid == objid;} + bool fulfillsMe (shared_ptr goal) override; std::string completeMessage() const override; }; class GetArtOfType : public CGoal diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 91ad34210..44c8a5372 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -259,7 +259,8 @@ void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visi markObjectVisited (visitedObj); erase_if_present(reservedObjs, visitedObj); //unreserve objects erase_if_present(reservedHeroesMap[visitor], visitedObj); - completeGoal (sptr(Goals::GetObj(visitedObj->id.getNum()).sethero(visitor))); //we don't need to visit in anymore + completeGoal (sptr(Goals::GetObj(visitedObj->id.getNum()).sethero(visitor))); //we don't need to visit it anymore + //TODO: what if we visited one-time visitable object that was reserved by another hero (shouldn't, but..) } status.heroVisit(visitedObj, start); @@ -1083,7 +1084,7 @@ std::vector VCAI::getPossibleDestinations(HeroPtr h) std::vector possibleDestinations; for(const CGObjectInstance *obj : visitableObjs) { - if(cb->getPathInfo(obj->visitablePos())->reachable() && !obj->wasVisited(playerID) && + if(isAccessibleForHero(obj->visitablePos(), h) && !obj->wasVisited(playerID) && (obj->tempOwner != playerID || isWeeklyRevisitable(obj))) //flag or get weekly resources / creatures possibleDestinations.push_back(obj); } @@ -1122,8 +1123,15 @@ void VCAI::wander(HeroPtr h) while(1) { validateVisitableObjs(); - std::vector dests; - range::copy(reservedHeroesMap[h], std::back_inserter(dests)); + std::vector dests, tmp; + + range::copy(reservedHeroesMap[h], std::back_inserter(tmp)); //visit our reserved objects first + for (auto obj : tmp) + { + if (isAccessibleForHero (obj->visitablePos(), h)) //even nearby objects could be blocked by other heroes :( + dests.push_back(obj); //can't use lambda for member function :( + } + if (!dests.size()) range::copy(getPossibleDestinations(h), std::back_inserter(dests)); @@ -1140,7 +1148,7 @@ void VCAI::wander(HeroPtr h) { if(!t->visitingHero && howManyReinforcementsCanGet(h,t) && !vstd::contains(townVisitsThisWeek[h], t)) { - if(isReachable(t)) + if (isAccessibleForHero (t->visitablePos(), h)) townsReachable.push_back(t); else townsNotReachable.push_back(t); @@ -1243,9 +1251,9 @@ void VCAI::completeGoal (Goals::TSubgoal goal) { for (auto p : lockedHeroes) { - if (p.second == goal) + if (p.second == goal || p.second->fulfillsMe(goal)) //we could have fulfilled goals of other heroes by chance { - logAi->debugStream() << boost::format("%s") % goal->completeMessage(); + logAi->debugStream() << boost::format("%s") % p.second->completeMessage(); lockedHeroes.erase (lockedHeroes.find(p.first)); //is it safe? } } @@ -1688,16 +1696,6 @@ void VCAI::endTurn() logAi->debugStream() << "Player " << static_cast(playerID.getNum()) << " ended turn"; } -bool VCAI::fulfillsGoal (Goals::TSubgoal goal, Goals::TSubgoal mainGoal) -{ - if (mainGoal->goalType == Goals::GET_OBJ && goal->goalType == Goals::VISIT_TILE) //deduce that GET_OBJ was completed by visiting object's tile - { //TODO: more universal mechanism - if (cb->getObj(ObjectInstanceID(mainGoal->objid))->visitablePos() == goal->tile) - return true; - } - return false; -} - void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal) { if (ultimateGoal->invalid()) @@ -1783,7 +1781,7 @@ Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool on catch(goalFulfilledException &e) { completeGoal (goal); - if (fulfillsGoal (goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition + if (ultimateGoal->fulfillsMe(goal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition return sptr(Goals::Invalid()); } catch(std::exception &e) diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 0a01186cd..9c52b3d24 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -239,7 +239,6 @@ public: void setGoal(HeroPtr h, Goals::TSubgoal goal); void completeGoal (Goals::TSubgoal goal); //safely removes goal from reserved hero void striveToQuest (const QuestInfo &q); - bool fulfillsGoal (Goals::TSubgoal goal, Goals::TSubgoal mainGoal); void recruitHero(const CGTownInstance * t, bool throwing = false); std::vector getPossibleDestinations(HeroPtr h);