Browse Source

NKAI: water paths in graph

Andrii Danylchenko 1 year ago
parent
commit
fb6fd63a58

+ 1 - 0
AI/Nullkiller/AIGateway.cpp

@@ -373,6 +373,7 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
 		return;
 
 	nullkiller->memory->removeFromMemory(obj);
+	nullkiller->baseGraph->removeObject(obj);
 
 	if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
 	{

+ 42 - 6
AI/Nullkiller/Pathfinding/ObjectGraph.cpp

@@ -10,6 +10,7 @@
 #include "StdInc.h"
 #include "ObjectGraph.h"
 #include "AIPathfinderConfig.h"
+#include "../../../lib/CRandomGenerator.h"
 #include "../../../CCallback.h"
 #include "../../../lib/mapping/CMap.h"
 #include "../Engine/Nullkiller.h"
@@ -21,10 +22,10 @@ namespace NKAI
 void ObjectGraph::updateGraph(const Nullkiller * ai)
 {
 	auto cb = ai->cb;
-	auto mapSize = cb->getMapSize();
 
 	std::map<const CGHeroInstance *, HeroRole> actors;
 	std::map<const CGHeroInstance *, const CGObjectInstance *> actorObjectMap;
+	std::vector<CGBoat *> boats;
 
 	auto addObjectActor = [&](const CGObjectInstance * obj)
 	{
@@ -37,8 +38,14 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
 		objectActor->pos = objectActor->convertFromVisitablePos(visitablePos);
 		objectActor->initObj(rng);
 
+		if(cb->getTile(visitablePos)->isWater())
+		{
+			boats.push_back(new CGBoat(objectActor->cb));
+			objectActor->boat = boats.back();
+		}
+
 		actorObjectMap[objectActor] = obj;
-		actors[objectActor] = obj->ID == Obj::TOWN ?  HeroRole::MAIN : HeroRole::SCOUT;
+		actors[objectActor] = obj->ID == Obj::TOWN || obj->ID == Obj::SHIPYARD ?  HeroRole::MAIN : HeroRole::SCOUT;
 		addObject(obj);
 	};
 
@@ -85,6 +92,17 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
 					auto obj1 = actorObjectMap[path1.targetHero];
 					auto obj2 = actorObjectMap[path2.targetHero];
 
+					auto tile1 = cb->getTile(obj1->visitablePos());
+					auto tile2 = cb->getTile(obj2->visitablePos());
+
+					if(tile2->isWater() && !tile1->isWater())
+					{
+						auto linkTile = cb->getTile(pos);
+
+						if(!linkTile->isWater() || obj1->ID != Obj::BOAT || obj1->ID != Obj::SHIPYARD)
+							continue;
+					}
+
 					auto danger = ai->pathfinder->getStorage()->evaluateDanger(obj2->visitablePos(), path1.targetHero, true);
 
 					auto updated = nodes[obj1->visitablePos()].connections[obj2->visitablePos()].update(
@@ -108,11 +126,16 @@ void ObjectGraph::updateGraph(const Nullkiller * ai)
 			}
 		});
 
-	for(auto h : actors)
+	for(auto h : actorObjectMap)
 	{
 		delete h.first;
 	}
 
+	for(auto boat : boats)
+	{
+		delete boat;
+	}
+
 #if NKAI_GRAPH_TRACE_LEVEL >= 1
 	dumpToLog("graph");
 #endif
@@ -123,6 +146,21 @@ void ObjectGraph::addObject(const CGObjectInstance * obj)
 	nodes[obj->visitablePos()].init(obj);
 }
 
+void ObjectGraph::removeObject(const CGObjectInstance * obj)
+{
+	nodes[obj->visitablePos()].objectExists = false;
+
+	if(obj->ID == Obj::BOAT)
+	{
+		vstd::erase_if(nodes[obj->visitablePos()].connections, [&](const std::pair<int3, ObjectLink> & link) -> bool
+			{
+				auto tile = cb->getTile(link.first, false);
+
+				return tile && tile->isWater();
+			});
+	}
+}
+
 void ObjectGraph::connectHeroes(const Nullkiller * ai)
 {
 	for(auto obj : ai->memory->visitableObjs)
@@ -170,7 +208,7 @@ void ObjectGraph::dumpToLog(std::string visualKey) const
 						node.second.danger);
 #endif
 
-					logBuilder.addLine(node.first, tile.first);
+					logBuilder.addLine(tile.first, node.first);
 				}
 			}
 		});
@@ -206,9 +244,7 @@ void GraphPaths::calculatePaths(const CGHeroInstance * targetHero, const Nullkil
 
 		graph.iterateConnections(pos.coord, [&](int3 target, ObjectLink o)
 			{
-				auto graphNode = graph.getNode(target);
 				auto targetNodeType = o.danger ? GrapthPathNodeType::BATTLE : pos.nodeType;
-
 				auto targetPointer = GraphPathNodePointer(target, targetNodeType);
 				auto & targetNode = getNode(targetPointer);
 

+ 1 - 0
AI/Nullkiller/Pathfinding/ObjectGraph.h

@@ -60,6 +60,7 @@ public:
 	void updateGraph(const Nullkiller * ai);
 	void addObject(const CGObjectInstance * obj);
 	void connectHeroes(const Nullkiller * ai);
+	void removeObject(const CGObjectInstance * obj);
 	void dumpToLog(std::string visualKey) const;
 
 	template<typename Func>

+ 14 - 0
Global.h

@@ -512,6 +512,20 @@ namespace vstd
 		}
 	}
 
+	//works for std::unordered_map, maybe something else
+	template<typename Key, typename Val, typename Predicate>
+	void erase_if(std::unordered_map<Key, Val> & container, Predicate pred)
+	{
+		auto itr = container.begin();
+		auto endItr = container.end();
+		while(itr != endItr)
+		{
+			auto tmpItr = itr++;
+			if(pred(*tmpItr))
+				container.erase(tmpItr);
+		}
+	}
+
 	template<typename InputRange, typename OutputIterator, typename Predicate>
 	OutputIterator copy_if(const InputRange &input, OutputIterator result, Predicate pred)
 	{

+ 4 - 1
client/mapView/MapView.cpp

@@ -80,9 +80,12 @@ public:
 		auto pEnd = model->getTargetTileArea(end).topLeft();
 		auto viewPort = target.getRenderArea();
 
+		pStart.x += 3;
+		pEnd.x -= 3;
+
 		if(viewPort.isInside(pStart) && viewPort.isInside(pEnd))
 		{
-			target.drawLine(pStart, pEnd, ColorRGBA(255, 255, 0), ColorRGBA(255, 255, 0));
+			target.drawLine(pStart, pEnd, ColorRGBA(255, 255, 0), ColorRGBA(255, 0, 0));
 		}
 	}
 };