1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

NKAI: composite pathfinder actions and fix for guarded bordergate

This commit is contained in:
Andrii Danylchenko 2022-12-26 20:17:39 +02:00 committed by Andrii Danylchenko
parent e23936f6dc
commit 0829593356
8 changed files with 131 additions and 8 deletions

View File

@ -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;
} }

View File

@ -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);
} }
} }

View File

@ -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;

View File

@ -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

View File

@ -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();
}
} }

View File

@ -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;
}; };
} }

View File

@ -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;

View File

@ -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(