Răsfoiți Sursa

WIP remove thread_local CCallback * ccTl

Mircea TheHonestCTO 3 luni în urmă
părinte
comite
fa677eb243

+ 42 - 42
AI/Nullkiller2/AIGateway.cpp

@@ -366,7 +366,7 @@ void AIGateway::objectRemoved(const CGObjectInstance * obj, const PlayerColor &
 
 	if(obj->ID == Obj::HERO && obj->tempOwner == playerID)
 	{
-		lostHero(cc->getHero(obj->id)); //we can promote, since objectRemoved is called just before actual deletion
+		lostHero(HeroPtr(cc->getHero(obj->id))); //we can promote, since objectRemoved is called just before actual deletion
 	}
 
 	if(obj->ID == Obj::HERO && cc->getPlayerRelations(obj->tempOwner, playerID) == PlayerRelations::ENEMIES)
@@ -587,13 +587,13 @@ void AIGateway::heroGotLevel(const CGHeroInstance * hero, PrimarySkill pskill, s
 	NET_EVENT_HANDLER;
 
 	status.addQuery(queryID, boost::str(boost::format("Hero %s got level %d") % hero->getNameTranslated() % hero->level));
-	HeroPtr hPtr = hero;
+	HeroPtr hPtr(hero);
 
 	executeActionAsync("heroGotLevel", [this, hPtr, skills, queryID]()
 	{
 		int sel = 0;
 
-		if(hPtr.validAndSet())
+		if(hPtr.isValid())
 		{
 			std::unique_lock lockGuard(nullkiller->aiStateMutex);
 
@@ -621,24 +621,24 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
 	status.addQuery(askID, boost::str(boost::format("Blocking dialog query with %d components - %s")
 									  % components.size() % text));
 
-	auto hero = nullkiller->getActiveHero();
+	auto heroPtr = nullkiller->getActiveHero();
 	auto target = nullkiller->getTargetTile();
 
 	if(!selection && cancel)
 	{
-		executeActionAsync("showBlockingDialog", [this, hero, target, askID]()
+		executeActionAsync("showBlockingDialog", [this, heroPtr, target, askID]()
 		{
 			//yes&no -> always answer yes, we are a brave AI :)
 			bool answer = true;
 			auto objects = cc->getVisitableObjs(target);
 
-			if(hero.validAndSet() && target.isValid() && objects.size())
+			if(heroPtr.isValid() && target.isValid() && objects.size())
 			{
-				auto topObj = objects.front()->id == hero->id ? objects.back() : objects.front();
+				auto topObj = objects.front()->id == heroPtr->id ? objects.back() : objects.front();
 				auto objType = topObj->ID; // top object should be our hero
 				auto goalObjectID = nullkiller->getTargetObject();
-				auto danger = nullkiller->dangerEvaluator->evaluateDanger(target, hero.get());
-				auto ratio = static_cast<float>(danger) / hero->getTotalStrength();
+				auto danger = nullkiller->dangerEvaluator->evaluateDanger(target, heroPtr.get(cc.get()));
+				auto ratio = static_cast<float>(danger) / heroPtr->getTotalStrength();
 
 				answer = true;
 
@@ -648,7 +648,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
 					answer = false;
 				}
 
-				logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), hero.name(), ratio);
+				logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), heroPtr.name(), ratio);
 
 				if(cc->getObj(goalObjectID, false))
 				{
@@ -674,7 +674,7 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
 		return;
 	}
 
-	executeActionAsync("showBlockingDialog", [this, selection, components, hero, askID]()
+	executeActionAsync("showBlockingDialog", [this, selection, components, heroPtr, askID]()
 	{
 		int sel = 0;
 
@@ -685,10 +685,10 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vector<C
 				std::unique_lock mxLock(nullkiller->aiStateMutex);
 
 				// TODO: Find better way to understand it is Chest of Treasures
-				if(hero.validAndSet()
+				if(heroPtr.isValid()
 					&& components.size() == 2
 					&& components.front().type == ComponentType::RESOURCE
-					&& (nullkiller->heroManager->getHeroRole(hero) != HeroRole::MAIN
+					&& (nullkiller->heroManager->getHeroRole(heroPtr) != HeroRole::MAIN
 						|| nullkiller->buildAnalyzer->isGoldPressureOverMax()))
 				{
 					sel = 1;
@@ -868,7 +868,7 @@ void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h
 	case Obj::TOWN:
 		if(h->getVisitedTown()) //we are inside, not just attacking
 		{
-			makePossibleUpgrades(h.get());
+			makePossibleUpgrades(h.get(cc.get()));
 
 			std::unique_lock lockGuard(nullkiller->aiStateMutex);
 
@@ -879,12 +879,12 @@ void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h
 				&& nullkiller->getFreeGold() >= GameConstants::SPELLBOOK_GOLD_COST)
 			{
 				if(h->getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
-					cc->buyArtifact(h.get(), ArtifactID::SPELLBOOK);
+					cc->buyArtifact(h.get(cc.get()), ArtifactID::SPELLBOOK);
 			}
 		}
 		break;
 	case Obj::HILL_FORT:
-		makePossibleUpgrades(h.get());
+		makePossibleUpgrades(h.get(cc.get()));
 		break;
 	}
 }
@@ -1085,12 +1085,12 @@ std::vector<const CGObjectInstance *> AIGateway::getFlaggedObjects() const
 	return ret;
 }
 
-bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
+bool AIGateway::moveHeroToTile(int3 dst, HeroPtr hPtr)
 {
-	if(h->isGarrisoned() && h->getVisitedTown())
+	if(hPtr->isGarrisoned() && hPtr->getVisitedTown())
 	{
-		cc->swapGarrisonHero(h->getVisitedTown());
-		moveCreaturesToHero(h->getVisitedTown());
+		cc->swapGarrisonHero(hPtr->getVisitedTown());
+		moveCreaturesToHero(hPtr->getVisitedTown());
 	}
 
 	//TODO: consider if blockVisit objects change something in our checks: AIUtility::isBlockVisitObj()
@@ -1098,9 +1098,9 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 	auto afterMovementCheck = [&]() -> void
 	{
 		waitTillFree(); //movement may cause battle or blocking dialog
-		if(!h)
+		if(!hPtr)
 		{
-			lostHero(h);
+			lostHero(hPtr);
 			teleportChannelProbingList.clear();
 			if(status.channelProbing()) // if hero lost during channel probing we need to switch this mode off
 				status.setChannelProbing(false);
@@ -1108,14 +1108,14 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 		}
 	};
 
-	logAi->debug("Moving hero %s to tile %s", h->getNameTranslated(), dst.toString());
-	int3 startHpos = h->visitablePos();
+	logAi->debug("Moving hero %s to tile %s", hPtr->getNameTranslated(), dst.toString());
+	int3 startHpos = hPtr->visitablePos();
 	bool ret = false;
 	if(startHpos == dst)
 	{
 		//FIXME: this assertion fails also if AI moves onto defeated guarded object
 		//assert(cb->getVisitableObjs(dst).size() > 1); //there's no point in revisiting tile where there is no visitable object
-		cc->moveHero(*h, h->convertFromVisitablePos(dst), false);
+		cc->moveHero(*hPtr, hPtr->convertFromVisitablePos(dst), false);
 		afterMovementCheck(); // TODO: is it feasible to hero get killed there if game work properly?
 		// If revisiting, teleport probing is never done, and so the entries into the list would remain unused and uncleared
 		teleportChannelProbingList.clear();
@@ -1125,10 +1125,10 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 	else
 	{
 		CGPath path;
-		nullkiller->getPathsInfo(h.get())->getPath(path, dst);
+		nullkiller->getPathsInfo(hPtr.get(cc.get()))->getPath(path, dst);
 		if(path.nodes.empty())
 		{
-			logAi->error("Hero %s cannot reach %s.", h->getNameTranslated(), dst.toString());
+			logAi->error("Hero %s cannot reach %s.", hPtr->getNameTranslated(), dst.toString());
 			return true;
 		}
 		int i = (int)path.nodes.size() - 1;
@@ -1168,20 +1168,20 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 
 		auto doMovement = [&](int3 dst, bool transit)
 		{
-			cc->moveHero(*h, h->convertFromVisitablePos(dst), transit);
+			cc->moveHero(*hPtr, hPtr->convertFromVisitablePos(dst), transit);
 		};
 
 		auto doTeleportMovement = [&](ObjectInstanceID exitId, int3 exitPos)
 		{
 			if(cc->getObj(exitId) && cc->getObj(exitId)->ID == Obj::WHIRLPOOL)
 			{
-				nullkiller->armyFormation->rearrangeArmyForWhirlpool(*h);
+				nullkiller->armyFormation->rearrangeArmyForWhirlpool(*hPtr);
 			}
 
 			destinationTeleport = exitId;
 			if(exitPos.isValid())
 				destinationTeleportPos = exitPos;
-			cc->moveHero(*h, h->pos, false);
+			cc->moveHero(*hPtr, hPtr->pos, false);
 			destinationTeleport = ObjectInstanceID();
 			destinationTeleportPos = int3(-1);
 			afterMovementCheck();
@@ -1189,7 +1189,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 
 		auto doChannelProbing = [&]() -> void
 		{
-			auto currentPos = h->visitablePos();
+			auto currentPos = hPtr->visitablePos();
 			auto currentTeleport = getObj(currentPos, true);
 
 			if(currentTeleport)
@@ -1222,7 +1222,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 			int3 currentCoord = path.nodes[i].coord;
 			int3 nextCoord = path.nodes[i - 1].coord;
 
-			auto currentObject = getObj(currentCoord, currentCoord == h->visitablePos());
+			auto currentObject = getObj(currentCoord, currentCoord == hPtr->visitablePos());
 			auto nextObjectTop = getObj(nextCoord, false);
 			auto nextObject = getObj(nextCoord, true);
 			auto destTeleportObj = getDestTeleportObj(currentObject, nextObjectTop, nextObject);
@@ -1245,7 +1245,7 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 			}
 
 			int3 endpos = path.nodes[i - 1].coord;
-			if(endpos == h->visitablePos())
+			if(endpos == hPtr->visitablePos())
 				continue;
 
 			bool isConnected = false;
@@ -1280,30 +1280,30 @@ bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 		{
 			// when we take resource we do not reach its position. We even might not move
 			// also guarded town is not get visited automatically after capturing
-			ret = h && i == 0;
+			ret = hPtr && i == 0;
 		}
 	}
-	if(h)
+	if(hPtr)
 	{
-		if(auto visitedObject = vstd::frontOrNull(cc->getVisitableObjs(h->visitablePos()))) //we stand on something interesting
+		if(auto visitedObject = vstd::frontOrNull(cc->getVisitableObjs(hPtr->visitablePos()))) //we stand on something interesting
 		{
-			if(visitedObject != *h)
+			if(visitedObject != *hPtr)
 			{
-				performObjectInteraction(visitedObject, h);
+				performObjectInteraction(visitedObject, hPtr);
 				ret = true;
 			}
 		}
 	}
-	if(h) //we could have lost hero after last move
+	if(hPtr) //we could have lost hero after last move
 	{
-		ret = ret || (dst == h->visitablePos());
+		ret = ret || (dst == hPtr->visitablePos());
 
-		if(startHpos == h->visitablePos() && !ret) //we didn't move and didn't reach the target
+		if(startHpos == hPtr->visitablePos() && !ret) //we didn't move and didn't reach the target
 		{
 			throw cannotFulfillGoalException("Invalid path found!");
 		}
 
-		logAi->debug("Hero %s moved from %s to %s. Returning %d.", h->getNameTranslated(), startHpos.toString(), h->visitablePos().toString(), ret);
+		logAi->debug("Hero %s moved from %s to %s. Returning %d.", hPtr->getNameTranslated(), startHpos.toString(), hPtr->visitablePos().toString(), ret);
 	}
 	return ret;
 }

+ 1 - 1
AI/Nullkiller2/AIGateway.h

@@ -204,7 +204,7 @@ public:
 	void performObjectInteraction(const CGObjectInstance * obj, HeroPtr h);
 	bool makePossibleUpgrades(const CArmedInstance * obj);
 
-	bool moveHeroToTile(int3 dst, HeroPtr h);
+	bool moveHeroToTile(int3 dst, HeroPtr hPtr);
 	void buildStructure(const CGTownInstance * t, BuildingID building);
 
 	void lostHero(HeroPtr h); //should remove all references to hero (assigned tasks and so on)

+ 32 - 33
AI/Nullkiller2/AIUtility.cpp

@@ -69,15 +69,15 @@ HeroPtr::HeroPtr(const CGHeroInstance * H)
 		return;
 	}
 
-	h = H;
-	hid = H->id;
+	hero = H;
+	heroId = H->id;
 //	infosCount[ai->playerID][hid]++;
 }
 
 HeroPtr::HeroPtr()
 {
-	h = nullptr;
-	hid = ObjectInstanceID();
+	hero = nullptr;
+	heroId = ObjectInstanceID();
 }
 
 HeroPtr::~HeroPtr()
@@ -88,32 +88,27 @@ HeroPtr::~HeroPtr()
 
 bool HeroPtr::operator<(const HeroPtr & rhs) const
 {
-	return hid < rhs.hid;
+	return heroId < rhs.heroId;
 }
 
 std::string HeroPtr::name() const
 {
-	if (h)
-		return h->getNameTextID();
+	if (hero)
+		return hero->getNameTextID();
 	else
 		return "<NO HERO>";
 }
 
-const CGHeroInstance * HeroPtr::get(bool doWeExpectNull) const
-{
-	return get(ccTl, doWeExpectNull);
-}
-
-const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cb, bool doWeExpectNull) const
+const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cpsic, bool doWeExpectNull) const
 {
 	//TODO? check if these all assertions every time we get info about hero affect efficiency
 	//
 	//behave terribly when attempting unauthorized access to hero that is not ours (or was lost)
-	assert(doWeExpectNull || h);
+	assert(doWeExpectNull || hero);
 
-	if(h)
+	if(hero)
 	{
-		auto obj = cb->getObj(hid);
+		const auto *obj = cpsic->getObj(heroId);
 		//const bool owned = obj && obj->tempOwner == ai->playerID;
 
 		if(doWeExpectNull && !obj)
@@ -127,27 +122,31 @@ const CGHeroInstance * HeroPtr::get(const CPlayerSpecificInfoCallback * cb, bool
 		}
 	}
 
-	return h;
+	return hero;
 }
 
 const CGHeroInstance * HeroPtr::operator->() const
 {
-	return get();
+	// return get();
+	return nullptr;
 }
 
-bool HeroPtr::validAndSet() const
+bool HeroPtr::isValid() const
 {
-	return get(true);
+	// return get(true);
+	return false;
 }
 
 const CGHeroInstance * HeroPtr::operator*() const
 {
-	return get();
+	// return get();
+	return nullptr;
 }
 
 bool HeroPtr::operator==(const HeroPtr & rhs) const
 {
-	return h == rhs.get(true);
+	// return hero == rhs.get(true);
+	return false;
 }
 
 bool isSafeToVisit(const CGHeroInstance * h, const CCreatureSet * heroArmy, uint64_t dangerStrength, float safeAttackRatio)
@@ -644,9 +643,9 @@ int getDuplicatingSlots(const CArmedInstance * army)
 }
 
 // todo: move to obj manager
-bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObjectInstance * obj)
+bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * hero, const CGObjectInstance * obj)
 {
-	auto relations = aiNk->cc->getPlayerRelations(obj->tempOwner, h->tempOwner);
+	auto relations = aiNk->cc->getPlayerRelations(obj->tempOwner, hero->tempOwner);
 
 	switch(obj->ID)
 	{
@@ -673,7 +672,7 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 		{
 			if(q.obj == obj->id)
 			{
-				if(q.getQuest(aiNk->cc.get())->checkQuest(h))
+				if(q.getQuest(aiNk->cc.get())->checkQuest(hero))
 					return true; //we completed the quest
 				else
 					return false; //we can't complete this quest
@@ -690,14 +689,14 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 			return false;
 
 		const CGDwelling * d = dynamic_cast<const CGDwelling *>(obj);
-		auto duplicatingSlotsCount = getDuplicatingSlots(h);
+		auto duplicatingSlotsCount = getDuplicatingSlots(hero);
 
 		for(auto level : d->creatures)
 		{
 			for(auto c : level.second)
 			{
 				if(level.first
-					&& (h->getSlotFor(CreatureID(c)) != SlotID() || duplicatingSlotsCount > 0)
+					&& (hero->getSlotFor(CreatureID(c)) != SlotID() || duplicatingSlotsCount > 0)
 					&& aiNk->cc->getResourceAmount().canAfford(c.toCreature()->getFullRecruitCost()))
 				{
 					return true;
@@ -709,7 +708,7 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 	}
 	case Obj::HILL_FORT:
 	{
-		for(const auto & slot : h->Slots())
+		for(const auto & slot : hero->Slots())
 		{
 			if(slot.second->getType()->hasUpgrades())
 				return true; //TODO: check price?
@@ -729,12 +728,12 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 		break;
 	}
 	case Obj::LIBRARY_OF_ENLIGHTENMENT:
-		if(h->level < 10)
+		if(hero->level < 10)
 			return false;
 		break;
 	case Obj::TREE_OF_KNOWLEDGE:
 	{
-		if(aiNk->heroManager->getHeroRole(h) == HeroRole::SCOUT)
+		if(aiNk->heroManager->getHeroRole(HeroPtr(hero)) == HeroRole::SCOUT)
 			return false;
 
 		TResources myRes = aiNk->getFreeResources();
@@ -743,7 +742,7 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 		break;
 	}
 	case Obj::MAGIC_WELL:
-		return h->mana < h->manaLimit();
+		return hero->mana < hero->manaLimit();
 	case Obj::PRISON:
 		return !aiNk->heroManager->heroCapReached();
 	case Obj::TAVERN:
@@ -753,12 +752,12 @@ bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObje
 		return false;
 	}
 
-	if(obj->wasVisited(h))
+	if(obj->wasVisited(hero))
 		return false;
 
 	auto rewardable = dynamic_cast<const Rewardable::Interface *>(obj);
 
-	if(rewardable && rewardable->getAvailableRewards(h, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
+	if(rewardable && rewardable->getAvailableRewards(hero, Rewardable::EEventType::EVENT_FIRST_VISIT).empty())
 	{
 		return false;
 	}

+ 9 - 10
AI/Nullkiller2/AIUtility.h

@@ -76,19 +76,19 @@ enum HeroRole
 
 struct DLL_EXPORT HeroPtr
 {
-	const CGHeroInstance * h;
-	ObjectInstanceID hid;
+	const CGHeroInstance * hero;
+	ObjectInstanceID heroId;
 
 public:
 	std::string name() const;
 
-	HeroPtr();
-	HeroPtr(const CGHeroInstance * H);
+	explicit HeroPtr();
+	explicit HeroPtr(const CGHeroInstance * H);
 	~HeroPtr();
 
-	operator bool() const
+	explicit operator bool() const
 	{
-		return validAndSet();
+		return isValid();
 	}
 
 	bool operator<(const HeroPtr & rhs) const;
@@ -100,9 +100,8 @@ public:
 		return !(*this == rhs);
 	}
 
-	const CGHeroInstance * get(bool doWeExpectNull = false) const;
-	const CGHeroInstance * get(const CPlayerSpecificInfoCallback * cb, bool doWeExpectNull = false) const;
-	bool validAndSet() const;
+	const CGHeroInstance * get(const CPlayerSpecificInfoCallback * cpsic, bool doWeExpectNull = false) const;
+	bool isValid() const;
 };
 
 enum BattleState
@@ -222,7 +221,7 @@ uint64_t getHeroArmyStrengthWithCommander(const CGHeroInstance * hero, const CCr
 uint64_t timeElapsed(std::chrono::time_point<std::chrono::high_resolution_clock> start);
 
 // todo: move to obj manager
-bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * h, const CGObjectInstance * obj);
+bool shouldVisit(const Nullkiller * aiNk, const CGHeroInstance * hero, const CGObjectInstance * obj);
 int getDuplicatingSlots(const CArmedInstance * army);
 
 template <class T>

+ 6 - 6
AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.cpp

@@ -35,10 +35,10 @@ void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data)
 					auto & threat = data.getTileThreat(pos).maximumDanger;
 					b.addText(pos, std::to_string(threat.danger));
 
-					if(threat.hero.validAndSet())
+					if(threat.heroPtr.isValid())
 					{
 						b.addText(pos, std::to_string(threat.turn));
-						b.addText(pos, threat.hero->getNameTranslated());
+						b.addText(pos, threat.heroPtr->getNameTranslated());
 					}
 				});
 		});
@@ -50,10 +50,10 @@ void logHitmap(PlayerColor playerID, DangerHitMapAnalyzer & data)
 					auto & threat = data.getTileThreat(pos).fastestDanger;
 					b.addText(pos, std::to_string(threat.danger));
 
-					if(threat.hero.validAndSet())
+					if(threat.heroPtr.isValid())
 					{
 						b.addText(pos, std::to_string(threat.turn));
-						b.addText(pos, threat.hero->getNameTranslated());
+						b.addText(pos, threat.heroPtr->getNameTranslated());
 					}
 				});
 		});
@@ -137,7 +137,7 @@ void DangerHitMapAnalyzer::updateHitMap()
 
 				HitMapInfo newThreat;
 
-				newThreat.hero = path.targetHero;
+				newThreat.heroPtr = HeroPtr(path.targetHero);
 				newThreat.turn = path.turn();
 				newThreat.threat = path.getHeroStrength() * (1 - path.movementCost() / 2.0);
 				// TODO: Mircea: Why is this danger calculated so differently than FuzzyHelper::evaluateDanger?
@@ -167,7 +167,7 @@ void DangerHitMapAnalyzer::updateHitMap()
 						auto & threats = townThreats[obj->id];
 						auto threat = std::find_if(threats.begin(), threats.end(), [&](const HitMapInfo & i) -> bool
 							{
-								return i.hero.hid == path.targetHero->id;
+								return i.heroPtr.heroId == path.targetHero->id;
 							});
 
 						if(threat == threats.end())

+ 2 - 2
AI/Nullkiller2/Analyzers/DangerHitMapAnalyzer.h

@@ -23,7 +23,7 @@ struct HitMapInfo
 	uint64_t danger;
 	uint8_t turn;
 	float threat;
-	HeroPtr hero;
+	HeroPtr heroPtr;
 
 	HitMapInfo()
 	{
@@ -35,7 +35,7 @@ struct HitMapInfo
 		danger = 0;
 		turn = 255;
 		threat = 0;
-		hero = HeroPtr();
+		heroPtr = HeroPtr();
 	}
 
 	double value() const;

+ 9 - 9
AI/Nullkiller2/Analyzers/HeroManager.cpp

@@ -62,7 +62,7 @@ const SecondarySkillEvaluator HeroManager::scountSkillsScores = SecondarySkillEv
 
 float HeroManager::evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const
 {
-	auto role = getHeroRole(hero);
+	auto role = getHeroRole(HeroPtr(hero));
 
 	if(role == HeroRole::MAIN)
 		return wariorSkillsScores.evaluateSecSkill(hero, skill);
@@ -134,24 +134,24 @@ void HeroManager::update()
 	{
 		if(hero->patrol.patrolling)
 		{
-			heroToRoleMap[hero] = HeroRole::MAIN;
+			heroToRoleMap[HeroPtr(hero)] = HeroRole::MAIN;
 		}
 		else
 		{
-			heroToRoleMap[hero] = (globalMainCount--) > 0 ? HeroRole::MAIN : HeroRole::SCOUT;
+			heroToRoleMap[HeroPtr(hero)] = (globalMainCount--) > 0 ? HeroRole::MAIN : HeroRole::SCOUT;
 		}
 	}
 
 	for(auto hero : myHeroes)
 	{
-		logAi->trace("Hero %s has role %s", hero->getNameTranslated(), heroToRoleMap[hero] == HeroRole::MAIN ? "main" : "scout");
+		logAi->trace("Hero %s has role %s", hero->getNameTranslated(), heroToRoleMap[HeroPtr(hero)] == HeroRole::MAIN ? "main" : "scout");
 	}
 }
 
-HeroRole HeroManager::getHeroRole(const HeroPtr & hero) const
+HeroRole HeroManager::getHeroRole(const HeroPtr & hPtr) const
 {
-	if (heroToRoleMap.find(hero) != heroToRoleMap.end())
-		return heroToRoleMap.at(hero);
+	if (heroToRoleMap.find(hPtr) != heroToRoleMap.end())
+		return heroToRoleMap.at(hPtr);
 	else
 		return HeroRole::SCOUT;
 }
@@ -171,7 +171,7 @@ int HeroManager::selectBestSkill(const HeroPtr & hero, const std::vector<Seconda
 
 	for(int i = 0; i < skills.size(); i++)
 	{
-		auto score = evaluator.evaluateSecSkill(hero.get(), skills[i]);
+		auto score = evaluator.evaluateSecSkill(hero.get(aiNk->cc.get()), skills[i]);
 
 		if(score > resultScore)
 		{
@@ -302,7 +302,7 @@ const CGHeroInstance * HeroManager::findWeakHeroToDismiss(uint64_t armyLimit, co
 	{
 		if(aiNk->getHeroLockedReason(existingHero) == HeroLockedReason::DEFENCE
 			|| existingHero->getArmyStrength() >armyLimit
-			|| getHeroRole(existingHero) == HeroRole::MAIN
+			|| getHeroRole(HeroPtr(existingHero)) == HeroRole::MAIN
 			|| existingHero->movementPointsRemaining()
 			|| (townToSpare != nullptr && existingHero->getVisitedTown() == townToSpare)
 			|| existingHero->artifactsWorn.size() > (existingHero->hasSpellbook() ? 2 : 1))

+ 1 - 1
AI/Nullkiller2/Analyzers/HeroManager.h

@@ -50,7 +50,7 @@ private:
 public:
 	HeroManager(CCallback * cc, const Nullkiller * aiNk) : cc(cc), aiNk(aiNk) {}
 	const std::map<HeroPtr, HeroRole> & getHeroToRoleMap() const;
-	HeroRole getHeroRole(const HeroPtr & hero) const;
+	HeroRole getHeroRole(const HeroPtr & hPtr) const;
 	int selectBestSkill(const HeroPtr & hero, const std::vector<SecondarySkill> & skills) const;
 	void update();
 	float evaluateSecSkill(SecondarySkill skill, const CGHeroInstance * hero) const;

+ 1 - 1
AI/Nullkiller2/Analyzers/ObjectClusterizer.cpp

@@ -427,7 +427,7 @@ void ObjectClusterizer::clusterizeObject(
 		logAi->trace("ObjectClusterizer Checking path %s", path.toString());
 #endif
 
-		if(aiNk->heroManager->getHeroRole(path.targetHero) == HeroRole::SCOUT)
+		if(aiNk->heroManager->getHeroRole(HeroPtr(path.targetHero)) == HeroRole::SCOUT)
 		{
 			// TODO: Mircea: Shouldn't this be linked with scoutHeroTurnDistanceLimit?
 			// TODO: Mircea: Move to constant

+ 1 - 1
AI/Nullkiller2/Behaviors/BuyArmyBehavior.cpp

@@ -53,7 +53,7 @@ Goals::TGoalVec BuyArmyBehavior::decompose(const Nullkiller * aiNk) const
 
 		for(const CGHeroInstance * targetHero : heroes)
 		{
-			if(aiNk->heroManager->getHeroRole(targetHero) == HeroRole::MAIN)
+			if(aiNk->heroManager->getHeroRole(HeroPtr(targetHero)) == HeroRole::MAIN)
 			{
 				auto reinforcement = aiNk->armyManager->howManyReinforcementsCanGet(
 					targetHero,

+ 3 - 3
AI/Nullkiller2/Behaviors/CaptureObjectsBehavior.cpp

@@ -82,7 +82,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(
 		if (hero->getOwner() != nullkiller->playerID)
 			continue;
 
-		if(nullkiller->heroManager->getHeroRole(hero) == HeroRole::SCOUT
+		if(nullkiller->heroManager->getHeroRole(HeroPtr(hero)) == HeroRole::SCOUT
 			&& (path.getTotalDanger() == 0 || path.turn() > 0)
 			&& path.exchangeCount > 1)
 		{
@@ -135,7 +135,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(
 
 			sharedPtr.reset(newWay);
 
-			auto heroRole = nullkiller->heroManager->getHeroRole(path.targetHero);
+			auto heroRole = nullkiller->heroManager->getHeroRole(HeroPtr(path.targetHero));
 
 			auto & closestWay = closestWaysByRole[heroRole];
 
@@ -154,7 +154,7 @@ Goals::TGoalVec CaptureObjectsBehavior::getVisitGoals(
 
 	for(auto way : waysToVisitObj)
 	{
-		auto heroRole = nullkiller->heroManager->getHeroRole(way->getPath().targetHero);
+		auto heroRole = nullkiller->heroManager->getHeroRole(HeroPtr(way->getPath().targetHero));
 		auto closestWay = closestWaysByRole[heroRole];
 
 		if(closestWay)

+ 6 - 6
AI/Nullkiller2/Behaviors/DefenceBehavior.cpp

@@ -84,12 +84,12 @@ void handleCounterAttack(
 	const Nullkiller * aiNk,
 	Goals::TGoalVec & tasks)
 {
-	if(threat.hero.validAndSet()
+	if(threat.heroPtr.isValid()
 		&& threat.turn <= 1
 		&& (threat.danger == maximumDanger.danger || threat.turn < maximumDanger.turn))
 	{
-		auto heroCapturingPaths = aiNk->pathfinder->getPathInfo(threat.hero->visitablePos());
-		auto goals = CaptureObjectsBehavior::getVisitGoals(heroCapturingPaths, aiNk, threat.hero.get());
+		auto heroCapturingPaths = aiNk->pathfinder->getPathInfo(threat.heroPtr->visitablePos());
+		auto goals = CaptureObjectsBehavior::getVisitGoals(heroCapturingPaths, aiNk, threat.heroPtr.get(aiNk->cc.get()));
 
 		for(int i = 0; i < heroCapturingPaths.size(); i++)
 		{
@@ -132,7 +132,7 @@ bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoa
 
 			return false;
 		}
-		else if(aiNk->heroManager->getHeroRole(town->getGarrisonHero()) == HeroRole::MAIN)
+		else if(aiNk->heroManager->getHeroRole(HeroPtr(town->getGarrisonHero())) == HeroRole::MAIN)
 		{
 			auto armyDismissLimit = 1000;
 			auto heroToDismiss = aiNk->heroManager->findWeakHeroToDismiss(armyDismissLimit);
@@ -164,7 +164,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 	{
 		return;
 	}
-	if(!threatNode.fastestDanger.hero)
+	if(!threatNode.fastestDanger.heroPtr)
 	{
 #if NK2AI_TRACE_LEVEL >= 1
 		logAi->trace("No threat found for town %s", town->getNameTranslated());
@@ -192,7 +192,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 			town->getNameTranslated(),
 			threat.danger,
 			std::to_string(threat.turn),
-			threat.hero ? threat.hero->getNameTranslated() : std::string("<no hero>"));
+			threat.heroPtr ? threat.heroPtr->getNameTranslated() : std::string("<no hero>"));
 #endif
 		handleCounterAttack(town, threat, threatNode.maximumDanger, aiNk, tasks);
 

+ 4 - 4
AI/Nullkiller2/Behaviors/GatherArmyBehavior.cpp

@@ -43,7 +43,7 @@ Goals::TGoalVec GatherArmyBehavior::decompose(const Nullkiller * aiNk) const
 
 	for(const CGHeroInstance * hero : heroes)
 	{
-		if(aiNk->heroManager->getHeroRole(hero) == HeroRole::MAIN)
+		if(aiNk->heroManager->getHeroRole(HeroPtr(hero)) == HeroRole::MAIN)
 		{
 			vstd::concatenate(tasks, deliverArmyToHero(aiNk, hero));
 		}
@@ -121,7 +121,7 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const Nullkiller * aiNk, c
 		{
 			if(!node.targetHero) continue;
 
-			auto heroRole = aiNk->heroManager->getHeroRole(node.targetHero);
+			auto heroRole = aiNk->heroManager->getHeroRole(HeroPtr(node.targetHero));
 
 			if(heroRole == HeroRole::MAIN)
 			{
@@ -239,7 +239,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * aiNk, const C
 
 	for(const AIPath & path : paths)
 	{
-		auto heroRole = aiNk->heroManager->getHeroRole(path.targetHero);
+		auto heroRole = aiNk->heroManager->getHeroRole(HeroPtr(path.targetHero));
 
 		if(heroRole == HeroRole::MAIN && path.turn() < aiNk->settings->getScoutHeroTurnDistanceLimit())
 			hasMainAround = true;
@@ -290,7 +290,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * aiNk, const C
 		auto upgrade = aiNk->armyManager->calculateCreaturesUpgrade(path.heroArmy, upgrader, availableResources);
 
 		if(!upgrader->getGarrisonHero()
-		   && (hasMainAround || aiNk->heroManager->getHeroRole(path.targetHero) == HeroRole::MAIN))
+		   && (hasMainAround || aiNk->heroManager->getHeroRole(HeroPtr(path.targetHero)) == HeroRole::MAIN))
 		{
 			ArmyUpgradeInfo armyToGetOrBuy;
 

+ 1 - 1
AI/Nullkiller2/Behaviors/RecruitHeroBehavior.cpp

@@ -52,7 +52,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * aiNk) const
 		float visitabilityRatio = 0;
 		for(const auto & [hero, role] : ourHeroes)
 		{
-			if(aiNk->dangerHitMap->getClosestTown(hero.get()->visitablePos()) == town)
+			if(aiNk->dangerHitMap->getClosestTown(hero.get(aiNk->cc.get())->visitablePos()) == town)
 				visitabilityRatio += 1.0f / ourHeroes.size();
 		}
 

+ 1 - 1
AI/Nullkiller2/Behaviors/StartupBehavior.cpp

@@ -172,7 +172,7 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * aiNk) const
 				auto garrisonHeroScore = aiNk->heroManager->evaluateHero(garrisonHero);
 
 				if(visitingHeroScore > garrisonHeroScore
-					|| (aiNk->heroManager->getHeroRole(garrisonHero) == HeroRole::SCOUT && aiNk->heroManager->getHeroRole(visitingHero) == HeroRole::MAIN))
+					|| (aiNk->heroManager->getHeroRole(HeroPtr(garrisonHero)) == HeroRole::SCOUT && aiNk->heroManager->getHeroRole(HeroPtr(visitingHero)) == HeroRole::MAIN))
 				{
 					if(canRecruitHero || aiNk->armyManager->howManyReinforcementsCanGet(visitingHero, garrisonHero) > 200)
 					{

+ 4 - 4
AI/Nullkiller2/Engine/Nullkiller.cpp

@@ -281,7 +281,7 @@ void Nullkiller::updateState()
 			if(getHeroLockedReason(hero) == HeroLockedReason::DEFENCE)
 				continue;
 
-			activeHeroes[hero] = heroManager->getHeroRole(hero);
+			activeHeroes[hero] = heroManager->getHeroRole(HeroPtr(hero));
 		}
 
 		PathfinderSettings cfg;
@@ -549,11 +549,11 @@ bool Nullkiller::areAffectedObjectsPresent(Goals::TTask task) const
 
 HeroRole Nullkiller::getTaskRole(Goals::TTask task) const
 {
-	HeroPtr hero = task->getHero();
+	HeroPtr heroPtr(task->getHero());
 	HeroRole heroRole = HeroRole::MAIN;
 
-	if(hero.validAndSet())
-		heroRole = heroManager->getHeroRole(hero);
+	if(heroPtr.isValid())
+		heroRole = heroManager->getHeroRole(heroPtr);
 
 	return heroRole;
 }

+ 1 - 1
AI/Nullkiller2/Engine/Nullkiller.h

@@ -119,7 +119,7 @@ public:
 	bool makeTurnHelperPriorityPass(Goals::TGoalVec& tempResults, int passIndex);
 	bool isActive(const CGHeroInstance * hero) const { return activeHero == hero; }
 	bool isHeroLocked(const CGHeroInstance * hero) const;
-	HeroPtr getActiveHero() { return activeHero; }
+	HeroPtr getActiveHero() { return HeroPtr(activeHero); }
 	HeroLockedReason getHeroLockedReason(const CGHeroInstance * hero) const;
 	int3 getTargetTile() const { return targetTile; }
 	ObjectInstanceID getTargetObject() const { return targetObject; }

+ 7 - 7
AI/Nullkiller2/Engine/PriorityEvaluator.cpp

@@ -778,7 +778,7 @@ public:
 
 		evaluationContext.addNonCriticalStrategicalValue(2.0f * armyStrength / (float)heroExchange.hero->getArmyStrength());
 		evaluationContext.conquestValue += 2.0f * armyStrength / (float)heroExchange.hero->getArmyStrength();
-		evaluationContext.heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(heroExchange.hero);
+		evaluationContext.heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(HeroPtr(heroExchange.hero));
 		evaluationContext.isExchange = true;
 	}
 };
@@ -898,7 +898,7 @@ public:
 		if(defendTown.getTurn() > 0 && defendTown.isCounterAttack())
 		{
 			auto ourSpeed = defendTown.hero->movementPointsLimit(true);
-			auto enemySpeed = threat.hero.get(evaluationContext.evaluator.aiNk->cc.get())->movementPointsLimit(true);
+			auto enemySpeed = threat.heroPtr.get(evaluationContext.evaluator.aiNk->cc.get())->movementPointsLimit(true);
 
 			if(enemySpeed > ourSpeed) multiplier *= 0.7f;
 		}
@@ -958,7 +958,7 @@ public:
 		float highestCostForSingleHero = 0;
 		for(auto pair : costsPerHero)
 		{
-			auto role = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(pair.first);
+			auto role = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(HeroPtr(pair.first));
 			evaluationContext.movementCostByRole[role] += pair.second;
 			if (pair.second > highestCostForSingleHero)
 				highestCostForSingleHero = pair.second;
@@ -975,7 +975,7 @@ public:
 		auto army = path.heroArmy;
 
 		const CGObjectInstance * target = aiNk->cc->getObj((ObjectInstanceID)task->objid, false);
-		auto heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(hero);
+		auto heroRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(HeroPtr(hero));
 
 		if(heroRole == HeroRole::MAIN)
 			evaluationContext.heroRole = heroRole;
@@ -1056,7 +1056,7 @@ public:
 		std::shared_ptr<ObjectCluster> cluster = clusterGoal.getCluster();
 
 		auto hero = clusterGoal.hero;
-		auto role = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(hero);
+		auto role = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(HeroPtr(hero));
 
 		std::vector<std::pair<ObjectInstanceID, ClusterObjectInfo>> objects(cluster->objects.begin(), cluster->objects.end());
 
@@ -1113,7 +1113,7 @@ public:
 
 		if(garrisonHero && swapCommand.getLockingReason() == HeroLockedReason::DEFENCE)
 		{
-			auto defenderRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(garrisonHero);
+			auto defenderRole = evaluationContext.evaluator.aiNk->heroManager->getHeroRole(HeroPtr(garrisonHero));
 			auto mpLeft = garrisonHero->movementPointsRemaining() / (float)garrisonHero->movementPointsLimit(true);
 
 			evaluationContext.movementCost += mpLeft;
@@ -1142,7 +1142,7 @@ public:
 		Goals::DismissHero & dismissCommand = dynamic_cast<Goals::DismissHero &>(*task);
 		const CGHeroInstance * dismissedHero = dismissCommand.getHero();
 
-		auto role = aiNk->heroManager->getHeroRole(dismissedHero);
+		auto role = aiNk->heroManager->getHeroRole(HeroPtr(dismissedHero));
 		auto mpLeft = dismissedHero->movementPointsRemaining();
 
 		evaluationContext.movementCost += mpLeft;

+ 1 - 1
AI/Nullkiller2/Goals/AdventureSpellCast.cpp

@@ -67,7 +67,7 @@ void AdventureSpellCast::accept(AIGateway * aiGw)
 	if(town && townPortalEffect)
 	{
 		// visit town
-		aiGw->moveHeroToTile(town->visitablePos(), hero);
+		aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(hero));
 	}
 
 	ccTl->waitTillRealize = wait;

+ 1 - 1
AI/Nullkiller2/Goals/BuyArmy.cpp

@@ -99,7 +99,7 @@ void BuyArmy::accept(AIGateway * aiGw)
 
 	if(town->getVisitingHero() && !town->getGarrisonHero())
 	{
-		aiGw->moveHeroToTile(town->visitablePos(), town->getVisitingHero());
+		aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(town->getVisitingHero()));
 	}
 }
 

+ 1 - 1
AI/Nullkiller2/Goals/ExchangeSwapTownHeroes.cpp

@@ -84,7 +84,7 @@ void ExchangeSwapTownHeroes::accept(AIGateway * aiGw)
 		ccTl->swapGarrisonHero(town);
 
 	aiGw->makePossibleUpgrades(town);
-	aiGw->moveHeroToTile(town->visitablePos(), getGarrisonHero());
+	aiGw->moveHeroToTile(town->visitablePos(), HeroPtr(getGarrisonHero()));
 
 	auto upperArmy = town->getUpperArmy();
 	

+ 6 - 6
AI/Nullkiller2/Goals/ExecuteHeroChain.cpp

@@ -109,9 +109,9 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
 		auto  * node = &chainPath.nodes[i];
 
 		const CGHeroInstance * hero = node->targetHero;
-		HeroPtr heroPtr = hero;
+		HeroPtr heroPtr(hero);
 
-		if(!heroPtr.validAndSet())
+		if(!heroPtr.isValid())
 		{
 			logAi->error("Hero %s was lost. Exit hero chain.", heroPtr.name());
 
@@ -148,7 +148,7 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
 					
 					node->specialAction->execute(aiGw, hero);
 					
-					if(!heroPtr.validAndSet())
+					if(!heroPtr.isValid())
 					{
 						logAi->error("Hero %s was lost trying to execute special action. Exit hero chain.", heroPtr.name());
 
@@ -229,7 +229,7 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
 					}
 					catch(const cannotFulfillGoalException &)
 					{
-						if(!heroPtr.validAndSet())
+						if(!heroPtr.isValid())
 						{
 							logAi->error("Hero %s was lost. Exit hero chain.", heroPtr.name());
 
@@ -275,7 +275,7 @@ void ExecuteHeroChain::accept(AIGateway * aiGw)
 		}
 		catch(const goalFulfilledException &)
 		{
-			if(!heroPtr.validAndSet())
+			if(!heroPtr.isValid())
 			{
 				logAi->debug("Hero %s was killed while attempting to reach %s", heroPtr.name(), node->coord.toString());
 
@@ -303,7 +303,7 @@ bool ExecuteHeroChain::moveHeroToTile(AIGateway * aiGw, const CGHeroInstance * h
 		return true;
 	}
 
-	return aiGw->moveHeroToTile(tile, hero);
+	return aiGw->moveHeroToTile(tile, HeroPtr(hero));
 }
 
 }

+ 1 - 1
AI/Nullkiller2/Goals/ExploreNeighbourTile.cpp

@@ -61,7 +61,7 @@ void ExploreNeighbourTile::accept(AIGateway * aiGw)
 
 		auto danger = aiGw->nullkiller->dangerEvaluator->evaluateDanger(target, hero, true);
 
-		if(danger > 0 || !aiGw->moveHeroToTile(target, hero))
+		if(danger > 0 || !aiGw->moveHeroToTile(target, HeroPtr(hero)))
 		{
 			return;
 		}

+ 2 - 2
AI/Nullkiller2/Helpers/ExplorationHelper.cpp

@@ -144,7 +144,7 @@ void ExplorationHelper::scanTile(const int3 & tile)
 {
 	if(tile == ourPos
 		|| !aiNk->cc->getTile(tile, false)
-		|| !aiNk->pathfinder->isTileAccessible(hero, tile)) //shouldn't happen, but it does
+		|| !aiNk->pathfinder->isTileAccessible(HeroPtr(hero), tile)) //shouldn't happen, but it does
 		return;
 
 	int tilesDiscovered = howManyTilesWillBeDiscovered(tile);
@@ -224,7 +224,7 @@ bool ExplorationHelper::hasReachableNeighbor(const int3 & pos) const
 		{
 			auto isAccessible = useCPathfinderAccessibility
 				? aiNk->getPathsInfo(hero)->getPathInfo(tile)->reachable()
-				: aiNk->pathfinder->isTileAccessible(hero, tile);
+				: aiNk->pathfinder->isTileAccessible(HeroPtr(hero), tile);
 
 			if(isAccessible)
 				return true;

+ 1 - 1
AI/Nullkiller2/Pathfinding/AINodeStorage.cpp

@@ -1406,7 +1406,7 @@ bool AINodeStorage::isTileAccessible(const HeroPtr & hero, const int3 & pos, con
 			&& node.layer == layer
 			&& node.action != EPathNodeAction::UNKNOWN 
 			&& node.actor
-			&& node.actor->hero == hero.h)
+			&& node.actor->hero == hero.hero)
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller2/Pathfinding/Actions/BattleAction.cpp

@@ -20,7 +20,7 @@ namespace AIPathfinding
 {
 	void BattleAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const
 	{
-		aiGw->moveHeroToTile(targetTile, hero);
+		aiGw->moveHeroToTile(targetTile, HeroPtr(hero));
 	}
 
 	std::string BattleAction::toString() const

+ 1 - 1
AI/Nullkiller2/Pathfinding/Actions/QuestAction.cpp

@@ -52,7 +52,7 @@ namespace AIPathfinding
 
 	void QuestAction::execute(AIGateway * aiGw, const CGHeroInstance * hero) const
 	{
-		aiGw->moveHeroToTile(questInfo.getObject(aiGw->cc.get())->visitablePos(), hero);
+		aiGw->moveHeroToTile(questInfo.getObject(aiGw->cc.get())->visitablePos(), HeroPtr(hero));
 	}
 
 	std::string QuestAction::toString() const