Browse Source

Merge pull request #5266 from MichalZr6/battlefield

Minor fixes to BattleHexArray. BattleHex'es as const reference where possible.
Ivan Savenko 10 tháng trước cách đây
mục cha
commit
f858a6e04b
63 tập tin đã thay đổi với 347 bổ sung359 xóa
  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 &));