Browse Source

#3876 - allow to embark after battle for AI pathfinder

Andrii Danylchenko 1 year ago
parent
commit
157443c1df

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

@@ -104,7 +104,7 @@ AINodeStorage::~AINodeStorage() = default;
 
 void AINodeStorage::initialize(const PathfinderOptions & options, const CGameState * gs)
 {
-	if(heroChainPass)
+	if(heroChainPass != EHeroChainPass::INITIAL)
 		return;
 
 	AISharedStorage::version++;
@@ -157,6 +157,7 @@ void AINodeStorage::initialize(const PathfinderOptions & options, const CGameSta
 void AINodeStorage::clear()
 {
 	actors.clear();
+	commitedTiles.clear();
 	heroChainPass = EHeroChainPass::INITIAL;
 	heroChainTurn = 0;
 	heroChainMaxTurns = 1;
@@ -169,7 +170,7 @@ std::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
 	const EPathfindingLayer layer, 
 	const ChainActor * actor)
 {
-	int bucketIndex = ((uintptr_t)actor) % AIPathfinding::BUCKET_COUNT;
+	int bucketIndex = ((uintptr_t)actor + static_cast<uint32_t>(layer)) % AIPathfinding::BUCKET_COUNT;
 	int bucketOffset = bucketIndex * AIPathfinding::BUCKET_SIZE;
 	auto chains = nodes.get(pos);
 
@@ -330,10 +331,38 @@ void AINodeStorage::calculateNeighbours(
 
 	for(auto & neighbour : accessibleNeighbourTiles)
 	{
+		if(getAccessibility(neighbour, layer) == EPathAccessibility::NOT_SET)
+		{
+#if NKAI_PATHFINDER_TRACE_LEVEL >= 2
+			logAi->trace(
+				"Node %s rejected for %s, layer %d because of inaccessibility",
+				neighbour.toString(),
+				source.coord.toString(),
+				static_cast<int32_t>(layer));
+#endif
+			continue;
+		}
+
 		auto nextNode = getOrCreateNode(neighbour, layer, srcNode->actor);
 
-		if(!nextNode || nextNode.value()->accessible == EPathAccessibility::NOT_SET)
+		if(!nextNode)
+		{
+#if NKAI_PATHFINDER_TRACE_LEVEL >= 2
+			logAi->trace(
+				"Failed to allocate node at %s[%d]",
+				neighbour.toString(),
+				static_cast<int32_t>(layer));
+#endif
 			continue;
+		}
+
+#if NKAI_PATHFINDER_TRACE_LEVEL >= 2
+		logAi->trace(
+			"Node %s added to neighbors of %s, layer %d",
+			neighbour.toString(),
+			source.coord.toString(),
+			static_cast<int32_t>(layer));
+#endif
 
 		result.push_back(nextNode.value());
 	}

+ 1 - 0
AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp

@@ -47,6 +47,7 @@ namespace AIPathfinding
 		:PathfinderConfig(nodeStorage, makeRuleset(cb, ai, nodeStorage, allowBypassObjects)), aiNodeStorage(nodeStorage)
 	{
 		options.canUseCast = true;
+		options.allowLayerTransitioningAfterBattle = true;
 	}
 
 	AIPathfinderConfig::~AIPathfinderConfig() = default;

+ 8 - 0
AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp

@@ -34,6 +34,14 @@ namespace AIPathfinding
 	{
 		LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
 
+#if NKAI_PATHFINDER_TRACE_LEVEL >= 2
+		logAi->trace("Layer transitioning %s -> %s, action: %d, blocked: %s",
+			source.coord.toString(),
+			destination.coord.toString(),
+			static_cast<int32_t>(destination.action),
+			destination.blocked ? "true" : "false");
+#endif
+
 		if(!destination.blocked)
 		{
 			if(source.node->layer == EPathfindingLayer::LAND

+ 3 - 2
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -84,10 +84,11 @@ namespace AIPathfinding
 
 #if NKAI_PATHFINDER_TRACE_LEVEL >= 2
 		logAi->trace(
-			"Movement from tile %s is blocked. Try to bypass. Action: %d, blocker: %d",
+			"Movement from tile %s is blocked. Try to bypass. Action: %d, blocker: %d, source: %s",
 			destination.coord.toString(),
 			(int)destination.action,
-			(int)blocker);
+			(int)blocker,
+			source.coord.toString());
 #endif
 
 		auto destGuardians = cb->getGuardingCreatures(destination.coord);

+ 1 - 1
lib/pathfinder/CPathfinder.cpp

@@ -330,7 +330,7 @@ bool CPathfinder::isLayerTransitionPossible() const
 	ELayer destLayer = destination.node->layer;
 
 	/// No layer transition allowed when previous node action is BATTLE
-	if(source.node->action == EPathNodeAction::BATTLE)
+	if(!config->options.allowLayerTransitioningAfterBattle && source.node->action == EPathNodeAction::BATTLE)
 		return false;
 
 	switch(source.node->layer.toEnum())

+ 1 - 0
lib/pathfinder/PathfinderOptions.cpp

@@ -33,6 +33,7 @@ PathfinderOptions::PathfinderOptions()
 	, oneTurnSpecialLayersLimit(true)
 	, turnLimit(std::numeric_limits<uint8_t>::max())
 	, canUseCast(false)
+	, allowLayerTransitioningAfterBattle(false)
 {
 }
 

+ 5 - 0
lib/pathfinder/PathfinderOptions.h

@@ -79,6 +79,11 @@ struct DLL_LINKAGE PathfinderOptions
 	/// </summary>
 	bool canUseCast;
 
+	/// <summary>
+	/// For AI. AI pathfinder needs to ignore this rule as it simulates battles on the way
+	/// </summary>
+	bool allowLayerTransitioningAfterBattle;
+
 	PathfinderOptions();
 };