mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
NKAI: graph add battle layer
This commit is contained in:
parent
047e076d05
commit
b236384356
@ -224,7 +224,11 @@ void ObjectClusterizer::clusterize()
|
|||||||
ai->memory->visitableObjs.begin(),
|
ai->memory->visitableObjs.begin(),
|
||||||
ai->memory->visitableObjs.end());
|
ai->memory->visitableObjs.end());
|
||||||
|
|
||||||
|
#if NKAI_TRACE_LEVEL == 0
|
||||||
parallel_for(blocked_range<size_t>(0, objs.size()), [&](const blocked_range<size_t> & r)
|
parallel_for(blocked_range<size_t>(0, objs.size()), [&](const blocked_range<size_t> & r)
|
||||||
|
#else
|
||||||
|
blocked_range<size_t> r(0, objs.size());
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
auto priorityEvaluator = ai->priorityEvaluators->acquire();
|
auto priorityEvaluator = ai->priorityEvaluators->acquire();
|
||||||
|
|
||||||
@ -255,9 +259,9 @@ void ObjectClusterizer::clusterize()
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::sort(paths.begin(), paths.end(), [](const AIPath & p1, const AIPath & p2) -> bool
|
std::sort(paths.begin(), paths.end(), [](const AIPath & p1, const AIPath & p2) -> bool
|
||||||
{
|
{
|
||||||
return p1.movementCost() < p2.movementCost();
|
return p1.movementCost() < p2.movementCost();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(vstd::contains(ignoreObjects, obj->ID))
|
if(vstd::contains(ignoreObjects, obj->ID))
|
||||||
{
|
{
|
||||||
@ -348,7 +352,11 @@ void ObjectClusterizer::clusterize()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if NKAI_TRACE_LEVEL == 0
|
||||||
});
|
});
|
||||||
|
#else
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
logAi->trace("Near objects count: %i", nearObjects.objects.size());
|
logAi->trace("Near objects count: %i", nearObjects.objects.size());
|
||||||
logAi->trace("Far objects count: %i", farObjects.objects.size());
|
logAi->trace("Far objects count: %i", farObjects.objects.size());
|
||||||
|
@ -42,6 +42,8 @@ void Nullkiller::init(std::shared_ptr<CCallback> cb, PlayerColor playerID)
|
|||||||
this->cb = cb;
|
this->cb = cb;
|
||||||
this->playerID = playerID;
|
this->playerID = playerID;
|
||||||
|
|
||||||
|
baseGraph.reset();
|
||||||
|
|
||||||
priorityEvaluator.reset(new PriorityEvaluator(this));
|
priorityEvaluator.reset(new PriorityEvaluator(this));
|
||||||
priorityEvaluators.reset(
|
priorityEvaluators.reset(
|
||||||
new SharedPool<PriorityEvaluator>(
|
new SharedPool<PriorityEvaluator>(
|
||||||
|
@ -39,12 +39,18 @@ void AdventureSpellCast::accept(AIGateway * ai)
|
|||||||
if(hero->mana < hero->getSpellCost(spell))
|
if(hero->mana < hero->getSpellCost(spell))
|
||||||
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getNameTranslated());
|
throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getNameTranslated());
|
||||||
|
|
||||||
if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
|
|
||||||
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
|
|
||||||
|
|
||||||
if(town && spellID == SpellID::TOWN_PORTAL)
|
if(town && spellID == SpellID::TOWN_PORTAL)
|
||||||
{
|
{
|
||||||
ai->selectedObject = town->id;
|
ai->selectedObject = town->id;
|
||||||
|
|
||||||
|
if(town->visitingHero && town->tempOwner == ai->playerID && !town->getUpperArmy()->stacksCount())
|
||||||
|
{
|
||||||
|
ai->myCb->swapGarrisonHero(town);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(town->visitingHero)
|
||||||
|
throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto wait = cb->waitTillRealize;
|
auto wait = cb->waitTillRealize;
|
||||||
|
@ -1123,14 +1123,14 @@ void AINodeStorage::calculateTownPortal(
|
|||||||
{
|
{
|
||||||
for(const CGTownInstance * targetTown : towns)
|
for(const CGTownInstance * targetTown : towns)
|
||||||
{
|
{
|
||||||
// TODO: allow to hide visiting hero in garrison
|
if(targetTown->visitingHero
|
||||||
if(targetTown->visitingHero && maskMap.find(targetTown->visitingHero.get()) != maskMap.end())
|
&& targetTown->getUpperArmy()->stacksCount()
|
||||||
|
&& maskMap.find(targetTown->visitingHero.get()) != maskMap.end())
|
||||||
{
|
{
|
||||||
auto basicMask = maskMap.at(targetTown->visitingHero.get());
|
auto basicMask = maskMap.at(targetTown->visitingHero.get());
|
||||||
bool heroIsInChain = (actor->chainMask & basicMask) != 0;
|
|
||||||
bool sameActorInTown = actor->chainMask == basicMask;
|
bool sameActorInTown = actor->chainMask == basicMask;
|
||||||
|
|
||||||
if(sameActorInTown || !heroIsInChain)
|
if(!sameActorInTown)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define NKAI_PATHFINDER_TRACE_LEVEL 0
|
#define NKAI_PATHFINDER_TRACE_LEVEL 0
|
||||||
#define NKAI_TRACE_LEVEL 2
|
#define NKAI_GRAPH_TRACE_LEVEL 0
|
||||||
|
#define NKAI_TRACE_LEVEL 0
|
||||||
|
|
||||||
#include "../../../lib/pathfinder/CGPathNode.h"
|
#include "../../../lib/pathfinder/CGPathNode.h"
|
||||||
#include "../../../lib/pathfinder/INodeStorage.h"
|
#include "../../../lib/pathfinder/INodeStorage.h"
|
||||||
|
@ -48,9 +48,10 @@ std::vector<AIPath> AIPathfinder::getPathInfo(const int3 & tile, bool includeGra
|
|||||||
{
|
{
|
||||||
for(auto hero : cb->getHeroesInfo())
|
for(auto hero : cb->getHeroesInfo())
|
||||||
{
|
{
|
||||||
auto & graph = heroGraphs.at(hero->id);
|
auto graph = heroGraphs.find(hero->id);
|
||||||
|
|
||||||
graph.addChainInfo(info, tile, hero, ai);
|
if(graph != heroGraphs.end())
|
||||||
|
graph->second.addChainInfo(info, tile, hero, ai);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,10 +141,10 @@ void AIPathfinder::updateGraphs(std::map<const CGHeroInstance *, HeroRole> heroe
|
|||||||
parallel_for(blocked_range<size_t>(0, heroesVector.size()), [&](const blocked_range<size_t> & r)
|
parallel_for(blocked_range<size_t>(0, heroesVector.size()), [&](const blocked_range<size_t> & r)
|
||||||
{
|
{
|
||||||
for(auto i = r.begin(); i != r.end(); i++)
|
for(auto i = r.begin(); i != r.end(); i++)
|
||||||
heroGraphs[heroesVector[i]->id].calculatePaths(heroesVector[i], ai);
|
heroGraphs.at(heroesVector[i]->id).calculatePaths(heroesVector[i], ai);
|
||||||
});
|
});
|
||||||
|
|
||||||
#if NKAI_TRACE_LEVEL >= 2
|
#if NKAI_GRAPH_TRACE_LEVEL >= 1
|
||||||
for(auto hero : heroes)
|
for(auto hero : heroes)
|
||||||
{
|
{
|
||||||
heroGraphs[hero.first->id].dumpToLog();
|
heroGraphs[hero.first->id].dumpToLog();
|
||||||
|
@ -30,7 +30,7 @@ namespace AIPathfinding
|
|||||||
std::vector<std::shared_ptr<IPathfindingRule>> rules = {
|
std::vector<std::shared_ptr<IPathfindingRule>> rules = {
|
||||||
std::make_shared<AILayerTransitionRule>(cb, ai, nodeStorage),
|
std::make_shared<AILayerTransitionRule>(cb, ai, nodeStorage),
|
||||||
std::make_shared<DestinationActionRule>(),
|
std::make_shared<DestinationActionRule>(),
|
||||||
std::make_shared<AIMovementToDestinationRule>(nodeStorage),
|
std::make_shared<AIMovementToDestinationRule>(nodeStorage, allowBypassObjects),
|
||||||
std::make_shared<MovementCostRule>(),
|
std::make_shared<MovementCostRule>(),
|
||||||
std::make_shared<AIPreviousNodeRule>(nodeStorage),
|
std::make_shared<AIPreviousNodeRule>(nodeStorage),
|
||||||
std::make_shared<AIMovementAfterDestinationRule>(cb, nodeStorage, allowBypassObjects)
|
std::make_shared<AIMovementAfterDestinationRule>(cb, nodeStorage, allowBypassObjects)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "../../../CCallback.h"
|
#include "../../../CCallback.h"
|
||||||
#include "../../../lib/mapping/CMap.h"
|
#include "../../../lib/mapping/CMap.h"
|
||||||
#include "../Engine/Nullkiller.h"
|
#include "../Engine/Nullkiller.h"
|
||||||
|
#include "../../../lib/logging/VisualLogger.h"
|
||||||
|
|
||||||
namespace NKAI
|
namespace NKAI
|
||||||
{
|
{
|
||||||
@ -64,6 +65,14 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
|
|||||||
|
|
||||||
foreach_tile_pos(cb.get(), [&](const CPlayerSpecificInfoCallback * cb, const int3 & pos)
|
foreach_tile_pos(cb.get(), [&](const CPlayerSpecificInfoCallback * cb, const int3 & pos)
|
||||||
{
|
{
|
||||||
|
if(nodes.find(pos) != nodes.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto guarded = ai->cb->getGuardingCreaturePosition(pos).valid();
|
||||||
|
|
||||||
|
if(guarded)
|
||||||
|
return;
|
||||||
|
|
||||||
auto paths = ai->pathfinder->getPathInfo(pos);
|
auto paths = ai->pathfinder->getPathInfo(pos);
|
||||||
|
|
||||||
for(AIPath & path1 : paths)
|
for(AIPath & path1 : paths)
|
||||||
@ -76,9 +85,25 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
|
|||||||
auto obj1 = actorObjectMap[path1.targetHero];
|
auto obj1 = actorObjectMap[path1.targetHero];
|
||||||
auto obj2 = actorObjectMap[path2.targetHero];
|
auto obj2 = actorObjectMap[path2.targetHero];
|
||||||
|
|
||||||
nodes[obj1->visitablePos()].connections[obj2->visitablePos()].update(
|
auto danger = ai->pathfinder->getStorage()->evaluateDanger(obj2->visitablePos(), path1.targetHero, true);
|
||||||
|
|
||||||
|
auto updated = nodes[obj1->visitablePos()].connections[obj2->visitablePos()].update(
|
||||||
path1.movementCost() + path2.movementCost(),
|
path1.movementCost() + path2.movementCost(),
|
||||||
path1.getPathDanger() + path2.getPathDanger());
|
danger);
|
||||||
|
|
||||||
|
#if NKAI_GRAPH_TRACE_LEVEL >= 2
|
||||||
|
if(updated)
|
||||||
|
{
|
||||||
|
logAi->trace(
|
||||||
|
"Connected %s[%s] -> %s[%s] through [%s], cost %2f",
|
||||||
|
obj1->getObjectName(), obj1->visitablePos().toString(),
|
||||||
|
obj2->getObjectName(), obj2->visitablePos().toString(),
|
||||||
|
pos.toString(),
|
||||||
|
path1.movementCost() + path2.movementCost());
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)updated;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -87,6 +112,10 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
|
|||||||
{
|
{
|
||||||
delete h.first;
|
delete h.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NKAI_GRAPH_TRACE_LEVEL >= 1
|
||||||
|
dumpToLog("graph");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectGraph::addObject(const CGObjectInstance * obj)
|
void ObjectGraph::addObject(const CGObjectInstance * obj)
|
||||||
@ -104,7 +133,7 @@ void ObjectGraph::connectHeroes(const Nullkiller * ai)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto node : nodes)
|
for(auto & node : nodes)
|
||||||
{
|
{
|
||||||
auto pos = node.first;
|
auto pos = node.first;
|
||||||
auto paths = ai->pathfinder->getPathInfo(pos);
|
auto paths = ai->pathfinder->getPathInfo(pos);
|
||||||
@ -124,6 +153,29 @@ void ObjectGraph::connectHeroes(const Nullkiller * ai)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectGraph::dumpToLog(std::string visualKey) const
|
||||||
|
{
|
||||||
|
logVisual->updateWithLock(visualKey, [&](IVisualLogBuilder & logBuilder)
|
||||||
|
{
|
||||||
|
for(auto & tile : nodes)
|
||||||
|
{
|
||||||
|
for(auto & node : tile.second.connections)
|
||||||
|
{
|
||||||
|
#if NKAI_GRAPH_TRACE_LEVEL >= 2
|
||||||
|
logAi->trace(
|
||||||
|
"%s -> %s: %f !%d",
|
||||||
|
node.first.toString(),
|
||||||
|
tile.first.toString(),
|
||||||
|
node.second.cost,
|
||||||
|
node.second.danger);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
logBuilder.addLine(node.first, tile.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool GraphNodeComparer::operator()(const GraphPathNodePointer & lhs, const GraphPathNodePointer & rhs) const
|
bool GraphNodeComparer::operator()(const GraphPathNodePointer & lhs, const GraphPathNodePointer & rhs) const
|
||||||
{
|
{
|
||||||
return pathNodes.at(lhs.coord)[lhs.nodeType].cost > pathNodes.at(rhs.coord)[rhs.nodeType].cost;
|
return pathNodes.at(lhs.coord)[lhs.nodeType].cost > pathNodes.at(rhs.coord)[rhs.nodeType].cost;
|
||||||
@ -134,6 +186,7 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
|
|||||||
graph = *ai->baseGraph;
|
graph = *ai->baseGraph;
|
||||||
graph.connectHeroes(ai);
|
graph.connectHeroes(ai);
|
||||||
|
|
||||||
|
visualKey = std::to_string(ai->playerID) + ":" + targetHero->getNameTranslated();
|
||||||
pathNodes.clear();
|
pathNodes.clear();
|
||||||
|
|
||||||
GraphNodeComparer cmp(pathNodes);
|
GraphNodeComparer cmp(pathNodes);
|
||||||
@ -153,11 +206,17 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
|
|||||||
|
|
||||||
graph.iterateConnections(pos.coord, [&](int3 target, ObjectLink o)
|
graph.iterateConnections(pos.coord, [&](int3 target, ObjectLink o)
|
||||||
{
|
{
|
||||||
auto targetPointer = GraphPathNodePointer(target, pos.nodeType);
|
auto graphNode = graph.getNode(target);
|
||||||
|
auto targetNodeType = o.danger ? GrapthPathNodeType::BATTLE : pos.nodeType;
|
||||||
|
|
||||||
|
auto targetPointer = GraphPathNodePointer(target, targetNodeType);
|
||||||
auto & targetNode = getNode(targetPointer);
|
auto & targetNode = getNode(targetPointer);
|
||||||
|
|
||||||
if(targetNode.tryUpdate(pos, node, o))
|
if(targetNode.tryUpdate(pos, node, o))
|
||||||
{
|
{
|
||||||
|
if(graph.getNode(target).objTypeID == Obj::HERO)
|
||||||
|
return;
|
||||||
|
|
||||||
if(targetNode.isInQueue)
|
if(targetNode.isInQueue)
|
||||||
{
|
{
|
||||||
pq.increase(targetNode.handle);
|
pq.increase(targetNode.handle);
|
||||||
@ -174,21 +233,28 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
|
|||||||
|
|
||||||
void GraphPaths::dumpToLog() const
|
void GraphPaths::dumpToLog() const
|
||||||
{
|
{
|
||||||
for(auto & tile : pathNodes)
|
logVisual->updateWithLock(visualKey, [&](IVisualLogBuilder & logBuilder)
|
||||||
{
|
|
||||||
for(auto & node : tile.second)
|
|
||||||
{
|
{
|
||||||
if(!node.previous.valid())
|
for(auto & tile : pathNodes)
|
||||||
continue;
|
{
|
||||||
|
for(auto & node : tile.second)
|
||||||
|
{
|
||||||
|
if(!node.previous.valid())
|
||||||
|
continue;
|
||||||
|
|
||||||
logAi->trace(
|
#if NKAI_GRAPH_TRACE_LEVEL >= 2
|
||||||
"%s -> %s: %f !%d",
|
logAi->trace(
|
||||||
node.previous.coord.toString(),
|
"%s -> %s: %f !%d",
|
||||||
tile.first.toString(),
|
node.previous.coord.toString(),
|
||||||
node.cost,
|
tile.first.toString(),
|
||||||
node.danger);
|
node.cost,
|
||||||
}
|
node.danger);
|
||||||
}
|
#endif
|
||||||
|
|
||||||
|
logBuilder.addLine(node.previous.coord, tile.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GraphPathNode::tryUpdate(const GraphPathNodePointer & pos, const GraphPathNode & prev, const ObjectLink & link)
|
bool GraphPathNode::tryUpdate(const GraphPathNodePointer & pos, const GraphPathNode & prev, const ObjectLink & link)
|
||||||
@ -197,6 +263,11 @@ bool GraphPathNode::tryUpdate(const GraphPathNodePointer & pos, const GraphPathN
|
|||||||
|
|
||||||
if(newCost < cost)
|
if(newCost < cost)
|
||||||
{
|
{
|
||||||
|
if(nodeType < pos.nodeType)
|
||||||
|
{
|
||||||
|
logAi->error("Linking error");
|
||||||
|
}
|
||||||
|
|
||||||
previous = pos;
|
previous = pos;
|
||||||
danger = prev.danger + link.danger;
|
danger = prev.danger + link.danger;
|
||||||
cost = newCost;
|
cost = newCost;
|
||||||
@ -214,7 +285,7 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
|
|||||||
if(nodes == pathNodes.end())
|
if(nodes == pathNodes.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(auto & node : (*nodes).second)
|
for(auto & node : nodes->second)
|
||||||
{
|
{
|
||||||
if(!node.reachable())
|
if(!node.reachable())
|
||||||
continue;
|
continue;
|
||||||
@ -236,6 +307,9 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
|
|||||||
|
|
||||||
auto currentNode = currentTile->second[current.nodeType];
|
auto currentNode = currentTile->second[current.nodeType];
|
||||||
|
|
||||||
|
if(currentNode.cost == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
|
allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
|
||||||
vstd::amax(danger, currentNode.danger);
|
vstd::amax(danger, currentNode.danger);
|
||||||
vstd::amax(cost, currentNode.cost);
|
vstd::amax(cost, currentNode.cost);
|
||||||
|
@ -23,19 +23,24 @@ struct ObjectLink
|
|||||||
float cost = 100000; // some big number
|
float cost = 100000; // some big number
|
||||||
uint64_t danger = 0;
|
uint64_t danger = 0;
|
||||||
|
|
||||||
void update(float newCost, uint64_t newDanger)
|
bool update(float newCost, uint64_t newDanger)
|
||||||
{
|
{
|
||||||
if(cost > newCost)
|
if(cost > newCost)
|
||||||
{
|
{
|
||||||
cost = newCost;
|
cost = newCost;
|
||||||
danger = newDanger;
|
danger = newDanger;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectNode
|
struct ObjectNode
|
||||||
{
|
{
|
||||||
ObjectInstanceID objID;
|
ObjectInstanceID objID;
|
||||||
|
MapObjectID objTypeID;
|
||||||
bool objectExists;
|
bool objectExists;
|
||||||
std::unordered_map<int3, ObjectLink> connections;
|
std::unordered_map<int3, ObjectLink> connections;
|
||||||
|
|
||||||
@ -43,6 +48,7 @@ struct ObjectNode
|
|||||||
{
|
{
|
||||||
objectExists = true;
|
objectExists = true;
|
||||||
objID = obj->id;
|
objID = obj->id;
|
||||||
|
objTypeID = obj->ID;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,15 +60,21 @@ public:
|
|||||||
void updateGraph(const Nullkiller * ai);
|
void updateGraph(const Nullkiller * ai);
|
||||||
void addObject(const CGObjectInstance * obj);
|
void addObject(const CGObjectInstance * obj);
|
||||||
void connectHeroes(const Nullkiller * ai);
|
void connectHeroes(const Nullkiller * ai);
|
||||||
|
void dumpToLog(std::string visualKey) const;
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
void iterateConnections(const int3 & pos, Func fn)
|
void iterateConnections(const int3 & pos, Func fn)
|
||||||
{
|
{
|
||||||
for(auto connection : nodes.at(pos).connections)
|
for(auto & connection : nodes.at(pos).connections)
|
||||||
{
|
{
|
||||||
fn(connection.first, connection.second);
|
fn(connection.first, connection.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ObjectNode & getNode(int3 tile) const
|
||||||
|
{
|
||||||
|
return nodes.at(tile);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GraphPathNode;
|
struct GraphPathNode;
|
||||||
@ -134,6 +146,7 @@ class GraphPaths
|
|||||||
{
|
{
|
||||||
ObjectGraph graph;
|
ObjectGraph graph;
|
||||||
GraphNodeStorage pathNodes;
|
GraphNodeStorage pathNodes;
|
||||||
|
std::string visualKey;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void calculatePaths(const CGHeroInstance * targetHero, const Nullkiller * ai);
|
void calculatePaths(const CGHeroInstance * targetHero, const Nullkiller * ai);
|
||||||
@ -143,7 +156,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
GraphPathNode & getNode(const GraphPathNodePointer & pos)
|
GraphPathNode & getNode(const GraphPathNodePointer & pos)
|
||||||
{
|
{
|
||||||
return pathNodes[pos.coord][pos.nodeType];
|
auto & node = pathNodes[pos.coord][pos.nodeType];
|
||||||
|
|
||||||
|
node.nodeType = pos.nodeType;
|
||||||
|
|
||||||
|
return node;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ namespace AIPathfinding
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!allowBypassObjects)
|
if(!allowBypassObjects)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -14,8 +14,10 @@ namespace NKAI
|
|||||||
{
|
{
|
||||||
namespace AIPathfinding
|
namespace AIPathfinding
|
||||||
{
|
{
|
||||||
AIMovementToDestinationRule::AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage)
|
AIMovementToDestinationRule::AIMovementToDestinationRule(
|
||||||
: nodeStorage(nodeStorage)
|
std::shared_ptr<AINodeStorage> nodeStorage,
|
||||||
|
bool allowBypassObjects)
|
||||||
|
: nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,15 +39,30 @@ namespace AIPathfinding
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(blocker == BlockingReason::SOURCE_GUARDED && nodeStorage->getAINode(source.node)->actor->allowBattle)
|
if(blocker == BlockingReason::SOURCE_GUARDED)
|
||||||
{
|
{
|
||||||
|
auto actor = nodeStorage->getAINode(source.node)->actor;
|
||||||
|
|
||||||
|
if(!allowBypassObjects)
|
||||||
|
{
|
||||||
|
if (source.node->getCost() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// when actor represents moster graph node, we need to let him escape monster
|
||||||
|
if(!destination.guarded && cb->getGuardingCreaturePosition(source.coord) == actor->initialPosition)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(actor->allowBattle)
|
||||||
|
{
|
||||||
#if NKAI_PATHFINDER_TRACE_LEVEL >= 1
|
#if NKAI_PATHFINDER_TRACE_LEVEL >= 1
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Bypass src guard while moving from %s to %s",
|
"Bypass src guard while moving from %s to %s",
|
||||||
source.coord.toString(),
|
source.coord.toString(),
|
||||||
destination.coord.toString());
|
destination.coord.toString());
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destination.blocked = true;
|
destination.blocked = true;
|
||||||
|
@ -24,9 +24,10 @@ namespace AIPathfinding
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<AINodeStorage> nodeStorage;
|
std::shared_ptr<AINodeStorage> nodeStorage;
|
||||||
|
bool allowBypassObjects;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage);
|
AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage, bool allowBypassObjects);
|
||||||
|
|
||||||
virtual void process(
|
virtual void process(
|
||||||
const PathNodeInfo & source,
|
const PathNodeInfo & source,
|
||||||
|
@ -21,7 +21,9 @@ void VisualLogger::updateWithLock(std::string channel, std::function<void(IVisua
|
|||||||
|
|
||||||
mapLines[channel].clear();
|
mapLines[channel].clear();
|
||||||
|
|
||||||
func(VisualLogBuilder(mapLines[channel]));
|
VisualLogBuilder builder(mapLines[channel]);
|
||||||
|
|
||||||
|
func(builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualLogger::visualize(ILogVisualizer & visulizer)
|
void VisualLogger::visualize(ILogVisualizer & visulizer)
|
||||||
|
Loading…
Reference in New Issue
Block a user