浏览代码

Merge pull request #5266 from MichalZr6/battlefield

Minor fixes to BattleHexArray. BattleHex'es as const reference where possible.
Ivan Savenko 9 月之前
父节点
当前提交
f858a6e04b
共有 63 个文件被更改,包括 347 次插入359 次删除
  1. 7 7
      AI/BattleAI/AttackPossibility.cpp
  2. 2 2
      AI/BattleAI/AttackPossibility.h
  3. 2 2
      AI/BattleAI/BattleAI.cpp
  4. 11 13
      AI/BattleAI/BattleEvaluator.cpp
  5. 1 1
      AI/BattleAI/BattleEvaluator.h
  6. 15 15
      AI/BattleAI/BattleExchangeVariant.cpp
  7. 4 4
      AI/BattleAI/BattleExchangeVariant.h
  8. 2 2
      AI/BattleAI/PotentialTargets.cpp
  9. 1 1
      AI/BattleAI/StackWithBonuses.cpp
  10. 1 1
      AI/BattleAI/StackWithBonuses.h
  11. 4 4
      AI/StupidAI/StupidAI.cpp
  12. 16 16
      client/battle/BattleActionsController.cpp
  13. 16 16
      client/battle/BattleActionsController.h
  14. 20 31
      client/battle/BattleFieldController.cpp
  15. 9 9
      client/battle/BattleFieldController.h
  16. 5 5
      client/battle/BattleInterface.cpp
  17. 5 5
      client/battle/BattleInterface.h
  18. 1 1
      client/battle/BattleOverlayLogVisualizer.cpp
  19. 1 1
      client/battle/BattleOverlayLogVisualizer.h
  20. 1 1
      client/battle/BattleRenderer.cpp
  21. 1 1
      client/battle/BattleRenderer.h
  22. 2 2
      client/battle/BattleSiegeController.cpp
  23. 2 2
      client/battle/BattleSiegeController.h
  24. 1 1
      client/battle/BattleStacksController.cpp
  25. 1 1
      client/battle/BattleStacksController.h
  26. 1 1
      lib/CStack.cpp
  27. 1 1
      lib/ObstacleHandler.cpp
  28. 1 1
      lib/ObstacleHandler.h
  29. 3 3
      lib/battle/AccessibilityInfo.cpp
  30. 3 3
      lib/battle/AccessibilityInfo.h
  31. 2 2
      lib/battle/BattleAction.cpp
  32. 2 2
      lib/battle/BattleAction.h
  33. 3 3
      lib/battle/BattleHex.cpp
  34. 19 15
      lib/battle/BattleHex.h
  35. 5 5
      lib/battle/BattleHexArray.cpp
  36. 39 36
      lib/battle/BattleHexArray.h
  37. 8 8
      lib/battle/BattleInfo.cpp
  38. 3 3
      lib/battle/BattleInfo.h
  39. 50 50
      lib/battle/CBattleInfoCallback.cpp
  40. 21 21
      lib/battle/CBattleInfoCallback.h
  41. 1 1
      lib/battle/CUnitState.cpp
  42. 1 1
      lib/battle/CUnitState.h
  43. 2 2
      lib/battle/IBattleInfoCallback.h
  44. 1 1
      lib/battle/IBattleState.h
  45. 4 4
      lib/battle/ReachabilityInfo.cpp
  46. 2 2
      lib/battle/ReachabilityInfo.h
  47. 11 17
      lib/battle/Unit.cpp
  48. 8 8
      lib/battle/Unit.h
  49. 2 2
      lib/bonuses/Limiters.cpp
  50. 3 3
      lib/logging/VisualLogger.h
  51. 3 3
      lib/spells/BattleSpellMechanics.cpp
  52. 2 2
      lib/spells/BattleSpellMechanics.h
  53. 1 1
      lib/spells/CSpellHandler.cpp
  54. 1 1
      lib/spells/ISpellMechanics.h
  55. 1 1
      lib/spells/effects/DemonSummon.cpp
  56. 1 1
      lib/spells/effects/Heal.cpp
  57. 2 2
      lib/spells/effects/UnitEffect.cpp
  58. 4 4
      server/battles/BattleActionProcessor.cpp
  59. 1 1
      server/battles/BattleActionProcessor.h
  60. 1 1
      server/battles/BattleFlowProcessor.cpp
  61. 1 1
      test/mock/mock_battle_IBattleState.h
  62. 1 1
      test/mock/mock_battle_Unit.h
  63. 1 1
      test/mock/mock_spells_Mechanics.h

+ 7 - 7
AI/BattleAI/AttackPossibility.cpp

@@ -72,7 +72,7 @@ void DamageCache::buildObstacleDamageCache(std::shared_ptr<HypotheticBattle> hb,
 
 			auto damageDealt = stack->getAvailableHealth() - updated->getAvailableHealth();
 
-			for(auto hex : affectedHexes)
+			for(const auto & hex : affectedHexes)
 			{
 				obstacleDamage[hex][stack->unitId()] = damageDealt;
 			}
@@ -129,7 +129,7 @@ int64_t DamageCache::getDamage(const battle::Unit * attacker, const battle::Unit
 	return damageCache[attacker->unitId()][defender->unitId()] * attacker->getCount();
 }
 
-int64_t DamageCache::getObstacleDamage(BattleHex hex, const battle::Unit * defender)
+int64_t DamageCache::getObstacleDamage(const BattleHex & hex, const battle::Unit * defender)
 {
 	if(parent)
 		return parent->getObstacleDamage(hex, defender);
@@ -166,7 +166,7 @@ int64_t DamageCache::getOriginalDamage(const battle::Unit * attacker, const batt
 	return getDamage(attacker, defender, hb);
 }
 
-AttackPossibility::AttackPossibility(BattleHex from, BattleHex dest, const BattleAttackInfo & attack)
+AttackPossibility::AttackPossibility(const BattleHex & from, const BattleHex & dest, const BattleAttackInfo & attack)
 	: from(from), dest(dest), attack(attack)
 {
 	this->attack.attackerPos = from;
@@ -281,7 +281,7 @@ int64_t AttackPossibility::evaluateBlockedShootersDmg(
 
 	auto attacker = attackInfo.attacker;
 	const auto & hexes = attacker->getSurroundingHexes(hex);
-	for(BattleHex tile : hexes)
+	for(const BattleHex & tile : hexes)
 	{
 		auto st = state->battleGetUnitByPos(tile, true);
 		if(!st || !state->battleMatchOwner(st, attacker))
@@ -332,7 +332,7 @@ AttackPossibility AttackPossibility::evaluate(
 	else
 		defenderHex = CStack::meleeAttackHexes(attacker, defender, hex);
 
-	for(BattleHex defHex : defenderHex)
+	for(const BattleHex & defHex : defenderHex)
 	{
 		if(defHex == hex) // should be impossible but check anyway
 			continue;
@@ -489,7 +489,7 @@ AttackPossibility AttackPossibility::evaluate(
 		logAi->trace("BattleAI AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
 			attackInfo.attacker->unitType()->getJsonKey(),
 			attackInfo.defender->unitType()->getJsonKey(),
-			(int)ap.dest, (int)ap.from, (int)ap.affectedUnits.size(),
+			ap.dest.toInt(), ap.from.toInt(), (int)ap.affectedUnits.size(),
 			ap.defenderDamageReduce, ap.attackerDamageReduce, ap.collateralDamageReduce, ap.shootersBlockedDmg);
 #endif
 
@@ -504,7 +504,7 @@ AttackPossibility AttackPossibility::evaluate(
 	logAi->trace("BattleAI best AP: %s -> %s at %d from %d, affects %d units: d:%lld a:%lld c:%lld s:%lld",
 		attackInfo.attacker->unitType()->getJsonKey(),
 		attackInfo.defender->unitType()->getJsonKey(),
-		(int)bestAp.dest, (int)bestAp.from, (int)bestAp.affectedUnits.size(),
+		bestAp.dest.toInt(), bestAp.from.toInt(), (int)bestAp.affectedUnits.size(),
 		bestAp.defenderDamageReduce, bestAp.attackerDamageReduce, bestAp.collateralDamageReduce, bestAp.shootersBlockedDmg);
 #endif
 

+ 2 - 2
AI/BattleAI/AttackPossibility.h

@@ -29,7 +29,7 @@ public:
 
 	void cacheDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
 	int64_t getDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
-	int64_t getObstacleDamage(BattleHex hex, const battle::Unit * defender);
+	int64_t getObstacleDamage(const BattleHex & hex, const battle::Unit * defender);
 	int64_t getOriginalDamage(const battle::Unit * attacker, const battle::Unit * defender, std::shared_ptr<CBattleInfoCallback> hb);
 	void buildDamageCache(std::shared_ptr<HypotheticBattle> hb, BattleSide side);
 };
@@ -55,7 +55,7 @@ public:
 	int64_t shootersBlockedDmg = 0;
 	bool defenderDead = false;
 
-	AttackPossibility(BattleHex from, BattleHex dest, const BattleAttackInfo & attack_);
+	AttackPossibility(const BattleHex & from, const BattleHex & dest, const BattleAttackInfo & attack_);
 
 	float damageDiff() const;
 	float attackValue() const;

+ 2 - 2
AI/BattleAI/BattleAI.cpp

@@ -54,8 +54,8 @@ void logHexNumbers()
 #if BATTLE_TRACE_LEVEL >= 1
 	logVisual->updateWithLock("hexes", [](IVisualLogBuilder & b)
 		{
-			for(BattleHex hex = BattleHex(0); hex < GameConstants::BFIELD_SIZE; hex = BattleHex(hex + 1))
-				b.addText(hex, std::to_string(hex.hex));
+			for(BattleHex hex = BattleHex(0); hex < GameConstants::BFIELD_SIZE; ++hex)
+				b.addText(hex, std::to_string(hex.toInt()));
 		});
 #endif
 }

+ 11 - 13
AI/BattleAI/BattleEvaluator.cpp

@@ -327,7 +327,7 @@ uint64_t timeElapsed(std::chrono::time_point<std::chrono::steady_clock> start)
 	return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
 }
 
-BattleAction BattleEvaluator::moveOrAttack(const CStack * stack, BattleHex hex, const PotentialTargets & targets)
+BattleAction BattleEvaluator::moveOrAttack(const CStack * stack, const BattleHex & hex, const PotentialTargets & targets)
 {
 	auto additionalScore = 0;
 	std::optional<AttackPossibility> attackOnTheWay;
@@ -371,21 +371,19 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, const Battl
 
 	if (siegeDefense)
 	{
-		vstd::erase_if(avHexes, [&](const BattleHex& hex) {
+		vstd::erase_if(avHexes, [&](const BattleHex & hex) {
 			return !cb->getBattle(battleID)->battleIsInsideWalls(hex);
 		});
 	}
 
-	if(!avHexes.size() || !hexes.size()) //we are blocked or dest is blocked
+	if(avHexes.empty() || hexes.empty()) //we are blocked or dest is blocked
 	{
 		return BattleAction::makeDefend(stack);
 	}
 
 	BattleHexArray targetHexes = hexes;
 
-	vstd::erase_if(targetHexes, [](const BattleHex & hex) { return !hex.isValid(); });
-
-	std::sort(targetHexes.begin(), targetHexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
+	std::sort(targetHexes.begin(), targetHexes.end(), [&](const BattleHex & h1, const BattleHex & h2) -> bool
 		{
 			return reachability.distances[h1.toInt()] < reachability.distances[h2.toInt()];
 		});
@@ -399,9 +397,9 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, const Battl
 	}
 
 	// this turn
-	for(auto hex : targetHexes)
+	for(const auto & hex : targetHexes)
 	{
-		if(vstd::contains(avHexes, hex))
+		if(avHexes.contains(hex))
 		{
 			return moveOrAttack(stack, hex, targets);
 		}
@@ -436,14 +434,14 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, const Battl
 		}
 		// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
 		// We just check all available hexes and pick the one closest to the target.
-		auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int
+		auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](const BattleHex & hex) -> int
 		{
 			const int NEGATIVE_OBSTACLE_PENALTY = 100; // avoid landing on negative obstacle (moat, fire wall, etc)
 			const int BLOCKED_STACK_PENALTY = 100; // avoid landing on moat
 
 			auto distance = BattleHex::getDistance(bestNeighbour, hex);
 
-			if(vstd::contains(obstacleHexes, hex))
+			if(obstacleHexes.contains(hex))
 				distance += NEGATIVE_OBSTACLE_PENALTY;
 
 			return scoreEvaluator.checkPositionBlocksOurStacks(*hb, stack, hex) ? BLOCKED_STACK_PENALTY + distance : distance;
@@ -462,7 +460,7 @@ BattleAction BattleEvaluator::goTowardsNearest(const CStack * stack, const Battl
 				return BattleAction::makeDefend(stack);
 			}
 
-			if(vstd::contains(avHexes, currentDest)
+			if(avHexes.contains(currentDest)
 				&& !scoreEvaluator.checkPositionBlocksOurStacks(*hb, stack, currentDest))
 			{
 				return moveOrAttack(stack, currentDest, targets);
@@ -687,7 +685,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
 				else
 				{
 					auto psFirst = ps.dest.front();
-					auto strWhere = psFirst.unitValue ? psFirst.unitValue->getDescription() : std::to_string(psFirst.hexValue.hex);
+					auto strWhere = psFirst.unitValue ? psFirst.unitValue->getDescription() : std::to_string(psFirst.hexValue.toInt());
 
 					logAi->trace("Evaluating %s at %s", ps.spell->getNameTranslated(), strWhere);
 				}
@@ -805,7 +803,7 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
 							logAi->trace(
 								"Spell %s to %d affects %s (%d), dps: %2f oldHealth: %d newHealth: %d",
 								ps.spell->getNameTranslated(),
-								ps.dest.at(0).hexValue.hex,  // Safe to access .at(0) now
+								ps.dest.at(0).hexValue.toInt(),  // Safe to access .at(0) now
 								unit->creatureId().toCreature()->getNameSingularTranslated(),
 								unit->getCount(),
 								dpsReduce,

+ 1 - 1
AI/BattleAI/BattleEvaluator.h

@@ -56,7 +56,7 @@ public:
 	bool hasWorkingTowers() const;
 	void evaluateCreatureSpellcast(const CStack * stack, PossibleSpellcast & ps); //for offensive damaging spells only
 	void print(const std::string & text) const;
-	BattleAction moveOrAttack(const CStack * stack, BattleHex hex, const PotentialTargets & targets);
+	BattleAction moveOrAttack(const CStack * stack, const BattleHex & hex, const PotentialTargets & targets);
 
 	BattleEvaluator(
 		std::shared_ptr<Environment> env,

+ 15 - 15
AI/BattleAI/BattleExchangeVariant.cpp

@@ -349,7 +349,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
 		logAi->trace(
 			"Checking movement towards %d of %s",
 			enemy->getCount(),
-			enemy->creatureId().toCreature()->getNameSingularTranslated());
+			VLC->creatures()->getById(enemy->creatureId())->getJsonKey());
 
 		auto distance = dists.distToNearestNeighbour(activeStack, enemy);
 
@@ -427,7 +427,7 @@ MoveTarget BattleExchangeEvaluator::findMoveTowardsUnreachable(
 							if(defenderToBypass)
 							{
 #if BATTLE_TRACE_LEVEL >= 1
-								logAi->trace("Found target to bypass at %d", enemyHex.hex);
+								logAi->trace("Found target to bypass at %d", enemyHex.toInt());
 #endif
 
 								auto attackHex = dists.predecessors[enemyHex.toInt()];
@@ -486,7 +486,7 @@ battle::Units BattleExchangeEvaluator::getAdjacentUnits(const battle::Unit * blo
 		checkedStacks.push_back(stack);
 
 		auto const & hexes = stack->getSurroundingHexes();
-		for(auto hex : hexes)
+		for(const auto & hex : hexes)
 		{
 			auto neighbour = cb->battleGetUnitByPos(hex);
 
@@ -517,14 +517,14 @@ ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
 
 	battle::Units allReachableUnits = additionalUnits;
 	
-	for(auto hex : hexes)
+	for(const auto & hex : hexes)
 	{
 		vstd::concatenate(allReachableUnits, getOneTurnReachableUnits(turn, hex));
 	}
 
 	if(!ap.attack.attacker->isTurret())
 	{
-		for(auto hex : ap.attack.attacker->getHexes())
+		for(const auto & hex : ap.attack.attacker->getHexes())
 		{
 			auto unitsReachingAttacker = getOneTurnReachableUnits(turn, hex);
 			for(auto unit : unitsReachingAttacker)
@@ -577,7 +577,7 @@ ReachabilityData BattleExchangeEvaluator::getExchangeUnits(
 
 		if(!accessible)
 		{
-			for(auto hex : unit->getSurroundingHexes())
+			for(const auto & hex : unit->getSurroundingHexes())
 			{
 				if(ap.attack.defender->coversPos(hex))
 				{
@@ -639,7 +639,7 @@ BattleScore BattleExchangeEvaluator::calculateExchange(
 	battle::Units additionalUnits) const
 {
 #if BATTLE_TRACE_LEVEL>=1
-	logAi->trace("Battle exchange at %d", ap.attack.shooting ? ap.dest.hex : ap.from.hex);
+	logAi->trace("Battle exchange at %d", ap.attack.shooting ? ap.dest.toInt() : ap.from.toInt());
 #endif
 
 	if(cb->battleGetMySide() == BattleSide::LEFT_SIDE
@@ -927,7 +927,7 @@ void BattleExchangeEvaluator::updateReachabilityMap(std::shared_ptr<HypotheticBa
 	reachabilityMap.update(turnOrder, hb);
 }
 
-const battle::Units & ReachabilityMapCache::getOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, BattleHex hex)
+const battle::Units & ReachabilityMapCache::getOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, const BattleHex & hex)
 {
 	auto & turnData = hexReachabilityPerTurn[turn];
 
@@ -940,7 +940,7 @@ const battle::Units & ReachabilityMapCache::getOneTurnReachableUnits(std::shared
 	return turnData.hexes[hex.toInt()];
 }
 
-battle::Units ReachabilityMapCache::computeOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, BattleHex hex)
+battle::Units ReachabilityMapCache::computeOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, const BattleHex & hex)
 {
 	battle::Units result;
 
@@ -977,7 +977,7 @@ battle::Units ReachabilityMapCache::computeOneTurnReachableUnits(std::shared_ptr
 
 				if(hexStack && cb->battleMatchOwner(unit, hexStack, false))
 				{
-					for(BattleHex neighbour : hex.getNeighbouringTiles())
+					for(const BattleHex & neighbour : hex.getNeighbouringTiles())
 					{
 						reachable = unitReachability.distances.at(neighbour.toInt()) <= radius;
 
@@ -996,13 +996,13 @@ battle::Units ReachabilityMapCache::computeOneTurnReachableUnits(std::shared_ptr
 	return result;
 }
 
-const battle::Units & BattleExchangeEvaluator::getOneTurnReachableUnits(uint8_t turn, BattleHex hex) const
+const battle::Units & BattleExchangeEvaluator::getOneTurnReachableUnits(uint8_t turn, const BattleHex & hex) const
 {
 	return reachabilityMap.getOneTurnReachableUnits(cb, env, turnOrder, turn, hex);
 }
 
 // avoid blocking path for stronger stack by weaker stack
-bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * activeUnit, BattleHex position)
+bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * activeUnit, const BattleHex & position)
 {
 	const int BLOCKING_THRESHOLD = 70;
 	const int BLOCKING_OWN_ATTACK_PENALTY = 100;
@@ -1031,7 +1031,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 			auto unitReachability = turnBattle.getReachability(unit);
 			auto unitSpeed = unit->getMovementRange(turn); // Cached value, to avoid performance hit
 
-			for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); hex++)
+			for(BattleHex hex = BattleHex::TOP_LEFT; hex.isValid(); ++hex)
 			{
 				bool enemyUnit = false;
 				bool reachable = unitReachability.distances.at(hex.toInt()) <= unitSpeed;
@@ -1043,7 +1043,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 					if(hexStack && cb->battleMatchOwner(unit, hexStack, false))
 					{
 						enemyUnit = true;
-						for(BattleHex neighbour : hex.getNeighbouringTiles())
+						for(const BattleHex & neighbour : hex.getNeighbouringTiles())
 						{
 							reachable = unitReachability.distances.at(neighbour.toInt()) <= unitSpeed;
 
@@ -1063,7 +1063,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 	}
 
 #if BATTLE_TRACE_LEVEL>=1
-	logAi->trace("Position %d, blocking score %f", position.hex, blockingScore);
+	logAi->trace("Position %d, blocking score %f", position.toInt(), blockingScore);
 #endif
 
 	return blockingScore > BLOCKING_THRESHOLD;

+ 4 - 4
AI/BattleAI/BattleExchangeVariant.h

@@ -134,9 +134,9 @@ class ReachabilityMapCache
 	std::map<uint32_t, PerTurnData> hexReachabilityPerTurn;
 
 	//const ReachabilityInfo & update();
-	battle::Units computeOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, BattleHex hex);
+	battle::Units computeOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, const BattleHex & hex);
 public:
-	const battle::Units & getOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, BattleHex hex);
+	const battle::Units & getOneTurnReachableUnits(std::shared_ptr<CBattleInfoCallback> cb, std::shared_ptr<Environment> env, const std::vector<battle::Units> & turnOrder, uint8_t turn, const BattleHex & hex);
 	void update(const std::vector<battle::Units> & turnOrder, std::shared_ptr<HypotheticBattle> hb);
 };
 
@@ -185,7 +185,7 @@ public:
 		DamageCache & damageCache,
 		std::shared_ptr<HypotheticBattle> hb) const;
 
-	const battle::Units & getOneTurnReachableUnits(uint8_t turn, BattleHex hex) const;
+	const battle::Units & getOneTurnReachableUnits(uint8_t turn, const BattleHex & hex) const;
 	void updateReachabilityMap(std::shared_ptr<HypotheticBattle> hb);
 
 	ReachabilityData getExchangeUnits(
@@ -195,7 +195,7 @@ public:
 		std::shared_ptr<HypotheticBattle> hb,
 		battle::Units additionalUnits = {}) const;
 
-	bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, BattleHex position);
+	bool checkPositionBlocksOurStacks(HypotheticBattle & hb, const battle::Unit * unit, const BattleHex & position);
 
 	MoveTarget findMoveTowardsUnreachable(
 		const battle::Unit * activeStack,

+ 2 - 2
AI/BattleAI/PotentialTargets.cpp

@@ -48,7 +48,7 @@ PotentialTargets::PotentialTargets(
 		if(!forceTarget && !state->battleMatchOwner(attackerInfo, defender))
 			continue;
 
-		auto GenerateAttackInfo = [&](bool shooting, BattleHex hex) -> AttackPossibility
+		auto GenerateAttackInfo = [&](bool shooting, const BattleHex & hex) -> AttackPossibility
 		{
 			int distance = hex.isValid() ? reachability.distances[hex.toInt()] : 0;
 			auto bai = BattleAttackInfo(attackerInfo, defender, distance, shooting);
@@ -69,7 +69,7 @@ PotentialTargets::PotentialTargets(
 		}
 		else
 		{
-			for(BattleHex hex : avHexes)
+			for(const BattleHex & hex : avHexes)
 			{
 				if(!CStack::isMeleeAttackPossible(attackerInfo, defender, hex))
 					continue;

+ 1 - 1
AI/BattleAI/StackWithBonuses.cpp

@@ -360,7 +360,7 @@ void HypotheticBattle::addUnit(uint32_t id, const JsonNode & data)
 	stackStates[newUnit->unitId()] = newUnit;
 }
 
-void HypotheticBattle::moveUnit(uint32_t id, BattleHex destination)
+void HypotheticBattle::moveUnit(uint32_t id, const BattleHex & destination)
 {
 	std::shared_ptr<StackWithBonuses> changed = getForUpdate(id);
 	changed->position = destination;

+ 1 - 1
AI/BattleAI/StackWithBonuses.h

@@ -141,7 +141,7 @@ public:
 
 	void addUnit(uint32_t id, const JsonNode & data) override;
 	void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
-	void moveUnit(uint32_t id, BattleHex destination) override;
+	void moveUnit(uint32_t id, const BattleHex & destination) override;
 	void removeUnit(uint32_t id) override;
 	void updateUnit(uint32_t id, const JsonNode & data) override;
 

+ 4 - 4
AI/StupidAI/StupidAI.cpp

@@ -160,7 +160,7 @@ void CStupidAI::activeStack(const BattleID & battleID, const CStack * stack)
 		{
 			BattleHexArray avHexes = cb->getBattle(battleID)->battleGetAvailableHexes(stack, false);
 
-			for (BattleHex hex : avHexes)
+			for (const BattleHex & hex : avHexes)
 			{
 				if(CStack::isMeleeAttackPossible(stack, s, hex))
 				{
@@ -289,12 +289,12 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
 		return BattleAction::makeDefend(stack);
 	}
 
-	std::sort(hexes.begin(), hexes.end(), [&](BattleHex h1, BattleHex h2) -> bool
+	std::sort(hexes.begin(), hexes.end(), [&](const BattleHex & h1, const BattleHex & h2) -> bool
 	{
 		return reachability.distances[h1.toInt()] < reachability.distances[h2.toInt()];
 	});
 
-	for(auto hex : hexes)
+	for(const auto & hex : hexes)
 	{
 		if(avHexes.contains(hex))
 		{
@@ -322,7 +322,7 @@ BattleAction CStupidAI::goTowards(const BattleID & battleID, const CStack * stac
 	{
 		// Flying stack doesn't go hex by hex, so we can't backtrack using predecessors.
 		// We just check all available hexes and pick the one closest to the target.
-		auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](BattleHex hex) -> int
+		auto nearestAvailableHex = vstd::minElementByFun(avHexes, [&](const BattleHex & hex) -> int
 		{
 			return BattleHex::getDistance(bestneighbour, hex);
 		});

+ 16 - 16
client/battle/BattleActionsController.cpp

@@ -358,7 +358,7 @@ const CSpell * BattleActionsController::getHeroSpellToCast( ) const
 	return nullptr;
 }
 
-const CSpell * BattleActionsController::getStackSpellToCast(BattleHex hoveredHex)
+const CSpell * BattleActionsController::getStackSpellToCast(const BattleHex & hoveredHex)
 {
 	if (heroSpellToCast)
 		return nullptr;
@@ -383,14 +383,14 @@ const CSpell * BattleActionsController::getStackSpellToCast(BattleHex hoveredHex
 	return action.spell().toSpell();
 }
 
-const CSpell * BattleActionsController::getCurrentSpell(BattleHex hoveredHex)
+const CSpell * BattleActionsController::getCurrentSpell(const BattleHex & hoveredHex)
 {
 	if (getHeroSpellToCast())
 		return getHeroSpellToCast();
 	return getStackSpellToCast(hoveredHex);
 }
 
-const CStack * BattleActionsController::getStackForHex(BattleHex hoveredHex)
+const CStack * BattleActionsController::getStackForHex(const BattleHex & hoveredHex)
 {
 	const CStack * shere = owner.getBattle()->battleGetStackByPos(hoveredHex, true);
 	if(shere)
@@ -398,7 +398,7 @@ const CStack * BattleActionsController::getStackForHex(BattleHex hoveredHex)
 	return owner.getBattle()->battleGetStackByPos(hoveredHex, false);
 }
 
-void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, BattleHex targetHex)
+void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	switch (action.get())
 	{
@@ -479,7 +479,7 @@ void BattleActionsController::actionSetCursor(PossiblePlayerBattleAction action,
 	assert(0);
 }
 
-void BattleActionsController::actionSetCursorBlocked(PossiblePlayerBattleAction action, BattleHex targetHex)
+void BattleActionsController::actionSetCursorBlocked(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	switch (action.get())
 	{
@@ -500,7 +500,7 @@ void BattleActionsController::actionSetCursorBlocked(PossiblePlayerBattleAction
 	assert(0);
 }
 
-std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattleAction action, BattleHex targetHex)
+std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	const CStack * targetStack = getStackForHex(targetHex);
 
@@ -589,7 +589,7 @@ std::string BattleActionsController::actionGetStatusMessage(PossiblePlayerBattle
 	return "";
 }
 
-std::string BattleActionsController::actionGetStatusMessageBlocked(PossiblePlayerBattleAction action, BattleHex targetHex)
+std::string BattleActionsController::actionGetStatusMessageBlocked(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	switch (action.get())
 	{
@@ -611,7 +611,7 @@ std::string BattleActionsController::actionGetStatusMessageBlocked(PossiblePlaye
 	}
 }
 
-bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, BattleHex targetHex)
+bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	const CStack * targetStack = getStackForHex(targetHex);
 	bool targetStackOwned = targetStack && targetStack->unitOwner() == owner.curInt->playerID;
@@ -706,7 +706,7 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
 	return false;
 }
 
-void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, BattleHex targetHex)
+void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, const BattleHex & targetHex)
 {
 	const CStack * targetStack = getStackForHex(targetHex);
 
@@ -846,7 +846,7 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B
 	return;
 }
 
-PossiblePlayerBattleAction BattleActionsController::selectAction(BattleHex targetHex)
+PossiblePlayerBattleAction BattleActionsController::selectAction(const BattleHex & targetHex)
 {
 	assert(owner.stacksController->getActiveStack() != nullptr);
 	assert(!possibleActions.empty());
@@ -870,7 +870,7 @@ PossiblePlayerBattleAction BattleActionsController::selectAction(BattleHex targe
 	return possibleActions.front();
 }
 
-void BattleActionsController::onHexHovered(BattleHex hoveredHex)
+void BattleActionsController::onHexHovered(const BattleHex & hoveredHex)
 {
 	if (owner.openingPlaying())
 	{
@@ -926,7 +926,7 @@ void BattleActionsController::onHoverEnded()
 	currentConsoleMsg.clear();
 }
 
-void BattleActionsController::onHexLeftClicked(BattleHex clickedHex)
+void BattleActionsController::onHexLeftClicked(const BattleHex & clickedHex)
 {
 	if (owner.stacksController->getActiveStack() == nullptr)
 		return;
@@ -983,7 +983,7 @@ spells::Mode BattleActionsController::getCurrentCastMode() const
 
 }
 
-bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell, const CStack *targetStack, BattleHex targetHex)
+bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell, const CStack *targetStack, const BattleHex & targetHex)
 {
 	assert(currentSpell);
 	if (!currentSpell)
@@ -1006,7 +1006,7 @@ bool BattleActionsController::isCastingPossibleHere(const CSpell * currentSpell,
 	return m->canBeCastAt(target, problem);
 }
 
-bool BattleActionsController::canStackMoveHere(const CStack * stackToMove, BattleHex myNumber) const
+bool BattleActionsController::canStackMoveHere(const CStack * stackToMove, const BattleHex & myNumber) const
 {
 	BattleHexArray acc = owner.getBattle()->battleGetAvailableHexes(stackToMove, false);
 	BattleHex shiftedDest = myNumber.cloneInDirection(stackToMove->destShiftDir(), false);
@@ -1057,7 +1057,7 @@ void BattleActionsController::activateStack()
 	}
 }
 
-void BattleActionsController::onHexRightClicked(BattleHex clickedHex)
+void BattleActionsController::onHexRightClicked(const BattleHex & clickedHex)
 {
 	bool isCurrentStackInSpellcastMode = creatureSpellcastingModeActive();
 
@@ -1095,7 +1095,7 @@ bool BattleActionsController::creatureSpellcastingModeActive() const
 	return !possibleActions.empty() && std::all_of(possibleActions.begin(), possibleActions.end(), spellcastModePredicate);
 }
 
-bool BattleActionsController::currentActionSpellcasting(BattleHex hoveredHex)
+bool BattleActionsController::currentActionSpellcasting(const BattleHex & hoveredHex)
 {
 	if (heroSpellToCast)
 		return true;

+ 16 - 16
client/battle/BattleActionsController.h

@@ -44,24 +44,24 @@ class BattleActionsController
 	/// stack that has been selected as first target for multi-target spells (Teleport & Sacrifice)
 	const CStack * selectedStack;
 
-	bool isCastingPossibleHere (const CSpell * spell, const CStack *shere, BattleHex myNumber);
-	bool canStackMoveHere (const CStack *sactive, BattleHex MyNumber) const; //TODO: move to BattleState / callback
+	bool isCastingPossibleHere (const CSpell * spell, const CStack *shere, const BattleHex & myNumber);
+	bool canStackMoveHere (const CStack *sactive, const BattleHex & MyNumber) const; //TODO: move to BattleState / callback
 	std::vector<PossiblePlayerBattleAction> getPossibleActionsForStack (const CStack *stack) const; //called when stack gets its turn
 	void reorderPossibleActionsPriority(const CStack * stack, const CStack * targetStack);
 
-	bool actionIsLegal(PossiblePlayerBattleAction action, BattleHex hoveredHex);
+	bool actionIsLegal(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
 
-	void actionSetCursor(PossiblePlayerBattleAction action, BattleHex hoveredHex);
-	void actionSetCursorBlocked(PossiblePlayerBattleAction action, BattleHex hoveredHex);
+	void actionSetCursor(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
+	void actionSetCursorBlocked(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
 
-	std::string actionGetStatusMessage(PossiblePlayerBattleAction action, BattleHex hoveredHex);
-	std::string actionGetStatusMessageBlocked(PossiblePlayerBattleAction action, BattleHex hoveredHex);
+	std::string actionGetStatusMessage(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
+	std::string actionGetStatusMessageBlocked(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
 
-	void actionRealize(PossiblePlayerBattleAction action, BattleHex hoveredHex);
+	void actionRealize(PossiblePlayerBattleAction action, const BattleHex & hoveredHex);
 
-	PossiblePlayerBattleAction selectAction(BattleHex myNumber);
+	PossiblePlayerBattleAction selectAction(const BattleHex & myNumber);
 
-	const CStack * getStackForHex(BattleHex myNumber) ;
+	const CStack * getStackForHex(const BattleHex & myNumber) ;
 
 	/// attempts to initialize spellcasting action for stack
 	/// will silently return if stack is not a spellcaster
@@ -71,7 +71,7 @@ class BattleActionsController
 	const CSpell * getHeroSpellToCast() const;
 
 	/// if current stack is spellcaster, returns spell being cast, or null othervice
-	const CSpell * getStackSpellToCast(BattleHex hoveredHex);
+	const CSpell * getStackSpellToCast(const BattleHex & hoveredHex);
 
 	/// returns true if current stack is a spellcaster
 	bool isActiveStackSpellcaster() const;
@@ -91,7 +91,7 @@ public:
 	/// - we are casting spell by hero
 	/// - we are casting spell by creature in targeted mode (F hotkey)
 	/// - current creature is spellcaster and preferred action for current hex is spellcast
-	bool currentActionSpellcasting(BattleHex hoveredHex);
+	bool currentActionSpellcasting(const BattleHex & hoveredHex);
 
 	/// enter targeted spellcasting mode for creature, e.g. via "F" hotkey
 	void enterCreatureCastingMode();
@@ -103,19 +103,19 @@ public:
 	void endCastingSpell();
 
 	/// update cursor and status bar according to new active hex
-	void onHexHovered(BattleHex hoveredHex);
+	void onHexHovered(const BattleHex & hoveredHex);
 
 	/// called when cursor is no longer over battlefield and cursor/battle log should be reset
 	void onHoverEnded();
 
 	/// performs action according to selected hex
-	void onHexLeftClicked(BattleHex clickedHex);
+	void onHexLeftClicked(const BattleHex & clickedHex);
 
 	/// performs action according to selected hex
-	void onHexRightClicked(BattleHex clickedHex);
+	void onHexRightClicked(const BattleHex & clickedHex);
 
 	const spells::Caster * getCurrentSpellcaster() const;
-	const CSpell * getCurrentSpell(BattleHex hoveredHex);
+	const CSpell * getCurrentSpell(const BattleHex & hoveredHex);
 	spells::Mode getCurrentCastMode() const;
 
 	/// methods to work with array of possible actions, needed to control special creatures abilities

+ 20 - 31
client/battle/BattleFieldController.cpp

@@ -281,7 +281,7 @@ void BattleFieldController::redrawBackgroundWithHexes()
 	{
 		BattleHexArray hexesToShade = occupiableHexes;
 		hexesToShade.insert(attackableHexes);
-		for(BattleHex hex : hexesToShade)
+		for(const BattleHex & hex : hexesToShade)
 		{
 			showHighlightedHex(*backgroundWithHexes, cellShade, hex, false);
 		}
@@ -302,7 +302,7 @@ void BattleFieldController::redrawBackgroundWithHexes()
 	}
 }
 
-void BattleFieldController::showHighlightedHex(Canvas & canvas, std::shared_ptr<IImage> highlight, BattleHex hex, bool darkBorder)
+void BattleFieldController::showHighlightedHex(Canvas & canvas, std::shared_ptr<IImage> highlight, const BattleHex & hex, bool darkBorder)
 {
 	Point hexPos = hexPositionLocal(hex).topLeft();
 
@@ -313,41 +313,30 @@ void BattleFieldController::showHighlightedHex(Canvas & canvas, std::shared_ptr<
 
 BattleHexArray BattleFieldController::getHighlightedHexesForActiveStack()
 {
-	BattleHexArray result;
-
 	if(!owner.stacksController->getActiveStack())
-		return result;
+		return BattleHexArray();
 
 	if(!settings["battle"]["stackRange"].Bool())
-		return result;
+		return BattleHexArray();
 
 	auto hoveredHex = getHoveredHex();
 
-	BattleHexArray set = owner.getBattle()->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex);
-	for(BattleHex hex : set)
-		result.insert(hex);
-
-	return result;
+	return owner.getBattle()->battleGetAttackedHexes(owner.stacksController->getActiveStack(), hoveredHex);
 }
 
 BattleHexArray BattleFieldController::getMovementRangeForHoveredStack()
 {
-	BattleHexArray result;
-
 	if (!owner.stacksController->getActiveStack())
-		return result;
+		return BattleHexArray();
 
 	if (!settings["battle"]["movementHighlightOnHover"].Bool() && !GH.isKeyboardShiftDown())
-		return result;
+		return BattleHexArray();
 
 	auto hoveredStack = getHoveredStack();
 	if(hoveredStack)
-	{
-		BattleHexArray v = owner.getBattle()->battleGetAvailableHexes(hoveredStack, true, true, nullptr);
-		for(BattleHex hex : v)
-			result.insert(hex);
-	}
-	return result;
+		return owner.getBattle()->battleGetAvailableHexes(hoveredStack, true, true, nullptr);
+	else
+		return BattleHexArray();
 }
 
 BattleHexArray BattleFieldController::getHighlightedHexesForSpellRange()
@@ -368,7 +357,7 @@ BattleHexArray BattleFieldController::getHighlightedHexesForSpellRange()
 		spells::BattleCast event(owner.getBattle().get(), caster, mode, spell);
 		auto shadedHexes = spell->battleMechanics(&event)->rangeInHexes(hoveredHex);
 
-		for(BattleHex shadedHex : shadedHexes)
+		for(const BattleHex & shadedHex : shadedHexes)
 		{
 			if((shadedHex.getX() != 0) && (shadedHex.getX() != GameConstants::BFIELD_WIDTH - 1))
 				result.insert(shadedHex);
@@ -411,7 +400,7 @@ BattleHexArray BattleFieldController::getHighlightedHexesForMovementTarget()
 
 	if(stack->doubleWide())
 	{
-		for(auto hex : availableHexes)
+		for(const auto & hex : availableHexes)
 		{
 			if(stack->occupiedHex(hex) == hoveredHex)
 				return {hoveredHex, hex};
@@ -423,7 +412,7 @@ BattleHexArray BattleFieldController::getHighlightedHexesForMovementTarget()
 
 // Range limit highlight helpers
 
-BattleHexArray BattleFieldController::getRangeHexes(BattleHex sourceHex, uint8_t distance)
+BattleHexArray BattleFieldController::getRangeHexes(const BattleHex & sourceHex, uint8_t distance)
 {
 	BattleHexArray rangeHexes;
 
@@ -441,7 +430,7 @@ BattleHexArray BattleFieldController::getRangeHexes(BattleHex sourceHex, uint8_t
 	return rangeHexes;
 }
 
-BattleHexArray BattleFieldController::getRangeLimitHexes(BattleHex hoveredHex, const BattleHexArray & rangeHexes, uint8_t distanceToLimit)
+BattleHexArray BattleFieldController::getRangeLimitHexes(const BattleHex & hoveredHex, const BattleHexArray & rangeHexes, uint8_t distanceToLimit)
 {
 	BattleHexArray rangeLimitHexes;
 
@@ -455,7 +444,7 @@ BattleHexArray BattleFieldController::getRangeLimitHexes(BattleHex hoveredHex, c
 	return rangeLimitHexes;
 }
 
-bool BattleFieldController::IsHexInRangeLimit(BattleHex hex, const BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit)
+bool BattleFieldController::IsHexInRangeLimit(const BattleHex & hex, const BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit)
 {
 	bool  hexInRangeLimit = false;
 
@@ -477,7 +466,7 @@ std::vector<std::vector<BattleHex::EDir>> BattleFieldController::getOutsideNeigh
 	if(wholeRangeHexes.empty())
 		return output;
 
-	for(auto hex : rangeLimitHexes)
+	for(const auto & hex : rangeLimitHexes)
 	{
 		// get all neighbours and their directions
 		
@@ -606,7 +595,7 @@ void BattleFieldController::showHighlightedHexes(Canvas & canvas)
 	}
 }
 
-Rect BattleFieldController::hexPositionLocal(BattleHex hex) const
+Rect BattleFieldController::hexPositionLocal(const BattleHex & hex) const
 {
 	int x = 14 + ((hex.getY())%2==0 ? 22 : 0) + 44*hex.getX();
 	int y = 86 + 42 *hex.getY();
@@ -615,7 +604,7 @@ Rect BattleFieldController::hexPositionLocal(BattleHex hex) const
 	return Rect(x, y, w, h);
 }
 
-Rect BattleFieldController::hexPositionAbsolute(BattleHex hex) const
+Rect BattleFieldController::hexPositionAbsolute(const BattleHex & hex) const
 {
 	return hexPositionLocal(hex) + pos.topLeft();
 }
@@ -674,7 +663,7 @@ BattleHex BattleFieldController::getHexAtPosition(Point hoverPos)
 	return BattleHex::INVALID;
 }
 
-BattleHex::EDir BattleFieldController::selectAttackDirection(BattleHex myNumber)
+BattleHex::EDir BattleFieldController::selectAttackDirection(const BattleHex & myNumber)
 {
 	const bool doubleWide = owner.stacksController->getActiveStack()->doubleWide();
 	const BattleHexArray & neighbours = myNumber.getAllNeighbouringTiles();
@@ -748,7 +737,7 @@ BattleHex::EDir BattleFieldController::selectAttackDirection(BattleHex myNumber)
 	return BattleHex::EDir(nearest);
 }
 
-BattleHex BattleFieldController::fromWhichHexAttack(BattleHex attackTarget)
+BattleHex BattleFieldController::fromWhichHexAttack(const BattleHex & attackTarget)
 {
 	BattleHex::EDir direction = selectAttackDirection(getHoveredHex());
 

+ 9 - 9
client/battle/BattleFieldController.h

@@ -55,7 +55,7 @@ class BattleFieldController : public CIntObject
 	/// hexes that when in front of a unit cause it's amount box to move back
 	std::array<bool, GameConstants::BFIELD_SIZE> stackCountOutsideHexes;
 
-	void showHighlightedHex(Canvas & to, std::shared_ptr<IImage> highlight, BattleHex hex, bool darkBorder);
+	void showHighlightedHex(Canvas & to, std::shared_ptr<IImage> highlight, const BattleHex & hex, bool darkBorder);
 
 	BattleHexArray getHighlightedHexesForActiveStack();
 	BattleHexArray getMovementRangeForHoveredStack();
@@ -65,13 +65,13 @@ class BattleFieldController : public CIntObject
 	// Range limit highlight helpers
 
 	/// get all hexes within a certain distance of given hex
-	BattleHexArray getRangeHexes(BattleHex sourceHex, uint8_t distance);
+	BattleHexArray getRangeHexes(const BattleHex & sourceHex, uint8_t distance);
 
 	/// get only hexes at the limit of a range
-	BattleHexArray getRangeLimitHexes(BattleHex hoveredHex, const BattleHexArray & hexRange, uint8_t distanceToLimit);
+	BattleHexArray getRangeLimitHexes(const BattleHex & hoveredHex, const BattleHexArray & hexRange, uint8_t distanceToLimit);
 
 	/// calculate if a hex is in range limit and return its index in range
-	bool IsHexInRangeLimit(BattleHex hex, const BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit);
+	bool IsHexInRangeLimit(const BattleHex & hex, const BattleHexArray & rangeLimitHexes, int * hexIndexInRangeLimit);
 
 	/// get an array that has for each hex in range, an array with all directions where an outside neighbour hex exists
 	std::vector<std::vector<BattleHex::EDir>> getOutsideNeighbourDirectionsForLimitHexes(const BattleHexArray & rangeHexes, const BattleHexArray & rangeLimitHexes);
@@ -94,7 +94,7 @@ class BattleFieldController : public CIntObject
 
 	/// Checks whether selected pixel is transparent, uses local coordinates of a hex
 	bool isPixelInHex(Point const & position);
-	size_t selectBattleCursor(BattleHex myNumber);
+	size_t selectBattleCursor(const BattleHex & myNumber);
 
 	void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
 	void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
@@ -118,10 +118,10 @@ public:
 	void renderBattlefield(Canvas & canvas);
 
 	/// Returns position of hex relative to owner (BattleInterface)
-	Rect hexPositionLocal(BattleHex hex) const;
+	Rect hexPositionLocal(const BattleHex & hex) const;
 
 	/// Returns position of hex relative to game window
-	Rect hexPositionAbsolute(BattleHex hex) const;
+	Rect hexPositionAbsolute(const BattleHex & hex) const;
 
 	/// Returns ID of currently hovered hex or BattleHex::INVALID if none
 	BattleHex getHoveredHex();
@@ -135,7 +135,7 @@ public:
 	/// returns true if stack should render its stack count image in default position - outside own hex
 	bool stackCountOutsideHex(const BattleHex & number) const;
 
-	BattleHex::EDir selectAttackDirection(BattleHex myNumber);
+	BattleHex::EDir selectAttackDirection(const BattleHex & myNumber);
 
-	BattleHex fromWhichHexAttack(BattleHex myNumber);
+	BattleHex fromWhichHexAttack(const BattleHex & myNumber);
 };

+ 5 - 5
client/battle/BattleInterface.cpp

@@ -261,7 +261,7 @@ void BattleInterface::newRound()
 	round++;
 }
 
-void BattleInterface::giveCommand(EActionType action, BattleHex tile, SpellID spell)
+void BattleInterface::giveCommand(EActionType action, const BattleHex & tile, SpellID spell)
 {
 	const CStack * actor = nullptr;
 	if(action != EActionType::HERO_SPELL && action != EActionType::RETREAT && action != EActionType::SURRENDER)
@@ -506,7 +506,7 @@ void BattleInterface::displayBattleLog(const std::vector<MetaString> & battleLog
 	}
 }
 
-void BattleInterface::displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit)
+void BattleInterface::displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, const BattleHex & destinationTile, bool isHit)
 {
 	for(const CSpell::TAnimation & animation : q)
 	{
@@ -542,19 +542,19 @@ void BattleInterface::displaySpellAnimationQueue(const CSpell * spell, const CSp
 	}
 }
 
-void BattleInterface::displaySpellCast(const CSpell * spell, BattleHex destinationTile)
+void BattleInterface::displaySpellCast(const CSpell * spell, const BattleHex & destinationTile)
 {
 	if(spell)
 		displaySpellAnimationQueue(spell, spell->animationInfo.cast, destinationTile, false);
 }
 
-void BattleInterface::displaySpellEffect(const CSpell * spell, BattleHex destinationTile)
+void BattleInterface::displaySpellEffect(const CSpell * spell, const BattleHex & destinationTile)
 {
 	if(spell)
 		displaySpellAnimationQueue(spell, spell->animationInfo.affect, destinationTile, false);
 }
 
-void BattleInterface::displaySpellHit(const CSpell * spell, BattleHex destinationTile)
+void BattleInterface::displaySpellHit(const CSpell * spell, const BattleHex & destinationTile)
 {
 	if(spell)
 		displaySpellAnimationQueue(spell, spell->animationInfo.hit, destinationTile, true);

+ 5 - 5
client/battle/BattleInterface.h

@@ -163,7 +163,7 @@ public:
 	void activateStack(); //sets activeStack to stackToActivate etc. //FIXME: No, it's not clear at all
 	void requestAutofightingAIToTakeAction();
 
-	void giveCommand(EActionType action, BattleHex tile = BattleHex(), SpellID spell = SpellID::NONE);
+	void giveCommand(EActionType action, const BattleHex & tile = BattleHex(), SpellID spell = SpellID::NONE);
 	void sendCommand(BattleAction command, const CStack * actor = nullptr);
 
 	const CGHeroInstance *getActiveHero(); //returns hero that can currently cast a spell
@@ -215,10 +215,10 @@ public:
 
 	void displayBattleLog(const std::vector<MetaString> & battleLog);
 
-	void displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, BattleHex destinationTile, bool isHit);
-	void displaySpellCast(const CSpell * spell, BattleHex destinationTile); //displays spell`s cast animation
-	void displaySpellEffect(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation
-	void displaySpellHit(const CSpell * spell, BattleHex destinationTile); //displays spell`s affected animation
+	void displaySpellAnimationQueue(const CSpell * spell, const CSpell::TAnimationQueue & q, const BattleHex & destinationTile, bool isHit);
+	void displaySpellCast(const CSpell * spell, const BattleHex & destinationTile); //displays spell`s cast animation
+	void displaySpellEffect(const CSpell * spell, const BattleHex & destinationTile); //displays spell`s affected animation
+	void displaySpellHit(const CSpell * spell, const BattleHex & destinationTile); //displays spell`s affected animation
 
 	void endAction(const BattleAction & action);
 

+ 1 - 1
client/battle/BattleOverlayLogVisualizer.cpp

@@ -29,7 +29,7 @@ BattleOverlayLogVisualizer::BattleOverlayLogVisualizer(
 {
 }
 
-void BattleOverlayLogVisualizer::drawText(BattleHex hex, int lineNumber, const std::string & text)
+void BattleOverlayLogVisualizer::drawText(const BattleHex & hex, int lineNumber, const std::string & text)
 {
 	Point offset = owner.fieldController->hexPositionLocal(hex).topLeft() + Point(20, 20);
 	const auto & font = GH.renderHandler().loadFont(FONT_TINY);

+ 1 - 1
client/battle/BattleOverlayLogVisualizer.h

@@ -24,5 +24,5 @@ private:
 public:
 	BattleOverlayLogVisualizer(BattleRenderer::RendererRef & target, BattleInterface & owner);
 
-	void drawText(BattleHex hex, int lineNumber, const std::string & text) override;
+	void drawText(const BattleHex & hex, int lineNumber, const std::string & text) override;
 };

+ 1 - 1
client/battle/BattleRenderer.cpp

@@ -64,7 +64,7 @@ BattleRenderer::BattleRenderer(BattleInterface & owner):
 {
 }
 
-void BattleRenderer::insert(EBattleFieldLayer layer, BattleHex tile, BattleRenderer::RenderFunctor functor)
+void BattleRenderer::insert(EBattleFieldLayer layer, const BattleHex & tile, BattleRenderer::RenderFunctor functor)
 {
 	objects.push_back({functor, layer, tile});
 }

+ 1 - 1
client/battle/BattleRenderer.h

@@ -48,6 +48,6 @@ private:
 public:
 	BattleRenderer(BattleInterface & owner);
 
-	void insert(EBattleFieldLayer layer, BattleHex tile, RenderFunctor functor);
+	void insert(EBattleFieldLayer layer, const BattleHex & tile, RenderFunctor functor);
 	void execute(RendererRef targetCanvas);
 };

+ 2 - 2
client/battle/BattleSiegeController.cpp

@@ -183,7 +183,7 @@ BattleSiegeController::BattleSiegeController(BattleInterface & owner, const CGTo
 	}
 }
 
-const CCreature *BattleSiegeController::getTurretCreature(BattleHex position) const
+const CCreature *BattleSiegeController::getTurretCreature(const BattleHex & position) const
 {
 	switch (position.toInt())
 	{
@@ -322,7 +322,7 @@ void BattleSiegeController::collectRenderableObjects(BattleRenderer & renderer)
 	}
 }
 
-bool BattleSiegeController::isAttackableByCatapult(BattleHex hex) const
+bool BattleSiegeController::isAttackableByCatapult(const BattleHex & hex) const
 {
 	if (owner.tacticsMode)
 		return false;

+ 2 - 2
client/battle/BattleSiegeController.h

@@ -102,9 +102,9 @@ public:
 	void collectRenderableObjects(BattleRenderer & renderer);
 
 	/// queries from other battle controllers
-	bool isAttackableByCatapult(BattleHex hex) const;
+	bool isAttackableByCatapult(const BattleHex & hex) const;
 	ImagePath getBattleBackgroundName() const;
-	const CCreature *getTurretCreature(BattleHex turretPosition) const;
+	const CCreature *getTurretCreature(const BattleHex & turretPosition) const;
 	Point getTurretCreaturePosition( BattleHex position ) const;
 
 	const CGTownInstance *getSiegedTown() const;

+ 1 - 1
client/battle/BattleStacksController.cpp

@@ -733,7 +733,7 @@ bool BattleStacksController::facingRight(const CStack * stack) const
 	return stackFacingRight.at(stack->unitId());
 }
 
-Point BattleStacksController::getStackPositionAtHex(BattleHex hexNum, const CStack * stack) const
+Point BattleStacksController::getStackPositionAtHex(const BattleHex & hexNum, const CStack * stack) const
 {
 	Point ret(-500, -500); //returned value
 	if(stack && stack->initialPosition < 0) //creatures in turrets

+ 1 - 1
client/battle/BattleStacksController.h

@@ -143,7 +143,7 @@ public:
 	void tick(uint32_t msPassed);
 
 	/// returns position of animation needed to place stack in specific hex
-	Point getStackPositionAtHex(BattleHex hexNum, const CStack * creature) const;
+	Point getStackPositionAtHex(const BattleHex & hexNum, const CStack * creature) const;
 
 	friend class BattleAnimation; // for exposing pendingAnims/creAnims/creDir to animations
 };

+ 1 - 1
lib/CStack.cpp

@@ -167,7 +167,7 @@ std::string CStack::nodeName() const
 	oss << owner.toString();
 	oss << " battle stack [" << ID << "]: " << getCount() << " of ";
 	if(typeID.hasValue())
-		oss << typeID.toEntity(VLC)->getNamePluralTextID();
+		oss << typeID.toEntity(VLC)->getJsonKey();
 	else
 		oss << "[UNDEFINED TYPE]";
 

+ 1 - 1
lib/ObstacleHandler.cpp

@@ -55,7 +55,7 @@ Obstacle ObstacleInfo::getId() const
 	return obstacle;
 }
 
-BattleHexArray ObstacleInfo::getBlocked(BattleHex hex) const
+BattleHexArray ObstacleInfo::getBlocked(const BattleHex & hex) const
 {
 	if(isAbsoluteObstacle)
 	{

+ 1 - 1
lib/ObstacleHandler.h

@@ -54,7 +54,7 @@ public:
 	void registerIcons(const IconRegistar & cb) const override;
 	Obstacle getId() const override;
 	
-	BattleHexArray getBlocked(BattleHex hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
+	BattleHexArray getBlocked(const BattleHex & hex) const; //returns vector of hexes blocked by obstacle when it's placed on hex 'hex'
 	
 	bool isAppropriate(const TerrainId terrainType, const BattleField & specialBattlefield) const;
 };

+ 3 - 3
lib/battle/AccessibilityInfo.cpp

@@ -15,7 +15,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side) const
+bool AccessibilityInfo::tileAccessibleWithGate(const BattleHex & tile, BattleSide side) const
 {
 	//at(otherHex) != EAccessibility::ACCESSIBLE && (at(otherHex) != EAccessibility::GATE || side != BattleSide::DEFENDER)
 	const auto & accessibility = at(tile.toInt());
@@ -35,12 +35,12 @@ bool AccessibilityInfo::tileAccessibleWithGate(BattleHex tile, BattleSide side)
 	return true;
 }
 
-bool AccessibilityInfo::accessible(BattleHex tile, const battle::Unit * stack) const
+bool AccessibilityInfo::accessible(const BattleHex & tile, const battle::Unit * stack) const
 {
 	return accessible(tile, stack->doubleWide(), stack->unitSide());
 }
 
-bool AccessibilityInfo::accessible(BattleHex tile, bool doubleWide, BattleSide side) const
+bool AccessibilityInfo::accessible(const BattleHex & tile, bool doubleWide, BattleSide side) const
 {
 	// All hexes that stack would cover if standing on tile have to be accessible.
 	//do not use getHexes for speed reasons

+ 3 - 3
lib/battle/AccessibilityInfo.h

@@ -39,10 +39,10 @@ struct DLL_LINKAGE AccessibilityInfo : TAccessibilityArray
 	std::shared_ptr<const TBattlefieldTurnsArray> destructibleEnemyTurns; //used only as a view for destructibleEnemyTurns from ReachabilityInfo::Parameters
 
 	public:
-		bool accessible(BattleHex tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide
-		bool accessible(BattleHex tile, bool doubleWide, BattleSide side) const; //checks for both tiles if stack is double wide
+		bool accessible(const BattleHex & tile, const battle::Unit * stack) const; //checks for both tiles if stack is double wide
+		bool accessible(const BattleHex & tile, bool doubleWide, BattleSide side) const; //checks for both tiles if stack is double wide
 	private:
-		bool tileAccessibleWithGate(BattleHex tile, BattleSide side) const;
+		bool tileAccessibleWithGate(const BattleHex & tile, BattleSide side) const;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 2 - 2
lib/battle/BattleAction.cpp

@@ -43,7 +43,7 @@ BattleAction BattleAction::makeDefend(const battle::Unit * stack)
 	return ba;
 }
 
-BattleAction BattleAction::makeMeleeAttack(const battle::Unit * stack, BattleHex destination, BattleHex attackFrom, bool returnAfterAttack)
+BattleAction BattleAction::makeMeleeAttack(const battle::Unit * stack, const BattleHex & destination, const BattleHex & attackFrom, bool returnAfterAttack)
 {
 	BattleAction ba;
 	ba.side = stack->unitSide(); //FIXME: will it fail if stack mind controlled?
@@ -86,7 +86,7 @@ BattleAction BattleAction::makeCreatureSpellcast(const battle::Unit * stack, con
 	return ba;
 }
 
-BattleAction BattleAction::makeMove(const battle::Unit * stack, BattleHex dest)
+BattleAction BattleAction::makeMove(const battle::Unit * stack, const BattleHex & dest)
 {
 	BattleAction ba;
 	ba.side = stack->unitSide();

+ 2 - 2
lib/battle/BattleAction.h

@@ -35,10 +35,10 @@ public:
 	static BattleAction makeHeal(const battle::Unit * healer, const battle::Unit * healed);
 	static BattleAction makeDefend(const battle::Unit * stack);
 	static BattleAction makeWait(const battle::Unit * stack);
-	static BattleAction makeMeleeAttack(const battle::Unit * stack, BattleHex destination, BattleHex attackFrom, bool returnAfterAttack = true);
+	static BattleAction makeMeleeAttack(const battle::Unit * stack, const BattleHex & destination, const BattleHex & attackFrom, bool returnAfterAttack = true);
 	static BattleAction makeShotAttack(const battle::Unit * shooter, const battle::Unit * target);
 	static BattleAction makeCreatureSpellcast(const battle::Unit * stack, const battle::Target & target, const SpellID & spellID);
-	static BattleAction makeMove(const battle::Unit * stack, BattleHex dest);
+	static BattleAction makeMove(const battle::Unit * stack, const BattleHex & dest);
 	static BattleAction makeEndOFTacticPhase(BattleSide side);
 	static BattleAction makeRetreat(BattleSide side);
 	static BattleAction makeSurrender(BattleSide side);

+ 3 - 3
lib/battle/BattleHex.cpp

@@ -13,7 +13,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, const BattleHexArray & hexes)
+BattleHex BattleHex::getClosestTile(BattleSide side, const BattleHex & initialPos, const BattleHexArray & hexes)
 {
 	if(hexes.empty())
 		return BattleHex();
@@ -22,7 +22,7 @@ BattleHex BattleHex::getClosestTile(BattleSide side, BattleHex initialPos, const
 	int closestDistance = std::numeric_limits<int>::max();
 	BattleHexArray closestTiles;
 
-	for(auto hex : hexes)
+	for(const auto & hex : hexes)
 	{
 		int distance = initialHex.getDistance(initialHex, hex);
 		if(distance < closestDistance)
@@ -65,7 +65,7 @@ const BattleHexArray & BattleHex::getNeighbouringTilesDoubleWide(BattleSide side
 
 std::ostream & operator<<(std::ostream & os, const BattleHex & hex)
 {
-	return os << boost::str(boost::format("{BattleHex: x '%d', y '%d', hex '%d'}") % hex.getX() % hex.getY() % hex.toInt());
+	return os << hex.toInt();
 }
 
 VCMI_LIB_NAMESPACE_END

+ 19 - 15
lib/battle/BattleHex.h

@@ -24,8 +24,12 @@ namespace GameConstants
 
 class BattleHexArray;
 
-// for battle stacks' positions; valid hexes are from 0 to 186; available are only those not in first and last column
-// castle towers are -2, -3 and -4
+/**
+ * @brief Represents a battlefield hexagonal tile.
+ *
+ * Valid hexes are within the range 0 to 186, excluding some invalid values, ex. castle towers (-2, -3, -4).
+ * Available hexes are those valid ones but NOT in the first or last column.
+ */
 class DLL_LINKAGE BattleHex
 {
 public:
@@ -94,6 +98,11 @@ public:
 		return isValid() && getX() > 0 && getX() < GameConstants::BFIELD_WIDTH - 1;
 	}
 
+	[[nodiscard]] inline bool isTower() const noexcept
+	{
+		return hex == BattleHex::CASTLE_CENTRAL_TOWER || hex == BattleHex::CASTLE_UPPER_TOWER || hex == BattleHex::CASTLE_BOTTOM_TOWER;
+	}
+
 	void setX(si16 x)
 	{
 		setXY(x, getY());
@@ -175,7 +184,7 @@ public:
 		return result;
 	}
 
-	[[nodiscard]] static uint8_t getDistance(BattleHex hex1, BattleHex hex2) noexcept
+	[[nodiscard]] static uint8_t getDistance(const BattleHex & hex1, const BattleHex & hex2) noexcept
 	{
 		int y1 = hex1.getY();
 		int y2 = hex2.getY();
@@ -192,7 +201,7 @@ public:
 		return std::abs(xDst) + std::abs(yDst);
 	}
 
-	[[nodiscard]] static BattleHex getClosestTile(BattleSide side, BattleHex initialPos, const BattleHexArray & hexes);
+	[[nodiscard]] static BattleHex getClosestTile(BattleSide side, const BattleHex & initialPos, const BattleHexArray & hexes);
 
 	//Constexpr defined array with all directions used in battle
 	[[nodiscard]] static constexpr auto hexagonalDirections() noexcept
@@ -200,7 +209,7 @@ public:
 		return std::array<EDir,6>{TOP_LEFT, TOP_RIGHT, RIGHT, BOTTOM_RIGHT, BOTTOM_LEFT, LEFT};
 	}
 
-	[[nodiscard]] static EDir mutualPosition(BattleHex hex1, BattleHex hex2)
+	[[nodiscard]] static EDir mutualPosition(const BattleHex & hex1, const BattleHex & hex2)
 	{
 		for(auto dir : hexagonalDirections())
 			if(hex2 == hex1.cloneInDirection(dir, false))
@@ -240,25 +249,20 @@ public:
 		return *this;
 	}
 
-	// Postfix increment
-	BattleHex operator++(int) noexcept
-	{
-		BattleHex temp = *this;
-		++hex;
-		return temp;
-	}
+	// Postfix increment is deleted; use prefix increment as it has better performance
+	BattleHex operator++(int) = delete;
 
-	[[nodiscard]] bool operator ==(BattleHex other) const noexcept
+	[[nodiscard]] bool operator ==(const BattleHex & other) const noexcept
 	{
 		return hex == other.hex;
 	}
 
-	[[nodiscard]] bool operator !=(BattleHex other) const noexcept
+	[[nodiscard]] bool operator !=(const BattleHex & other) const noexcept
 	{
 		return hex != other.hex;
 	}
 
-	[[nodiscard]] bool operator <(BattleHex other) const noexcept
+	[[nodiscard]] bool operator <(const BattleHex & other) const noexcept
 	{
 		return hex < other.hex;
 	}

+ 5 - 5
lib/battle/BattleHexArray.cpp

@@ -16,7 +16,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 BattleHexArray::BattleHexArray(std::initializer_list<BattleHex> initList) noexcept 
 	: BattleHexArray()
 {
-	for(auto hex : initList)
+	for(const auto & hex : initList)
 	{
 		insert(hex);
 	}
@@ -24,7 +24,7 @@ BattleHexArray::BattleHexArray(std::initializer_list<BattleHex> initList) noexce
 
 void BattleHexArray::insert(const BattleHexArray & other) noexcept
 {
-	for(auto hex : other)
+	for(const auto & hex : other)
 	{
 		insert(hex);
 	}
@@ -34,7 +34,7 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
 {
 	for(auto it = first; it != last && it != internalStorage.end(); ++it)
 	{
-		presenceFlags[it->toInt()] = 0;
+		presenceFlags[it->toInt()] = false;
 	}
 
 	internalStorage.erase(first, last);
@@ -42,8 +42,8 @@ void BattleHexArray::erase(iterator first, iterator last) noexcept
 
 void BattleHexArray::clear() noexcept
 {
-	for(auto hex : internalStorage)
-		presenceFlags[hex.toInt()] = 0;
+	for(const auto & hex : internalStorage)
+		presenceFlags[hex.toInt()] = false;
 
 	internalStorage.clear();
 }

+ 39 - 36
lib/battle/BattleHexArray.h

@@ -15,7 +15,18 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-/// Class representing an array of unique BattleHex objects
+/**
+* @brief Class representing a collection of unique, valid BattleHex objects.
+
+* The BattleHexArray is a specialized container designed for storing instances
+* of BattleHex. Key notes:
+* - Each BattleHex in the array is unique.
+* - Invalid BattleHex objects (e.g., those with an out-of-bounds or special
+*   value) cannot be inserted into the array.
+* - Maintains an efficient storage mechanism for fast access and presence tracking system using bitset for quick existence checks.
+* - Attempting to insert invalid BattleHex objects will have no effect.
+*
+*/
 class DLL_LINKAGE BattleHexArray
 {
 public:
@@ -56,7 +67,7 @@ public:
 	
 	BattleHexArray(std::initializer_list<BattleHex> initList) noexcept;
 
-	void checkAndPush(BattleHex tile)
+	void checkAndPush(const BattleHex & tile)
 	{
 		if(tile.isAvailable() && !contains(tile))
 		{
@@ -65,7 +76,7 @@ public:
 		}
 	}
 
-	void insert(BattleHex hex) noexcept
+	void insert(const BattleHex & hex) noexcept
 	{
 		if(contains(hex))
 			return;
@@ -74,7 +85,7 @@ public:
 		internalStorage.emplace_back(hex);
 	}
 
-	void set(size_type index, BattleHex hex)
+	void set(size_type index, const BattleHex & hex)
 	{
 		if(index >= internalStorage.size())
 		{
@@ -91,7 +102,7 @@ public:
 		internalStorage[index] = hex;
 	}
 
-	iterator insert(iterator pos, BattleHex hex) noexcept
+	iterator insert(iterator pos, const BattleHex & hex) noexcept
 	{
 		if(contains(hex))
 			return pos;
@@ -113,11 +124,11 @@ public:
 	}
 
 	void clear() noexcept;
-	inline void erase(BattleHex target) noexcept
+	inline void erase(const BattleHex & target) noexcept
 	{
 		assert(contains(target));
 		vstd::erase(internalStorage, target);
-		presenceFlags[target.toInt()] = 0;
+		presenceFlags[target.toInt()] = false;
 	}
 	void erase(iterator first, iterator last) noexcept;
 	inline void pop_back() noexcept
@@ -131,6 +142,20 @@ public:
 		return std::vector<BattleHex>(internalStorage.begin(), internalStorage.end());
 	}
 
+	[[nodiscard]] std::string toString(std::string delimiter = ", ") const noexcept
+	{
+		std::string result = "[";
+		for(auto it = internalStorage.begin(); it != internalStorage.end(); ++it)
+		{
+			if(it != internalStorage.begin())
+				result += delimiter;
+			result += std::to_string(it->toInt());
+		}
+		result += "]";
+
+		return result;
+	}
+
 	template <typename Predicate>
 	iterator findIf(Predicate predicate) noexcept
 	{
@@ -147,7 +172,7 @@ public:
 	BattleHexArray filterBy(Predicate predicate) const noexcept
 	{
 		BattleHexArray filtered;
-		for(auto hex : internalStorage)
+		for(const auto & hex : internalStorage)
 		{
 			if(predicate(hex))
 			{
@@ -158,7 +183,7 @@ public:
 	}
 
 	/// get (precomputed) all possible surrounding tiles
-	static const BattleHexArray & getAllNeighbouringTiles(BattleHex hex) noexcept
+	static const BattleHexArray & getAllNeighbouringTiles(const BattleHex & hex) noexcept
 	{
 		static const BattleHexArray invalid;
 
@@ -169,7 +194,7 @@ public:
 	}
 
 	/// get (precomputed) only valid and available surrounding tiles
-	static const BattleHexArray & getNeighbouringTiles(BattleHex hex) noexcept
+	static const BattleHexArray & getNeighbouringTiles(const BattleHex & hex) noexcept
 	{
 		static const BattleHexArray invalid;
 
@@ -180,23 +205,19 @@ public:
 	}
 
 	/// get (precomputed) only valid and available surrounding tiles for double wide creatures
-	static const BattleHexArray & getNeighbouringTilesDoubleWide(BattleHex hex, BattleSide side) noexcept
+	static const BattleHexArray & getNeighbouringTilesDoubleWide(const BattleHex & hex, BattleSide side) noexcept
 	{
 		assert(hex.isValid() && (side == BattleSide::ATTACKER || side == BattleSide::DEFENDER));
 
 		return neighbouringTilesDoubleWide.at(side)[hex.toInt()];
 	}
 
-	[[nodiscard]] inline bool contains(BattleHex hex) const noexcept
+	/// note: returns true when param is ivalid BattleHex
+	[[nodiscard]] inline bool contains(const BattleHex & hex) const noexcept
 	{
 		if(hex.isValid())
 			return presenceFlags[hex.toInt()];
-		/*
-		if(!isTower(hex))
-			logGlobal->warn("BattleHexArray::contains( %d ) - invalid BattleHex!", hex);
-		*/
 		
-		// returns true also for invalid hexes
 		return true;
 	}
 
@@ -206,7 +227,7 @@ public:
 		s & internalStorage;
 		if(!s.saving)
 		{
-			for(auto hex : internalStorage)
+			for(const auto & hex : internalStorage)
 				presenceFlags[hex.toInt()] = true;
 		}
 	}
@@ -293,24 +314,6 @@ private:
 	StorageType internalStorage;
 	std::bitset<totalSize> presenceFlags;
 
-	[[nodiscard]] inline bool isNotValidForInsertion(BattleHex hex) const
-	{
-		if(isTower(hex))
-			return true;
-		if(!hex.isValid())
-		{
-			//logGlobal->warn("BattleHexArray::insert( %d ) - invalid BattleHex!", hex);
-			return true;
-		}
-
-		return contains(hex) || internalStorage.size() >= totalSize;
-	}
-
-	[[nodiscard]] inline bool isTower(BattleHex hex) const
-	{
-		return hex == BattleHex::CASTLE_CENTRAL_TOWER || hex == BattleHex::CASTLE_UPPER_TOWER || hex == BattleHex::CASTLE_BOTTOM_TOWER;
-	}
-
 	static const ArrayOfBattleHexArrays neighbouringTiles;
 	static const ArrayOfBattleHexArrays allNeighbouringTiles;
 	static const std::map<BattleSide, ArrayOfBattleHexArrays> neighbouringTilesDoubleWide;

+ 8 - 8
lib/battle/BattleInfo.cpp

@@ -40,7 +40,7 @@ SideInBattle & BattleInfo::getSide(BattleSide side)
 }
 
 ///BattleInfo
-CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position)
+CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, const BattleHex & position)
 {
 	PlayerColor owner = getSide(side).color;
 	assert(!owner.isValidPlayer() || (base.armyObj && base.armyObj->tempOwner == owner));
@@ -51,7 +51,7 @@ CStack * BattleInfo::generateNewStack(uint32_t id, const CStackInstance & base,
 	return ret;
 }
 
-CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position)
+CStack * BattleInfo::generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, const BattleHex & position)
 {
 	PlayerColor owner = getSide(side).color;
 	auto * ret = new CStack(&base, owner, id, side, slot);
@@ -231,7 +231,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 				obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
 				currentBattle->obstacles.push_back(obstPtr);
 
-				for(BattleHex blocked : obstPtr->getBlockedTiles())
+				for(const BattleHex & blocked : obstPtr->getBlockedTiles())
 					blockedTiles.insert(blocked);
 				tilesToBlock -= Obstacle(obstPtr->ID).getInfo()->blockedTiles.size() / 2;
 			}
@@ -251,7 +251,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 				const int obid = obidgen.getSuchNumber(appropriateUsualObstacle);
 				const ObstacleInfo &obi = *Obstacle(obid).getInfo();
 
-				auto validPosition = [&](BattleHex pos) -> bool
+				auto validPosition = [&](const BattleHex & pos) -> bool
 				{
 					if(obi.height >= pos.getY())
 						return false;
@@ -262,7 +262,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 					if(blockedTiles.contains(pos))
 						return false;
 
-					for(BattleHex blocked : obi.getBlocked(pos))
+					for(const BattleHex & blocked : obi.getBlocked(pos))
 					{
 						if(tileAccessibility[blocked.toInt()] == EAccessibility::UNAVAILABLE) //for ship-to-ship battlefield - exclude hardcoded unavailable tiles
 							return false;
@@ -284,7 +284,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 				obstPtr->uniqueID = static_cast<si32>(currentBattle->obstacles.size());
 				currentBattle->obstacles.push_back(obstPtr);
 
-				for(BattleHex blocked : obstPtr->getBlockedTiles())
+				for(const BattleHex & blocked : obstPtr->getBlockedTiles())
 					blockedTiles.insert(blocked);
 				tilesToBlock -= static_cast<int>(obi.blockedTiles.size());
 			}
@@ -297,7 +297,7 @@ BattleInfo * BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const
 
 	//adding war machines
 	//Checks if hero has artifact and create appropriate stack
-	auto handleWarMachine = [&](BattleSide side, const ArtifactPosition & artslot, BattleHex hex)
+	auto handleWarMachine = [&](BattleSide side, const ArtifactPosition & artslot, const BattleHex & hex)
 	{
 		const CArtifactInstance * warMachineArt = heroes[side]->getArt(artslot);
 
@@ -682,7 +682,7 @@ void BattleInfo::addUnit(uint32_t id, const JsonNode & data)
 	ret->summoned = info.summoned;
 }
 
-void BattleInfo::moveUnit(uint32_t id, BattleHex destination)
+void BattleInfo::moveUnit(uint32_t id, const BattleHex & destination)
 {
 	auto * sta = getStack(id);
 	if(!sta)

+ 3 - 3
lib/battle/BattleInfo.h

@@ -121,7 +121,7 @@ public:
 	void nextTurn(uint32_t unitId) override;
 
 	void addUnit(uint32_t id, const JsonNode & data) override;
-	void moveUnit(uint32_t id, BattleHex destination) override;
+	void moveUnit(uint32_t id, const BattleHex & destination) override;
 	void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) override;
 	void removeUnit(uint32_t id) override;
 	void updateUnit(uint32_t id, const JsonNode & data) override;
@@ -145,8 +145,8 @@ public:
 	using CBattleInfoEssentials::battleGetFightingHero;
 	CGHeroInstance * battleGetFightingHero(BattleSide side) const;
 
-	CStack * generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, BattleHex position);
-	CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, BattleHex position);
+	CStack * generateNewStack(uint32_t id, const CStackInstance & base, BattleSide side, const SlotID & slot, const BattleHex & position);
+	CStack * generateNewStack(uint32_t id, const CStackBasicDescriptor & base, BattleSide side, const SlotID & slot, const BattleHex & position);
 
 	const SideInBattle & getSide(BattleSide side) const;
 	SideInBattle & getSide(BattleSide side);

+ 50 - 50
lib/battle/CBattleInfoCallback.cpp

@@ -41,7 +41,7 @@ static BattleHex lineToWallHex(int line) //returns hex with wall in given line (
 	return lineToHex[line];
 }
 
-static bool sameSideOfWall(BattleHex pos1, BattleHex pos2)
+static bool sameSideOfWall(const BattleHex & pos1, const BattleHex & pos2)
 {
 	const bool stackLeft = pos1 < lineToWallHex(pos1.getY());
 	const bool destLeft = pos2 < lineToWallHex(pos2.getY());
@@ -49,7 +49,7 @@ static bool sameSideOfWall(BattleHex pos1, BattleHex pos2)
 	return stackLeft == destLeft;
 }
 
-static bool isInsideWalls(BattleHex pos)
+static bool isInsideWalls(const BattleHex & pos)
 {
 	return lineToWallHex(pos.getY()) < pos;
 }
@@ -73,7 +73,7 @@ static const std::pair<int, EWallPart> wallParts[] =
 	std::make_pair(165, EWallPart::INDESTRUCTIBLE_PART)
 };
 
-static EWallPart hexToWallPart(BattleHex hex)
+static EWallPart hexToWallPart(const BattleHex & hex)
 {
 	si16 hexValue = hex.toInt();
 	for(const auto & elem : wallParts)
@@ -144,7 +144,7 @@ ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(const spells::Caster *
 	return ESpellCastProblem::OK;
 }
 
-std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const
+std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(const BattleHex & start, const BattleHex & dest, const battle::Unit * stack) const
 {
 	auto reachability = getReachability(stack);
 
@@ -165,17 +165,17 @@ std::pair< BattleHexArray, int > CBattleInfoCallback::getPath(BattleHex start, B
 	return std::make_pair(path, reachability.distances[dest.toInt()]);
 }
 
-bool CBattleInfoCallback::battleIsInsideWalls(BattleHex from) const
+bool CBattleInfoCallback::battleIsInsideWalls(const BattleHex & from) const
 {
 	return isInsideWalls(from);
 }
 
-bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const
+bool CBattleInfoCallback::battleHasPenaltyOnLine(const BattleHex & from, const BattleHex & dest, bool checkWall, bool checkMoat) const
 {
 	if (!from.isAvailable() || !dest.isAvailable())
 		throw std::runtime_error("Invalid hex (" + std::to_string(from.toInt()) + " and " + std::to_string(dest.toInt()) + ") received in battleHasPenaltyOnLine!" );
 
-	auto isTileBlocked = [&](BattleHex tile)
+	auto isTileBlocked = [&](const BattleHex & tile)
 	{
 		EWallPart wallPart = battleHexToWallPart(tile);
 		if (wallPart == EWallPart::INVALID)
@@ -188,7 +188,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest,
 		return isWallPartAttackable(wallPart);
 	};
 	// Count wall penalty requirement by shortest path, not by arbitrary line, to avoid various OH3 bugs
-	auto getShortestPath = [](BattleHex from, BattleHex dest) -> BattleHexArray
+	auto getShortestPath = [](const BattleHex & from, const BattleHex & dest) -> BattleHexArray
 	{
 		//Out early
 		if(from == dest)
@@ -231,7 +231,7 @@ bool CBattleInfoCallback::battleHasPenaltyOnLine(BattleHex from, BattleHex dest,
 	return checkNeeded && ( (checkWall && pathHasWall) || (checkMoat && pathHasMoat) );
 }
 
-bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const
+bool CBattleInfoCallback::battleHasWallPenalty(const IBonusBearer * shooter, const BattleHex & shooterPosition, const BattleHex & destHex) const
 {
 	RETURN_IF_NOT_BATTLE(false);
 	if(battleGetFortifications().wallsHealth == 0)
@@ -313,14 +313,14 @@ PossiblePlayerBattleAction CBattleInfoCallback::getCasterAction(const CSpell * s
 	return PossiblePlayerBattleAction(spellSelMode, spell->id);
 }
 
-BattleHexArray CBattleInfoCallback::battleGetAttackedHexes(const battle::Unit * attacker, BattleHex destinationTile, BattleHex attackerPos) const
+BattleHexArray CBattleInfoCallback::battleGetAttackedHexes(const battle::Unit * attacker, const BattleHex & destinationTile, const BattleHex & attackerPos) const
 {
 	BattleHexArray attackedHexes;
 	RETURN_IF_NOT_BATTLE(attackedHexes);
 
 	AttackableTiles at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos);
 
-	for (BattleHex tile : at.hostileCreaturePositions)
+	for (const BattleHex & tile : at.hostileCreaturePositions)
 	{
 		const auto * st = battleGetUnitByPos(tile, true);
 		if(st && st->unitOwner() != attacker->unitOwner()) //only hostile stacks - does it work well with Berserk?
@@ -328,7 +328,7 @@ BattleHexArray CBattleInfoCallback::battleGetAttackedHexes(const battle::Unit *
 			attackedHexes.insert(tile);
 		}
 	}
-	for (BattleHex tile : at.friendlyCreaturePositions)
+	for (const BattleHex & tile : at.friendlyCreaturePositions)
 	{
 		if(battleGetUnitByPos(tile, true)) //friendly stacks can also be damaged by Dragon Breath
 		{
@@ -338,7 +338,7 @@ BattleHexArray CBattleInfoCallback::battleGetAttackedHexes(const battle::Unit *
 	return attackedHexes;
 }
 
-const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyAlive) const
+const CStack* CBattleInfoCallback::battleGetStackByPos(const BattleHex & pos, bool onlyAlive) const
 {
 	RETURN_IF_NOT_BATTLE(nullptr);
 	for(const auto * s : battleGetAllStacks(true))
@@ -348,7 +348,7 @@ const CStack* CBattleInfoCallback::battleGetStackByPos(BattleHex pos, bool onlyA
 	return nullptr;
 }
 
-const battle::Unit * CBattleInfoCallback::battleGetUnitByPos(BattleHex pos, bool onlyAlive) const
+const battle::Unit * CBattleInfoCallback::battleGetUnitByPos(const BattleHex & pos, bool onlyAlive) const
 {
 	RETURN_IF_NOT_BATTLE(nullptr);
 
@@ -622,7 +622,7 @@ BattleHexArray CBattleInfoCallback::battleGetAvailableHexes(const battle::Unit *
 	{
 		BattleHexArray occupiable;
 
-		for(auto hex : ret)
+		for(const auto & hex : ret)
 			occupiable.insert(unit->occupiedHex(hex));
 
 		ret.insert(occupiable);
@@ -631,11 +631,11 @@ BattleHexArray CBattleInfoCallback::battleGetAvailableHexes(const battle::Unit *
 
 	if(attackable)
 	{
-		auto meleeAttackable = [&](BattleHex hex) -> bool
+		auto meleeAttackable = [&](const BattleHex & hex) -> bool
 		{
 			// Return true if given hex has at least one available neighbour.
 			// Available hexes are already present in ret vector.
-			auto availableNeighbour = boost::find_if(ret, [=] (BattleHex availableHex)
+			auto availableNeighbour = boost::find_if(ret, [=] (const BattleHex & availableHex)
 			{
 				return BattleHex::mutualPosition(hex, availableHex) >= 0;
 			});
@@ -654,7 +654,7 @@ BattleHexArray CBattleInfoCallback::battleGetAvailableHexes(const battle::Unit *
 				continue;
 			}
 
-			for(BattleHex he : occupied)
+			for(const BattleHex & he : occupied)
 			{
 				if(meleeAttackable(he))
 					attackable->insert(he);
@@ -665,7 +665,7 @@ BattleHexArray CBattleInfoCallback::battleGetAvailableHexes(const battle::Unit *
 	return ret;
 }
 
-bool CBattleInfoCallback::battleCanAttack(const battle::Unit * stack, const battle::Unit * target, BattleHex dest) const
+bool CBattleInfoCallback::battleCanAttack(const battle::Unit * stack, const battle::Unit * target, const BattleHex & dest) const
 {
 	RETURN_IF_NOT_BATTLE(false);
 
@@ -729,7 +729,7 @@ bool CBattleInfoCallback::battleCanTargetEmptyHex(const battle::Unit * attacker)
 	return false;
 }
 
-bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker, BattleHex dest) const
+bool CBattleInfoCallback::battleCanShoot(const battle::Unit * attacker, const BattleHex & dest) const
 {
 	RETURN_IF_NOT_BATTLE(false);
 
@@ -777,7 +777,7 @@ DamageEstimation CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &
 	return calculator.calculateDmgRange();
 }
 
-DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerPosition, DamageEstimation * retaliationDmg) const
+DamageEstimation CBattleInfoCallback::battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, const BattleHex & attackerPosition, DamageEstimation * retaliationDmg) const
 {
 	RETURN_IF_NOT_BATTLE({});
 	auto reachability = battleGetDistances(attacker, attacker->getPosition());
@@ -840,7 +840,7 @@ DamageEstimation CBattleInfoCallback::battleEstimateDamage(const BattleAttackInf
 	return ret;
 }
 
-std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking) const
+std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::battleGetAllObstaclesOnPos(const BattleHex & tile, bool onlyBlocking) const
 {
 	auto obstacles = std::vector<std::shared_ptr<const CObstacleInstance>>();
 	RETURN_IF_NOT_BATTLE(obstacles);
@@ -871,7 +871,7 @@ std::vector<std::shared_ptr<const CObstacleInstance>> CBattleInfoCallback::getAl
 					if(!vstd::contains(affectedObstacles, i))
 						affectedObstacles.push_back(i);
 		}
-		for(auto hex : unit->getHexes())
+		for(const auto & hex : unit->getHexes())
 			if(hex == BattleHex::GATE_BRIDGE && battleIsGatePassable())
 				for(int i=0; i<affectedObstacles.size(); i++)
 					if(affectedObstacles.at(i)->obstacleType == CObstacleInstance::MOAT)
@@ -959,7 +959,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
 
 	if(bFieldType != BattleField::NONE)
 	{
-		for(auto hex : bFieldType.getInfo()->impassableHexes)
+		for(const auto & hex : bFieldType.getInfo()->impassableHexes)
 			ret[hex.toInt()] = EAccessibility::UNAVAILABLE;
 	}
 
@@ -983,7 +983,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
 	//tiles occupied by standing stacks
 	for(const auto * unit : battleAliveUnits())
 	{
-		for(auto hex : unit->getHexes())
+		for(const auto & hex : unit->getHexes())
 			if(hex.isAvailable()) //towers can have <0 pos; we don't also want to overwrite side columns
 				ret[hex.toInt()] = EAccessibility::ALIVE_STACK;
 	}
@@ -991,7 +991,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
 	//obstacles
 	for(const auto &obst : battleGetAllObstacles())
 	{
-		for(auto hex : obst->getBlockedTiles())
+		for(const auto & hex : obst->getBlockedTiles())
 			ret[hex.toInt()] = EAccessibility::OBSTACLE;
 	}
 
@@ -999,7 +999,7 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
 	if(battleGetFortifications().wallsHealth > 0)
 	{
 		static const int permanentlyLocked[] = {12, 45, 62, 112, 147, 165};
-		for(auto hex : permanentlyLocked)
+		for(const auto & hex : permanentlyLocked)
 			ret[hex] = EAccessibility::UNAVAILABLE;
 
 		//TODO likely duplicated logic
@@ -1024,13 +1024,13 @@ AccessibilityInfo CBattleInfoCallback::getAccessibility() const
 
 AccessibilityInfo CBattleInfoCallback::getAccessibility(const battle::Unit * stack) const
 {
-	return getAccessibility(battle::Unit::getHexes(stack->getPosition(), stack->doubleWide(), stack->unitSide()));
+	return getAccessibility(stack->getHexes());
 }
 
 AccessibilityInfo CBattleInfoCallback::getAccessibility(const BattleHexArray & accessibleHexes) const
 {
 	auto ret = getAccessibility();
-	for(auto hex : accessibleHexes)
+	for(const auto & hex : accessibleHexes)
 		if(hex.isValid())
 			ret[hex.toInt()] = EAccessibility::ACCESSIBLE;
 
@@ -1074,7 +1074,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
 
 		const int costToNeighbour = ret.distances.at(curHex.toInt()) + 1;
 
-		for(BattleHex neighbour : curHex.getNeighbouringTiles())
+		for(const BattleHex & neighbour : curHex.getNeighbouringTiles())
 		{
 			auto additionalCost = 0;
 
@@ -1103,12 +1103,12 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo & accessib
 }
 
 bool CBattleInfoCallback::isInObstacle(
-	BattleHex hex,
+	const BattleHex & hex,
 	const BattleHexArray & obstacleHexes,
 	const ReachabilityInfo::Parameters & params) const
 {
 
-	for(auto occupiedHex : battle::Unit::getHexes(hex, params.doubleWide, params.side))
+	for(const auto & occupiedHex : battle::Unit::getHexes(hex, params.doubleWide, params.side))
 	{
 		if(params.ignoreKnownAccessible && params.knownAccessible->contains(occupiedHex))
 			continue;
@@ -1138,7 +1138,7 @@ BattleHexArray CBattleInfoCallback::getStoppers(BattleSide whichSidePerspective)
 		if(!battleIsObstacleVisibleForSide(*oi, whichSidePerspective))
 			continue;
 
-		for(auto hex : oi->getStoppingTile())
+		for(const auto & hex : oi->getStoppingTile())
 		{
 			if(hex == BattleHex::GATE_BRIDGE && oi->obstacleType == CObstacleInstance::MOAT)
 			{
@@ -1173,7 +1173,7 @@ std::pair<const battle::Unit *, BattleHex> CBattleInfoCallback::getNearestStack(
 
 	for(const battle::Unit * st : possible)
 	{
-		for(BattleHex hex : avHexes)
+		for(const BattleHex & hex : avHexes)
 			if(CStack::isMeleeAttackPossible(closest, st, hex))
 			{
 				DistStack hlp = {reachability.distances[hex.toInt()], hex, st};
@@ -1232,7 +1232,7 @@ si8 CBattleInfoCallback::battleGetTacticDist() const
 	return 0;
 }
 
-bool CBattleInfoCallback::isInTacticRange(BattleHex dest) const
+bool CBattleInfoCallback::isInTacticRange(const BattleHex & dest) const
 {
 	RETURN_IF_NOT_BATTLE(false);
 	auto side = battleGetTacticsSide();
@@ -1340,7 +1340,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
 	if(attacker->hasBonusOfType(BonusType::THREE_HEADED_ATTACK))
 	{
 		const BattleHexArray & hexes = attacker->getSurroundingHexes(attackerPos);
-		for(BattleHex tile : hexes)
+		for(const BattleHex & tile : hexes)
 		{
 			if((BattleHex::mutualPosition(tile, destinationTile) > -1 && BattleHex::mutualPosition(tile, attackOriginHex) > -1)) //adjacent both to attacker's head and attacked tile
 			{
@@ -1356,7 +1356,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
 		if (hexes.contains(attackOriginHex))
 			hexes.erase(attackOriginHex);
 
-		for(BattleHex tile : hexes)
+		for(const BattleHex & tile : hexes)
 		{
 			//friendly stacks can also be damaged by Dragon Breath
 			const auto * st = battleGetUnitByPos(tile, true);
@@ -1414,7 +1414,7 @@ AttackableTiles CBattleInfoCallback::getPotentiallyAttackableHexes(
 	return at;
 }
 
-AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::Unit * attacker, BattleHex destinationTile, BattleHex attackerPos) const
+AttackableTiles CBattleInfoCallback::getPotentiallyShootableHexes(const battle::Unit * attacker, const BattleHex & destinationTile, const BattleHex & attackerPos) const
 {
 	//does not return hex attacked directly
 	AttackableTiles at;
@@ -1458,7 +1458,7 @@ battle::Units CBattleInfoCallback::getAttackedBattleUnits(
 		if (unit->isGhost() || !unit->alive())
 			return false;
 
-		for (BattleHex hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
+		for (const BattleHex & hex : unit->getHexes())
 		{
 			if (at.hostileCreaturePositions.contains(hex))
 				return true;
@@ -1471,7 +1471,7 @@ battle::Units CBattleInfoCallback::getAttackedBattleUnits(
 	return units;
 }
 
-std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos) const
+std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack* attacker, const BattleHex & destinationTile, bool rangedAttack, BattleHex attackerPos) const
 {
 	std::set<const CStack*> attackedCres;
 	RETURN_IF_NOT_BATTLE(attackedCres);
@@ -1483,7 +1483,7 @@ std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack*
 	else
 		at = getPotentiallyAttackableHexes(attacker, destinationTile, attackerPos);
 
-	for (BattleHex tile : at.hostileCreaturePositions) //all around & three-headed attack
+	for (const BattleHex & tile : at.hostileCreaturePositions) //all around & three-headed attack
 	{
 		const CStack * st = battleGetStackByPos(tile, true);
 		if(st && st->unitOwner() != attacker->unitOwner()) //only hostile stacks - does it work well with Berserk?
@@ -1491,7 +1491,7 @@ std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack*
 			attackedCres.insert(st);
 		}
 	}
-	for (BattleHex tile : at.friendlyCreaturePositions)
+	for (const BattleHex & tile : at.friendlyCreaturePositions)
 	{
 		const CStack * st = battleGetStackByPos(tile, true);
 		if(st) //friendly stacks can also be damaged by Dragon Breath
@@ -1502,7 +1502,7 @@ std::set<const CStack*> CBattleInfoCallback::getAttackedCreatures(const CStack*
 	return attackedCres;
 }
 
-static bool isHexInFront(BattleHex hex, BattleHex testHex, BattleSide side )
+static bool isHexInFront(const BattleHex & hex, const BattleHex & testHex, BattleSide side )
 {
 	static const std::set<BattleHex::EDir> rightDirs { BattleHex::BOTTOM_RIGHT, BattleHex::TOP_RIGHT, BattleHex::RIGHT };
 	static const std::set<BattleHex::EDir> leftDirs  { BattleHex::BOTTOM_LEFT, BattleHex::TOP_LEFT, BattleHex::LEFT };
@@ -1559,7 +1559,7 @@ bool CBattleInfoCallback::isToReverse(const battle::Unit * attacker, const battl
 	return true;
 }
 
-ReachabilityInfo::TDistances CBattleInfoCallback::battleGetDistances(const battle::Unit * unit, BattleHex assumedPosition) const
+ReachabilityInfo::TDistances CBattleInfoCallback::battleGetDistances(const battle::Unit * unit, const BattleHex & assumedPosition) const
 {
 	ReachabilityInfo::TDistances ret;
 	ret.fill(-1);
@@ -1572,7 +1572,7 @@ ReachabilityInfo::TDistances CBattleInfoCallback::battleGetDistances(const battl
 	return ret;
 }
 
-bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const
+bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter, const BattleHex & shooterPosition, const BattleHex & destHex) const
 {
 	RETURN_IF_NOT_BATTLE(false);
 
@@ -1603,16 +1603,16 @@ bool CBattleInfoCallback::battleHasDistancePenalty(const IBonusBearer * shooter,
 	return true;
 }
 
-bool CBattleInfoCallback::isEnemyUnitWithinSpecifiedRange(BattleHex attackerPosition, const battle::Unit * defenderUnit, unsigned int range) const
+bool CBattleInfoCallback::isEnemyUnitWithinSpecifiedRange(const BattleHex & attackerPosition, const battle::Unit * defenderUnit, unsigned int range) const
 {
-	for(auto hex : defenderUnit->getHexes())
+	for(const auto & hex : defenderUnit->getHexes())
 		if(BattleHex::getDistance(attackerPosition, hex) <= range)
 			return true;
 	
 	return false;
 }
 
-bool CBattleInfoCallback::isHexWithinSpecifiedRange(BattleHex attackerPosition, BattleHex targetPosition, unsigned int range) const
+bool CBattleInfoCallback::isHexWithinSpecifiedRange(const BattleHex & attackerPosition, const BattleHex & targetPosition, unsigned int range) const
 {
 	if(BattleHex::getDistance(attackerPosition, targetPosition) <= range)
 		return true;
@@ -1626,7 +1626,7 @@ BattleHex CBattleInfoCallback::wallPartToBattleHex(EWallPart part) const
 	return WallPartToHex(part);
 }
 
-EWallPart CBattleInfoCallback::battleHexToWallPart(BattleHex hex) const
+EWallPart CBattleInfoCallback::battleHexToWallPart(const BattleHex & hex) const
 {
 	RETURN_IF_NOT_BATTLE(EWallPart::INVALID);
 	return hexToWallPart(hex);
@@ -1692,7 +1692,7 @@ int32_t CBattleInfoCallback::battleGetSpellCost(const spells::Spell * sp, const
 	return std::max(0, ret - manaReduction + manaIncrease);
 }
 
-bool CBattleInfoCallback::battleHasShootingPenalty(const battle::Unit * shooter, BattleHex destHex) const
+bool CBattleInfoCallback::battleHasShootingPenalty(const battle::Unit * shooter, const BattleHex & destHex) const
 {
 	return battleHasDistancePenalty(shooter, shooter->getPosition(), destHex) || battleHasWallPenalty(shooter, shooter->getPosition(), destHex);
 }

+ 21 - 21
lib/battle/CBattleInfoCallback.h

@@ -58,14 +58,14 @@ class DLL_LINKAGE CBattleInfoCallback : public virtual CBattleInfoEssentials
 public:
 	std::optional<BattleSide> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
 
-	std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
+	std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(const BattleHex & tile, bool onlyBlocking = true) const override;
 	std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const BattleHexArray & passed) const override;
 	//Handle obstacle damage here, requires SpellCastEnvironment
 	bool handleObstacleTriggersForUnit(SpellCastEnvironment & spellEnv, const battle::Unit & unit, const BattleHexArray & passed = {}) const;
 
-	const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const;
+	const CStack * battleGetStackByPos(const BattleHex & pos, bool onlyAlive = true) const;
 
-	const battle::Unit * battleGetUnitByPos(BattleHex pos, bool onlyAlive = true) const override;
+	const battle::Unit * battleGetUnitByPos(const BattleHex & pos, bool onlyAlive = true) const override;
 
 	///returns all alive units excluding turrets
 	battle::Units battleAliveUnits() const;
@@ -83,16 +83,16 @@ public:
 	BattleHexArray battleGetAvailableHexes(const ReachabilityInfo & cache, const battle::Unit * unit, bool obtainMovementRange) const;
 
 	int battleGetSurrenderCost(const PlayerColor & Player) const; //returns cost of surrendering battle, -1 if surrendering is not possible
-	ReachabilityInfo::TDistances battleGetDistances(const battle::Unit * unit, BattleHex assumedPosition) const;
-	BattleHexArray battleGetAttackedHexes(const battle::Unit * attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID) const;
-	bool isEnemyUnitWithinSpecifiedRange(BattleHex attackerPosition, const battle::Unit * defenderUnit, unsigned int range) const;
-	bool isHexWithinSpecifiedRange(BattleHex attackerPosition, BattleHex targetPosition, unsigned int range) const;
+	ReachabilityInfo::TDistances battleGetDistances(const battle::Unit * unit, const BattleHex & assumedPosition) const;
+	BattleHexArray battleGetAttackedHexes(const battle::Unit * attacker, const BattleHex & destinationTile, const BattleHex & attackerPos = BattleHex::INVALID) const;
+	bool isEnemyUnitWithinSpecifiedRange(const BattleHex & attackerPosition, const battle::Unit * defenderUnit, unsigned int range) const;
+	bool isHexWithinSpecifiedRange(const BattleHex & attackerPosition, const BattleHex & targetPosition, unsigned int range) const;
 
-	std::pair< BattleHexArray, int > getPath(BattleHex start, BattleHex dest, const battle::Unit * stack) const;
+	std::pair< BattleHexArray, int > getPath(const BattleHex & start, const BattleHex & dest, const battle::Unit * stack) const;
 
 	bool battleCanTargetEmptyHex(const battle::Unit * attacker) const; //determines of stack with given ID can target empty hex to attack - currently used only for SPELL_LIKE_ATTACK shooting
-	bool battleCanAttack(const battle::Unit * stack, const battle::Unit * target, BattleHex dest) const; //determines if stack with given ID can attack target at the selected destination
-	bool battleCanShoot(const battle::Unit * attacker, BattleHex dest) const; //determines if stack with given ID shoot at the selected destination
+	bool battleCanAttack(const battle::Unit * stack, const battle::Unit * target, const BattleHex & dest) const; //determines if stack with given ID can attack target at the selected destination
+	bool battleCanShoot(const battle::Unit * attacker, const BattleHex & dest) const; //determines if stack with given ID shoot at the selected destination
 	bool battleCanShoot(const battle::Unit * attacker) const; //determines if stack with given ID shoot in principle
 	bool battleIsUnitBlocked(const battle::Unit * unit) const; //returns true if there is neighboring enemy stack
 	battle::Units battleAdjacentUnits(const battle::Unit * unit) const;
@@ -103,17 +103,17 @@ public:
 	/// only non-random bonuses are considered in estimation
 	/// returns pair <min dmg, max dmg>
 	DamageEstimation battleEstimateDamage(const BattleAttackInfo & bai, DamageEstimation * retaliationDmg = nullptr) const;
-	DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerPosition, DamageEstimation * retaliationDmg = nullptr) const;
+	DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, const BattleHex & attackerPosition, DamageEstimation * retaliationDmg = nullptr) const;
 	DamageEstimation battleEstimateDamage(const battle::Unit * attacker, const battle::Unit * defender, int getMovementRange, DamageEstimation * retaliationDmg = nullptr) const;
 
-	bool battleIsInsideWalls(BattleHex from) const;
-	bool battleHasPenaltyOnLine(BattleHex from, BattleHex dest, bool checkWall, bool checkMoat) const;
-	bool battleHasDistancePenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
-	bool battleHasWallPenalty(const IBonusBearer * shooter, BattleHex shooterPosition, BattleHex destHex) const;
-	bool battleHasShootingPenalty(const battle::Unit * shooter, BattleHex destHex) const;
+	bool battleIsInsideWalls(const BattleHex & from) const;
+	bool battleHasPenaltyOnLine(const BattleHex & from, const BattleHex & dest, bool checkWall, bool checkMoat) const;
+	bool battleHasDistancePenalty(const IBonusBearer * shooter, const BattleHex & shooterPosition, const BattleHex & destHex) const;
+	bool battleHasWallPenalty(const IBonusBearer * shooter, const BattleHex & shooterPosition, const BattleHex & destHex) const;
+	bool battleHasShootingPenalty(const battle::Unit * shooter, const BattleHex & destHex) const;
 
 	BattleHex wallPartToBattleHex(EWallPart part) const;
-	EWallPart battleHexToWallPart(BattleHex hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
+	EWallPart battleHexToWallPart(const BattleHex & hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
 	bool isWallPartPotentiallyAttackable(EWallPart wallPart) const; // returns true if the wall part is potentially attackable (independent of wall state), false if not
 	bool isWallPartAttackable(EWallPart wallPart) const; // returns true if the wall part is actually attackable, false if not
 	BattleHexArray getAttackableBattleHexes() const;
@@ -130,7 +130,7 @@ public:
 	PossiblePlayerBattleAction getCasterAction(const CSpell * spell, const spells::Caster * caster, spells::Mode mode) const;
 
 	//convenience methods using the ones above
-	bool isInTacticRange(BattleHex dest) const;
+	bool isInTacticRange(const BattleHex & dest) const;
 	si8 battleGetTacticDist() const; //returns tactic distance for calling player or 0 if this player is not in tactic phase (for ALL_KNOWING actual distance for tactic side)
 
 	AttackableTiles getPotentiallyAttackableHexes(
@@ -145,7 +145,7 @@ public:
 		BattleHex destinationTile,
 		BattleHex attackerPos) const;
 
-	AttackableTiles getPotentiallyShootableHexes(const  battle::Unit* attacker, BattleHex destinationTile, BattleHex attackerPos) const;
+	AttackableTiles getPotentiallyShootableHexes(const  battle::Unit* attacker, const BattleHex & destinationTile, const BattleHex & attackerPos) const;
 
 	battle::Units getAttackedBattleUnits(
 		const battle::Unit* attacker,
@@ -155,7 +155,7 @@ public:
 		BattleHex attackerPos = BattleHex::INVALID,
 		BattleHex defenderPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
 	
-	std::set<const CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, bool rangedAttack, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
+	std::set<const CStack*> getAttackedCreatures(const CStack* attacker, const BattleHex & destinationTile, bool rangedAttack, BattleHex attackerPos = BattleHex::INVALID) const; //calculates range of multi-hex attacks
 	bool isToReverse(const battle::Unit * attacker, const battle::Unit * defender, BattleHex attackerHex = BattleHex::INVALID, BattleHex defenderHex = BattleHex::INVALID) const; //determines if attacker standing at attackerHex should reverse in order to attack defender
 
 	ReachabilityInfo getReachability(const battle::Unit * unit) const;
@@ -169,7 +169,7 @@ public:
 protected:
 	ReachabilityInfo getFlyingReachability(const ReachabilityInfo::Parameters & params) const;
 	ReachabilityInfo makeBFS(const AccessibilityInfo & accessibility, const ReachabilityInfo::Parameters & params) const;
-	bool isInObstacle(BattleHex hex, const BattleHexArray & obstacles, const ReachabilityInfo::Parameters & params) const;
+	bool isInObstacle(const BattleHex & hex, const BattleHexArray & obstacles, const ReachabilityInfo::Parameters & params) const;
 	BattleHexArray getStoppers(BattleSide whichSidePerspective) const; //get hexes with stopping obstacles (quicksands)
 };
 

+ 1 - 1
lib/battle/CUnitState.cpp

@@ -577,7 +577,7 @@ BattleHex CUnitState::getPosition() const
 	return position;
 }
 
-void CUnitState::setPosition(BattleHex hex)
+void CUnitState::setPosition(const BattleHex & hex)
 {
 	position = hex;
 }

+ 1 - 1
lib/battle/CUnitState.h

@@ -212,7 +212,7 @@ public:
 	uint32_t getMaxHealth() const override;
 
 	BattleHex getPosition() const override;
-	void setPosition(BattleHex hex) override;
+	void setPosition(const BattleHex & hex) override;
 	int32_t getInitiative(int turn = 0) const override;
 	uint8_t getRangedFullDamageDistance() const;
 	uint8_t getShootingRangeDistance() const;

+ 2 - 2
lib/battle/IBattleInfoCallback.h

@@ -75,12 +75,12 @@ public:
 	virtual battle::Units battleGetUnitsIf(const battle::UnitFilter & predicate) const = 0;
 
 	virtual const battle::Unit * battleGetUnitByID(uint32_t ID) const = 0;
-	virtual const battle::Unit * battleGetUnitByPos(BattleHex pos, bool onlyAlive = true) const = 0;
+	virtual const battle::Unit * battleGetUnitByPos(const BattleHex & pos, bool onlyAlive = true) const = 0;
 
 	virtual const battle::Unit * battleActiveUnit() const = 0;
 
 	//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
-	virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
+	virtual std::vector<std::shared_ptr<const CObstacleInstance>> battleGetAllObstaclesOnPos(const BattleHex & tile, bool onlyBlocking = true) const = 0;
 	virtual std::vector<std::shared_ptr<const CObstacleInstance>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const BattleHexArray & passed) const = 0;
 };
 

+ 1 - 1
lib/battle/IBattleState.h

@@ -84,7 +84,7 @@ public:
 
 	virtual void addUnit(uint32_t id, const JsonNode & data) = 0;
 	virtual void setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta) = 0;
-	virtual void moveUnit(uint32_t id, BattleHex destination) = 0;
+	virtual void moveUnit(uint32_t id, const BattleHex & destination) = 0;
 	virtual void removeUnit(uint32_t id) = 0;
 	virtual void updateUnit(uint32_t id, const JsonNode & data) = 0;
 

+ 4 - 4
lib/battle/ReachabilityInfo.cpp

@@ -14,7 +14,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, BattleHex StartPosition):
+ReachabilityInfo::Parameters::Parameters(const battle::Unit * Stack, const BattleHex & StartPosition):
 	perspective(static_cast<BattleSide>(Stack->unitSide())),
 	startPosition(StartPosition),
 	doubleWide(Stack->doubleWide()),
@@ -31,7 +31,7 @@ ReachabilityInfo::ReachabilityInfo()
 	predecessors.fill(BattleHex::INVALID);
 }
 
-bool ReachabilityInfo::isReachable(BattleHex hex) const
+bool ReachabilityInfo::isReachable(const BattleHex & hex) const
 {
 	return distances[hex.toInt()] < INFINITE_DIST;
 }
@@ -42,7 +42,7 @@ uint32_t ReachabilityInfo::distToNearestNeighbour(
 {
 	uint32_t ret = 1000000;
 
-	for(auto targetHex : targetHexes)
+	for(const auto & targetHex : targetHexes)
 	{
 		for(auto & n : targetHex.getNeighbouringTiles())
 		{
@@ -79,7 +79,7 @@ uint32_t ReachabilityInfo::distToNearestNeighbour(
 		}
 	}
 
-	vstd::erase_if(attackableHexes, [defender](BattleHex h) -> bool
+	vstd::erase_if(attackableHexes, [defender](const BattleHex & h) -> bool
 		{
 			return h.getY() != defender->getPosition().getY() || !h.isAvailable();
 		});

+ 2 - 2
lib/battle/ReachabilityInfo.h

@@ -42,7 +42,7 @@ struct DLL_LINKAGE ReachabilityInfo
 		{
 			destructibleEnemyTurns.fill(-1);
 		}
-		Parameters(const battle::Unit * Stack, BattleHex StartPosition);
+		Parameters(const battle::Unit * Stack, const BattleHex & StartPosition);
 	};
 
 	Parameters params;
@@ -52,7 +52,7 @@ struct DLL_LINKAGE ReachabilityInfo
 
 	ReachabilityInfo();
 
-	bool isReachable(BattleHex hex) const;
+	bool isReachable(const BattleHex & hex) const;
 
 	uint32_t distToNearestNeighbour(
 		const BattleHexArray & targetHexes,

+ 11 - 17
lib/battle/Unit.cpp

@@ -51,14 +51,14 @@ const IBonusBearer* Unit::getBonusBearer() const
 	return this;
 }
 
-const BattleHexArray & Unit::getSurroundingHexes(BattleHex assumedPosition) const
+const BattleHexArray & Unit::getSurroundingHexes(const BattleHex & assumedPosition) const
 {
 	BattleHex hex = (assumedPosition.toInt() != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position
 
 	return getSurroundingHexes(hex, doubleWide(), unitSide());
 }
 
-const BattleHexArray & Unit::getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side)
+const BattleHexArray & Unit::getSurroundingHexes(const BattleHex & position, bool twoHex, BattleSide side)
 {
 	if(!twoHex)
 		return position.getNeighbouringTiles();
@@ -68,31 +68,25 @@ const BattleHexArray & Unit::getSurroundingHexes(BattleHex position, bool twoHex
 
 BattleHexArray Unit::getAttackableHexes(const Unit * attacker) const
 {
-	const BattleHexArray & defenderHexes = battle::Unit::getHexes(
-		getPosition(),
-		doubleWide(),
-		unitSide());
+	const BattleHexArray & defenderHexes = getHexes();
 	
 	BattleHexArray targetableHexes;
 
-	for(auto defenderHex : defenderHexes)
+	for(const auto & defenderHex : defenderHexes)
 	{
-		auto hexes = battle::Unit::getHexes(
-			defenderHex,
-			attacker->doubleWide(),
-			unitSide());
+		auto hexes = battle::Unit::getHexes(defenderHex);
 
 		if(hexes.size() == 2 && BattleHex::getDistance(hexes.front(), hexes.back()) != 1)
 			hexes.pop_back();
 
-		for(auto hex : hexes)
+		for(const auto & hex : hexes)
 			targetableHexes.insert(hex.getNeighbouringTiles());
 	}
 
 	return targetableHexes;
 }
 
-bool Unit::coversPos(BattleHex pos) const
+bool Unit::coversPos(const BattleHex & pos) const
 {
 	return getPosition() == pos || (doubleWide() && (occupiedHex() == pos));
 }
@@ -102,7 +96,7 @@ const BattleHexArray & Unit::getHexes() const
 	return getHexes(getPosition(), doubleWide(), unitSide());
 }
 
-const BattleHexArray & Unit::getHexes(BattleHex assumedPos) const
+const BattleHexArray & Unit::getHexes(const BattleHex & assumedPos) const
 {
 	return getHexes(assumedPos, doubleWide(), unitSide());
 }
@@ -125,7 +119,7 @@ BattleHexArray::ArrayOfBattleHexArrays Unit::precomputeUnitHexes(BattleSide side
 	return result;
 }
 
-const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
+const BattleHexArray & Unit::getHexes(const BattleHex & assumedPos, bool twoHex, BattleSide side)
 {
 	static const std::array<BattleHexArray::ArrayOfBattleHexArrays, 4> precomputed = {
 		precomputeUnitHexes(BattleSide::ATTACKER, false),
@@ -159,12 +153,12 @@ BattleHex Unit::occupiedHex() const
 	return occupiedHex(getPosition(), doubleWide(), unitSide());
 }
 
-BattleHex Unit::occupiedHex(BattleHex assumedPos) const
+BattleHex Unit::occupiedHex(const BattleHex & assumedPos) const
 {
 	return occupiedHex(assumedPos, doubleWide(), unitSide());
 }
 
-BattleHex Unit::occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side)
+BattleHex Unit::occupiedHex(const BattleHex & assumedPos, bool twoHex, BattleSide side)
 {
 	if(twoHex)
 	{

+ 8 - 8
lib/battle/Unit.h

@@ -116,7 +116,7 @@ public:
 	virtual int getTotalAttacks(bool ranged) const = 0;
 
 	virtual BattleHex getPosition() const = 0;
-	virtual void setPosition(BattleHex hex) = 0;
+	virtual void setPosition(const BattleHex & hex) = 0;
 
 	virtual bool canMove(int turn = 0) const = 0; //if stack can move
 	virtual bool defended(int turn = 0) const = 0;
@@ -131,19 +131,19 @@ public:
 
 	virtual std::string getDescription() const;
 
-	const BattleHexArray & getSurroundingHexes(BattleHex assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
+	const BattleHexArray & getSurroundingHexes(const BattleHex & assumedPosition = BattleHex::INVALID) const; // get six or 8 surrounding hexes depending on creature size
 	BattleHexArray getAttackableHexes(const Unit * attacker) const;
-	static const BattleHexArray & getSurroundingHexes(BattleHex position, bool twoHex, BattleSide side);
+	static const BattleHexArray & getSurroundingHexes(const BattleHex & position, bool twoHex, BattleSide side);
 
-	bool coversPos(BattleHex position) const; //checks also if unit is double-wide
+	bool coversPos(const BattleHex & position) const; //checks also if unit is double-wide
 
 	const BattleHexArray & getHexes() const; //up to two occupied hexes, starting from front
-	const BattleHexArray & getHexes(BattleHex assumedPos) const; //up to two occupied hexes, starting from front
-	static const BattleHexArray & getHexes(BattleHex assumedPos, bool twoHex, BattleSide side);
+	const BattleHexArray & getHexes(const BattleHex & assumedPos) const; //up to two occupied hexes, starting from front
+	static const BattleHexArray & getHexes(const BattleHex & assumedPos, bool twoHex, BattleSide side);
 
 	BattleHex occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1
-	BattleHex occupiedHex(BattleHex assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
-	static BattleHex occupiedHex(BattleHex assumedPos, bool twoHex, BattleSide side);
+	BattleHex occupiedHex(const BattleHex & assumedPos) const; //returns number of occupied hex (not the position) if stack is double wide and would stand on assumedPos; otherwise -1
+	static BattleHex occupiedHex(const BattleHex & assumedPos, bool twoHex, BattleSide side);
 
 	///MetaStrings
 	void addText(MetaString & text, EMetaText type, int32_t serial, const boost::logic::tribool & plural = boost::logic::indeterminate) const;

+ 2 - 2
lib/bonuses/Limiters.cpp

@@ -221,7 +221,7 @@ ILimiter::EDecision UnitOnHexLimiter::limit(const BonusLimitationContext &contex
 
 	auto accept = false;
 
-	for (auto hex : stack->getHexes())
+	for (const auto & hex : stack->getHexes())
 		accept |= applicableHexes.contains(hex);
 
 	return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
@@ -237,7 +237,7 @@ JsonNode UnitOnHexLimiter::toJsonNode() const
 	JsonNode root;
 
 	root["type"].String() = "UNIT_ON_HEXES";
-	for(auto hex : applicableHexes)
+	for(const auto & hex : applicableHexes)
 		root["parameters"].Vector().emplace_back(hex.toInt());
 
 	return root;

+ 3 - 3
lib/logging/VisualLogger.h

@@ -26,7 +26,7 @@ public:
 class IBattleOverlayLogVisualizer
 {
 public:
-	virtual void drawText(BattleHex tile, int lineNumber, const std::string & text) = 0;
+	virtual void drawText(const BattleHex & tile, int lineNumber, const std::string & text) = 0;
 };
 
 class DLL_LINKAGE IVisualLogBuilder
@@ -34,7 +34,7 @@ class DLL_LINKAGE IVisualLogBuilder
 public:
 	virtual void addLine(int3 start, int3 end) = 0;
 	virtual void addText(int3 tile, const std::string & text, const std::optional<ColorRGBA> & color = {}) = 0;
-	virtual void addText(BattleHex tile, const std::string & text) = 0;
+	virtual void addText(const BattleHex & tile, const std::string & text) = 0;
 
 	void addText(int3 tile, const std::string & text, PlayerColor background);
 };
@@ -89,7 +89,7 @@ private:
 			mapLines.emplace_back(start, end);
 		}
 
-		void addText(BattleHex tile, const std::string & text) override
+		void addText(const BattleHex & tile, const std::string & text) override
 		{
 			battleTexts.emplace_back(tile, text, std::optional<ColorRGBA>());
 		}

+ 3 - 3
lib/spells/BattleSpellMechanics.cpp

@@ -508,7 +508,7 @@ bool BattleSpellMechanics::counteringSelector(const Bonus * bonus) const
 	return false;
 }
 
-BattleHexArray BattleSpellMechanics::spellRangeInHexes(BattleHex centralHex) const
+BattleHexArray BattleSpellMechanics::spellRangeInHexes(const BattleHex & centralHex) const
 {
 	using namespace SRSLPraserHelpers;
 
@@ -612,7 +612,7 @@ std::vector<Destination> BattleSpellMechanics::getPossibleDestinations(size_t in
 				hexesToCheck.insert(stack->getPosition().getNeighbouringTiles());
 			}
 
-			for(auto hex : hexesToCheck)
+			for(const auto & hex : hexesToCheck)
 			{
 				if(hex.isAvailable())
 				{
@@ -659,7 +659,7 @@ bool BattleSpellMechanics::isReceptive(const battle::Unit * target) const
 	return targetCondition->isReceptive(this, target);
 }
 
-BattleHexArray BattleSpellMechanics::rangeInHexes(BattleHex centralHex) const
+BattleHexArray BattleSpellMechanics::rangeInHexes(const BattleHex & centralHex) const
 {
 	if(isMassive() || !centralHex.isValid())
 		return BattleHexArray();

+ 2 - 2
lib/spells/BattleSpellMechanics.h

@@ -61,7 +61,7 @@ public:
 	bool isReceptive(const battle::Unit * target) const override;
 
 	/// Returns list of hexes that are affected by spell assuming cast at centralHex
-	BattleHexArray rangeInHexes(BattleHex centralHex) const override;
+	BattleHexArray rangeInHexes(const BattleHex & centralHex) const override;
 
 	const Spell * getSpell() const override;
 
@@ -80,7 +80,7 @@ private:
 
 	void doRemoveEffects(ServerCallback * server, const battle::Units & targets, const CSelector & selector);
 
-	BattleHexArray spellRangeInHexes(BattleHex centralHex) const;
+	BattleHexArray spellRangeInHexes(const BattleHex & centralHex) const;
 
 	Target transformSpellTarget(const Target & aimPoint) const;
 };

+ 1 - 1
lib/spells/CSpellHandler.cpp

@@ -758,7 +758,7 @@ std::vector<int> CSpellHandler::spellRangeInHexes(std::string input) const
 	result.reserve(ret.size());
 
 	std::transform(ret.begin(), ret.end(), std::back_inserter(result),
-		[](BattleHex hex) { return hex.toInt(); }
+		[](const BattleHex & hex) { return hex.toInt(); }
 	);
 
 	return result;

+ 1 - 1
lib/spells/ISpellMechanics.h

@@ -185,7 +185,7 @@ public:
 	virtual bool adaptProblem(ESpellCastProblem source, Problem & target) const = 0;
 	virtual bool adaptGenericProblem(Problem & target) const = 0;
 
-	virtual BattleHexArray rangeInHexes(BattleHex centralHex) const = 0;
+	virtual BattleHexArray rangeInHexes(const BattleHex & centralHex) const = 0;
 	virtual std::vector<const CStack *> getAffectedStacks(const Target & target) const = 0;
 
 	virtual bool canBeCast(Problem & problem) const = 0;

+ 1 - 1
lib/spells/effects/DemonSummon.cpp

@@ -107,7 +107,7 @@ bool DemonSummon::isValidTarget(const Mechanics * m, const battle::Unit * unit)
 		return false;
 
 	//check if alive unit blocks rising
-	for(const BattleHex & hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
+	for(const BattleHex & hex : unit->getHexes())
 	{
 		auto blocking = m->battle()->battleGetUnitsIf([hex, unit](const battle::Unit * other)
 		{

+ 1 - 1
lib/spells/effects/Heal.cpp

@@ -70,7 +70,7 @@ bool Heal::isValidTarget(const Mechanics * m, const battle::Unit * unit) const
 	if(unit->isDead())
 	{
 		//check if alive unit blocks resurrection
-		for(const BattleHex & hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
+		for(const BattleHex & hex : unit->getHexes())
 		{
 			auto blocking = m->battle()->battleGetUnitsIf([hex, unit](const battle::Unit * other)
 			{

+ 2 - 2
lib/spells/effects/UnitEffect.cpp

@@ -202,7 +202,7 @@ EffectTarget UnitEffect::transformTargetByChain(const Mechanics * m, const Targe
 
 	for(const auto *unit : possibleTargets)
 	{
-		for(auto hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
+		for(const auto & hex : unit->getHexes())
 			possibleHexes.insert(hex);
 	}
 
@@ -222,7 +222,7 @@ EffectTarget UnitEffect::transformTargetByChain(const Mechanics * m, const Targe
 		else
 			effectTarget.emplace_back();
 
-		for(auto hex : battle::Unit::getHexes(unit->getPosition(), unit->doubleWide(), unit->unitSide()))
+		for(const auto & hex : unit->getHexes())
 			if (possibleHexes.contains(hex))
 				possibleHexes.erase(hex);
 

+ 4 - 4
server/battles/BattleActionProcessor.cpp

@@ -679,7 +679,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 		return obst->obstacleType == CObstacleInstance::MOAT;
 	});
 
-	auto isGateDrawbridgeHex = [&](BattleHex hex) -> bool
+	auto isGateDrawbridgeHex = [&](const BattleHex & hex) -> bool
 	{
 		if (hasWideMoat && hex == BattleHex::GATE_BRIDGE)
 			return true;
@@ -691,7 +691,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 		return false;
 	};
 
-	auto occupyGateDrawbridgeHex = [&](BattleHex hex) -> bool
+	auto occupyGateDrawbridgeHex = [&](const BattleHex & hex) -> bool
 	{
 		if (isGateDrawbridgeHex(hex))
 			return true;
@@ -744,7 +744,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 		{
 			for (int i = (int)path.first.size()-1; i >= 0; i--)
 			{
-				auto needOpenGates = [&](BattleHex hex) -> bool
+				auto needOpenGates = [&](const BattleHex & hex) -> bool
 				{
 					if (hasWideMoat && hex == BattleHex::GATE_BRIDGE)
 						return true;
@@ -911,7 +911,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 	return ret;
 }
 
-void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter)
+void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, const BattleHex & targetHex, bool first, bool ranged, bool counter)
 {
 	if(defender && first && !counter)
 		handleAttackBeforeCasting(battle, ranged, attacker, defender);

+ 1 - 1
server/battles/BattleActionProcessor.h

@@ -42,7 +42,7 @@ class BattleActionProcessor : boost::noncopyable
 	CGameHandler * gameHandler;
 
 	int moveStack(const CBattleInfoCallback & battle, int stack, BattleHex dest); //returned value - travelled distance
-	void makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, BattleHex targetHex, bool first, bool ranged, bool counter);
+	void makeAttack(const CBattleInfoCallback & battle, const CStack * attacker, const CStack * defender, int distance, const BattleHex & targetHex, bool first, bool ranged, bool counter);
 
 	void handleAttackBeforeCasting(const CBattleInfoCallback & battle, bool ranged, const CStack * attacker, const CStack * defender);
 

+ 1 - 1
server/battles/BattleFlowProcessor.cpp

@@ -163,7 +163,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
 	else
 		summonGuardiansHelper(battle, targetHexes, stack->getPosition(), stack->unitSide(), targetIsBig);
 
-	for(auto hex : targetHexes)
+	for(const auto & hex : targetHexes)
 	{
 		if(accessibility.accessible(hex, guardianIsBig, stack->unitSide())) //without this multiple creatures can occupy one hex
 		{

+ 1 - 1
test/mock/mock_battle_IBattleState.h

@@ -45,7 +45,7 @@ public:
 	MOCK_METHOD1(nextTurn, void(uint32_t));
 	MOCK_METHOD2(addUnit, void(uint32_t, const JsonNode &));
 	MOCK_METHOD3(setUnitState, void(uint32_t, const JsonNode &, int64_t));
-	MOCK_METHOD2(moveUnit, void(uint32_t, BattleHex));
+	MOCK_METHOD2(moveUnit, void(uint32_t, const BattleHex &));
 	MOCK_METHOD1(removeUnit, void(uint32_t));
 	MOCK_METHOD2(updateUnit, void(uint32_t, const JsonNode &));
 	MOCK_METHOD2(addUnitBonus, void(uint32_t, const std::vector<Bonus> &));

+ 1 - 1
test/mock/mock_battle_Unit.h

@@ -76,7 +76,7 @@ public:
 	MOCK_CONST_METHOD1(getTotalAttacks, int(bool));
 
 	MOCK_CONST_METHOD0(getPosition, BattleHex());
-	MOCK_METHOD1(setPosition, void(BattleHex));
+	MOCK_METHOD1(setPosition, void(const BattleHex&));
 	MOCK_CONST_METHOD1(getInitiative, int32_t(int));
 
 	MOCK_CONST_METHOD1(canMove, bool(int));

+ 1 - 1
test/mock/mock_spells_Mechanics.h

@@ -23,7 +23,7 @@ public:
 	MOCK_CONST_METHOD2(adaptProblem, bool(ESpellCastProblem, Problem &));
 	MOCK_CONST_METHOD1(adaptGenericProblem, bool(Problem &));
 
-	MOCK_CONST_METHOD1(rangeInHexes, BattleHexArray(BattleHex));
+	MOCK_CONST_METHOD1(rangeInHexes, BattleHexArray(const BattleHex&));
 	MOCK_CONST_METHOD1(getAffectedStacks, std::vector<const CStack *>(const Target &));
 
 	MOCK_CONST_METHOD1(canBeCast, bool(Problem &));