1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-25 22:42:04 +02:00

NKAI: graph add battle layer

This commit is contained in:
Andrii Danylchenko
2024-02-03 12:20:59 +02:00
parent 047e076d05
commit b236384356
13 changed files with 176 additions and 47 deletions

View File

@@ -13,6 +13,7 @@
#include "../../../CCallback.h"
#include "../../../lib/mapping/CMap.h"
#include "../Engine/Nullkiller.h"
#include "../../../lib/logging/VisualLogger.h"
namespace NKAI
{
@@ -64,6 +65,14 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
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);
for(AIPath & path1 : paths)
@@ -76,9 +85,25 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
auto obj1 = actorObjectMap[path1.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.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;
}
#if NKAI_GRAPH_TRACE_LEVEL >= 1
dumpToLog("graph");
#endif
}
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 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
{
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.connectHeroes(ai);
visualKey = std::to_string(ai->playerID) + ":" + targetHero->getNameTranslated();
pathNodes.clear();
GraphNodeComparer cmp(pathNodes);
@@ -153,11 +206,17 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
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);
if(targetNode.tryUpdate(pos, node, o))
{
if(graph.getNode(target).objTypeID == Obj::HERO)
return;
if(targetNode.isInQueue)
{
pq.increase(targetNode.handle);
@@ -174,21 +233,28 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
void GraphPaths::dumpToLog() const
{
for(auto & tile : pathNodes)
{
for(auto & node : tile.second)
logVisual->updateWithLock(visualKey, [&](IVisualLogBuilder & logBuilder)
{
if(!node.previous.valid())
continue;
for(auto & tile : pathNodes)
{
for(auto & node : tile.second)
{
if(!node.previous.valid())
continue;
logAi->trace(
"%s -> %s: %f !%d",
node.previous.coord.toString(),
tile.first.toString(),
node.cost,
node.danger);
}
}
#if NKAI_GRAPH_TRACE_LEVEL >= 2
logAi->trace(
"%s -> %s: %f !%d",
node.previous.coord.toString(),
tile.first.toString(),
node.cost,
node.danger);
#endif
logBuilder.addLine(node.previous.coord, tile.first);
}
}
});
}
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(nodeType < pos.nodeType)
{
logAi->error("Linking error");
}
previous = pos;
danger = prev.danger + link.danger;
cost = newCost;
@@ -214,7 +285,7 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
if(nodes == pathNodes.end())
return;
for(auto & node : (*nodes).second)
for(auto & node : nodes->second)
{
if(!node.reachable())
continue;
@@ -236,6 +307,9 @@ void GraphPaths::addChainInfo(std::vector<AIPath> & paths, int3 tile, const CGHe
auto currentNode = currentTile->second[current.nodeType];
if(currentNode.cost == 0)
break;
allowBattle = allowBattle || currentNode.nodeType == GrapthPathNodeType::BATTLE;
vstd::amax(danger, currentNode.danger);
vstd::amax(cost, currentNode.cost);