diff --git a/AI/VCAI/Goals.cpp b/AI/VCAI/Goals.cpp index f6d2abb12..8f63750de 100644 --- a/AI/VCAI/Goals.cpp +++ b/AI/VCAI/Goals.cpp @@ -851,3 +851,15 @@ void CGoal::accept (VCAI * ai) { ai->tryRealize(static_cast(*this)); //casting enforces template instantiation } + +//TODO: find out why the following are not generated automatically on MVS? +void CGoal::accept (VCAI * ai) +{ + ai->tryRealize(static_cast(*this)); +} + +void CGoal::accept (VCAI * ai) +{ + ai->tryRealize(static_cast(*this)); +} + diff --git a/AI/VCAI/Goals.h b/AI/VCAI/Goals.h index 79900769c..45c385b84 100644 --- a/AI/VCAI/Goals.h +++ b/AI/VCAI/Goals.h @@ -100,10 +100,11 @@ public: static TSubgoal tryRecruitHero(); virtual TSubgoal whatToDoToAchieve() = 0; + ///Visitor pattern //TODO: make accept work for shared_ptr... somehow virtual void accept (VCAI * ai); //unhandled goal will report standard error - virtual bool operator== (AbstractGoal &g) //TODO: virtualize - comparison returns true only for same subclasses + virtual bool operator== (AbstractGoal &g) { return false; } @@ -195,7 +196,6 @@ class Build : public CGoal public: Build() : CGoal (Goals::BUILD){}; TSubgoal whatToDoToAchieve() override; - void accept (const VCAI *); }; class Explore : public CGoal { diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index 8367ba421..91ad34210 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -1703,28 +1703,42 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal) if (ultimateGoal->invalid()) return; + //we are looking for abstract goals + auto abstractGoal = striveToGoalInternal (ultimateGoal, false); + + if (abstractGoal->invalid()) + return; + + //we received abstratc goal, need to find concrete goals + striveToGoalInternal (abstractGoal, true); + + //TODO: save abstract goals not related to hero +} + +Goals::TSubgoal VCAI::striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool onlyAbstract) +{ Goals::TSubgoal abstractGoal = sptr(Goals::Invalid()); while(1) { - Goals::TSubgoal goal = ultimateGoal; //FIXME: preserve subclass of goal + Goals::TSubgoal goal = ultimateGoal; logAi->debugStream() << boost::format("Striving to goal of type %s") % ultimateGoal->name(); int maxGoals = 100; //preventing deadlock for mutually dependent goals //FIXME: do not try to realize goal when loop didn't suceed - while(!goal->isElementar && !goal->isAbstract && maxGoals) + while(!goal->isElementar && maxGoals && (onlyAbstract || !goal->isAbstract)) { logAi->debugStream() << boost::format("Considering goal %s") % goal->name(); try { boost::this_thread::interruption_point(); - goal = goal->whatToDoToAchieve(); //FIXME: why it calls always base class? + goal = goal->whatToDoToAchieve(); --maxGoals; } catch(std::exception &e) { logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal->name() % e.what(); //setGoal (goal.hero, INVALID); //test: if we don't know how to realize goal, we should abandon it for now - return; + return sptr(Goals::Invalid()); } } @@ -1770,7 +1784,7 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal) { completeGoal (goal); if (fulfillsGoal (goal, ultimateGoal) || maxGoals > 98) //completed goal was main goal //TODO: find better condition - return; + return sptr(Goals::Invalid()); } catch(std::exception &e) { @@ -1779,61 +1793,7 @@ void VCAI::striveToGoal(Goals::TSubgoal ultimateGoal) break; } } - - //TODO: save abstract goals not related to hero - //TODO: refactor, duplicated code - if (!abstractGoal->invalid()) //try to realize our one goal - { - while (1) - { - std::shared_ptr goal(abstractGoal); - goal->setisAbstract(false); - int maxGoals = 50; - while (!goal->isElementar && maxGoals) //find elementar goal and fulfill it - { - try - { - boost::this_thread::interruption_point(); - goal = goal->whatToDoToAchieve(); - --maxGoals; - } - catch(std::exception &e) - { - logAi->debugStream() << boost::format("Goal %s decomposition failed: %s") % goal->name() % e.what(); - //setGoal (goal.hero, INVALID); - return; - } - } - try - { - boost::this_thread::interruption_point(); - if (!maxGoals) - { - std::runtime_error e("Too many subgoals, don't know what to do"); - throw (e); - } - goal->accept(this); - boost::this_thread::interruption_point(); - } - catch(boost::thread_interrupted &e) - { - logAi->debugStream() << boost::format("Player %d: Making turn thread received an interruption!") % playerID; - throw; //rethrow, we want to truly end this thread - } - catch(goalFulfilledException &e) - { - completeGoal (goal); //FIXME: deduce that we have realized GET_OBJ goal - if (fulfillsGoal (goal, abstractGoal) || maxGoals > 98) //completed goal was main goal - return; - } - catch(std::exception &e) - { - logAi->debugStream() << boost::format("Failed to realize subgoal of type %s (greater goal type was %s), I will stop.") % goal->name() % ultimateGoal->name(); - logAi->debugStream() << boost::format("The error message was: %s") % e.what(); - break; - } - } - } + return abstractGoal; } void VCAI::striveToQuest (const QuestInfo &q) diff --git a/AI/VCAI/VCAI.h b/AI/VCAI/VCAI.h index 519cddfc1..0a01186cd 100644 --- a/AI/VCAI/VCAI.h +++ b/AI/VCAI/VCAI.h @@ -233,6 +233,7 @@ public: void buildArmyIn(const CGTownInstance * t); void striveToGoal(Goals::TSubgoal ultimateGoal); + Goals::TSubgoal striveToGoalInternal(Goals::TSubgoal ultimateGoal, bool onlyAbstract); void endTurn(); void wander(HeroPtr h); void setGoal(HeroPtr h, Goals::TSubgoal goal);