Browse Source

AI: hero chain stabilisation

Andrii Danylchenko 4 years ago
parent
commit
0e328ab3c2

+ 21 - 9
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -172,6 +172,12 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf
 	{
 		commit(dstNode, srcNode, destination.action, destination.turn, destination.movementLeft, destination.cost);
 
+		if(srcNode->specialAction || srcNode->chainOther)
+		{
+			// there is some action on source tile which should be performed before we can bypass it
+			destination.node->theNodeBefore = source.node;
+		}
+
 		if(dstNode->specialAction && dstNode->actor)
 		{
 			dstNode->specialAction->applyOnDestination(dstNode->actor->hero, destination, source, dstNode, srcNode);
@@ -183,7 +189,7 @@ void AINodeStorage::commit(CDestinationNodeInfo & destination, const PathNodeInf
 			source.coord.toString(),
 			destination.coord.toString(),
 			destination.cost,
-			dstNode->actor->hero->name,
+			dstNode->actor->toString(),
 			dstNode->actor->chainMask);
 #endif
 	});
@@ -251,13 +257,19 @@ bool AINodeStorage::calculateHeroChain()
 
 		for(AIPathNode & node : chains)
 		{
+			if(node.coord.x == 60 && node.coord.y == 56 && node.actor)
+				logAi->trace(node.actor->toString());
+
 			if(node.turns <= heroChainMaxTurns && node.action != CGPathNode::ENodeAction::UNKNOWN)
 				buffer.push_back(&node);
 		}
 
 		for(AIPathNode * node : buffer)
 		{
-			addHeroChain(node, buffer);
+			if(node->actor->hero)
+			{
+				addHeroChain(node, buffer);
+			}
 		}
 	});
 
@@ -277,9 +289,9 @@ void AINodeStorage::addHeroChain(AIPathNode * srcNode, std::vector<AIPathNode *>
 #ifdef VCMI_TRACE_PATHFINDER_EX
 		logAi->trace(
 			"Thy exchange %s[%i] -> %s[%i] at %s",
-			node->actor->hero->name,
+			node->actor->toString(),
 			node->actor->chainMask,
-			srcNode->actor->hero->name,
+			srcNode->actor->toString(),
 			srcNode->actor->chainMask,
 			srcNode->coord.toString());
 #endif
@@ -299,9 +311,9 @@ void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other)
 #ifdef VCMI_TRACE_PATHFINDER_EX
 		logAi->trace(
 			"Exchange allowed %s[%i] -> %s[%i] at %s",
-			other->actor->hero->name,
+			other->actor->toString(),
 			other->actor->chainMask,
-			carrier->actor->hero->name,
+			carrier->actor->toString(),
 			carrier->actor->chainMask,
 			carrier->coord.toString());
 #endif
@@ -344,8 +356,8 @@ void AINodeStorage::addHeroChain(AIPathNode * carrier, AIPathNode * other)
 			logAi->trace(
 				"Chain accepted at %s %s -> %s, mask %i, cost %f", 
 				chainNode->coord.toString(), 
-				other->actor->hero->name, 
-				chainNode->actor->hero->name,
+				other->actor->toString(), 
+				chainNode->actor->toString(),
 				chainNode->actor->chainMask,
 				chainNode->cost);
 #endif
@@ -430,7 +442,7 @@ void AINodeStorage::setHeroes(std::vector<HeroPtr> heroes, const VCAI * _ai)
 
 void AINodeStorage::setTownsAndDwellings(
 	const std::vector<const CGTownInstance *> & towns,
-	const std::vector<const CGObjectInstance *> & visitableObjs)
+	const std::set<const CGObjectInstance *> & visitableObjs)
 {
 	for(auto town : towns)
 	{

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

@@ -85,7 +85,7 @@ private:
 
 public:
 	/// more than 1 chain layer for each hero allows us to have more than 1 path to each tile so we can chose more optimal one.
-	static const int NUM_CHAINS = 3 * GameConstants::MAX_HEROES_PER_PLAYER;
+	static const int NUM_CHAINS = 5 * GameConstants::MAX_HEROES_PER_PLAYER;
 	
 	AINodeStorage(const int3 & sizes);
 	~AINodeStorage();
@@ -116,7 +116,7 @@ public:
 	void setHeroes(std::vector<HeroPtr> heroes, const VCAI * ai);
 	void setTownsAndDwellings(
 		const std::vector<const CGTownInstance *> & towns,
-		const std::vector<const CGObjectInstance *> & visitableObjs);
+		const std::set<const CGObjectInstance *> & visitableObjs);
 	const CGHeroInstance * getHero(const CGPathNode * node) const;
 	const std::set<const CGHeroInstance *> getAllHeroes() const;
 	void clear();

+ 5 - 0
AI/Nullkiller/Pathfinding/AIPathfinder.cpp

@@ -56,6 +56,11 @@ void AIPathfinder::updatePaths(std::vector<HeroPtr> heroes, bool useHeroChain)
 	storage->clear();
 	storage->setHeroes(heroes, ai);
 
+	if(useHeroChain)
+	{
+		storage->setTownsAndDwellings(cb->getTownsInfo(), ai->visitableObjs);
+	}
+
 	auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, ai, storage);
 
 	do {

+ 18 - 19
AI/Nullkiller/Pathfinding/Actors.cpp

@@ -16,23 +16,6 @@
 #include "../../../lib/mapping/CMap.h"
 #include "../../../lib/mapObjects/MapObjects.h"
 
-class ExchangeAction : public ISpecialAction
-{
-private:
-	const CGHeroInstance * target;
-	const CGHeroInstance * source;
-
-public:
-	ExchangeAction(const CGHeroInstance * target, const CGHeroInstance * source)
-		:target(target), source(source)
-	{ }
-
-	virtual Goals::TSubgoal whatToDo(const HeroPtr & hero) const override
-	{
-		return Goals::sptr(Goals::VisitHero(target->id.getNum()).sethero(hero));
-	}
-};
-
 ChainActor::ChainActor(const CGHeroInstance * hero, uint64_t chainMask)
 	:hero(hero), isMovable(true), chainMask(chainMask), creatureSet(hero),
 	baseActor(this), carrierParent(nullptr), otherParent(nullptr)
@@ -60,6 +43,11 @@ ChainActor::ChainActor(const CGObjectInstance * obj, const CCreatureSet * creatu
 	armyValue = creatureSet->getArmyStrength();
 }
 
+std::string ChainActor::toString() const
+{
+	return hero->name;
+}
+
 HeroActor::HeroActor(const CGHeroInstance * hero, uint64_t chainMask, const VCAI * ai)
 	:ChainActor(hero, chainMask)
 {
@@ -213,7 +201,8 @@ DwellingActor::DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bo
 		dwelling, 
 		getDwellingCreatures(dwelling, waitForGrowth), 
 		chainMask, 
-		getInitialTurn(waitForGrowth, dayOfWeek))
+		getInitialTurn(waitForGrowth, dayOfWeek)),
+	dwelling(dwelling)
 {
 }
 
@@ -230,6 +219,11 @@ int DwellingActor::getInitialTurn(bool waitForGrowth, int dayOfWeek)
 	return 8 - dayOfWeek;
 }
 
+std::string DwellingActor::toString() const
+{
+	return dwelling->typeName + dwelling->visitablePos().toString();
+}
+
 CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling, bool waitForGrowth)
 {
 	CCreatureSet * dwellingCreatures = new CCreatureSet();
@@ -259,6 +253,11 @@ CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling,
 }
 
 TownGarrisonActor::TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask)
-	:ChainActor(town, town->getUpperArmy(), chainMask, 0)
+	:ChainActor(town, town->getUpperArmy(), chainMask, 0), town(town)
+{
+}
+
+std::string TownGarrisonActor::toString() const
 {
+	return town->name;
 }

+ 9 - 0
AI/Nullkiller/Pathfinding/Actors.h

@@ -48,6 +48,7 @@ public:
 	ChainActor(){}
 
 	virtual bool canExchange(const ChainActor * other) const;
+	virtual std::string toString() const;
 	ChainActor * exchange(const ChainActor * other) const { return exchange(this, other); }
 	void setBaseActor(HeroActor * base);
 
@@ -102,9 +103,13 @@ protected:
 
 class DwellingActor : public ChainActor
 {
+private:
+	const CGDwelling * dwelling;
+
 public:
 	DwellingActor(const CGDwelling * dwelling, uint64_t chainMask, bool waitForGrowth, int dayOfWeek);
 	~DwellingActor();
+	virtual std::string toString() const override;
 
 protected:
 	int getInitialTurn(bool waitForGrowth, int dayOfWeek);
@@ -113,6 +118,10 @@ protected:
 
 class TownGarrisonActor : public ChainActor
 {
+private:
+	const CGTownInstance * town;
+
 public:
 	TownGarrisonActor(const CGTownInstance * town, uint64_t chainMask);
+	virtual std::string toString() const override;
 };

+ 0 - 8
AI/Nullkiller/Pathfinding/Rules/AIPreviousNodeRule.cpp

@@ -35,13 +35,5 @@ namespace AIPathfinding
 #endif
 			return;
 		}
-
-		auto srcNode = nodeStorage->getAINode(source.node);
-
-		if(srcNode->specialAction || srcNode->chainOther)
-		{
-			// there is some action on source tile which should be performed before we can bypass it
-			destination.node->theNodeBefore = source.node;
-		}
 	}
 }