Browse Source

Nullkiller: refactoring and stabilization of gather army & clusterization

Andrii Danylchenko 4 năm trước cách đây
mục cha
commit
35a1167f3d
36 tập tin đã thay đổi với 254 bổ sung1521 xóa
  1. 8 20
      AI/Nullkiller/Analyzers/ObjectClusterizer.cpp
  2. 1 1
      AI/Nullkiller/Behaviors/ClusterBehavior.cpp
  3. 49 40
      AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp
  4. 8 10
      AI/Nullkiller/CMakeLists.txt
  5. 36 2
      AI/Nullkiller/Engine/PriorityEvaluator.cpp
  6. 3 3
      AI/Nullkiller/Goals/AbstractGoal.h
  7. 0 85
      AI/Nullkiller/Goals/ClearWayTo.cpp
  8. 0 45
      AI/Nullkiller/Goals/ClearWayTo.h
  9. 0 191
      AI/Nullkiller/Goals/CollectRes.cpp
  10. 0 38
      AI/Nullkiller/Goals/CollectRes.h
  11. 2 19
      AI/Nullkiller/Goals/CompleteQuest.cpp
  12. 0 0
      AI/Nullkiller/Goals/CompleteQuest.h
  13. 0 90
      AI/Nullkiller/Goals/Conquer.cpp
  14. 0 32
      AI/Nullkiller/Goals/Conquer.h
  15. 0 432
      AI/Nullkiller/Goals/Explore.cpp
  16. 0 64
      AI/Nullkiller/Goals/Explore.h
  17. 0 138
      AI/Nullkiller/Goals/GatherTroops.cpp
  18. 0 38
      AI/Nullkiller/Goals/GatherTroops.h
  19. 0 29
      AI/Nullkiller/Goals/GetArtOfType.cpp
  20. 0 34
      AI/Nullkiller/Goals/GetArtOfType.h
  21. 0 3
      AI/Nullkiller/Goals/Goals.h
  22. 0 29
      AI/Nullkiller/Goals/VisitHero.cpp
  23. 0 36
      AI/Nullkiller/Goals/VisitHero.h
  24. 0 41
      AI/Nullkiller/Goals/VisitObj.cpp
  25. 0 30
      AI/Nullkiller/Goals/VisitObj.h
  26. 0 30
      AI/Nullkiller/Goals/VisitTile.cpp
  27. 0 35
      AI/Nullkiller/Goals/VisitTile.h
  28. 36 0
      AI/Nullkiller/Markers/ArmyUpgrade.cpp
  29. 35 0
      AI/Nullkiller/Markers/ArmyUpgrade.h
  30. 36 0
      AI/Nullkiller/Markers/HeroExchange.cpp
  31. 34 0
      AI/Nullkiller/Markers/HeroExchange.h
  32. 0 0
      AI/Nullkiller/Markers/UnlockCluster.cpp
  33. 1 1
      AI/Nullkiller/Markers/UnlockCluster.h
  34. 3 3
      AI/Nullkiller/Pathfinding/AINodeStorage.cpp
  35. 1 1
      AI/Nullkiller/Pathfinding/AINodeStorage.h
  36. 1 1
      AI/Nullkiller/Pathfinding/Actions/BattleAction.cpp

+ 8 - 20
AI/Nullkiller/Analyzers/ObjectClusterizer.cpp

@@ -241,7 +241,6 @@ void ObjectClusterizer::clusterize()
 			continue;
 		}
 		
-		bool directlyAccessible = false;
 		std::set<const CGHeroInstance *> heroesProcessed;
 
 		for(auto & path : paths)
@@ -292,44 +291,33 @@ void ObjectClusterizer::clusterize()
 #if AI_TRACE_LEVEL >= 2
 					logAi->trace("Path added to cluster %s%s", blocker->getObjectName(), blocker->visitablePos().toString());
 #endif
+					continue;
 				}
-				else
-				{
-					directlyAccessible = true;
-				}
-			}
-			else
-			{
-				directlyAccessible = true;
 			}
 			
 			heroesProcessed.insert(path.targetHero);
-		}
 
-		if(directlyAccessible)
-		{
-			AIPath & shortestPath = paths.front();
-			float priority = ai->priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(shortestPath, obj)));
+			float priority = ai->priorityEvaluator->evaluate(Goals::sptr(Goals::ExecuteHeroChain(path, obj)));
 
 			if(priority < MIN_PRIORITY)
 				continue;
-
-			bool interestingObject = shortestPath.turn() <= 2 || priority > 0.5f;
+			
+			bool interestingObject = path.turn() <= 2 || priority > 0.5f;
 
 			if(interestingObject)
 			{
-				nearObjects.addObject(obj, shortestPath, priority);
+				nearObjects.addObject(obj, path, priority);
 			}
 			else
 			{
-				farObjects.addObject(obj, shortestPath, priority);
+				farObjects.addObject(obj, path, priority);
 			}
 
 #if AI_TRACE_LEVEL >= 2
 			logAi->trace("Path %s added to %s objects. Turn: %d, priority: %f",
-				shortestPath.toString(),
+				path.toString(),
 				interestingObject ? "near" : "far",
-				shortestPath.turn(),
+				path.turn(),
 				priority);
 #endif
 		}

+ 1 - 1
AI/Nullkiller/Behaviors/ClusterBehavior.cpp

@@ -12,7 +12,7 @@
 #include "../VCAI.h"
 #include "../Engine/Nullkiller.h"
 #include "../AIUtility.h"
-#include "../Goals/UnlockCluster.h"
+#include "../Markers/UnlockCluster.h"
 #include "../Goals/Composition.h"
 #include "../Behaviors/CaptureObjectsBehavior.h"
 

+ 49 - 40
AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp

@@ -11,6 +11,9 @@
 #include "../VCAI.h"
 #include "../Engine/Nullkiller.h"
 #include "../Goals/ExecuteHeroChain.h"
+#include "../Goals/Composition.h"
+#include "../Markers/HeroExchange.h"
+#include "../Markers/ArmyUpgrade.h"
 #include "GatherArmyBehavior.h"
 #include "../AIUtility.h"
 #include "lib/mapping/CMap.h" //for victory conditions
@@ -73,7 +76,6 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
 	}
 
 	auto paths = ai->nullkiller->pathfinder->getPathInfo(pos);
-	std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
 
 #if AI_TRACE_LEVEL >= 1
 	logAi->trace("Found %d paths", paths.size());
@@ -87,32 +89,43 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
 		
 		if(path.containsHero(hero)) continue;
 
-		if(path.getFirstBlockedAction())
+		if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
 		{
 #if AI_TRACE_LEVEL >= 2
-			// TODO: decomposition
-			logAi->trace("Ignore path. Action is blocked.");
+			logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
 #endif
 			continue;
 		}
 
-		if(ai->nullkiller->dangerHitMap->enemyCanKillOurHeroesAlongThePath(path))
+		if(ai->nullkiller->arePathHeroesLocked(path))
 		{
 #if AI_TRACE_LEVEL >= 2
-			logAi->trace("Ignore path. Target hero can be killed by enemy. Our power %lld", path.heroArmy->getArmyStrength());
+			logAi->trace("Ignore path because of locked hero");
 #endif
 			continue;
 		}
 
-		float armyValue = (float)ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero, path.heroArmy) / hero->getArmyStrength();
+		HeroExchange heroExchange(hero, path);
+
+		float armyValue = (float)heroExchange.getReinforcementArmyStrength() / hero->getArmyStrength();
 
 		// avoid transferring very small amount of army
 		if(armyValue < 0.1f)
+		{
+#if AI_TRACE_LEVEL >= 2
+			logAi->trace("Army value is too small.");
+#endif
 			continue;
+		}
 
 		// avoid trying to move bigger army to the weaker one.
-		if(armyValue > 0.5f)
+		if(armyValue > 1)
+		{
+#if AI_TRACE_LEVEL >= 2
+			logAi->trace("Army value is too large.");
+#endif
 			continue;
+		}
 
 		auto danger = path.getTotalDanger();
 
@@ -131,24 +144,26 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const CGHeroInstance * her
 
 		if(isSafe)
 		{
-			auto newWay = std::make_shared<ExecuteHeroChain>(path, hero);
-
-			newWay->strategicalValue = armyValue;
-			waysToVisitObj.push_back(newWay);
-		}
-	}
+			Composition composition;
+			ExecuteHeroChain exchangePath(path, hero);
 
-	if(waysToVisitObj.empty())
-		return tasks;
+			exchangePath.closestWayRatio = 1;
 
-	for(auto way : waysToVisitObj)
-	{
-		if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
-			continue;
+			composition.addNext(heroExchange);
+			composition.addNext(exchangePath);
 
-		way->closestWayRatio = 1;
+			auto blockedAction = path.getFirstBlockedAction();
 
-		tasks.push_back(sptr(*way));
+			if(blockedAction)
+			{
+	#if AI_TRACE_LEVEL >= 2
+				logAi->trace("Action is blocked. Considering decomposition.");
+	#endif
+				composition.addNext(blockedAction->decompose(path.targetHero));
+			}
+			
+			tasks.push_back(sptr(composition));
+		}
 	}
 
 	return tasks;
@@ -184,6 +199,14 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
 			continue;
 		}
 
+		if(ai->nullkiller->arePathHeroesLocked(path))
+		{
+#if AI_TRACE_LEVEL >= 2
+			logAi->trace("Ignore path because of locked hero");
+#endif
+			continue;
+		}
+
 		if(path.getFirstBlockedAction())
 		{
 #if AI_TRACE_LEVEL >= 2
@@ -224,27 +247,13 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const CGTownInstance * upgrader)
 
 		if(isSafe)
 		{
-			auto newWay = std::make_shared<ExecuteHeroChain>(path, upgrader);
+			ExecuteHeroChain newWay(path, upgrader);
+			
+			newWay.closestWayRatio = 1;
 
-			newWay->strategicalValue = armyValue;
-			newWay->goldCost = upgrade.upgradeCost[Res::GOLD];
-
-			waysToVisitObj.push_back(newWay);
+			tasks.push_back(sptr(Composition().addNext(ArmyUpgrade(path, upgrader, upgrade)).addNext(newWay)));
 		}
 	}
 
-	if(waysToVisitObj.empty())
-		return tasks;
-
-	for(auto way : waysToVisitObj)
-	{
-		if(ai->nullkiller->arePathHeroesLocked(way->getPath()))
-			continue;
-
-		way->closestWayRatio = 1;
-
-		tasks.push_back(sptr(*way));
-	}
-
 	return tasks;
 }

+ 8 - 10
AI/Nullkiller/CMakeLists.txt

@@ -24,17 +24,17 @@ set(VCAI_SRCS
 		Goals/BuildBoat.cpp
 		Goals/BuildThis.cpp
 		Goals/DismissHero.cpp
-		Goals/GatherTroops.cpp
 		Goals/BuyArmy.cpp
 		Goals/AdventureSpellCast.cpp
-		Goals/CollectRes.cpp
 		Goals/Trade.cpp
 		Goals/RecruitHero.cpp
-		Goals/UnlockCluster.cpp
 		Goals/DigAtTile.cpp
-		Goals/GetArtOfType.cpp
 		Goals/ExecuteHeroChain.cpp
 		Goals/ExchangeSwapTownHeroes.cpp
+		Goals/CompleteQuest.cpp
+		Markers/ArmyUpgrade.cpp
+		Markers/HeroExchange.cpp
+		Markers/UnlockCluster.cpp
 		Engine/Nullkiller.cpp
 		Engine/PriorityEvaluator.cpp
 		Analyzers/DangerHitMapAnalyzer.cpp
@@ -47,7 +47,6 @@ set(VCAI_SRCS
 		Behaviors/StartupBehavior.cpp
 		Behaviors/BuildingBehavior.cpp
 		Behaviors/GatherArmyBehavior.cpp
-		Behaviors/CompleteQuestBehavior.cpp
 		Behaviors/ClusterBehavior.cpp
 		main.cpp
 		VCAI.cpp
@@ -81,18 +80,18 @@ set(VCAI_HEADERS
 		Goals/BuildBoat.h
 		Goals/BuildThis.h
 		Goals/DismissHero.h
-		Goals/GatherTroops.h
 		Goals/BuyArmy.h
 		Goals/AdventureSpellCast.h
-		Goals/CollectRes.h
 		Goals/Trade.h
-		Goals/UnlockCluster.h
 		Goals/RecruitHero.h
 		Goals/DigAtTile.h
-		Goals/GetArtOfType.h
 		Goals/ExecuteHeroChain.h
 		Goals/ExchangeSwapTownHeroes.h
+		Goals/CompleteQuest.h
 		Goals/Goals.h
+		Markers/ArmyUpgrade.h
+		Markers/HeroExchange.h
+		Markers/UnlockCluster.h
 		Engine/Nullkiller.h
 		Engine/PriorityEvaluator.h
 		Analyzers/DangerHitMapAnalyzer.h
@@ -105,7 +104,6 @@ set(VCAI_HEADERS
 		Behaviors/StartupBehavior.h
 		Behaviors/BuildingBehavior.h
 		Behaviors/GatherArmyBehavior.h
-		Behaviors/CompleteQuestBehavior.h
 		Behaviors/ClusterBehavior.h
 		VCAI.h
 )

+ 36 - 2
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -20,8 +20,10 @@
 #include "../../../CCallback.h"
 #include "../../../lib/filesystem/Filesystem.h"
 #include "../Goals/ExecuteHeroChain.h"
-#include "../Goals/UnlockCluster.h"
+#include "../Markers/UnlockCluster.h"
 #include "../Goals/BuildThis.h"
+#include "../Markers/HeroExchange.h"
+#include "../Markers/ArmyUpgrade.h"
 
 #define MIN_AI_STRENGHT (0.5f) //lower when combat AI gets smarter
 #define UNGUARDED_OBJECT (100.0f) //we consider unguarded objects 100 times weaker than us
@@ -456,6 +458,38 @@ int32_t RewardEvaluator::getGoldReward(const CGObjectInstance * target, const CG
 	}
 }
 
+class HeroExchangeEvaluator : public IEvaluationContextBuilder
+{
+public:
+	virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
+	{
+		if(task->goalType != Goals::HERO_EXCHANGE)
+			return;
+
+		Goals::HeroExchange & heroExchange = dynamic_cast<Goals::HeroExchange &>(*task);
+
+		uint64_t armyStrength = heroExchange.getReinforcementArmyStrength();
+
+		evaluationContext.strategicalValue += 0.5f * armyStrength / heroExchange.hero.get()->getArmyStrength();
+	}
+};
+
+class ArmyUpgradeEvaluator : public IEvaluationContextBuilder
+{
+public:
+	virtual void buildEvaluationContext(EvaluationContext & evaluationContext, Goals::TSubgoal task) const override
+	{
+		if(task->goalType != Goals::ARMY_UPGRADE)
+			return;
+
+		Goals::ArmyUpgrade & armyUpgrade = dynamic_cast<Goals::ArmyUpgrade &>(*task);
+
+		uint64_t upgradeValue = armyUpgrade.getUpgradeValue();
+
+		evaluationContext.armyReward += upgradeValue;
+	}
+};
+
 class ExecuteHeroChainEvaluationContextBuilder : public IEvaluationContextBuilder
 {
 public:
@@ -610,6 +644,7 @@ PriorityEvaluator::PriorityEvaluator(const Nullkiller * ai)
 	evaluationContextBuilders.push_back(std::make_shared<ExecuteHeroChainEvaluationContextBuilder>());
 	evaluationContextBuilders.push_back(std::make_shared<BuildThisEvaluationContextBuilder>());
 	evaluationContextBuilders.push_back(std::make_shared<ClusterEvaluationContextBuilder>());
+	evaluationContextBuilders.push_back(std::make_shared<HeroExchangeEvaluator>());
 }
 
 EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal) const
@@ -628,7 +663,6 @@ EvaluationContext PriorityEvaluator::buildEvaluationContext(Goals::TSubgoal goal
 
 	for(auto subgoal : parts)
 	{
-		context.strategicalValue += subgoal->strategicalValue;
 		context.goldCost += subgoal->goldCost;
 
 		for(auto builder : evaluationContextBuilders)

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

@@ -63,7 +63,9 @@ namespace Goals
 		DISMISS_HERO,
 		COMPOSITION,
 		CLUSTER_BEHAVIOR,
-		UNLOCK_CLUSTER
+		UNLOCK_CLUSTER,
+		HERO_EXCHANGE,
+		ARMY_UPGRADE
 	};
 
 	class DLL_EXPORT TSubgoal : public std::shared_ptr<AbstractGoal>
@@ -96,7 +98,6 @@ namespace Goals
 	public:
 		bool isAbstract; VSETTER(bool, isAbstract)
 		int value; VSETTER(int, value)
-		float strategicalValue; VSETTER(float, strategicalValue)
 		ui64 goldCost; VSETTER(ui64, goldCost)
 		int resID; VSETTER(int, resID)
 		int objid; VSETTER(int, objid)
@@ -119,7 +120,6 @@ namespace Goals
 			tile = int3(-1, -1, -1);
 			town = nullptr;
 			bid = -1;
-			strategicalValue = 0;
 			goldCost = 0;
 		}
 		virtual ~AbstractGoal() {}

+ 0 - 85
AI/Nullkiller/Goals/ClearWayTo.cpp

@@ -1,85 +0,0 @@
-/*
-* ClearWayTo.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 "ClearWayTo.h"
-#include "Explore.h"
-#include "RecruitHero.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../FuzzyHelper.h"
-#include "../AIhelper.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-bool ClearWayTo::operator==(const ClearWayTo & other) const
-{
-	return other.hero.h == hero.h && other.tile == tile;
-}
-
-TSubgoal ClearWayTo::whatToDoToAchieve()
-{
-	assert(cb->isInTheMap(tile)); //set tile
-	if(!cb->isVisible(tile))
-	{
-		logAi->error("Clear way should be used with visible tiles!");
-		return sptr(Explore());
-	}
-
-	return (fh->chooseSolution(getAllPossibleSubgoals()));
-}
-
-bool ClearWayTo::fulfillsMe(TSubgoal goal)
-{
-	if (goal->goalType == VISIT_TILE)
-	{
-		if (!hero || hero == goal->hero)
-			return tile == goal->tile;
-	}
-	return false;
-}
-
-TGoalVec ClearWayTo::getAllPossibleSubgoals()
-{
-	TGoalVec ret;
-
-	std::vector<const CGHeroInstance *> heroes;
-	if(hero)
-		heroes.push_back(hero.h);
-	else
-		heroes = cb->getHeroesInfo();
-
-	for(auto h : heroes)
-	{
-		//TODO: handle clearing way to allied heroes that are blocked
-		//if ((hero && hero->visitablePos() == tile && hero == *h) || //we can't free the way ourselves
-		//	h->visitablePos() == tile) //we are already on that tile! what does it mean?
-		//	continue;
-
-		//if our hero is trapped, make sure we request clearing the way from OUR perspective
-
-		vstd::concatenate(ret, ai->ah->howToVisitTile(h, tile));
-	}
-
-	if(ret.empty() && ai->canRecruitAnyHero())
-		ret.push_back(sptr(RecruitHero()));
-
-	if(ret.empty())
-	{
-		logAi->warn("There is no known way to clear the way to tile %s", tile.toString());
-		throw goalFulfilledException(sptr(ClearWayTo(tile))); //make sure asigned hero gets unlocked
-	}
-
-	return ret;
-}

+ 0 - 45
AI/Nullkiller/Goals/ClearWayTo.h

@@ -1,45 +0,0 @@
-/*
-* ClearWayTo.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
-{
-	class DLL_EXPORT ClearWayTo : public CGoal<ClearWayTo>
-	{
-	public:
-		ClearWayTo()
-			: CGoal(Goals::CLEAR_WAY_TO)
-		{
-		}
-		ClearWayTo(int3 Tile)
-			: CGoal(Goals::CLEAR_WAY_TO)
-		{
-			tile = Tile;
-			priority = 5;
-		}
-		ClearWayTo(int3 Tile, HeroPtr h)
-			: CGoal(Goals::CLEAR_WAY_TO)
-		{
-			tile = Tile;
-			hero = h;
-			priority = 5;
-		}
-		TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;
-		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const ClearWayTo & other) const override;
-	};
-}

+ 0 - 191
AI/Nullkiller/Goals/CollectRes.cpp

@@ -1,191 +0,0 @@
-/*
-* CollectRes.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 "Goals.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../../../lib/mapping/CMap.h" //for victory conditions
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-
-using namespace Goals;
-
-bool CollectRes::operator==(const CollectRes & other) const
-{
-	return resID == other.resID;
-}
-
-//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);
-	//	}
-	//}
-//	return ret;
-//}
-
-//TSubgoal CollectRes::whatToDoToAchieve()
-//{
-//	auto goals = getAllPossibleSubgoals();
-//	auto trade = whatToDoToTrade();
-//	if (!trade->invalid())
-//		goals.push_back(trade);
-//
-//	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
-	//		}
-	//	}
-	//}
-	return sptr(Invalid()); //cannot trade
-}

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

@@ -1,38 +0,0 @@
-/*
-* CollectRes.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
-{
-	class DLL_EXPORT CollectRes : public CGoal<CollectRes>
-	{
-	public:
-		CollectRes()
-			: CGoal(Goals::COLLECT_RES)
-		{
-		}
-		CollectRes(int rid, int val)
-			: CGoal(Goals::COLLECT_RES)
-		{
-			resID = rid;
-			value = val;
-		}
-		/*TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;*/
-		TSubgoal whatToDoToTrade();
-		virtual bool operator==(const CollectRes & other) const override;
-	};
-}

+ 2 - 19
AI/Nullkiller/Behaviors/CompleteQuestBehavior.cpp → AI/Nullkiller/Goals/CompleteQuest.cpp

@@ -8,8 +8,8 @@
 *
 */
 #include "StdInc.h"
-#include "CompleteQuestBehavior.h"
-#include "CaptureObjectsBehavior.h"
+#include "CompleteQuest.h"
+#include "../Behaviors/CaptureObjectsBehavior.h"
 #include "../VCAI.h"
 #include "../../../lib/mapping/CMap.h" //for victory conditions
 #include "../../../lib/CPathfinder.h"
@@ -26,23 +26,6 @@ std::string CompleteQuest::toString() const
 
 TGoalVec CompleteQuest::decompose() const
 {
-	/*TGoalVec solutions;
-
-	auto quests = cb->getMyQuests();
-
-	for(auto & q : quests)
-	{
-		if(q.quest->missionType == CQuest::MISSION_NONE
-			|| q.quest->progress == CQuest::COMPLETE)
-		{
-			continue;
-		}
-
-		vstd::concatenate(solutions, getQuestTasks());
-	}
-
-	return solutions;*/
-
 	if(q.obj && (q.obj->ID == Obj::BORDER_GATE || q.obj->ID == Obj::BORDERGUARD))
 	{
 		return missionKeymaster();

+ 0 - 0
AI/Nullkiller/Behaviors/CompleteQuestBehavior.h → AI/Nullkiller/Goals/CompleteQuest.h


+ 0 - 90
AI/Nullkiller/Goals/Conquer.cpp

@@ -1,90 +0,0 @@
-/*
-* Conquer.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 "Goals.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
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-bool Conquer::operator==(const Conquer & other) const
-{
-	return other.hero.h == hero.h;
-}
-
-TSubgoal Conquer::whatToDoToAchieve()
-{
-	logAi->trace("Entering goal CONQUER");
-
-	return fh->chooseSolution(getAllPossibleSubgoals());
-}
-
-TGoalVec Conquer::getAllPossibleSubgoals()
-{
-	TGoalVec ret;
-
-	auto conquerable = [](const CGObjectInstance * obj) -> bool
-	{
-		if(cb->getPlayerRelations(ai->playerID, obj->tempOwner) == PlayerRelations::ENEMIES)
-		{
-			switch(obj->ID.num)
-			{
-			case Obj::TOWN:
-			case Obj::HERO:
-			case Obj::CREATURE_GENERATOR1:
-			case Obj::MINE: //TODO: check ai->knownSubterraneanGates
-				return true;
-			}
-		}
-		return false;
-	};
-
-	std::vector<const CGObjectInstance *> objs;
-	for(auto obj : ai->visitableObjs)
-	{
-		if(conquerable(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(conquerable(obj))
-				ourObjs.push_back(obj);
-		}
-		for(auto obj : ourObjs)
-		{
-			auto waysToGo = ai->ah->howToVisitObj(h, ObjectIdRef(obj));
-
-			vstd::concatenate(ret, waysToGo);
-		}
-	}
-	if(!objs.empty() && ai->canRecruitAnyHero()) //probably no point to recruit hero if we see no objects to capture
-		ret.push_back(sptr(RecruitHero()));
-
-	if(ret.empty())
-		ret.push_back(sptr(Explore())); //we need to find an enemy
-	return ret;
-}

+ 0 - 32
AI/Nullkiller/Goals/Conquer.h

@@ -1,32 +0,0 @@
-/*
-* Conquer.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
-{
-	class DLL_EXPORT Conquer : public CGoal<Conquer>
-	{
-	public:
-		Conquer()
-			: CGoal(Goals::CONQUER)
-		{
-			priority = 10;
-		}
-		TGoalVec getAllPossibleSubgoals() override;
-		TSubgoal whatToDoToAchieve() override;
-		virtual bool operator==(const Conquer & other) const override;
-	};
-}

+ 0 - 432
AI/Nullkiller/Goals/Explore.cpp

@@ -1,432 +0,0 @@
-/*
-* Explore.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 "Goals.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
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-#include "../../../lib/CPlayerState.h"
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-namespace Goals
-{
-	struct ExplorationHelper
-	{
-		HeroPtr hero;
-		int sightRadius;
-		float bestValue;
-		TSubgoal bestGoal;
-		VCAI * aip;
-		CCallback * cbp;
-		const TeamState * ts;
-		int3 ourPos;
-		bool allowDeadEndCancellation;
-		bool allowGatherArmy;
-
-		ExplorationHelper(HeroPtr h, bool gatherArmy)
-		{
-			cbp = cb.get();
-			aip = ai.get();
-			hero = h;
-			ts = cbp->getPlayerTeam(ai->playerID);
-			sightRadius = hero->getSightRadius();
-			bestGoal = sptr(Goals::Invalid());
-			bestValue = 0;
-			ourPos = h->convertPosition(h->pos, false);
-			allowDeadEndCancellation = true;
-			allowGatherArmy = gatherArmy;
-		}
-
-		void scanSector(int scanRadius)
-		{
-			for(int x = ourPos.x - scanRadius; x <= ourPos.x + scanRadius; x++)
-			{
-				for(int y = ourPos.y - scanRadius; y <= ourPos.y + scanRadius; y++)
-				{
-					int3 tile = int3(x, y, ourPos.z);
-
-					if(cbp->isInTheMap(tile) && ts->fogOfWarMap[tile.x][tile.y][tile.z])
-					{
-						scanTile(tile);
-					}
-				}
-			}
-		}
-
-		void scanMap()
-		{
-			int3 mapSize = cbp->getMapSize();
-			int perimeter = 2 * sightRadius * (mapSize.x + mapSize.y);
-
-			std::vector<int3> from;
-			std::vector<int3> to;
-
-			from.reserve(perimeter);
-			to.reserve(perimeter);
-
-			foreach_tile_pos([&](const int3 & pos)
-			{
-				if(ts->fogOfWarMap[pos.x][pos.y][pos.z])
-				{
-					bool hasInvisibleNeighbor = false;
-
-					foreach_neighbour(cbp, pos, [&](CCallback * cbp, int3 neighbour)
-					{
-						if(!ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z])
-						{
-							hasInvisibleNeighbor = true;
-						}
-					});
-
-					if(hasInvisibleNeighbor)
-						from.push_back(pos);
-				}
-			});
-
-			logAi->debug("Exploration scan visible area perimeter for hero %s", hero.name);
-
-			for(const int3 & tile : from)
-			{
-				scanTile(tile);
-			}
-
-			if(!bestGoal->invalid())
-			{
-				return;
-			}
-
-			allowDeadEndCancellation = false;
-
-			for(int i = 0; i < sightRadius; i++)
-			{
-				getVisibleNeighbours(from, to);
-				vstd::concatenate(from, to);
-				vstd::removeDuplicates(from);
-			}
-
-			logAi->debug("Exploration scan all possible tiles for hero %s", hero.name);
-
-			for(const int3 & tile : from)
-			{
-				scanTile(tile);
-			}
-		}
-
-		void scanTile(const int3 & tile)
-		{
-			if(tile == ourPos
-				|| !aip->ah->isTileAccessible(hero, tile)) //shouldn't happen, but it does
-				return;
-
-			int tilesDiscovered = howManyTilesWillBeDiscovered(tile);
-			if(!tilesDiscovered)
-				return;
-
-			auto waysToVisit = aip->ah->howToVisitTile(hero, tile, allowGatherArmy);
-			for(auto goal : waysToVisit)
-			{
-				if(goal->evaluationContext.movementCost <= 0.0) // should not happen
-					continue;
-
-				float ourValue = (float)tilesDiscovered * tilesDiscovered / goal->evaluationContext.movementCost;
-
-				if(ourValue > bestValue) //avoid costly checks of tiles that don't reveal much
-				{
-					auto obj = cb->getTopObj(tile);
-
-					// picking up resources does not yield any exploration at all.
-					// if it blocks the way to some explorable tile AIPathfinder will take care of it
-					if(obj && obj->blockVisit)
-					{
-						continue;
-					}
-
-					if(isSafeToVisit(hero, tile))
-					{
-						bestGoal = goal;
-						bestValue = ourValue;
-					}
-				}
-			}
-		}
-
-		void getVisibleNeighbours(const std::vector<int3> & tiles, std::vector<int3> & out) const
-		{
-			for(const int3 & tile : tiles)
-			{
-				foreach_neighbour(cbp, tile, [&](CCallback * cbp, int3 neighbour)
-				{
-					if(ts->fogOfWarMap[neighbour.x][neighbour.y][neighbour.z])
-					{
-						out.push_back(neighbour);
-					}
-				});
-			}
-		}
-
-		int howManyTilesWillBeDiscovered(
-			const int3 & pos) const
-		{
-			int ret = 0;
-			for(int x = pos.x - sightRadius; x <= pos.x + sightRadius; x++)
-			{
-				for(int y = pos.y - sightRadius; y <= pos.y + sightRadius; y++)
-				{
-					int3 npos = int3(x, y, pos.z);
-					if(cbp->isInTheMap(npos)
-						&& pos.dist2d(npos) - 0.5 < sightRadius
-						&& !ts->fogOfWarMap[npos.x][npos.y][npos.z])
-					{
-						if(allowDeadEndCancellation
-							&& !hasReachableNeighbor(npos))
-						{
-							continue;
-						}
-
-						ret++;
-					}
-				}
-			}
-
-			return ret;
-		}
-
-		bool hasReachableNeighbor(const int3 &pos) const
-		{
-			for(crint3 dir : int3::getDirs())
-			{
-				int3 tile = pos + dir;
-				if(cbp->isInTheMap(tile))
-				{
-					auto isAccessible = aip->ah->isTileAccessible(hero, tile);
-
-					if(isAccessible)
-						return true;
-				}
-			}
-
-			return false;
-		}
-	};
-}
-
-bool Explore::operator==(const Explore & other) const
-{
-	return other.hero.h == hero.h && other.allowGatherArmy == allowGatherArmy;
-}
-
-TSubgoal Explore::whatToDoToAchieve()
-{
-	return sptr(Goals::Invalid());
-}
-
-TGoalVec Explore::getAllPossibleSubgoals()
-{
-	TGoalVec ret;
-	std::vector<const CGHeroInstance *> heroes;
-
-	if(hero)
-	{
-		heroes.push_back(hero.h);
-	}
-	else
-	{
-		//heroes = ai->getUnblockedHeroes();
-		heroes = cb->getHeroesInfo();
-		vstd::erase_if(heroes, [](const HeroPtr h)
-		{
-			if(ai->getGoal(h)->goalType == EXPLORE) //do not reassign hero who is already explorer
-				return true;
-
-			if(!ai->isAbleToExplore(h))
-				return true;
-
-			return !h->movement; //saves time, immobile heroes are useless anyway
-		});
-	}
-
-	//try to use buildings that uncover map
-	std::vector<const CGObjectInstance *> objs;
-	for(auto obj : ai->visitableObjs)
-	{
-		if(!vstd::contains(ai->alreadyVisited, obj))
-		{
-			switch(obj->ID.num)
-			{
-			case Obj::REDWOOD_OBSERVATORY:
-			case Obj::PILLAR_OF_FIRE:
-			case Obj::CARTOGRAPHER:
-				objs.push_back(obj);
-				break;
-			case Obj::MONOLITH_ONE_WAY_ENTRANCE:
-			case Obj::MONOLITH_TWO_WAY:
-			case Obj::SUBTERRANEAN_GATE:
-				auto tObj = dynamic_cast<const CGTeleport *>(obj);
-				assert(ai->knownTeleportChannels.find(tObj->channel) != ai->knownTeleportChannels.end());
-				if(TeleportChannel::IMPASSABLE != ai->knownTeleportChannels[tObj->channel]->passability)
-					objs.push_back(obj);
-				break;
-			}
-		}
-		else
-		{
-			switch(obj->ID.num)
-			{
-			case Obj::MONOLITH_TWO_WAY:
-			case Obj::SUBTERRANEAN_GATE:
-				auto tObj = dynamic_cast<const CGTeleport *>(obj);
-				if(TeleportChannel::IMPASSABLE == ai->knownTeleportChannels[tObj->channel]->passability)
-					break;
-				for(auto exit : ai->knownTeleportChannels[tObj->channel]->exits)
-				{
-					if(!cb->getObj(exit))
-					{ // Always attempt to visit two-way teleports if one of channel exits is not visible
-						objs.push_back(obj);
-						break;
-					}
-				}
-				break;
-			}
-		}
-	}
-
-	for(auto h : heroes)
-	{
-		for(auto obj : objs) //double loop, performance risk?
-		{
-			auto waysToVisitObj = ai->ah->howToVisitObj(h, obj, allowGatherArmy);
-
-			vstd::concatenate(ret, waysToVisitObj);
-		}
-
-		TSubgoal goal = exploreNearestNeighbour(h);
-
-		if(!goal->invalid())
-		{
-			ret.push_back(goal);
-		}
-	}
-
-	if(ret.empty())
-	{
-		for(auto h : heroes)
-		{
-			logAi->trace("Exploration searching for a new point for hero %s", h->name);
-
-			TSubgoal goal = explorationNewPoint(h);
-
-			if(goal->invalid())
-			{
-				ai->markHeroUnableToExplore(h); //there is no freely accessible tile, do not poll this hero anymore
-			}
-			else
-			{
-				ret.push_back(goal);
-			}
-		}
-	}
-
-	//we either don't have hero yet or none of heroes can explore
-	if((!hero || ret.empty()) && ai->canRecruitAnyHero())
-		ret.push_back(sptr(RecruitHero()));
-
-	if(ret.empty())
-	{
-		throw goalFulfilledException(sptr(Explore().sethero(hero)));
-	}
-
-	return ret;
-}
-
-TSubgoal Explore::explorationBestNeighbour(int3 hpos, HeroPtr h) const
-{
-	ExplorationHelper scanResult(h, allowGatherArmy);
-
-	for(crint3 dir : int3::getDirs())
-	{
-		int3 tile = hpos + dir;
-		if(cb->isInTheMap(tile))
-		{
-			scanResult.scanTile(tile);
-		}
-	}
-
-	return scanResult.bestGoal;
-}
-
-
-TSubgoal Explore::explorationNewPoint(HeroPtr h) const
-{
-	ExplorationHelper scanResult(h, allowGatherArmy);
-
-	scanResult.scanSector(10);
-
-	if(!scanResult.bestGoal->invalid())
-	{
-		return scanResult.bestGoal;
-	}
-
-	scanResult.scanMap();
-
-	return scanResult.bestGoal;
-}
-
-
-TSubgoal Explore::exploreNearestNeighbour(HeroPtr h) const
-{
-	TimeCheck tc("where to explore");
-	int3 hpos = h->visitablePos();
-
-	//look for nearby objs -> visit them if they're close enough
-	const int DIST_LIMIT = 3;
-	const float COST_LIMIT = .2; //todo: fine tune
-
-	std::vector<const CGObjectInstance *> nearbyVisitableObjs;
-	for(int x = hpos.x - DIST_LIMIT; x <= hpos.x + DIST_LIMIT; ++x) //get only local objects instead of all possible objects on the map
-	{
-		for(int y = hpos.y - DIST_LIMIT; y <= hpos.y + DIST_LIMIT; ++y)
-		{
-			for(auto obj : cb->getVisitableObjs(int3(x, y, hpos.z), false))
-			{
-				if(ai->isGoodForVisit(obj, h, COST_LIMIT))
-				{
-					nearbyVisitableObjs.push_back(obj);
-				}
-			}
-		}
-	}
-
-	if(nearbyVisitableObjs.size())
-	{
-		vstd::removeDuplicates(nearbyVisitableObjs); //one object may occupy multiple tiles
-		boost::sort(nearbyVisitableObjs, CDistanceSorter(h.get()));
-
-		TSubgoal pickupNearestObj = fh->chooseSolution(ai->ah->howToVisitObj(h, nearbyVisitableObjs.back(), false));
-
-		if(!pickupNearestObj->invalid())
-		{
-			return pickupNearestObj;
-		}
-	}
-
-	//check if nearby tiles allow us to reveal anything - this is quick
-	return explorationBestNeighbour(hpos, h);
-}

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

@@ -1,64 +0,0 @@
-///*
-//* 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;
-//	};
-//}

+ 0 - 138
AI/Nullkiller/Goals/GatherTroops.cpp

@@ -1,138 +0,0 @@
-/*
-* GatherTroops.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 "Goals.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../../../lib/mapping/CMap.h" //for victory conditions
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-
-using namespace Goals;
-
-bool GatherTroops::operator==(const GatherTroops & other) const
-{
-	return objid == other.objid;
-}
-
-int GatherTroops::getCreaturesCount(const CArmedInstance * army)
-{
-	int count = 0;
-
-	for(auto stack : army->Slots())
-	{
-		if(objid == stack.second->getCreatureID().num)
-		{
-			count += stack.second->count;
-		}
-	}
-
-	return count;
-}
-//
-//TSubgoal GatherTroops::whatToDoToAchieve()
-//{
-//	logAi->trace("Entering GatherTroops::whatToDoToAchieve");
-//
-//	auto heroes = cb->getHeroesInfo(true);
-//
-//	for(auto hero : heroes)
-//	{
-//		if(getCreaturesCount(hero) >= this->value)
-//		{
-//			logAi->trace("Completing GATHER_TROOPS by hero %s", hero->name);
-//
-//			throw goalFulfilledException(sptr(*this));
-//		}
-//	}
-//
-//	return sptr(Invalid());
-//}
-
-//
-//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));
-	//			}
-	//		}
-	//	}
-	//}
-
-	//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
-//}

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

@@ -1,38 +0,0 @@
-/*
-* GatherTroops.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
-{
-	class DLL_EXPORT GatherTroops : public CGoal<GatherTroops>
-	{
-	public:
-		GatherTroops()
-			: CGoal(Goals::GATHER_TROOPS)
-		{
-		}
-		GatherTroops(int type, int val)
-			: CGoal(Goals::GATHER_TROOPS)
-		{
-			objid = type;
-			value = val;
-		}
-		virtual bool operator==(const GatherTroops & other) const override;
-
-	private:
-		int getCreaturesCount(const CArmedInstance * army);
-	};
-}

+ 0 - 29
AI/Nullkiller/Goals/GetArtOfType.cpp

@@ -1,29 +0,0 @@
-/*
-* GetArtOfType.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 "GetArtOfType.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-
-using namespace Goals;
-
-bool GetArtOfType::operator==(const GetArtOfType & other) const
-{
-	return other.hero.h == hero.h && other.objid == objid;
-}
-//
-//TSubgoal GetArtOfType::whatToDoToAchieve()
-//{
-//	return sptr(FindObj(Obj::ARTIFACT, aid));
-//}

+ 0 - 34
AI/Nullkiller/Goals/GetArtOfType.h

@@ -1,34 +0,0 @@
-/*
-* GetArtOfType.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
-{
-	class DLL_EXPORT GetArtOfType : public CGoal<GetArtOfType>
-	{
-	public:
-		GetArtOfType()
-			: CGoal(Goals::GET_ART_TYPE)
-		{
-		}
-		GetArtOfType(int type)
-			: CGoal(Goals::GET_ART_TYPE)
-		{
-			aid = type;
-		}
-		virtual bool operator==(const GetArtOfType & other) const override;
-	};
-}

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

@@ -14,10 +14,7 @@
 #include "BuildBoat.h"
 #include "BuildThis.h"
 #include "BuyArmy.h"
-#include "GatherTroops.h"
 #include "Trade.h"
-#include "CollectRes.h"
 #include "RecruitHero.h"
-#include "GetArtOfType.h"
 #include "DigAtTile.h"
 #include "AdventureSpellCast.h"

+ 0 - 29
AI/Nullkiller/Goals/VisitHero.cpp

@@ -1,29 +0,0 @@
-/*
-* VisitHero.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 "VisitHero.h"
-#include "Invalid.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../AIhelper.h"
-#include "../FuzzyHelper.h"
-#include "../../../lib/mapping/CMap.h" //for victory conditions
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-bool VisitHero::operator==(const VisitHero & other) const
-{
-	return other.hero.h == hero.h && other.objid == objid;
-}

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

@@ -1,36 +0,0 @@
-/*
-* VisitHero.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
-
-#error not used
-
-#include "CGoal.h"
-
-struct HeroPtr;
-class VCAI;
-class FuzzyHelper;
-
-namespace Goals
-{
-	class DLL_EXPORT VisitHero : public CGoal<VisitHero>
-	{
-	public:
-		VisitHero()
-			: CGoal(Goals::VISIT_HERO)
-		{
-		}
-		VisitHero(int hid)
-			: CGoal(Goals::VISIT_HERO)
-		{
-			objid = hid;
-		}
-		virtual bool operator==(const VisitHero & other) const override;
-	};
-}

+ 0 - 41
AI/Nullkiller/Goals/VisitObj.cpp

@@ -1,41 +0,0 @@
-/*
-* VisitObj.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 "Goals.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../AIhelper.h"
-#include "../FuzzyHelper.h"
-#include "../../../lib/mapping/CMap.h" //for victory conditions
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-bool VisitObj::operator==(const VisitObj & other) const
-{
-	return other.hero.h == hero.h && other.objid == objid;
-}
-
-VisitObj::VisitObj(int Objid)
-	: CGoal(VISIT_OBJ)
-{
-	objid = Objid;
-	auto obj = ai->myCb->getObjInstance(ObjectInstanceID(objid));
-	if(obj)
-		tile = obj->visitablePos();
-	else
-		logAi->error("VisitObj constructed with invalid object instance %d", Objid);
-}

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

@@ -1,30 +0,0 @@
-/*
-* VisitObj.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
-
-#error not used
-
-#include "CGoal.h"
-
-struct HeroPtr;
-class VCAI;
-class FuzzyHelper;
-
-namespace Goals
-{
-	class DLL_EXPORT VisitObj : public CGoal<VisitObj> //this goal was previously known as GetObj
-	{
-	public:
-		VisitObj() = delete; // empty constructor not allowed
-		VisitObj(int Objid);
-
-		virtual bool operator==(const VisitObj & other) const override;
-	};
-}

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

@@ -1,30 +0,0 @@
-/*
-* VisitTile.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 "Goals.h"
-#include "../VCAI.h"
-#include "../AIUtility.h"
-#include "../AIhelper.h"
-#include "../FuzzyHelper.h"
-#include "../../../lib/mapping/CMap.h" //for victory conditions
-#include "../../../lib/CPathfinder.h"
-#include "../../../lib/StringConstants.h"
-
-
-extern boost::thread_specific_ptr<CCallback> cb;
-extern boost::thread_specific_ptr<VCAI> ai;
-extern FuzzyHelper * fh;
-
-using namespace Goals;
-
-bool VisitTile::operator==(const VisitTile & other) const
-{
-	return other.hero.h == hero.h && other.tile == tile;
-}

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

@@ -1,35 +0,0 @@
-/*
-* VisitTile.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
-
-#error not used
-
-#include "CGoal.h"
-
-struct HeroPtr;
-class VCAI;
-class FuzzyHelper;
-
-namespace Goals
-{
-	class DLL_EXPORT VisitTile : public CGoal<VisitTile>
-		//tile, in conjunction with hero elementar; assumes tile is reachable
-	{
-	public:
-		VisitTile() {} // empty constructor not allowed
-
-		VisitTile(int3 Tile)
-			: CGoal(Goals::VISIT_TILE)
-		{
-			tile = Tile;
-		}
-		virtual bool operator==(const VisitTile & other) const override;
-	};
-}

+ 36 - 0
AI/Nullkiller/Markers/ArmyUpgrade.cpp

@@ -0,0 +1,36 @@
+/*
+* ArmyUpgrade.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 "ArmyUpgrade.h"
+#include "../VCAI.h"
+#include "../Engine/Nullkiller.h"
+#include "../AIUtility.h"
+
+extern boost::thread_specific_ptr<CCallback> cb;
+extern boost::thread_specific_ptr<VCAI> ai;
+
+using namespace Goals;
+
+ArmyUpgrade::ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade)
+	: CGoal(Goals::ARMY_UPGRADE), upgrader(upgrader), upgradeValue(upgrade.upgradeValue),
+	initialValue(upgradePath.heroArmy->getArmyStrength()), goldCost(upgrade.upgradeCost[Res::GOLD])
+{
+	sethero(upgradePath.targetHero);
+}
+
+bool ArmyUpgrade::operator==(const ArmyUpgrade & other) const
+{
+	return false;
+}
+
+std::string ArmyUpgrade::toString() const
+{
+	return "Army upgrade at " + upgrader->getObjectName() + upgrader->visitablePos().toString();
+}

+ 35 - 0
AI/Nullkiller/Markers/ArmyUpgrade.h

@@ -0,0 +1,35 @@
+/*
+* ArmyUpgrade.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 "../Goals/CGoal.h"
+#include "../Pathfinding/AINodeStorage.h"
+#include "../Analyzers/ArmyManager.h"
+
+namespace Goals
+{
+	class DLL_EXPORT ArmyUpgrade : public CGoal<ArmyUpgrade>
+	{
+	private:
+		const CGObjectInstance * upgrader;
+		uint64_t initialValue;
+		uint64_t upgradeValue;
+		uint64_t goldCost;
+
+	public:
+		ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade);
+
+		virtual bool operator==(const ArmyUpgrade & other) const override;
+		virtual std::string toString() const override;
+
+		uint64_t getUpgradeValue() const { return upgradeValue; }
+		uint64_t getInitialArmyValue() const { return initialValue; }
+	};
+}

+ 36 - 0
AI/Nullkiller/Markers/HeroExchange.cpp

@@ -0,0 +1,36 @@
+/*
+* HeroExchange.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 "HeroExchange.h"
+#include "../VCAI.h"
+#include "../Engine/Nullkiller.h"
+#include "../AIUtility.h"
+
+extern boost::thread_specific_ptr<CCallback> cb;
+extern boost::thread_specific_ptr<VCAI> ai;
+
+using namespace Goals;
+
+bool HeroExchange::operator==(const HeroExchange & other) const
+{
+	return false;
+}
+
+std::string HeroExchange::toString() const
+{
+	return "Hero exchange " + exchangePath.toString();
+}
+
+uint64_t HeroExchange::getReinforcementArmyStrength() const
+{
+	uint64_t armyValue = ai->nullkiller->armyManager->howManyReinforcementsCanGet(hero.get(), exchangePath.heroArmy);
+
+	return armyValue;
+}

+ 34 - 0
AI/Nullkiller/Markers/HeroExchange.h

@@ -0,0 +1,34 @@
+/*
+* HeroExchange.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 "../Goals/CGoal.h"
+#include "../Pathfinding/AINodeStorage.h"
+
+namespace Goals
+{
+	class DLL_EXPORT HeroExchange : public CGoal<HeroExchange>
+	{
+	private:
+		AIPath exchangePath;
+
+	public:
+		HeroExchange(const CGHeroInstance * targetHero, const AIPath & exchangePath)
+			: CGoal(Goals::HERO_EXCHANGE), exchangePath(exchangePath)
+		{
+			sethero(targetHero);
+		}
+
+		virtual bool operator==(const HeroExchange & other) const override;
+		virtual std::string toString() const override;
+
+		uint64_t getReinforcementArmyStrength() const;
+	};
+}

+ 0 - 0
AI/Nullkiller/Goals/UnlockCluster.cpp → AI/Nullkiller/Markers/UnlockCluster.cpp


+ 1 - 1
AI/Nullkiller/Goals/UnlockCluster.h → AI/Nullkiller/Markers/UnlockCluster.h

@@ -9,7 +9,7 @@
 */
 #pragma once
 
-#include "CGoal.h"
+#include "../Goals/CGoal.h"
 #include "../Analyzers/ObjectClusterizer.h"
 
 

+ 3 - 3
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -1112,10 +1112,10 @@ AIPath::AIPath()
 
 std::shared_ptr<const SpecialAction> AIPath::getFirstBlockedAction() const
 {
-	for(auto node : nodes)
+	for(auto node = nodes.rbegin(); node != nodes.rend(); node++)
 	{
-		if(node.specialAction && node.actionIsBlocked)
-			return node.specialAction;
+		if(node->specialAction && node->actionIsBlocked)
+			return node->specialAction;
 	}
 
 	return std::shared_ptr<const SpecialAction>();

+ 1 - 1
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -11,7 +11,7 @@
 #pragma once
 
 #define PATHFINDER_TRACE_LEVEL 0
-#define AI_TRACE_LEVEL 0
+#define AI_TRACE_LEVEL 2
 #define SCOUT_TURN_DISTANCE_LIMIT 3
 
 #include "../../../lib/CPathfinder.h"

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

@@ -11,7 +11,7 @@
 #include "StdInc.h"
 #include "BattleAction.h"
 #include "../../VCAI.h"
-#include "../../Behaviors/CompleteQuestBehavior.h"
+#include "../../Goals/CompleteQuest.h"
 #include "../../../../lib/mapping/CMap.h" //for victory conditions
 
 extern boost::thread_specific_ptr<CCallback> cb;