瀏覽代碼

NKAI: configurable object graph

Andrii Danylchenko 1 年之前
父節點
當前提交
6245adb9a4

+ 5 - 1
AI/Nullkiller/AIGateway.cpp

@@ -373,7 +373,11 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
 		return;
 
 	nullkiller->memory->removeFromMemory(obj);
-	nullkiller->baseGraph->removeObject(obj);
+
+	if(nullkiller->baseGraph && nullkiller->settings->isObjectGraphAllowed())
+	{
+		nullkiller->baseGraph->removeObject(obj);
+	}
 
 	if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
 	{

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

@@ -178,8 +178,11 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
 #endif
 
 			const int3 pos = objToVisit->visitablePos();
+			bool useObjectGraph = ai->nullkiller->settings->isObjectGraphAllowed()
+				&& ai->nullkiller->getScanDepth() != ScanDepth::SMALL;
+
+			auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, useObjectGraph);
 
-			auto paths = ai->nullkiller->pathfinder->getPathInfo(pos, true);
 			std::vector<std::shared_ptr<ExecuteHeroChain>> waysToVisitObj;
 			std::shared_ptr<ExecuteHeroChain> closestWay;
 					
@@ -210,7 +213,7 @@ Goals::TGoalVec CaptureObjectsBehavior::decompose() const
 	{
 		captureObjects(ai->nullkiller->objectClusterizer->getNearbyObjects());
 
-		if(tasks.empty())
+		if(tasks.empty() || ai->nullkiller->getScanDepth() != ScanDepth::SMALL)
 			captureObjects(ai->nullkiller->objectClusterizer->getFarObjects());
 	}
 

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

@@ -42,7 +42,7 @@ Goals::TGoalVec ClusterBehavior::decompose() const
 Goals::TGoalVec ClusterBehavior::decomposeCluster(std::shared_ptr<ObjectCluster> cluster) const
 {
 	auto center = cluster->calculateCenter();
-	auto paths = ai->nullkiller->pathfinder->getPathInfo(center->visitablePos(), true);
+	auto paths = ai->nullkiller->pathfinder->getPathInfo(center->visitablePos(), ai->nullkiller->settings->isObjectGraphAllowed());
 	auto blockerPos = cluster->blocker->visitablePos();
 	std::vector<AIPath> blockerPaths;
 

+ 4 - 0
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -443,6 +443,10 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
 						heroToDismiss = town->garrisonHero.get();
 					}
 				}
+
+				// avoid dismissing one weak hero in order to recruit another.
+				if(heroToDismiss && heroToDismiss->getArmyStrength() + 500 > hero->getArmyStrength())
+					continue;
 			}
 			else if(ai->nullkiller->heroManager->heroCapReached())
 			{

+ 29 - 21
AI/Nullkiller/Engine/Nullkiller.cpp

@@ -125,7 +125,7 @@ void Nullkiller::resetAiState()
 	dangerHitMap->reset();
 	useHeroChain = true;
 
-	if(!baseGraph)
+	if(!baseGraph && ai->nullkiller->settings->isObjectGraphAllowed())
 	{
 		baseGraph = std::make_unique<ObjectGraph>();
 		baseGraph->updateGraph(this);
@@ -172,20 +172,24 @@ void Nullkiller::updateAiState(int pass, bool fast)
 		cfg.useHeroChain = useHeroChain;
 		cfg.allowBypassObjects = true;
 
-		if(scanDepth == ScanDepth::SMALL)
+		if(scanDepth == ScanDepth::SMALL || settings->isObjectGraphAllowed())
 		{
-			cfg.mainTurnDistanceLimit = ai->nullkiller->settings->getMainHeroTurnDistanceLimit();
+			cfg.mainTurnDistanceLimit = settings->getMainHeroTurnDistanceLimit();
 		}
 
-		if(scanDepth != ScanDepth::ALL_FULL)
+		if(scanDepth != ScanDepth::ALL_FULL || settings->isObjectGraphAllowed())
 		{
-			cfg.scoutTurnDistanceLimit = ai->nullkiller->settings->getScoutHeroTurnDistanceLimit();
+			cfg.scoutTurnDistanceLimit =settings->getScoutHeroTurnDistanceLimit();
 		}
 
 		boost::this_thread::interruption_point();
 
 		pathfinder->updatePaths(activeHeroes, cfg);
-		pathfinder->updateGraphs(activeHeroes);
+
+		if(settings->isObjectGraphAllowed())
+		{
+			pathfinder->updateGraphs(activeHeroes);
+		}
 
 		boost::this_thread::interruption_point();
 
@@ -299,7 +303,8 @@ void Nullkiller::makeTurn()
 
 		// TODO: better to check turn distance here instead of priority
 		if((heroRole != HeroRole::MAIN || bestTask->priority < SMALL_SCAN_MIN_PRIORITY)
-			&& scanDepth == ScanDepth::MAIN_FULL)
+			&& scanDepth == ScanDepth::MAIN_FULL
+			&& !settings->isObjectGraphAllowed())
 		{
 			useHeroChain = false;
 			scanDepth = ScanDepth::SMALL;
@@ -312,22 +317,25 @@ void Nullkiller::makeTurn()
 
 		if(bestTask->priority < MIN_PRIORITY)
 		{
-			auto heroes = cb->getHeroesInfo();
-			auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool
-				{
-					return h->movementPointsRemaining() > 100;
-				});
-
-			if(hasMp && scanDepth != ScanDepth::ALL_FULL)
+			if(!settings->isObjectGraphAllowed())
 			{
-				logAi->trace(
-					"Goal %s has too low priority %f so increasing scan depth to full.",
-					taskDescription,
-					bestTask->priority);
+				auto heroes = cb->getHeroesInfo();
+				auto hasMp = vstd::contains_if(heroes, [](const CGHeroInstance * h) -> bool
+					{
+						return h->movementPointsRemaining() > 100;
+					});
 
-				scanDepth = ScanDepth::ALL_FULL;
-				useHeroChain = false;
-				continue;
+				if(hasMp && scanDepth != ScanDepth::ALL_FULL)
+				{
+					logAi->trace(
+						"Goal %s has too low priority %f so increasing scan depth to full.",
+						taskDescription,
+						bestTask->priority);
+
+					scanDepth = ScanDepth::ALL_FULL;
+					useHeroChain = false;
+					continue;
+				}
 			}
 
 			logAi->trace("Goal %s has too low priority. It is not worth doing it. Ending turn.", taskDescription);

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

@@ -27,7 +27,8 @@ namespace NKAI
 		mainHeroTurnDistanceLimit(10),
 		scoutHeroTurnDistanceLimit(5),
 		maxGoldPreasure(0.3f), 
-		maxpass(30)
+		maxpass(30),
+		allowObjectGraph(false)
 	{
 		ResourcePath resource("config/ai/nkai/nkai-settings", EResType::JSON);
 
@@ -74,5 +75,10 @@ namespace NKAI
 		{
 			maxGoldPreasure = node.Struct()["maxGoldPreasure"].Float();
 		}
+
+		if(!node.Struct()["allowObjectGraph"].isNull())
+		{
+			allowObjectGraph = node.Struct()["allowObjectGraph"].Bool();
+		}
 	}
 }

+ 2 - 0
AI/Nullkiller/Engine/Settings.h

@@ -26,6 +26,7 @@ namespace NKAI
 		int scoutHeroTurnDistanceLimit;
 		int maxpass;
 		float maxGoldPreasure;
+		bool allowObjectGraph;
 
 	public:
 		Settings();
@@ -35,6 +36,7 @@ namespace NKAI
 		int getMaxRoamingHeroes() const { return maxRoamingHeroes; }
 		int getMainHeroTurnDistanceLimit() const { return mainHeroTurnDistanceLimit; }
 		int getScoutHeroTurnDistanceLimit() const { return scoutHeroTurnDistanceLimit; }
+		bool isObjectGraphAllowed() const { return allowObjectGraph; }
 
 	private:
 		void loadFromMod(const std::string & modName, const ResourcePath & resource);

+ 2 - 4
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -12,7 +12,7 @@
 
 #define NKAI_PATHFINDER_TRACE_LEVEL 0
 #define NKAI_GRAPH_TRACE_LEVEL 0
-#define NKAI_TRACE_LEVEL 0
+#define NKAI_TRACE_LEVEL 1
 
 #include "../../../lib/pathfinder/CGPathNode.h"
 #include "../../../lib/pathfinder/INodeStorage.h"
@@ -27,11 +27,9 @@ namespace NKAI
 {
 namespace AIPathfinding
 {
-
-    const int BUCKET_COUNT = 5;
+	const int BUCKET_COUNT = 5;
 	const int BUCKET_SIZE = 3;
 	const int NUM_CHAINS = BUCKET_COUNT * BUCKET_SIZE;
-	const int THREAD_COUNT = 8;
 	const int CHAIN_MAX_DEPTH = 4;
 }