Browse Source

Remove ConstTransitivePtr from hero and town instances

Ivan Savenko 7 months ago
parent
commit
417ea6451a
57 changed files with 436 additions and 390 deletions
  1. 10 10
      AI/Nullkiller/AIGateway.cpp
  2. 3 3
      AI/Nullkiller/AIUtility.cpp
  3. 2 2
      AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp
  4. 1 1
      AI/Nullkiller/Analyzers/HeroManager.cpp
  5. 35 35
      AI/Nullkiller/Behaviors/DefenceBehavior.cpp
  6. 7 7
      AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp
  7. 2 2
      AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp
  8. 17 17
      AI/Nullkiller/Behaviors/StartupBehavior.cpp
  9. 1 1
      AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp
  10. 4 4
      AI/Nullkiller/Engine/FuzzyHelper.cpp
  11. 5 5
      AI/Nullkiller/Goals/AdventureSpellCast.cpp
  12. 2 2
      AI/Nullkiller/Goals/BuyArmy.cpp
  13. 20 20
      AI/Nullkiller/Goals/ExchangeSwapTownHeroes.cpp
  14. 2 2
      AI/Nullkiller/Goals/RecruitHero.cpp
  15. 8 8
      AI/Nullkiller/Pathfinding/AINodeStorage.cpp
  16. 2 2
      AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp
  17. 2 2
      AI/VCAI/Goals/AdventureSpellCast.cpp
  18. 1 1
      AI/VCAI/Goals/BuildThis.cpp
  19. 2 2
      AI/VCAI/Goals/GatherArmy.cpp
  20. 2 2
      AI/VCAI/Goals/GatherTroops.cpp
  21. 2 2
      AI/VCAI/Goals/Win.cpp
  22. 1 1
      AI/VCAI/Pathfinding/AINodeStorage.cpp
  23. 13 13
      AI/VCAI/VCAI.cpp
  24. 1 1
      CCallback.cpp
  25. 9 21
      client/CPlayerInterface.cpp
  26. 1 1
      client/NetPacksClient.cpp
  27. 1 1
      client/mapView/MapRendererContext.cpp
  28. 1 1
      client/widgets/CGarrisonInt.cpp
  29. 36 36
      client/windows/CCastleInterface.cpp
  30. 3 3
      client/windows/CHeroWindow.cpp
  31. 3 3
      client/windows/CKingdomInterface.cpp
  32. 1 1
      client/windows/GUIClasses.cpp
  33. 1 1
      lib/CCreatureSet.cpp
  34. 4 4
      lib/CGameInfoCallback.cpp
  35. 1 1
      lib/CStack.cpp
  36. 1 1
      lib/IGameCallback.cpp
  37. 2 2
      lib/battle/BattleInfo.cpp
  38. 7 7
      lib/gameState/CGameState.cpp
  39. 1 1
      lib/gameState/GameStatistics.cpp
  40. 1 1
      lib/gameState/InfoAboutArmy.cpp
  41. 55 17
      lib/mapObjects/CGHeroInstance.cpp
  42. 11 7
      lib/mapObjects/CGHeroInstance.h
  43. 63 48
      lib/mapObjects/CGTownInstance.cpp
  44. 5 3
      lib/mapObjects/CGTownInstance.h
  45. 1 1
      lib/mapObjects/MiscObjects.cpp
  46. 12 13
      lib/networkPacks/NetPacksLib.cpp
  47. 1 1
      lib/pathfinder/CPathfinder.cpp
  48. 2 2
      lib/serializer/BinaryDeserializer.h
  49. 4 4
      lib/spells/AdventureSpellMechanics.cpp
  50. 1 1
      mapeditor/maphandler.cpp
  51. 46 46
      server/CGameHandler.cpp
  52. 1 1
      server/NetPacksServer.cpp
  53. 9 9
      server/battles/BattleResultProcessor.cpp
  54. 1 1
      server/processors/HeroPoolProcessor.cpp
  55. 4 4
      server/processors/NewTurnProcessor.cpp
  56. 1 1
      server/processors/PlayerMessageProcessor.cpp
  57. 1 1
      server/queries/MapQueries.cpp

+ 10 - 10
AI/Nullkiller/AIGateway.cpp

@@ -904,19 +904,19 @@ void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h
 	switch(obj->ID)
 	{
 	case Obj::TOWN:
-		if(h->visitedTown) //we are inside, not just attacking
+		if(h->getVisitedTown()) //we are inside, not just attacking
 		{
 			makePossibleUpgrades(h.get());
 
 			std::unique_lock lockGuard(nullkiller->aiStateMutex);
 
-			if(!h->visitedTown->garrisonHero || !nullkiller->isHeroLocked(h->visitedTown->garrisonHero))
-				moveCreaturesToHero(h->visitedTown);
+			if(!h->getVisitedTown()->getGarrisonHero() || !nullkiller->isHeroLocked(h->getVisitedTown()->getGarrisonHero()))
+				moveCreaturesToHero(h->getVisitedTown());
 
 			if(nullkiller->heroManager->getHeroRole(h) == HeroRole::MAIN && !h->hasSpellbook()
 				&& nullkiller->getFreeGold() >= GameConstants::SPELLBOOK_GOLD_COST)
 			{
-				if(h->visitedTown->hasBuilt(BuildingID::MAGES_GUILD_1))
+				if(h->getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
 					cb->buyArtifact(h.get(), ArtifactID::SPELLBOOK);
 			}
 		}
@@ -929,9 +929,9 @@ void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h
 
 void AIGateway::moveCreaturesToHero(const CGTownInstance * t)
 {
-	if(t->visitingHero && t->armedGarrison() && t->visitingHero->tempOwner == t->tempOwner)
+	if(t->getVisitingHero() && t->armedGarrison() && t->getVisitingHero()->tempOwner == t->tempOwner)
 	{
-		pickBestCreatures(t->visitingHero, t->getUpperArmy());
+		pickBestCreatures(t->getVisitingHero(), t->getUpperArmy());
 	}
 }
 
@@ -1282,10 +1282,10 @@ void AIGateway::addVisitableObj(const CGObjectInstance * obj)
 
 bool AIGateway::moveHeroToTile(int3 dst, HeroPtr h)
 {
-	if(h->inTownGarrison && h->visitedTown)
+	if(h->isGarrisoned() && h->getVisitedTown())
 	{
-		cb->swapGarrisonHero(h->visitedTown);
-		moveCreaturesToHero(h->visitedTown);
+		cb->swapGarrisonHero(h->getVisitedTown());
+		moveCreaturesToHero(h->getVisitedTown());
 	}
 
 	//TODO: consider if blockVisit objects change something in our checks: AIUtility::isBlockVisitObj()
@@ -1596,7 +1596,7 @@ void AIGateway::endTurn()
 
 void AIGateway::buildArmyIn(const CGTownInstance * t)
 {
-	makePossibleUpgrades(t->visitingHero);
+	makePossibleUpgrades(t->getVisitingHero());
 	makePossibleUpgrades(t);
 	recruitCreatures(t, t->getUpperArmy());
 	moveCreaturesToHero(t);

+ 3 - 3
AI/Nullkiller/AIUtility.cpp

@@ -767,7 +767,7 @@ bool shouldVisit(const Nullkiller * ai, const CGHeroInstance * h, const CGObject
 bool townHasFreeTavern(const CGTownInstance * town)
 {
 	if(!town->hasBuilt(BuildingID::TAVERN)) return false;
-	if(!town->visitingHero) return true;
+	if(!town->getVisitingHero()) return true;
 
 	bool canMoveVisitingHeroToGarrison = !town->getUpperArmy()->stacksCount();
 
@@ -778,9 +778,9 @@ uint64_t getHeroArmyStrengthWithCommander(const CGHeroInstance * hero, const CCr
 {
 	auto armyStrength = heroArmy->getArmyStrength(fortLevel);
 
-	if(hero && hero->commander && hero->commander->alive)
+	if(hero && hero->getCommander() && hero->getCommander()->alive)
 	{
-		armyStrength += 100 * hero->commander->level;
+		armyStrength += 100 * hero->getCommander()->level;
 	}
 
 	return armyStrength;

+ 2 - 2
AI/Nullkiller/Analyzers/DangerHitMapAnalyzer.cpp

@@ -93,8 +93,8 @@ void DangerHitMapAnalyzer::updateHitMap()
 		{
 			auto town = dynamic_cast<const CGTownInstance *>(obj);
 
-			if(town->garrisonHero)
-				heroes[town->garrisonHero->tempOwner][town->garrisonHero] = HeroRole::MAIN;
+			if(town->getGarrisonHero())
+				heroes[town->getGarrisonHero()->tempOwner][town->getGarrisonHero()] = HeroRole::MAIN;
 		}
 	}
 

+ 1 - 1
AI/Nullkiller/Analyzers/HeroManager.cpp

@@ -293,7 +293,7 @@ const CGHeroInstance * HeroManager::findWeakHeroToDismiss(uint64_t armyLimit, co
 			|| existingHero->getArmyStrength() >armyLimit
 			|| getHeroRole(existingHero) == HeroRole::MAIN
 			|| existingHero->movementPointsRemaining()
-			|| (townToSpare != nullptr && existingHero->visitedTown == townToSpare)
+			|| (townToSpare != nullptr && existingHero->getVisitedTown() == townToSpare)
 			|| existingHero->artifactsWorn.size() > (existingHero->hasSpellbook() ? 2 : 1))
 		{
 			continue;

+ 35 - 35
AI/Nullkiller/Behaviors/DefenceBehavior.cpp

@@ -109,30 +109,30 @@ void handleCounterAttack(
 
 bool handleGarrisonHeroFromPreviousTurn(const CGTownInstance * town, Goals::TGoalVec & tasks, const Nullkiller * ai)
 {
-	if(ai->isHeroLocked(town->garrisonHero.get()))
+	if(ai->isHeroLocked(town->getGarrisonHero()))
 	{
 		logAi->trace(
 			"Hero %s in garrison of town %s is supposed to defend the town",
-			town->garrisonHero->getNameTranslated(),
+			town->getGarrisonHero()->getNameTranslated(),
 			town->getNameTranslated());
 
 		return true;
 	}
 
-	if(!town->visitingHero)
+	if(!town->getVisitingHero())
 	{
 		if(ai->cb->getHeroCount(ai->playerID, false) < GameConstants::MAX_HEROES_PER_PLAYER)
 		{
 			logAi->trace(
 				"Extracting hero %s from garrison of town %s",
-				town->garrisonHero->getNameTranslated(),
+				town->getGarrisonHero()->getNameTranslated(),
 				town->getNameTranslated());
 
 			tasks.push_back(Goals::sptr(Goals::ExchangeSwapTownHeroes(town, nullptr).setpriority(5)));
 
 			return false;
 		}
-		else if(ai->heroManager->getHeroRole(town->garrisonHero.get()) == HeroRole::MAIN)
+		else if(ai->heroManager->getHeroRole(town->getGarrisonHero()) == HeroRole::MAIN)
 		{
 			auto armyDismissLimit = 1000;
 			auto heroToDismiss = ai->heroManager->findWeakHeroToDismiss(armyDismissLimit);
@@ -160,7 +160,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 	
 	threats.push_back(threatNode.fastestDanger); // no guarantee that fastest danger will be there
 
-	if (town->garrisonHero && handleGarrisonHeroFromPreviousTurn(town, tasks, ai))
+	if (town->getGarrisonHero() && handleGarrisonHeroFromPreviousTurn(town, tasks, ai))
 	{
 		return;
 	}
@@ -233,16 +233,16 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 				path.toString());
 #endif
 
-			auto townDefenseStrength = town->garrisonHero
-				? town->garrisonHero->getTotalStrength()
-				: (town->visitingHero ? town->visitingHero->getTotalStrength() : town->getUpperArmy()->getArmyStrength());
+			auto townDefenseStrength = town->getGarrisonHero()
+				? town->getGarrisonHero()->getTotalStrength()
+				: (town->getVisitingHero() ? town->getVisitingHero()->getTotalStrength() : town->getUpperArmy()->getArmyStrength());
 
-			if(town->visitingHero && path.targetHero == town->visitingHero.get())
+			if(town->getVisitingHero() && path.targetHero == town->getVisitingHero())
 			{
 				if(path.getHeroStrength() < townDefenseStrength)
 					continue;
 			}
-			else if(town->garrisonHero && path.targetHero == town->garrisonHero.get())
+			else if(town->getGarrisonHero() && path.targetHero == town->getGarrisonHero())
 			{
 				if(path.getHeroStrength() < townDefenseStrength)
 					continue;
@@ -271,7 +271,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 				continue;
 			}
 
-			if(path.targetHero == town->visitingHero.get() && path.exchangeCount == 1)
+			if(path.targetHero == town->getVisitingHero() && path.exchangeCount == 1)
 			{
 #if NKAI_TRACE_LEVEL >= 1
 				logAi->trace("Put %s to garrison of town %s",
@@ -280,7 +280,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 #endif
 
 				// dismiss creatures we are not able to pick to be able to hide in garrison
-				if(town->garrisonHero
+				if(town->getGarrisonHero()
 					|| town->getUpperArmy()->stacksCount() == 0
 					|| path.targetHero->canBeMergedWith(*town)
 					|| (town->getUpperArmy()->getArmyStrength() < 500 && town->fortLevel() >= CGTownInstance::CITADEL))
@@ -288,25 +288,25 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 					tasks.push_back(
 						Goals::sptr(Composition()
 							.addNext(DefendTown(town, threat, path.targetHero))
-							.addNext(ExchangeSwapTownHeroes(town, town->visitingHero.get(), HeroLockedReason::DEFENCE))));
+							.addNext(ExchangeSwapTownHeroes(town, town->getVisitingHero(), HeroLockedReason::DEFENCE))));
 				}
 
 				continue;
 			}
 
 			// main without army and visiting scout with army, very specific case
-			if(town->visitingHero && town->getUpperArmy()->stacksCount() == 0
-				&& path.targetHero != town->visitingHero.get() && path.exchangeCount == 1 && path.turn() == 0
-				&& ai->heroManager->evaluateHero(path.targetHero) > ai->heroManager->evaluateHero(town->visitingHero.get())
-				&& 10 * path.targetHero->getTotalStrength() < town->visitingHero->getTotalStrength())
+			if(town->getVisitingHero() && town->getUpperArmy()->stacksCount() == 0
+				&& path.targetHero != town->getVisitingHero() && path.exchangeCount == 1 && path.turn() == 0
+				&& ai->heroManager->evaluateHero(path.targetHero) > ai->heroManager->evaluateHero(town->getVisitingHero())
+				&& 10 * path.targetHero->getTotalStrength() < town->getVisitingHero()->getTotalStrength())
 			{
-				path.heroArmy = town->visitingHero.get();
+				path.heroArmy = town->getVisitingHero();
 
 				tasks.push_back(
 					Goals::sptr(Composition()
 						.addNext(DefendTown(town, threat, path))
 						.addNextSequence({
-								sptr(ExchangeSwapTownHeroes(town, town->visitingHero.get())),
+								sptr(ExchangeSwapTownHeroes(town, town->getVisitingHero())),
 								sptr(ExecuteHeroChain(path, town)),
 								sptr(ExchangeSwapTownHeroes(town, path.targetHero, HeroLockedReason::DEFENCE))
 							})));
@@ -350,22 +350,22 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 			composition.addNext(DefendTown(town, threat, path));
 			TGoalVec sequence;
 
-			if(town->garrisonHero && path.targetHero == town->garrisonHero.get() && path.exchangeCount == 1)
+			if(town->getGarrisonHero() && path.targetHero == town->getGarrisonHero() && path.exchangeCount == 1)
 			{
-				composition.addNext(ExchangeSwapTownHeroes(town, town->garrisonHero.get(), HeroLockedReason::DEFENCE));
+				composition.addNext(ExchangeSwapTownHeroes(town, town->getGarrisonHero(), HeroLockedReason::DEFENCE));
 				tasks.push_back(Goals::sptr(composition));
 
 #if NKAI_TRACE_LEVEL >= 1
 				logAi->trace("Locking hero %s in garrison of %s",
-					town->garrisonHero.get()->getObjectName(),
+					town->getGarrisonHero()->getObjectName(),
 					town->getObjectName());
 #endif
 
 				continue;
 			}
-			else if(town->visitingHero && path.targetHero != town->visitingHero && !path.containsHero(town->visitingHero))
+			else if(town->getVisitingHero() && path.targetHero != town->getVisitingHero() && !path.containsHero(town->getVisitingHero()))
 			{
-				if(town->garrisonHero && town->garrisonHero != path.targetHero)
+				if(town->getGarrisonHero() && town->getGarrisonHero() != path.targetHero)
 				{
 #if NKAI_TRACE_LEVEL >= 1
 					logAi->trace("Cancel moving %s to defend town %s as the town has garrison hero",
@@ -376,7 +376,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 				}
 				else if(path.turn() == 0)
 				{
-					sequence.push_back(sptr(ExchangeSwapTownHeroes(town, town->visitingHero.get())));
+					sequence.push_back(sptr(ExchangeSwapTownHeroes(town, town->getVisitingHero())));
 				}
 			}
 
@@ -425,7 +425,7 @@ void DefenceBehavior::evaluateDefence(Goals::TGoalVec & tasks, const CGTownInsta
 
 void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitMapInfo & threat, const CGTownInstance * town, const Nullkiller * ai) const
 {
-	if (threat.turn > 0 || town->garrisonHero || town->visitingHero)
+	if (threat.turn > 0 || town->getGarrisonHero() || town->getVisitingHero())
 		return;
 	
 	if(town->hasBuilt(BuildingID::TAVERN)
@@ -461,25 +461,25 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
 			bool needSwap = false;
 			const CGHeroInstance * heroToDismiss = nullptr;
 
-			if(town->visitingHero)
+			if(town->getVisitingHero())
 			{
-				if(!town->garrisonHero)
+				if(!town->getGarrisonHero())
 					needSwap = true;
 				else
 				{
-					if(town->visitingHero->getArmyStrength() < town->garrisonHero->getArmyStrength())
+					if(town->getVisitingHero()->getArmyStrength() < town->getGarrisonHero()->getArmyStrength())
 					{
-						if(town->visitingHero->getArmyStrength() >= hero->getArmyStrength())
+						if(town->getVisitingHero()->getArmyStrength() >= hero->getArmyStrength())
 							continue;
 
-						heroToDismiss = town->visitingHero.get();
+						heroToDismiss = town->getVisitingHero();
 					}
-					else if(town->garrisonHero->getArmyStrength() >= hero->getArmyStrength())
+					else if(town->getGarrisonHero()->getArmyStrength() >= hero->getArmyStrength())
 						continue;
 					else
 					{
 						needSwap = true;
-						heroToDismiss = town->garrisonHero.get();
+						heroToDismiss = town->getGarrisonHero();
 					}
 				}
 
@@ -499,7 +499,7 @@ void DefenceBehavior::evaluateRecruitingHero(Goals::TGoalVec & tasks, const HitM
 			Goals::Composition recruitHeroComposition;
 
 			if(needSwap)
-				sequence.push_back(sptr(ExchangeSwapTownHeroes(town, town->visitingHero.get())));
+				sequence.push_back(sptr(ExchangeSwapTownHeroes(town, town->getVisitingHero())));
 
 			if(heroToDismiss)
 				sequence.push_back(sptr(DismissHero(heroToDismiss)));

+ 7 - 7
AI/Nullkiller/Behaviors/GatherArmyBehavior.cpp

@@ -167,21 +167,21 @@ Goals::TGoalVec GatherArmyBehavior::deliverArmyToHero(const Nullkiller * ai, con
 
 			composition.addNext(heroExchange);
 
-			if(hero->inTownGarrison && path.turn() == 0)
+			if(hero->isGarrisoned() && path.turn() == 0)
 			{
 				auto lockReason = ai->getHeroLockedReason(hero);
 
-				if(path.targetHero->visitedTown == hero->visitedTown)
+				if(path.targetHero->getVisitedTown() == hero->getVisitedTown())
 				{
 					composition.addNextSequence({
-						sptr(ExchangeSwapTownHeroes(hero->visitedTown, hero, lockReason))});
+						sptr(ExchangeSwapTownHeroes(hero->getVisitedTown(), hero, lockReason))});
 				}
 				else
 				{
 					composition.addNextSequence({
-						sptr(ExchangeSwapTownHeroes(hero->visitedTown)),
+						sptr(ExchangeSwapTownHeroes(hero->getVisitedTown())),
 						sptr(exchangePath),
-						sptr(ExchangeSwapTownHeroes(hero->visitedTown, hero, lockReason))});
+						sptr(ExchangeSwapTownHeroes(hero->getVisitedTown(), hero, lockReason))});
 				}
 			}
 			else
@@ -262,7 +262,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * ai, const CGT
 			continue;
 		}
 
-		if(upgrader->visitingHero && (upgrader->visitingHero.get() != path.targetHero || path.exchangeCount == 1))
+		if(upgrader->getVisitingHero() && (upgrader->getVisitingHero() != path.targetHero || path.exchangeCount == 1))
 		{
 #if NKAI_TRACE_LEVEL >= 2
 			logAi->trace("Ignore path. Town has visiting hero.");
@@ -289,7 +289,7 @@ Goals::TGoalVec GatherArmyBehavior::upgradeArmy(const Nullkiller * ai, const CGT
 
 		auto upgrade = ai->armyManager->calculateCreaturesUpgrade(path.heroArmy, upgrader, availableResources);
 
-		if(!upgrader->garrisonHero
+		if(!upgrader->getGarrisonHero()
 			&& (
 				hasMainAround
 				|| ai->heroManager->getHeroRole(path.targetHero) == HeroRole::MAIN))

+ 2 - 2
AI/Nullkiller/Behaviors/RecruitHeroBehavior.cpp

@@ -68,7 +68,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * ai) const
 			closestThreat = std::min(closestThreat, threat.turn);
 		}
 		//Don't hire a hero where there already is one present
-		if (town->visitingHero && town->garrisonHero)
+		if (town->getVisitingHero() && town->getGarrisonHero())
 			continue;
 		float visitability = 0;
 		for (auto checkHero : ourHeroes)
@@ -98,7 +98,7 @@ Goals::TGoalVec RecruitHeroBehavior::decompose(const Nullkiller * ai) const
 
 			for(auto hero : availableHeroes)
 			{
-				if ((town->visitingHero || town->garrisonHero) 
+				if ((town->getVisitingHero() || town->getGarrisonHero()) 
 					&& closestThreat < 1
 					&& hero->getArmyCost() < GameConstants::HERO_GOLD_COST / 3.0)
 					continue;

+ 17 - 17
AI/Nullkiller/Behaviors/StartupBehavior.cpp

@@ -32,7 +32,7 @@ const AIPath getShortestPath(const CGTownInstance * town, const std::vector<AIPa
 {
 	auto shortestPath = *vstd::minElementByFun(paths, [town](const AIPath & path) -> float
 	{
-		if(town->garrisonHero && path.targetHero == town->garrisonHero.get())
+		if(town->getGarrisonHero() && path.targetHero == town->getGarrisonHero())
 			return 1;
 
 		return path.movementCost();
@@ -53,7 +53,7 @@ const CGHeroInstance * getNearestHero(const Nullkiller * ai, const CGTownInstanc
 	if(shortestPath.nodes.size() > 1
 		|| shortestPath.turn() != 0
 		|| shortestPath.targetHero->visitablePos().dist2dSQ(town->visitablePos()) > 4
-		|| (town->garrisonHero && shortestPath.targetHero == town->garrisonHero.get()))
+		|| (town->getGarrisonHero() && shortestPath.targetHero == town->getGarrisonHero()))
 		return nullptr;
 
 	return shortestPath.targetHero;
@@ -64,7 +64,7 @@ bool needToRecruitHero(const Nullkiller * ai, const CGTownInstance * startupTown
 	if(!ai->heroManager->canRecruitHero(startupTown))
 		return false;
 
-	if(!startupTown->garrisonHero && !startupTown->visitingHero)
+	if(!startupTown->getGarrisonHero() && !startupTown->getVisitingHero())
 		return true;
 
 	int treasureSourcesCount = 0;
@@ -122,8 +122,8 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 	{
 		startupTown = *vstd::maxElementByFun(towns, [ai](const CGTownInstance * town) -> float
 		{
-			if(town->garrisonHero)
-				return ai->heroManager->evaluateHero(town->garrisonHero.get());
+			if(town->getGarrisonHero())
+				return ai->heroManager->evaluateHero(town->getGarrisonHero());
 
 			auto closestHero = getNearestHero(ai, town);
 
@@ -147,7 +147,7 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 
 	if(closestHero)
 	{
-		if(!startupTown->visitingHero)
+		if(!startupTown->getVisitingHero())
 		{
 			if(ai->armyManager->howManyReinforcementsCanGet(startupTown->getUpperArmy(), startupTown->getUpperArmy(), closestHero, TerrainId::NONE) > 200)
 			{
@@ -163,12 +163,12 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 		}
 		else
 		{
-			auto visitingHero = startupTown->visitingHero.get();
+			auto visitingHero = startupTown->getVisitingHero();
 			auto visitingHeroScore = ai->heroManager->evaluateHero(visitingHero);
 				
-			if(startupTown->garrisonHero)
+			if(startupTown->getGarrisonHero())
 			{
-				auto garrisonHero = startupTown->garrisonHero.get();
+				auto garrisonHero = startupTown->getGarrisonHero();
 				auto garrisonHeroScore = ai->heroManager->evaluateHero(garrisonHero);
 
 				if(visitingHeroScore > garrisonHeroScore
@@ -187,7 +187,7 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 			else if(canRecruitHero)
 			{
 				auto canPickTownArmy = startupTown->stacksCount() == 0
-					|| ai->armyManager->howManyReinforcementsCanGet(startupTown->visitingHero, startupTown) > 0;
+					|| ai->armyManager->howManyReinforcementsCanGet(startupTown->getVisitingHero(), startupTown) > 0;
 
 				if(canPickTownArmy)
 				{
@@ -197,16 +197,16 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 		}
 	}
 
-	if(tasks.empty() && canRecruitHero && !startupTown->visitingHero)
+	if(tasks.empty() && canRecruitHero && !startupTown->getVisitingHero())
 	{
 		tasks.push_back(Goals::sptr(Goals::RecruitHero(startupTown)));
 	}
 
-	if(tasks.empty() && !startupTown->visitingHero)
+	if(tasks.empty() && !startupTown->getVisitingHero())
 	{
 		for(auto town : towns)
 		{
-			if(!town->visitingHero && needToRecruitHero(ai, town))
+			if(!town->getVisitingHero() && needToRecruitHero(ai, town))
 			{
 				tasks.push_back(Goals::sptr(Goals::RecruitHero(town)));
 
@@ -219,10 +219,10 @@ Goals::TGoalVec StartupBehavior::decompose(const Nullkiller * ai) const
 	{
 		for(const CGTownInstance * town : towns)
 		{
-			if(town->garrisonHero
-				&& town->garrisonHero->movementPointsRemaining()
-				&& !town->visitingHero
-				&& ai->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE)
+			if(town->getGarrisonHero()
+				&& town->getGarrisonHero()->movementPointsRemaining()
+				&& !town->getVisitingHero()
+				&& ai->getHeroLockedReason(town->getGarrisonHero()) != HeroLockedReason::DEFENCE)
 			{
 				tasks.push_back(Goals::sptr(ExchangeSwapTownHeroes(town, nullptr).setpriority(MIN_PRIORITY)));
 			}

+ 1 - 1
AI/Nullkiller/Behaviors/StayAtTownBehavior.cpp

@@ -43,7 +43,7 @@ Goals::TGoalVec StayAtTownBehavior::decompose(const Nullkiller * ai) const
 
 		for(auto & path : paths)
 		{
-			if(town->visitingHero && town->visitingHero.get() != path.targetHero)
+			if(town->getVisitingHero() && town->getVisitingHero() != path.targetHero)
 				continue;
 
 			if(!path.getFirstBlockedAction() && path.exchangeCount <= 1)

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

@@ -47,16 +47,16 @@ ui64 FuzzyHelper::evaluateDanger(const int3 & tile, const CGHeroInstance * visit
 		{
 			auto hero = dynamic_cast<const CGHeroInstance *>(dangerousObject);
 
-			if(hero->visitedTown && !hero->visitedTown->garrisonHero)
+			if(hero->getVisitedTown() && !hero->getVisitedTown()->getGarrisonHero())
 			{
-				objectDanger += evaluateDanger(hero->visitedTown.get());
+				objectDanger += evaluateDanger(hero->getVisitedTown());
 			}
 			objectDanger *= ai->heroManager->getFightingStrengthCached(hero);
 		}
 		if (objWithID<Obj::TOWN>(dangerousObject))
 		{
 			auto town = dynamic_cast<const CGTownInstance*>(dangerousObject);
-			auto hero = town->garrisonHero;
+			auto hero = town->getGarrisonHero();
 
 			if (hero)
 				objectDanger *= ai->heroManager->getFightingStrengthCached(hero);
@@ -121,7 +121,7 @@ ui64 FuzzyHelper::evaluateDanger(const CGObjectInstance * obj)
 		const CGTownInstance * town = dynamic_cast<const CGTownInstance *>(obj);
 		auto danger = town->getUpperArmy()->getArmyStrength();
 
-		if(danger || town->visitingHero)
+		if(danger || town->getVisitingHero())
 		{
 			auto fortLevel = town->fortLevel();
 

+ 5 - 5
AI/Nullkiller/Goals/AdventureSpellCast.cpp

@@ -44,17 +44,17 @@ void AdventureSpellCast::accept(AIGateway * ai)
 	{
 		ai->selectedObject = town->id;
 
-		if(town->visitingHero && town->tempOwner == ai->playerID && !town->getUpperArmy()->stacksCount())
+		if(town->getVisitingHero() && town->tempOwner == ai->playerID && !town->getUpperArmy()->stacksCount())
 		{
 			ai->myCb->swapGarrisonHero(town);
 		}
 
-		if(town->visitingHero)
-			throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
+		if(town->getVisitingHero())
+			throw cannotFulfillGoalException("The town is already occupied by " + town->getVisitingHero()->getNameTranslated());
 	}
 
-	if (hero->inTownGarrison)
-		ai->myCb->swapGarrisonHero(hero->visitedTown);
+	if (hero->isGarrisoned())
+		ai->myCb->swapGarrisonHero(hero->getVisitedTown());
 
 	auto wait = cb->waitTillRealize;
 

+ 2 - 2
AI/Nullkiller/Goals/BuyArmy.cpp

@@ -97,9 +97,9 @@ void BuyArmy::accept(AIGateway * ai)
 		throw cannotFulfillGoalException("No creatures to buy.");
 	}
 
-	if(town->visitingHero && !town->garrisonHero)
+	if(town->getVisitingHero() && !town->getGarrisonHero())
 	{
-		ai->moveHeroToTile(town->visitablePos(), town->visitingHero.get());
+		ai->moveHeroToTile(town->visitablePos(), town->getVisitingHero());
 	}
 }
 

+ 20 - 20
AI/Nullkiller/Goals/ExchangeSwapTownHeroes.cpp

@@ -19,7 +19,7 @@ namespace NKAI
 using namespace Goals;
 
 ExchangeSwapTownHeroes::ExchangeSwapTownHeroes(
-	const CGTownInstance * town, 
+	const CGTownInstance * town,
 	const CGHeroInstance * garrisonHero,
 	HeroLockedReason lockingReason)
 	:ElementarGoal(Goals::EXCHANGE_SWAP_TOWN_HEROES), town(town), garrisonHero(garrisonHero), lockingReason(lockingReason)
@@ -30,11 +30,11 @@ std::vector<ObjectInstanceID> ExchangeSwapTownHeroes::getAffectedObjects() const
 {
 	std::vector<ObjectInstanceID> affectedObjects = { town->id };
 
-	if(town->garrisonHero)
-		affectedObjects.push_back(town->garrisonHero->id);
+	if(town->getGarrisonHero())
+		affectedObjects.push_back(town->getGarrisonHero()->id);
 
-	if(town->visitingHero)
-		affectedObjects.push_back(town->visitingHero->id);
+	if(town->getVisitingHero())
+		affectedObjects.push_back(town->getVisitingHero()->id);
 
 	return affectedObjects;
 }
@@ -42,8 +42,8 @@ std::vector<ObjectInstanceID> ExchangeSwapTownHeroes::getAffectedObjects() const
 bool ExchangeSwapTownHeroes::isObjectAffected(ObjectInstanceID id) const
 {
 	return town->id == id
-		|| (town->visitingHero && town->visitingHero->id == id)
-		|| (town->garrisonHero && town->garrisonHero->id == id);
+		|| (town->getVisitingHero() && town->getVisitingHero()->id == id)
+		|| (town->getGarrisonHero() && town->getGarrisonHero()->id == id);
 }
 
 std::string ExchangeSwapTownHeroes::toString() const
@@ -58,39 +58,39 @@ bool ExchangeSwapTownHeroes::operator==(const ExchangeSwapTownHeroes & other) co
 
 void ExchangeSwapTownHeroes::accept(AIGateway * ai)
 {
-	if(!garrisonHero)
+	if(!getGarrisonHero())
 	{
-		auto currentGarrisonHero = town->garrisonHero;
+		auto currentGarrisonHero = town->getGarrisonHero();
 		
 		if(!currentGarrisonHero)
 			throw cannotFulfillGoalException("Invalid configuration. There is no hero in town garrison.");
 		
 		cb->swapGarrisonHero(town);
 
-		if(currentGarrisonHero.get() != town->visitingHero.get())
+		if(currentGarrisonHero != town->getVisitingHero())
 		{
 			logAi->error("VisitingHero is empty, expected %s", currentGarrisonHero->getNameTranslated());
 			return;
 		}
 
 		ai->buildArmyIn(town);
-		ai->nullkiller->unlockHero(currentGarrisonHero.get());
+		ai->nullkiller->unlockHero(currentGarrisonHero);
 		logAi->debug("Extracted hero %s from garrison of %s", currentGarrisonHero->getNameTranslated(), town->getNameTranslated());
 
 		return;
 	}
 
-	if(town->visitingHero && town->visitingHero.get() != garrisonHero)
+	if(town->getVisitingHero() && town->getVisitingHero() != getGarrisonHero())
 		cb->swapGarrisonHero(town);
 
 	ai->makePossibleUpgrades(town);
-	ai->moveHeroToTile(town->visitablePos(), garrisonHero);
+	ai->moveHeroToTile(town->visitablePos(), getGarrisonHero());
 
 	auto upperArmy = town->getUpperArmy();
 	
-	if(!town->garrisonHero)
+	if(!town->getGarrisonHero())
 	{
-		if (!garrisonHero->canBeMergedWith(*town))
+		if (!getGarrisonHero()->canBeMergedWith(*town))
 		{
 			while (upperArmy->stacksCount() != 0)
 			{
@@ -103,16 +103,16 @@ void ExchangeSwapTownHeroes::accept(AIGateway * ai)
 
 	if(lockingReason != HeroLockedReason::NOT_LOCKED)
 	{
-		ai->nullkiller->lockHero(garrisonHero, lockingReason);
+		ai->nullkiller->lockHero(getGarrisonHero(), lockingReason);
 	}
 
-	if(town->visitingHero && town->visitingHero != garrisonHero)
+	if(town->getVisitingHero() && town->getVisitingHero() != getGarrisonHero())
 	{
-		ai->nullkiller->unlockHero(town->visitingHero.get());
-		ai->makePossibleUpgrades(town->visitingHero);
+		ai->nullkiller->unlockHero(town->getVisitingHero());
+		ai->makePossibleUpgrades(town->getVisitingHero());
 	}
 
-	logAi->debug("Put hero %s to garrison of %s", garrisonHero->getNameTranslated(), town->getNameTranslated());
+	logAi->debug("Put hero %s to garrison of %s", getGarrisonHero()->getNameTranslated(), town->getNameTranslated());
 }
 
 }

+ 2 - 2
AI/Nullkiller/Goals/RecruitHero.cpp

@@ -59,12 +59,12 @@ void RecruitHero::accept(AIGateway * ai)
 	if(!heroToHire)
 		throw cannotFulfillGoalException("No hero to hire!");
 
-	if(t->visitingHero)
+	if(t->getVisitingHero())
 	{
 		cb->swapGarrisonHero(t);
 	}
 
-	if(t->visitingHero)
+	if(t->getVisitingHero())
 		throw cannotFulfillGoalException("Town " + t->nodeName() + " is occupied. Cannot recruit hero!");
 
 	cb->recruitHero(t, heroToHire);

+ 8 - 8
AI/Nullkiller/Pathfinding/AINodeStorage.cpp

@@ -958,7 +958,7 @@ void AINodeStorage::setHeroes(std::map<const CGHeroInstance *, HeroRole> heroes)
 	{
 		// do not allow our own heroes in garrison to act on map
 		if(hero.first->getOwner() == ai->playerID
-			&& hero.first->inTownGarrison
+			&& hero.first->isGarrisoned()
 			&& (ai->isHeroLocked(hero.first) || ai->heroManager->heroCapReached(false)))
 		{
 			continue;
@@ -987,9 +987,9 @@ void AINodeStorage::setTownsAndDwellings(
 	{
 		uint64_t mask = FirstActorMask << actors.size();
 
-		// TODO: investigate logix of second condition || ai->nullkiller->getHeroLockedReason(town->garrisonHero) != HeroLockedReason::DEFENCE
+		// TODO: investigate logix of second condition || ai->nullkiller->getHeroLockedReason(town->getGarrisonHero()) != HeroLockedReason::DEFENCE
 		// check defence imrove
-		if(!town->garrisonHero)
+		if(!town->getGarrisonHero())
 		{
 			actors.push_back(std::make_shared<TownGarrisonActor>(town, mask));
 		}
@@ -1185,19 +1185,19 @@ void AINodeStorage::calculateTownPortal(
 	{
 		for(const CGTownInstance * targetTown : towns)
 		{
-			if(targetTown->visitingHero
+			if(targetTown->getVisitingHero()
 				&& targetTown->getUpperArmy()->stacksCount()
-				&& maskMap.find(targetTown->visitingHero.get()) != maskMap.end())
+				&& maskMap.find(targetTown->getVisitingHero()) != maskMap.end())
 			{
-				auto basicMask = maskMap.at(targetTown->visitingHero.get());
+				auto basicMask = maskMap.at(targetTown->getVisitingHero());
 				bool sameActorInTown = actor->chainMask == basicMask;
 
 				if(!sameActorInTown)
 					continue;
 			}
 
-			if (targetTown->visitingHero
-				&& (targetTown->visitingHero.get()->getFactionID() != actor->hero->getFactionID()
+			if (targetTown->getVisitingHero()
+				&& (targetTown->getVisitingHero()->getFactionID() != actor->hero->getFactionID()
 					|| targetTown->getUpperArmy()->stacksCount()))
 				continue;
 

+ 2 - 2
AI/Nullkiller/Pathfinding/Actions/BuyArmyAction.cpp

@@ -20,13 +20,13 @@ namespace AIPathfinding
 {
 	void BuyArmyAction::execute(AIGateway * ai, const CGHeroInstance * hero) const
 	{
-		if(!hero->visitedTown)
+		if(!hero->getVisitedTown())
 		{
 			throw cannotFulfillGoalException(
 				hero->getNameTranslated() + " being at " + hero->visitablePos().toString() + " has no town to recruit creatures.");
 		}
 
-		ai->recruitCreatures(hero->visitedTown, hero);
+		ai->recruitCreatures(hero->getVisitedTown(), hero);
 	}
 
 	std::string BuyArmyAction::toString() const

+ 2 - 2
AI/VCAI/Goals/AdventureSpellCast.cpp

@@ -39,8 +39,8 @@ TSubgoal AdventureSpellCast::whatToDoToAchieve()
 	if(hero->mana < hero->getSpellCost(spell))
 		throw cannotFulfillGoalException("Hero has not enough mana to cast " + spell->getNameTranslated());
 
-	if(spellID == SpellID::TOWN_PORTAL && town && town->visitingHero)
-		throw cannotFulfillGoalException("The town is already occupied by " + town->visitingHero->getNameTranslated());
+	if(spellID == SpellID::TOWN_PORTAL && town && town->getVisitingHero())
+		throw cannotFulfillGoalException("The town is already occupied by " + town->getVisitingHero()->getNameTranslated());
 
 	return iAmElementar();
 }

+ 1 - 1
AI/VCAI/Goals/BuildThis.cpp

@@ -32,7 +32,7 @@ TSubgoal BuildThis::whatToDoToAchieve()
 
 	// find town if not set
 	if(!town && hero)
-		town = hero->visitedTown;
+		town = hero->getVisitedTown();
 
 	if(!town)
 	{

+ 2 - 2
AI/VCAI/Goals/GatherArmy.cpp

@@ -56,14 +56,14 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 		if(waysToVisit.size())
 		{
 			//grab army from town
-			if(!t->visitingHero && ai->ah->howManyReinforcementsCanGet(hero.get(), t))
+			if(!t->getVisitingHero() && ai->ah->howManyReinforcementsCanGet(hero.get(), t))
 			{
 				if(!vstd::contains(ai->townVisitsThisWeek[hero], t))
 					vstd::concatenate(ret, waysToVisit);
 			}
 
 			//buy army in town
-			if (!t->visitingHero || t->visitingHero == hero.get(true))
+			if (!t->getVisitingHero() || t->getVisitingHero() == hero.get(true))
 			{
 				std::vector<int> values = {
 					value,

+ 2 - 2
AI/VCAI/Goals/GatherTroops.cpp

@@ -75,9 +75,9 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
 
 		if(count >= this->value)
 		{
-			if(t->visitingHero)
+			if(t->getVisitingHero())
 			{
-				solutions.push_back(sptr(VisitObj(t->id.getNum()).sethero(t->visitingHero.get())));
+				solutions.push_back(sptr(VisitObj(t->id.getNum()).sethero(t->getVisitingHero())));
 			}
 			else
 			{

+ 2 - 2
AI/VCAI/Goals/Win.cpp

@@ -83,9 +83,9 @@ TSubgoal Win::whatToDoToAchieve()
 				if(auto h = ai->getHeroWithGrail())
 				{
 					//hero is in a town that can host Grail
-					if(h->visitedTown && !vstd::contains(h->visitedTown->forbiddenBuildings, BuildingID::GRAIL))
+					if(h->getVisitedTown() && !vstd::contains(h->getVisitedTown()->forbiddenBuildings, BuildingID::GRAIL))
 					{
-						const CGTownInstance * t = h->visitedTown;
+						const CGTownInstance * t = h->getVisitedTown();
 						return sptr(BuildThis(BuildingID::GRAIL, t).setpriority(10));
 					}
 					else

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

@@ -267,7 +267,7 @@ void AINodeStorage::calculateTownPortalTeleportations(
 
 		for(const CGTownInstance * targetTown : towns)
 		{
-			if(targetTown->visitingHero)
+			if(targetTown->getVisitingHero())
 				continue;
 
 			auto nodeOptional = getOrCreateNode(targetTown->visitablePos(), EPathfindingLayer::LAND, srcNode->chainMask | CAST_CHAIN);

+ 13 - 13
AI/VCAI/VCAI.cpp

@@ -486,8 +486,8 @@ void VCAI::playerBonusChanged(const Bonus & bonus, bool gain)
 void VCAI::heroCreated(const CGHeroInstance * h)
 {
 	LOG_TRACE(logAi);
-	if(h->visitedTown)
-		townVisitsThisWeek[HeroPtr(h)].insert(h->visitedTown);
+	if(h->getVisitedTown())
+		townVisitsThisWeek[HeroPtr(h)].insert(h->getVisitedTown());
 	NET_EVENT_HANDLER;
 }
 
@@ -1073,12 +1073,12 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 	{
 	case Obj::TOWN:
 		moveCreaturesToHero(dynamic_cast<const CGTownInstance *>(obj));
-		if(h->visitedTown) //we are inside, not just attacking
+		if(h->getVisitedTown()) //we are inside, not just attacking
 		{
-			townVisitsThisWeek[h].insert(h->visitedTown);
+			townVisitsThisWeek[h].insert(h->getVisitedTown());
 			if(!h->hasSpellbook() && ah->freeGold() >= GameConstants::SPELLBOOK_GOLD_COST)
 			{
-				if(h->visitedTown->hasBuilt(BuildingID::MAGES_GUILD_1))
+				if(h->getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
 					cb->buyArtifact(h.get(), ArtifactID::SPELLBOOK);
 			}
 		}
@@ -1089,9 +1089,9 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
 
 void VCAI::moveCreaturesToHero(const CGTownInstance * t)
 {
-	if(t->visitingHero && t->armedGarrison() && t->visitingHero->tempOwner == t->tempOwner)
+	if(t->getVisitingHero() && t->armedGarrison() && t->getVisitingHero()->tempOwner == t->tempOwner)
 	{
-		pickBestCreatures(t->visitingHero, t);
+		pickBestCreatures(t->getVisitingHero(), t);
 	}
 }
 
@@ -1363,10 +1363,10 @@ void VCAI::wander(HeroPtr h)
 {
 	auto visitTownIfAny = [this](HeroPtr h) -> bool
 	{
-		if (h->visitedTown)
+		if (h->getVisitedTown())
 		{
-			townVisitsThisWeek[h].insert(h->visitedTown);
-			buildArmyIn(h->visitedTown);
+			townVisitsThisWeek[h].insert(h->getVisitedTown());
+			buildArmyIn(h->getVisitedTown());
 			return true;
 		}
 		return false;
@@ -1434,7 +1434,7 @@ void VCAI::wander(HeroPtr h)
 			std::vector<const CGTownInstance *> townsNotReachable;
 			for(const CGTownInstance * t : cb->getTownsInfo())
 			{
-				if(!t->visitingHero && !vstd::contains(townVisitsThisWeek[h], t))
+				if(!t->getVisitingHero() && !vstd::contains(townVisitsThisWeek[h], t))
 				{
 					if(isAccessibleForHero(t->visitablePos(), h))
 						townsReachable.push_back(t);
@@ -2251,7 +2251,7 @@ void VCAI::tryRealize(Goals::AbstractGoal & g)
 const CGTownInstance * VCAI::findTownWithTavern() const
 {
 	for(const CGTownInstance * t : cb->getTownsInfo())
-		if(t->hasBuilt(BuildingID::TAVERN) && !t->visitingHero)
+		if(t->hasBuilt(BuildingID::TAVERN) && !t->getVisitingHero())
 			return t;
 
 	return nullptr;
@@ -2455,7 +2455,7 @@ void VCAI::performTypicalActions()
 
 void VCAI::buildArmyIn(const CGTownInstance * t)
 {
-	makePossibleUpgrades(t->visitingHero);
+	makePossibleUpgrades(t->getVisitingHero());
 	makePossibleUpgrades(t);
 	recruitCreatures(t, t->getUpperArmy());
 	moveCreaturesToHero(t);

+ 1 - 1
CCallback.cpp

@@ -273,7 +273,7 @@ void CCallback::spellResearch( const CGTownInstance *town, SpellID spellAtSlot,
 
 void CCallback::swapGarrisonHero( const CGTownInstance *town )
 {
-	if(town->tempOwner == *player || (town->garrisonHero && town->garrisonHero->tempOwner == *player ))
+	if(town->tempOwner == *player || (town->getGarrisonHero() && town->getGarrisonHero()->tempOwner == *player ))
 	{
 		GarrisonHeroSwap pack(town->id);
 		sendRequest(pack);

+ 9 - 21
client/CPlayerInterface.cpp

@@ -118,18 +118,6 @@
 
 std::shared_ptr<BattleInterface> CPlayerInterface::battleInt;
 
-struct HeroObjectRetriever
-{
-	const CGHeroInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
-	{
-		return h;
-	}
-	const CGHeroInstance * operator()(const ConstTransitivePtr<CStackInstance> &s) const
-	{
-		return nullptr;
-	}
-};
-
 CPlayerInterface::CPlayerInterface(PlayerColor Player):
 	localState(std::make_unique<PlayerLocalState>(*this)),
 	movementController(std::make_unique<HeroMovementController>()),
@@ -542,18 +530,18 @@ void CPlayerInterface::heroInGarrisonChange(const CGTownInstance *town)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	if(town->garrisonHero) //wandering hero moved to the garrison
+	if(town->getGarrisonHero()) //wandering hero moved to the garrison
 	{
 		// This method also gets called on hero recruitment -> garrisoned hero is already in garrison
-		if(town->garrisonHero->tempOwner == playerID && vstd::contains(localState->getWanderingHeroes(), town->garrisonHero))
-			localState->removeWanderingHero(town->garrisonHero);
+		if(town->getGarrisonHero()->tempOwner == playerID && vstd::contains(localState->getWanderingHeroes(), town->getGarrisonHero()))
+			localState->removeWanderingHero(town->getGarrisonHero());
 	}
 
-	if(town->visitingHero) //hero leaves garrison
+	if(town->getVisitingHero()) //hero leaves garrison
 	{
 		// This method also gets called on hero recruitment -> wandering heroes already contains new hero
-		if(town->visitingHero->tempOwner == playerID && !vstd::contains(localState->getWanderingHeroes(), town->visitingHero))
-			localState->addWanderingHero(town->visitingHero);
+		if(town->getVisitingHero()->tempOwner == playerID && !vstd::contains(localState->getWanderingHeroes(), town->getVisitingHero()))
+			localState->addWanderingHero(town->getVisitingHero());
 	}
 	adventureInt->onHeroChanged(nullptr);
 	adventureInt->onTownChanged(town);
@@ -611,8 +599,8 @@ void CPlayerInterface::garrisonsChanged(std::vector<const CArmedInstance *> objs
 			localState->verifyPath(hero);
 
 			adventureInt->onHeroChanged(hero);
-			if(hero->inTownGarrison && hero->visitedTown != town)
-				adventureInt->onTownChanged(hero->visitedTown);
+			if(hero->isGarrisoned() && hero->getVisitedTown() != town)
+				adventureInt->onTownChanged(hero->getVisitedTown());
 		}
 	}
 
@@ -1363,7 +1351,7 @@ void CPlayerInterface::initializeHeroTownList()
 	{
 		for(auto & hero : cb->getHeroesInfo())
 		{
-			if(!hero->inTownGarrison)
+			if(!hero->isGarrisoned())
 				localState->addWanderingHero(hero);
 		}
 	}

+ 1 - 1
client/NetPacksClient.cpp

@@ -703,7 +703,7 @@ void ApplyClientNetPackVisitor::visitCommanderLevelUp(CommanderLevelUp & pack)
 {
 	const CGHeroInstance * hero = cl.getHero(pack.heroId);
 	assert(hero);
-	const CCommanderInstance * commander = hero->commander;
+	const auto & commander = hero->getCommander();
 	assert(commander);
 	assert(commander->armyObj); //is it possible for Commander to exist beyond armed instance?
 	callOnlyThatInterface(cl, pack.player, &CGameInterface::commanderGotLevel, commander, pack.skills, pack.queryID);

+ 1 - 1
client/mapView/MapRendererContext.cpp

@@ -132,7 +132,7 @@ double MapRendererBaseContext::objectTransparency(ObjectInstanceID objectID, con
 	{
 		const auto * hero = dynamic_cast<const CGHeroInstance *>(object);
 
-		if(hero->inTownGarrison)
+		if(hero->isGarrisoned())
 			return 0;
 
 		if(hero->boat)

+ 1 - 1
client/widgets/CGarrisonInt.cpp

@@ -81,7 +81,7 @@ void CGarrisonSlot::hover (bool on)
 				const bool isHeroOnMap = owner->upperArmy() // Hero is not a visitor and not a garrison defender
 					&& owner->upperArmy()->ID == Obj::HERO
 					&& (!owner->lowerArmy() || owner->lowerArmy()->ID == Obj::HERO) // one hero or we are in the Heroes exchange window
-					&& !(static_cast<const CGHeroInstance*>(owner->upperArmy()))->inTownGarrison;
+					&& !(static_cast<const CGHeroInstance*>(owner->upperArmy()))->isGarrisoned();
 
 				if(isHeroOnMap)
 				{

+ 36 - 36
client/windows/CCastleInterface.cpp

@@ -595,16 +595,16 @@ HeroSlots::HeroSlots(const CGTownInstance * Town, Point garrPos, Point visitPos,
 	garr(Garrison)
 {
 	OBJECT_CONSTRUCTION;
-	garrisonedHero = std::make_shared<CHeroGSlot>(garrPos.x, garrPos.y, 0, town->garrisonHero, this);
-	visitingHero = std::make_shared<CHeroGSlot>(visitPos.x, visitPos.y, 1, town->visitingHero, this);
+	garrisonedHero = std::make_shared<CHeroGSlot>(garrPos.x, garrPos.y, 0, town->getGarrisonHero(), this);
+	visitingHero = std::make_shared<CHeroGSlot>(visitPos.x, visitPos.y, 1, town->getVisitingHero(), this);
 }
 
 HeroSlots::~HeroSlots() = default;
 
 void HeroSlots::update()
 {
-	garrisonedHero->set(town->garrisonHero);
-	visitingHero->set(town->visitingHero);
+	garrisonedHero->set(town->getGarrisonHero());
+	visitingHero->set(town->getVisitingHero());
 }
 
 void HeroSlots::swapArmies()
@@ -612,9 +612,9 @@ void HeroSlots::swapArmies()
 	bool allow = true;
 
 	//moving hero out of town - check if it is allowed
-	if (town->garrisonHero)
+	if (town->getGarrisonHero())
 	{
-		if (!town->visitingHero && GAME->interface()->cb->howManyHeroes(false) >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
+		if (!town->getVisitingHero() && GAME->interface()->cb->howManyHeroes(false) >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP))
 		{
 			std::string text = LIBRARY->generaltexth->translate("core.genrltxt.18"); //You already have %d adventuring heroes under your command.
 			boost::algorithm::replace_first(text,"%d",std::to_string(GAME->interface()->cb->howManyHeroes(false)));
@@ -622,7 +622,7 @@ void HeroSlots::swapArmies()
 			GAME->interface()->showInfoDialog(text, std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			allow = false;
 		}
-		else if (town->garrisonHero->stacksCount() == 0)
+		else if (town->getGarrisonHero()->stacksCount() == 0)
 		{
 			//This hero has no creatures.  A hero must have creatures before he can brave the dangers of the countryside.
 			GAME->interface()->showInfoDialog(LIBRARY->generaltexth->translate("core.genrltxt.19"), {}, soundBase::sound_todo);
@@ -630,9 +630,9 @@ void HeroSlots::swapArmies()
 		}
 	}
 
-	if(!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army
+	if(!town->getGarrisonHero() && town->getVisitingHero()) //visiting => garrison, merge armies: town army => hero army
 	{
-		if(!town->visitingHero->canBeMergedWith(*town))
+		if(!town->getVisitingHero()->canBeMergedWith(*town))
 		{
 			GAME->interface()->showInfoDialog(LIBRARY->generaltexth->allTexts[275], std::vector<std::shared_ptr<CComponent>>(), soundBase::sound_todo);
 			allow = false;
@@ -809,10 +809,10 @@ void CCastleBuildings::removeBuilding(BuildingID building)
 
 const CGHeroInstance * CCastleBuildings::getHero()
 {
-	if(town->visitingHero)
-		return town->visitingHero;
+	if(town->getVisitingHero())
+		return town->getVisitingHero();
 	else
-		return town->garrisonHero;
+		return town->getGarrisonHero();
 }
 
 void CCastleBuildings::buildingClicked(BuildingID building)
@@ -983,7 +983,7 @@ bool CCastleBuildings::buildingTryActivateCustomUI(BuildingID buildingToTest, Bu
 
 void CCastleBuildings::enterRewardable(BuildingID building)
 {
-	if (town->visitingHero == nullptr)
+	if (town->getVisitingHero() == nullptr)
 	{
 		MetaString message;
 		message.appendTextID("core.genrltxt.273"); // only visiting heroes may visit %s
@@ -993,7 +993,7 @@ void CCastleBuildings::enterRewardable(BuildingID building)
 	}
 	else
 	{
-		if (town->rewardableBuildings.at(building)->wasVisited(town->visitingHero))
+		if (town->rewardableBuildings.at(building)->wasVisited(town->getVisitingHero()))
 			enterBuilding(building);
 		else
 			GAME->interface()->cb->visitTownBuilding(town, building);
@@ -1002,7 +1002,7 @@ void CCastleBuildings::enterRewardable(BuildingID building)
 
 void CCastleBuildings::enterBlacksmith(BuildingID building, ArtifactID artifactID)
 {
-	const CGHeroInstance *hero = town->visitingHero;
+	const CGHeroInstance *hero = town->getVisitingHero();
 	if(!hero)
 	{
 		GAME->interface()->showInfoDialog(boost::str(boost::format(LIBRARY->generaltexth->allTexts[273]) % town->getTown()->buildings.find(building)->second->getNameTranslated()));
@@ -1040,7 +1040,7 @@ void CCastleBuildings::enterBuilding(BuildingID building)
 
 void CCastleBuildings::enterCastleGate(BuildingID building)
 {
-	if (!town->visitingHero)
+	if (!town->getVisitingHero())
 	{
 		GAME->interface()->showInfoDialog(LIBRARY->generaltexth->allTexts[126]);
 		return;//only visiting hero can use castle gates
@@ -1051,7 +1051,7 @@ void CCastleBuildings::enterCastleGate(BuildingID building)
 	for(auto & Town : Towns)
 	{
 		const CGTownInstance *t = Town;
-		if (t->id != this->town->id && t->visitingHero == nullptr && //another town, empty and this is
+		if (t->id != this->town->id && t->getVisitingHero() == nullptr && //another town, empty and this is
 			t->getFactionID() == town->getFactionID() && //the town of the same faction
 			t->hasBuilt(BuildingSubID::CASTLE_GATE)) //and the town has a castle gate
 		{
@@ -1169,7 +1169,7 @@ void CCastleBuildings::enterMagesGuild()
 
 void CCastleBuildings::enterTownHall()
 {
-	if(town->visitingHero && town->visitingHero->hasArt(ArtifactID::GRAIL) &&
+	if(town->getVisitingHero() && town->getVisitingHero()->hasArt(ArtifactID::GRAIL) &&
 		!town->hasBuilt(BuildingID::GRAIL)) //hero has grail, but town does not have it
 	{
 		if(!vstd::contains(town->forbiddenBuildings, BuildingID::GRAIL))
@@ -1427,7 +1427,7 @@ CCastleInterface::CCastleInterface(const CGTownInstance * Town, const CGTownInst
 	center();
 	updateShadow();
 
-	garr = std::make_shared<CGarrisonInt>(Point(305, 387), 4, Point(0,96), town->getUpperArmy(), town->visitingHero);
+	garr = std::make_shared<CGarrisonInt>(Point(305, 387), 4, Point(0,96), town->getUpperArmy(), town->getVisitingHero());
 	garr->setRedrawParent(true);
 
 	heroes = std::make_shared<HeroSlots>(town, Point(241, 387), Point(241, 483), garr, true);
@@ -1476,7 +1476,7 @@ CCastleInterface::~CCastleInterface()
 void CCastleInterface::updateGarrisons()
 {
 	garr->setArmy(town->getUpperArmy(), EGarrisonType::UPPER);
-	garr->setArmy(town->visitingHero, EGarrisonType::LOWER);
+	garr->setArmy(town->getVisitingHero(), EGarrisonType::LOWER);
 	garr->recreateSlots();
 	heroes->update();
 
@@ -1485,15 +1485,15 @@ void CCastleInterface::updateGarrisons()
 
 bool CCastleInterface::holdsGarrison(const CArmedInstance * army)
 {
-	return army == town || army == town->getUpperArmy() || army == town->visitingHero;
+	return army == town || army == town->getUpperArmy() || army == town->getVisitingHero();
 }
 
 void CCastleInterface::close()
 {
 	if(town->tempOwner == GAME->interface()->playerID) //we may have opened window for an allied town
 	{
-		if(town->visitingHero && town->visitingHero->tempOwner == GAME->interface()->playerID)
-			GAME->interface()->localState->setSelection(town->visitingHero);
+		if(town->getVisitingHero() && town->getVisitingHero()->tempOwner == GAME->interface()->playerID)
+			GAME->interface()->localState->setSelection(town->getVisitingHero());
 		else
 			GAME->interface()->localState->setSelection(town);
 	}
@@ -1503,9 +1503,9 @@ void CCastleInterface::close()
 void CCastleInterface::castleTeleport(int where)
 {
 	const CGTownInstance * dest = GAME->interface()->cb->getTown(ObjectInstanceID(where));
-	GAME->interface()->localState->setSelection(town->visitingHero);//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
-	GAME->interface()->cb->teleportHero(town->visitingHero, dest);
-	GAME->interface()->localState->erasePath(town->visitingHero);
+	GAME->interface()->localState->setSelection(town->getVisitingHero());//according to assert(ho == adventureInt->selection) in the eraseCurrentPathOf
+	GAME->interface()->cb->teleportHero(town->getVisitingHero(), dest);
+	GAME->interface()->localState->erasePath(town->getVisitingHero());
 }
 
 void CCastleInterface::townChange()
@@ -1605,22 +1605,22 @@ void CCastleInterface::keyPressed(EShortcut key)
 	case EShortcut::TOWN_OPEN_THIEVES_GUILD:
 		break;
 	case EShortcut::TOWN_OPEN_HERO_EXCHANGE:
-		if (town->visitingHero && town->garrisonHero)
-			GAME->interface()->showHeroExchange(town->visitingHero->id, town->garrisonHero->id);
+		if (town->getVisitingHero() && town->getGarrisonHero())
+			GAME->interface()->showHeroExchange(town->getVisitingHero()->id, town->getGarrisonHero()->id);
 		break;
 	case EShortcut::TOWN_OPEN_HERO:
-		if (town->visitingHero)
-			GAME->interface()->openHeroWindow(town->visitingHero);
-		else if (town->garrisonHero)
-			GAME->interface()->openHeroWindow(town->garrisonHero);
+		if (town->getVisitingHero())
+			GAME->interface()->openHeroWindow(town->getVisitingHero());
+		else if (town->getGarrisonHero())
+			GAME->interface()->openHeroWindow(town->getGarrisonHero());
 		break;
 	case EShortcut::TOWN_OPEN_VISITING_HERO:
-		if (town->visitingHero)
-			GAME->interface()->openHeroWindow(town->visitingHero);
+		if (town->getVisitingHero())
+			GAME->interface()->openHeroWindow(town->getVisitingHero());
 		break;
 	case EShortcut::TOWN_OPEN_GARRISONED_HERO:
-		if (town->garrisonHero)
-			GAME->interface()->openHeroWindow(town->garrisonHero);
+		if (town->getGarrisonHero())
+			GAME->interface()->openHeroWindow(town->getGarrisonHero());
 		break;
 	case EShortcut::TOWN_SWAP_ARMIES:
 		heroes->swapArmies();

+ 3 - 3
client/windows/CHeroWindow.cpp

@@ -104,7 +104,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), AnimationPath::builtin("hsbtns6.def"), std::make_pair(heroscrn[23], heroscrn[29]), 0, EShortcut::HERO_TIGHT_FORMATION));
 	formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), AnimationPath::builtin("hsbtns7.def"), std::make_pair(heroscrn[24], heroscrn[30]), 0, EShortcut::HERO_LOOSE_FORMATION));
 
-	if(hero->commander)
+	if(hero->getCommander())
 	{
 		commanderButton = std::make_shared<CButton>(Point(317, 18), AnimationPath::builtin("heroCommander"), CButton::tooltipLocalized("vcmi.heroWindow.openCommander"), [&](){ commanderWindow(); }, EShortcut::HERO_COMMANDER);
 		commanderButton->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/commanderButtonIcon")));
@@ -328,7 +328,7 @@ void CHeroWindow::commanderWindow()
 
 	if(pickedArtInst)
 	{
-		const auto freeSlot = ArtifactUtils::getArtAnyPosition(curHero->commander, pickedArtInst->getTypeId());
+		const auto freeSlot = ArtifactUtils::getArtAnyPosition(curHero->getCommander(), pickedArtInst->getTypeId());
 		if(vstd::contains(ArtifactUtils::commanderSlots(), freeSlot)) // We don't want to put it in commander's backpack!
 		{
 			ArtifactLocation dst(curHero->id, freeSlot);
@@ -338,7 +338,7 @@ void CHeroWindow::commanderWindow()
 	}
 	else
 	{
-		ENGINE->windows().createAndPushWindow<CStackWindow>(curHero->commander, false);
+		ENGINE->windows().createAndPushWindow<CStackWindow>(curHero->getCommander(), false);
 	}
 }
 

+ 3 - 3
client/windows/CKingdomInterface.cpp

@@ -785,7 +785,7 @@ CTownItem::CTownItem(const CGTownInstance * Town)
 	hall = std::make_shared<CTownInfo>( 69, 31, town, true);
 	fort = std::make_shared<CTownInfo>(111, 31, town, false);
 
-	garr = std::make_shared<CGarrisonInt>(Point(313, 3), 4, Point(232,0), town->getUpperArmy(), town->visitingHero, true, true, CGarrisonInt::ESlotsLayout::TWO_ROWS);
+	garr = std::make_shared<CGarrisonInt>(Point(313, 3), 4, Point(232,0), town->getUpperArmy(), town->getVisitingHero(), true, true, CGarrisonInt::ESlotsLayout::TWO_ROWS);
 	heroes = std::make_shared<HeroSlots>(town, Point(244,6), Point(475,6), garr, false);
 
 	size_t iconIndex = town->getTown()->clientInfo.icons[town->hasFort()][town->built >= GAME->interface()->cb->getSettings().getInteger(EGameSettings::TOWNS_BUILDINGS_PER_TURN_CAP)];
@@ -837,13 +837,13 @@ void CTownItem::updateGarrisons()
 {
 	garr->selectSlot(nullptr);
 	garr->setArmy(town->getUpperArmy(), EGarrisonType::UPPER);
-	garr->setArmy(town->visitingHero, EGarrisonType::LOWER);
+	garr->setArmy(town->getVisitingHero(), EGarrisonType::LOWER);
 	garr->recreateSlots();
 }
 
 bool CTownItem::holdsGarrison(const CArmedInstance * army)
 {
-	return army == town || army == town->getUpperArmy() || army == town->visitingHero;
+	return army == town || army == town->getUpperArmy() || army == town->getVisitingHero();
 }
 
 void CTownItem::update()

+ 1 - 1
client/windows/GUIClasses.cpp

@@ -517,7 +517,7 @@ CTavernWindow::CTavernWindow(const CGObjectInstance * TavernObj, const std::func
 		recruit->addHoverText(EButtonState::NORMAL, message.toString());
 		recruit->block(true);
 	}
-	else if(dynamic_cast<const CGTownInstance *>(TavernObj) && dynamic_cast<const CGTownInstance *>(TavernObj)->visitingHero)
+	else if(dynamic_cast<const CGTownInstance *>(TavernObj) && dynamic_cast<const CGTownInstance *>(TavernObj)->getVisitingHero())
 	{
 		recruit->addHoverText(EButtonState::NORMAL, LIBRARY->generaltexth->tavernInfo[2]); //Cannot recruit. You already have a Hero in this town.
 		recruit->block(true);

+ 1 - 1
lib/CCreatureSet.cpp

@@ -499,7 +499,7 @@ bool CCreatureSet::contains(const CStackInstance *stack) const
 SlotID CCreatureSet::findStack(const CStackInstance *stack) const
 {
 	const auto * h = dynamic_cast<const CGHeroInstance *>(this);
-	if (h && h->commander == stack)
+	if (h && h->getCommander() == stack)
 		return SlotID::COMMANDER_SLOT_PLACEHOLDER;
 
 	if(!stack)

+ 4 - 4
lib/CGameInfoCallback.cpp

@@ -721,7 +721,7 @@ int CGameInfoCallback::getHeroCount( PlayerColor player, bool includeGarrisoned
 		return static_cast<int>(p->getHeroes().size());
 	else
 		for(const auto & elem : p->getHeroes())
-			if(!elem->inTownGarrison)
+			if(!elem->isGarrisoned())
 				ret++;
 	return ret;
 }
@@ -792,7 +792,7 @@ std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo
 
 int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned) const
 {
-	if (hero->inTownGarrison && !includeGarrisoned)
+	if (hero->isGarrisoned() && !includeGarrisoned)
 		return -1;
 
 	size_t index = 0;
@@ -800,7 +800,7 @@ int CPlayerSpecificInfoCallback::getHeroSerial(const CGHeroInstance * hero, bool
 
 	for (auto & possibleHero : heroes)
 	{
-		if (includeGarrisoned || !(possibleHero)->inTownGarrison)
+		if (includeGarrisoned || !(possibleHero)->isGarrisoned())
 			index++;
 
 		if (possibleHero == hero)
@@ -853,7 +853,7 @@ const CGHeroInstance* CPlayerSpecificInfoCallback::getHeroBySerial(int serialId,
 	if (!includeGarrisoned)
 	{
 		for(ui32 i = 0; i < p->getHeroes().size() && static_cast<int>(i) <= serialId; i++)
-			if(p->getHeroes()[i]->inTownGarrison)
+			if(p->getHeroes()[i]->isGarrisoned())
 				serialId++;
 	}
 	ERROR_RET_VAL_IF(serialId < 0 || serialId >= p->getHeroes().size(), "No player info", nullptr);

+ 1 - 1
lib/CStack.cpp

@@ -410,7 +410,7 @@ void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot
 	{
 		const auto * hero = dynamic_cast<const CGHeroInstance *>(army);
 		assert(hero);
-		base = hero->commander;
+		base = hero->getCommander();
 	}
 	else if(slot == SlotID::SUMMONED_SLOT_PLACEHOLDER || slot == SlotID::ARROW_TOWERS_SLOT || slot == SlotID::WAR_MACHINES_SLOT)
 	{

+ 1 - 1
lib/IGameCallback.cpp

@@ -271,7 +271,7 @@ CArtifactSet * CNonConstInfoCallback::getArtSet(const ArtifactLocation & loc)
 		if(loc.creature.has_value())
 		{
 			if(loc.creature.value() == SlotID::COMMANDER_SLOT_PLACEHOLDER)
-				return hero->commander;
+				return hero->getCommander();
 			else
 				return hero->getStackPtr(loc.creature.value());
 		}

+ 2 - 2
lib/battle/BattleInfo.cpp

@@ -351,9 +351,9 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 	//adding commanders
 	for(BattleSide i : {BattleSide::ATTACKER, BattleSide::DEFENDER})
 	{
-		if (heroes[i] && heroes[i]->commander && heroes[i]->commander->alive)
+		if (heroes[i] && heroes[i]->getCommander() && heroes[i]->getCommander()->alive)
 		{
-			currentBattle->generateNewStack(currentBattle->nextUnitId(), *heroes[i]->commander, i, SlotID::COMMANDER_SLOT_PLACEHOLDER, layout.commanders.at(i));
+			currentBattle->generateNewStack(currentBattle->nextUnitId(), *heroes[i]->getCommander(), i, SlotID::COMMANDER_SLOT_PLACEHOLDER, layout.commanders.at(i));
 		}
 	}
 

+ 7 - 7
lib/gameState/CGameState.cpp

@@ -992,7 +992,7 @@ void CGameState::initVisitingAndGarrisonedHeroes()
 
 				if (t->visitableAt(h->visitablePos()))
 				{
-					assert(t->visitingHero == nullptr);
+					assert(t->getVisitingHero() == nullptr);
 					t->setVisitingHero(h);
 				}
 			}
@@ -1000,9 +1000,9 @@ void CGameState::initVisitingAndGarrisonedHeroes()
 	}
 	for (auto hero : map->heroesOnMap)
 	{
-		if (hero->visitedTown)
+		if (hero->getVisitedTown())
 		{
-			assert (hero->visitedTown->visitingHero == hero);
+			assert (hero->getVisitedTown()->getVisitingHero() == hero);
 		}
 	}
 }
@@ -1092,9 +1092,9 @@ UpgradeInfo CGameState::fillUpgradeInfo(const CStackInstance & stack) const
 		auto hero = dynamic_cast<const CGHeroInstance *>(stack.armyObj);
 		hero->fillUpgradeInfo(ret, stack);
 
-		if (hero->visitedTown)
+		if (hero->getVisitedTown())
 		{
-			hero->visitedTown->fillUpgradeInfo(ret, stack);
+			hero->getVisitedTown()->fillUpgradeInfo(ret, stack);
 		}
 		else
 		{
@@ -1382,8 +1382,8 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		case EventCondition::TRANSPORT:
 		{
 			const auto * t = getTown(condition.objectID);
-			bool garrisonedWon = t->garrisonHero && t->garrisonHero->getOwner() == player && t->garrisonHero->hasArt(condition.objectType.as<ArtifactID>());
-			bool visitingWon = t->visitingHero && t->visitingHero->getOwner() == player && t->visitingHero->hasArt(condition.objectType.as<ArtifactID>());
+			bool garrisonedWon = t->getGarrisonHero() && t->getGarrisonHero()->getOwner() == player && t->getGarrisonHero()->hasArt(condition.objectType.as<ArtifactID>());
+			bool visitingWon = t->getVisitingHero() && t->getVisitingHero()->getOwner() == player && t->getVisitingHero()->hasArt(condition.objectType.as<ArtifactID>());
 
 			return garrisonedWon || visitingWon;
 		}

+ 1 - 1
lib/gameState/GameStatistics.cpp

@@ -244,7 +244,7 @@ si64 Statistic::getArmyStrength(const PlayerState * ps, bool withTownGarrison)
 
 	for(auto h : ps->getHeroes())
 	{
-		if(!h->inTownGarrison || withTownGarrison)		//original h3 behavior
+		if(!h->isGarrisoned() || withTownGarrison)		//original h3 behavior
 			str += h->getArmyStrength();
 	}
 	return str;

+ 1 - 1
lib/gameState/InfoAboutArmy.cpp

@@ -183,7 +183,7 @@ void InfoAboutTown::initFromTown(const CGTownInstance *t, bool detailed)
 		details->goldIncome = income[EGameResID::GOLD];
 		details->customRes = t->hasBuilt(BuildingID::RESOURCE_SILO);
 		details->hallLevel = t->hallLevel();
-		details->garrisonedHero = t->garrisonHero;
+		details->garrisonedHero = t->getGarrisonHero();
 	}
 }
 

+ 55 - 17
lib/mapObjects/CGHeroInstance.cpp

@@ -308,6 +308,47 @@ void CGHeroInstance::setHeroType(HeroTypeID heroType)
 	subID = heroType;
 }
 
+bool CGHeroInstance::isGarrisoned() const
+{
+	return inTownGarrison;
+}
+
+const CGTownInstance * CGHeroInstance::getVisitedTown() const
+{
+	if (!visitedTown.hasValue())
+		return nullptr;
+
+	return cb->getTown(visitedTown);
+}
+
+CGTownInstance * CGHeroInstance::getVisitedTown()
+{
+	if (!visitedTown.hasValue())
+		return nullptr;
+
+	return dynamic_cast<CGTownInstance*>(cb->gameState()->getObjInstance(visitedTown));
+}
+
+void CGHeroInstance::setVisitedTown(const CGTownInstance * town, bool garrisoned)
+{
+	if (town)
+		visitedTown = town->id;
+	else
+		visitedTown = {};
+
+	inTownGarrison = garrisoned;
+}
+
+const CCommanderInstance * CGHeroInstance::getCommander() const
+{
+	return commander.get();
+}
+
+CCommanderInstance * CGHeroInstance::getCommander()
+{
+	return commander.get();
+}
+
 void CGHeroInstance::initObj(vstd::RNG & rand)
 {
 	if (ID == Obj::HERO)
@@ -423,7 +464,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
 
 	if (cb->getSettings().getBoolean(EGameSettings::MODULE_COMMANDERS) && !commander && getHeroClass()->commander.hasValue())
 	{
-		commander = new CCommanderInstance(getHeroClass()->commander);
+		commander = std::make_unique<CCommanderInstance>(getHeroClass()->commander);
 		commander->setArmyObj (castToArmyObj()); //TODO: separate function for setting commanders
 		commander->giveStackExp (exp); //after our exp is set
 	}
@@ -504,10 +545,7 @@ void CGHeroInstance::initArmy(vstd::RNG & rand, IArmyDescriptor * dst)
 	}
 }
 
-CGHeroInstance::~CGHeroInstance()
-{
-	commander.dellNull();
-}
+CGHeroInstance::~CGHeroInstance() = default;
 
 bool CGHeroInstance::needsLastStack() const
 {
@@ -527,8 +565,8 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const
 		}
 		else //battle
 		{
-			if(visitedTown) //we're in town
-				visitedTown->onHeroVisit(h); //town will handle attacking
+			if(getVisitedTown()) //we're in town
+				getVisitedTown()->onHeroVisit(h); //town will handle attacking
 			else
 				cb->startBattle(h,	this);
 		}
@@ -1060,7 +1098,7 @@ si32 CGHeroInstance::manaRegain() const
 
 si32 CGHeroInstance::getManaNewTurn() const
 {
-	if(visitedTown && visitedTown->hasBuilt(BuildingID::MAGES_GUILD_1))
+	if(getVisitedTown() && getVisitedTown()->hasBuilt(BuildingID::MAGES_GUILD_1))
 	{
 		//if hero starts turn in town with mage guild - restore all mana
 		return std::max(mana, manaLimit());
@@ -1280,30 +1318,30 @@ void CGHeroInstance::boatDeserializationFix()
 
 CBonusSystemNode * CGHeroInstance::whereShouldBeAttachedOnSiege(const bool isBattleOutsideTown) const
 {
-	if(!visitedTown)
+	if(!getVisitedTown())
 		return nullptr;
 
-	return isBattleOutsideTown ? (CBonusSystemNode *)(& visitedTown->townAndVis)
-		: (CBonusSystemNode *)(visitedTown.get());
+	return isBattleOutsideTown ? (CBonusSystemNode *)(& getVisitedTown()->townAndVis)
+		: (CBonusSystemNode *)(getVisitedTown());
 
 }
 
 CBonusSystemNode * CGHeroInstance::whereShouldBeAttachedOnSiege(CGameState * gs)
 {
-	if(visitedTown)
-		return whereShouldBeAttachedOnSiege(visitedTown->isBattleOutsideTown(this));
+	if(getVisitedTown())
+		return whereShouldBeAttachedOnSiege(getVisitedTown()->isBattleOutsideTown(this));
 
 	return &CArmedInstance::whereShouldBeAttached(gs);
 }
 
 CBonusSystemNode & CGHeroInstance::whereShouldBeAttached(CGameState * gs)
 {
-	if(visitedTown)
+	if(getVisitedTown())
 	{
-		if(inTownGarrison)
-			return *visitedTown;
+		if(isGarrisoned())
+			return *getVisitedTown();
 		else
-			return visitedTown->townAndVis;
+			return getVisitedTown()->townAndVis;
 	}
 	else
 		return CArmedInstance::whereShouldBeAttached(gs);

+ 11 - 7
lib/mapObjects/CGHeroInstance.h

@@ -17,7 +17,6 @@
 #include "../bonuses/BonusCache.h"
 #include "../entities/hero/EHeroGender.h"
 #include "../CArtHandler.h" // For CArtifactSet
-#include "../ConstTransitivePtr.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -66,12 +65,14 @@ private:
 	MagicSchoolMasteryCache magicSchoolMastery;
 	BonusValueCache manaPerKnowledgeCached;
 	std::unique_ptr<TurnInfoCache> turnInfoCache;
+	std::unique_ptr<CCommanderInstance> commander;
 
 	std::set<SpellID> spells; //known spells (spell IDs)
+	ObjectInstanceID visitedTown; //set if hero is visiting town or in the town garrison
 	ui32 movement; //remaining movement points
+	bool inTownGarrison; // if hero is in town garrison
 
 public:
-
 	//////////////////////////////////////////////////////////////////////////
 	//format:   123
 	//          8 4
@@ -93,9 +94,6 @@ public:
 	std::string nameCustomTextId;
 	std::string biographyCustomTextId;
 
-	bool inTownGarrison; // if hero is in town garrison
-	ConstTransitivePtr<CGTownInstance> visitedTown; //set if hero is visiting town or in the town garrison
-	ConstTransitivePtr<CCommanderInstance> commander;
 	const CGBoat * boat = nullptr; //set to CGBoat when sailing
 
 	static constexpr si32 UNINITIALIZED_MANA = -1;
@@ -103,8 +101,6 @@ public:
 	static constexpr auto UNINITIALIZED_EXPERIENCE = std::numeric_limits<TExpType>::max();
 	static const ui32 NO_PATROLLING;
 
-	//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag
-	//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5
 	std::set<ObjectInstanceID> visitedObjects;
 
 	struct DLL_LINKAGE Patrol
@@ -252,6 +248,14 @@ public:
 	HeroTypeID getHeroTypeID() const;
 	void setHeroType(HeroTypeID type);
 
+	bool isGarrisoned() const;
+	const CGTownInstance * getVisitedTown() const;
+	CGTownInstance * getVisitedTown();
+	void setVisitedTown(const CGTownInstance * town, bool garrisoned);
+
+	const CCommanderInstance * getCommander() const;
+	CCommanderInstance * getCommander();
+
 	void initObj(vstd::RNG & rand) override;
 	void initHero(vstd::RNG & rand);
 	void initHero(vstd::RNG & rand, const HeroTypeID & SUBID);

+ 63 - 48
lib/mapObjects/CGTownInstance.cpp

@@ -59,13 +59,13 @@ void CGTownInstance::setPropertyDer(ObjProperty what, ObjPropertyID identifier)
 	switch (what)
 	{
 		case ObjProperty::STRUCTURE_ADD_VISITING_HERO:
-			rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, visitingHero->id);
+			rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, getVisitingHero()->id);
 			break;
 		case ObjProperty::STRUCTURE_CLEAR_VISITORS:
 			rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::STRUCTURE_CLEAR_VISITORS, NumericID(0));
 			break;
 		case ObjProperty::STRUCTURE_ADD_GARRISONED_HERO: //add garrisoned hero to visitors
-			rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, garrisonHero->id);
+			rewardableBuildings.at(identifier.getNum())->setProperty(ObjProperty::VISITORS, getGarrisonHero()->id);
 			break;
 		case ObjProperty::BONUS_VALUE_FIRST:
 			bonusValue.first = identifier.getNum();
@@ -296,7 +296,7 @@ int CGTownInstance::spellsAtLevel(int level, bool checkGuild) const
 
 bool CGTownInstance::needsLastStack() const
 {
-	return garrisonHero != nullptr;
+	return getGarrisonHero() != nullptr;
 }
 
 void CGTownInstance::setOwner(const PlayerColor & player) const
@@ -309,13 +309,13 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 {
 	if(cb->gameState()->getPlayerRelations( getOwner(), h->getOwner() ) == PlayerRelations::ENEMIES)
 	{
-		if(armedGarrison() || visitingHero)
+		if(armedGarrison() || getVisitingHero())
 		{
-			const CGHeroInstance * defendingHero = visitingHero ? visitingHero : garrisonHero;
+			const CGHeroInstance * defendingHero = getVisitingHero() ? getVisitingHero() : getGarrisonHero();
 			const CArmedInstance * defendingArmy = defendingHero ? (CArmedInstance *)defendingHero : this;
 			const bool isBattleOutside = isBattleOutsideTown(defendingHero);
 
-			if(!isBattleOutside && visitingHero && defendingHero == visitingHero)
+			if(!isBattleOutside && getVisitingHero() && defendingHero == getVisitingHero())
 			{
 				//we have two approaches to merge armies: mergeGarrisonOnSiege() and used in the CGameHandler::garrisonSwap(ObjectInstanceID tid)
 				auto * nodeSiege = defendingHero->whereShouldBeAttachedOnSiege(isBattleOutside);
@@ -323,7 +323,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 				if(nodeSiege == (CBonusSystemNode *)this)
 					cb->swapGarrisonOnSiege(this->id);
 
-				const_cast<CGHeroInstance *>(defendingHero)->inTownGarrison = false; //hack to return visitor from garrison after battle
+				const_cast<CGHeroInstance *>(defendingHero)->setVisitedTown(this, false); //hack to return visitor from garrison after battle
 			}
 			cb->startBattle(h, defendingArmy, getSightCenter(), h, defendingHero, BattleLayout::createDefaultLayout(cb, h, defendingArmy), (isBattleOutside ? nullptr : this));
 		}
@@ -343,7 +343,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 	else
 	{
 		assert(h->visitablePos() == this->visitablePos());
-		bool commander_recover = h->commander && !h->commander->alive;
+		bool commander_recover = h->getCommander() && !h->getCommander()->alive;
 		if (commander_recover) // rise commander from dead
 		{
 			SetCommanderProperty scp;
@@ -358,8 +358,8 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 		{
 			InfoWindow iw;
 			iw.player = h->tempOwner;
-			iw.text.appendRawString(h->commander->getName());
-			iw.components.emplace_back(ComponentType::CREATURE, h->commander->getId(), h->commander->getCount());
+			iw.text.appendRawString(h->getCommander()->getName());
+			iw.components.emplace_back(ComponentType::CREATURE, h->getCommander()->getId(), h->getCommander()->getCount());
 			cb->showInfoDialog(&iw);
 		}
 	}
@@ -368,7 +368,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const
 void CGTownInstance::onHeroLeave(const CGHeroInstance * h) const
 {
 	//FIXME: find out why this issue appears on random maps
-	if(visitingHero == h)
+	if(getVisitingHero() == h)
 	{
 		cb->stopHeroVisitCastle(this, h);
 		logGlobal->trace("%s correctly left town %s", h->getNameTranslated(), getNameTranslated());
@@ -584,13 +584,13 @@ void CGTownInstance::mergeGarrisonOnSiege() const
 	auto getWeakestStackSlot = [&](ui64 powerLimit)
 	{
 		std::vector<SlotID> weakSlots;
-		auto stacksList = visitingHero->stacks;
+		auto stacksList = getVisitingHero()->stacks;
 		std::pair<SlotID, CStackInstance *> pair;
 		while(!stacksList.empty())
 		{
 			pair = *vstd::minElementByFun(stacksList, [&](const std::pair<SlotID, CStackInstance *> & elem) { return elem.second->getPower(); });
 			if(powerLimit > pair.second->getPower() &&
-				(weakSlots.empty() || pair.second->getPower() == visitingHero->getStack(weakSlots.front()).getPower()))
+				(weakSlots.empty() || pair.second->getPower() == getVisitingHero()->getStack(weakSlots.front()).getPower()))
 			{
 				weakSlots.push_back(pair.first);
 				stacksList.erase(pair.first);
@@ -612,20 +612,20 @@ void CGTownInstance::mergeGarrisonOnSiege() const
 		auto pair = *vstd::maxElementByFun(stacks, [&](const std::pair<SlotID, CStackInstance *> & elem)
 		{
 			ui64 power = elem.second->getPower();
-			auto dst = visitingHero->getSlotFor(elem.second->getCreatureID());
-			if(dst.validSlot() && visitingHero->hasStackAtSlot(dst))
-				power += visitingHero->getStack(dst).getPower();
+			auto dst = getVisitingHero()->getSlotFor(elem.second->getCreatureID());
+			if(dst.validSlot() && getVisitingHero()->hasStackAtSlot(dst))
+				power += getVisitingHero()->getStack(dst).getPower();
 
 			return power;
 		});
-		auto dst = visitingHero->getSlotFor(pair.second->getCreatureID());
+		auto dst = getVisitingHero()->getSlotFor(pair.second->getCreatureID());
 		if(dst.validSlot())
-			cb->moveStack(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst), -1);
+			cb->moveStack(StackLocation(id, pair.first), StackLocation(getVisitingHero()->id, dst), -1);
 		else
 		{
 			dst = getWeakestStackSlot(static_cast<int>(pair.second->getPower()));
 			if(dst.validSlot())
-				cb->swapStacks(StackLocation(id, pair.first), StackLocation(visitingHero->id, dst));
+				cb->swapStacks(StackLocation(id, pair.first), StackLocation(getVisitingHero()->id, dst));
 		}
 	}
 }
@@ -722,10 +722,10 @@ void CGTownInstance::deserializationFix()
 
 	//Hero is already handled by CGameState::attachArmedObjects
 
-// 	if(visitingHero)
-// 		visitingHero->attachTo(&townAndVis);
-// 	if(garrisonHero)
-// 		garrisonHero->attachTo(this);
+// 	if(getVisitingHero())
+// 		getVisitingHero()->attachTo(&townAndVis);
+// 	if(getGarrisonHero())
+// 		getGarrisonHero()->attachTo(this);
 }
 
 void CGTownInstance::updateMoraleBonusFromArmy()
@@ -737,7 +737,7 @@ void CGTownInstance::updateMoraleBonusFromArmy()
 		addNewBonus(b);
 	}
 
-	if (garrisonHero)
+	if (getGarrisonHero())
 	{
 		b->val = 0;
 		nodeHasChanged();
@@ -786,7 +786,7 @@ void CGTownInstance::recreateBuildingsBonuses()
 
 void CGTownInstance::setVisitingHero(CGHeroInstance *h)
 {
-	if(visitingHero.get() == h)
+	if(getVisitingHero() == h)
 		return;
 	
 	if(h)
@@ -795,23 +795,23 @@ void CGTownInstance::setVisitingHero(CGHeroInstance *h)
 		assert(p);
 		h->detachFrom(*p);
 		h->attachTo(townAndVis);
-		visitingHero = h;
-		h->visitedTown = this;
-		h->inTownGarrison = false;
+		h->setVisitedTown(this, false);
+		visitingHero = h->id;
 	}
 	else
 	{
-		PlayerState *p = cb->gameState()->getPlayerState(visitingHero->tempOwner);
-		visitingHero->visitedTown = nullptr;
-		visitingHero->detachFrom(townAndVis);
-		visitingHero->attachTo(*p);
-		visitingHero = nullptr;
+		auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero));
+		PlayerState *p = cb->gameState()->getPlayerState(getVisitingHero()->tempOwner);
+		oldVisitor->setVisitedTown(nullptr, false);
+		oldVisitor->detachFrom(townAndVis);
+		oldVisitor->attachTo(*p);
+		visitingHero = {};
 	}
 }
 
 void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
 {
-	if(garrisonHero.get() == h)
+	if(getGarrisonHero() == h)
 		return;
 	
 	if(h)
@@ -820,25 +820,40 @@ void CGTownInstance::setGarrisonedHero(CGHeroInstance *h)
 		assert(p);
 		h->detachFrom(*p);
 		h->attachTo(*this);
-		garrisonHero = h;
-		h->visitedTown = this;
-		h->inTownGarrison = true;
+		h->setVisitedTown(this, true);
+		garrisonHero = h->id;
 	}
 	else
 	{
-		PlayerState *p = cb->gameState()->getPlayerState(garrisonHero->tempOwner);
-		garrisonHero->visitedTown = nullptr;
-		garrisonHero->inTownGarrison = false;
-		garrisonHero->detachFrom(*this);
-		garrisonHero->attachTo(*p);
-		garrisonHero = nullptr;
+		PlayerState *p = cb->gameState()->getPlayerState(getGarrisonHero()->tempOwner);
+		auto oldVisitor = dynamic_cast<CGHeroInstance*>(cb->gameState()->getObjInstance(visitingHero));
+		oldVisitor->setVisitedTown(nullptr, false);
+		oldVisitor->detachFrom(*this);
+		oldVisitor->attachTo(*p);
+		garrisonHero = {};
 	}
 	updateMoraleBonusFromArmy(); //avoid giving morale bonus for same army twice
 }
 
+const CGHeroInstance * CGTownInstance::getVisitingHero() const
+{
+	if (!visitingHero.hasValue())
+		return nullptr;
+
+	return cb->getHero(visitingHero);
+}
+
+const CGHeroInstance * CGTownInstance::getGarrisonHero() const
+{
+	if (!garrisonHero.hasValue())
+		return nullptr;
+
+	return cb->getHero(garrisonHero);
+}
+
 bool CGTownInstance::armedGarrison() const
 {
-	return !stacks.empty() || garrisonHero;
+	return !stacks.empty() || getGarrisonHero();
 }
 
 int CGTownInstance::getTownLevel() const
@@ -876,8 +891,8 @@ void CGTownInstance::setNameTextId( const std::string & newName )
 
 const CArmedInstance * CGTownInstance::getUpperArmy() const
 {
-	if(garrisonHero)
-		return garrisonHero;
+	if(getGarrisonHero())
+		return getGarrisonHero();
 	return this;
 }
 
@@ -1014,9 +1029,9 @@ CBuilding::TRequired CGTownInstance::genBuildingRequirements(const BuildingID &
 
 void CGTownInstance::addHeroToStructureVisitors(const CGHeroInstance *h, si64 structureInstanceID ) const
 {
-	if(visitingHero == h)
+	if(getVisitingHero() == h)
 		cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_VISITING_HERO, structureInstanceID); //add to visitors
-	else if(garrisonHero == h)
+	else if(getGarrisonHero() == h)
 		cb->setObjPropertyValue(id, ObjProperty::STRUCTURE_ADD_GARRISONED_HERO, structureInstanceID); //then it must be garrisoned hero
 	else
 	{

+ 5 - 3
lib/mapObjects/CGTownInstance.h

@@ -11,7 +11,6 @@
 
 #include "IMarket.h"
 #include "CGDwelling.h"
-#include "../ConstTransitivePtr.h"
 #include "../entities/faction/CFaction.h" // TODO: remove
 #include "../entities/faction/CTown.h" // TODO: remove
 
@@ -57,13 +56,14 @@ class DLL_LINKAGE CGTownInstance : public CGDwelling, public IShipyard, public I
 	std::map<BuildingID, TownRewardableBuildingInstance*> convertOldBuildings(std::vector<TownRewardableBuildingInstance*> oldVector);
 	std::set<BuildingID> builtBuildings;
 
+	ObjectInstanceID garrisonHero;
+	ObjectInstanceID visitingHero;
 public:
 	enum EFortLevel {NONE = 0, FORT = 1, CITADEL = 2, CASTLE = 3};
 
 	CTownAndVisitingHero townAndVis;
 	si32 built; //how many buildings has been built this turn
 	si32 destroyed; //how many buildings has been destroyed this turn
-	ConstTransitivePtr<CGHeroInstance> garrisonHero, visitingHero;
 	ui32 identifier; //special identifier from h3m (only > RoE maps)
 	PlayerColor alignmentToPlayer; // if set to non-neutral, random town will have same faction as specified player
 	std::set<BuildingID> forbiddenBuildings;
@@ -115,6 +115,8 @@ public:
 	void setVisitingHero(CGHeroInstance *h);
 	void setGarrisonedHero(CGHeroInstance *h);
 	const CArmedInstance *getUpperArmy() const; //garrisoned hero if present or the town itself
+	const CGHeroInstance * getVisitingHero() const;
+	const CGHeroInstance * getGarrisonHero() const;
 
 	std::string getNameTranslated() const;
 	std::string getNameTextID() const;
@@ -211,7 +213,7 @@ public:
 
 	inline bool isBattleOutsideTown(const CGHeroInstance * defendingHero) const
 	{
-		return defendingHero && garrisonHero && defendingHero != garrisonHero;
+		return defendingHero && getGarrisonHero() && defendingHero != getGarrisonHero();
 	}
 protected:
 	void setPropertyDer(ObjProperty what, ObjPropertyID identifier) override;

+ 1 - 1
lib/mapObjects/MiscObjects.cpp

@@ -616,7 +616,7 @@ bool CGWhirlpool::isProtected(const CGHeroInstance * h)
 {
 	return h->hasBonusOfType(BonusType::WHIRLPOOL_PROTECTION)
 		|| (h->stacksCount() == 1 && h->Slots().begin()->second->count == 1)
-		|| (h->stacksCount() == 0 && h->commander && h->commander->alive);
+		|| (h->stacksCount() == 0 && h->getCommander() && h->getCommander()->alive);
 }
 
 ArtifactID CGArtifact::getArtifact() const

+ 12 - 13
lib/networkPacks/NetPacksLib.cpp

@@ -872,7 +872,7 @@ void SetSecSkill::applyGs(CGameState *gs)
 
 void SetCommanderProperty::applyGs(CGameState *gs)
 {
-	CCommanderInstance * commander = gs->getHero(heroid)->commander;
+	const auto & commander = gs->getHero(heroid)->getCommander();
 	assert (commander);
 
 	switch (which)
@@ -1219,15 +1219,14 @@ void RemoveObject::applyGs(CGameState *gs)
 			return asi.artifact->getTypeId() == ArtifactID::GRAIL;
 		});
 
-		if(beatenHero->visitedTown)
+		if(beatenHero->getVisitedTown())
 		{
-			if(beatenHero->visitedTown->garrisonHero == beatenHero)
-				beatenHero->visitedTown->garrisonHero = nullptr;
+			if(beatenHero->getVisitedTown()->getGarrisonHero() == beatenHero)
+				beatenHero->getVisitedTown()->setGarrisonedHero(nullptr);
 			else
-				beatenHero->visitedTown->visitingHero = nullptr;
+				beatenHero->getVisitedTown()->setVisitingHero(nullptr);
 
-			beatenHero->visitedTown = nullptr;
-			beatenHero->inTownGarrison = false;
+			beatenHero->setVisitedTown(nullptr, false);
 		}
 		//return hero to the pool, so he may reappear in tavern
 
@@ -1403,8 +1402,8 @@ void SetHeroesInTown::applyGs(CGameState *gs)
 	CGHeroInstance * v = gs->getHero(visiting);
 	CGHeroInstance * g = gs->getHero(garrison);
 
-	bool newVisitorComesFromGarrison = v && v == t->garrisonHero;
-	bool newGarrisonComesFromVisiting = g && g == t->visitingHero;
+	bool newVisitorComesFromGarrison = v && v == t->getGarrisonHero();
+	bool newGarrisonComesFromVisiting = g && g == t->getVisitingHero();
 
 	if(newVisitorComesFromGarrison)
 		t->setGarrisonedHero(nullptr);
@@ -1493,7 +1492,7 @@ void GiveHero::applyGs(CGameState *gs)
 	gs->getPlayerState(h->getOwner())->addOwnedObject(h);
 
 	gs->getMap().addBlockVisTiles(h);
-	h->inTownGarrison = false;
+	h->setVisitedTown(nullptr, false);
 }
 
 void NewObject::applyGs(CGameState *gs)
@@ -2032,7 +2031,7 @@ void CommanderLevelUp::applyGs(CGameState *gs)
 {
 	auto * hero = gs->getHero(heroId);
 	assert(hero);
-	auto commander = hero->commander;
+	const auto & commander = hero->getCommander();
 	assert(commander);
 	commander->levelUp();
 }
@@ -2128,9 +2127,9 @@ void BattleResultAccepted::applyGs(CGameState *gs)
 		// Grow up growing artifacts
 		if(const auto winnerHero = gs->getHero(heroResult[winnerSide].heroId))
 		{
-			if(winnerHero->commander && winnerHero->commander->alive)
+			if(winnerHero->getCommander() && winnerHero->getCommander()->alive)
 			{
-				for(auto & art : winnerHero->commander->artifactsWorn)
+				for(auto & art : winnerHero->getCommander()->artifactsWorn)
 					art.second.artifact->growingUp();
 			}
 			for(auto & art : winnerHero->artifactsWorn)

+ 1 - 1
lib/pathfinder/CPathfinder.cpp

@@ -268,7 +268,7 @@ TeleporterTilesVector CPathfinderHelper::getCastleGates(const PathNodeInfo & sou
 
 	for(const auto & town : getPlayerState(hero->tempOwner)->getTowns())
 	{
-		if(town->id != source.nodeObject->id && town->visitingHero == nullptr
+		if(town->id != source.nodeObject->id && town->getVisitingHero() == nullptr
 			&& town->hasBuilt(BuildingSubID::CASTLE_GATE))
 		{
 			allowedExits.push_back(town->visitablePos());

+ 2 - 2
lib/serializer/BinaryDeserializer.h

@@ -70,8 +70,8 @@ class BinaryDeserializer : public CLoaderBase
 		{
 			auto * hero = dynamic_cast<CGHeroInstance *>(armyPtr);
 			assert(hero);
-			assert(hero->commander);
-			data = hero->commander;
+			assert(hero->getCommander());
+			data = hero->getCommander();
 		}
 		return true;
 	}

+ 4 - 4
lib/spells/AdventureSpellMechanics.cpp

@@ -43,7 +43,7 @@ bool AdventureSpellMechanics::canBeCast(spells::Problem & problem, const CGameIn
 
 	if (heroCaster)
 	{
-		if(heroCaster->inTownGarrison)
+		if(heroCaster->isGarrisoned())
 			return false;
 
 		const auto level = heroCaster->getSpellSchoolLevel(owner);
@@ -467,7 +467,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
 		if(static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()) < moveCost)
 			return ESpellCastResult::ERROR;
 
-		if(destination->visitingHero)
+		if(destination->getVisitingHero())
 		{
 			InfoWindow iw;
 			iw.player = parameters.caster->getCasterOwner();
@@ -520,7 +520,7 @@ ESpellCastResult TownPortalMechanics::applyAdventureEffects(SpellCastEnvironment
 			return ESpellCastResult::ERROR;
 		}
 
-		if(destination->visitingHero)
+		if(destination->getVisitingHero())
 		{
 			env->complain("[Internal error] Can't teleport to occupied town");
 			return ESpellCastResult::ERROR;
@@ -635,7 +635,7 @@ ESpellCastResult TownPortalMechanics::beginCast(SpellCastEnvironment * env, cons
 
 		for(const auto * t : towns)
 		{
-			if(t->visitingHero == nullptr) //empty town
+			if(t->getVisitingHero() == nullptr) //empty town
 				request.objects.push_back(t->id);
 		}
 

+ 1 - 1
mapeditor/maphandler.cpp

@@ -174,7 +174,7 @@ void setPlayerColor(QImage * sur, PlayerColor player)
 std::shared_ptr<QImage> MapHandler::getObjectImage(const CGObjectInstance * obj)
 {
 	if(	!obj
-	   || (obj->ID==Obj::HERO && static_cast<const CGHeroInstance*>(obj)->inTownGarrison) //garrisoned hero
+	   || (obj->ID==Obj::HERO && static_cast<const CGHeroInstance*>(obj)->isGarrisoned()) //garrisoned hero
 	   || (obj->ID==Obj::BOAT && static_cast<const CGBoat*>(obj)->hero)) //boat with hero (hero graphics is used)
 	{
 		return nullptr;

+ 46 - 46
server/CGameHandler.cpp

@@ -334,8 +334,8 @@ void CGameHandler::expGiven(const CGHeroInstance *hero)
 {
 	if (hero->gainsLevel())
 		levelUpHero(hero);
-	else if (hero->commander && hero->commander->gainsLevel())
-		levelUpCommander(hero->commander);
+	else if (hero->getCommander() && hero->getCommander()->gainsLevel())
+		levelUpCommander(hero->getCommander());
 
 	//if (hero->commander && hero->level > hero->commander->level && hero->commander->gainsLevel())
 // 		levelUpCommander(hero->commander);
@@ -375,7 +375,7 @@ void CGameHandler::giveExperience(const CGHeroInstance * hero, TExpType amountTo
 	sendAndApply(sps);
 
 	//hero may level up
-	if (hero->commander && hero->commander->alive)
+	if (hero->getCommander() && hero->getCommander()->alive)
 	{
 		//FIXME: trim experience according to map limit?
 		SetCommanderProperty scp;
@@ -412,8 +412,8 @@ void CGameHandler::changeSecSkill(const CGHeroInstance * hero, SecondarySkill wh
 	sss.abs = abs;
 	sendAndApply(sss);
 
-	if (hero->visitedTown)
-		giveSpells(hero->visitedTown, hero);
+	if (hero->getVisitedTown())
+		giveSpells(hero->getVisitedTown(), hero);
 
 	// Our scouting range may have changed - update it
 	if (hero->getOwner().isValidPlayer())
@@ -893,7 +893,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
 	if(distance(h->pos, dst) >= 1.5 && movementMode == EMovementMode::STANDARD)
 		return complainRet("Tiles " + h->pos.toString()+ " and "+ dst.toString() +" are not neighboring!");
 
-	if(h->inTownGarrison)
+	if(h->isGarrisoned())
 		return complainRet("Can not move garrisoned hero!");
 
 	if(h->movementPointsRemaining() < cost && dst != h->pos && movementMode == EMovementMode::STANDARD)
@@ -1048,7 +1048,7 @@ bool CGameHandler::teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui
 	if (!h || !t)
 		COMPLAIN_RET("Invalid call to teleportHero!");
 
-	const CGTownInstance *from = h->visitedTown;
+	const CGTownInstance *from = h->getVisitedTown();
 	if (((h->getOwner() != t->getOwner())
 		&& complain("Cannot teleport hero to another player"))
 
@@ -1186,7 +1186,7 @@ void CGameHandler::takeCreatures(ObjectInstanceID objid, const std::vector<CStac
 
 void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInstance * hero)
 {
-	if (obj->visitingHero != hero && obj->garrisonHero != hero)
+	if (obj->getVisitingHero() != hero && obj->getGarrisonHero() != hero)
 	{
 		HeroVisitCastle vc;
 		vc.hid = hero->id;
@@ -1196,8 +1196,8 @@ void CGameHandler::heroVisitCastle(const CGTownInstance * obj, const CGHeroInsta
 	}
 	visitCastleObjects(obj, hero);
 
-	if (obj->visitingHero && obj->garrisonHero)
-		useScholarSkill(obj->visitingHero->id, obj->garrisonHero->id);
+	if (obj->getVisitingHero() && obj->getGarrisonHero())
+		useScholarSkill(obj->getVisitingHero()->id, obj->getGarrisonHero()->id);
 	checkVictoryLossConditionsForPlayer(hero->tempOwner); //transported artifact?
 }
 
@@ -2073,10 +2073,10 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
 		case CBuilding::BUILD_GRAIL  :
 			if(requestedBuilding->mode == CBuilding::BUILD_GRAIL) //needs grail
 			{
-				if(!t->visitingHero || !t->visitingHero->hasArt(ArtifactID::GRAIL))
+				if(!t->getVisitingHero() || !t->getVisitingHero()->hasArt(ArtifactID::GRAIL))
 					COMPLAIN_RET("Cannot build this without grail!")
 				else
-					removeArtifact(ArtifactLocation(t->visitingHero->id, t->visitingHero->getArtPos(ArtifactID::GRAIL, false)));
+					removeArtifact(ArtifactLocation(t->getVisitingHero()->id, t->getVisitingHero()->getArtPos(ArtifactID::GRAIL, false)));
 			}
 			break;
 		}
@@ -2123,10 +2123,10 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
 
 		if(isMageGuild || isLibrary || (t->getFactionID() == ETownType::CONFLUX && buildingID == BuildingID::GRAIL))
 		{
-			if(t->visitingHero)
-				giveSpells(t,t->visitingHero);
-			if(t->garrisonHero)
-				giveSpells(t,t->garrisonHero);
+			if(t->getVisitingHero())
+				giveSpells(t,t->getVisitingHero());
+			if(t->getGarrisonHero())
+				giveSpells(t,t->getGarrisonHero());
 		}
 	};
 
@@ -2201,10 +2201,10 @@ bool CGameHandler::buildStructure(ObjectInstanceID tid, BuildingID requestedID,
 	{
 		//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
 		std::vector<const CGHeroInstance *> visitors;
-		if (t->garrisonHero)
-			visitors.push_back(t->garrisonHero);
-		if (t->visitingHero)
-			visitors.push_back(t->visitingHero);
+		if (t->getGarrisonHero())
+			visitors.push_back(t->getGarrisonHero());
+		if (t->getVisitingHero())
+			visitors.push_back(t->getVisitingHero());
 
 		if (!visitors.empty())
 			visitCastleObjects(t, visitors);
@@ -2233,12 +2233,12 @@ bool CGameHandler::visitTownBuilding(ObjectInstanceID tid, BuildingID bid)
 		return true;
 	}
 
-	if (t->rewardableBuildings.count(bid) && t->visitingHero && t->getTown()->buildings.at(bid)->manualHeroVisit)
+	if (t->rewardableBuildings.count(bid) && t->getVisitingHero() && t->getTown()->buildings.at(bid)->manualHeroVisit)
 	{
 		std::vector<BuildingID> buildingsToVisit;
 		std::vector<const CGHeroInstance*> visitors;
 		buildingsToVisit.push_back(bid);
-		visitors.push_back(t->visitingHero);
+		visitors.push_back(t->getVisitingHero());
 		auto visitQuery = std::make_shared<TownBuildingVisitQuery>(this, t, visitors, buildingsToVisit);
 		queries->addQuery(visitQuery);
 		return true;
@@ -2316,10 +2316,10 @@ bool CGameHandler::spellResearch(ObjectInstanceID tid, SpellID spellAtSlot, bool
 
 	setResearchedSpells(t, level, spells, accepted);
 
-	if(t->visitingHero)
-		giveSpells(t, t->visitingHero);
-	if(t->garrisonHero)
-		giveSpells(t, t->garrisonHero);
+	if(t->getVisitingHero())
+		giveSpells(t, t->getVisitingHero());
+	if(t->getGarrisonHero())
+		giveSpells(t, t->getGarrisonHero());
 
 	return true;
 }
@@ -2342,7 +2342,7 @@ bool CGameHandler::recruitCreatures(ObjectInstanceID objid, ObjectInstanceID dst
 	if (town)
 	{
 		COMPLAIN_RET_FALSE_IF(town != army && !hero, "Cannot recruit: invalid destination!");
-		COMPLAIN_RET_FALSE_IF(hero != town->garrisonHero && hero != town->visitingHero, "Cannot recruit: can only recruit to town or hero in town!!");
+		COMPLAIN_RET_FALSE_IF(hero != town->getGarrisonHero() && hero != town->getVisitingHero(), "Cannot recruit: can only recruit to town or hero in town!!");
 	}
 	else
 	{
@@ -2505,16 +2505,16 @@ bool CGameHandler::swapGarrisonOnSiege(ObjectInstanceID tid)
 {
 	const CGTownInstance * town = getTown(tid);
 
-	if(!town->garrisonHero == !town->visitingHero)
+	if(!town->getGarrisonHero() == !town->getVisitingHero())
 		return false;
 
 	SetHeroesInTown intown;
 	intown.tid = tid;
 
-	if(town->garrisonHero) //garrison -> vising
+	if(town->getGarrisonHero()) //garrison -> vising
 	{
 		intown.garrison = ObjectInstanceID();
-		intown.visiting = town->garrisonHero->id;
+		intown.visiting = town->getGarrisonHero()->id;
 	}
 	else //visiting -> garrison
 	{
@@ -2522,7 +2522,7 @@ bool CGameHandler::swapGarrisonOnSiege(ObjectInstanceID tid)
 			town->mergeGarrisonOnSiege();
 
 		intown.visiting = ObjectInstanceID();
-		intown.garrison = town->visitingHero->id;
+		intown.garrison = town->getVisitingHero()->id;
 	}
 	sendAndApply(intown);
 	return true;
@@ -2531,29 +2531,29 @@ bool CGameHandler::swapGarrisonOnSiege(ObjectInstanceID tid)
 bool CGameHandler::garrisonSwap(ObjectInstanceID tid)
 {
 	const CGTownInstance * town = getTown(tid);
-	if (!town->garrisonHero && town->visitingHero) //visiting => garrison, merge armies: town army => hero army
+	if (!town->getGarrisonHero() && town->getVisitingHero()) //visiting => garrison, merge armies: town army => hero army
 	{
 
-		if (!town->visitingHero->canBeMergedWith(*town))
+		if (!town->getVisitingHero()->canBeMergedWith(*town))
 		{
 			complain("Cannot make garrison swap, not enough free slots!");
 			return false;
 		}
 
-		moveArmy(town, town->visitingHero, true);
+		moveArmy(town, town->getVisitingHero(), true);
 
 		SetHeroesInTown intown;
 		intown.tid = tid;
 		intown.visiting = ObjectInstanceID();
-		intown.garrison = town->visitingHero->id;
+		intown.garrison = town->getVisitingHero()->id;
 		sendAndApply(intown);
 		return true;
 	}
-	else if (town->garrisonHero && !town->visitingHero) //move hero out of the garrison
+	else if (town->getGarrisonHero() && !town->getVisitingHero()) //move hero out of the garrison
 	{
 		int mapCap = getSettings().getInteger(EGameSettings::HEROES_PER_PLAYER_ON_MAP_CAP);
 		//check if moving hero out of town will break wandering heroes limit
-		if (getHeroCount(town->garrisonHero->tempOwner,false) >= mapCap)
+		if (getHeroCount(town->getGarrisonHero()->tempOwner,false) >= mapCap)
 		{
 			complain("Cannot move hero out of the garrison, there are already " + std::to_string(mapCap) + " wandering heroes!");
 			return false;
@@ -2562,16 +2562,16 @@ bool CGameHandler::garrisonSwap(ObjectInstanceID tid)
 		SetHeroesInTown intown;
 		intown.tid = tid;
 		intown.garrison = ObjectInstanceID();
-		intown.visiting =  town->garrisonHero->id;
+		intown.visiting =  town->getGarrisonHero()->id;
 		sendAndApply(intown);
 		return true;
 	}
-	else if (!!town->garrisonHero && town->visitingHero) //swap visiting and garrison hero
+	else if (!!town->getGarrisonHero() && town->getVisitingHero()) //swap visiting and garrison hero
 	{
 		SetHeroesInTown intown;
 		intown.tid = tid;
-		intown.garrison = town->visitingHero->id;
-		intown.visiting =  town->garrisonHero->id;
+		intown.garrison = town->getVisitingHero()->id;
+		intown.visiting =  town->getGarrisonHero()->id;
 		sendAndApply(intown);
 		return true;
 	}
@@ -2991,7 +2991,7 @@ bool CGameHandler::buyArtifact(ObjectInstanceID hid, ArtifactID aid)
 {
 	const CGHeroInstance * hero = getHero(hid);
 	COMPLAIN_RET_FALSE_IF(nullptr == hero, "Invalid hero index");
-	const CGTownInstance * town = hero->visitedTown;
+	const CGTownInstance * town = hero->getVisitedTown();
 	COMPLAIN_RET_FALSE_IF(nullptr == town, "Hero not in town");
 
 	if (aid==ArtifactID::SPELLBOOK)
@@ -3342,13 +3342,13 @@ bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)
 		if (o1->ID == Obj::TOWN)
 		{
 			const CGTownInstance *t = static_cast<const CGTownInstance*>(o1);
-			if (t->visitingHero == o2  ||  t->garrisonHero == o2)
+			if (t->getVisitingHero() == o2  ||  t->getGarrisonHero() == o2)
 				return true;
 		}
 		if (o2->ID == Obj::TOWN)
 		{
 			const CGTownInstance *t = static_cast<const CGTownInstance*>(o2);
-			if (t->visitingHero == o1  ||  t->garrisonHero == o1)
+			if (t->getVisitingHero() == o1  ||  t->getGarrisonHero() == o1)
 				return true;
 		}
 
@@ -3364,7 +3364,7 @@ bool CGameHandler::isAllowedExchange(ObjectInstanceID id1, ObjectInstanceID id2)
 			const CGHeroInstance *h2 = static_cast<const CGHeroInstance*>(o2);
 
 			// two heroes in same town (garrisoned and visiting)
-			if (h1->visitedTown != nullptr && h2->visitedTown != nullptr && h1->visitedTown == h2->visitedTown)
+			if (h1->getVisitedTown() != nullptr && h2->getVisitedTown() != nullptr && h1->getVisitedTown() == h2->getVisitedTown())
 				return true;
 		}
 
@@ -3408,7 +3408,7 @@ void CGameHandler::objectVisited(const CGObjectInstance * obj, const CGHeroInsta
 		if(obj->ID == Obj::HERO)
 		{
 			auto visitedHero = static_cast<const CGHeroInstance *>(obj);
-			const auto visitedTown = visitedHero->visitedTown;
+			const auto visitedTown = visitedHero->getVisitedTown();
 
 			if(visitedTown)
 			{

+ 1 - 1
server/NetPacksServer.cpp

@@ -183,7 +183,7 @@ void ApplyGhNetPackVisitor::visitUpgradeCreature(UpgradeCreature & pack)
 void ApplyGhNetPackVisitor::visitGarrisonHeroSwap(GarrisonHeroSwap & pack)
 {
 	const CGTownInstance * town = gh.getTown(pack.tid);
-	if(!gh.isPlayerOwns(connection, &pack, pack.tid) && !(town->garrisonHero && gh.isPlayerOwns(connection, &pack, town->garrisonHero->id)))
+	if(!gh.isPlayerOwns(connection, &pack, pack.tid) && !(town->getGarrisonHero() && gh.isPlayerOwns(connection, &pack, town->getGarrisonHero()->id)))
 		gh.throwNotAllowedAction(connection); //neither town nor garrisoned hero (if present) is ours
 	gh.throwIfPlayerNotActive(connection, &pack);
 

+ 9 - 9
server/battles/BattleResultProcessor.cpp

@@ -106,7 +106,7 @@ CasualtiesAfterBattle::CasualtiesAfterBattle(const CBattleInfoCallback & battle,
 				if(c)
 				{
 					auto h = dynamic_cast <const CGHeroInstance *>(army);
-					if(h && h->commander == c && (st->getCount() == 0 || !st->alive()))
+					if(h && h->getCommander() == c && (st->getCount() == 0 || !st->alive()))
 					{
 						logGlobal->debug("Commander is dead.");
 						heroWithDeadCommander = army->id; //TODO: unify commander handling
@@ -323,11 +323,11 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 
 	if(battleResult->winner == BattleSide::DEFENDER
 	   && winnerHero
-	   && winnerHero->visitedTown
-	   && !winnerHero->inTownGarrison
-	   && winnerHero->visitedTown->garrisonHero == winnerHero)
+	   && winnerHero->getVisitedTown()
+	   && !winnerHero->isGarrisoned()
+	   && winnerHero->getVisitedTown()->getGarrisonHero() == winnerHero)
 	{
-		gameHandler->swapGarrisonOnSiege(winnerHero->visitedTown->id); //return defending visitor from garrison to its rightful place
+		gameHandler->swapGarrisonOnSiege(winnerHero->getVisitedTown()->id); //return defending visitor from garrison to its rightful place
 	}
 	//give exp
 	if(!finishingBattle->isDraw() && battleResult->exp[finishingBattle->winnerSide] && winnerHero)
@@ -336,7 +336,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 	// Add statistics
 	if(loserHero && !finishingBattle->isDraw())
 	{
-		ConstTransitivePtr<CGHeroInstance> strongestHero = nullptr;
+		const CGHeroInstance * strongestHero = nullptr;
 		for(auto & hero : gameHandler->gameState()->getPlayerState(finishingBattle->loser)->getHeroes())
 			if(!strongestHero || hero->exp > strongestHero->exp)
 				strongestHero = hero;
@@ -460,11 +460,11 @@ void BattleResultProcessor::battleFinalize(const BattleID & battleID, const Batt
 					addArtifactToTransfer(packHero, loserHero->getArtPos(art), art);
 			}
 
-			if(loserHero->commander)
+			if(loserHero->getCommander())
 			{
 				auto & packCommander = resultsApplied.artifacts.emplace_back(finishingBattle->victor, finishingBattle->loserId, finishingBattle->winnerId, false);
-				packCommander.srcCreature = loserHero->findStack(loserHero->commander);
-				for(const auto & artSlot : loserHero->commander->artifactsWorn)
+				packCommander.srcCreature = loserHero->findStack(loserHero->getCommander());
+				for(const auto & artSlot : loserHero->getCommander()->artifactsWorn)
 					addArtifactToTransfer(packCommander, artSlot.first, artSlot.second.getArt());
 			}
 			auto armyObj = dynamic_cast<const CArmedInstance*>(gameHandler->getObj(finishingBattle->loserId));

+ 1 - 1
server/processors/HeroPoolProcessor.cpp

@@ -185,7 +185,7 @@ bool HeroPoolProcessor::hireHero(const ObjectInstanceID & objectID, const HeroTy
 		if(!town->hasBuilt(BuildingID::TAVERN) && gameHandler->complain("No tavern!"))
 			return false;
 
-		if(town->visitingHero && gameHandler->complain("There is visiting hero - no place!"))
+		if(town->getVisitingHero() && gameHandler->complain("There is visiting hero - no place!"))
 			return false;
 	}
 

+ 4 - 4
server/processors/NewTurnProcessor.cpp

@@ -143,11 +143,11 @@ void NewTurnProcessor::onPlayerTurnStarted(PlayerColor which)
 	for (const auto * t : playerState->getTowns())
 	{
 		//garrison hero first - consistent with original H3 Mana Vortex and Battle Scholar Academy levelup windows order
-		if (t->garrisonHero != nullptr)
-			gameHandler->objectVisited(t, t->garrisonHero);
+		if (t->getGarrisonHero() != nullptr)
+			gameHandler->objectVisited(t, t->getGarrisonHero());
 
-		if (t->visitingHero != nullptr)
-			gameHandler->objectVisited(t, t->visitingHero);
+		if (t->getVisitingHero() != nullptr)
+			gameHandler->objectVisited(t, t->getVisitingHero());
 	}
 }
 

+ 1 - 1
server/processors/PlayerMessageProcessor.cpp

@@ -773,7 +773,7 @@ void PlayerMessageProcessor::executeCheatCode(const std::string & cheatName, Pla
 	const CGHeroInstance * hero = gameHandler->getHero(currObj);
 	const CGTownInstance * town = gameHandler->getTown(currObj);
 	if (!town && hero)
-		town = hero->visitedTown;
+		town = hero->getVisitedTown();
 
 	const auto & doCheatGiveSpells = [&]() { cheatGiveSpells(player, hero); };
 	const auto & doCheatBuildTown = [&]() { cheatBuildTown(player, town); };

+ 1 - 1
server/queries/MapQueries.cpp

@@ -237,7 +237,7 @@ void CCommanderLevelUpDialogQuery::onRemoval(PlayerColor color)
 {
 	assert(answer);
 	logGlobal->trace("Completing commander level-up query. Commander of hero %s gains skill %s", hero->getObjectName(), answer.value());
-	gh->levelUpCommander(hero->commander, clu.skills[*answer]);
+	gh->levelUpCommander(hero->getCommander(), clu.skills[*answer]);
 }
 
 void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CGObjectInstance * visitedObject, const CGHeroInstance * visitingHero) const