Sfoglia il codice sorgente

more thread_local removal work

Mircea TheHonestCTO 4 mesi fa
parent
commit
3aed53de3d

+ 1 - 1
AI/Nullkiller2/AIGateway.cpp

@@ -361,7 +361,7 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
 
 	if(nullkiller->baseGraph && nullkiller->isObjectGraphAllowed())
 	{
-		nullkiller->baseGraph->removeObject(obj);
+		nullkiller->baseGraph->removeObject(obj, *nullkiller->cc);
 	}
 
 	if(obj->ID == Obj::HERO && obj->tempOwner == playerID)

+ 10 - 10
AI/Nullkiller2/Engine/DeepDecomposer.cpp

@@ -75,7 +75,7 @@ void DeepDecomposer::decompose(TGoalVec & results, TSubgoal behavior, int depthL
 				// TODO: Mircea: Issue with CGameHandler::spawnWanderingMonsters, see getFreeTiles(tiles, true);
 				// danger not linked GraphPaths::addChainInfo, so spawning only with nearby unblocked
 #if NK2AI_TRACE_LEVEL >= 1
-				logAi->trace("Found task %s", task->toString());
+				logAi->trace("Found task %s", task->toString(TODO));
 #endif
 				if(!isCompositionLoop(subgoal))
 				{
@@ -90,7 +90,7 @@ void DeepDecomposer::decompose(TGoalVec & results, TSubgoal behavior, int depthL
 			else if(depth < depthLimit - 1)
 			{
 #if NK2AI_TRACE_LEVEL >= 1
-				logAi->trace("Found abstract goal %s", subgoal->toString());
+				logAi->trace("Found abstract goal %s", subgoal->toString(TODO));
 #endif
 				if(!isCompositionLoop(subgoal))
 				{
@@ -142,14 +142,14 @@ Goals::TSubgoal DeepDecomposer::unwrapComposition(Goals::TSubgoal goal)
 	return goal->goalType == Goals::COMPOSITION ? goal->decompose(aiNk).back() : goal;
 }
 
-bool isEquivalentGoals(TSubgoal goal1, TSubgoal goal2)
+bool isEquivalentGoals(TSubgoal goal1, TSubgoal goal2, CCallback & cc)
 {
 	if(goal1 == goal2) return true;
 
 	if(goal1->goalType == Goals::CAPTURE_OBJECT && goal2->goalType == Goals::CAPTURE_OBJECT)
 	{
-		auto o1 = ccTl->getObj(ObjectInstanceID(goal1->objid));
-		auto o2 = ccTl->getObj(ObjectInstanceID(goal2->objid));
+		const auto o1 = cc.getObj(ObjectInstanceID(goal1->objid));
+		const auto o2 = cc.getObj(ObjectInstanceID(goal2->objid));
 
 		return o1->ID == Obj::SHIPYARD && o1->ID == o2->ID;
 	}
@@ -167,7 +167,7 @@ bool DeepDecomposer::isCompositionLoop(TSubgoal goal)
 		{
 			auto parent = unwrapComposition(goals[i].back());
 
-			if(isEquivalentGoals(parent, goalToTest))
+			if(isEquivalentGoals(parent, goalToTest, *aiNk->cc))
 			{
 				return true;
 			}
@@ -180,7 +180,7 @@ bool DeepDecomposer::isCompositionLoop(TSubgoal goal)
 TGoalVec DeepDecomposer::decomposeCached(TSubgoal goal, bool & fromCache)
 {
 #if NK2AI_TRACE_LEVEL >= 1
-	logAi->trace("Decomposing %s, level %s", goal->toString(), depth);
+	logAi->trace("Decomposing %s, level %s", goal->toString(TODO), depth);
 #endif
 
 	if(goal->hasHash())
@@ -192,7 +192,7 @@ TGoalVec DeepDecomposer::decomposeCached(TSubgoal goal, bool & fromCache)
 			if(cached != decompositionCache[i].end())
 			{
 #if NK2AI_TRACE_LEVEL >= 1
-				logAi->trace("Use decomposition cache for %s, level: %d", goal->toString(), depth);
+				logAi->trace("Use decomposition cache for %s, level: %d", goal->toString(TODO), depth);
 #endif
 				fromCache = true;
 
@@ -204,7 +204,7 @@ TGoalVec DeepDecomposer::decomposeCached(TSubgoal goal, bool & fromCache)
 	}
 
 #if NK2AI_TRACE_LEVEL >= 2
-	logAi->trace("Calling decompose on %s, level %s", goal->toString(), depth);
+	logAi->trace("Calling decompose on %s, level %s", goal->toString(TODO), depth);
 #endif
 
 	fromCache = false;
@@ -225,7 +225,7 @@ void DeepDecomposer::addToCache(TSubgoal goal)
 			auto solution = parentDepth < depth ? aggregateGoals(parentDepth + 1, goal) : goal;
 
 #if NK2AI_TRACE_LEVEL >= 2
-			logAi->trace("Adding %s to decomosition cache of %s at level %d", solution->toString(), parent->toString(), parentDepth);
+			logAi->trace("Adding %s to decomosition cache of %s at level %d", solution->toString(TODO), parent->toString(TODO), parentDepth);
 #endif
 
 			decompositionCache[parentDepth][parent].push_back(solution);

+ 1 - 2
AI/Nullkiller2/Pathfinding/AIPathfinder.cpp

@@ -91,8 +91,7 @@ void AIPathfinder::updatePaths(const std::map<const CGHeroInstance *, HeroRole>
 		storage->setTownsAndDwellings(cb->getTownsInfo(), aiNk->memory->visitableObjs);
 	}
 
-	auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(cb, aiNk, storage, pathfinderSettings.allowBypassObjects);
-
+	const auto config = std::make_shared<AIPathfinding::AIPathfinderConfig>(aiNk, storage, pathfinderSettings.allowBypassObjects);
 	logAi->trace("Recalculate paths pass %d", pass++);
 	cb->calculatePaths(config);
 

+ 13 - 20
AI/Nullkiller2/Pathfinding/AIPathfinderConfig.cpp

@@ -8,12 +8,12 @@
 *
 */
 #include "StdInc.h"
+#include "AI/Nullkiller2/Engine/Nullkiller.h"
 #include "AIPathfinderConfig.h"
 #include "Rules/AILayerTransitionRule.h"
 #include "Rules/AIMovementAfterDestinationRule.h"
 #include "Rules/AIMovementToDestinationRule.h"
 #include "Rules/AIPreviousNodeRule.h"
-#include "../Engine/Nullkiller.h"
 
 #include "../../../lib/pathfinder/CPathfinder.h"
 
@@ -21,30 +21,23 @@ namespace NK2AI
 {
 namespace AIPathfinding
 {
-	std::vector<std::shared_ptr<IPathfindingRule>> makeRuleset(
-		CPlayerSpecificInfoCallback * cb,
-		Nullkiller * aiNk,
-		std::shared_ptr<AINodeStorage> nodeStorage,
-		bool allowBypassObjects)
+	std::vector<std::shared_ptr<IPathfindingRule>>
+	makeRuleset(CPlayerSpecificInfoCallback * cpsic, Nullkiller * aiNk, std::shared_ptr<AINodeStorage> nodeStorage, bool allowBypassObjects)
 	{
-			std::vector<std::shared_ptr<IPathfindingRule>> rules = {
-				std::make_shared<AILayerTransitionRule>(cb, aiNk, nodeStorage),
-				std::make_shared<DestinationActionRule>(),
-				std::make_shared<AIMovementToDestinationRule>(nodeStorage, allowBypassObjects),
-				std::make_shared<MovementCostRule>(),
-				std::make_shared<AIPreviousNodeRule>(nodeStorage),
-				std::make_shared<AIMovementAfterDestinationRule>(aiNk, cb, nodeStorage, allowBypassObjects)
-			};
+		std::vector<std::shared_ptr<IPathfindingRule>> rules = {
+			std::make_shared<AILayerTransitionRule>(aiNk, nodeStorage),
+			std::make_shared<DestinationActionRule>(),
+			std::make_shared<AIMovementToDestinationRule>(nodeStorage, allowBypassObjects, *aiNk->cc),
+			std::make_shared<MovementCostRule>(),
+			std::make_shared<AIPreviousNodeRule>(nodeStorage),
+			std::make_shared<AIMovementAfterDestinationRule>(aiNk, nodeStorage, allowBypassObjects)
+		};
 
 		return rules;
 	}
 
-	AIPathfinderConfig::AIPathfinderConfig(
-		CPlayerSpecificInfoCallback * cb,
-		Nullkiller * aiNk,
-		std::shared_ptr<AINodeStorage> nodeStorage,
-		bool allowBypassObjects)
-		:PathfinderConfig(nodeStorage, *cb, makeRuleset(cb, aiNk, nodeStorage, allowBypassObjects)), aiNodeStorage(nodeStorage)
+	AIPathfinderConfig::AIPathfinderConfig(Nullkiller * aiNk, std::shared_ptr<AINodeStorage> nodeStorage, bool allowBypassObjects)
+		: PathfinderConfig(nodeStorage, *aiNk->cc, makeRuleset(aiNk->cc.get(), aiNk, nodeStorage, allowBypassObjects)), aiNodeStorage(nodeStorage)
 	{
 		options.canUseCast = true;
 		options.allowLayerTransitioningAfterBattle = true;

+ 1 - 6
AI/Nullkiller2/Pathfinding/AIPathfinderConfig.h

@@ -27,12 +27,7 @@ namespace AIPathfinding
 		std::shared_ptr<AINodeStorage> aiNodeStorage;
 
 	public:
-		AIPathfinderConfig(
-			CPlayerSpecificInfoCallback * cb,
-			Nullkiller * aiNk,
-			std::shared_ptr<AINodeStorage> nodeStorage,
-			bool allowBypassObjects);
-
+		AIPathfinderConfig(Nullkiller * aiNk, std::shared_ptr<AINodeStorage> nodeStorage, bool allowBypassObjects);
 		~AIPathfinderConfig();
 
 		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, const IGameInfoCallback & gameInfo) override;

+ 2 - 2
AI/Nullkiller2/Pathfinding/ObjectGraph.cpp

@@ -78,7 +78,7 @@ void ObjectGraph::registerJunction(const int3 & pos)
 
 }
 
-void ObjectGraph::removeObject(const CGObjectInstance * obj)
+void ObjectGraph::removeObject(const CGObjectInstance * obj, CCallback & cc)
 {
 	nodes[obj->visitablePos()].objectExists = false;
 
@@ -86,7 +86,7 @@ void ObjectGraph::removeObject(const CGObjectInstance * obj)
 	{
 		vstd::erase_if(nodes[obj->visitablePos()].connections, [&](const std::pair<int3, ObjectLink> & link) -> bool
 			{
-				const auto tile = ccTl->getTile(link.first, false);
+				const auto tile = cc.getTile(link.first, false);
 				return tile && tile->isWater();
 			});
 	}

+ 1 - 1
AI/Nullkiller2/Pathfinding/ObjectGraph.h

@@ -76,7 +76,7 @@ public:
 	void registerJunction(const int3 & pos);
 	void addVirtualBoat(const int3 & pos, const CGObjectInstance * shipyard);
 	void connectHeroes(const Nullkiller * aiNk);
-	void removeObject(const CGObjectInstance * obj);
+	void removeObject(const CGObjectInstance * obj, CCallback & cc);
 	bool tryAddConnection(const int3 & from, const int3 & to, float cost, uint64_t danger);
 	void removeConnection(const int3 & from, const int3 & to);
 	void dumpToLog(std::string visualKey) const;

+ 26 - 26
AI/Nullkiller2/Pathfinding/Rules/AILayerTransitionRule.cpp

@@ -8,8 +8,9 @@
 *
 */
 #include "StdInc.h"
+#include "AI/Nullkiller2/Engine/Nullkiller.h"
 #include "AILayerTransitionRule.h"
-#include "../../Engine/Nullkiller.h"
+
 #include "../../../../lib/pathfinder/CPathfinder.h"
 #include "../../../../lib/pathfinder/TurnInfo.h"
 #include "../../../../lib/spells/ISpellMechanics.h"
@@ -19,11 +20,7 @@ namespace NK2AI
 {
 namespace AIPathfinding
 {
-	AILayerTransitionRule::AILayerTransitionRule(
-		CPlayerSpecificInfoCallback * cb,
-		Nullkiller * aiNk,
-		std::shared_ptr<AINodeStorage> nodeStorage)
-		:cb(cb), aiNk(aiNk), nodeStorage(nodeStorage)
+	AILayerTransitionRule::AILayerTransitionRule(Nullkiller * aiNk, std::shared_ptr<AINodeStorage> nodeStorage) : aiNk(aiNk), nodeStorage(nodeStorage)
 	{
 		setup();
 	}
@@ -32,22 +29,25 @@ namespace AIPathfinding
 		const PathNodeInfo & source,
 		CDestinationNodeInfo & destination,
 		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const
+		CPathfinderHelper * pathfinderHelper
+	) const
 	{
 		LayerTransitionRule::process(source, destination, pathfinderConfig, pathfinderHelper);
 
 #if NK2AI_PATHFINDER_TRACE_LEVEL >= 2
-		logAi->trace("Layer transitioning %s -> %s, action: %d, blocked: %s",
+		logAi->trace(
+			"Layer transitioning %s -> %s, action: %d, blocked: %s",
 			source.coord.toString(),
 			destination.coord.toString(),
 			static_cast<int32_t>(destination.action),
-			destination.blocked ? "true" : "false");
+			destination.blocked ? "true" : "false"
+		);
 #endif
 
 		if(!destination.blocked)
 		{
 			if(source.node->layer == EPathfindingLayer::LAND
-				&& (destination.node->layer == EPathfindingLayer::AIR || destination.node->layer == EPathfindingLayer::WATER))
+			   && (destination.node->layer == EPathfindingLayer::AIR || destination.node->layer == EPathfindingLayer::WATER))
 			{
 				if(pathfinderHelper->getTurnInfo()->isLayerAvailable(destination.node->layer))
 					return;
@@ -113,17 +113,19 @@ namespace AIPathfinding
 	{
 		for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
 		{
-			for (const auto & spell : LIBRARY->spellh->objects)
+			for(const auto & spell : LIBRARY->spellh->objects)
 			{
-				if (!spell || !spell->isAdventure())
+				if(!spell || !spell->isAdventure())
 					continue;
 
-				if(spell->getAdventureMechanics().givesBonus(hero, BonusType::WATER_WALKING) && hero->canCastThisSpell(spell.get()) && hero->mana >= hero->getSpellCost(spell.get()))
+				if(spell->getAdventureMechanics().givesBonus(hero, BonusType::WATER_WALKING) && hero->canCastThisSpell(spell.get())
+				   && hero->mana >= hero->getSpellCost(spell.get()))
 				{
 					waterWalkingActions[hero] = std::make_shared<WaterWalkingAction>(hero, spell->id);
 				}
 
-				if(spell->getAdventureMechanics().givesBonus(hero, BonusType::FLYING_MOVEMENT) && hero->canCastThisSpell(spell.get()) && hero->mana >= hero->getSpellCost(spell.get()))
+				if(spell->getAdventureMechanics().givesBonus(hero, BonusType::FLYING_MOVEMENT) && hero->canCastThisSpell(spell.get())
+				   && hero->mana >= hero->getSpellCost(spell.get()))
 				{
 					airWalkingActions[hero] = std::make_shared<AirWalkingAction>(hero, spell->id);
 				}
@@ -137,7 +139,7 @@ namespace AIPathfinding
 	{
 		std::vector<const IShipyard *> shipyards;
 
-		for(const CGTownInstance * t : cb->getTownsInfo())
+		for(const CGTownInstance * t : aiNk->cc->getTownsInfo())
 		{
 			if(t->hasBuilt(BuildingID::SHIPYARD))
 				shipyards.push_back(t);
@@ -157,24 +159,24 @@ namespace AIPathfinding
 			if(shipyard->shipyardStatus() == IShipyard::GOOD)
 			{
 				int3 boatLocation = shipyard->bestLocation();
-				virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(cb, shipyard);
+				virtualBoats[boatLocation] = std::make_shared<BuildBoatAction>(aiNk->cc.get(), shipyard);
 				logAi->debug("Virtual boat added at %s", boatLocation.toString());
 			}
 		}
 
 		for(const CGHeroInstance * hero : nodeStorage->getAllHeroes())
 		{
-			for (const auto & spell : LIBRARY->spellh->objects)
+			for(const auto & spell : LIBRARY->spellh->objects)
 			{
-				if (!spell || !spell->isAdventure())
+				if(!spell || !spell->isAdventure())
 					continue;
 
 				auto effect = spell->getAdventureMechanics().getEffectAs<SummonBoatEffect>(hero);
 
-				if (!effect || !hero->canCastThisSpell(spell.get()))
+				if(!effect || !hero->canCastThisSpell(spell.get()))
 					continue;
 
-				if (effect->canCreateNewBoat() && effect->getSuccessChance(hero) == 100)
+				if(effect->canCreateNewBoat() && effect->getSuccessChance(hero) == 100)
 				{
 					// TODO: For lower school level we might need to check the existence of some boat
 					summonableVirtualBoats[hero] = std::make_shared<SummonBoatAction>(spell->id);
@@ -183,9 +185,7 @@ namespace AIPathfinding
 		}
 	}
 
-	std::shared_ptr<const VirtualBoatAction> AILayerTransitionRule::findVirtualBoat(
-		CDestinationNodeInfo & destination,
-		const PathNodeInfo & source) const
+	std::shared_ptr<const VirtualBoatAction> AILayerTransitionRule::findVirtualBoat(CDestinationNodeInfo & destination, const PathNodeInfo & source) const
 	{
 		std::shared_ptr<const VirtualBoatAction> virtualBoat;
 
@@ -197,8 +197,7 @@ namespace AIPathfinding
 		{
 			const CGHeroInstance * hero = nodeStorage->getHero(source.node);
 
-			if(vstd::contains(summonableVirtualBoats, hero)
-				&& summonableVirtualBoats.at(hero)->canAct(aiNk, nodeStorage->getAINode(source.node)))
+			if(vstd::contains(summonableVirtualBoats, hero) && summonableVirtualBoats.at(hero)->canAct(aiNk, nodeStorage->getAINode(source.node)))
 			{
 				virtualBoat = summonableVirtualBoats.at(hero);
 			}
@@ -211,7 +210,8 @@ namespace AIPathfinding
 		CDestinationNodeInfo & destination,
 		const PathNodeInfo & source,
 		std::shared_ptr<const SpecialAction> specialAction,
-		EPathNodeAction targetAction) const
+		EPathNodeAction targetAction
+	) const
 	{
 		bool result = false;
 

+ 3 - 7
AI/Nullkiller2/Pathfinding/Rules/AILayerTransitionRule.h

@@ -23,8 +23,6 @@ namespace AIPathfinding
 {
 	class AILayerTransitionRule : public LayerTransitionRule
 	{
-	private:
-		CPlayerSpecificInfoCallback * cb;
 		Nullkiller * aiNk;
 		std::map<int3, std::shared_ptr<const BuildBoatAction>> virtualBoats;
 		std::shared_ptr<AINodeStorage> nodeStorage;
@@ -33,16 +31,14 @@ namespace AIPathfinding
 		std::map<const CGHeroInstance *, std::shared_ptr<const AirWalkingAction>> airWalkingActions;
 
 	public:
-		AILayerTransitionRule(
-			CPlayerSpecificInfoCallback * cb,
-			Nullkiller * aiNk,
-			std::shared_ptr<AINodeStorage> nodeStorage);
+		AILayerTransitionRule(Nullkiller * aiNk, std::shared_ptr<AINodeStorage> nodeStorage);
 
 		virtual void process(
 			const PathNodeInfo & source,
 			CDestinationNodeInfo & destination,
 			const PathfinderConfig * pathfinderConfig,
-			CPathfinderHelper * pathfinderHelper) const override;
+			CPathfinderHelper * pathfinderHelper
+		) const override;
 
 	private:
 		void setup();

+ 5 - 8
AI/Nullkiller2/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -24,10 +24,9 @@ namespace AIPathfinding
 {
 	AIMovementAfterDestinationRule::AIMovementAfterDestinationRule(
 		const Nullkiller * aiNk,
-		CPlayerSpecificInfoCallback * cb, 
 		std::shared_ptr<AINodeStorage> nodeStorage,
 		bool allowBypassObjects)
-		:aiNk(aiNk), cb(cb), nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects)
+		:aiNk(aiNk), nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects)
 	{
 	}
 
@@ -94,7 +93,7 @@ namespace AIPathfinding
 			source.coord.toString());
 #endif
 
-		auto destGuardians = cb->getGuardingCreatures(destination.coord);
+		auto destGuardians = aiNk->cc->getGuardingCreatures(destination.coord);
 		bool allowBypass = false;
 
 		switch(blocker)
@@ -255,22 +254,20 @@ namespace AIPathfinding
 		const PathfinderConfig * pathfinderConfig,
 		CPathfinderHelper * pathfinderHelper) const
 	{
-		auto srcGuardians = cb->getGuardingCreatures(source.coord);
-
 		if(destGuardians.empty())
 		{
 			return false;
 		}
 
-		auto srcNode = nodeStorage->getAINode(source.node);
+		const auto srcGuardians = aiNk->cc->getGuardingCreatures(source.coord);
+		const auto srcNode = nodeStorage->getAINode(source.node);
 
 		vstd::erase_if(destGuardians, [&](const CGObjectInstance * destGuard) -> bool
 		{
 			return vstd::contains(srcGuardians, destGuard);
 		});
 
-		auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
-
+		const auto guardsAlreadyBypassed = destGuardians.empty() && srcGuardians.size();
 		if(guardsAlreadyBypassed && srcNode->actor->allowBattle)
 		{
 #if NK2AI_PATHFINDER_TRACE_LEVEL >= 1

+ 0 - 2
AI/Nullkiller2/Pathfinding/Rules/AIMovementAfterDestinationRule.h

@@ -22,7 +22,6 @@ namespace AIPathfinding
 	class AIMovementAfterDestinationRule : public MovementAfterDestinationRule
 	{
 	private:
-		CPlayerSpecificInfoCallback * cb;
 		const Nullkiller * aiNk;
 		std::shared_ptr<AINodeStorage> nodeStorage;
 		bool allowBypassObjects;
@@ -30,7 +29,6 @@ namespace AIPathfinding
 	public:
 		AIMovementAfterDestinationRule(
 			const Nullkiller * aiNk,
-			CPlayerSpecificInfoCallback * cb,
 			std::shared_ptr<AINodeStorage> nodeStorage,
 			bool allowBypassObjects);
 

+ 9 - 14
AI/Nullkiller2/Pathfinding/Rules/AIMovementToDestinationRule.cpp

@@ -14,10 +14,8 @@ namespace NK2AI
 {
 namespace AIPathfinding
 {
-	AIMovementToDestinationRule::AIMovementToDestinationRule(
-		std::shared_ptr<AINodeStorage> nodeStorage,
-		bool allowBypassObjects)
-		: nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects)
+	AIMovementToDestinationRule::AIMovementToDestinationRule(const std::shared_ptr<AINodeStorage> & nodeStorage, const bool allowBypassObjects, CCallback & cc)
+		: nodeStorage(nodeStorage), allowBypassObjects(allowBypassObjects), cc(cc)
 	{
 	}
 
@@ -25,16 +23,16 @@ namespace AIPathfinding
 		const PathNodeInfo & source,
 		CDestinationNodeInfo & destination,
 		const PathfinderConfig * pathfinderConfig,
-		CPathfinderHelper * pathfinderHelper) const
+		CPathfinderHelper * pathfinderHelper
+	) const
 	{
 		auto blocker = getBlockingReason(source, destination, pathfinderConfig, pathfinderHelper);
 
 		if(blocker == BlockingReason::NONE)
 			return;
 
-		if(blocker == BlockingReason::DESTINATION_BLOCKED
-			&& destination.action == EPathNodeAction::EMBARK
-			&& nodeStorage->getAINode(destination.node)->specialAction)
+		if(blocker == BlockingReason::DESTINATION_BLOCKED && destination.action == EPathNodeAction::EMBARK
+		   && nodeStorage->getAINode(destination.node)->specialAction)
 		{
 			return;
 		}
@@ -45,21 +43,18 @@ namespace AIPathfinding
 
 			if(!allowBypassObjects)
 			{
-				if (source.node->getCost() < 0.0001f)
+				if(source.node->getCost() < 0.0001f)
 					return;
 
 				// when actor represents moster graph node, we need to let him escape monster
-				if(ccTl->getGuardingCreaturePosition(source.coord) == actor->initialPosition)
+				if(cc.getGuardingCreaturePosition(source.coord) == actor->initialPosition)
 					return;
 			}
 
 			if(actor->allowBattle)
 			{
 #if NK2AI_PATHFINDER_TRACE_LEVEL >= 1
-				logAi->trace(
-					"Bypass src guard while moving from %s to %s",
-					source.coord.toString(),
-					destination.coord.toString());
+				logAi->trace("Bypass src guard while moving from %s to %s", source.coord.toString(), destination.coord.toString());
 #endif
 				return;
 			}

+ 2 - 2
AI/Nullkiller2/Pathfinding/Rules/AIMovementToDestinationRule.h

@@ -21,12 +21,12 @@ namespace AIPathfinding
 {
 	class AIMovementToDestinationRule : public MovementToDestinationRule
 	{
-	private:
 		std::shared_ptr<AINodeStorage> nodeStorage;
 		bool allowBypassObjects;
+		CCallback & cc;
 
 	public:
-		AIMovementToDestinationRule(std::shared_ptr<AINodeStorage> nodeStorage, bool allowBypassObjects);
+		AIMovementToDestinationRule(const std::shared_ptr<AINodeStorage> & nodeStorage, bool allowBypassObjects, CCallback & cc);
 
 		virtual void process(
 			const PathNodeInfo & source,