瀏覽代碼

NKAI: composite pathfinder actions and fix for guarded bordergate

Andrii Danylchenko 2 年之前
父節點
當前提交
0829593356

+ 1 - 1
AI/Nullkiller/AIUtility.cpp

@@ -255,7 +255,7 @@ bool isObjectPassable(const CGObjectInstance * obj, PlayerColor playerColor, Pla
 	{
 	{
 		auto quest = dynamic_cast<const CGKeys *>(obj);
 		auto quest = dynamic_cast<const CGKeys *>(obj);
 
 
-		if(quest->passableFor(playerColor))
+		if(quest->wasMyColorVisited(playerColor))
 			return true;
 			return true;
 	}
 	}
 
 

+ 1 - 1
AI/Nullkiller/Analyzers/ObjectClusterizer.cpp

@@ -114,7 +114,7 @@ const CGObjectInstance * ObjectClusterizer::getBlocker(const AIPath & path) cons
 
 
 			if(blockerObject)
 			if(blockerObject)
 			{
 			{
-				blockers.push_back(blockerObject);
+				blockers.insert(blockers.begin(), blockerObject);
 			}
 			}
 		}
 		}
 
 

+ 23 - 2
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -52,6 +52,27 @@ AISharedStorage::~AISharedStorage()
 	}
 	}
 }
 }
 
 
+void AIPathNode::addSpecialAction(std::shared_ptr<const SpecialAction> action)
+{
+	if(!specialAction)
+	{
+		specialAction = action;
+	}
+	else
+	{
+		auto parts = specialAction->getParts();
+
+		if(parts.empty())
+		{
+			parts.push_back(specialAction);
+		}
+
+		parts.push_back(action);
+
+		specialAction = std::make_shared<CompositeAction>(parts);
+	}
+}
+
 AINodeStorage::AINodeStorage(const Nullkiller * ai, const int3 & Sizes)
 AINodeStorage::AINodeStorage(const Nullkiller * ai, const int3 & Sizes)
 	: sizes(Sizes), ai(ai), cb(ai->cb.get()), nodes(Sizes)
 	: sizes(Sizes), ai(ai), cb(ai->cb.get()), nodes(Sizes)
 {
 {
@@ -765,7 +786,7 @@ void HeroChainCalculationTask::addHeroChain(const std::vector<ExchangeCandidate>
 		if(exchangeNode->actor->actorAction)
 		if(exchangeNode->actor->actorAction)
 		{
 		{
 			exchangeNode->theNodeBefore = carrier;
 			exchangeNode->theNodeBefore = carrier;
-			exchangeNode->specialAction = exchangeNode->actor->actorAction;
+			exchangeNode->addSpecialAction(exchangeNode->actor->actorAction);
 		}
 		}
 
 
 		exchangeNode->chainOther = other;
 		exchangeNode->chainOther = other;
@@ -1045,7 +1066,7 @@ struct TowmPortalFinder
 				movementCost);
 				movementCost);
 
 
 			node->theNodeBefore = bestNode;
 			node->theNodeBefore = bestNode;
-			node->specialAction.reset(new AIPathfinding::TownPortalAction(targetTown));
+			node->addSpecialAction(std::make_shared<AIPathfinding::TownPortalAction>(targetTown));
 		}
 		}
 
 
 		return nodeOptional;
 		return nodeOptional;

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

@@ -55,6 +55,8 @@ struct AIPathNode : public CGPathNode
 		return accessible == CGPathNode::EAccessibility::NOT_SET
 		return accessible == CGPathNode::EAccessibility::NOT_SET
 			|| accessible == CGPathNode::EAccessibility::BLOCKED;
 			|| accessible == CGPathNode::EAccessibility::BLOCKED;
 	}
 	}
+
+	void addSpecialAction(std::shared_ptr<const SpecialAction> action);
 };
 };
 
 
 struct AIPathNodeInfo
 struct AIPathNodeInfo

+ 63 - 0
AI/Nullkiller/Pathfinding/Actions/SpecialAction.cpp

@@ -27,4 +27,67 @@ void SpecialAction::execute(const CGHeroInstance * hero) const
 	throw cannotFulfillGoalException("Can not execute " + toString());
 	throw cannotFulfillGoalException("Can not execute " + toString());
 }
 }
 
 
+bool CompositeAction::canAct(const AIPathNode * source) const
+{
+	for(auto part : parts)
+	{
+		if(!part->canAct(source)) return false;
+	}
+
+	return true;
+}
+
+Goals::TSubgoal CompositeAction::decompose(const CGHeroInstance * hero) const
+{
+	for(auto part : parts)
+	{
+		auto goal = part->decompose(hero);
+
+		if(!goal->invalid()) return goal;
+	}
+
+	return SpecialAction::decompose(hero);
+}
+
+void CompositeAction::execute(const CGHeroInstance * hero) const
+{
+	for(auto part : parts)
+	{
+		part->execute(hero);
+	}
+}
+
+void CompositeAction::applyOnDestination(
+	const CGHeroInstance * hero,
+	CDestinationNodeInfo & destination,
+	const PathNodeInfo & source,
+	AIPathNode * dstNode,
+	const AIPathNode * srcNode) const
+{
+	for(auto part : parts)
+	{
+		part->applyOnDestination(hero, destination, source, dstNode, srcNode);
+	}
+}
+
+std::string CompositeAction::toString() const
+{
+	std::string result = "";
+
+	for(auto part : parts)
+	{
+		result += ", " + part->toString();
+	}
+
+	return result;
+}
+
+const CGObjectInstance * CompositeAction::targetObject() const
+{
+	if(parts.empty())
+		return nullptr;
+
+	return parts.front()->targetObject();
+}
+
 }
 }

+ 33 - 1
AI/Nullkiller/Pathfinding/Actions/SpecialAction.h

@@ -36,7 +36,7 @@ public:
 		const CGHeroInstance * hero,
 		const CGHeroInstance * hero,
 		CDestinationNodeInfo & destination,
 		CDestinationNodeInfo & destination,
 		const PathNodeInfo & source,
 		const PathNodeInfo & source,
-		AIPathNode * dstMode,
+		AIPathNode * dstNode,
 		const AIPathNode * srcNode) const
 		const AIPathNode * srcNode) const
 	{
 	{
 	}
 	}
@@ -44,6 +44,38 @@ public:
 	virtual std::string toString() const = 0;
 	virtual std::string toString() const = 0;
 
 
 	virtual const CGObjectInstance * targetObject() const { return nullptr; }
 	virtual const CGObjectInstance * targetObject() const { return nullptr; }
+
+	virtual std::vector<std::shared_ptr<const SpecialAction>> getParts() const
+	{
+		return {};
+	}
+};
+
+class CompositeAction : public SpecialAction
+{
+private:
+	std::vector<std::shared_ptr<const SpecialAction>> parts;
+
+public:
+	CompositeAction(std::vector<std::shared_ptr<const SpecialAction>> parts) : parts(parts) {}
+
+	bool canAct(const AIPathNode * source) const override;
+	void execute(const CGHeroInstance * hero) const override;
+	std::string toString() const override;
+	const CGObjectInstance * targetObject() const override;
+	Goals::TSubgoal decompose(const CGHeroInstance * hero) const override;
+
+	std::vector<std::shared_ptr<const SpecialAction>> getParts() const override
+	{
+		return parts;
+	}
+
+	void applyOnDestination(
+		const CGHeroInstance * hero,
+		CDestinationNodeInfo & destination,
+		const PathNodeInfo & source,
+		AIPathNode * dstNode,
+		const AIPathNode * srcNode) const override;
 };
 };
 
 
 }
 }

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

@@ -133,7 +133,7 @@ namespace AIPathfinding
 
 
 				if(boatNode->action == CGPathNode::UNKNOWN)
 				if(boatNode->action == CGPathNode::UNKNOWN)
 				{
 				{
-					boatNode->specialAction = virtualBoat;
+					boatNode->addSpecialAction(virtualBoat);
 					destination.blocked = false;
 					destination.blocked = false;
 					destination.action = CGPathNode::ENodeAction::EMBARK;
 					destination.action = CGPathNode::ENodeAction::EMBARK;
 					destination.node = boatNode;
 					destination.node = boatNode;

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

@@ -157,7 +157,7 @@ namespace AIPathfinding
 
 
 			nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
 			nodeStorage->updateAINode(destination.node, [&](AIPathNode * node)
 			{
 			{
-				node->specialAction.reset(new QuestAction(questAction));
+				node->addSpecialAction(std::make_shared<QuestAction>(questAction));
 			});
 			});
 		}
 		}
 
 
@@ -279,6 +279,11 @@ namespace AIPathfinding
 
 
 		if(loss < actualArmyValue)
 		if(loss < actualArmyValue)
 		{
 		{
+			if(destNode->specialAction)
+			{
+				battleNode->specialAction = destNode->specialAction;
+			}
+
 			destination.node = battleNode;
 			destination.node = battleNode;
 			nodeStorage->commit(destination, source);
 			nodeStorage->commit(destination, source);
 
 
@@ -288,7 +293,7 @@ namespace AIPathfinding
 
 
 			AIPreviousNodeRule(nodeStorage).process(source, destination, pathfinderConfig, pathfinderHelper);
 			AIPreviousNodeRule(nodeStorage).process(source, destination, pathfinderConfig, pathfinderHelper);
 
 
-			battleNode->specialAction = std::make_shared<BattleAction>(destination.coord);
+			battleNode->addSpecialAction(std::make_shared<BattleAction>(destination.coord));
 
 
 #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
 #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
 			logAi->trace(
 			logAi->trace(