Pārlūkot izejas kodu

Nullkiller: initial cleanup of unused code

Andrii Danylchenko 5 gadi atpakaļ
vecāks
revīzija
af0dcf97c4
67 mainītis faili ar 395 papildinājumiem un 2930 dzēšanām
  1. 0 111
      AI/Nullkiller/AIhelper.cpp
  2. 4 35
      AI/Nullkiller/AIhelper.h
  3. 5 0
      AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp
  4. 3 1
      AI/Nullkiller/Behaviors/DefenceBehavior.cpp
  5. 2 0
      AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp
  6. 0 257
      AI/Nullkiller/BuildingManager.cpp
  7. 0 75
      AI/Nullkiller/BuildingManager.h
  8. 0 18
      AI/Nullkiller/CMakeLists.txt
  9. 1 1
      AI/Nullkiller/Engine/Nullkiller.cpp
  10. 3 2
      AI/Nullkiller/FuzzyEngines.cpp
  11. 1 1
      AI/Nullkiller/FuzzyEngines.h
  12. 0 166
      AI/Nullkiller/FuzzyHelper.cpp
  13. 0 24
      AI/Nullkiller/FuzzyHelper.h
  14. 0 58
      AI/Nullkiller/Goals/AbstractGoal.cpp
  15. 3 13
      AI/Nullkiller/Goals/AbstractGoal.h
  16. 0 5
      AI/Nullkiller/Goals/AdventureSpellCast.cpp
  17. 0 1
      AI/Nullkiller/Goals/AdventureSpellCast.h
  18. 17 22
      AI/Nullkiller/Goals/BuildBoat.cpp
  19. 0 2
      AI/Nullkiller/Goals/BuildBoat.h
  20. 1 45
      AI/Nullkiller/Goals/BuildThis.cpp
  21. 0 6
      AI/Nullkiller/Goals/BuildThis.h
  22. 2 16
      AI/Nullkiller/Goals/BuyArmy.cpp
  23. 0 2
      AI/Nullkiller/Goals/BuyArmy.h
  24. 0 5
      AI/Nullkiller/Goals/CGoal.h
  25. 143 157
      AI/Nullkiller/Goals/CollectRes.cpp
  26. 0 1
      AI/Nullkiller/Goals/CollectRes.h
  27. 8 14
      AI/Nullkiller/Goals/CompleteQuest.cpp
  28. 0 1
      AI/Nullkiller/Goals/CompleteQuest.h
  29. 0 5
      AI/Nullkiller/Goals/DismissHero.cpp
  30. 0 1
      AI/Nullkiller/Goals/DismissHero.h
  31. 0 5
      AI/Nullkiller/Goals/ExchangeSwapTownHeroes.cpp
  32. 0 1
      AI/Nullkiller/Goals/ExchangeSwapTownHeroes.h
  33. 22 25
      AI/Nullkiller/Goals/ExecuteHeroChain.cpp
  34. 0 1
      AI/Nullkiller/Goals/ExecuteHeroChain.h
  35. 1 18
      AI/Nullkiller/Goals/Explore.cpp
  36. 64 66
      AI/Nullkiller/Goals/Explore.h
  37. 1 17
      AI/Nullkiller/Goals/FindObj.cpp
  38. 0 1
      AI/Nullkiller/Goals/FindObj.h
  39. 68 76
      AI/Nullkiller/Goals/GatherTroops.cpp
  40. 0 1
      AI/Nullkiller/Goals/GatherTroops.h
  41. 0 5
      AI/Nullkiller/Goals/Goals.h
  42. 0 13
      AI/Nullkiller/Goals/RecruitHero.cpp
  43. 0 7
      AI/Nullkiller/Goals/RecruitHero.h
  44. 1 46
      AI/Nullkiller/Goals/VisitHero.cpp
  45. 0 7
      AI/Nullkiller/Goals/VisitHero.h
  46. 1 76
      AI/Nullkiller/Goals/VisitObj.cpp
  47. 0 4
      AI/Nullkiller/Goals/VisitObj.h
  48. 0 68
      AI/Nullkiller/Goals/VisitTile.cpp
  49. 0 3
      AI/Nullkiller/Goals/VisitTile.h
  50. 6 8
      AI/Nullkiller/Goals/Win.cpp
  51. 6 1
      AI/Nullkiller/MapObjectsEvaluator.cpp
  52. 1 1
      AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp
  53. 1 1
      AI/Nullkiller/Pathfinding/Actions/BattleAction.h
  54. 2 2
      AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp
  55. 2 2
      AI/Nullkiller/Pathfinding/Actions/BoatActions.h
  56. 1 1
      AI/Nullkiller/Pathfinding/Actions/ISpecialAction.h
  57. 1 1
      AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp
  58. 1 1
      AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h
  59. 0 216
      AI/Nullkiller/Pathfinding/PathfindingManager.cpp
  60. 0 8
      AI/Nullkiller/Pathfinding/PathfindingManager.h
  61. 1 1
      AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp
  62. 0 364
      AI/Nullkiller/ResourceManager.cpp
  63. 0 113
      AI/Nullkiller/ResourceManager.h
  64. 3 1
      AI/Nullkiller/VCAI.cbp
  65. 13 702
      AI/Nullkiller/VCAI.cpp
  66. 3 19
      AI/Nullkiller/VCAI.h
  67. 3 3
      AI/Nullkiller/VCAI.vcxproj

+ 0 - 111
AI/Nullkiller/AIhelper.cpp

@@ -13,8 +13,6 @@
 
 AIhelper::AIhelper()
 {
-	resourceManager.reset(new ResourceManager());
-	buildingManager.reset(new BuildingManager());
 	pathfindingManager.reset(new PathfindingManager());
 	armyManager.reset(new ArmyManager());
 	heroManager.reset(new HeroManager());
@@ -24,15 +22,8 @@ AIhelper::~AIhelper()
 {
 }
 
-bool AIhelper::notifyGoalCompleted(Goals::TSubgoal goal)
-{
-	return resourceManager->notifyGoalCompleted(goal);
-}
-
 void AIhelper::init(CPlayerSpecificInfoCallback * CB)
 {
-	resourceManager->init(CB);
-	buildingManager->init(CB);
 	pathfindingManager->init(CB);
 	armyManager->init(CB);
 	heroManager->init(CB);
@@ -40,8 +31,6 @@ void AIhelper::init(CPlayerSpecificInfoCallback * CB)
 
 void AIhelper::setAI(VCAI * AI)
 {
-	resourceManager->setAI(AI);
-	buildingManager->setAI(AI);
 	pathfindingManager->setAI(AI);
 	armyManager->setAI(AI);
 	heroManager->setAI(AI);
@@ -53,106 +42,6 @@ void AIhelper::update()
 	heroManager->update();
 }
 
-bool AIhelper::getBuildingOptions(const CGTownInstance * t)
-{
-	return buildingManager->getBuildingOptions(t);
-}
-
-BuildingID AIhelper::getMaxPossibleGoldBuilding(const CGTownInstance * t)
-{
-	return buildingManager->getMaxPossibleGoldBuilding(t);
-}
-
-boost::optional<PotentialBuilding> AIhelper::immediateBuilding() const
-{
-	return buildingManager->immediateBuilding();
-}
-
-boost::optional<PotentialBuilding> AIhelper::expensiveBuilding() const
-{
-	return buildingManager->expensiveBuilding();
-}
-
-boost::optional<BuildingID> AIhelper::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
-{
-	return buildingManager->canBuildAnyStructure(t, buildList, maxDays);
-}
-
-Goals::TSubgoal AIhelper::whatToDo(TResources & res, Goals::TSubgoal goal)
-{
-	return resourceManager->whatToDo(res, goal);
-}
-
-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();
-}
-
-bool AIhelper::removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal&)> predicate)
-{
-	return resourceManager->removeOutdatedObjectives(predicate);
-}
-
-bool AIhelper::canAfford(const TResources & cost) const
-{
-	return resourceManager->canAfford(cost);
-}
-
-TResources AIhelper::reservedResources() const
-{
-	return resourceManager->reservedResources();
-}
-
-TResources AIhelper::freeResources() const
-{
-	return resourceManager->freeResources();
-}
-
-TResource AIhelper::freeGold() const
-{
-	return resourceManager->freeGold();
-}
-
-TResources AIhelper::allResources() const
-{
-	return resourceManager->allResources();
-}
-
-TResource AIhelper::allGold() const
-{
-	return resourceManager->allGold();
-}
-
-Goals::TGoalVec AIhelper::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
-{
-	return pathfindingManager->howToVisitTile(tile, allowGatherArmy);
-}
-
-Goals::TGoalVec AIhelper::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
-{
-	return pathfindingManager->howToVisitObj(obj, allowGatherArmy);
-}
-
-Goals::TGoalVec AIhelper::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const
-{
-	return pathfindingManager->howToVisitTile(hero, tile, allowGatherArmy);
-}
-
-Goals::TGoalVec AIhelper::howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy) const
-{
-	return pathfindingManager->howToVisitObj(hero, obj, allowGatherArmy);
-}
-
 std::vector<AIPath> AIhelper::getPathsToTile(const HeroPtr & hero, const int3 & tile) const
 {
 	return pathfindingManager->getPathsToTile(hero, tile);

+ 4 - 35
AI/Nullkiller/AIhelper.h

@@ -14,8 +14,6 @@
 	!!!	Note: Include THIS file at the end of include list to avoid "undefined base class" error
 */
 
-#include "ResourceManager.h"
-#include "BuildingManager.h"
 #include "ArmyManager.h"
 #include "HeroManager.h"
 #include "Pathfinding/PathfindingManager.h"
@@ -24,14 +22,11 @@ class ResourceManager;
 class BuildingManager;
 
 
-//indirection interface for various modules
-class DLL_EXPORT AIhelper : public IResourceManager, public IBuildingManager, public IPathfindingManager, public IArmyManager, public IHeroManager
+//TODO: remove class, put managers to engine
+class DLL_EXPORT AIhelper : public IPathfindingManager, public IArmyManager, public IHeroManager
 {
-	friend class VCAI;
-	friend struct SetGlobalState; //mess?
-
-	std::shared_ptr<ResourceManager> resourceManager;
-	std::shared_ptr<BuildingManager> buildingManager;
+	//std::shared_ptr<ResourceManager> resourceManager;
+	//std::shared_ptr<BuildingManager> buildingManager;
 	std::shared_ptr<PathfindingManager> pathfindingManager;
 	std::shared_ptr<ArmyManager> armyManager;
 	std::shared_ptr<HeroManager> heroManager;
@@ -40,29 +35,6 @@ public:
 	AIhelper();
 	~AIhelper();
 
-	bool canAfford(const TResources & cost) const;
-	TResources reservedResources() const override;
-	TResources freeResources() const override;
-	TResource freeGold() const override;
-	TResources allResources() const override;
-	TResource allGold() const override;
-
-	Goals::TSubgoal whatToDo(TResources &res, Goals::TSubgoal goal) override;
-	Goals::TSubgoal whatToDo() const override;
-	bool containsObjective(Goals::TSubgoal goal) const override;
-	bool hasTasksLeft() const override;
-	bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) override;
-
-	bool getBuildingOptions(const CGTownInstance * t) override;
-	BuildingID getMaxPossibleGoldBuilding(const CGTownInstance * t);
-	boost::optional<PotentialBuilding> immediateBuilding() const override;
-	boost::optional<PotentialBuilding> expensiveBuilding() const override;
-	boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
-
-	Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
 	std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
 	std::vector<AIPath> getPathsToTile(const int3 & tile) const override;
 	void updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain = false) override;
@@ -95,9 +67,6 @@ public:
 
 	void update() override;
 
-private:
-	bool notifyGoalCompleted(Goals::TSubgoal goal) override;
-
 	void init(CPlayerSpecificInfoCallback * CB) override;
 	void setAI(VCAI * AI) override;
 };

+ 5 - 0
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.cpp

@@ -91,6 +91,11 @@ Goals::TGoalVec CaptureObjectsBehavior::getTasks()
 				if(ai->ah->getHeroRole(hero) == HeroRole::SCOUT && danger == 0 && path.exchangeCount > 1)
 					continue;
 
+				if(path.specialAction && !path.specialAction->canAct(path.targetHero))
+				{
+					auto subGoal = path.specialAction->whatToDo(path.targetHero);
+				}
+
 				auto isSafe = isSafeToVisit(hero, path.heroArmy, danger);
 				
 #ifdef AI_TRACE_LEVEL >= 2

+ 3 - 1
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -148,7 +148,9 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 		if(treatIsUnderControl)
 			continue;
 
-		if(cb->getResourceAmount(Res::GOLD) > GameConstants::HERO_GOLD_COST)
+		if(!town->visitingHero
+			&& town->hasBuilt(BuildingID::TAVERN)
+			&& cb->getResourceAmount(Res::GOLD) > GameConstants::HERO_GOLD_COST)
 		{
 			auto heroesInTavern = cb->getAvailableHeroes(town);
 

+ 2 - 0
AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp

@@ -56,6 +56,8 @@ Goals::TGoalVec GatherArmyBehavior::getTasks()
 	{
 		vstd::concatenate(tasks, upgradeArmy(town));
 	}
+
+	return tasks;
 }
 
 Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * hero) const

+ 0 - 257
AI/Nullkiller/BuildingManager.cpp

@@ -1,257 +0,0 @@
-/*
-* BuildingManager.cpp, part of VCMI engine
-*
-* Authors: listed in file AUTHORS in main folder
-*
-* License: GNU General Public License v2.0 or later
-* Full text of license available in license.txt file, in main folder
-*
-*/
-
-#include "StdInc.h"
-#include "BuildingManager.h"
-
-#include "../../CCallback.h"
-#include "../../lib/mapObjects/MapObjects.h"
-
-bool BuildingManager::tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays)
-{
-	if (maxDays == 0)
-	{
-		logAi->warn("Request to build building %d in 0 days!", building.toEnum());
-		return false;
-	}
-
-	if (!vstd::contains(t->town->buildings, building))
-		return false; // no such building in town
-
-	if (t->hasBuilt(building)) //Already built? Shouldn't happen in general
-		return true;
-
-	const CBuilding * buildPtr = t->town->buildings.at(building);
-
-	auto toBuild = buildPtr->requirements.getFulfillmentCandidates([&](const BuildingID & buildID)
-	{
-		return t->hasBuilt(buildID);
-	});
-	toBuild.push_back(building);
-
-	for (BuildingID buildID : toBuild)
-	{
-		EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
-		if (canBuild == EBuildingState::HAVE_CAPITAL || canBuild == EBuildingState::FORBIDDEN || canBuild == EBuildingState::NO_WATER)
-			return false; //we won't be able to build this
-	}
-
-	if (maxDays && toBuild.size() > maxDays)
-		return false;
-
-	//TODO: calculate if we have enough resources to build it in maxDays?
-
-	for (const auto & buildID : toBuild)
-	{
-		const CBuilding * b = t->town->buildings.at(buildID);
-
-		EBuildingState::EBuildingState canBuild = cb->canBuildStructure(t, buildID);
-		if (canBuild == EBuildingState::ALLOWED)
-		{
-			PotentialBuilding pb;
-			pb.bid = buildID;
-			pb.price = t->getBuildingCost(buildID);
-			immediateBuildings.push_back(pb); //these are checked again in try
-			return true;
-		}
-		else if (canBuild == EBuildingState::PREREQUIRES)
-		{
-			// can happen when dependencies have their own missing dependencies
-			if (tryBuildThisStructure(t, buildID, maxDays - 1))
-				return true;
-		}
-		else if (canBuild == EBuildingState::MISSING_BASE)
-		{
-			if (tryBuildThisStructure(t, b->upgrade, maxDays - 1))
-				return true;
-		}
-		else if (canBuild == EBuildingState::NO_RESOURCES)
-		{
-			//we may need to gather resources for those
-			PotentialBuilding pb;
-			pb.bid = buildID;
-			pb.price = t->getBuildingCost(buildID);
-			expensiveBuildings.push_back(pb); //these are checked again in try
-			return false;
-		}
-		else
-			return false;
-	}
-	return false;
-}
-
-bool BuildingManager::tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
-{
-	for (const auto & building : buildList)
-	{
-		if (t->hasBuilt(building))
-			continue;
-		return tryBuildThisStructure(t, building, maxDays);
-
-	}
-	return false; //Can't build anything
-}
-
-boost::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
-{
-	for (const auto & building : buildList)
-	{
-		if (t->hasBuilt(building))
-			continue;
-		switch (cb->canBuildStructure(t, building))
-		{
-			case EBuildingState::ALLOWED:
-			case EBuildingState::NO_RESOURCES: //TODO: allow this via optional parameter?
-				return boost::optional<BuildingID>(building);
-				break;
-		}
-	}
-	return boost::optional<BuildingID>(); //Can't build anything
-}
-
-bool BuildingManager::tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
-{
-	for (const auto & building : buildList)
-	{
-		if (t->hasBuilt(building))
-			continue;
-		return tryBuildThisStructure(t, building, maxDays);
-	}
-	return false; //Nothing to build
-}
-
-void BuildingManager::init(CPlayerSpecificInfoCallback * CB)
-{
-	cb = CB;
-}
-
-void BuildingManager::setAI(VCAI * AI)
-{
-	ai = AI;
-}
-//Set of buildings for different goals. Does not include any prerequisites.
-static const std::vector<BuildingID> essential = { BuildingID::TAVERN, BuildingID::TOWN_HALL };
-static const std::vector<BuildingID> basicGoldSource = { BuildingID::TOWN_HALL, BuildingID::CITY_HALL };
-static const std::vector<BuildingID> capitolAndRequirements = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::CAPITOL };
-static const std::vector<BuildingID> unitsSource = { BuildingID::DWELL_LVL_1, BuildingID::DWELL_LVL_2, BuildingID::DWELL_LVL_3,
-BuildingID::DWELL_LVL_4, BuildingID::DWELL_LVL_5, BuildingID::DWELL_LVL_6, BuildingID::DWELL_LVL_7 };
-static const std::vector<BuildingID> unitsUpgrade = { BuildingID::DWELL_LVL_1_UP, BuildingID::DWELL_LVL_2_UP, BuildingID::DWELL_LVL_3_UP,
-BuildingID::DWELL_LVL_4_UP, BuildingID::DWELL_LVL_5_UP, BuildingID::DWELL_LVL_6_UP, BuildingID::DWELL_LVL_7_UP };
-static const std::vector<BuildingID> unitGrowth = { BuildingID::FORT, BuildingID::CITADEL, BuildingID::CASTLE, BuildingID::HORDE_1,
-BuildingID::HORDE_1_UPGR, BuildingID::HORDE_2, BuildingID::HORDE_2_UPGR };
-static const std::vector<BuildingID> _spells = { BuildingID::MAGES_GUILD_1, BuildingID::MAGES_GUILD_2, BuildingID::MAGES_GUILD_3,
-BuildingID::MAGES_GUILD_4, BuildingID::MAGES_GUILD_5 };
-static const std::vector<BuildingID> extra = { BuildingID::RESOURCE_SILO, BuildingID::SPECIAL_1, BuildingID::SPECIAL_2, BuildingID::SPECIAL_3,
-BuildingID::SPECIAL_4, BuildingID::SHIPYARD }; // all remaining buildings
-
-bool BuildingManager::getBuildingOptions(const CGTownInstance * t)
-{
-	//TODO make *real* town development system
-	//TODO: faction-specific development: use special buildings, build dwellings in better order, etc
-	//TODO: build resource silo, defences when needed
-	//Possible - allow "locking" on specific building (build prerequisites and then building itself)
-	
-	//TODO: There is some disabled building code in GatherTroops and GatherArmy - take it into account when enhancing building. For now AI works best with building only via Build goal.
-
-	immediateBuildings.clear();
-	expensiveBuildings.clear();
-
-	//below algorithm focuses on economy growth at start of the game, saving money instead of build rushing is handled by Build goal
-	//changing code blocks order will alter behavior by changing order of adding elements to immediateBuildings / expensiveBuildings
-
-	TResources currentRes = cb->getResourceAmount();
-	TResources currentIncome = t->dailyIncome();
-
-	if(tryBuildAnyStructure(t, essential))
-		return true;
-
-	//the more gold the better and less problems later //TODO: what about building mage guild / marketplace etc. with city hall disabled in editor?
-	if(tryBuildNextStructure(t, basicGoldSource))
-		return true;
-
-	//workaround for mantis #2696 - build capitol with separate algorithm if it is available
-	if(vstd::contains(t->builtBuildings, BuildingID::CITY_HALL) && getMaxPossibleGoldBuilding(t) == BuildingID::CAPITOL)
-	{
-		if(tryBuildNextStructure(t, capitolAndRequirements))
-			return true;
-	}
-
-	if(!t->hasBuilt(BuildingID::FORT)) //in vast majority of situations fort is top priority building if we already have city hall, TODO: unite with unitGrowth building chain
-		if(tryBuildThisStructure(t, BuildingID::FORT))
-			return true;
-
-
-
-	if (cb->getDate(Date::DAY_OF_WEEK) > 6) // last 2 days of week - try to focus on growth
-	{
-		if (tryBuildNextStructure(t, unitGrowth, 2))
-			return true;
-	}
-
-	//try building dwellings
-	if (t->hasBuilt(BuildingID::FORT))
-	{
-		if (tryBuildAnyStructure(t, unitsSource, 8 - cb->getDate(Date::DAY_OF_WEEK)))
-			return true;
-	}
-
-	//try to upgrade dwelling
-	for (int i = 0; i < unitsUpgrade.size(); i++)
-	{
-		if (t->hasBuilt(unitsSource[i]) && !t->hasBuilt(unitsUpgrade[i]) && t->hasBuilt(BuildingID::FORT))
-		{
-			if (tryBuildThisStructure(t, unitsUpgrade[i]))
-				return true;
-		}
-	}
-
-	//remaining tasks
-	if (tryBuildNextStructure(t, _spells))
-		return true;
-	if (tryBuildAnyStructure(t, extra))
-		return true;
-
-	//at the end, try to get and build any extra buildings with nonstandard slots (for example HotA 3rd level dwelling)
-	std::vector<BuildingID> extraBuildings;
-	for (auto buildingInfo : t->town->buildings)
-	{
-		if (buildingInfo.first > 43)
-			extraBuildings.push_back(buildingInfo.first);
-	}
-	return tryBuildAnyStructure(t, extraBuildings);
-}
-
-BuildingID BuildingManager::getMaxPossibleGoldBuilding(const CGTownInstance * t)
-{
-	if(cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::HAVE_CAPITAL && cb->canBuildStructure(t, BuildingID::CAPITOL) != EBuildingState::FORBIDDEN)
-		return BuildingID::CAPITOL;
-	else if(cb->canBuildStructure(t, BuildingID::CITY_HALL) != EBuildingState::FORBIDDEN)
-		return BuildingID::CITY_HALL;
-	else if(cb->canBuildStructure(t, BuildingID::TOWN_HALL) != EBuildingState::FORBIDDEN)
-		return BuildingID::TOWN_HALL;
-	else
-		return BuildingID::VILLAGE_HALL;
-}
-
-boost::optional<PotentialBuilding> BuildingManager::immediateBuilding() const
-{
-	if (immediateBuildings.size())
-		return boost::optional<PotentialBuilding>(immediateBuildings.front()); //back? whatever
-	else
-		return boost::optional<PotentialBuilding>();
-}
-
-boost::optional<PotentialBuilding> BuildingManager::expensiveBuilding() const
-{
-	if (expensiveBuildings.size())
-		return boost::optional<PotentialBuilding>(expensiveBuildings.front());
-	else
-		return boost::optional<PotentialBuilding>();
-}

+ 0 - 75
AI/Nullkiller/BuildingManager.h

@@ -1,75 +0,0 @@
-/*
-* BuildingManager.h, part of VCMI engine
-*
-* Authors: listed in file AUTHORS in main folder
-*
-* License: GNU General Public License v2.0 or later
-* Full text of license available in license.txt file, in main folder
-*
-*/
-
-#pragma once
-
-#include "AIUtility.h"
-
-#include "../../lib/GameConstants.h"
-#include "../../lib/VCMI_Lib.h"
-#include "../../lib/CTownHandler.h"
-#include "../../lib/CBuildingHandler.h"
-#include "VCAI.h"
-
-struct DLL_EXPORT PotentialBuilding
-{
-	BuildingID bid;
-	TResources price;
-	//days to build?
-};
-
-class DLL_EXPORT IBuildingManager //: public: IAbstractManager
-{ //info about town development
-public:
-	virtual ~IBuildingManager() = default;
-	virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
-	virtual void setAI(VCAI * AI) = 0;
-
-	virtual bool getBuildingOptions(const CGTownInstance * t) = 0;
-	virtual boost::optional<PotentialBuilding> immediateBuilding() const = 0;
-	virtual boost::optional<PotentialBuilding> expensiveBuilding() const = 0;
-	virtual boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const = 0;
-};
-
-class DLL_EXPORT BuildingManager : public IBuildingManager
-{
-	friend class VCAI;
-	friend class AIhelper;
-	friend struct SetGlobalState;
-
-	CPlayerSpecificInfoCallback * cb; //this is enough, but we downcast from CCallback
-	VCAI * ai;
-
-public:
-
-	//try build anything in given town, and execute resulting Goal if any
-	bool getBuildingOptions(const CGTownInstance * t) override;
-	BuildingID getMaxPossibleGoldBuilding(const CGTownInstance * t);
-	boost::optional<PotentialBuilding> immediateBuilding() const override;
-	boost::optional<PotentialBuilding> expensiveBuilding() const override;
-	boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
-
-protected:
-
-	bool tryBuildAnyStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
-	//try build first unbuilt structure
-	bool tryBuildThisStructure(const CGTownInstance * t, BuildingID building, unsigned int maxDays = 7);
-	//try build ANY unbuilt structure
-	
-	bool tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays = 7);
-
-private:
-	//TODO: remember current town?
-	std::vector<PotentialBuilding> immediateBuildings; //what we can build right now in current town
-	std::vector<PotentialBuilding> expensiveBuildings; //what we coudl build but can't afford
-
-	void init(CPlayerSpecificInfoCallback * CB) override;
-	void setAI(VCAI * AI) override;
-};

+ 0 - 18
AI/Nullkiller/CMakeLists.txt

@@ -17,19 +17,12 @@ set(VCAI_SRCS
 		AIhelper.cpp
 		ArmyManager.cpp
 		HeroManager.cpp
-		ResourceManager.cpp
-		BuildingManager.cpp
-		SectorMap.cpp
-		BuildingManager.cpp
 		MapObjectsEvaluator.cpp
 		FuzzyEngines.cpp
 		FuzzyHelper.cpp
 		Goals/AbstractGoal.cpp
 		Goals/BuildBoat.cpp
-		Goals/Build.cpp
 		Goals/BuildThis.cpp
-		Goals/Explore.cpp
-		Goals/GatherArmy.cpp
 		Goals/DismissHero.cpp
 		Goals/GatherTroops.cpp
 		Goals/BuyArmy.cpp
@@ -41,8 +34,6 @@ set(VCAI_SRCS
 		Goals/CollectRes.cpp
 		Goals/Trade.cpp
 		Goals/RecruitHero.cpp
-		Goals/Conquer.cpp
-		Goals/ClearWayTo.cpp
 		Goals/DigAtTile.cpp
 		Goals/GetArtOfType.cpp
 		Goals/FindObj.cpp
@@ -85,10 +76,6 @@ set(VCAI_HEADERS
 		AIhelper.h
 		ArmyManager.h
 		HeroManager.h
-		ResourceManager.h
-		BuildingManager.h
-		SectorMap.h
-		BuildingManager.h
 		MapObjectsEvaluator.h
 		FuzzyEngines.h
 		FuzzyHelper.h
@@ -96,10 +83,7 @@ set(VCAI_HEADERS
 		Goals/CGoal.h
 		Goals/Invalid.h
 		Goals/BuildBoat.h
-		Goals/Build.h
 		Goals/BuildThis.h
-		Goals/Explore.h
-		Goals/GatherArmy.h
 		Goals/DismissHero.h
 		Goals/GatherTroops.h
 		Goals/BuyArmy.h
@@ -111,8 +95,6 @@ set(VCAI_HEADERS
 		Goals/CollectRes.h
 		Goals/Trade.h
 		Goals/RecruitHero.h
-		Goals/Conquer.h
-		Goals/ClearWayTo.h
 		Goals/DigAtTile.h
 		Goals/GetArtOfType.h
 		Goals/FindObj.h

+ 1 - 1
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -184,7 +184,7 @@ void Nullkiller::makeTurn()
 		}
 		catch(goalFulfilledException &)
 		{
-			logAi->trace(bestTask->completeMessage());
+			logAi->trace("Task %s completed", bestTask->name());
 		}
 		catch(std::exception & e)
 		{

+ 3 - 2
AI/Nullkiller/FuzzyEngines.cpp

@@ -23,7 +23,8 @@ extern FuzzyHelper * fh;
 
 engineBase::engineBase()
 {
-	engine.addRuleBlock(&rules);
+	rules = new fl::RuleBlock();
+	engine.addRuleBlock(rules);
 }
 
 void engineBase::configure()
@@ -34,7 +35,7 @@ void engineBase::configure()
 
 void engineBase::addRule(const std::string & txt)
 {
-	rules.addRule(fl::Rule::parse(txt, &engine));
+	rules->addRule(fl::Rule::parse(txt, &engine));
 }
 
 struct armyStructure

+ 1 - 1
AI/Nullkiller/FuzzyEngines.h

@@ -17,7 +17,7 @@ class engineBase //subclasses create fuzzylite variables with "new" that are not
 {
 protected:
 	fl::Engine engine;
-	fl::RuleBlock rules;
+	fl::RuleBlock * rules;
 	virtual void configure();
 	void addRule(const std::string & txt);
 public:

+ 0 - 166
AI/Nullkiller/FuzzyHelper.cpp

@@ -19,44 +19,6 @@ FuzzyHelper * fh;
 extern boost::thread_specific_ptr<VCAI> ai;
 extern boost::thread_specific_ptr<CCallback> cb;
 
-Goals::TSubgoal FuzzyHelper::chooseSolution(Goals::TGoalVec vec)
-{
-	if(vec.empty())
-	{
-		logAi->debug("FuzzyHelper found no goals. Returning Goals::Invalid.");
-
-		//no possibilities found
-		return sptr(Goals::Invalid());
-	}
-
-	//a trick to switch between heroes less often - calculatePaths is costly
-	auto sortByHeroes = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
-	{
-		return lhs->hero.h < rhs->hero.h;
-	};
-	boost::sort(vec, sortByHeroes);
-
-	for(auto g : vec)
-	{
-		setPriority(g);
-	}
-
-	auto compareGoals = [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
-	{
-		return lhs->priority < rhs->priority;
-	};
-
-	for(auto goal : vec)
-	{
-		logAi->trace("FuzzyHelper evaluated goal %s, priority=%.4f", goal->name(), goal->priority);
-	}
-
-	Goals::TSubgoal result = *boost::max_element(vec, compareGoals);
-
-	logAi->debug("FuzzyHelper returned goal %s, priority=%.4f", result->name(), result->priority);
-
-	return result;
-}
 
 ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
 {
@@ -77,134 +39,6 @@ ui64 FuzzyHelper::estimateBankDanger(const CBank * bank)
 
 }
 
-float FuzzyHelper::evaluate(Goals::VisitTile & g)
-{
-	if(g.parent)
-	{
-		g.parent->accept(this);
-	}
-
-	return visitTileEngine.evaluate(g);
-}
-
-float FuzzyHelper::evaluate(Goals::BuildBoat & g)
-{
-	const float buildBoatPenalty = 0.25;
-
-	if(!g.parent)
-	{
-		return 0;
-	}
-
-	return g.parent->accept(this) - buildBoatPenalty;
-}
-
-float FuzzyHelper::evaluate(Goals::AdventureSpellCast & g)
-{
-	if(!g.parent)
-	{
-		return 0;
-	}
-
-	const CSpell * spell = g.getSpell();
-	const float spellCastPenalty = (float)g.hero->getSpellCost(spell) / g.hero->mana;
-
-	return g.parent->accept(this) - spellCastPenalty;
-}
-
-float FuzzyHelper::evaluate(Goals::CompleteQuest & g)
-{
-	// TODO: How to evaluate quest complexity?
-	const float questPenalty = 0.2;
-
-	if(!g.parent)
-	{
-		return 0;
-	}
-
-	return g.parent->accept(this) * questPenalty;
-}
-
-float FuzzyHelper::evaluate(Goals::VisitObj & g)
-{
-	if(g.parent)
-	{
-		g.parent->accept(this);
-	}
-
-	return visitObjEngine.evaluate(g);
-}
-
-float FuzzyHelper::evaluate(Goals::VisitHero & g)
-{
-	auto obj = ai->myCb->getObj(ObjectInstanceID(g.objid)); //we assume for now that these goals are similar
-	if(!obj)
-		return -100; //hero died in the meantime
-	else
-	{
-		g.setpriority(Goals::VisitTile(obj->visitablePos()).sethero(g.hero).accept(this));
-	}
-	return g.priority;
-}
-float FuzzyHelper::evaluate(Goals::GatherArmy & g)
-{
-	//the more army we need, the more important goal
-	//the more army we lack, the less important goal
-	float army = g.hero->getArmyStrength();
-	float ratio = g.value / std::max(g.value - army, 2000.0f); //2000 is about the value of hero recruited from tavern
-	return 5 * (ratio / (ratio + 2)); //so 50% army gives 2.5, asymptotic 5
-}
-
-float FuzzyHelper::evaluate(Goals::ClearWayTo & g)
-{
-	if (!g.hero.h)
-		return 0; //lowest priority
-
-	return g.whatToDoToAchieve()->accept(this);
-}
-
-float FuzzyHelper::evaluate(Goals::BuildThis & g)
-{
-	return g.priority; //TODO
-}
-float FuzzyHelper::evaluate(Goals::DigAtTile & g)
-{
-	return 0;
-}
-float FuzzyHelper::evaluate(Goals::CollectRes & g)
-{
-	return g.priority; //handled by ResourceManager
-}
-float FuzzyHelper::evaluate(Goals::Build & g)
-{
-	return 0;
-}
-float FuzzyHelper::evaluate(Goals::BuyArmy & g)
-{
-	return g.priority;
-}
-float FuzzyHelper::evaluate(Goals::Explore & g)
-{
-	return 1;
-}
-float FuzzyHelper::evaluate(Goals::RecruitHero & g)
-{
-	return 1;
-}
-float FuzzyHelper::evaluate(Goals::Invalid & g)
-{
-	return -1e10;
-}
-float FuzzyHelper::evaluate(Goals::AbstractGoal & g)
-{
-	logAi->warn("Cannot evaluate goal %s", g.name());
-	return g.priority;
-}
-void FuzzyHelper::setPriority(Goals::TSubgoal & g) //calls evaluate - Visitor pattern
-{
-	g->setpriority(g->accept(this)); //this enforces returned value is set
-}
-
 ui64 FuzzyHelper::evaluateDanger(crint3 tile, const CGHeroInstance * visitor)
 {
 	return evaluateDanger(tile, visitor, ai.get());

+ 0 - 24
AI/Nullkiller/FuzzyHelper.h

@@ -16,33 +16,9 @@ class DLL_EXPORT FuzzyHelper
 {
 public:
 	TacticalAdvantageEngine tacticalAdvantageEngine;
-	VisitTileEngine visitTileEngine;
-	VisitObjEngine visitObjEngine;
-
-	float evaluate(Goals::Explore & g);
-	float evaluate(Goals::RecruitHero & g);
-	float evaluate(Goals::VisitTile & g);
-	float evaluate(Goals::VisitObj & g);
-	float evaluate(Goals::VisitHero & g);
-	float evaluate(Goals::BuildThis & g);
-	float evaluate(Goals::DigAtTile & g);
-	float evaluate(Goals::CollectRes & g);
-	float evaluate(Goals::Build & g);
-	float evaluate(Goals::BuyArmy & g);
-	float evaluate(Goals::BuildBoat & g);
-	float evaluate(Goals::GatherArmy & g);
-	float evaluate(Goals::ClearWayTo & g);
-	float evaluate(Goals::CompleteQuest & g);
-	float evaluate(Goals::AdventureSpellCast & g);
-	float evaluate(Goals::Invalid & g);
-	float evaluate(Goals::AbstractGoal & g);
-	void setPriority(Goals::TSubgoal & g);
 
 	ui64 estimateBankDanger(const CBank * bank); //TODO: move to another class?
 
-	Goals::TSubgoal chooseSolution(Goals::TGoalVec vec);
-	//std::shared_ptr<AbstractGoal> chooseSolution (std::vector<std::shared_ptr<AbstractGoal>> & vec);
-
 	ui64 evaluateDanger(const CGObjectInstance * obj, const VCAI * ai);
 	ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor, const VCAI * ai, bool checkGuards = true);
 	ui64 evaluateDanger(crint3 tile, const CGHeroInstance * visitor);

+ 0 - 58
AI/Nullkiller/Goals/AbstractGoal.cpp

@@ -12,8 +12,6 @@
 #include "../VCAI.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -115,63 +113,12 @@ bool AbstractGoal::operator==(const AbstractGoal & g) const
 	return false;
 }
 
-bool AbstractGoal::operator<(AbstractGoal & g) //for std::unique
-{
-	//TODO: make sure it gets goals consistent with == operator
-	if (goalType < g.goalType)
-		return true;
-	if (goalType > g.goalType)
-		return false;
-	if (hero < g.hero)
-		return true;
-	if (hero > g.hero)
-		return false;
-	if (tile < g.tile)
-		return true;
-	if (g.tile < tile)
-		return false;
-	if (objid < g.objid)
-		return true;
-	if (objid > g.objid)
-		return false;
-	if (town < g.town)
-		return true;
-	if (town > g.town)
-		return false;
-	if (value < g.value)
-		return true;
-	if (value > g.value)
-		return false;
-	if (priority < g.priority)
-		return true;
-	if (priority > g.priority)
-		return false;
-	if (resID < g.resID)
-		return true;
-	if (resID > g.resID)
-		return false;
-	if (bid < g.bid)
-		return true;
-	if (bid > g.bid)
-		return false;
-	if (aid < g.aid)
-		return true;
-	if (aid > g.aid)
-		return false;
-	return false;
-}
-
 //TODO: find out why the following are not generated automatically on MVS?
 bool TSubgoal::operator==(const TSubgoal & rhs) const
 {
 	return *get() == *rhs.get(); //comparison for Goals is overloaded, so they don't need to be identical to match
 }
 
-bool TSubgoal::operator<(const TSubgoal & rhs) const
-{
-	return get() < rhs.get(); //compae by value
-}
-
 bool AbstractGoal::invalid() const
 {
 	return goalType == EGoals::INVALID;
@@ -182,11 +129,6 @@ void AbstractGoal::accept(VCAI * ai)
 	ai->tryRealize(*this);
 }
 
-float AbstractGoal::accept(FuzzyHelper * f)
-{
-	return f->evaluate(*this);
-}
-
 EvaluationContext::EvaluationContext()
 	: movementCost(0.0),
 	manaCost(0),

+ 3 - 13
AI/Nullkiller/Goals/AbstractGoal.h

@@ -30,7 +30,6 @@ namespace Goals
 	class BuildThis;
 	class DigAtTile;
 	class CollectRes;
-	class Build;
 	class BuyArmy;
 	class BuildBoat;
 	class GatherArmy;
@@ -43,7 +42,8 @@ namespace Goals
 	enum EGoals
 	{
 		INVALID = -1,
-		WIN, CONQUER, BUILD, //build needs to get a real reasoning
+		WIN, CONQUER,
+		BUILD,
 		EXPLORE, GATHER_ARMY,
 		BOOST_HERO,
 		RECRUIT_HERO,
@@ -162,25 +162,15 @@ namespace Goals
 		EGoals goalType;
 
 		virtual std::string name() const;
-		virtual std::string completeMessage() const
-		{
-			return "This goal is unspecified!";
-		}
 
 		bool invalid() const;
 
 		///Visitor pattern
 		//TODO: make accept work for std::shared_ptr... somehow
 		virtual void accept(VCAI * ai); //unhandled goal will report standard error
-		virtual float accept(FuzzyHelper * f);
 
 		virtual bool operator==(const AbstractGoal & g) const;
-		bool operator<(AbstractGoal & g); //final
-		virtual bool fulfillsMe(Goals::TSubgoal goal) //TODO: multimethod instead of type check
-		{
-			return false; //use this method to check if goal is fulfilled by another (not equal) goal, operator == is handled spearately
-		}
-
+		
 		bool operator!=(const AbstractGoal & g) const
 		{
 			return !(*this == g);

+ 0 - 5
AI/Nullkiller/Goals/AdventureSpellCast.cpp

@@ -77,8 +77,3 @@ std::string AdventureSpellCast::name() const
 {
 	return "AdventureSpellCast " + spellID.toSpell()->name;
 }
-
-std::string AdventureSpellCast::completeMessage() const
-{
-	return "Spell casted successfully  " + spellID.toSpell()->name;
-}

+ 0 - 1
AI/Nullkiller/Goals/AdventureSpellCast.h

@@ -38,7 +38,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		void accept(VCAI * ai) override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const AdventureSpellCast & other) const override;
 	};
 }

+ 17 - 22
AI/Nullkiller/Goals/BuildBoat.cpp

@@ -26,23 +26,23 @@ bool BuildBoat::operator==(const BuildBoat & other) const
 	return shipyard->o->id == other.shipyard->o->id;
 }
 
-TSubgoal BuildBoat::whatToDoToAchieve()
-{
-	if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
-	{
-		return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
-	}
-
-	if(shipyard->shipyardStatus() != IShipyard::GOOD)
-	{
-		throw cannotFulfillGoalException("Shipyard is busy.");
-	}
-
-	TResources boatCost;
-	shipyard->getBoatCost(boatCost);
-
-	return ai->ah->whatToDo(boatCost, this->iAmElementar());
-}
+//TSubgoal BuildBoat::whatToDoToAchieve()
+//{
+//	if(cb->getPlayerRelations(ai->playerID, shipyard->o->tempOwner) == PlayerRelations::ENEMIES)
+//	{
+//		return fh->chooseSolution(ai->ah->howToVisitObj(shipyard->o));
+//	}
+//
+//	if(shipyard->shipyardStatus() != IShipyard::GOOD)
+//	{
+//		throw cannotFulfillGoalException("Shipyard is busy.");
+//	}
+//
+//	TResources boatCost;
+//	shipyard->getBoatCost(boatCost);
+//
+//	return ai->ah->whatToDo(boatCost, this->iAmElementar());
+//}
 
 void BuildBoat::accept(VCAI * ai)
 {
@@ -79,8 +79,3 @@ std::string BuildBoat::name() const
 {
 	return "BuildBoat";
 }
-
-std::string BuildBoat::completeMessage() const
-{
-	return "Boat have been built at " + shipyard->o->visitablePos().toString();
-}

+ 0 - 2
AI/Nullkiller/Goals/BuildBoat.h

@@ -28,10 +28,8 @@ namespace Goals
 		{
 			return TGoalVec();
 		}
-		TSubgoal whatToDoToAchieve() override;
 		void accept(VCAI * ai) override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const BuildBoat & other) const override;
 	};
 }

+ 1 - 45
AI/Nullkiller/Goals/BuildThis.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -34,46 +32,4 @@ bool BuildThis::operator==(const BuildThis & other) const
 std::string BuildThis::name() const
 {
 	return "Build " + buildingInfo.name + "(" + std::to_string(bid) + ") in " + town->name;
-}
-
-TSubgoal BuildThis::whatToDoToAchieve()
-{
-	auto b = BuildingID(bid);
-
-	// find town if not set
-	if(!town && hero)
-		town = hero->visitedTown;
-
-	if(!town)
-	{
-		for(const CGTownInstance * t : cb->getTownsInfo())
-		{
-			switch(cb->canBuildStructure(town, b))
-			{
-			case EBuildingState::ALLOWED:
-				town = t;
-				break; //TODO: look for prerequisites? this is not our reponsibility
-			default:
-				continue;
-			}
-		}
-	}
-
-	if(town) //we have specific town to build this
-	{
-		switch(cb->canBuildStructure(town, b))
-		{
-		case EBuildingState::ALLOWED:
-		case EBuildingState::NO_RESOURCES:
-		{
-			auto res = town->town->buildings.at(BuildingID(bid))->resources;
-			return ai->ah->whatToDo(res, iAmElementar()); //realize immediately or gather resources
-		}
-		break;
-		default:
-			throw cannotFulfillGoalException("Not possible to build");
-		}
-	}
-	else
-		throw cannotFulfillGoalException("Cannot find town to build this");
-}
+}

+ 0 - 6
AI/Nullkiller/Goals/BuildThis.h

@@ -47,12 +47,6 @@ namespace Goals
 			bid = Bid;
 			priority = 1;
 		}
-		TGoalVec getAllPossibleSubgoals() override
-		{
-			return TGoalVec();
-		}
-		TSubgoal whatToDoToAchieve() override;
-		//bool fulfillsMe(TSubgoal goal) override;
 		virtual bool operator==(const BuildThis & other) const override;
 		virtual std::string name() const override;
 	};

+ 2 - 16
AI/Nullkiller/Goals/BuyArmy.cpp

@@ -25,21 +25,7 @@ bool BuyArmy::operator==(const BuyArmy & other) const
 	return town == other.town && objid == other.objid;
 }
 
-bool BuyArmy::fulfillsMe(TSubgoal goal)
-{
-	//if (hero && hero != goal->hero)
-	//	return false;
-	return town == goal->town && goal->value >= value; //can always buy more army
-}
 TSubgoal BuyArmy::whatToDoToAchieve()
 {
-	//TODO: calculate the actual cost of units instead
-	TResources price;
-	price[Res::GOLD] = value * 0.4f; //some approximate value
-	return ai->ah->whatToDo(price, iAmElementar()); //buy right now or gather resources
-}
-
-std::string BuyArmy::completeMessage() const
-{
-	return boost::format("Bought army of value %d in town of %s") % value, town->name;
-}
+	return iAmElementar();
+}

+ 0 - 2
AI/Nullkiller/Goals/BuyArmy.h

@@ -32,10 +32,8 @@ namespace Goals
 			value = val; //expressed in AI unit strength
 			priority = 3;//TODO: evaluate?
 		}
-		bool fulfillsMe(TSubgoal goal) override;
 
 		TSubgoal whatToDoToAchieve() override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const BuyArmy & other) const override;
 	};
 }

+ 0 - 5
AI/Nullkiller/Goals/CGoal.h

@@ -51,11 +51,6 @@ namespace Goals
 			ai->tryRealize(static_cast<T &>(*this)); //casting enforces template instantiation
 		}
 
-		float accept(FuzzyHelper * f) override
-		{
-			return f->evaluate(static_cast<T &>(*this)); //casting enforces template instantiation
-		}
-
 		CGoal<T> * clone() const override
 		{
 			return new T(static_cast<T const &>(*this)); //casting enforces template instantiation

+ 143 - 157
AI/Nullkiller/Goals/CollectRes.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -35,80 +33,80 @@ TGoalVec CollectRes::getAllPossibleSubgoals()
 {
 	TGoalVec ret;
 
-	auto givesResource = [this](const CGObjectInstance * obj) -> bool
-	{
-		//TODO: move this logic to object side
-		//TODO: remember mithril exists
-		//TODO: water objects
-		//TODO: Creature banks
-
-		//return false first from once-visitable, before checking if they were even visited
-		switch (obj->ID.num)
-		{
-		case Obj::TREASURE_CHEST:
-			return resID == Res::GOLD;
-			break;
-		case Obj::RESOURCE:
-			return obj->subID == resID;
-			break;
-		case Obj::MINE:
-			return (obj->subID == resID &&
-				(cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
-			break;
-		case Obj::CAMPFIRE:
-			return true; //contains all resources
-			break;
-		case Obj::WINDMILL:
-			switch (resID)
-			{
-			case Res::GOLD:
-			case Res::WOOD:
-				return false;
-			}
-			break;
-		case Obj::WATER_WHEEL:
-			if (resID != Res::GOLD)
-				return false;
-			break;
-		case Obj::MYSTICAL_GARDEN:
-			if ((resID != Res::GOLD) && (resID != Res::GEMS))
-				return false;
-			break;
-		case Obj::LEAN_TO:
-		case Obj::WAGON:
-			if (resID != Res::GOLD)
-				return false;
-			break;
-		default:
-			return false;
-			break;
-		}
-		return !vstd::contains(ai->alreadyVisited, obj); //for weekly / once visitable
-	};
-
-	std::vector<const CGObjectInstance *> objs;
-	for (auto obj : ai->visitableObjs)
-	{
-		if (givesResource(obj))
-			objs.push_back(obj);
-	}
-	for (auto h : cb->getHeroesInfo())
-	{
-		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
-
-		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
-		{
-			if (givesResource(obj))
-				ourObjs.push_back(obj);
-		}
-
-		for (auto obj : ourObjs)
-		{
-			auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
-
-			vstd::concatenate(ret, waysToGo);
-		}
-	}
+	//auto givesResource = [this](const CGObjectInstance * obj) -> bool
+	//{
+	//	//TODO: move this logic to object side
+	//	//TODO: remember mithril exists
+	//	//TODO: water objects
+	//	//TODO: Creature banks
+
+	//	//return false first from once-visitable, before checking if they were even visited
+	//	switch (obj->ID.num)
+	//	{
+	//	case Obj::TREASURE_CHEST:
+	//		return resID == Res::GOLD;
+	//		break;
+	//	case Obj::RESOURCE:
+	//		return obj->subID == resID;
+	//		break;
+	//	case Obj::MINE:
+	//		return (obj->subID == resID &&
+	//			(cb->getPlayerRelations(obj->tempOwner, ai->playerID) == PlayerRelations::ENEMIES)); //don't capture our mines
+	//		break;
+	//	case Obj::CAMPFIRE:
+	//		return true; //contains all resources
+	//		break;
+	//	case Obj::WINDMILL:
+	//		switch (resID)
+	//		{
+	//		case Res::GOLD:
+	//		case Res::WOOD:
+	//			return false;
+	//		}
+	//		break;
+	//	case Obj::WATER_WHEEL:
+	//		if (resID != Res::GOLD)
+	//			return false;
+	//		break;
+	//	case Obj::MYSTICAL_GARDEN:
+	//		if ((resID != Res::GOLD) && (resID != Res::GEMS))
+	//			return false;
+	//		break;
+	//	case Obj::LEAN_TO:
+	//	case Obj::WAGON:
+	//		if (resID != Res::GOLD)
+	//			return false;
+	//		break;
+	//	default:
+	//		return false;
+	//		break;
+	//	}
+	//	return !vstd::contains(ai->alreadyVisited, obj); //for weekly / once visitable
+	//};
+
+	//std::vector<const CGObjectInstance *> objs;
+	//for (auto obj : ai->visitableObjs)
+	//{
+	//	if (givesResource(obj))
+	//		objs.push_back(obj);
+	//}
+	//for (auto h : cb->getHeroesInfo())
+	//{
+	//	std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
+
+	//	for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
+	//	{
+	//		if (givesResource(obj))
+	//			ourObjs.push_back(obj);
+	//	}
+
+	//	for (auto obj : ourObjs)
+	//	{
+	//		auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
+
+	//		vstd::concatenate(ret, waysToGo);
+	//	}
+	//}
 	return ret;
 }
 
@@ -119,90 +117,78 @@ TSubgoal CollectRes::whatToDoToAchieve()
 	if (!trade->invalid())
 		goals.push_back(trade);
 
-	if (goals.empty())
-		return sptr(Explore()); //we can always do that
-	else
-		return fh->chooseSolution(goals); //TODO: evaluate trading
+	return sptr(Invalid()); //we can always do that
 }
 
 TSubgoal CollectRes::whatToDoToTrade()
 {
-	std::vector<const IMarket *> markets;
-
-	std::vector<const CGObjectInstance *> visObjs;
-	ai->retrieveVisitableObjs(visObjs, true);
-	for (const CGObjectInstance * obj : visObjs)
-	{
-		if (const IMarket * m = IMarket::castFrom(obj, false))
-		{
-			if (obj->ID == Obj::TOWN && obj->tempOwner == ai->playerID && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE))
-				markets.push_back(m);
-			else if (obj->ID == Obj::TRADING_POST)
-				markets.push_back(m);
-		}
-	}
-
-	boost::sort(markets, [](const IMarket * m1, const IMarket * m2) -> bool
-	{
-		return m1->getMarketEfficiency() < m2->getMarketEfficiency();
-	});
-
-	markets.erase(boost::remove_if(markets, [](const IMarket * market) -> bool
-	{
-		if (!(market->o->ID == Obj::TOWN && market->o->tempOwner == ai->playerID))
-		{
-			if (!ai->isAccessible(market->o->visitablePos()))
-				return true;
-		}
-		return false;
-	}), markets.end());
-
-	if (!markets.size())
-	{
-		for (const CGTownInstance * t : cb->getTownsInfo())
-		{
-			if (cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED)
-				return sptr(BuildThis(BuildingID::MARKETPLACE, t).setpriority(2));
-		}
-	}
-	else
-	{
-		const IMarket * m = markets.back();
-		//attempt trade at back (best prices)
-		int howManyCanWeBuy = 0;
-		for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
-		{
-			if (i == resID)
-				continue;
-			int toGive = -1, toReceive = -1;
-			m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
-			assert(toGive > 0 && toReceive > 0);
-			howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
-		}
-
-		if (howManyCanWeBuy >= value)
-		{
-			auto backObj = cb->getTopObj(m->o->visitablePos()); //it'll be a hero if we have one there; otherwise marketplace
-			assert(backObj);
-			auto objid = m->o->id.getNum();
-			if (backObj->tempOwner != ai->playerID) //top object not owned
-			{
-				return sptr(VisitObj(objid)); //just go there
-			}
-			else //either it's our town, or we have hero there
-			{
-				return sptr(Trade(resID, value, objid).setisElementar(true)); //we can do this immediately
-			}
-		}
-	}
+	//std::vector<const IMarket *> markets;
+
+	//std::vector<const CGObjectInstance *> visObjs;
+	//ai->retrieveVisitableObjs(visObjs, true);
+	//for (const CGObjectInstance * obj : visObjs)
+	//{
+	//	if (const IMarket * m = IMarket::castFrom(obj, false))
+	//	{
+	//		if (obj->ID == Obj::TOWN && obj->tempOwner == ai->playerID && m->allowsTrade(EMarketMode::RESOURCE_RESOURCE))
+	//			markets.push_back(m);
+	//		else if (obj->ID == Obj::TRADING_POST)
+	//			markets.push_back(m);
+	//	}
+	//}
+
+	//boost::sort(markets, [](const IMarket * m1, const IMarket * m2) -> bool
+	//{
+	//	return m1->getMarketEfficiency() < m2->getMarketEfficiency();
+	//});
+
+	//markets.erase(boost::remove_if(markets, [](const IMarket * market) -> bool
+	//{
+	//	if (!(market->o->ID == Obj::TOWN && market->o->tempOwner == ai->playerID))
+	//	{
+	//		if (!ai->isAccessible(market->o->visitablePos()))
+	//			return true;
+	//	}
+	//	return false;
+	//}), markets.end());
+
+	//if (!markets.size())
+	//{
+	//	for (const CGTownInstance * t : cb->getTownsInfo())
+	//	{
+	//		if (cb->canBuildStructure(t, BuildingID::MARKETPLACE) == EBuildingState::ALLOWED)
+	//			return sptr(BuildThis(BuildingID::MARKETPLACE, t).setpriority(2));
+	//	}
+	//}
+	//else
+	//{
+	//	const IMarket * m = markets.back();
+	//	//attempt trade at back (best prices)
+	//	int howManyCanWeBuy = 0;
+	//	for (Res::ERes i = Res::WOOD; i <= Res::GOLD; vstd::advance(i, 1))
+	//	{
+	//		if (i == resID)
+	//			continue;
+	//		int toGive = -1, toReceive = -1;
+	//		m->getOffer(i, resID, toGive, toReceive, EMarketMode::RESOURCE_RESOURCE);
+	//		assert(toGive > 0 && toReceive > 0);
+	//		howManyCanWeBuy += toReceive * (ai->ah->freeResources()[i] / toGive);
+	//	}
+
+	//	if (howManyCanWeBuy >= value)
+	//	{
+	//		auto backObj = cb->getTopObj(m->o->visitablePos()); //it'll be a hero if we have one there; otherwise marketplace
+	//		assert(backObj);
+	//		auto objid = m->o->id.getNum();
+	//		if (backObj->tempOwner != ai->playerID) //top object not owned
+	//		{
+	//			return sptr(VisitObj(objid)); //just go there
+	//		}
+	//		else //either it's our town, or we have hero there
+	//		{
+	//			return sptr(Trade(resID, value, objid).setisElementar(true)); //we can do this immediately
+	//		}
+	//	}
+	//}
 	return sptr(Invalid()); //cannot trade
 }
-
-bool CollectRes::fulfillsMe(TSubgoal goal)
-{
-	if (goal->resID == resID)
-		if (goal->value >= value)
-			return true;
-
-	return false;
-}

+ 0 - 1
AI/Nullkiller/Goals/CollectRes.h

@@ -34,7 +34,6 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		TSubgoal whatToDoToTrade();
-		bool fulfillsMe(TSubgoal goal) override; //TODO: Trade
 		virtual bool operator==(const CollectRes & other) const override;
 	};
 }

+ 8 - 14
AI/Nullkiller/Goals/CompleteQuest.cpp

@@ -82,9 +82,8 @@ TSubgoal CompleteQuest::whatToDoToAchieve()
 
 	TGoalVec solutions = getAllPossibleSubgoals();
 
-	if(solutions.empty())
-		throw cannotFulfillGoalException("Can not complete quest " + questToString());
-
+	throw cannotFulfillGoalException("Can not complete quest " + questToString());
+/*
 	TSubgoal result = fh->chooseSolution(solutions);
 
 	logAi->trace(
@@ -94,7 +93,7 @@ TSubgoal CompleteQuest::whatToDoToAchieve()
 		result->objid,
 		result->hero.validAndSet() ? result->hero->name : "not specified");
 
-	return result;
+	return result;*/
 }
 
 std::string CompleteQuest::name() const
@@ -102,11 +101,6 @@ std::string CompleteQuest::name() const
 	return "CompleteQuest";
 }
 
-std::string CompleteQuest::completeMessage() const
-{
-	return "Completed quest " + questToString();
-}
-
 std::string CompleteQuest::questToString() const
 {
 	if(q.quest->missionType == CQuest::MISSION_NONE)
@@ -128,7 +122,7 @@ TGoalVec CompleteQuest::tryCompleteQuest() const
 	{
 		if(q.quest->checkQuest(hero))
 		{
-			vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.obj->id)));
+			//vstd::concatenate(solutions, ai->ah->howToVisitObj(hero, ObjectIdRef(q.obj->id)));
 		}
 	}
 
@@ -228,7 +222,7 @@ TGoalVec CompleteQuest::missionResources() const
 	{
 		if(q.quest->checkQuest(heroes.front())) //it doesn't matter which hero it is
 		{
-			return ai->ah->howToVisitObj(q.obj);
+			return solutions;// ai->ah->howToVisitObj(q.obj);
 		}
 		else
 		{
@@ -254,7 +248,7 @@ TGoalVec CompleteQuest::missionDestroyObj() const
 	auto obj = cb->getObjByQuestIdentifier(q.quest->m13489val);
 
 	if(!obj)
-		return ai->ah->howToVisitObj(q.obj);
+		return solutions;// ai->ah->howToVisitObj(q.obj);
 
 	if(obj->ID == Obj::HERO)
 	{
@@ -264,11 +258,11 @@ TGoalVec CompleteQuest::missionDestroyObj() const
 		{
 			auto heroToProtect = cb->getHero(obj->id);
 
-			solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
+			//solutions.push_back(sptr(GatherArmy().sethero(heroToProtect)));
 		}
 		else if(relations == PlayerRelations::ENEMIES)
 		{
-			solutions = ai->ah->howToVisitObj(obj);
+			//solutions = ai->ah->howToVisitObj(obj);
 		}
 	}
 

+ 0 - 1
AI/Nullkiller/Goals/CompleteQuest.h

@@ -28,7 +28,6 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const CompleteQuest & other) const override;
 
 	private:

+ 0 - 5
AI/Nullkiller/Goals/DismissHero.cpp

@@ -48,8 +48,3 @@ std::string DismissHero::name() const
 {
 	return "DismissHero " + hero.name;
 }
-
-std::string DismissHero::completeMessage() const
-{
-	return "Hero dismissed successfully " + hero.name;
-}

+ 0 - 1
AI/Nullkiller/Goals/DismissHero.h

@@ -30,7 +30,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		void accept(VCAI * ai) override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const DismissHero & other) const override;
 	};
 }

+ 0 - 5
AI/Nullkiller/Goals/ExchangeSwapTownHeroes.cpp

@@ -36,11 +36,6 @@ std::string ExchangeSwapTownHeroes::name() const
 	return "Exchange and swap heroes of " + town->name;
 }
 
-std::string ExchangeSwapTownHeroes::completeMessage() const
-{
-	return "Exchange and swap heroes of " + town->name + " compelete";
-}
-
 bool ExchangeSwapTownHeroes::operator==(const ExchangeSwapTownHeroes & other) const
 {
 	return town == other.town;

+ 0 - 1
AI/Nullkiller/Goals/ExchangeSwapTownHeroes.h

@@ -35,7 +35,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		void accept(VCAI * ai) override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const ExchangeSwapTownHeroes & other) const override;
 	};
 }

+ 22 - 25
AI/Nullkiller/Goals/ExecuteHeroChain.cpp

@@ -72,27 +72,29 @@ void ExecuteHeroChain::accept(VCAI * ai)
 	{
 		auto & node = chainPath.nodes[i];
 
-		HeroPtr hero = node.targetHero;
+		const CGHeroInstance * hero = node.targetHero;
+		HeroPtr heroPtr = hero;
 
 		if(vstd::contains(blockedIndexes, i))
 		{
 			blockedIndexes.insert(node.parentIndex);
-			ai->nullkiller->lockHero(hero.get(), HeroLockedReason::HERO_CHAIN);
+			ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN);
 
 			continue;
 		}
 
-		logAi->debug("Executing chain node %d. Moving hero %s to %s", i, hero.name, node.coord.toString());
+		logAi->debug("Executing chain node %d. Moving hero %s to %s", i, hero->name, node.coord.toString());
 
 		try
 		{
 			if(hero->movement)
 			{
-				ai->nullkiller->setActive(hero.get(), node.coord);
+
+				ai->nullkiller->setActive(hero, node.coord);
 
 				if(node.specialAction)
 				{
-					if(node.specialAction->canAct(hero.get()))
+					if(node.specialAction->canAct(hero))
 					{
 						auto specialGoal = node.specialAction->whatToDo(hero);
 
@@ -100,12 +102,12 @@ void ExecuteHeroChain::accept(VCAI * ai)
 					}
 					else
 					{
-						//TODO: decompose
+						throw cannotFulfillGoalException("Path is nondeterministic.");
 					}
-
-					if(!hero.validAndSet())
+					
+					if(!heroPtr.validAndSet())
 					{
-						logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", hero.name);
+						logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", heroPtr.name);
 
 						return;
 					}
@@ -113,7 +115,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
 
 				if(node.turns == 0 && node.coord != hero->visitablePos())
 				{
-					auto targetNode = cb->getPathsInfo(hero.get())->getPathInfo(node.coord);
+					auto targetNode = cb->getPathsInfo(hero)->getPathInfo(node.coord);
 
 					if(targetNode->accessible == CGPathNode::EAccessibility::NOT_SET
 						|| targetNode->accessible == CGPathNode::EAccessibility::BLOCKED
@@ -122,7 +124,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
 					{
 						logAi->error(
 							"Enable to complete chain. Expected hero %s to arive to %s in 0 turns but he can not do this",
-							hero.name,
+							hero->name,
 							node.coord.toString());
 
 						return;
@@ -137,9 +139,9 @@ void ExecuteHeroChain::accept(VCAI * ai)
 					}
 					catch(cannotFulfillGoalException)
 					{
-						if(!hero.validAndSet())
+						if(!heroPtr.validAndSet())
 						{
-							logAi->error("Hero %s was lost. Exit hero chain.", hero.name);
+							logAi->error("Hero %s was lost. Exit hero chain.", heroPtr.name);
 
 							return;
 						}
@@ -147,13 +149,13 @@ void ExecuteHeroChain::accept(VCAI * ai)
 						if(hero->movement > 0)
 						{
 							CGPath path;
-							bool isOk = cb->getPathsInfo(hero.get())->getPath(path, node.coord);
+							bool isOk = cb->getPathsInfo(hero)->getPath(path, node.coord);
 
 							if(isOk && path.nodes.back().turns > 0)
 							{
-								logAi->warn("Hero %s has %d mp which is not enough to continue his way towards %s.", hero.name, hero->movement, node.coord.toString());
+								logAi->warn("Hero %s has %d mp which is not enough to continue his way towards %s.", hero->name, hero->movement, node.coord.toString());
 
-								ai->nullkiller->lockHero(hero.get(), HeroLockedReason::HERO_CHAIN);
+								ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN);
 								return;
 							}
 						}
@@ -170,7 +172,7 @@ void ExecuteHeroChain::accept(VCAI * ai)
 			{
 				logAi->error(
 					"Enable to complete chain. Expected hero %s to arive to %s but he is at %s", 
-					hero.name, 
+					hero->name, 
 					node.coord.toString(),
 					hero->visitablePos().toString());
 
@@ -178,14 +180,14 @@ void ExecuteHeroChain::accept(VCAI * ai)
 			}
 			
 			// no exception means we were not able to rich the tile
-			ai->nullkiller->lockHero(hero.get(), HeroLockedReason::HERO_CHAIN);
+			ai->nullkiller->lockHero(hero, HeroLockedReason::HERO_CHAIN);
 			blockedIndexes.insert(node.parentIndex);
 		}
 		catch(goalFulfilledException)
 		{
-			if(!hero)
+			if(!heroPtr.validAndSet())
 			{
-				logAi->debug("Hero %s was killed while attempting to rich %s", hero.name, node.coord.toString());
+				logAi->debug("Hero %s was killed while attempting to rich %s", heroPtr.name, node.coord.toString());
 
 				return;
 			}
@@ -196,9 +198,4 @@ void ExecuteHeroChain::accept(VCAI * ai)
 std::string ExecuteHeroChain::name() const
 {
 	return "ExecuteHeroChain " + targetName + " by " + chainPath.targetHero->name;
-}
-
-std::string ExecuteHeroChain::completeMessage() const
-{
-	return "Hero chain completed";
 }

+ 0 - 1
AI/Nullkiller/Goals/ExecuteHeroChain.h

@@ -30,7 +30,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		void accept(VCAI * ai) override;
 		std::string name() const override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const ExecuteHeroChain & other) const override;
 		const AIPath & getPath() const { return chainPath; }
 	};

+ 1 - 18
AI/Nullkiller/Goals/Explore.cpp

@@ -233,14 +233,9 @@ bool Explore::operator==(const Explore & other) const
 	return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy;
 }
 
-std::string Explore::completeMessage() const
-{
-	return "Hero " + hero.get()->name + " completed exploration";
-}
-
 TSubgoal Explore::whatToDoToAchieve()
 {
-	return fh->chooseSolution(getAllPossibleSubgoals());
+	return sptr(Goals::Invalid());
 }
 
 TGoalVec Explore::getAllPossibleSubgoals()
@@ -361,18 +356,6 @@ TGoalVec Explore::getAllPossibleSubgoals()
 	return ret;
 }
 
-bool Explore::fulfillsMe(TSubgoal goal)
-{
-	if(goal->goalType == EXPLORE)
-	{
-		if(goal->hero)
-			return hero == goal->hero;
-		else
-			return true; //cancel ALL exploration
-	}
-	return false;
-}
-
 TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const
 {
 	ExplorationHelper scanResult(h, allowGatherArmy);

+ 64 - 66
AI/Nullkiller/Goals/Explore.h

@@ -1,66 +1,64 @@
-/*
-* Explore.h, part of VCMI engine
-*
-* Authors: listed in file AUTHORS in main folder
-*
-* License: GNU General Public License v2.0 or later
-* Full text of license available in license.txt file, in main folder
-*
-*/
-#pragma once
-
-#include "CGoal.h"
-
-struct HeroPtr;
-class VCAI;
-class FuzzyHelper;
-
-namespace Goals
-{
-	struct ExplorationHelper;
-
-	class DLL_EXPORT Explore : public CGoal<Explore>
-	{
-	private:
-		bool allowGatherArmy;
-
-	public:
-		Explore(bool allowGatherArmy)
-			: CGoal(Goals::EXPLORE), allowGatherArmy(allowGatherArmy)
-		{
-			priority = 1;
-		}
-
-		Explore()
-			: Explore(true)
-		{
-		}
-
-		Explore(HeroPtr h)
-			: CGoal(Goals::EXPLORE)
-		{
-			hero = h;
-			priority = 1;
-		}
-		TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;
-		std::string completeMessage() const override;
-		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const Explore & other) const override;
-
-	private:
-		TSubgoal exploreNearestNeighbour(HeroPtr h) const;
-		TSubgoal explorationNewPoint(HeroPtr h) const;
-		TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const;
-		void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const;
-		bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
-
-		void getVisibleNeighbours(
-			const std::vector<int3> & tiles,
-			std::vector<int3> & out,
-			CCallback * cbp,
-			const TeamState * ts) const;
-
-		int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const;
-	};
-}
+///*
+//* Explore.h, part of VCMI engine
+//*
+//* Authors: listed in file AUTHORS in main folder
+//*
+//* License: GNU General Public License v2.0 or later
+//* Full text of license available in license.txt file, in main folder
+//*
+//*/
+//#pragma once
+//
+//#include "CGoal.h"
+//
+//struct HeroPtr;
+//class VCAI;
+//class FuzzyHelper;
+//
+//namespace Goals
+//{
+//	struct ExplorationHelper;
+//
+//	class DLL_EXPORT Explore : public CGoal<Explore>
+//	{
+//	private:
+//		bool allowGatherArmy;
+//
+//	public:
+//		Explore(bool allowGatherArmy)
+//			: CGoal(Goals::EXPLORE), allowGatherArmy(allowGatherArmy)
+//		{
+//			priority = 1;
+//		}
+//
+//		Explore()
+//			: Explore(true)
+//		{
+//		}
+//
+//		Explore(HeroPtr h)
+//			: CGoal(Goals::EXPLORE)
+//		{
+//			hero = h;
+//			priority = 1;
+//		}
+//		TGoalVec getAllPossibleSubgoals() override;
+//		TSubgoal whatToDoToAchieve() override;
+//		virtual bool operator==(const Explore & other) const override;
+//
+//	private:
+//		TSubgoal exploreNearestNeighbour(HeroPtr h) const;
+//		TSubgoal explorationNewPoint(HeroPtr h) const;
+//		TSubgoal explorationBestNeighbour(int3 hpos, HeroPtr h) const;
+//		void explorationScanTile(const int3 & tile, ExplorationHelper & scanResult) const;
+//		bool hasReachableNeighbor(const int3 &pos, HeroPtr hero, CCallback * cbp, VCAI * vcai) const;
+//
+//		void getVisibleNeighbours(
+//			const std::vector<int3> & tiles,
+//			std::vector<int3> & out,
+//			CCallback * cbp,
+//			const TeamState * ts) const;
+//
+//		int howManyTilesWillBeDiscovered(const int3 & pos, ExplorationHelper & scanResult) const;
+//	};
+//}

+ 1 - 17
AI/Nullkiller/Goals/FindObj.cpp

@@ -10,7 +10,6 @@
 #include "StdInc.h"
 #include "FindObj.h"
 #include "VisitObj.h"
-#include "Explore.h"
 #include "../VCAI.h"
 #include "../AIUtility.h"
 
@@ -52,19 +51,4 @@ TSubgoal FindObj::whatToDoToAchieve()
 	}
 	if(o && ai->isAccessible(o->pos)) //we don't use isAccessibleForHero as we don't know which hero it is
 		return sptr(VisitObj(o->id.getNum()));
-	else
-		return sptr(Explore());
-}
-
-bool FindObj::fulfillsMe(TSubgoal goal)
-{
-	if (goal->goalType == VISIT_TILE) //visiting tile visits object at same time
-	{
-		if (!hero || hero == goal->hero)
-			for (auto obj : cb->getVisitableObjs(goal->tile)) //check if any object on that tile matches criteria
-				if (obj->visitablePos() == goal->tile) //object could be removed
-					if (obj->ID == objid && obj->subID == resID) //same type and subtype
-						return true;
-	}
-	return false;
-}
+}

+ 0 - 1
AI/Nullkiller/Goals/FindObj.h

@@ -41,7 +41,6 @@ namespace Goals
 			return TGoalVec();
 		}
 		TSubgoal whatToDoToAchieve() override;
-		bool fulfillsMe(TSubgoal goal) override;
 		virtual bool operator==(const FindObj & other) const override;
 	};
 }

+ 68 - 76
AI/Nullkiller/Goals/GatherTroops.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -62,12 +60,7 @@ TSubgoal GatherTroops::whatToDoToAchieve()
 		}
 	}
 
-	TGoalVec solutions = getAllPossibleSubgoals();
-
-	if(solutions.empty())
-		return sptr(Explore());
-
-	return fh->chooseSolution(solutions);
+	return sptr(Invalid());
 }
 
 
@@ -75,75 +68,74 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
 {
 	TGoalVec solutions;
 
-	for(const CGTownInstance * t : cb->getTownsInfo())
-	{
-		int count = getCreaturesCount(t->getUpperArmy());
-
-		if(count >= this->value)
-		{
-			if(t->visitingHero)
-			{
-				solutions.push_back(sptr(VisitObj(t->id.getNum()).sethero(t->visitingHero.get())));
-			}
-			else
-			{
-				vstd::concatenate(solutions, ai->ah->howToVisitObj(t));
-			}
-
-			continue;
-		}
-
-		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) && ai->ah->freeResources().canAfford(creature->cost)) //this assumes only creatures with dwellings are assigned to faction
-			{
-				solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
-			}
-			/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
-			{	
-				return sptr(BuildThis(bid, t).setpriority(priority));
-			}*/
-		}
-	}
-	for(auto obj : ai->visitableObjs)
-	{
-		auto d = dynamic_cast<const CGDwelling *>(obj);
-
-		if(!d || obj->ID == Obj::TOWN)
-			continue;
-
-		for(auto creature : d->creatures)
-		{
-			if(creature.first) //there are more than 0 creatures avaliabe
-			{
-				for(auto type : creature.second)
-				{
-					if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
-						vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
-				}
-			}
-		}
-	}
+	//for(const CGTownInstance * t : cb->getTownsInfo())
+	//{
+	//	int count = getCreaturesCount(t->getUpperArmy());
+
+	//	if(count >= this->value)
+	//	{
+	//		if(t->visitingHero)
+	//		{
+	//			solutions.push_back(sptr(VisitObj(t->id.getNum()).sethero(t->visitingHero.get())));
+	//		}
+	//		else
+	//		{
+	//			vstd::concatenate(solutions, ai->ah->howToVisitObj(t));
+	//		}
+
+	//		continue;
+	//	}
+
+	//	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) && ai->ah->freeResources().canAfford(creature->cost)) //this assumes only creatures with dwellings are assigned to faction
+	//		{
+	//			solutions.push_back(sptr(BuyArmy(t, creature->AIValue * this->value).setobjid(objid)));
+	//		}
+	//		/*else //disable random building requests for now - this code needs to know a lot of town/resource context to do more good than harm
+	//		{	
+	//			return sptr(BuildThis(bid, t).setpriority(priority));
+	//		}*/
+	//	}
+	//}
+
+	//for(auto obj : ai->visitableObjs)
+	//{
+	//	auto d = dynamic_cast<const CGDwelling *>(obj);
+
+	//	if(!d || obj->ID == Obj::TOWN)
+	//		continue;
+
+	//	for(auto creature : d->creatures)
+	//	{
+	//		if(creature.first) //there are more than 0 creatures avaliabe
+	//		{
+	//			for(auto type : creature.second)
+	//			{
+	//				if(type == objid && ai->ah->freeResources().canAfford(VLC->creh->creatures[type]->cost))
+	//					vstd::concatenate(solutions, ai->ah->howToVisitObj(obj));
+	//			}
+	//		}
+	//	}
+	//}
+
+	//CreatureID creID = CreatureID(objid);
+
+	//vstd::erase_if(solutions, [&](TSubgoal goal)->bool
+	//{
+	//	return goal->hero && !goal->hero->getSlotFor(creID).validSlot() && !goal->hero->getFreeSlot().validSlot();
+	//});
 
 	return solutions;
 	//TODO: exchange troops between heroes
 }
-
-bool GatherTroops::fulfillsMe(TSubgoal goal)
-{
-	if (!hero || hero == goal->hero) //we got army for desired hero or any hero
-		if (goal->objid == objid) //same creature type //TODO: consider upgrades?
-			if (goal->value >= value) //notify every time we get resources?
-				return true;
-	return false;
-}

+ 0 - 1
AI/Nullkiller/Goals/GatherTroops.h

@@ -34,7 +34,6 @@ namespace Goals
 		}
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
-		bool fulfillsMe(TSubgoal goal) override;
 		virtual bool operator==(const GatherTroops & other) const override;
 
 	private:

+ 0 - 5
AI/Nullkiller/Goals/Goals.h

@@ -12,22 +12,17 @@
 #include "CGoal.h"
 #include "Invalid.h"
 #include "BuildBoat.h"
-#include "Build.h"
 #include "BuildThis.h"
-#include "Conquer.h"
-#include "GatherArmy.h"
 #include "Win.h"
 #include "VisitObj.h"
 #include "VisitTile.h"
 #include "VisitHero.h"
-#include "Explore.h"
 #include "BuyArmy.h"
 #include "GatherTroops.h"
 #include "Trade.h"
 #include "CollectRes.h"
 #include "RecruitHero.h"
 #include "GetArtOfType.h"
-#include "ClearWayTo.h"
 #include "DigAtTile.h"
 #include "FindObj.h"
 #include "CompleteQuest.h"

+ 0 - 13
AI/Nullkiller/Goals/RecruitHero.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -25,14 +23,3 @@ extern boost::thread_specific_ptr<VCAI> ai;
 extern FuzzyHelper * fh;
 
 using namespace Goals;
-
-TSubgoal RecruitHero::whatToDoToAchieve()
-{
-	const CGTownInstance * t = ai->findTownWithTavern();
-	if(!t)
-		return sptr(BuildThis(BuildingID::TAVERN).setpriority(2));
-
-	TResources res;
-	res[Res::GOLD] = GameConstants::HERO_GOLD_COST;
-	return ai->ah->whatToDo(res, iAmElementar()); //either buy immediately, or collect res
-}

+ 0 - 7
AI/Nullkiller/Goals/RecruitHero.h

@@ -26,13 +26,6 @@ namespace Goals
 			priority = 1;
 		}
 
-		TGoalVec getAllPossibleSubgoals() override
-		{
-			return TGoalVec();
-		}
-
-		TSubgoal whatToDoToAchieve() override;
-
 		virtual bool operator==(const RecruitHero & other) const override
 		{
 			return true;

+ 1 - 46
AI/Nullkiller/Goals/VisitHero.cpp

@@ -9,14 +9,11 @@
 */
 #include "StdInc.h"
 #include "VisitHero.h"
-#include "Explore.h"
 #include "Invalid.h"
 #include "../VCAI.h"
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 
 
@@ -29,46 +26,4 @@ using namespace Goals;
 bool VisitHero::operator==(const VisitHero & other) const
 {
 	return other.hero.h == hero.h && other.objid == objid;
-}
-
-std::string VisitHero::completeMessage() const
-{
-	return "hero " + hero.get()->name + " visited hero " + boost::lexical_cast<std::string>(objid);
-}
-
-TSubgoal VisitHero::whatToDoToAchieve()
-{
-	const CGObjectInstance * obj = cb->getObj(ObjectInstanceID(objid));
-	if(!obj)
-		return sptr(Explore());
-	int3 pos = obj->visitablePos();
-
-	if(hero && ai->isAccessibleForHero(pos, hero, true) && isSafeToVisit(hero, pos)) //enemy heroes can get reinforcements
-	{
-		if(hero->visitablePos() == pos)
-			logAi->error("Hero %s tries to visit himself.", hero.name);
-		else
-		{
-			//can't use VISIT_TILE here as tile appears blocked by target hero
-			//FIXME: elementar goal should not be abstract
-			return sptr(VisitHero(objid).sethero(hero).settile(pos).setisElementar(true));
-		}
-	}
-	return sptr(Invalid());
-}
-
-bool VisitHero::fulfillsMe(TSubgoal goal)
-{
-	//TODO: VisitObj shoudl not be used for heroes, but...
-	if(goal->goalType == VISIT_TILE)
-	{
-		auto obj = cb->getObj(ObjectInstanceID(objid));
-		if (!obj)
-		{
-			logAi->error("Hero %s: VisitHero::fulfillsMe at %s: object %d not found", hero.name, goal->tile.toString(), objid);
-			return false;
-		}
-		return obj->visitablePos() == goal->tile;
-	}
-	return false;
-}
+}

+ 0 - 7
AI/Nullkiller/Goals/VisitHero.h

@@ -30,13 +30,6 @@ namespace Goals
 			objid = hid;
 			priority = 4;
 		}
-		TGoalVec getAllPossibleSubgoals() override
-		{
-			return TGoalVec();
-		}
-		TSubgoal whatToDoToAchieve() override;
-		bool fulfillsMe(TSubgoal goal) override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const VisitHero & other) const override;
 	};
 }

+ 1 - 76
AI/Nullkiller/Goals/VisitObj.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -31,65 +29,6 @@ bool VisitObj::operator==(const VisitObj & other) const
 	return other.hero.h == hero.h && other.objid == objid;
 }
 
-std::string VisitObj::completeMessage() const
-{
-	return "hero " + hero.get()->name + " captured Object ID = " + boost::lexical_cast<std::string>(objid);
-}
-
-TGoalVec VisitObj::getAllPossibleSubgoals()
-{
-	TGoalVec goalList;
-	const CGObjectInstance * obj = cb->getObjInstance(ObjectInstanceID(objid));
-	if(!obj)
-	{
-		throw cannotFulfillGoalException("Object is missing - goal is invalid now!");
-	}
-
-	int3 pos = obj->visitablePos();
-	if(hero)
-	{
-		if(ai->isAccessibleForHero(pos, hero))
-		{
-			if(isSafeToVisit(hero, pos))
-				goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(hero)));
-			else
-				goalList.push_back(sptr(GatherArmy(fh->evaluateDanger(pos, hero.h) * SAFE_ATTACK_CONSTANT).sethero(hero).setisAbstract(true)));
-
-			return goalList;
-		}
-	}
-	else
-	{
-		for(auto potentialVisitor : cb->getHeroesInfo())
-		{
-			if(ai->isAccessibleForHero(pos, potentialVisitor))
-			{
-				if(isSafeToVisit(potentialVisitor, pos))
-					goalList.push_back(sptr(VisitObj(obj->id.getNum()).sethero(potentialVisitor)));
-				else
-					goalList.push_back(sptr(GatherArmy(fh->evaluateDanger(pos, potentialVisitor) * SAFE_ATTACK_CONSTANT).sethero(potentialVisitor).setisAbstract(true)));
-			}
-		}
-		if(!goalList.empty())
-		{
-			return goalList;
-		}
-	}
-
-	goalList.push_back(sptr(ClearWayTo(pos)));
-	return goalList;
-}
-
-TSubgoal VisitObj::whatToDoToAchieve()
-{
-	auto bestGoal = fh->chooseSolution(getAllPossibleSubgoals());
-
-	if(bestGoal->goalType == VISIT_OBJ && bestGoal->hero)
-		bestGoal->setisElementar(true);
-
-	return bestGoal;
-}
-
 VisitObj::VisitObj(int Objid)
 	: CGoal(VISIT_OBJ)
 {
@@ -101,18 +40,4 @@ VisitObj::VisitObj(int Objid)
 		logAi->error("VisitObj constructed with invalid object instance %d", Objid);
 
 	priority = 3;
-}
-
-bool VisitObj::fulfillsMe(TSubgoal goal)
-{
-	if(goal->goalType == VISIT_TILE)
-	{
-		if (!hero || hero == goal->hero)
-		{
-			auto obj = cb->getObjInstance(ObjectInstanceID(objid));
-			if (obj && obj->visitablePos() == goal->tile) //object could be removed
-				return true;
-		}
-	}
-	return false;
-}
+}

+ 0 - 4
AI/Nullkiller/Goals/VisitObj.h

@@ -23,10 +23,6 @@ namespace Goals
 		VisitObj() = delete; // empty constructor not allowed
 		VisitObj(int Objid);
 
-		TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;
-		bool fulfillsMe(TSubgoal goal) override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const VisitObj & other) const override;
 	};
 }

+ 0 - 68
AI/Nullkiller/Goals/VisitTile.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -30,69 +28,3 @@ bool VisitTile::operator==(const VisitTile & other) const
 {
 	return other.hero.h == hero.h && other.tile == tile;
 }
-
-std::string VisitTile::completeMessage() const
-{
-	return "Hero " + hero.get()->name + " visited tile " + tile.toString();
-}
-
-TSubgoal VisitTile::whatToDoToAchieve()
-{
-	auto ret = fh->chooseSolution(getAllPossibleSubgoals());
-
-	if(ret->hero)
-	{
-		if(isSafeToVisit(ret->hero, tile) && ai->isAccessibleForHero(tile, ret->hero))
-		{
-			ret->setisElementar(true);
-			return ret;
-		}
-		else
-		{
-			return sptr(GatherArmy(fh->evaluateDanger(tile, *ret->hero) * SAFE_ATTACK_CONSTANT)
-				    .sethero(ret->hero).setisAbstract(true));
-		}
-	}
-	return ret;
-}
-
-TGoalVec VisitTile::getAllPossibleSubgoals()
-{
-	assert(cb->isInTheMap(tile));
-
-	TGoalVec ret;
-	if(!cb->isVisible(tile))
-		ret.push_back(sptr(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(VisitTile(tile).sethero(h)));
-		}
-		if(ai->canRecruitAnyHero())
-			ret.push_back(sptr(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(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(ClearWayTo(tile)));
-	}
-
-	//important - at least one sub-goal must handle case which is impossible to fulfill (unreachable tile)
-	return ret;
-}

+ 0 - 3
AI/Nullkiller/Goals/VisitTile.h

@@ -29,9 +29,6 @@ namespace Goals
 			tile = Tile;
 			priority = 5;
 		}
-		TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;
-		std::string completeMessage() const override;
 		virtual bool operator==(const VisitTile & other) const override;
 	};
 }

+ 6 - 8
AI/Nullkiller/Goals/Win.cpp

@@ -13,8 +13,6 @@
 #include "../AIUtility.h"
 #include "../AIhelper.h"
 #include "../FuzzyHelper.h"
-#include "../ResourceManager.h"
-#include "../BuildingManager.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
 #include "../../../lib/StringConstants.h"
@@ -62,9 +60,9 @@ TSubgoal Win::whatToDoToAchieve()
 			if(goal.object)
 			{
 				auto obj = cb->getObj(goal.object->id);
-				if(obj)
+				/*if(obj)
 					if(obj->getOwner() == ai->playerID) //we can't capture our own object
-						return sptr(Conquer());
+						return sptr(Conquer());*/
 
 
 				return sptr(VisitObj(goal.object->id.getNum()));
@@ -122,8 +120,8 @@ TSubgoal Win::whatToDoToAchieve()
 				} //TODO: use FIND_OBJ
 				else if(const CGObjectInstance * obj = ai->getUnvisitedObj(objWithID<Obj::OBELISK>)) //there are unvisited Obelisks
 					return sptr(VisitObj(obj->id.getNum()));
-				else
-					return sptr(Explore());
+				/*else
+					return sptr(Explore());*/
 			}
 			break;
 		}
@@ -166,7 +164,7 @@ TSubgoal Win::whatToDoToAchieve()
 			break;
 		}
 		case EventCondition::STANDARD_WIN:
-			return sptr(Conquer());
+			return sptr(Invalid());
 
 		// Conditions that likely don't need any implementation
 		case EventCondition::DAYS_PASSED:
@@ -182,7 +180,7 @@ TSubgoal Win::whatToDoToAchieve()
 		case EventCondition::HAVE_BUILDING_0:
 		case EventCondition::DESTROY_0:
 			//TODO: support new condition format
-			return sptr(Conquer());
+			return sptr(Invalid());
 		default:
 			assert(0);
 		}

+ 6 - 1
AI/Nullkiller/MapObjectsEvaluator.cpp

@@ -64,7 +64,12 @@ boost::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance
 		auto hero = dynamic_cast<const CGHeroInstance*>(obj);
 		return getObjectValue(obj->ID, hero->type->heroClass->id);
 	}
-	if(obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4)
+	else if(obj->ID == Obj::PRISON)
+	{
+		//special case: in-game prison subID is captured hero ID, but config has one subID with index 0 for normal prison - use that one
+		return getObjectValue(obj->ID, 0);
+	}
+	else if(obj->ID == Obj::CREATURE_GENERATOR1 || obj->ID == Obj::CREATURE_GENERATOR4)
 	{
 		auto dwelling = dynamic_cast<const CGDwelling *>(obj);
 		int aiValue = 0;

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp

@@ -14,7 +14,7 @@
 
 namespace AIPathfinding
 {
-	Goals::TSubgoal BattleAction::whatToDo(const HeroPtr & hero) const
+	Goals::TSubgoal BattleAction::whatToDo(const CGHeroInstance * hero) const
 	{
 		return Goals::sptr(Goals::VisitTile(targetTile).sethero(hero));
 	}

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/BattleAction.h

@@ -25,6 +25,6 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override;
+		virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
 	};
 }

+ 2 - 2
AI/Nullkiller/Pathfinding/Actions/BoatActions.cpp

@@ -17,7 +17,7 @@
 
 namespace AIPathfinding
 {
-	Goals::TSubgoal BuildBoatAction::whatToDo(const HeroPtr & hero) const
+	Goals::TSubgoal BuildBoatAction::whatToDo(const CGHeroInstance * hero) const
 	{
 		return Goals::sptr(Goals::BuildBoat(shipyard));
 	}
@@ -27,7 +27,7 @@ namespace AIPathfinding
 		return sourceActor->resourceActor;
 	}
 
-	Goals::TSubgoal SummonBoatAction::whatToDo(const HeroPtr & hero) const
+	Goals::TSubgoal SummonBoatAction::whatToDo(const CGHeroInstance * hero) const
 	{
 		return Goals::sptr(Goals::AdventureSpellCast(hero, SpellID::SUMMON_BOAT));
 	}

+ 2 - 2
AI/Nullkiller/Pathfinding/Actions/BoatActions.h

@@ -25,7 +25,7 @@ namespace AIPathfinding
 	class SummonBoatAction : public VirtualBoatAction
 	{
 	public:
-		virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override;
+		virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
 
 		virtual void applyOnDestination(
 			const CGHeroInstance * hero,
@@ -53,7 +53,7 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override;
+		virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
 
 		virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
 	};

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/ISpecialAction.h

@@ -23,7 +23,7 @@ public:
 		return true;
 	}
 
-	virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const = 0;
+	virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const = 0;
 
 	virtual void applyOnDestination(
 		const CGHeroInstance * hero,

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/TownPortalAction.cpp

@@ -16,7 +16,7 @@
 
 using namespace AIPathfinding;
 
-Goals::TSubgoal TownPortalAction::whatToDo(const HeroPtr & hero) const
+Goals::TSubgoal TownPortalAction::whatToDo(const CGHeroInstance * hero) const
 {
 	const CGTownInstance * targetTown = target; // const pointer is not allowed in settown
 

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h

@@ -28,6 +28,6 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override;
+		virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override;
 	};
 }

+ 0 - 216
AI/Nullkiller/Pathfinding/PathfindingManager.cpp

@@ -32,76 +32,6 @@ void PathfindingManager::setAI(VCAI * AI)
 	ai = AI;
 }
 
-Goals::TGoalVec PathfindingManager::howToVisitTile(const int3 & tile, bool allowGatherArmy) const
-{
-	Goals::TGoalVec result;
-
-	auto heroes = cb->getHeroesInfo();
-	result.reserve(heroes.size());
-
-	for(auto hero : heroes)
-	{
-		vstd::concatenate(result, howToVisitTile(hero, tile, allowGatherArmy));
-	}
-
-	return result;
-}
-
-Goals::TGoalVec PathfindingManager::howToVisitObj(ObjectIdRef obj, bool allowGatherArmy) const
-{
-	Goals::TGoalVec result;
-
-	auto heroes = cb->getHeroesInfo();
-	result.reserve(heroes.size());
-
-	for(auto hero : heroes)
-	{
-		vstd::concatenate(result, howToVisitObj(hero, obj, allowGatherArmy));
-	}
-
-	return result;
-}
-
-Goals::TGoalVec PathfindingManager::howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy) const
-{
-	auto result = findPaths(tile, allowGatherArmy, hero, [&](int3 firstTileToGet) -> Goals::TSubgoal
-	{
-		return sptr(Goals::VisitTile(firstTileToGet).sethero(hero).setisAbstract(true));
-	});
-
-	for(Goals::TSubgoal solution : result)
-	{
-		solution->setparent(sptr(Goals::VisitTile(tile).sethero(hero).setevaluationContext(solution->evaluationContext)));
-	}
-
-	return result;
-}
-
-Goals::TGoalVec PathfindingManager::howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy) const
-{
-	if(!obj)
-	{
-		return Goals::TGoalVec();
-	}
-
-	int3 dest = obj->visitablePos();
-
-	auto result = findPaths(dest, allowGatherArmy, hero, [&](int3 firstTileToGet) -> Goals::TSubgoal
-	{
-		if(obj->ID.num == Obj::HERO && obj->getOwner() == hero->getOwner())
-			return sptr(Goals::VisitHero(obj->id.getNum()).sethero(hero).setisAbstract(true));
-		else
-			return sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero).setisAbstract(true));
-	});
-
-	for(Goals::TSubgoal solution : result)
-	{
-		solution->setparent(sptr(Goals::VisitObj(obj->id.getNum()).sethero(hero).setevaluationContext(solution->evaluationContext)));
-	}
-
-	return result;
-}
-
 std::vector<AIPath> PathfindingManager::getPathsToTile(const HeroPtr & hero, const int3 & tile) const
 {
 	auto paths = pathfinder->getPathInfo(tile);
@@ -118,152 +48,6 @@ std::vector<AIPath> PathfindingManager::getPathsToTile(const int3 & tile) const
 	return pathfinder->getPathInfo(tile);
 }
 
-Goals::TGoalVec PathfindingManager::findPaths(
-	crint3 dest,
-	bool allowGatherArmy,
-	HeroPtr hero,
-	const std::function<Goals::TSubgoal(int3)> doVisitTile) const
-{
-	Goals::TGoalVec result;
-	boost::optional<uint64_t> armyValueRequired;
-	uint64_t danger;
-
-	std::vector<AIPath> chainInfo = pathfinder->getPathInfo(dest);
-
-#ifdef VCMI_TRACE_PATHFINDER
-	logAi->trace("Trying to find a way for %s to visit tile %s", hero->name, dest.toString());
-#endif
-
-	for(auto path : chainInfo)
-	{
-		if((hero && hero.get() != path.targetHero) || path.nodes.empty())
-			continue;
-
-		const AIPathNodeInfo & firstNode = path.firstNode();
-		int3 firstTileToGet = firstNode.coord;
-
-#ifdef VCMI_TRACE_PATHFINDER
-		std::stringstream str;
-
-		str << "Path found ";
-
-		for(auto node : path.nodes)
-			str << node.targetHero->name << "->" << node.coord.toString() << "; ";
-
-		logAi->trace(str.str());
-#endif
-		if(ai->isTileNotReserved(hero.get(), firstTileToGet))
-		{
-			danger = path.getTotalDanger();
-
-			if(isSafeToVisit(hero, path.heroArmy, danger))
-			{
-				Goals::TSubgoal solution;
-
-				if(path.specialAction)
-				{
-					solution = path.specialAction->whatToDo(hero);
-				}
-				else
-				{
-					solution = dest == firstTileToGet
-						? doVisitTile(firstTileToGet)
-						: clearWayTo(firstNode.targetHero, firstTileToGet);
-				}
-
-				if(solution->invalid())
-					continue;
-
-				if(solution->evaluationContext.danger < danger)
-					solution->evaluationContext.danger = danger;
-
-				solution->evaluationContext.movementCost += path.movementCost();
-				solution->evaluationContext.armyLoss += path.getTotalArmyLoss();
-				solution->evaluationContext.heroStrength = path.getHeroStrength();
-#ifdef VCMI_TRACE_PATHFINDER
-				logAi->trace("It's safe for %s to visit tile %s with danger %s, loss %s, army strength %s, goal %s", 
-					hero->name, 
-					dest.toString(), 
-					std::to_string(danger),
-					std::to_string(path.armyLoss),
-					std::to_string(path.heroArmy->getArmyStrength()),
-					solution->name());
-#endif
-				result.push_back(solution);
-
-				continue;
-			}
-
-			if(!armyValueRequired || armyValueRequired > danger)
-			{
-				armyValueRequired = boost::make_optional(danger);
-			}
-		}
-	}
-
-	danger = armyValueRequired.get_value_or(0);
-
-	if(allowGatherArmy && danger > 0)
-	{
-		//we need to get army in order to conquer that place
-#ifdef VCMI_TRACE_PATHFINDER
-		logAi->trace("Gather army for %s, value=%s", hero->name, std::to_string(danger));
-#endif
-		result.push_back(sptr(Goals::GatherArmy(danger * SAFE_ATTACK_CONSTANT).sethero(hero).setisAbstract(true)));
-	}
-
-	return result;
-}
-
-Goals::TSubgoal PathfindingManager::clearWayTo(HeroPtr hero, int3 firstTileToGet) const
-{
-	if(isBlockedBorderGate(firstTileToGet))
-	{
-		//FIXME: this way we'll not visit gate and activate quest :?
-		return sptr(Goals::FindObj(Obj::KEYMASTER, cb->getTile(firstTileToGet)->visitableObjects.back()->subID));
-	}
-
-	auto topObj = cb->getTopObj(firstTileToGet);
-	if(topObj)
-	{
-
-		if(vstd::contains(ai->reservedObjs, topObj) && !vstd::contains(ai->reservedHeroesMap[hero], topObj))
-		{
-			return sptr(Goals::Invalid());
-		}
-
-		if(topObj->ID == Obj::HERO && cb->getPlayerRelations(hero->tempOwner, topObj->tempOwner) != PlayerRelations::ENEMIES)
-		{
-			if(topObj != hero.get(true)) //the hero we want to free
-			{
-				logAi->warn("%s stands in the way of %s", topObj->getObjectName(), hero->getObjectName());
-			}
-		}
-
-		if(topObj->ID == Obj::QUEST_GUARD || topObj->ID == Obj::BORDERGUARD)
-		{
-			if(shouldVisit(hero, topObj))
-			{
-				//do NOT use VISIT_TILE, as tile with quets guard can't be visited
-				return sptr(Goals::VisitObj(topObj->id.getNum()).sethero(hero));
-			}
-
-			auto questObj = dynamic_cast<const IQuestObject*>(topObj);
-
-			if(questObj)
-			{
-				auto questInfo = QuestInfo(questObj->quest, topObj, topObj->visitablePos());
-
-				return sptr(Goals::CompleteQuest(questInfo));
-			}
-
-			return sptr(Goals::Invalid());
-		}
-	}
-
-	return sptr(Goals::VisitTile(firstTileToGet).sethero(hero).setisAbstract(true));
-}
-
 void PathfindingManager::updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain)
 {
 	logAi->debug("AIPathfinder has been reseted.");

+ 0 - 8
AI/Nullkiller/Pathfinding/PathfindingManager.h

@@ -21,10 +21,6 @@ public:
 	virtual void setAI(VCAI * AI) = 0;
 
 	virtual void updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain = false) = 0;
-	virtual Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const = 0;
-	virtual Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
-	virtual Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const = 0;
-	virtual Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const = 0;
 	virtual std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const = 0;
 	virtual std::vector<AIPath> getPathsToTile(const int3 & tile) const = 0;
 };
@@ -42,10 +38,6 @@ public:
 	PathfindingManager() = default;
 	PathfindingManager(CPlayerSpecificInfoCallback * CB, VCAI * AI = nullptr); //for tests only
 
-	Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitTile(const int3 & tile, bool allowGatherArmy = true) const override;
-	Goals::TGoalVec howToVisitObj(ObjectIdRef obj, bool allowGatherArmy = true) const override;
 	std::vector<AIPath> getPathsToTile(const HeroPtr & hero, const int3 & tile) const override;
 	std::vector<AIPath> getPathsToTile(const int3 & tile) const override;
 	void updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain = false) override;

+ 1 - 1
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -26,7 +26,7 @@ namespace AIPathfinding
 			return false;
 		}
 
-		virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override
+		virtual Goals::TSubgoal whatToDo(const CGHeroInstance * hero) const override
 		{
 			return Goals::sptr(Goals::Invalid());
 		}

+ 0 - 364
AI/Nullkiller/ResourceManager.cpp

@@ -1,364 +0,0 @@
-/*
-* ResourceManager.cpp, part of VCMI engine
-*
-* Authors: listed in file AUTHORS in main folder
-*
-* License: GNU General Public License v2.0 or later
-* Full text of license available in license.txt file, in main folder
-*
-*/
-#include "StdInc.h"
-#include "ResourceManager.h"
-#include "Goals/Goals.h"
-
-#include "../../CCallback.h"
-#include "../../lib/mapObjects/MapObjects.h"
-
-#define GOLD_RESERVE (10000); //at least we'll be able to reach capitol
-
-ResourceObjective::ResourceObjective(const TResources & Res, Goals::TSubgoal Goal)
-	: resources(Res), goal(Goal)
-{
-}
-
-bool ResourceObjective::operator<(const ResourceObjective & ro) const
-{
-	return goal->priority < ro.goal->priority;
-}
-
-ResourceManager::ResourceManager(CPlayerSpecificInfoCallback * CB, VCAI * AI)
-	: ai(AI), cb(CB)
-{
-}
-
-void ResourceManager::init(CPlayerSpecificInfoCallback * CB)
-{
-	cb = CB;
-}
-
-void ResourceManager::setAI(VCAI * AI)
-{
-	ai = AI;
-}
-
-bool ResourceManager::canAfford(const TResources & cost) const
-{
-	return freeResources().canAfford(cost);
-}
-
-TResources ResourceManager::estimateIncome() const
-{
-	TResources ret;
-	for (const CGTownInstance * t : cb->getTownsInfo())
-	{
-		ret += t->dailyIncome();
-	}
-
-	for (const CGObjectInstance * obj : ai->getFlaggedObjects())
-	{
-		if (obj->ID == Obj::MINE)
-		{
-			switch (obj->subID)
-			{
-			case Res::WOOD:
-			case Res::ORE:
-				ret[obj->subID] += WOOD_ORE_MINE_PRODUCTION;
-				break;
-			case Res::GOLD:
-			case 7: //abandoned mine -> also gold
-				ret[Res::GOLD] += GOLD_MINE_PRODUCTION;
-				break;
-			default:
-				ret[obj->subID] += RESOURCE_MINE_PRODUCTION;
-				break;
-			}
-		}
-	}
-
-	return ret;
-}
-
-void ResourceManager::reserveResoures(const TResources & res, Goals::TSubgoal goal)
-{
-	if (!goal->invalid())
-		tryPush(ResourceObjective(res, goal));
-	else
-		logAi->warn("Attempt to reserve resources for Invalid goal");
-}
-
-Goals::TSubgoal ResourceManager::collectResourcesForOurGoal(ResourceObjective &o) const
-{
-	auto allResources = cb->getResourceAmount();
-	auto income = estimateIncome();
-	Res::ERes resourceType = Res::INVALID;
-	TResource amountToCollect = 0;
-
-	typedef std::pair<Res::ERes, TResource> resPair;
-	std::map<Res::ERes, TResource> missingResources;
-
-	//TODO: unit test for complex resource sets
-
-	//sum missing resources of given type for ALL reserved objectives
-	for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
-	{
-		//choose specific resources we need for this goal (not 0)
-		for (auto r = Res::ResourceSet::nziterator(o.resources); r.valid(); r++)
-			missingResources[r->resType] += it->resources[r->resType]; //goal it costs r units of resType
-	}
-	for (auto it = Res::ResourceSet::nziterator(o.resources); it.valid(); it++)
-	{
-		missingResources[it->resType] -= allResources[it->resType]; //missing = (what we need) - (what we have)
-		vstd::amax(missingResources[it->resType], 0); // if we have more resources than reserved, we don't need them
-	}
-	vstd::erase_if(missingResources, [=](const resPair & p) -> bool
-	{
-		return !(p.second); //in case evaluated to 0 or less
-	});
-	if (missingResources.empty()) //FIXME: should be unit-tested out
-	{
-		logAi->error("We don't need to collect resources %s for goal %s", o.resources.toString(), o.goal->name());
-		return o.goal;
-	}
-
-	float goalPriority = 10; //arbitrary, will be divided
-	for (const resPair & p : missingResources)
-	{
-		if (!income[p.first]) //prioritize resources with 0 income
-		{
-			resourceType = p.first;
-			amountToCollect = p.second;
-			goalPriority /= amountToCollect; //need more resources -> lower priority
-			break;
-		}
-	}
-	if (resourceType == Res::INVALID) //no needed resources has 0 income,
-	{
-		//find the one which takes longest to collect
-		typedef std::pair<Res::ERes, float> timePair;
-		std::map<Res::ERes, float> daysToEarn;
-		for (auto it : missingResources)
-			daysToEarn[it.first] = (float)missingResources[it.first] / income[it.first];
-		auto incomeComparer = [&income](const timePair & lhs, const timePair & rhs) -> bool
-		{
-			//theoretically income can be negative, but that falls into this comparison
-			return lhs.second < rhs.second;
-		};
-
-		resourceType = boost::max_element(daysToEarn, incomeComparer)->first;
-		amountToCollect = missingResources[resourceType];
-		goalPriority /= daysToEarn[resourceType]; //more days - lower priority
-	}
-	if (resourceType == Res::GOLD)
-		goalPriority *= 1000;
-
-	//this is abstract goal and might take soem time to complete
-	return Goals::sptr(Goals::CollectRes(resourceType, amountToCollect).setisAbstract(true));
-}
-
-Goals::TSubgoal ResourceManager::whatToDo() const //suggest any goal
-{
-	if (queue.size())
-	{
-		auto o = queue.top();
-
-		auto allResources = cb->getResourceAmount(); //we don't consider savings, it's out top-priority goal
-		if (allResources.canAfford(o.resources))
-			return o.goal;
-		else //we can't afford even top-priority goal, need to collect resources
-			return collectResourcesForOurGoal(o);
-	}
-	else
-		return Goals::sptr(Goals::Invalid()); //nothing else to do
-}
-
-Goals::TSubgoal ResourceManager::whatToDo(TResources &res, Goals::TSubgoal goal)
-{
-	logAi->trace("ResourceManager: checking goal %s which requires resources %s", goal->name(), res.toString());
-
-	TResources accumulatedResources;
-	auto allResources = cb->getResourceAmount();
-
-	ResourceObjective ro(res, goal);
-	tryPush(ro);
-	//check if we can afford all the objectives with higher priority first
-	for (auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
-	{
-		accumulatedResources += it->resources;
-
-		logAi->trace(
-			"ResourceManager: checking goal %s, accumulatedResources=%s, available=%s",
-			it->goal->name(),
-			accumulatedResources.toString(),
-			allResources.toString());
-
-		if(!accumulatedResources.canBeAfforded(allResources))
-		{
-			//can't afford
-			break;
-		}
-		else //can afford all goals up to this point
-		{
-			if(it->goal == goal)
-			{
-				logAi->debug("ResourceManager: can afford goal %s", goal->name());
-				return goal; //can afford immediately
-			}
-		}
-	}
-
-	logAi->debug("ResourceManager: can not afford goal %s", goal->name());
-
-	return collectResourcesForOurGoal(ro);
-}
-
-bool ResourceManager::containsObjective(Goals::TSubgoal goal) const
-{
-	logAi->trace("Entering ResourceManager.containsObjective goal=%s", goal->name());
-	dumpToLog();
-
-	//TODO: unit tests for once
-	for (auto objective : queue)
-	{
-		if (objective.goal == goal)
-			return true;
-	}
-	return false;
-}
-
-bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
-{
-	logAi->trace("Entering ResourceManager.notifyGoalCompleted goal=%s", goal->name());
-
-	if (goal->invalid())
-		logAi->warn("Attempt to complete Invalid goal");
-
-	std::function<bool(const Goals::TSubgoal &)> equivalentGoalsCheck = [goal](const Goals::TSubgoal & x) -> bool
-	{
-		return x == goal || x->fulfillsMe(goal);
-	};
-
-	bool removedGoal = removeOutdatedObjectives(equivalentGoalsCheck);
-
-	dumpToLog();
-
-	return removedGoal;
-}
-
-bool ResourceManager::updateGoal(Goals::TSubgoal goal)
-{
-	//we update priority of goal if it is easier or more difficult to complete
-	if (goal->invalid())
-		logAi->warn("Attempt to update Invalid goal");
-
-	auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
-	{
-		return ro.goal == goal;
-	});
-	if (it != queue.end())
-	{
-		it->goal->setpriority(goal->priority);
-		auto handle = queue.s_handle_from_iterator(it);
-		queue.update(handle); //restore order
-		return true;
-	}
-	else
-		return false;
-}
-
-void ResourceManager::dumpToLog() const
-{
-	for(auto it = queue.ordered_begin(); it != queue.ordered_end(); it++)
-	{
-		logAi->trace("ResourceManager contains goal %s which requires resources %s", it->goal->name(), it->resources.toString());
-	}
-}
-
-bool ResourceManager::tryPush(const ResourceObjective & o)
-{
-	auto goal = o.goal;
-
-	logAi->trace("ResourceManager: Trying to add goal %s which requires resources %s", goal->name(), o.resources.toString());
-	dumpToLog();
-
-	auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
-	{
-		return ro.goal == goal;
-	});
-	if (it != queue.end())
-	{
-		auto handle = queue.s_handle_from_iterator(it);
-		vstd::amax(goal->priority, it->goal->priority); //increase priority if case
-		//update resources with new value
-		queue.update(handle, ResourceObjective(o.resources, goal)); //restore order
-		return false;
-	}
-	else
-	{
-		queue.push(o); //add new objective
-		logAi->debug("Reserved resources (%s) for %s", o.resources.toString(), goal->name());
-		return true;
-	}
-}
-
-bool ResourceManager::hasTasksLeft() const
-{
-	return !queue.empty();
-}
-
-bool ResourceManager::removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate)
-{
-	bool removedAnything = false;
-	while(true)
-	{ //unfortunately we can't use remove_if on heap
-		auto it = boost::find_if(queue, [&](const ResourceObjective & ro) -> bool
-		{
-			return predicate(ro.goal);
-		});
-
-		if(it != queue.end()) //removed at least one
-		{
-			logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
-			queue.erase(queue.s_handle_from_iterator(it));
-			removedAnything = true;
-		}
-		else
-		{ //found nothing more to remove
-			break;
-		}
-	}
-	return removedAnything;
-}
-
-TResources ResourceManager::reservedResources() const
-{
-	TResources res;
-	for (auto it : queue) //substract the value of reserved goals
-		res += it.resources;
-	return res;
-}
-
-TResources ResourceManager::freeResources() const
-{
-	TResources myRes = cb->getResourceAmount();
-	myRes -= reservedResources(); //substract the value of reserved goals
-
-	for (auto & val : myRes)
-		vstd::amax(val, 0); //never negative
-
-	return myRes;
-}
-
-TResource ResourceManager::freeGold() const
-{
-	return freeResources()[Res::GOLD];
-}
-
-TResources ResourceManager::allResources() const
-{
-	return cb->getResourceAmount();
-}
-
-TResource ResourceManager::allGold() const
-{
-	return cb->getResourceAmount()[Res::GOLD];
-}

+ 0 - 113
AI/Nullkiller/ResourceManager.h

@@ -1,113 +0,0 @@
-/*
-* ResourceManager.h, part of VCMI engine
-*
-* Authors: listed in file AUTHORS in main folder
-*
-* License: GNU General Public License v2.0 or later
-* Full text of license available in license.txt file, in main folder
-*
-*/
-#pragma once
-
-#include "AIUtility.h"
-#include "../../lib/GameConstants.h"
-#include "../../lib/VCMI_Lib.h"
-#include "VCAI.h"
-#include <boost/heap/binomial_heap.hpp>
-
-class AIhelper;
-class IResourceManager;
-
-struct DLL_EXPORT ResourceObjective
-{
-	ResourceObjective() = default;
-	ResourceObjective(const TResources &res, Goals::TSubgoal goal);
-	bool operator < (const ResourceObjective &ro) const;
-
-	TResources resources; //how many resoures do we need
-	Goals::TSubgoal goal; //what for (build, gather army etc...)
-
-	 //TODO: register?
-	template<typename Handler> void serializeInternal(Handler & h, const int version)
-	{
-		h & resources;
-		//h & goal; //FIXME: goal serialization is broken
-	}
-};
-
-class DLL_EXPORT IResourceManager //: public: IAbstractManager
-{
-public:
-	virtual ~IResourceManager() = default;
-	virtual void init(CPlayerSpecificInfoCallback * CB) = 0;
-	virtual void setAI(VCAI * AI) = 0;
-
-	virtual TResources reservedResources() const = 0;
-	virtual TResources freeResources() const = 0;
-	virtual TResource freeGold() const = 0;
-	virtual TResources allResources() const = 0;
-	virtual TResource allGold() const = 0;
-
-	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;
-	virtual bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) = 0; //remove ResourceObjectives from queue if ResourceObjective->goal meets specific criteria
-	virtual bool notifyGoalCompleted(Goals::TSubgoal goal) = 0;
-};
-
-class DLL_EXPORT ResourceManager : public IResourceManager
-{
-	/*Resource Manager is a smart shopping list for AI to help
-	Uses priority queue based on CGoal.priority */
-	friend class VCAI;
-	friend class AIhelper;
-	friend struct SetGlobalState;
-
-	CPlayerSpecificInfoCallback * cb; //this is enough, but we downcast from CCallback
-	VCAI * ai;
-
-public:
-	ResourceManager() = default;
-	ResourceManager(CPlayerSpecificInfoCallback * CB, VCAI * AI = nullptr); //for tests only
-
-	bool canAfford(const TResources & cost) const;
-	TResources reservedResources() const override;
-	TResources freeResources() const override;
-	TResource freeGold() const override;
-	TResources allResources() const override;
-	TResource allGold() const override;
-
-	Goals::TSubgoal whatToDo() const override; //peek highest-priority goal
-	Goals::TSubgoal whatToDo(TResources & res, Goals::TSubgoal goal) override; //can we afford this goal or need to CollectRes?
-	bool containsObjective(Goals::TSubgoal goal) const override;
-	bool hasTasksLeft() const override;
-	bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) override;
-	bool notifyGoalCompleted(Goals::TSubgoal goal) override;
-
-protected: //not-const actions only for AI
-	virtual void reserveResoures(const TResources & res, Goals::TSubgoal goal = Goals::TSubgoal());
-	virtual bool updateGoal(Goals::TSubgoal goal); //new goal must have same properties but different priority
-	virtual bool tryPush(const ResourceObjective &o);
-
-	//inner processing
-	virtual TResources estimateIncome() const;
-	virtual Goals::TSubgoal collectResourcesForOurGoal(ResourceObjective &o) const;
-
-	void init(CPlayerSpecificInfoCallback * CB) override;
-	void setAI(VCAI * AI) override;
-
-private:
-	TResources saving;
-
-	boost::heap::binomial_heap<ResourceObjective> queue;
-
-	void dumpToLog() const;
-
-	//TODO: register?
-	template<typename Handler> void serializeInternal(Handler & h, const int version)
-	{
-		h & saving;
-		h & queue;
-	}
-};

+ 3 - 1
AI/Nullkiller/VCAI.cbp

@@ -76,7 +76,7 @@
 			<Add option="-Wno-sign-compare" />
 			<Add option="-Wno-unused-parameter" />
 			<Add option="-Wno-overloaded-virtual" />
-			<Add option="-DBOOST_THREAD_USE_LIB" />
+			<Add option="-DBOOST_ALL_DYN_LINK" />
 			<Add option="-DBOOST_SYSTEM_NO_DEPRECATED" />
 			<Add option="-D_WIN32_WINNT=0x0501" />
 			<Add option="-D_WIN32" />
@@ -93,6 +93,8 @@
 		<Unit filename="AIUtility.h" />
 		<Unit filename="AIhelper.cpp" />
 		<Unit filename="AIhelper.h" />
+		<Unit filename="ArmyManager.cpp" />
+		<Unit filename="ArmyManager.h" />
 		<Unit filename="BuildingManager.cpp" />
 		<Unit filename="BuildingManager.h" />
 		<Unit filename="FuzzyEngines.cpp" />

+ 13 - 702
AI/Nullkiller/VCAI.cpp

@@ -10,8 +10,6 @@
 #include "StdInc.h"
 #include "VCAI.h"
 #include "FuzzyHelper.h"
-#include "ResourceManager.h"
-#include "BuildingManager.h"
 #include "Goals/Goals.h"
 
 #include "../../lib/UnlockGuard.h"
@@ -119,9 +117,6 @@ void VCAI::heroMoved(const TryMoveHero & details)
 				}
 			}
 		}
-		//FIXME: teleports are not correctly visited
-		unreserveObject(hero, t1);
-		unreserveObject(hero, t2);
 	}
 	else if(details.result == TryMoveHero::EMBARK && hero)
 	{
@@ -246,8 +241,6 @@ void VCAI::heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * vi
 	if(start && visitedObj) //we can end visit with null object, anyway
 	{
 		markObjectVisited(visitedObj);
-		unreserveObject(visitor, visitedObj);
-		completeGoal(sptr(Goals::VisitObj(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..)
 		if (visitedObj->ID == Obj::HERO)
 		{
@@ -350,9 +343,6 @@ void VCAI::heroExchangeStarted(ObjectInstanceID hero1, ObjectInstanceID hero2, Q
 				transferFrom2to1(secondHero, firstHero);
 		}
 
-		completeGoal(sptr(Goals::VisitHero(firstHero->id.getNum()))); //TODO: what if we were visited by other hero in the meantime?
-		completeGoal(sptr(Goals::VisitHero(secondHero->id.getNum())));
-
 		answerQuery(query, 0);
 	});
 }
@@ -399,9 +389,6 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
 	vstd::erase_if_present(visitableObjs, obj);
 	vstd::erase_if_present(alreadyVisited, obj);
 
-	for(auto h : cb->getHeroesInfo())
-		unreserveObject(h, obj);
-
 	std::function<bool(const Goals::TSubgoal &)> checkRemovalValidity = [&](const Goals::TSubgoal & x) -> bool
 	{
 		if((x->goalType == Goals::VISIT_OBJ) && (x->objid == obj->id.getNum()))
@@ -412,27 +399,6 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
 			return false;
 	};
 
-	//clear VCAI / main loop caches
-	vstd::erase_if(lockedHeroes, [&](const std::pair<HeroPtr, Goals::TSubgoal> & x) -> bool
-	{
-		return checkRemovalValidity(x.second);
-	});
-
-	vstd::erase_if(ultimateGoalsFromBasic, [&](const std::pair<Goals::TSubgoal, Goals::TGoalVec> & x) -> bool
-	{
-		return checkRemovalValidity(x.first);
-	});
-
-	vstd::erase_if(basicGoals, checkRemovalValidity);
-	vstd::erase_if(goalsToAdd, checkRemovalValidity);
-	vstd::erase_if(goalsToRemove, checkRemovalValidity);
-
-	for(auto goal : ultimateGoalsFromBasic)
-		vstd::erase_if(goal.second, checkRemovalValidity);
-
-	//clear resource manager goal cache
-	ah->removeOutdatedObjectives(checkRemovalValidity);
-
 	//TODO: Find better way to handle hero boat removal
 	if(auto hero = dynamic_cast<const CGHeroInstance *>(obj))
 	{
@@ -440,9 +406,6 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
 		{
 			vstd::erase_if_present(visitableObjs, hero->boat);
 			vstd::erase_if_present(alreadyVisited, hero->boat);
-
-			for(auto h : cb->getHeroesInfo())
-				unreserveObject(h, hero->boat);
 		}
 	}
 
@@ -569,9 +532,6 @@ void VCAI::buildChanged(const CGTownInstance * town, BuildingID buildingID, int
 {
 	LOG_TRACE_PARAMS(logAi, "what '%i'", what);
 	NET_EVENT_HANDLER;
-
-	if(town->getOwner() == playerID && what == 1) //built
-		completeGoal(sptr(Goals::BuildThis(buildingID, town)));
 }
 
 void VCAI::heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain)
@@ -855,22 +815,7 @@ void VCAI::makeTurn()
 
 	try
 	{
-		if(nullkiller)
-		{
-			nullkiller->makeTurn();
-		}
-		else
-		{
-			//it looks messy here, but it's better to have armed heroes before attempting realizing goals
-			for(const CGTownInstance * t : cb->getTownsInfo())
-				moveCreaturesToHero(t);
-
-			mainLoop();
-
-			/*Below function is also responsible for hero movement via internal wander function. By design it is separate logic for heroes that have nothing to do.
-			Heroes that were not picked by striveToGoal(sptr(Goals::Win())); recently (so they do not have new goals and cannot continue/reevaluate previously locked goals) will do logic in wander().*/
-			performTypicalActions();
-		}
+		nullkiller->makeTurn();
 
 		//for debug purpose
 		for (auto h : cb->getHeroesInfo())
@@ -904,194 +849,6 @@ std::vector<HeroPtr> VCAI::getMyHeroes() const
 	return ret;
 }
 
-void VCAI::mainLoop()
-{
-	std::vector<Goals::TSubgoal> elementarGoals; //no duplicates allowed (operator ==)
-	basicGoals.clear();
-
-	validateVisitableObjs();
-
-	//get all potential and saved goals
-	//TODO: not lose
-	basicGoals.push_back(sptr(Goals::Win()));
-	for (auto goalPair : lockedHeroes)
-	{
-		fh->setPriority(goalPair.second);  //re-evaluate, as heroes moved in the meantime
-		basicGoals.push_back(goalPair.second);
-	}
-	if (ah->hasTasksLeft())
-		basicGoals.push_back(ah->whatToDo());
-	for (auto quest : myCb->getMyQuests())
-	{
-		basicGoals.push_back(sptr(Goals::CompleteQuest(quest)));
-	}
-	basicGoals.push_back(sptr(Goals::Build()));
-
-	invalidPathHeroes.clear();
-
-	while (basicGoals.size())
-	{
-		vstd::removeDuplicates(basicGoals); //TODO: container which does this automagically without has would be nice
-		goalsToAdd.clear();
-		goalsToRemove.clear();
-		elementarGoals.clear();
-		ultimateGoalsFromBasic.clear();
-		
-		ah->updatePaths(getMyHeroes());
-
-		logAi->debug("Main loop: decomposing %i basic goals", basicGoals.size());
-
-		for (auto basicGoal : basicGoals)
-		{
-			logAi->debug("Main loop: decomposing basic goal %s", basicGoal->name());
-
-			auto goalToDecompose = basicGoal;
-			Goals::TSubgoal elementarGoal = sptr(Goals::Invalid());
-			int maxAbstractGoals = 10;
-			while (!elementarGoal->isElementar && maxAbstractGoals)
-			{
-				try
-				{
-					elementarGoal = decomposeGoal(goalToDecompose);
-				}
-				catch (goalFulfilledException & e)
-				{
-					//it is impossible to continue some goals (like exploration, for example)
-					//complete abstract goal for now, but maybe main goal finds another path
-					logAi->debug("Goal %s decomposition failed: goal was completed as much as possible", e.goal->name());
-					completeGoal(e.goal); //put in goalsToRemove
-					break;
-				}
-				catch(cannotFulfillGoalException & e)
-				{
-					//it is impossible to continue some goals (like exploration, for example)
-					//complete abstract goal for now, but maybe main goal finds another path
-					goalsToRemove.push_back(basicGoal);
-					logAi->debug("Goal %s decomposition failed: %s", goalToDecompose->name(), e.what());
-					break;
-				}
-				catch (std::exception & e) //decomposition failed, which means we can't decompose entire tree
-				{
-					goalsToRemove.push_back(basicGoal);
-					logAi->debug("Goal %s decomposition failed: %s", basicGoal->name(), e.what());
-					break;
-				}
-				if (elementarGoal->isAbstract) //we can decompose it further
-				{
-					goalsToAdd.push_back(elementarGoal);
-					//decompose further now - this is necesssary if we can't add over 10 goals in the pool
-					goalToDecompose = elementarGoal;
-					//there is a risk of infinite abstract goal loop, though it indicates failed logic
-					maxAbstractGoals--;
-				}
-				else if (elementarGoal->isElementar) //should be
-				{
-					logAi->debug("Found elementar goal %s", elementarGoal->name());
-					elementarGoals.push_back(elementarGoal);
-					ultimateGoalsFromBasic[elementarGoal].push_back(goalToDecompose); //TODO: how about indirect basicGoal?
-					break;
-				}
-				else //should never be here
-					throw cannotFulfillGoalException("Goal %s is neither abstract nor elementar!" + basicGoal->name());
-			}
-		}
-
-		logAi->trace("Main loop: selecting best elementar goal");
-
-		//now choose one elementar goal to realize
-		Goals::TGoalVec possibleGoals(elementarGoals.begin(), elementarGoals.end()); //copy to vector
-		Goals::TSubgoal goalToRealize = sptr(Goals::Invalid());
-		while (possibleGoals.size())
-		{
-			//allow assign goals to heroes with 0 movement, but don't realize them
-			//maybe there are beter ones left
-
-			auto bestGoal = fh->chooseSolution(possibleGoals);
-			if (bestGoal->hero) //lock this hero to fulfill goal
-			{
-				setGoal(bestGoal->hero, bestGoal);
-				if (!bestGoal->hero->movement || vstd::contains(invalidPathHeroes, bestGoal->hero))
-				{
-					if (!vstd::erase_if_present(possibleGoals, bestGoal))
-					{
-						logAi->error("erase_if_preset failed? Something very wrong!");
-						break;
-					}
-					continue; //chose next from the list
-				}
-			}
-			goalToRealize = bestGoal; //we found our goal to execute
-			break;
-		}
-
-		//realize best goal
-		if (!goalToRealize->invalid())
-		{
-			logAi->debug("Trying to realize %s (value %2.3f)", goalToRealize->name(), goalToRealize->priority);
-
-			try
-			{
-				boost::this_thread::interruption_point();
-				goalToRealize->accept(this); //visitor pattern
-				boost::this_thread::interruption_point();
-			}
-			catch (boost::thread_interrupted & e)
-			{
-				logAi->debug("Player %d: Making turn thread received an interruption!", playerID);
-				throw; //rethrow, we want to truly end this thread
-			}
-			catch (goalFulfilledException & e)
-			{
-				//the sub-goal was completed successfully
-				completeGoal(e.goal);
-				//local goal was also completed?
-				completeGoal(goalToRealize);
-
-				// remove abstract visit tile if we completed the elementar one
-				vstd::erase_if_present(goalsToAdd, goalToRealize);
-			}
-			catch (std::exception & e)
-			{
-				logAi->debug("Failed to realize subgoal of type %s, I will stop.", goalToRealize->name());
-				logAi->debug("The error message was: %s", e.what());
-
-				//erase base goal if we failed to execute decomposed goal
-				for (auto basicGoal : ultimateGoalsFromBasic[goalToRealize])
-					goalsToRemove.push_back(basicGoal);
-
-				// sometimes resource manager contains an elementar goal which is not able to execute anymore and just fails each turn.
-				ai->ah->notifyGoalCompleted(goalToRealize);
-
-				//we failed to realize best goal, but maybe others are still possible?
-			}
-
-			//remove goals we couldn't decompose
-			for (auto goal : goalsToRemove)
-				vstd::erase_if_present(basicGoals, goal);
-
-			//add abstract goals
-			boost::sort(goalsToAdd, [](const Goals::TSubgoal & lhs, const Goals::TSubgoal & rhs) -> bool
-			{
-				return lhs->priority > rhs->priority; //highest priority at the beginning
-			});
-
-			//max number of goals = 10
-			int i = 0;
-			while (basicGoals.size() < 10 && goalsToAdd.size() > i)
-			{
-				if (!vstd::contains(basicGoals, goalsToAdd[i])) //don't add duplicates
-					basicGoals.push_back(goalsToAdd[i]);
-				i++;
-			}
-		}
-		else //no elementar goals possible
-		{
-			logAi->debug("Goal decomposition exhausted");
-			break;
-		}
-	}
-}
-
 void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 {
 	LOG_TRACE_PARAMS(logAi, "Hero %s and object %s at %s", h->name % obj->getObjectName() % obj->pos.toString());
@@ -1099,7 +856,6 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 	{
 	case Obj::CREATURE_GENERATOR1:
 		recruitCreatures(dynamic_cast<const CGDwelling *>(obj), h.get());
-		checkHeroArmy(h);
 		break;
 	case Obj::TOWN:
 		if(h->visitedTown) //we are inside, not just attacking
@@ -1116,7 +872,7 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 				ah->update();
 			}
 
-			if(ah->getHeroRole(h) == HeroRole::MAIN && !h->hasSpellbook() && ah->freeGold() >= GameConstants::SPELLBOOK_GOLD_COST)
+			if(ah->getHeroRole(h) == HeroRole::MAIN && !h->hasSpellbook() && cb->getResourceAmount(Res::GOLD) >= GameConstants::SPELLBOOK_GOLD_COST)
 			{
 				if(h->visitedTown->hasBuilt(BuildingID::MAGES_GUILD_1))
 					cb->buyArtifact(h.get(), ArtifactID::SPELLBOOK);
@@ -1127,7 +883,6 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 		makePossibleUpgrades(h.get());
 		break;
 	}
-	completeGoal(sptr(Goals::VisitObj(obj->id.getNum()).sethero(h)));
 }
 
 void VCAI::moveCreaturesToHero(const CGTownInstance * t)
@@ -1197,10 +952,6 @@ void VCAI::pickBestCreatures(const CArmedInstance * destinationArmy, const CArme
 	}
 
 	//TODO - having now strongest possible army, we may want to think about arranging stacks
-
-	auto hero = dynamic_cast<const CGHeroInstance *>(destinationArmy);
-	if(hero)
-		checkHeroArmy(hero);
 }
 
 void VCAI::pickBestArtifacts(const CGHeroInstance * h, const CGHeroInstance * other)
@@ -1313,7 +1064,7 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
 		int count = d->creatures[i].first;
 		CreatureID creID = d->creatures[i].second.back();
 
-		vstd::amin(count, ah->freeResources() / VLC->creh->creatures[creID]->cost);
+		vstd::amin(count, cb->getResourceAmount() / VLC->creh->creatures[creID]->cost);
 		if(count > 0)
 			cb->recruitCreatures(d, recruiter, creID, count, i);
 	}
@@ -1402,250 +1153,6 @@ bool VCAI::canRecruitAnyHero(const CGTownInstance * t) const
 	return true;
 }
 
-void VCAI::wander(HeroPtr h)
-{
-	auto visitTownIfAny = [this](HeroPtr h) -> bool
-	{
-		if (h->visitedTown)
-		{
-			townVisitsThisWeek[h].insert(h->visitedTown);
-			buildArmyIn(h->visitedTown);
-			return true;
-		}
-		return false;
-	};
-
-	//unclaim objects that are now dangerous for us
-	auto reservedObjsSetCopy = reservedHeroesMap[h];
-	for(auto obj : reservedObjsSetCopy)
-	{
-		if(!isSafeToVisit(h, obj->visitablePos()))
-			unreserveObject(h, obj);
-	}
-
-	TimeCheck tc("looking for wander destination");
-
-	while(h->movement)
-	{
-		validateVisitableObjs();
-		ah->updatePaths(getMyHeroes());
-
-		std::vector<ObjectIdRef> dests;
-
-		//also visit our reserved objects - but they are not prioritized to avoid running back and forth
-		vstd::copy_if(reservedHeroesMap[h], std::back_inserter(dests), [&](ObjectIdRef obj) -> bool
-		{
-			return ah->isTileAccessible(h, obj->visitablePos());
-		});
-
-		int pass = 0;
-		std::vector<boost::optional<float>> distanceLimits =
-		{
-			1.0,
-			2.0,
-			boost::none
-		};
-
-		while(!dests.size() && pass < distanceLimits.size())
-		{
-			auto & distanceLimit = distanceLimits[pass];
-
-			logAi->debug("Looking for wander destination pass=%i, cost limit=%f", pass, distanceLimit.get_value_or(-1.0));
-
-			vstd::copy_if(visitableObjs, std::back_inserter(dests), [&](ObjectIdRef obj) -> bool
-			{
-				return isGoodForVisit(obj, h, distanceLimit);
-			});
-
-			pass++;
-		}
-
-		if(!dests.size())
-		{
-			logAi->debug("Looking for town destination");
-
-			if(cb->getVisitableObjs(h->visitablePos()).size() > 1)
-				moveHeroToTile(h->visitablePos(), h); //just in case we're standing on blocked subterranean gate
-
-			auto compareReinforcements = [&](const CGTownInstance * lhs, const CGTownInstance * rhs) -> bool
-			{
-				const CGHeroInstance * hptr = h.get();
-				auto r1 = ah->howManyReinforcementsCanGet(hptr, lhs),
-					r2 = ah->howManyReinforcementsCanGet(hptr, rhs);
-				if (r1 != r2)
-					return r1 < r2;
-				else
-					return ah->howManyReinforcementsCanBuy(hptr, lhs) < ah->howManyReinforcementsCanBuy(hptr, rhs);
-			};
-
-			std::vector<const CGTownInstance *> townsReachable;
-			std::vector<const CGTownInstance *> townsNotReachable;
-			for(const CGTownInstance * t : cb->getTownsInfo())
-			{
-				if(!t->visitingHero && !vstd::contains(townVisitsThisWeek[h], t))
-				{
-					if(isAccessibleForHero(t->visitablePos(), h))
-						townsReachable.push_back(t);
-					else
-						townsNotReachable.push_back(t);
-				}
-			}
-			if(townsReachable.size()) //travel to town with largest garrison, or empty - better than nothing
-			{
-				dests.push_back(*boost::max_element(townsReachable, compareReinforcements));
-			}
-			else if(townsNotReachable.size())
-			{
-				//TODO pick the truly best
-				const CGTownInstance * t = *boost::max_element(townsNotReachable, compareReinforcements);
-				logAi->debug("%s can't reach any town, we'll try to make our way to %s at %s", h->name, t->name, t->visitablePos().toString());
-				int3 pos1 = h->pos;
-				striveToGoal(sptr(Goals::ClearWayTo(t->visitablePos()).sethero(h))); //TODO: drop "strive", add to mainLoop
-				//if out hero is stuck, we may need to request another hero to clear the way we see
-
-				if(pos1 == h->pos && h == primaryHero()) //hero can't move
-				{
-					if(canRecruitAnyHero(t))
-						recruitHero(t);
-				}
-				break;
-			}
-			else if(cb->getResourceAmount(Res::GOLD) >= GameConstants::HERO_GOLD_COST)
-			{
-				std::vector<const CGTownInstance *> towns = cb->getTownsInfo();
-				vstd::erase_if(towns, [&](const CGTownInstance * t) -> bool
-				{
-					for(const CGHeroInstance * h : cb->getHeroesInfo())
-					{
-						if(!t->getArmyStrength() || ah->howManyReinforcementsCanGet(h, t))
-							return true;
-					}
-					return false;
-				});
-				if (towns.size())
-				{
-					recruitHero(*boost::max_element(towns, compareArmyStrength));
-				}
-				break;
-			}
-			else
-			{
-				logAi->debug("Nowhere more to go...");
-				break;
-			}
-		}
-		//end of objs empty
-
-		if(dests.size()) //performance improvement
-		{
-			Goals::TGoalVec targetObjectGoals;
-			for(auto destination : dests)
-			{
-				vstd::concatenate(targetObjectGoals, ah->howToVisitObj(h, destination, false));
-			}
-
-			if(targetObjectGoals.size())
-			{
-				auto bestObjectGoal = fh->chooseSolution(targetObjectGoals);
-
-				//wander should not cause heroes to be reserved - they are always considered free
-				if(bestObjectGoal->goalType == Goals::VISIT_OBJ)
-				{
-					auto chosenObject = cb->getObjInstance(ObjectInstanceID(bestObjectGoal->objid));
-					if(chosenObject != nullptr)
-						logAi->debug("Of all %d destinations, object %s at pos=%s seems nice", dests.size(), chosenObject->getObjectName(), chosenObject->pos.toString());
-				}
-				else
-					logAi->debug("Trying to realize goal of type %s as part of wandering.", bestObjectGoal->name());
-
-				try
-				{
-					decomposeGoal(bestObjectGoal)->accept(this);
-				}
-				catch(const goalFulfilledException & e)
-				{
-					if(e.goal->goalType == Goals::EGoals::VISIT_TILE || e.goal->goalType == Goals::EGoals::VISIT_OBJ)
-						continue;
-
-					throw e;
-				}
-			}
-			else
-			{
-				logAi->debug("Nowhere more to go...");
-				break;
-			}
-
-			visitTownIfAny(h);
-		}
-	}
-
-	visitTownIfAny(h); //in case hero is just sitting in town
-}
-
-void VCAI::setGoal(HeroPtr h, Goals::TSubgoal goal)
-{
-	if(goal->invalid())
-	{
-		vstd::erase_if_present(lockedHeroes, h);
-	}
-	else
-	{
-		lockedHeroes[h] = goal;
-		goal->setisElementar(false); //Force always evaluate goals before realizing
-	}
-}
-void VCAI::evaluateGoal(HeroPtr h)
-{
-	if(vstd::contains(lockedHeroes, h))
-		fh->setPriority(lockedHeroes[h]);
-}
-
-void VCAI::completeGoal(Goals::TSubgoal goal)
-{
-	if (goal->goalType == Goals::WIN) //we can never complete this goal - unless we already won
-		return;
-
-	logAi->debug("Completing goal: %s", goal->name());
-
-	//notify Managers
-	ah->notifyGoalCompleted(goal);
-	//notify mainLoop()
-	goalsToRemove.push_back(goal); //will be removed from mainLoop() goals
-	for (auto basicGoal : basicGoals) //we could luckily fulfill any of our goals
-	{
-		if (basicGoal->fulfillsMe(goal))
-			goalsToRemove.push_back(basicGoal);
-	}
-
-	//unreserve heroes
-	if(const CGHeroInstance * h = goal->hero.get(true))
-	{
-		auto it = lockedHeroes.find(h);
-		if(it != lockedHeroes.end())
-		{
-			if(it->second == goal || it->second->fulfillsMe(goal)) //FIXME this is overspecified, fulfillsMe shoudl be complete
-			{
-				logAi->debug(goal->completeMessage());
-				lockedHeroes.erase(it); //goal fulfilled, free hero
-			}
-		}
-	}
-	else //complete goal for all heroes maybe?
-	{
-		vstd::erase_if(lockedHeroes, [goal](std::pair<HeroPtr, Goals::TSubgoal> p)
-		{
-			if(p.second == goal || p.second->fulfillsMe(goal)) //we could have fulfilled goals of other heroes by chance
-			{
-				logAi->debug(p.second->completeMessage());
-				return true;
-			}
-			return false;
-		});
-	}
-
-}
-
 void VCAI::battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side)
 {
 	NET_EVENT_HANDLER;
@@ -1686,19 +1193,6 @@ void VCAI::markObjectVisited(const CGObjectInstance * obj)
 	alreadyVisited.insert(obj);
 }
 
-void VCAI::reserveObject(HeroPtr h, const CGObjectInstance * obj)
-{
-	reservedObjs.insert(obj);
-	reservedHeroesMap[h].insert(obj);
-	logAi->debug("reserved object id=%d; address=%p; name=%s", obj->id, obj, obj->getObjectName());
-}
-
-void VCAI::unreserveObject(HeroPtr h, const CGObjectInstance * obj)
-{
-	vstd::erase_if_present(reservedObjs, obj); //unreserve objects
-	vstd::erase_if_present(reservedHeroesMap[h], obj);
-}
-
 void VCAI::markHeroUnableToExplore(HeroPtr h)
 {
 	heroesUnableToExplore.insert(h);
@@ -2053,25 +1547,15 @@ bool VCAI::moveHeroToTile(int3 dst, HeroPtr h)
 	}
 	if(h) //we could have lost hero after last move
 	{
-		completeGoal(sptr(Goals::VisitTile(dst).sethero(h))); //we stepped on some tile, anyway
-		completeGoal(sptr(Goals::ClearWayTo(dst).sethero(h)));
-
 		ret = ret || (dst == h->visitablePos());
 
-		if(!ret) //reserve object we are heading towards
-		{
-			auto obj = vstd::frontOrNull(cb->getVisitableObjs(dst));
-			if(obj && obj != *h)
-				reserveObject(h, obj);
-		}
-
 		if(startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
 		{
 			vstd::erase_if_present(lockedHeroes, h); //hero seemingly is confused or has only 95mp which is not enough to move
 			invalidPathHeroes.insert(h);
 			throw cannotFulfillGoalException("Invalid path found!");
 		}
-		evaluateGoal(h); //new hero position means new game situation
+
 		logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->name, startHpos.toString(), h->visitablePos().toString(), ret);
 	}
 	return ret;
@@ -2181,7 +1665,6 @@ void VCAI::tryRealize(Goals::DigAtTile & g)
 	if(g.hero->diggingStatus() == EDiggingStatus::CAN_DIG)
 	{
 		cb->dig(g.hero.get());
-		completeGoal(sptr(g)); // finished digging
 	}
 	else
 	{
@@ -2192,7 +1675,7 @@ void VCAI::tryRealize(Goals::DigAtTile & g)
 
 void VCAI::tryRealize(Goals::Trade & g) //trade
 {
-	if(ah->freeResources()[g.resID] >= g.value) //goal is already fulfilled. Why we need this check, anyway?
+	if(cb->getResourceAmount((Res::ERes)g.resID) >= g.value) //goal is already fulfilled. Why we need this check, anyway?
 		throw goalFulfilledException(sptr(g));
 
 	int accquiredResources = 0;
@@ -2200,7 +1683,7 @@ void VCAI::tryRealize(Goals::Trade & g) //trade
 	{
 		if(const IMarket * m = IMarket::castFrom(obj, false))
 		{
-			auto freeRes = ah->freeResources(); //trade only resources which are not reserved
+			auto freeRes = cb->getResourceAmount(); //trade only resources which are not reserved
 			for(auto it = Res::ResourceSet::nziterator(freeRes); it.valid(); it++)
 			{
 				auto res = it->resType;
@@ -2217,7 +1700,7 @@ void VCAI::tryRealize(Goals::Trade & g) //trade
 					accquiredResources = toGet * (it->resVal / toGive);
 					logAi->debug("Traded %d of %s for %d of %s at %s", toGive, res, accquiredResources, g.resID, obj->getObjectName());
 				}
-				if (ah->freeResources()[g.resID] >= g.value)
+				if (cb->getResourceAmount((Res::ERes)g.resID) >= g.value)
 					throw goalFulfilledException(sptr(g)); //we traded all we needed
 			}
 
@@ -2255,7 +1738,7 @@ void VCAI::tryRealize(Goals::BuyArmy & g)
 
 	for (int i = 0; valueBought < g.value && i < armyToBuy.size(); i++)
 	{
-		auto res = ah->allResources();
+		auto res = cb->getResourceAmount();
 		auto & ci = armyToBuy[i];
 
 		if(g.objid != -1 && ci.creID != g.objid)
@@ -2365,140 +1848,6 @@ void VCAI::endTurn()
 	logGlobal->info("Player %d (%s) ended turn", playerID, playerID.getStr());
 }
 
-void VCAI::striveToGoal(Goals::TSubgoal basicGoal)
-{
-	//TODO: this function is deprecated and should be dropped altogether
-
-	auto goalToDecompose = basicGoal;
-	Goals::TSubgoal elementarGoal = sptr(Goals::Invalid());
-	int maxAbstractGoals = 10;
-	while (!elementarGoal->isElementar && maxAbstractGoals)
-	{
-		try
-		{
-			elementarGoal = decomposeGoal(goalToDecompose);
-		}
-		catch (goalFulfilledException & e)
-		{
-			//it is impossible to continue some goals (like exploration, for example)
-			completeGoal(e.goal); //put in goalsToRemove
-			logAi->debug("Goal %s decomposition failed: goal was completed as much as possible", e.goal->name());
-			return;
-		}
-		catch (std::exception & e)
-		{
-			goalsToRemove.push_back(basicGoal);
-			logAi->debug("Goal %s decomposition failed: %s", basicGoal->name(), e.what());
-			return;
-		}
-		if (elementarGoal->isAbstract) //we can decompose it further
-		{
-			goalsToAdd.push_back(elementarGoal);
-			//decompose further now - this is necesssary if we can't add over 10 goals in the pool
-			goalToDecompose = elementarGoal;
-			//there is a risk of infinite abstract goal loop, though it indicates failed logic
-			maxAbstractGoals--;
-		}
-		else if (elementarGoal->isElementar) //should be
-		{
-			logAi->debug("Found elementar goal %s", elementarGoal->name());
-			ultimateGoalsFromBasic[elementarGoal].push_back(goalToDecompose); //TODO: how about indirect basicGoal?
-			break;
-		}
-		else //should never be here
-			throw cannotFulfillGoalException("Goal %s is neither abstract nor elementar!" + basicGoal->name());
-	}
-
-	//realize best goal
-	if (!elementarGoal->invalid())
-	{
-		logAi->debug("Trying to realize %s (value %2.3f)", elementarGoal->name(), elementarGoal->priority);
-
-		try
-		{
-			boost::this_thread::interruption_point();
-			elementarGoal->accept(this); //visitor pattern
-			boost::this_thread::interruption_point();
-		}
-		catch (boost::thread_interrupted & e)
-		{
-			logAi->debug("Player %d: Making turn thread received an interruption!", playerID);
-			throw; //rethrow, we want to truly end this thread
-		}
-		catch (goalFulfilledException & e)
-		{
-			//the sub-goal was completed successfully
-			completeGoal(e.goal);
-			//local goal was also completed
-			completeGoal(elementarGoal);
-		}
-		catch (std::exception & e)
-		{
-			logAi->debug("Failed to realize subgoal of type %s, I will stop.", elementarGoal->name());
-			logAi->debug("The error message was: %s", e.what());
-
-			//erase base goal if we failed to execute decomposed goal
-			for (auto basicGoalToRemove : ultimateGoalsFromBasic[elementarGoal])
-				goalsToRemove.push_back(basicGoalToRemove);
-		}
-	}
-}
-
-Goals::TSubgoal VCAI::decomposeGoal(Goals::TSubgoal ultimateGoal)
-{
-	if(ultimateGoal->isElementar)
-	{
-		logAi->warn("Trying to decompose elementar goal %s", ultimateGoal->name());
-
-		return ultimateGoal;
-	}
-
-	const int searchDepth = 30;
-
-	Goals::TSubgoal goal = ultimateGoal;
-	logAi->debug("Decomposing goal %s", ultimateGoal->name());
-	int maxGoals = searchDepth; //preventing deadlock for mutually dependent goals
-	while (maxGoals)
-	{
-		boost::this_thread::interruption_point();
-
-		goal = goal->whatToDoToAchieve(); //may throw if decomposition fails
-		--maxGoals;
-		if (goal == ultimateGoal) //compare objects by value
-			if (goal->isElementar == ultimateGoal->isElementar)
-				throw cannotFulfillGoalException((boost::format("Goal dependency loop detected for %s!")
-												% ultimateGoal->name()).str());
-		if (goal->isAbstract || goal->isElementar)
-			return goal;
-		else
-			logAi->debug("Considering: %s", goal->name());
-	}
-
-	throw cannotFulfillGoalException("Too many subgoals, don't know what to do");
-}
-
-void VCAI::performTypicalActions()
-{
-	for(auto h : getUnblockedHeroes())
-	{
-		if(!h) //hero might be lost. getUnblockedHeroes() called once on start of turn
-			continue;
-
-		logAi->debug("Hero %s started wandering, MP=%d", h->name.c_str(), h->movement);
-		makePossibleUpgrades(*h);
-		pickBestArtifacts(*h);
-		try
-		{
-			wander(h);
-		}
-		catch(std::exception & e)
-		{
-			logAi->debug("Cannot use this hero anymore, received exception: %s", e.what());
-			continue;
-		}
-	}
-}
-
 void VCAI::buildArmyIn(const CGTownInstance * t)
 {
 	makePossibleUpgrades(t->visitingHero);
@@ -2507,16 +1856,6 @@ void VCAI::buildArmyIn(const CGTownInstance * t)
 	moveCreaturesToHero(t);
 }
 
-void VCAI::checkHeroArmy(HeroPtr h)
-{
-	auto it = lockedHeroes.find(h);
-	if(it != lockedHeroes.end())
-	{
-		if(it->second->goalType == Goals::GATHER_ARMY && it->second->value <= h->getArmyStrength())
-			completeGoal(sptr(Goals::GatherArmy(it->second->value).sethero(h)));
-	}
-}
-
 void VCAI::recruitHero(const CGTownInstance * t, bool throwing)
 {
 	logAi->debug("Trying to recruit a hero in %s at %s", t->name, t->visitablePos().toString());
@@ -2547,6 +1886,8 @@ void VCAI::recruitHero(const CGTownInstance * t, bool throwing)
 
 void VCAI::finish()
 {
+	//we want to lock to avoid multiple threads from calling makingTurn->join() at same time
+	boost::lock_guard<boost::mutex> multipleCleanupGuard(turnInterruptionMutex);
 	if(makingTurn)
 	{
 		makingTurn->interrupt();
@@ -2570,41 +1911,11 @@ void VCAI::lostHero(HeroPtr h)
 {
 	logAi->debug("I lost my hero %s. It's best to forget and move on.", h.name);
 
-	vstd::erase_if_present(lockedHeroes, h);
-	for(auto obj : reservedHeroesMap[h])
-	{
-		vstd::erase_if_present(reservedObjs, obj); //unreserve all objects for that hero
-	}
-	vstd::erase_if_present(reservedHeroesMap, h);
 	vstd::erase_if_present(visitedHeroes, h);
 	for (auto heroVec : visitedHeroes)
 	{
 		vstd::erase_if_present(heroVec.second, h);
 	}
-
-	//remove goals with removed hero assigned from main loop
-	vstd::erase_if(ultimateGoalsFromBasic, [&](const std::pair<Goals::TSubgoal, Goals::TGoalVec> & x) -> bool
-	{
-		if(x.first->hero == h)
-			return true;
-		else
-			return false;
-	});
-
-	auto removedHeroGoalPredicate = [&](const Goals::TSubgoal & x) ->bool
-	{
-		if(x->hero == h)
-			return true;
-		else
-			return false;
-	};
-
-	vstd::erase_if(basicGoals, removedHeroGoalPredicate);
-	vstd::erase_if(goalsToAdd, removedHeroGoalPredicate);
-	vstd::erase_if(goalsToRemove, removedHeroGoalPredicate);
-
-	for(auto goal : ultimateGoalsFromBasic)
-		vstd::erase_if(goal.second, removedHeroGoalPredicate);
 }
 
 void VCAI::answerQuery(QueryID queryID, int selection)
@@ -2914,7 +2225,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 	case Obj::SCHOOL_OF_MAGIC:
 	case Obj::SCHOOL_OF_WAR:
 	{
-		if (ai->ah->freeGold() < 1000)
+		if (cb->getResourceAmount(Res::GOLD) < 1000)
 			return false;
 		break;
 	}
@@ -2924,7 +2235,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 		break;
 	case Obj::TREE_OF_KNOWLEDGE:
 	{
-		TResources myRes = ai->ah->freeResources();
+		TResources myRes = cb->getResourceAmount();
 		if(myRes[Res::GOLD] < 2000 || myRes[Res::GEMS] < 10)
 			return false;
 		break;
@@ -2939,7 +2250,7 @@ bool shouldVisit(HeroPtr h, const CGObjectInstance * obj)
 		//TODO: only on request
 		if(ai->myCb->getHeroesInfo().size() >= VLC->modh->settings.MAX_HEROES_ON_MAP_PER_PLAYER)
 			return false;
-		else if(ai->ah->freeGold() < GameConstants::HERO_GOLD_COST)
+		else if(cb->getResourceAmount(Res::GOLD) < GameConstants::HERO_GOLD_COST)
 			return false;
 		break;
 	}

+ 3 - 19
AI/Nullkiller/VCAI.h

@@ -13,9 +13,7 @@
 #include "Goals/AbstractGoal.h"
 #include "../../lib/AI_Base.h"
 #include "../../CCallback.h"
-
 #include "../../lib/CThreadHelper.h"
-
 #include "../../lib/GameConstants.h"
 #include "../../lib/VCMI_Lib.h"
 #include "../../lib/CBuildingHandler.h"
@@ -90,12 +88,6 @@ public:
 	//std::vector<const CGObjectInstance *> visitedThisWeek; //only OPWs
 	std::map<HeroPtr, std::set<const CGTownInstance *>> townVisitsThisWeek;
 
-	//part of mainLoop, but accessible from outisde
-	std::vector<Goals::TSubgoal> basicGoals;
-	Goals::TGoalVec goalsToRemove;
-	Goals::TGoalVec goalsToAdd;
-	std::map<Goals::TSubgoal, Goals::TGoalVec> ultimateGoalsFromBasic; //theoreticlaly same goal can fulfill multiple basic goals
-
 	std::set<HeroPtr> invalidPathHeroes; //FIXME, just a workaround
 	std::map<HeroPtr, Goals::TSubgoal> lockedHeroes; //TODO: allow non-elementar objectives
 	std::map<HeroPtr, std::set<const CGObjectInstance *>> reservedHeroesMap; //objects reserved by specific heroes
@@ -113,6 +105,9 @@ public:
 	std::shared_ptr<CCallback> myCb;
 
 	std::unique_ptr<boost::thread> makingTurn;
+private:
+	boost::mutex turnInterruptionMutex;
+public:
 	ObjectInstanceID selectedObject;
 
 	AIhelper * ah;
@@ -199,17 +194,9 @@ public:
 	void battleEnd(const BattleResult * br) override;
 
 	void makeTurn();
-	void mainLoop();
-	void performTypicalActions();
 
 	void buildArmyIn(const CGTownInstance * t);
-	void striveToGoal(Goals::TSubgoal ultimateGoal);
-	Goals::TSubgoal decomposeGoal(Goals::TSubgoal ultimateGoal);
 	void endTurn();
-	void wander(HeroPtr h);
-	void setGoal(HeroPtr h, Goals::TSubgoal goal);
-	void evaluateGoal(HeroPtr h); //evaluates goal assigned to hero, if any
-	void completeGoal(Goals::TSubgoal goal); //safely removes goal from reserved hero
 
 	void recruitHero(const CGTownInstance * t, bool throwing = false);
 	bool isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, boost::optional<float> movementCostLimit = boost::none);
@@ -230,8 +217,6 @@ public:
 
 	void addVisitableObj(const CGObjectInstance * obj);
 	void markObjectVisited(const CGObjectInstance * obj);
-	void reserveObject(HeroPtr h, const CGObjectInstance * obj); //TODO: reserve all objects that heroes attempt to visit
-	void unreserveObject(HeroPtr h, const CGObjectInstance * obj);
 
 	void markHeroUnableToExplore(HeroPtr h);
 	void markHeroAbleToExplore(HeroPtr h);
@@ -261,7 +246,6 @@ public:
 	std::vector<HeroPtr> getUnblockedHeroes() const;
 	std::vector<HeroPtr> getMyHeroes() const;
 	HeroPtr primaryHero() const;
-	void checkHeroArmy(HeroPtr h);
 
 	void requestSent(const CPackForServer * pack, int requestID) override;
 	void answerQuery(QueryID queryID, int selection);

+ 3 - 3
AI/Nullkiller/VCAI.vcxproj

@@ -21,7 +21,7 @@
   <PropertyGroup Label="Globals">
     <ProjectGuid>{276C3DB0-7A6B-4417-8E5C-322B08633AAC}</ProjectGuid>
     <RootNamespace>StupidAI</RootNamespace>
-    <WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@@ -41,7 +41,7 @@
     <UseDebugLibraries>false</UseDebugLibraries>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
-    <PlatformToolset>v141</PlatformToolset>
+    <PlatformToolset>v142</PlatformToolset>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='RD|x64'" Label="Configuration">
     <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -117,7 +117,7 @@
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
-      <Optimization>MaxSpeed</Optimization>
+      <Optimization>Disabled</Optimization>
     </ClCompile>
     <Link>
       <AdditionalDependencies>VCMI_lib.lib;FuzzyLite.lib;%(AdditionalDependencies)</AdditionalDependencies>