Răsfoiți Sursa

Do not add duplicate objectives to GatherArmy pool (or any other, if it ever exist)

DJWarmonger 7 ani în urmă
părinte
comite
b687688f5a

+ 5 - 0
AI/VCAI/AIhelper.cpp

@@ -48,6 +48,11 @@ Goals::TSubgoal AIhelper::whatToDo() const
 	return resourceManager->whatToDo();
 }
 
+bool AIhelper::containsObjective(Goals::TSubgoal goal) const
+{
+	return resourceManager->containsObjective(goal);
+}
+
 bool AIhelper::hasTasksLeft() const
 {
 	return resourceManager->hasTasksLeft();

+ 1 - 0
AI/VCAI/AIhelper.h

@@ -41,6 +41,7 @@ public:
 
 	Goals::TSubgoal whatToDo(TResources &res, Goals::TSubgoal goal) override;
 	Goals::TSubgoal whatToDo() const override; //peek highest-priority goal
+	bool containsObjective(Goals::TSubgoal goal) const;
 	bool hasTasksLeft() const override;
 
 private:

+ 8 - 2
AI/VCAI/Goals.cpp

@@ -1330,13 +1330,19 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 			{
 				ui32 val = std::min<ui32>(value, howManyReinforcementsCanBuy(hero, t));
 				if (val)
-					ret.push_back(sptr(Goals::BuyArmy(t, val).sethero(hero)));
+				{
+					auto goal = sptr(Goals::BuyArmy(t, val).sethero(hero));
+					if (!ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
+						ret.push_back(goal);
+				}
 			}
 			//build dwelling
 			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).setpriority(priority)));
+				auto goal = sptr(BuildThis(bid, t).setpriority(priority));
+				if (!ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice
+					ret.push_back(goal);
 			}
 		}
 	}

+ 11 - 0
AI/VCAI/ResourceManager.cpp

@@ -191,6 +191,17 @@ Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
 	return collectResourcesForOurGoal(ro); //fallback, ever needed?
 }
 
+bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
+{
+	//TODO: unit tests for once
+	for (auto objective : queue)
+	{
+		if (objective.goal == goal)
+			return true;
+	}
+	return false;
+}
+
 bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
 {
 	if (goal->invalid())

+ 2 - 0
AI/VCAI/ResourceManager.h

@@ -51,6 +51,7 @@ public:
 
 	virtual Goals::TSubgoal whatToDo() const = 0;//get highest-priority goal
 	virtual Goals::TSubgoal whatToDo(TResources &res, Goals::TSubgoal goal) = 0;
+	virtual bool containsObjective(Goals::TSubgoal goal) const = 0;
 	virtual bool hasTasksLeft() const = 0;
 private:
 	virtual bool notifyGoalCompleted(Goals::TSubgoal goal) = 0;
@@ -80,6 +81,7 @@ public:
 
 	Goals::TSubgoal whatToDo() const override; //peek highest-priority goal
 	Goals::TSubgoal whatToDo(TResources &res, Goals::TSubgoal goal); //can we afford this goal or need to CollectRes?
+	bool containsObjective(Goals::TSubgoal goal) const;
 	bool hasTasksLeft() const override;
 
 protected: //not-const actions only for AI