Selaa lähdekoodia

Merge remote-tracking branch 'upstream/develop' into boats

# Conflicts:
#	AI/VCAI/Pathfinding/AINodeStorage.cpp
nordsoft 2 vuotta sitten
vanhempi
sitoutus
0a28262c15
100 muutettua tiedostoa jossa 1467 lisäystä ja 904 poistoa
  1. 6 6
      AI/BattleAI/BattleAI.cpp
  2. 1 1
      AI/BattleAI/BattleAI.h
  3. 2 3
      AI/Nullkiller/AIGateway.cpp
  4. 1 1
      AI/Nullkiller/AIGateway.h
  5. 7 7
      AI/Nullkiller/Goals/Build.cpp
  6. 1 1
      AI/Nullkiller/Goals/GatherArmy.cpp
  7. 13 13
      AI/Nullkiller/Pathfinding/AINodeStorage.cpp
  8. 1 1
      AI/Nullkiller/Pathfinding/AINodeStorage.h
  9. 1 1
      AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp
  10. 4 4
      AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp
  11. 3 3
      AI/VCAI/AIhelper.cpp
  12. 3 3
      AI/VCAI/AIhelper.h
  13. 9 9
      AI/VCAI/BuildingManager.cpp
  14. 6 6
      AI/VCAI/BuildingManager.h
  15. 3 3
      AI/VCAI/FuzzyEngines.cpp
  16. 7 7
      AI/VCAI/Goals/Build.cpp
  17. 1 1
      AI/VCAI/Goals/GatherArmy.cpp
  18. 12 1
      AI/VCAI/Goals/GatherTroops.cpp
  19. 5 5
      AI/VCAI/MapObjectsEvaluator.cpp
  20. 2 2
      AI/VCAI/MapObjectsEvaluator.h
  21. 7 9
      AI/VCAI/Pathfinding/AINodeStorage.cpp
  22. 1 1
      AI/VCAI/Pathfinding/AINodeStorage.h
  23. 3 3
      AI/VCAI/Pathfinding/PathfindingManager.cpp
  24. 1 1
      AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp
  25. 1 1
      AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp
  26. 4 9
      AI/VCAI/VCAI.cpp
  27. 1 1
      AI/VCAI/VCAI.h
  28. 6 7
      CCallback.cpp
  29. 4 4
      CCallback.h
  30. 6 31
      Global.h
  31. BIN
      android/vcmi-app/src/main/res/mipmap-hdpi/ic_launcher.png
  32. BIN
      android/vcmi-app/src/main/res/mipmap-mdpi/ic_launcher.png
  33. BIN
      android/vcmi-app/src/main/res/mipmap-xhdpi/ic_launcher.png
  34. BIN
      android/vcmi-app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  35. BIN
      android/vcmi-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  36. 11 5
      client/CMakeLists.txt
  37. 11 11
      client/CPlayerInterface.cpp
  38. 2 2
      client/Client.cpp
  39. 1 1
      client/Client.h
  40. 406 306
      client/ClientCommandManager.cpp
  41. 76 6
      client/ClientCommandManager.h
  42. 1 1
      client/NetPacksClient.cpp
  43. 2 2
      client/adventureMap/CAdvMapInt.cpp
  44. 1 1
      client/adventureMap/CAdvMapInt.h
  45. 1 1
      client/adventureMap/MapAudioPlayer.cpp
  46. 1 1
      client/battle/BattleInterface.cpp
  47. 6 6
      client/battle/BattleInterfaceClasses.cpp
  48. 3 3
      client/battle/BattleInterfaceClasses.h
  49. 3 3
      client/battle/BattleObstacleController.cpp
  50. 6 6
      client/battle/BattleStacksController.cpp
  51. 1 1
      client/battle/BattleWindow.cpp
  52. 1 1
      client/battle/BattleWindow.h
  53. BIN
      client/icons/vcmiclient.1024x1024.png
  54. BIN
      client/icons/vcmiclient.128x128.png
  55. BIN
      client/icons/vcmiclient.16x16.png
  56. BIN
      client/icons/vcmiclient.2048x2048.png
  57. BIN
      client/icons/vcmiclient.256x256.png
  58. BIN
      client/icons/vcmiclient.32x32.png
  59. BIN
      client/icons/vcmiclient.48x48.png
  60. BIN
      client/icons/vcmiclient.512x512.png
  61. BIN
      client/icons/vcmiclient.64x64.png
  62. BIN
      client/icons/vcmiclient.psd
  63. 401 0
      client/icons/vcmiclient.svg
  64. 234 222
      client/icons/vcmiclient.xpm
  65. BIN
      client/ios/vcmi_logo.png
  66. BIN
      client/vcmi.ico
  67. 6 6
      client/widgets/Buttons.cpp
  68. 7 7
      client/widgets/Buttons.h
  69. 1 1
      client/widgets/Images.cpp
  70. 1 1
      client/widgets/Images.h
  71. 11 11
      client/windows/CCreatureWindow.cpp
  72. 1 1
      client/windows/CCreatureWindow.h
  73. 19 23
      lib/CArtHandler.cpp
  74. 0 2
      lib/CArtHandler.h
  75. 1 1
      lib/CCreatureHandler.cpp
  76. 2 2
      lib/CCreatureSet.cpp
  77. 2 2
      lib/CCreatureSet.h
  78. 9 9
      lib/CGameInfoCallback.cpp
  79. 6 6
      lib/CGameInfoCallback.h
  80. 2 2
      lib/CGameInterface.h
  81. 6 6
      lib/CGameState.cpp
  82. 2 3
      lib/CGameState.h
  83. 8 8
      lib/CModHandler.cpp
  84. 4 4
      lib/CModHandler.h
  85. 7 3
      lib/CPathfinder.cpp
  86. 1 1
      lib/CPlayerState.h
  87. 1 1
      lib/CSkillHandler.cpp
  88. 2 2
      lib/CTownHandler.cpp
  89. 7 7
      lib/GameConstants.cpp
  90. 1 1
      lib/HeroBonus.cpp
  91. 1 1
      lib/HeroBonus.h
  92. 2 2
      lib/IGameCallback.cpp
  93. 2 2
      lib/IGameCallback.h
  94. 36 36
      lib/LogicalExpression.h
  95. 6 6
      lib/NetPacks.h
  96. 3 3
      lib/NetPacksBase.h
  97. 11 11
      lib/NetPacksLib.cpp
  98. 1 1
      lib/battle/BattleHex.h
  99. 7 7
      lib/battle/CBattleInfoCallback.cpp
  100. 1 1
      lib/battle/CBattleInfoCallback.h

+ 6 - 6
AI/BattleAI/BattleAI.cpp

@@ -134,7 +134,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
 
 
 		//evaluate casting spell for spellcasting stack
-		boost::optional<PossibleSpellcast> bestSpellcast(boost::none);
+		std::optional<PossibleSpellcast> bestSpellcast(std::nullopt);
 		//TODO: faerie dragon type spell should be selected by server
 		SpellID creatureSpellToCast = cb->battleGetRandomStackSpell(CRandomGenerator::getDefault(), stack, CBattleInfoCallback::RANDOM_AIMED);
 		if(stack->hasBonusOfType(Bonus::SPELLCASTER) && stack->canCast() && creatureSpellToCast != SpellID::NONE)
@@ -157,7 +157,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
 				std::sort(possibleCasts.begin(), possibleCasts.end(), [&](const PossibleSpellcast & lhs, const PossibleSpellcast & rhs) { return lhs.value > rhs.value; });
 				if(!possibleCasts.empty() && possibleCasts.front().value > 0)
 				{
-					bestSpellcast = boost::optional<PossibleSpellcast>(possibleCasts.front());
+					bestSpellcast = std::optional<PossibleSpellcast>(possibleCasts.front());
 				}
 			}
 		}
@@ -180,7 +180,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
 			auto & bestAttack = evaluationResult.bestAttack;
 
 			//TODO: consider more complex spellcast evaluation, f.e. because "re-retaliation" during enemy move in same turn for melee attack etc.
-			if(bestSpellcast.is_initialized() && bestSpellcast->value > bestAttack.damageDiff())
+			if(bestSpellcast.has_value() && bestSpellcast->value > bestAttack.damageDiff())
 			{
 				// return because spellcast value is damage dealt and score is dps reduce
 				movesSkippedByDefense = 0;
@@ -219,7 +219,7 @@ BattleAction CBattleAI::activeStack( const CStack * stack )
 				);
 			}
 		}
-		else if(bestSpellcast.is_initialized())
+		else if(bestSpellcast.has_value())
 		{
 			movesSkippedByDefense = 0;
 			return BattleAction::makeCreatureSpellcast(stack, bestSpellcast->dest, bestSpellcast->spell->id);
@@ -801,7 +801,7 @@ void CBattleAI::print(const std::string &text) const
 	logAi->trace("%s Battle AI[%p]: %s", playerID.getStr(), this, text);
 }
 
-boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
+std::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
 {
 	BattleStateInfoForRetreat bs;
 
@@ -829,7 +829,7 @@ boost::optional<BattleAction> CBattleAI::considerFleeingOrSurrendering()
 
 	if(!bs.canFlee || !bs.canSurrender)
 	{
-		return boost::none;
+		return std::nullopt;
 	}
 
 	auto result = cb->makeSurrenderRetreatDecision(bs);

+ 1 - 1
AI/BattleAI/BattleAI.h

@@ -73,7 +73,7 @@ public:
 
 	BattleAction activeStack(const CStack * stack) override; //called when it's turn of that stack
 
-	boost::optional<BattleAction> considerFleeingOrSurrendering();
+	std::optional<BattleAction> considerFleeingOrSurrendering();
 
 	void print(const std::string &text) const;
 	BattleAction useCatapult(const CStack *stack);

+ 2 - 3
AI/Nullkiller/AIGateway.cpp

@@ -501,8 +501,7 @@ void AIGateway::showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositio
 	NET_EVENT_HANDLER;
 }
 
-boost::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(
-	const BattleStateInfoForRetreat & battleState)
+std::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
 {
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
@@ -516,7 +515,7 @@ boost::optional<BattleAction> AIGateway::makeSurrenderRetreatDecision(
 		return BattleAction::makeRetreat(battleState.ourSide);
 	}
 
-	return boost::none;
+	return std::nullopt;
 }
 
 

+ 1 - 1
AI/Nullkiller/AIGateway.h

@@ -166,7 +166,7 @@ public:
 	void heroBonusChanged(const CGHeroInstance * hero, const Bonus & bonus, bool gain) override;
 	void showMarketWindow(const IMarket * market, const CGHeroInstance * visitor) override;
 	void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain) override;
-	boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
+	std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
 
 	void battleStart(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool side) override;
 	void battleEnd(const BattleResult * br, QueryID queryID) override;

+ 7 - 7
AI/Nullkiller/Goals/Build.cpp

@@ -42,10 +42,10 @@ TGoalVec Build::getAllPossibleSubgoals()
 		auto expensiveBuilding = ai->ah->expensiveBuilding();
 
 		//handling for early town development to save money and focus on income
-		if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.is_initialized())
+		if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.has_value())
 		{
-			auto potentialBuilding = expensiveBuilding.get();
-			switch(expensiveBuilding.get().bid)
+			auto potentialBuilding = expensiveBuilding.value();
+			switch(expensiveBuilding.value().bid)
 			{
 			case BuildingID::TOWN_HALL:
 			case BuildingID::CITY_HALL:
@@ -61,15 +61,15 @@ TGoalVec Build::getAllPossibleSubgoals()
 			}
 		}
 
-		if(immediateBuilding.is_initialized())
+		if(immediateBuilding.has_value())
 		{
-			ret.push_back(sptr(BuildThis(immediateBuilding.get().bid, t).setpriority(2))); //prioritize buildings we can build quick
+			ret.push_back(sptr(BuildThis(immediateBuilding.value().bid, t).setpriority(2))); //prioritize buildings we can build quick
 		}
 		else //try build later
 		{
-			if(expensiveBuilding.is_initialized())
+			if(expensiveBuilding.has_value())
 			{
-				auto potentialBuilding = expensiveBuilding.get(); //gather resources for any we can't afford
+				auto potentialBuilding = expensiveBuilding.value(); //gather resources for any we can't afford
 				auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(BuildThis(potentialBuilding.bid, t).setpriority(0.5)));
 				ret.push_back(goal);
 			}

+ 1 - 1
AI/Nullkiller/Goals/GatherArmy.cpp

@@ -97,7 +97,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 
 			//Do not use below code for now, rely on generic Build. Code below needs to know a lot of town/resource context to do more good than harm
 			/*auto bid = ai->ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + ARRAY_COUNT(unitsSource)), 1);
-			if (bid.is_initialized())
+			if (bid.has_value())
 			{
 				auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
 				if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice

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

@@ -120,7 +120,7 @@ void AINodeStorage::clear()
 	turnDistanceLimit[HeroRole::SCOUT] = 255;
 }
 
-boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
+std::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
 	const int3 & pos, 
 	const EPathfindingLayer layer, 
 	const ChainActor * actor)
@@ -131,7 +131,7 @@ boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
 
 	if(chains[0].blocked())
 	{
-		return boost::none;
+		return std::nullopt;
 	}
 
 	for(auto i = AIPathfinding::BUCKET_SIZE - 1; i >= 0; i--)
@@ -151,7 +151,7 @@ boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(
 		}
 	}
 
-	return boost::none;
+	return std::nullopt;
 }
 
 std::vector<CGPathNode *> AINodeStorage::getInitialNodes()
@@ -175,7 +175,7 @@ std::vector<CGPathNode *> AINodeStorage::getInitialNodes()
 		if(!allocated)
 			continue;
 
-		AIPathNode * initialNode = allocated.get();
+		AIPathNode * initialNode = allocated.value();
 
 		initialNode->inPQ = false;
 		initialNode->pq = nullptr;
@@ -289,10 +289,10 @@ std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
 		{
 			auto nextNode = getOrCreateNode(neighbour, i, srcNode->actor);
 
-			if(!nextNode || nextNode.get()->accessible == CGPathNode::NOT_SET)
+			if(!nextNode || nextNode.value()->accessible == CGPathNode::NOT_SET)
 				continue;
 
-			neighbours.push_back(nextNode.get());
+			neighbours.push_back(nextNode.value());
 		}
 	}
 	
@@ -722,7 +722,7 @@ void HeroChainCalculationTask::addHeroChain(const std::vector<ExchangeCandidate>
 			continue;
 		}
 
-		auto exchangeNode = chainNodeOptional.get();
+		auto exchangeNode = chainNodeOptional.value();
 
 		if(exchangeNode->action != CGPathNode::ENodeAction::UNKNOWN)
 		{
@@ -946,7 +946,7 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
 			if(!node)
 				continue;
 
-			neighbours.push_back(node.get());
+			neighbours.push_back(node.value());
 		}
 	}
 
@@ -1017,19 +1017,19 @@ struct TowmPortalFinder
 		return nullptr;
 	}
 
-	boost::optional<AIPathNode *> createTownPortalNode(const CGTownInstance * targetTown)
+	std::optional<AIPathNode *> createTownPortalNode(const CGTownInstance * targetTown)
 	{
 		auto bestNode = getBestInitialNodeForTownPortal(targetTown);
 
 		if(!bestNode)
-			return boost::none;
+			return std::nullopt;
 
 		auto nodeOptional = nodeStorage->getOrCreateNode(targetTown->visitablePos(), EPathfindingLayer::LAND, actor->castActor);
 
 		if(!nodeOptional)
-			return boost::none;
+			return std::nullopt;
 
-		AIPathNode * node = nodeOptional.get();
+		AIPathNode * node = nodeOptional.value();
 		float movementCost = (float)movementNeeded / (float)hero->maxMovePoints(EPathfindingLayer::LAND);
 
 		movementCost += bestNode->getCost();
@@ -1095,7 +1095,7 @@ void AINodeStorage::calculateTownPortal(
 #if NKAI_PATHFINDER_TRACE_LEVEL >= 1
 				logAi->trace("Adding town portal node at %s", targetTown->name);
 #endif
-				output.push_back(nodeOptional.get());
+				output.push_back(nodeOptional.value());
 			}
 		}
 	}

+ 1 - 1
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -232,7 +232,7 @@ public:
 		const AIPathNode * destinationNode,
 		const NodeRange & chains) const;
 
-	boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, const ChainActor * actor);
+	std::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, const ChainActor * actor);
 	std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const;
 	bool isTileAccessible(const HeroPtr & hero, const int3 & pos, const EPathfindingLayer layer) const;
 	void setHeroes(std::map<const CGHeroInstance *, HeroRole> heroes);

+ 1 - 1
AI/Nullkiller/Pathfinding/Rules/AILayerTransitionRule.cpp

@@ -131,7 +131,7 @@ namespace AIPathfinding
 
 			if(boatNodeOptional)
 			{
-				AIPathNode * boatNode = boatNodeOptional.get();
+				AIPathNode * boatNode = boatNodeOptional.value();
 
 				if(boatNode->action == CGPathNode::UNKNOWN)
 				{

+ 4 - 4
AI/Nullkiller/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -139,17 +139,17 @@ namespace AIPathfinding
 		{
 			if(!destinationNode->actor->allowUseResources)
 			{
-				boost::optional<AIPathNode *> questNode = nodeStorage->getOrCreateNode(
+				std::optional<AIPathNode *> questNode = nodeStorage->getOrCreateNode(
 					destination.coord,
 					destination.node->layer,
 					destinationNode->actor->resourceActor);
 
-				if(!questNode || questNode.get()->getCost() < destination.cost)
+				if(!questNode || questNode.value()->getCost() < destination.cost)
 				{
 					return false;
 				}
 
-				destination.node = questNode.get();
+				destination.node = questNode.value();
 
 				nodeStorage->commit(destination, source);
 				AIPreviousNodeRule(nodeStorage).process(source, destination, pathfinderConfig, pathfinderHelper);
@@ -259,7 +259,7 @@ namespace AIPathfinding
 			return false;
 		}
 
-		AIPathNode * battleNode = battleNodeOptional.get();
+		auto * battleNode = battleNodeOptional.value();
 
 		if(battleNode->locked)
 		{

+ 3 - 3
AI/VCAI/AIhelper.cpp

@@ -50,17 +50,17 @@ BuildingID AIhelper::getMaxPossibleGoldBuilding(const CGTownInstance * t)
 	return buildingManager->getMaxPossibleGoldBuilding(t);
 }
 
-boost::optional<PotentialBuilding> AIhelper::immediateBuilding() const
+std::optional<PotentialBuilding> AIhelper::immediateBuilding() const
 {
 	return buildingManager->immediateBuilding();
 }
 
-boost::optional<PotentialBuilding> AIhelper::expensiveBuilding() const
+std::optional<PotentialBuilding> AIhelper::expensiveBuilding() const
 {
 	return buildingManager->expensiveBuilding();
 }
 
-boost::optional<BuildingID> AIhelper::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
+std::optional<BuildingID> AIhelper::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
 {
 	return buildingManager->canBuildAnyStructure(t, buildList, maxDays);
 }

+ 3 - 3
AI/VCAI/AIhelper.h

@@ -52,9 +52,9 @@ public:
 
 	bool getBuildingOptions(const CGTownInstance * t) override;
 	BuildingID getMaxPossibleGoldBuilding(const CGTownInstance * t);
-	boost::optional<PotentialBuilding> immediateBuilding() const override;
-	boost::optional<PotentialBuilding> expensiveBuilding() const override;
-	boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
+	std::optional<PotentialBuilding> immediateBuilding() const override;
+	std::optional<PotentialBuilding> expensiveBuilding() const override;
+	std::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
 
 	Goals::TGoalVec howToVisitTile(const HeroPtr & hero, const int3 & tile, bool allowGatherArmy = true) const override;
 	Goals::TGoalVec howToVisitObj(const HeroPtr & hero, ObjectIdRef obj, bool allowGatherArmy = true) const override;

+ 9 - 9
AI/VCAI/BuildingManager.cpp

@@ -99,7 +99,7 @@ bool BuildingManager::tryBuildAnyStructure(const CGTownInstance * t, std::vector
 	return false; //Can't build anything
 }
 
-boost::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
+std::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const
 {
 	for (const auto & building : buildList)
 	{
@@ -109,11 +109,11 @@ boost::optional<BuildingID> BuildingManager::canBuildAnyStructure(const CGTownIn
 		{
 			case EBuildingState::ALLOWED:
 			case EBuildingState::NO_RESOURCES: //TODO: allow this via optional parameter?
-				return boost::optional<BuildingID>(building);
+				return std::optional<BuildingID>(building);
 				break;
 		}
 	}
-	return boost::optional<BuildingID>(); //Can't build anything
+	return std::optional<BuildingID>(); //Can't build anything
 }
 
 bool BuildingManager::tryBuildNextStructure(const CGTownInstance * t, std::vector<BuildingID> buildList, unsigned int maxDays)
@@ -240,18 +240,18 @@ BuildingID BuildingManager::getMaxPossibleGoldBuilding(const CGTownInstance * t)
 		return BuildingID::VILLAGE_HALL;
 }
 
-boost::optional<PotentialBuilding> BuildingManager::immediateBuilding() const
+std::optional<PotentialBuilding> BuildingManager::immediateBuilding() const
 {
 	if (immediateBuildings.size())
-		return boost::optional<PotentialBuilding>(immediateBuildings.front()); //back? whatever
+		return std::optional<PotentialBuilding>(immediateBuildings.front()); //back? whatever
 	else
-		return boost::optional<PotentialBuilding>();
+		return std::optional<PotentialBuilding>();
 }
 
-boost::optional<PotentialBuilding> BuildingManager::expensiveBuilding() const
+std::optional<PotentialBuilding> BuildingManager::expensiveBuilding() const
 {
 	if (expensiveBuildings.size())
-		return boost::optional<PotentialBuilding>(expensiveBuildings.front());
+		return std::optional<PotentialBuilding>(expensiveBuildings.front());
 	else
-		return boost::optional<PotentialBuilding>();
+		return std::optional<PotentialBuilding>();
 }

+ 6 - 6
AI/VCAI/BuildingManager.h

@@ -33,9 +33,9 @@ public:
 	virtual void setAI(VCAI * AI) = 0;
 
 	virtual bool getBuildingOptions(const CGTownInstance * t) = 0;
-	virtual boost::optional<PotentialBuilding> immediateBuilding() const = 0;
-	virtual boost::optional<PotentialBuilding> expensiveBuilding() const = 0;
-	virtual boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const = 0;
+	virtual std::optional<PotentialBuilding> immediateBuilding() const = 0;
+	virtual std::optional<PotentialBuilding> expensiveBuilding() const = 0;
+	virtual std::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays) const = 0;
 };
 
 class DLL_EXPORT BuildingManager : public IBuildingManager
@@ -52,9 +52,9 @@ public:
 	//try build anything in given town, and execute resulting Goal if any
 	bool getBuildingOptions(const CGTownInstance * t) override;
 	BuildingID getMaxPossibleGoldBuilding(const CGTownInstance * t);
-	boost::optional<PotentialBuilding> immediateBuilding() const override;
-	boost::optional<PotentialBuilding> expensiveBuilding() const override;
-	boost::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
+	std::optional<PotentialBuilding> immediateBuilding() const override;
+	std::optional<PotentialBuilding> expensiveBuilding() const override;
+	std::optional<BuildingID> canBuildAnyStructure(const CGTownInstance * t, const std::vector<BuildingID> & buildList, unsigned int maxDays = 7) const override;
 
 protected:
 

+ 3 - 3
AI/VCAI/FuzzyEngines.cpp

@@ -399,12 +399,12 @@ float VisitObjEngine::evaluate(Goals::VisitObj & goal)
 		return -100; // FIXME: Added check when goal was used for hero instead of VisitHero, but crashes are bad anyway
 	}
 
-	boost::optional<int> objValueKnownByAI = MapObjectsEvaluator::getInstance().getObjectValue(obj);
+	std::optional<int> objValueKnownByAI = MapObjectsEvaluator::getInstance().getObjectValue(obj);
 	int objValue = 0;
 
-	if(objValueKnownByAI != boost::none) //consider adding value manipulation based on object instances on map
+	if(objValueKnownByAI != std::nullopt) //consider adding value manipulation based on object instances on map
 	{
-		objValue = std::min(std::max(objValueKnownByAI.get(), 0), 20000);
+		objValue = std::min(std::max(objValueKnownByAI.value(), 0), 20000);
 	}
 	else
 	{

+ 7 - 7
AI/VCAI/Goals/Build.cpp

@@ -39,10 +39,10 @@ TGoalVec Build::getAllPossibleSubgoals()
 		auto expensiveBuilding = ai->ah->expensiveBuilding();
 
 		//handling for early town development to save money and focus on income
-		if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.is_initialized())
+		if(!t->hasBuilt(ai->ah->getMaxPossibleGoldBuilding(t)) && expensiveBuilding.has_value())
 		{
-			auto potentialBuilding = expensiveBuilding.get();
-			switch(expensiveBuilding.get().bid)
+			auto potentialBuilding = expensiveBuilding.value();
+			switch(expensiveBuilding.value().bid)
 			{
 			case BuildingID::TOWN_HALL:
 			case BuildingID::CITY_HALL:
@@ -58,15 +58,15 @@ TGoalVec Build::getAllPossibleSubgoals()
 			}
 		}
 
-		if(immediateBuilding.is_initialized())
+		if(immediateBuilding.has_value())
 		{
-			ret.push_back(sptr(BuildThis(immediateBuilding.get().bid, t).setpriority(2))); //prioritize buildings we can build quick
+			ret.push_back(sptr(BuildThis(immediateBuilding.value().bid, t).setpriority(2))); //prioritize buildings we can build quick
 		}
 		else //try build later
 		{
-			if(expensiveBuilding.is_initialized())
+			if(expensiveBuilding.has_value())
 			{
-				auto potentialBuilding = expensiveBuilding.get(); //gather resources for any we can't afford
+				auto potentialBuilding = expensiveBuilding.value(); //gather resources for any we can't afford
 				auto goal = ai->ah->whatToDo(potentialBuilding.price, sptr(BuildThis(potentialBuilding.bid, t).setpriority(0.5)));
 				ret.push_back(goal);
 			}

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

@@ -94,7 +94,7 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 
 			//Do not use below code for now, rely on generic Build. Code below needs to know a lot of town/resource context to do more good than harm
 			/*auto bid = ai->ah->canBuildAnyStructure(t, std::vector<BuildingID>(unitsSource, unitsSource + std::size(unitsSource)), 1);
-			if (bid.is_initialized())
+			if (bid.has_value())
 			{
 				auto goal = sptr(BuildThis(bid.get(), t).setpriority(priority));
 				if (!ai->ah->containsObjective(goal)) //avoid loops caused by reserving same objective twice

+ 12 - 1
AI/VCAI/Goals/GatherTroops.cpp

@@ -96,7 +96,18 @@ TGoalVec GatherTroops::getAllPossibleSubgoals()
 		auto creature = VLC->creatures()->getByIndex(objid);
 		if(t->subID == creature->getFaction()) //TODO: how to force AI to build unupgraded creatures? :O
 		{
-			auto creatures = vstd::tryAt(t->town->creatures, creature->getLevel() - 1);
+			auto tryFindCreature = [&]() -> std::optional<std::vector<CreatureID>>
+			{
+				if(vstd::isValidIndex(t->town->creatures, creature->getLevel() - 1))
+				{
+					auto itr = t->town->creatures.begin();
+					std::advance(itr, creature->getLevel() - 1);
+					return make_optional(*itr);
+				}
+				return std::nullopt;
+			};
+
+			auto creatures = tryFindCreature();
 			if(!creatures)
 				continue;
 

+ 5 - 5
AI/VCAI/MapObjectsEvaluator.cpp

@@ -28,9 +28,9 @@ MapObjectsEvaluator::MapObjectsEvaluator()
 			auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);
 			if(handler && !handler->isStaticObject())
 			{
-				if(handler->getAiValue() != boost::none)
+				if(handler->getAiValue() != std::nullopt)
 				{
-					objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = handler->getAiValue().get();
+					objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = handler->getAiValue().value();
 				}
 				else //some default handling when aiValue not found, objects that require advanced properties (unavailable from handler) get their value calculated in getObjectValue
 				{
@@ -41,7 +41,7 @@ MapObjectsEvaluator::MapObjectsEvaluator()
 	}
 }
 
-boost::optional<int> MapObjectsEvaluator::getObjectValue(int primaryID, int secondaryID) const
+std::optional<int> MapObjectsEvaluator::getObjectValue(int primaryID, int secondaryID) const
 {
 	CompoundMapObjectID internalIdentifier = CompoundMapObjectID(primaryID, secondaryID);
 	auto object = objectDatabase.find(internalIdentifier);
@@ -49,10 +49,10 @@ boost::optional<int> MapObjectsEvaluator::getObjectValue(int primaryID, int seco
 		return object->second;
 
 	logGlobal->trace("Unknown object for AI, ID: " + std::to_string(primaryID) + ", SubID: " + std::to_string(secondaryID));
-	return boost::optional<int>();
+	return std::optional<int>();
 }
 
-boost::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance * obj) const
+std::optional<int> MapObjectsEvaluator::getObjectValue(const CGObjectInstance * obj) const
 {
 	if(obj->ID == Obj::HERO)
 	{

+ 2 - 2
AI/VCAI/MapObjectsEvaluator.h

@@ -18,8 +18,8 @@ private:
 public:
 	MapObjectsEvaluator();
 	static MapObjectsEvaluator & getInstance();
-	boost::optional<int> getObjectValue(int primaryID, int secondaryID) const;
-	boost::optional<int> getObjectValue(const CGObjectInstance * obj) const;
+	std::optional<int> getObjectValue(int primaryID, int secondaryID) const;
+	std::optional<int> getObjectValue(const CGObjectInstance * obj) const;
 	void addObjectData(int primaryID, int secondaryID, int value);
 	void removeObjectData(int primaryID, int secondaryID);
 };

+ 7 - 9
AI/VCAI/Pathfinding/AINodeStorage.cpp

@@ -83,7 +83,7 @@ bool AINodeStorage::isBattleNode(const CGPathNode * node) const
 	return (getAINode(node)->chainMask & BATTLE_CHAIN) > 0;
 }
 
-boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, const EPathfindingLayer layer, int chainNumber)
+std::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, const EPathfindingLayer layer, int chainNumber)
 {
 	auto chains = nodes[layer][pos.z][pos.x][pos.y];
 
@@ -102,15 +102,13 @@ boost::optional<AIPathNode *> AINodeStorage::getOrCreateNode(const int3 & pos, c
 		}
 	}
 
-	return boost::none;
+	return std::nullopt;
 }
 
 std::vector<CGPathNode *> AINodeStorage::getInitialNodes()
 {
 	auto hpos = hero->visitablePos();
-	auto initialNode =
-		getOrCreateNode(hpos, hero->boat ? hero->boat->layer : EPathfindingLayer::LAND, NORMAL_CHAIN)
-		.get();
+	auto initialNode = getOrCreateNode(hpos, hero->boat ? EPathfindingLayer::SAIL : EPathfindingLayer::LAND, NORMAL_CHAIN).value();
 
 	initialNode->turns = 0;
 	initialNode->moveRemains = hero->movement;
@@ -171,10 +169,10 @@ std::vector<CGPathNode *> AINodeStorage::calculateNeighbours(
 		{
 			auto nextNode = getOrCreateNode(neighbour, i, srcNode->chainMask);
 
-			if(!nextNode || nextNode.get()->accessible == CGPathNode::NOT_SET)
+			if(!nextNode || nextNode.value()->accessible == CGPathNode::NOT_SET)
 				continue;
 
-			neighbours.push_back(nextNode.get());
+			neighbours.push_back(nextNode.value());
 		}
 	}
 
@@ -207,7 +205,7 @@ std::vector<CGPathNode *> AINodeStorage::calculateTeleportations(
 			if(!node)
 				continue;
 
-			neighbours.push_back(node.get());
+			neighbours.push_back(node.value());
 		}
 	}
 
@@ -273,7 +271,7 @@ void AINodeStorage::calculateTownPortalTeleportations(
 				logAi->trace("Adding town portal node at %s", targetTown->name);
 #endif
 
-				AIPathNode * node = nodeOptional.get();
+				AIPathNode * node = nodeOptional.value();
 
 				node->theNodeBefore = source.node;
 				node->specialAction.reset(new AIPathfinding::TownPortalAction(targetTown));

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

@@ -107,7 +107,7 @@ public:
 
 	bool isBattleNode(const CGPathNode * node) const;
 	bool hasBetterChain(const PathNodeInfo & source, CDestinationNodeInfo & destination) const;
-	boost::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
+	std::optional<AIPathNode *> getOrCreateNode(const int3 & coord, const EPathfindingLayer layer, int chainNumber);
 	std::vector<AIPath> getChainInfo(const int3 & pos, bool isOnLand) const;
 	bool isTileAccessible(const int3 & pos, const EPathfindingLayer layer) const;
 

+ 3 - 3
AI/VCAI/Pathfinding/PathfindingManager.cpp

@@ -114,7 +114,7 @@ Goals::TGoalVec PathfindingManager::findPath(
 	const std::function<Goals::TSubgoal(int3)> doVisitTile) const
 {
 	Goals::TGoalVec result;
-	boost::optional<uint64_t> armyValueRequired;
+	std::optional<uint64_t> armyValueRequired;
 	uint64_t danger;
 
 	std::vector<AIPath> chainInfo = pathfinder->getPathInfo(hero, dest);
@@ -165,12 +165,12 @@ Goals::TGoalVec PathfindingManager::findPath(
 
 			if(!armyValueRequired || armyValueRequired > danger)
 			{
-				armyValueRequired = boost::make_optional(danger);
+				armyValueRequired = std::make_optional(danger);
 			}
 		}
 	}
 
-	danger = armyValueRequired.get_value_or(0);
+	danger = armyValueRequired.value_or(0);
 
 	if(allowGatherArmy && danger > 0)
 	{

+ 1 - 1
AI/VCAI/Pathfinding/Rules/AILayerTransitionRule.cpp

@@ -120,7 +120,7 @@ namespace AIPathfinding
 
 			if(boatNodeOptional)
 			{
-				AIPathNode * boatNode = boatNodeOptional.get();
+				AIPathNode * boatNode = boatNodeOptional.value();
 
 				if(boatNode->action == CGPathNode::UNKNOWN)
 				{

+ 1 - 1
AI/VCAI/Pathfinding/Rules/AIMovementAfterDestinationRule.cpp

@@ -106,7 +106,7 @@ namespace AIPathfinding
 				return;
 			}
 
-			AIPathNode *  battleNode = battleNodeOptional.get();
+			auto * battleNode = battleNodeOptional.value();
 
 			if(battleNode->locked)
 			{

+ 4 - 9
AI/VCAI/VCAI.cpp

@@ -1241,14 +1241,14 @@ void VCAI::recruitCreatures(const CGDwelling * d, const CArmedInstance * recruit
 	}
 }
 
-bool VCAI::isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, boost::optional<float> movementCostLimit)
+bool VCAI::isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, std::optional<float> movementCostLimit)
 {
 	int3 op = obj->visitablePos();
 	auto paths = ah->getPathsToTile(h, op);
 
 	for(const auto & path : paths)
 	{
-		if(movementCostLimit && movementCostLimit.get() < path.movementCost())
+		if(movementCostLimit && movementCostLimit.value() < path.movementCost())
 			return false;
 
 		if(isGoodForVisit(obj, h, path))
@@ -1363,18 +1363,13 @@ void VCAI::wander(HeroPtr h)
 		});
 
 		int pass = 0;
-		std::vector<boost::optional<float>> distanceLimits =
-		{
-			1.0,
-			2.0,
-			boost::none
-		};
+		std::vector<std::optional<float>> distanceLimits = {1.0, 2.0, std::nullopt};
 
 		while(!dests.size() && pass < distanceLimits.size())
 		{
 			auto & distanceLimit = distanceLimits[pass];
 
-			logAi->debug("Looking for wander destination pass=%i, cost limit=%f", pass, distanceLimit.get_value_or(-1.0));
+			logAi->debug("Looking for wander destination pass=%i, cost limit=%f", pass, distanceLimit.value_or(-1.0));
 
 			vstd::copy_if(visitableObjs, std::back_inserter(dests), [&](ObjectIdRef obj) -> bool
 			{

+ 1 - 1
AI/VCAI/VCAI.h

@@ -217,7 +217,7 @@ public:
 	void completeGoal(Goals::TSubgoal goal); //safely removes goal from reserved hero
 
 	void recruitHero(const CGTownInstance * t, bool throwing = false);
-	bool isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, boost::optional<float> movementCostLimit = boost::none);
+	bool isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, std::optional<float> movementCostLimit = std::nullopt);
 	bool isGoodForVisit(const CGObjectInstance * obj, HeroPtr h, const AIPath & path) const;
 	//void recruitCreatures(const CGTownInstance * t);
 	void recruitCreatures(const CGDwelling * d, const CArmedInstance * recruiter);

+ 6 - 7
CCallback.cpp

@@ -90,7 +90,7 @@ bool CCallback::upgradeCreature(const CArmedInstance *obj, SlotID stackPos, Crea
 
 void CCallback::endTurn()
 {
-	logGlobal->trace("Player %d ended his turn.", player.get().getNum());
+	logGlobal->trace("Player %d ended his turn.", player->getNum());
 	EndTurn pack;
 	sendRequest(&pack);
 }
@@ -306,8 +306,8 @@ void CCallback::buildBoat( const IShipyard *obj )
 	sendRequest(&bb);
 }
 
-CCallback::CCallback(CGameState * GS, boost::optional<PlayerColor> Player, CClient * C)
-	: CBattleCallback(Player, C)
+CCallback::CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C):
+	CBattleCallback(Player, C)
 {
 	gs = GS;
 
@@ -380,7 +380,7 @@ scripting::Pool * CBattleCallback::getContextPool() const
 }
 #endif
 
-CBattleCallback::CBattleCallback(boost::optional<PlayerColor> Player, CClient *C )
+CBattleCallback::CBattleCallback(std::optional<PlayerColor> Player, CClient * C)
 {
 	player = Player;
 	cl = C;
@@ -395,8 +395,7 @@ bool CBattleCallback::battleMakeTacticAction( BattleAction * action )
 	return true;
 }
 
-boost::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(
-	const BattleStateInfoForRetreat & battleState)
+std::optional<BattleAction> CBattleCallback::makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
 {
-	return cl->playerint[getPlayerID().get()]->makeSurrenderRetreatDecision(battleState);
+	return cl->playerint[getPlayerID().value()]->makeSurrenderRetreatDecision(battleState);
 }

+ 4 - 4
CCallback.h

@@ -54,7 +54,7 @@ public:
 	//battle
 	virtual int battleMakeAction(const BattleAction * action) = 0;//for casting spells by hero - DO NOT use it for moving active stack
 	virtual bool battleMakeTacticAction(BattleAction * action) = 0; // performs tactic phase actions
-	virtual boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0;
+	virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) = 0;
 };
 
 class IGameActionCallback
@@ -113,10 +113,10 @@ protected:
 	CClient *cl;
 
 public:
-	CBattleCallback(boost::optional<PlayerColor> Player, CClient *C);
+	CBattleCallback(std::optional<PlayerColor> Player, CClient * C);
 	int battleMakeAction(const BattleAction * action) override;//for casting spells by hero - DO NOT use it for moving active stack
 	bool battleMakeTacticAction(BattleAction * action) override; // performs tactic phase actions
-	boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
+	std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState) override;
 
 #if SCRIPTING_ENABLED
 	scripting::Pool * getContextPool() const override;
@@ -131,7 +131,7 @@ class CCallback : public CPlayerSpecificInfoCallback,
 	public CBattleCallback
 {
 public:
-	CCallback(CGameState * GS, boost::optional<PlayerColor> Player, CClient *C);
+	CCallback(CGameState * GS, std::optional<PlayerColor> Player, CClient * C);
 	virtual ~CCallback();
 
 	//client-specific functionalities (pathfinding)

+ 6 - 31
Global.h

@@ -101,6 +101,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #define _USE_MATH_DEFINES
 
 #include <algorithm>
+#include <any>
 #include <array>
 #include <atomic>
 #include <bitset>
@@ -144,14 +145,13 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #endif
 
 #include <boost/algorithm/string.hpp>
-#include <boost/any.hpp>
-#include <boost/current_function.hpp>
 #include <boost/crc.hpp>
+#include <boost/current_function.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
 #include <boost/date_time/posix_time/posix_time_io.hpp>
 #include <boost/filesystem.hpp>
-#include <boost/filesystem/path.hpp>
 #include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/path.hpp>
 #include <boost/format.hpp>
 #include <boost/functional/hash.hpp>
 #include <boost/lexical_cast.hpp>
@@ -159,14 +159,11 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
 #include <boost/locale/generator.hpp>
 #endif
 #include <boost/logic/tribool.hpp>
-#include <boost/optional.hpp>
-#include <boost/optional/optional_io.hpp>
+#include <boost/multi_array.hpp>
 #include <boost/range/adaptor/filtered.hpp>
 #include <boost/range/adaptor/reversed.hpp>
 #include <boost/range/algorithm.hpp>
 #include <boost/thread.hpp>
-#include <boost/variant.hpp>
-#include <boost/multi_array.hpp>
 
 #ifndef M_PI
 #  define M_PI 3.14159265358979323846
@@ -576,28 +573,6 @@ namespace vstd
 		return i >= 0  &&  i < c.size();
 	}
 
-	template <typename Container, typename Index>
-	boost::optional<typename Container::const_reference> tryAt(const Container &c, Index i)
-	{
-		if(isValidIndex(c, i))
-		{
-			auto itr = c.begin();
-			std::advance(itr, i);
-			return *itr;
-		}
-		return boost::none;
-	}
-
-	template <typename Container, typename Pred>
-	static boost::optional<typename Container::const_reference> tryFindIf(const Container &r, const Pred &t)
-	{
-		auto pos = range::find_if(r, t);
-		if(pos == boost::end(r))
-			return boost::none;
-		else
-			return *pos;
-	}
-
 	template <typename Container>
 	typename Container::const_reference atOrDefault(const Container &r, size_t index, const typename Container::const_reference &defaultValue)
 	{
@@ -668,8 +643,8 @@ namespace vstd
 		return false;
 	}
 
-	template <class M, class Key, class F>
-	typename M::mapped_type & getOrCompute(M & m, Key const & k, F f)
+	template<class M, class Key, class F>
+	typename M::mapped_type & getOrCompute(M & m, const Key & k, F f)
 	{
 		typedef typename M::mapped_type V;
 

BIN
android/vcmi-app/src/main/res/mipmap-hdpi/ic_launcher.png


BIN
android/vcmi-app/src/main/res/mipmap-mdpi/ic_launcher.png


BIN
android/vcmi-app/src/main/res/mipmap-xhdpi/ic_launcher.png


BIN
android/vcmi-app/src/main/res/mipmap-xxhdpi/ic_launcher.png


BIN
android/vcmi-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png


+ 11 - 5
client/CMakeLists.txt

@@ -403,9 +403,15 @@ endif()
 #install icons and desktop file on Linux
 if(NOT WIN32 AND NOT APPLE AND NOT ANDROID)
 	#FIXME: move to client makefile?
-	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.64x64.png"   DESTINATION share/icons/hicolor/64x64/apps RENAME vcmiclient.png)
-	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.48x48.png"   DESTINATION share/icons/hicolor/48x48/apps RENAME vcmiclient.png)
-	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.32x32.png"   DESTINATION share/icons/hicolor/32x32/apps RENAME vcmiclient.png)
-	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.256x256.png" DESTINATION share/icons/hicolor/256x256/apps RENAME vcmiclient.png)
-	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.desktop"     DESTINATION share/applications)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.16x16.png"     DESTINATION share/icons/hicolor/16x16/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.32x32.png"     DESTINATION share/icons/hicolor/32x32/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.48x48.png"     DESTINATION share/icons/hicolor/48x48/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.64x64.png"     DESTINATION share/icons/hicolor/64x64/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.128x128.png"   DESTINATION share/icons/hicolor/128x128/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.256x256.png"   DESTINATION share/icons/hicolor/256x256/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.512x512.png"   DESTINATION share/icons/hicolor/512x512/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.1024x1024.png" DESTINATION share/icons/hicolor/1024x1024/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.2048x2048.png" DESTINATION share/icons/hicolor/2048x2048/apps RENAME vcmiclient.png)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.svg"           DESTINATION share/icons/hicolor/scalable/apps RENAME vcmiclient.svg)
+	install(FILES "${CMAKE_SOURCE_DIR}/client/icons/vcmiclient.desktop"       DESTINATION share/applications)
 endif()

+ 11 - 11
client/CPlayerInterface.cpp

@@ -103,7 +103,7 @@ std::shared_ptr<BattleInterface> CPlayerInterface::battleInt;
 enum  EMoveState {STOP_MOVE, WAITING_MOVE, CONTINUE_MOVE, DURING_MOVE};
 CondSh<EMoveState> stillMoveHero(STOP_MOVE); //used during hero movement
 
-struct HeroObjectRetriever : boost::static_visitor<const CGHeroInstance *>
+struct HeroObjectRetriever
 {
 	const CGHeroInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
 	{
@@ -328,7 +328,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details, bool verbose)
 	if (details.result == TryMoveHero::EMBARK || details.result == TryMoveHero::DISEMBARK)
 	{
 		if(hero->getRemovalSound() && hero->tempOwner == playerID)
-			CCS->soundh->playSound(hero->getRemovalSound().get());
+			CCS->soundh->playSound(hero->getRemovalSound().value());
 	}
 
 	adventureInt->minimap->updateTile(hero->convertToVisitablePos(details.start));
@@ -463,7 +463,7 @@ void CPlayerInterface::heroVisit(const CGHeroInstance * visitor, const CGObjectI
 	if(start && visitedObj)
 	{
 		if(visitedObj->getVisitSound())
-			CCS->soundh->playSound(visitedObj->getVisitSound().get());
+			CCS->soundh->playSound(visitedObj->getVisitSound().value());
 	}
 }
 
@@ -1530,7 +1530,7 @@ void CPlayerInterface::objectRemoved(const CGObjectInstance * obj)
 	if(LOCPLINT->cb->getCurrentPlayer() == playerID && obj->getRemovalSound())
 	{
 		waitWhileDialog();
-		CCS->soundh->playSound(obj->getRemovalSound().get());
+		CCS->soundh->playSound(obj->getRemovalSound().value());
 	}
 	CGI->mh->waitForOngoingAnimations();
 
@@ -1758,7 +1758,7 @@ void CPlayerInterface::acceptTurn()
 
 		if(optDaysWithoutCastle)
 		{
-			auto daysWithoutCastle = optDaysWithoutCastle.get();
+			auto daysWithoutCastle = optDaysWithoutCastle.value();
 			if (daysWithoutCastle < 6)
 			{
 				text.addTxt(MetaString::ARRAY_TXT,128); //%s, you only have %d days left to capture a town or you will be banished from this land.
@@ -1915,7 +1915,7 @@ void CPlayerInterface::requestReturningToMainMenu(bool won)
 
 void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
 {
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	if(hero)
 	{
 		auto art = hero->getArt(al.slot);
@@ -1932,14 +1932,14 @@ void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
 void CPlayerInterface::artifactPut(const ArtifactLocation &al)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	updateInfo(hero);
 }
 
 void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	updateInfo(hero);
 	for(auto isa : GH.listInt)
 	{
@@ -1954,7 +1954,7 @@ void CPlayerInterface::artifactRemoved(const ArtifactLocation &al)
 void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), dst.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), dst.artHolder);
 	updateInfo(hero);
 
 	bool redraw = true;
@@ -1983,7 +1983,7 @@ void CPlayerInterface::bulkArtMovementStart(size_t numOfArts)
 void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	updateInfo(hero);
 	for(auto isa : GH.listInt)
 	{
@@ -1996,7 +1996,7 @@ void CPlayerInterface::artifactAssembled(const ArtifactLocation &al)
 void CPlayerInterface::artifactDisassembled(const ArtifactLocation &al)
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
-	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);
+	auto hero = std::visit(HeroObjectRetriever(), al.artHolder);
 	updateInfo(hero);
 	for(auto isa : GH.listInt)
 	{

+ 2 - 2
client/Client.cpp

@@ -421,7 +421,7 @@ void CClient::initPlayerEnvironments()
 	
 	if(settings["session"]["spectate"].Bool())
 	{
-		playerEnvironments[PlayerColor::SPECTATOR] = std::make_shared<CPlayerEnvironment>(PlayerColor::SPECTATOR, this, std::make_shared<CCallback>(gs, boost::none, this));
+		playerEnvironments[PlayerColor::SPECTATOR] = std::make_shared<CPlayerEnvironment>(PlayerColor::SPECTATOR, this, std::make_shared<CCallback>(gs, std::nullopt, this));
 	}
 }
 
@@ -626,7 +626,7 @@ void CClient::commenceTacticPhaseForInt(std::shared_ptr<CBattleGameInterface> ba
 		battleInt->yourTacticPhase(gs->curB->tacticDistance);
 		if(gs && !!gs->curB && gs->curB->tacticDistance) //while awaiting for end of tactics phase, many things can happen (end of battle... or game)
 		{
-			MakeAction ma(BattleAction::makeEndOFTacticPhase(gs->curB->playerToSide(battleInt->playerID).get()));
+			MakeAction ma(BattleAction::makeEndOFTacticPhase(gs->curB->playerToSide(battleInt->playerID).value()));
 			sendRequest(&ma, battleInt->playerID);
 		}
 	}

+ 1 - 1
client/Client.h

@@ -140,7 +140,7 @@ public:
 
 	std::map<PlayerColor, std::vector<std::shared_ptr<IBattleEventsReceiver>>> additionalBattleInts;
 
-	boost::optional<BattleAction> curbaction;
+	std::optional<BattleAction> curbaction;
 
 	CClient();
 	~CClient();

+ 406 - 306
client/ClientCommandManager.cpp

@@ -42,7 +42,34 @@
 
 #include <SDL_surface.h>
 
-void ClientCommandManager::handleGoSolo()
+void ClientCommandManager::handleQuitCommand()
+{
+		exit(EXIT_SUCCESS);
+}
+
+void ClientCommandManager::handleSaveCommand(std::istringstream & singleWordBuffer)
+{
+	if(!CSH->client)
+	{
+		printCommandMessage("Game is not in playing state");
+		return;
+	}
+
+	std::string saveFilename;
+	singleWordBuffer >> saveFilename;
+	CSH->client->save(saveFilename);
+	printCommandMessage("Game saved as: " + saveFilename);
+}
+
+void ClientCommandManager::handleLoadCommand(std::istringstream& singleWordBuffer)
+{
+	// TODO: this code should end the running game and manage to call startGame instead
+	//std::string fname;
+	//singleWordBuffer >> fname;
+	//CSH->client->loadGame(fname);
+}
+
+void ClientCommandManager::handleGoSoloCommand()
 {
 	Settings session = settings.write["session"];
 
@@ -80,21 +107,33 @@ void ClientCommandManager::handleGoSolo()
 	session["aiSolo"].Bool() = !session["aiSolo"].Bool();
 }
 
-void ClientCommandManager::handleControlAi(const std::string &colorName)
+void ClientCommandManager::handleAutoskipCommand()
+{
+		Settings session = settings.write["session"];
+		session["autoSkip"].Bool() = !session["autoSkip"].Bool();
+}
+
+void ClientCommandManager::handleControlaiCommand(std::istringstream& singleWordBuffer)
 {
+	std::string colorName;
+	singleWordBuffer >> colorName;
+	boost::to_lower(colorName);
+
 	boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
 	if(!CSH->client)
 	{
 		printCommandMessage("Game is not in playing state");
 		return;
 	}
+
 	PlayerColor color;
 	if(LOCPLINT)
 		color = LOCPLINT->playerID;
+
 	for(auto & elem : CSH->client->gameState()->players)
 	{
-		if(elem.second.human || (colorName.length() &&
-								 elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
+		if(elem.second.human || 
+			(colorName.length() && elem.first.getNum() != vstd::find_pos(GameConstants::PLAYER_COLOR_NAMES, colorName)))
 		{
 			continue;
 		}
@@ -102,386 +141,319 @@ void ClientCommandManager::handleControlAi(const std::string &colorName)
 		CSH->client->removeGUI();
 		CSH->client->installNewPlayerInterface(std::make_shared<CPlayerInterface>(elem.first), elem.first);
 	}
+
 	GH.totalRedraw();
 	if(color != PlayerColor::NEUTRAL)
 		giveTurn(color);
 }
 
-void ClientCommandManager::processCommand(const std::string &message, bool calledFromIngameConsole)
+void ClientCommandManager::handleSetBattleAICommand(std::istringstream& singleWordBuffer)
 {
-	std::istringstream singleWordBuffer;
-	singleWordBuffer.str(message);
-	std::string commandName;
-	singleWordBuffer >> commandName;
-	currentCallFromIngameConsole = calledFromIngameConsole;
+	std::string aiName;
+	singleWordBuffer >> aiName;
 
-	if(message==std::string("die, fool"))
+	printCommandMessage("Will try loading that AI to see if it is correct name...\n");
+	try
 	{
-		exit(EXIT_SUCCESS);
+		if(auto ai = CDynLibHandler::getNewBattleAI(aiName)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
+		{
+			Settings neutralAI = settings.write["server"]["neutralAI"];
+			neutralAI->String() = aiName;
+			printCommandMessage("Setting changed, from now the battle ai will be " + aiName + "!\n");
+		}
 	}
-	else if(commandName == "redraw")
+	catch(std::exception &e)
 	{
-		GH.totalRedraw();
+		printCommandMessage("Failed opening " + aiName + ": " + e.what(), ELogLevel::WARN);
+		printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN);
 	}
-	else if(commandName == "screen")
-	{
-		printCommandMessage("Screenbuf points to ");
+}
 
-		if(screenBuf == screen)
-			printCommandMessage("screen", ELogLevel::ERROR);
-		else if(screenBuf == screen2)
-			printCommandMessage("screen2", ELogLevel::ERROR);
-		else
-			printCommandMessage("?!?", ELogLevel::ERROR);
+void ClientCommandManager::handleRedrawCommand()
+{
+	GH.totalRedraw();
+}
 
-		SDL_SaveBMP(screen, "Screen_c.bmp");
-		SDL_SaveBMP(screen2, "Screen2_c.bmp");
-	}
-	else if(commandName == "save")
+void ClientCommandManager::handleScreenCommand()
+{
+	printCommandMessage("Screenbuf points to ");
+
+	if(screenBuf == screen)
+		printCommandMessage("screen", ELogLevel::ERROR);
+	else if(screenBuf == screen2)
+		printCommandMessage("screen2", ELogLevel::ERROR);
+	else
+		printCommandMessage("?!?", ELogLevel::ERROR);
+
+	SDL_SaveBMP(screen, "Screen_c.bmp");
+	SDL_SaveBMP(screen2, "Screen2_c.bmp");
+}
+
+void ClientCommandManager::handleNotDialogCommand()
+{
+	LOCPLINT->showingDialog->setn(false);
+}
+
+void ClientCommandManager::handleGuiCommand()
+{
+	for(const auto & child : GH.listInt)
 	{
-		if(!CSH->client)
-		{
-			printCommandMessage("Game is not in playing state");
-			return;
-		}
-		std::string fname;
-		singleWordBuffer >> fname;
-		CSH->client->save(fname);
+		const auto childPtr = child.get();
+		if(const CIntObject * obj = dynamic_cast<const CIntObject*>(childPtr))
+			printInfoAboutInterfaceObject(obj, 0);
+		else
+			printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
 	}
-//	else if(commandName=="load")
-//	{
-//		// TODO: this code should end the running game and manage to call startGame instead
-//		std::string fname;
-//		singleWordBuffer >> fname;
-//		CSH->client->loadGame(fname);
-//	}
-	else if(message=="convert txt")
+}
+
+void ClientCommandManager::handleConvertTextCommand()
+{
+	logGlobal->info("Searching for available maps");
+	std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
 	{
-		logGlobal->info("Searching for available maps");
-		std::unordered_set<ResourceID> mapList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
-		{
-			return ident.getType() == EResType::MAP;
-		});
+		return ident.getType() == EResType::MAP;
+	});
 
-		std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
-		{
-			return ident.getType() == EResType::CAMPAIGN;
-		});
+	std::unordered_set<ResourceID> campaignList = CResourceHandler::get()->getFilteredFiles([&](const ResourceID & ident)
+	{
+		return ident.getType() == EResType::CAMPAIGN;
+	});
 
-		CMapService mapService;
+	CMapService mapService;
 
-		logGlobal->info("Loading maps for export");
-		for (auto const & mapName : mapList)
+	logGlobal->info("Loading maps for export");
+	for (auto const & mapName : mapList)
+	{
+		try
 		{
-			try
-			{
-				// load and drop loaded map - we only need loader to run over all maps
-				mapService.loadMap(mapName);
-			}
-			catch(std::exception & e)
-			{
-				logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
-			}
+			// load and drop loaded map - we only need loader to run over all maps
+			mapService.loadMap(mapName);
 		}
-
-		logGlobal->info("Loading campaigns for export");
-		for (auto const & campaignName : campaignList)
+		catch(std::exception & e)
 		{
-			CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName()));
-			for (auto const & part : state.camp->mapPieces)
-				delete state.getMap(part.first);
+			logGlobal->error("Map %s is invalid. Message: %s", mapName.getName(), e.what());
 		}
-
-		VLC->generaltexth->dumpAllTexts();
 	}
-	else if(message=="get config")
+
+	logGlobal->info("Loading campaigns for export");
+	for (auto const & campaignName : campaignList)
 	{
-		printCommandMessage("Command accepted.\t");
+		CCampaignState state(CCampaignHandler::getCampaign(campaignName.getName()));
+		for (auto const & part : state.camp->mapPieces)
+			delete state.getMap(part.first);
+	}
 
-		const boost::filesystem::path outPath =
-				VCMIDirs::get().userExtractedPath() / "configuration";
+	VLC->generaltexth->dumpAllTexts();
+}
 
-		boost::filesystem::create_directories(outPath);
+void ClientCommandManager::handleGetConfigCommand()
+{
+	printCommandMessage("Command accepted.\t");
 
-		const std::vector<std::string> contentNames = {"heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills"};
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "configuration";
 
-		for(auto contentName : contentNames)
-		{
-			auto & content = (*VLC->modh->content)[contentName];
+	boost::filesystem::create_directories(outPath);
 
-			auto contentOutPath = outPath / contentName;
-			boost::filesystem::create_directories(contentOutPath);
+	const std::vector<std::string> contentNames = { "heroClasses", "artifacts", "creatures", "factions", "objects", "heroes", "spells", "skills" };
 
-			for(auto & iter : content.modData)
-			{
-				const JsonNode & modData = iter.second.modData;
+	for(auto contentName : contentNames)
+	{
+		auto& content = (*VLC->modh->content)[contentName];
 
-				for(auto & nameAndObject : modData.Struct())
-				{
-					const JsonNode & object = nameAndObject.second;
+		auto contentOutPath = outPath / contentName;
+		boost::filesystem::create_directories(contentOutPath);
 
-					std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
+		for(auto& iter : content.modData)
+		{
+			const JsonNode& modData = iter.second.modData;
+
+			for(auto& nameAndObject : modData.Struct())
+			{
+				const JsonNode& object = nameAndObject.second;
 
-					boost::algorithm::replace_all(name,":","_");
+				std::string name = CModHandler::makeFullIdentifier(object.meta, contentName, nameAndObject.first);
 
-					const boost::filesystem::path filePath = contentOutPath / (name + ".json");
-					boost::filesystem::ofstream file(filePath);
-					file << object.toJson();
-				}
+				boost::algorithm::replace_all(name, ":", "_");
+
+				const boost::filesystem::path filePath = contentOutPath / (name + ".json");
+				boost::filesystem::ofstream file(filePath);
+				file << object.toJson();
 			}
 		}
-
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
 	}
+
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+}
+
+void ClientCommandManager::handleGetScriptsCommand()
+{
 #if SCRIPTING_ENABLED
-		else if(message=="get scripts")
-	{
-		printCommandMessage("Command accepted.\t");
+	printCommandMessage("Command accepted.\t");
 
-		const boost::filesystem::path outPath =
-			VCMIDirs::get().userExtractedPath() / "scripts";
+	const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / "scripts";
 
-		boost::filesystem::create_directories(outPath);
+	boost::filesystem::create_directories(outPath);
 
-		for(auto & kv : VLC->scriptHandler->objects)
-		{
-			std::string name = kv.first;
-			boost::algorithm::replace_all(name,":","_");
+	for(auto & kv : VLC->scriptHandler->objects)
+	{
+		std::string name = kv.first;
+		boost::algorithm::replace_all(name,":","_");
 
-			const scripting::ScriptImpl * script = kv.second.get();
-			boost::filesystem::path filePath = outPath / (name + ".lua");
-			boost::filesystem::ofstream file(filePath);
-			file << script->getSource();
-		}
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+		const scripting::ScriptImpl * script = kv.second.get();
+		boost::filesystem::path filePath = outPath / (name + ".lua");
+		boost::filesystem::ofstream file(filePath);
+		file << script->getSource();
 	}
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
 #endif
-	else if(message=="get txt")
-	{
-		printCommandMessage("Command accepted.\t");
+}
 
-		const boost::filesystem::path outPath =
-				VCMIDirs::get().userExtractedPath();
+void ClientCommandManager::handleGetTextCommand()
+{
+	printCommandMessage("Command accepted.\t");
 
-		auto list =
-				CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
-				{
-					return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
-				});
+	const boost::filesystem::path outPath =
+			VCMIDirs::get().userExtractedPath();
 
-		for (auto & filename : list)
-		{
-			const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT");
+	auto list =
+			CResourceHandler::get()->getFilteredFiles([](const ResourceID & ident)
+			{
+				return ident.getType() == EResType::TEXT && boost::algorithm::starts_with(ident.getName(), "DATA/");
+			});
 
-			boost::filesystem::create_directories(filePath.parent_path());
+	for (auto & filename : list)
+	{
+		const boost::filesystem::path filePath = outPath / (filename.getName() + ".TXT");
 
-			boost::filesystem::ofstream file(filePath);
-			auto text = CResourceHandler::get()->load(filename)->readAll();
+		boost::filesystem::create_directories(filePath.parent_path());
 
-			file.write((char*)text.first.get(), text.second);
-		}
+		boost::filesystem::ofstream file(filePath);
+		auto text = CResourceHandler::get()->load(filename)->readAll();
 
-		printCommandMessage("\rExtracting done :)\n");
-		printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
-	}
-	else if(commandName == "crash")
-	{
-		int *ptr = nullptr;
-		*ptr = 666;
-		//disaster!
-	}
-	else if(commandName == "mp" && adventureInt)
-	{
-		if(const CGHeroInstance *h = adventureInt->curHero())
-			printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
-	}
-	else if(commandName == "bonuses")
-	{
-		bool jsonFormat = (message == "bonuses json");
-		auto format = [jsonFormat](const BonusList & b) -> std::string
-		{
-			if(jsonFormat)
-				return b.toJsonNode().toJson(true);
-			std::ostringstream ss;
-			ss << b;
-			return ss.str();
-		};
-		printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n");
-		printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n");
-
-		printCommandMessage("\nInherited bonuses:\n");
-		TCNodes parents;
-		adventureInt->curArmy()->getParents(parents);
-		for(const CBonusSystemNode *parent : parents)
-		{
-			printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
-		}
-	}
-	else if(commandName == "not dialog")
-	{
-		LOCPLINT->showingDialog->setn(false);
+		file.write((char*)text.first.get(), text.second);
 	}
-	else if(commandName == "gui")
-	{
-		for(auto & child : GH.listInt)
-		{
-			const auto childPtr = child.get();
-			if(const CIntObject * obj = dynamic_cast<const CIntObject *>(childPtr))
-				printInfoAboutInterfaceObject(obj, 0);
-			else
-				printCommandMessage(std::string(typeid(childPtr).name()) + "\n");
-		}
-	}
-	else if(commandName == "tell")
-	{
-		std::string what;
-		int id1, id2;
-		singleWordBuffer >> what >> id1 >> id2;
-		if(what == "hs")
-		{
-			for(const CGHeroInstance *h : LOCPLINT->cb->getHeroesInfo())
-				if(h->type->getIndex() == id1)
-					if(const CArtifactInstance *a = h->getArt(ArtifactPosition(id2)))
-						printCommandMessage(a->nodeName());
-		}
-	}
-	else if (commandName == "set")
-	{
-		std::string what, value;
-		singleWordBuffer >> what;
 
-		Settings config = settings.write["session"][what];
+	printCommandMessage("\rExtracting done :)\n");
+	printCommandMessage("Extracted files can be found in " + outPath.string() + " directory\n");
+}
 
-		singleWordBuffer >> value;
+void ClientCommandManager::handleDef2bmpCommand(std::istringstream& singleWordBuffer)
+{
+	std::string URI;
+	singleWordBuffer >> URI;
+	std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
+	anim->preload();
+	anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
+}
 
-		if (value == "on")
-		{
-			config->Bool() = true;
-			printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO);
-		}
-		else if (value == "off")
-		{
-			config->Bool() = false;
-			printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO);
-		}
-	}
-	else if(commandName == "unlock")
-	{
-		std::string mxname;
-		singleWordBuffer >> mxname;
-		if(mxname == "pim" && LOCPLINT)
-			LOCPLINT->pim->unlock();
-	}
-	else if(commandName == "def2bmp")
-	{
-		std::string URI;
-		singleWordBuffer >> URI;
-		std::unique_ptr<CAnimation> anim = std::make_unique<CAnimation>(URI);
-		anim->preload();
-		anim->exportBitmaps(VCMIDirs::get().userExtractedPath());
-	}
-	else if(commandName == "extract")
-	{
-		std::string URI;
-		singleWordBuffer >> URI;
+void ClientCommandManager::handleExtractCommand(std::istringstream& singleWordBuffer)
+{
+	std::string URI;
+	singleWordBuffer >> URI;
 
-		if (CResourceHandler::get()->existsResource(ResourceID(URI)))
-		{
-			const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
+	if(CResourceHandler::get()->existsResource(ResourceID(URI)))
+	{
+		const boost::filesystem::path outPath = VCMIDirs::get().userExtractedPath() / URI;
 
-			auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
+		auto data = CResourceHandler::get()->load(ResourceID(URI))->readAll();
 
-			boost::filesystem::create_directories(outPath.parent_path());
-			boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary);
-			outFile.write((char*)data.first.get(), data.second);
-		}
-		else
-			printCommandMessage("File not found!", ELogLevel::ERROR);
+		boost::filesystem::create_directories(outPath.parent_path());
+		boost::filesystem::ofstream outFile(outPath, boost::filesystem::ofstream::binary);
+		outFile.write((char*)data.first.get(), data.second);
 	}
-	else if(commandName == "setBattleAI")
+	else
+		printCommandMessage("File not found!", ELogLevel::ERROR);
+}
+
+void ClientCommandManager::handleBonusesCommand(std::istringstream & singleWordBuffer)
+{
+	if(currentCallFromIngameConsole)
 	{
-		std::string fname;
-		singleWordBuffer >> fname;
-		printCommandMessage("Will try loading that AI to see if it is correct name...\n");
-		try
-		{
-			if(auto ai = CDynLibHandler::getNewBattleAI(fname)) //test that given AI is indeed available... heavy but it is easy to make a typo and break the game
-			{
-				Settings neutralAI = settings.write["server"]["neutralAI"];
-				neutralAI->String() = fname;
-				printCommandMessage("Setting changed, from now the battle ai will be " + fname + "!\n");
-			}
-		}
-		catch(std::exception &e)
-		{
-			printCommandMessage("Failed opening " + fname + ": " + e.what(), ELogLevel::WARN);
-			printCommandMessage("Setting not changed, AI not found or invalid!", ELogLevel::WARN);
-		}
+		printCommandMessage("Output for this command is too large for ingame chat! Please run it from client console.\n");
+		return;
 	}
-	else if(commandName == "autoskip")
+
+	std::string outputFormat;
+	singleWordBuffer >> outputFormat;
+
+	auto format = [outputFormat](const BonusList & b) -> std::string
 	{
-		Settings session = settings.write["session"];
-		session["autoSkip"].Bool() = !session["autoSkip"].Bool();
-	}
-	else if(commandName == "gosolo")
+		if(outputFormat == "json")
+			return b.toJsonNode().toJson(true);
+
+		std::ostringstream ss;
+		ss << b;
+		return ss.str();
+	};
+	printCommandMessage("Bonuses of " + adventureInt->curArmy()->getObjectName() + "\n");
+	printCommandMessage(format(adventureInt->curArmy()->getBonusList()) + "\n");
+
+	printCommandMessage("\nInherited bonuses:\n");
+	TCNodes parents;
+	adventureInt->curArmy()->getParents(parents);
+	for(const CBonusSystemNode *parent : parents)
 	{
-		ClientCommandManager::handleGoSolo();
+		printCommandMessage(std::string("\nBonuses from ") + typeid(*parent).name() + "\n" + format(*parent->getAllBonuses(Selector::all, Selector::all)) + "\n");
 	}
-	else if(commandName == "controlai")
-	{
-		std::string colorName;
-		singleWordBuffer >> colorName;
-		boost::to_lower(colorName);
+}
 
-		ClientCommandManager::handleControlAi(colorName);
-	}
-	else
+void ClientCommandManager::handleTellCommand(std::istringstream& singleWordBuffer)
+{
+	std::string what;
+	int id1, id2;
+	singleWordBuffer >> what >> id1 >> id2;
+
+	if(what == "hs")
 	{
-		if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise
-			printCommandMessage("Command not found :(", ELogLevel::ERROR);
+		for(const CGHeroInstance* h : LOCPLINT->cb->getHeroesInfo())
+			if(h->type->getIndex() == id1)
+				if(const CArtifactInstance* a = h->getArt(ArtifactPosition(id2)))
+					printCommandMessage(a->nodeName());
 	}
 }
 
-void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
+void ClientCommandManager::handleMpCommand()
 {
-	YourTurn yt;
-	yt.player = colorIdentifier;
-	yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle;
-
-	ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState());
-	yt.visit(visitor);
+	if(const CGHeroInstance* h = adventureInt->curHero())
+		printCommandMessage(std::to_string(h->movement) + "; max: " + std::to_string(h->maxMovePoints(true)) + "/" + std::to_string(h->maxMovePoints(false)) + "\n");
 }
 
-void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level)
+void ClientCommandManager::handleSetCommand(std::istringstream& singleWordBuffer)
 {
-	std::stringstream sbuffer;
-	sbuffer << std::string(level, '\t');
+	std::string what, value;
+	singleWordBuffer >> what;
 
-	sbuffer << typeid(*obj).name() << " *** ";
-	if (obj->active)
+	Settings config = settings.write["session"][what];
+
+	singleWordBuffer >> value;
+
+	if(value == "on")
 	{
-#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
-		PRINT(LCLICK, 'L');
-		PRINT(RCLICK, 'R');
-		PRINT(HOVER, 'H');
-		PRINT(MOVE, 'M');
-		PRINT(KEYBOARD, 'K');
-		PRINT(TIME, 'T');
-		PRINT(GENERAL, 'A');
-		PRINT(WHEEL, 'W');
-		PRINT(DOUBLECLICK, 'D');
-#undef  PRINT
+		config->Bool() = true;
+		printCommandMessage("Option " + what + " enabled!", ELogLevel::INFO);
 	}
-	else
-		sbuffer << "inactive";
-	sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
-	sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
-	printCommandMessage(sbuffer.str(), ELogLevel::INFO);
+	else if(value == "off")
+	{
+		config->Bool() = false;
+		printCommandMessage("Option " + what + " disabled!", ELogLevel::INFO);
+	}
+}
 
-	for(const CIntObject *child : obj->children)
-		printInfoAboutInterfaceObject(child, level+1);
+void ClientCommandManager::handleUnlockCommand(std::istringstream& singleWordBuffer)
+{
+	std::string mxname;
+	singleWordBuffer >> mxname;
+	if(mxname == "pim" && LOCPLINT)
+		LOCPLINT->pim->unlock();
+}
+
+void ClientCommandManager::handleCrashCommand()
+{
+	int* ptr = nullptr;
+	*ptr = 666;
+	//disaster!
 }
 
 void ClientCommandManager::printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType)
@@ -520,3 +492,131 @@ void ClientCommandManager::printCommandMessage(const std::string &commandMessage
 		}
 	}
 }
+
+void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj, int level)
+{
+	std::stringstream sbuffer;
+	sbuffer << std::string(level, '\t');
+
+	sbuffer << typeid(*obj).name() << " *** ";
+	if (obj->active)
+	{
+#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
+		PRINT(LCLICK, 'L');
+		PRINT(RCLICK, 'R');
+		PRINT(HOVER, 'H');
+		PRINT(MOVE, 'M');
+		PRINT(KEYBOARD, 'K');
+		PRINT(TIME, 'T');
+		PRINT(GENERAL, 'A');
+		PRINT(WHEEL, 'W');
+		PRINT(DOUBLECLICK, 'D');
+#undef  PRINT
+	}
+	else
+		sbuffer << "inactive";
+	sbuffer << " at " << obj->pos.x <<"x"<< obj->pos.y;
+	sbuffer << " (" << obj->pos.w <<"x"<< obj->pos.h << ")";
+	printCommandMessage(sbuffer.str(), ELogLevel::INFO);
+
+	for(const CIntObject *child : obj->children)
+		printInfoAboutInterfaceObject(child, level+1);
+}
+
+void ClientCommandManager::giveTurn(const PlayerColor &colorIdentifier)
+{
+	YourTurn yt;
+	yt.player = colorIdentifier;
+	yt.daysWithoutCastle = CSH->client->getPlayerState(colorIdentifier)->daysWithoutCastle;
+
+	ApplyClientNetPackVisitor visitor(*CSH->client, *CSH->client->gameState());
+	yt.visit(visitor);
+}
+
+void ClientCommandManager::processCommand(const std::string & message, bool calledFromIngameConsole)
+{
+	// split the message into individual words
+	std::istringstream singleWordBuffer;
+	singleWordBuffer.str(message);
+
+	// get command name, to be used for single word commands
+	std::string commandName;
+	singleWordBuffer >> commandName;
+
+	currentCallFromIngameConsole = calledFromIngameConsole;
+
+	if(message == std::string("die, fool"))
+		handleQuitCommand();
+
+	else if(commandName == "save")
+		handleSaveCommand(singleWordBuffer);
+
+	else if(commandName=="load")
+		handleLoadCommand(singleWordBuffer); // not implemented
+
+	else if(commandName == "gosolo")
+		handleGoSoloCommand();
+
+	else if(commandName == "autoskip")
+		handleAutoskipCommand();
+
+	else if(commandName == "controlai")
+		handleControlaiCommand(singleWordBuffer);
+
+	else if(commandName == "setBattleAI")
+		handleSetBattleAICommand(singleWordBuffer);
+
+	else if(commandName == "redraw")
+		handleRedrawCommand();
+
+	else if(commandName == "screen")
+		handleScreenCommand();
+
+	else if(commandName == "not dialog")
+		handleNotDialogCommand();
+
+	else if(commandName == "gui")
+		handleGuiCommand();
+
+	else if(message=="convert txt")
+		handleConvertTextCommand();
+
+	else if(message=="get config")
+		handleGetConfigCommand();
+
+	else if(message=="get scripts")
+		handleGetScriptsCommand();
+
+	else if(message=="get txt")
+		handleGetTextCommand();
+
+	else if(commandName == "def2bmp")
+		handleDef2bmpCommand(singleWordBuffer);
+
+	else if(commandName == "extract")
+		handleExtractCommand(singleWordBuffer);
+
+	else if(commandName == "bonuses")
+		handleBonusesCommand(singleWordBuffer);
+
+	else if(commandName == "tell")
+		handleTellCommand(singleWordBuffer);
+
+	else if(commandName == "mp" && adventureInt)
+		handleMpCommand();
+
+	else if (commandName == "set")
+		handleSetCommand(singleWordBuffer);
+
+	else if(commandName == "unlock")
+		handleUnlockCommand(singleWordBuffer);
+
+	else if(commandName == "crash")
+		handleCrashCommand();
+
+	else
+	{
+		if (!commandName.empty() && !vstd::iswithin(commandName[0], 0, ' ')) // filter-out debugger/IDE noise
+			printCommandMessage("Command not found :(", ELogLevel::ERROR);
+	}
+}

+ 76 - 6
client/ClientCommandManager.h

@@ -17,15 +17,85 @@ class CIntObject;
 
 class ClientCommandManager //take mantis #2292 issue about account if thinking about handling cheats from command-line
 {
-	bool currentCallFromIngameConsole = false;
+	bool currentCallFromIngameConsole = false; // commands can come from 2 sources: ingame console (chat) and client console
+	
+	// Quits the game (die, fool command)
+	void handleQuitCommand();
 
-	void giveTurn(const PlayerColor &color);
-	void printInfoAboutInterfaceObject(const CIntObject *obj, int level);
+	// Saves current game under the given filename
+	void handleSaveCommand(std::istringstream & singleWordBuffer);
+
+	// Loads a game with the given filename
+	void handleLoadCommand(std::istringstream & singleWordBuffer);
+
+	// AI takes over until the end of turn (unlike original H3 currently causes AI to take over until typed again)
+	void handleGoSoloCommand();
+
+	// Toggles autoskip mode on and off. In this mode, player turns are automatically skipped and only AI moves.
+	// However, GUI is still present and allows to observe AI moves. After this option is activated, you need to end first turn manually.
+	// Press [Shift] before your turn starts to not skip it.
+	void handleAutoskipCommand();
+
+	// Gives you control over specified AI player. If none is specified gives you control over all AI players
+	void handleControlaiCommand(std::istringstream& singleWordBuffer);
+
+	// Change battle AI used by neutral creatures to the one specified. Persists through game quit
+	void handleSetBattleAICommand(std::istringstream& singleWordBuffer);
+
+	// Redraw the current screen
+	void handleRedrawCommand();
+
+	// Prints information about current screen, and saves both screens as .bmp in root folder
+	void handleScreenCommand();
+
+	// Set the state indicating if dialog box is active to "no"
+	void handleNotDialogCommand();
+
+	// Displays tree view of currently present VCMI common GUI elements
+	void handleGuiCommand();
+
+	// Dumps all game text, maps text and campaign maps text into Client log between BEGIN TEXT EXPORT and END TEXT EXPORT
+	void handleConvertTextCommand();
+
+	// Saves current game configuration into extracted/configuration folder
+	void handleGetConfigCommand();
+
+	// Dumps all scripts in Extracted/Scripts
+	void handleGetScriptsCommand();
+
+	// Dumps all .txt files from DATA into Extracted/DATA
+	void handleGetTextCommand();
+
+	// Extract .def animation as BMP files
+	void handleDef2bmpCommand(std::istringstream& singleWordBuffer);
+
+	// Export file into Extracted directory
+	void handleExtractCommand(std::istringstream& singleWordBuffer);
+
+	// Print in console the current bonuses for curent army
+	void handleBonusesCommand(std::istringstream & singleWordBuffer);
+
+	// Get what artifact is present on artifact slot with specified ID for hero with specified ID
+	void handleTellCommand(std::istringstream& singleWordBuffer);
+
+	// Show current movement points, max movement points on land / max movement points on water.
+	void handleMpCommand();
+
+	// set <command> <on/off> - sets special temporary settings that reset on game quit.
+	void handleSetCommand(std::istringstream& singleWordBuffer);
+
+	// Unlocks specific mutex known in VCMI code as "pim"
+	void handleUnlockCommand(std::istringstream& singleWordBuffer);
+
+	// Crashes the game forcing an exception
+	void handleCrashCommand();
+
+	// Prints in Chat the given message
 	void printCommandMessage(const std::string &commandMessage, ELogLevel::ELogLevel messageType = ELogLevel::NOT_SET);
-	void handleGoSolo();
-	void handleControlAi(const std::string &colorName);
+	void printInfoAboutInterfaceObject(const CIntObject *obj, int level);
+	void giveTurn(const PlayerColor &color);
 
 public:
 	ClientCommandManager() = default;
-	void processCommand(const std::string &message, bool calledFromIngameConsole);
+	void processCommand(const std::string & message, bool calledFromIngameConsole);
 };

+ 1 - 1
client/NetPacksClient.cpp

@@ -762,7 +762,7 @@ void ApplyClientNetPackVisitor::visitBattleAttack(BattleAttack & pack)
 
 void ApplyFirstClientNetPackVisitor::visitStartAction(StartAction & pack)
 {
-	cl.curbaction = boost::make_optional(pack.ba);
+	cl.curbaction = std::make_optional(pack.ba);
 	callBattleInterfaceIfPresentForBothSides(cl, &IBattleEventsReceiver::actionStarted, pack.ba);
 }
 

+ 2 - 2
client/adventureMap/CAdvMapInt.cpp

@@ -853,7 +853,7 @@ void CAdvMapInt::keyPressed(const SDL_Keycode & key)
 	}
 }
 
-boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
+std::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
 {
 	switch (key) {
 		case SDLK_DOWN:  return Point( 0, +1);
@@ -871,7 +871,7 @@ boost::optional<Point> CAdvMapInt::keyToMoveDirection(const SDL_Keycode & key)
 		case SDLK_KP_8: return Point( 0, -1);
 		case SDLK_KP_9: return Point(+1, -1);
 	}
-	return boost::none;
+	return std::nullopt;
 }
 
 void CAdvMapInt::select(const CArmedInstance *sel, bool centerView)

+ 1 - 1
client/adventureMap/CAdvMapInt.h

@@ -143,7 +143,7 @@ private:
 
 	const CGObjectInstance *getActiveObject(const int3 &tile);
 
-	boost::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
+	std::optional<Point> keyToMoveDirection(const SDL_Keycode & key);
 
 public:
 	CAdvMapInt();

+ 1 - 1
client/adventureMap/MapAudioPlayer.cpp

@@ -136,7 +136,7 @@ std::vector<std::string> MapAudioPlayer::getAmbientSounds(const int3 & tile)
 			logGlobal->warn("Already removed object %d found on tile! (%d %d %d)", objectID.getNum(), tile.x, tile.y, tile.z);
 
 		if(object && object->getAmbientSound())
-			result.push_back(object->getAmbientSound().get());
+			result.push_back(object->getAmbientSound().value());
 	}
 
 	if(CGI->mh->getMap()->isCoastalTile(tile))

+ 1 - 1
client/battle/BattleInterface.cpp

@@ -252,7 +252,7 @@ void BattleInterface::giveCommand(EActionType action, BattleHex tile, si32 addit
 	}
 
 	auto ba = new BattleAction(); //is deleted in CPlayerInterface::stacksController->getActiveStack()()
-	ba->side = side.get();
+	ba->side = side.value();
 	ba->actionType = action;
 	ba->aimToHex(tile);
 	ba->actionSubtype = additional;

+ 6 - 6
client/battle/BattleInterfaceClasses.cpp

@@ -68,7 +68,7 @@ void BattleConsole::showAll(SDL_Surface * to)
 std::vector<std::string> BattleConsole::getVisibleText()
 {
 	// high priority texts that hide battle log entries
-	for (auto const & text : {consoleText, hoverText} )
+	for(const auto & text : {consoleText, hoverText})
 	{
 		if (text.empty())
 			continue;
@@ -94,7 +94,7 @@ std::vector<std::string> BattleConsole::splitText(const std::string &text)
 
 	boost::split(lines, text, boost::is_any_of("\n"));
 
-	for (auto const & line : lines)
+	for(const auto & line : lines)
 	{
 		if (graphics->fonts[FONT_SMALL]->getStringWidth(text) < pos.w)
 		{
@@ -679,7 +679,7 @@ int32_t StackQueue::getSiegeShooterIconID()
 	return owner.siegeController->getSiegedTown()->town->faction->getIndex();
 }
 
-boost::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
+std::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
 {
 	for(const auto & stackBox : stackBoxes)
 	{
@@ -689,7 +689,7 @@ boost::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
 		}
 	}
 
-	return boost::none;
+	return std::nullopt;
 }
 
 StackQueue::StackBox::StackBox(StackQueue * owner):
@@ -758,7 +758,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
 	}
 	else
 	{
-		boundUnitID = boost::none;
+		boundUnitID = std::nullopt;
 		background->colorize(PlayerColor::NEUTRAL);
 		icon->visible = false;
 		icon->setFrame(0);
@@ -769,7 +769,7 @@ void StackQueue::StackBox::setUnit(const battle::Unit * unit, size_t turn)
 	}
 }
 
-boost::optional<uint32_t> StackQueue::StackBox::getBoundUnitID() const
+std::optional<uint32_t> StackQueue::StackBox::getBoundUnitID() const
 {
 	return boundUnitID;
 }

+ 3 - 3
client/battle/BattleInterfaceClasses.h

@@ -166,7 +166,7 @@ class StackQueue : public CIntObject
 	class StackBox : public CIntObject
 	{
 		StackQueue * owner;
-		boost::optional<uint32_t> boundUnitID;
+		std::optional<uint32_t> boundUnitID;
 		bool highlighted = false;
 
 	public:
@@ -178,7 +178,7 @@ class StackQueue : public CIntObject
 		StackBox(StackQueue * owner);
 		void setUnit(const battle::Unit * unit, size_t turn = 0);
 		void toggleHighlight(bool value);
-		boost::optional<uint32_t> getBoundUnitID() const;
+		std::optional<uint32_t> getBoundUnitID() const;
 
 		void show(SDL_Surface * to) override;
 	};
@@ -197,7 +197,7 @@ public:
 
 	StackQueue(bool Embedded, BattleInterface & owner);
 	void update();
-	boost::optional<uint32_t> getHoveredUnitIdIfAny() const;
+	std::optional<uint32_t> getHoveredUnitIdIfAny() const;
 
 	void show(SDL_Surface * to) override;
 };

+ 3 - 3
client/battle/BattleObstacleController.cpp

@@ -66,7 +66,7 @@ void BattleObstacleController::loadObstacleImage(const CObstacleInstance & oi)
 
 void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges> & obstacles)
 {
-	for (auto const & oi : obstacles)
+	for(const auto & oi : obstacles)
 	{
 		auto & obstacle = oi.data["obstacle"];
 
@@ -97,11 +97,11 @@ void BattleObstacleController::obstacleRemoved(const std::vector<ObstacleChanges
 
 void BattleObstacleController::obstaclePlaced(const std::vector<std::shared_ptr<const CObstacleInstance>> & obstacles)
 {
-	for (auto const & oi : obstacles)
+	for(const auto & oi : obstacles)
 	{
 		auto side = owner.curInt->cb->playerToSide(owner.curInt->playerID);
 
-		if(!oi->visibleForSide(side.get(),owner.curInt->cb->battleHasNativeStack(side.get())))
+		if(!oi->visibleForSide(side.value(), owner.curInt->cb->battleHasNativeStack(side.value())))
 			continue;
 
 		auto animation = std::make_shared<CAnimation>(oi->getAppearAnimation());

+ 6 - 6
client/battle/BattleStacksController.cpp

@@ -281,7 +281,7 @@ std::shared_ptr<IImage> BattleStacksController::getStackAmountBox(const CStack *
 
 	int effectsPositivness = 0;
 
-	for ( auto const & spellID : activeSpells)
+	for(const auto & spellID : activeSpells)
 		effectsPositivness += CGI->spellh->objects.at(spellID)->positiveness;
 
 	if (effectsPositivness > 0)
@@ -336,7 +336,7 @@ void BattleStacksController::showStackAmountBox(Canvas & canvas, const CStack *
 void BattleStacksController::showStack(Canvas & canvas, const CStack * stack)
 {
 	ColorFilter fullFilter = ColorFilter::genEmptyShifter();
-	for (auto const & filter : stackFilterEffects)
+	for(const auto & filter : stackFilterEffects)
 	{
 		if (filter.target == stack)
 			fullFilter = ColorFilter::genCombined(fullFilter, filter.effect);
@@ -814,7 +814,7 @@ void BattleStacksController::updateHoveredStacks()
 {
 	auto newStacks = selectHoveredStacks();
 
-	for (auto const * stack : mouseHoveredStacks)
+	for(const auto * stack : mouseHoveredStacks)
 	{
 		if (vstd::contains(newStacks, stack))
 			continue;
@@ -825,7 +825,7 @@ void BattleStacksController::updateHoveredStacks()
 			stackAnimation[stack->ID]->setBorderColor(AnimationControls::getNoBorder());
 	}
 
-	for (auto const * stack : newStacks)
+	for(const auto * stack : newStacks)
 	{
 		if (vstd::contains(mouseHoveredStacks, stack))
 			continue;
@@ -848,7 +848,7 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
 		return {};
 
 	auto hoveredQueueUnitId = owner.windowObject->getQueueHoveredUnitId();
-	if(hoveredQueueUnitId.is_initialized())
+	if(hoveredQueueUnitId.has_value())
 	{
 		return { owner.curInt->cb->battleGetStackByID(hoveredQueueUnitId.value(), true) };
 	}
@@ -889,7 +889,7 @@ std::vector<const CStack *> BattleStacksController::selectHoveredStacks()
 const std::vector<uint32_t> BattleStacksController::getHoveredStacksUnitIds() const
 {
 	auto result = std::vector<uint32_t>();
-	for (auto const * stack : mouseHoveredStacks)
+	for(const auto * stack : mouseHoveredStacks)
 	{
 		result.push_back(stack->unitId());
 	}

+ 1 - 1
client/battle/BattleWindow.cpp

@@ -590,7 +590,7 @@ void BattleWindow::blockUI(bool on)
 	}
 }
 
-boost::optional<uint32_t> BattleWindow::getQueueHoveredUnitId()
+std::optional<uint32_t> BattleWindow::getQueueHoveredUnitId()
 {
 	return queue->getHoveredUnitIdIfAny();
 }

+ 1 - 1
client/battle/BattleWindow.h

@@ -80,7 +80,7 @@ public:
 	void updateQueue();
 
 	/// Get mouse-hovered battle queue unit ID if any found
-	boost::optional<uint32_t> getQueueHoveredUnitId();
+	std::optional<uint32_t> getQueueHoveredUnitId();
 
 	void activate() override;
 	void deactivate() override;

BIN
client/icons/vcmiclient.1024x1024.png


BIN
client/icons/vcmiclient.128x128.png


BIN
client/icons/vcmiclient.16x16.png


BIN
client/icons/vcmiclient.2048x2048.png


BIN
client/icons/vcmiclient.256x256.png


BIN
client/icons/vcmiclient.32x32.png


BIN
client/icons/vcmiclient.48x48.png


BIN
client/icons/vcmiclient.512x512.png


BIN
client/icons/vcmiclient.64x64.png


BIN
client/icons/vcmiclient.psd


+ 401 - 0
client/icons/vcmiclient.svg

@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="1671.788"
+   height="1671.788"
+   viewBox="0 0 442.32723 442.32723"
+   version="1.1"
+   id="svg8061"
+   sodipodi:docname="VCMI-logo.svg"
+   inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <sodipodi:namedview
+     id="namedview71"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     showgrid="false"
+     showguides="true"
+     inkscape:zoom="0.61431235"
+     inkscape:cx="835.89398"
+     inkscape:cy="835.08006"
+     inkscape:window-width="2560"
+     inkscape:window-height="1372"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg8061" />
+  <defs
+     id="defs8058">
+    <filter
+       style="color-interpolation-filters:sRGB"
+       id="filter5509"
+       x="-0.049653775"
+       y="-0.046298778"
+       width="1.0993076"
+       height="1.0925976">
+      <feFlood
+         flood-opacity="0.741176"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood5499" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite5501" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="5"
+         result="blur"
+         id="feGaussianBlur5503" />
+      <feOffset
+         dx="0"
+         dy="0"
+         result="offset"
+         id="feOffset5505" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite5507" />
+    </filter>
+    <linearGradient
+       xlink:href="#b"
+       id="linearGradient6733"
+       x1="142.42035"
+       y1="742.36987"
+       x2="894.56238"
+       y2="-43.642666"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="b">
+      <stop
+         style="stop-color:#413c35;stop-opacity:1;"
+         offset="0"
+         id="stop6727" />
+      <stop
+         style="stop-color:#e1dfde;stop-opacity:1;"
+         offset="0.25866053"
+         id="stop23920" />
+      <stop
+         style="stop-color:#ffffff;stop-opacity:1;"
+         offset="0.34411085"
+         id="stop17103" />
+      <stop
+         style="stop-color:#343131;stop-opacity:1;"
+         offset="0.45496535"
+         id="stop19868" />
+      <stop
+         style="stop-color:#676565;stop-opacity:1;"
+         offset="0.60739028"
+         id="stop23916" />
+      <stop
+         style="stop-color:#bab9b9;stop-opacity:1;"
+         offset="0.69515014"
+         id="stop21700" />
+      <stop
+         style="stop-color:#bab9b9;stop-opacity:1;"
+         offset="0.80369514"
+         id="stop23918" />
+      <stop
+         style="stop-color:#87837d;stop-opacity:1;"
+         offset="1"
+         id="stop6729" />
+    </linearGradient>
+    <linearGradient
+       xlink:href="#b"
+       id="linearGradient23922"
+       gradientUnits="userSpaceOnUse"
+       x1="214.29761"
+       y1="742.36987"
+       x2="709.07269"
+       y2="-78.421982" />
+    <linearGradient
+       xlink:href="#linearGradient6731"
+       id="linearGradient13982"
+       x1="284.41074"
+       y1="647.30627"
+       x2="722.42993"
+       y2="-25.09388"
+       gradientUnits="userSpaceOnUse" />
+    <linearGradient
+       id="linearGradient6731">
+      <stop
+         style="stop-color:#644d40;stop-opacity:1;"
+         offset="0"
+         id="stop14834" />
+      <stop
+         style="stop-color:#492e1e;stop-opacity:1;"
+         offset="0.34180138"
+         id="stop14836" />
+      <stop
+         style="stop-color:#2d0e00;stop-opacity:1;"
+         offset="0.44341803"
+         id="stop14838" />
+      <stop
+         style="stop-color:#2d0e00;stop-opacity:1;"
+         offset="0.57999998"
+         id="stop14840" />
+      <stop
+         style="stop-color:#7d6456;stop-opacity:1;"
+         offset="0.68000001"
+         id="stop14842" />
+      <stop
+         style="stop-color:#d2c3ba;stop-opacity:1;"
+         offset="1"
+         id="stop14844" />
+    </linearGradient>
+    <linearGradient
+       xlink:href="#linearGradient942"
+       id="linearGradient944"
+       x1="827.46008"
+       y1="110.79597"
+       x2="827.46008"
+       y2="208.54196"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-805.23573,44.793022)" />
+    <linearGradient
+       id="linearGradient942">
+      <stop
+         style="stop-color:#f8c52d;stop-opacity:1;"
+         offset="0"
+         id="stop938" />
+      <stop
+         style="stop-color:#8b6d05;stop-opacity:1;"
+         offset="1"
+         id="stop940" />
+    </linearGradient>
+    <filter
+       style="color-interpolation-filters:sRGB"
+       id="filter6247"
+       x="-0.27160581"
+       y="-0.20290551"
+       width="1.5432116"
+       height="1.405811">
+      <feFlood
+         flood-opacity="0.741176"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood6237" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite6239" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="5"
+         result="blur"
+         id="feGaussianBlur6241" />
+      <feOffset
+         dx="0"
+         dy="0"
+         result="offset"
+         id="feOffset6243" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite6245" />
+    </filter>
+    <linearGradient
+       xlink:href="#linearGradient942"
+       id="linearGradient4820"
+       x1="931.25116"
+       y1="108.46269"
+       x2="931.25116"
+       y2="208.13298"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-805.23573,44.793022)" />
+    <filter
+       style="color-interpolation-filters:sRGB"
+       id="filter6259"
+       x="-0.22545054"
+       y="-0.20290551"
+       width="1.4509011"
+       height="1.405811">
+      <feFlood
+         flood-opacity="0.741176"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood6249" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite6251" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="5"
+         result="blur"
+         id="feGaussianBlur6253" />
+      <feOffset
+         dx="0"
+         dy="0"
+         result="offset"
+         id="feOffset6255" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite6257" />
+    </filter>
+    <linearGradient
+       xlink:href="#linearGradient942"
+       id="linearGradient4816"
+       x1="1047.7046"
+       y1="112.43189"
+       x2="1047.7046"
+       y2="207.724"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-805.23573,44.793022)" />
+    <filter
+       style="color-interpolation-filters:sRGB"
+       id="filter6271"
+       x="-0.17643958"
+       y="-0.20290551"
+       width="1.3528792"
+       height="1.405811">
+      <feFlood
+         flood-opacity="0.741176"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood6261" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite6263" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="5"
+         result="blur"
+         id="feGaussianBlur6265" />
+      <feOffset
+         dx="0"
+         dy="0"
+         result="offset"
+         id="feOffset6267" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite6269" />
+    </filter>
+    <linearGradient
+       xlink:href="#linearGradient942"
+       id="linearGradient4818"
+       x1="1192.9985"
+       y1="110.38699"
+       x2="1192.9985"
+       y2="208.13298"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="translate(-805.23573,44.793022)" />
+    <filter
+       style="color-interpolation-filters:sRGB"
+       id="filter6283"
+       x="-0.90773429"
+       y="-0.20290551"
+       width="2.8154686"
+       height="1.405811">
+      <feFlood
+         flood-opacity="0.741176"
+         flood-color="rgb(0,0,0)"
+         result="flood"
+         id="feFlood6273" />
+      <feComposite
+         in="flood"
+         in2="SourceGraphic"
+         operator="in"
+         result="composite1"
+         id="feComposite6275" />
+      <feGaussianBlur
+         in="composite1"
+         stdDeviation="5"
+         result="blur"
+         id="feGaussianBlur6277" />
+      <feOffset
+         dx="0"
+         dy="0"
+         result="offset"
+         id="feOffset6279" />
+      <feComposite
+         in="SourceGraphic"
+         in2="offset"
+         operator="over"
+         result="composite2"
+         id="feComposite6281" />
+    </filter>
+    <linearGradient
+       xlink:href="#linearGradient6731"
+       id="linearGradient8804"
+       gradientUnits="userSpaceOnUse"
+       x1="284.41074"
+       y1="647.30627"
+       x2="722.42993"
+       y2="-25.09388" />
+  </defs>
+  <g
+     id="g959">
+    <g
+       id="g1382"
+       transform="matrix(1.3884149,0,0,1.3884149,42.02983,5.902602)"
+       style="filter:url(#filter5509)">
+      <g
+         style="fill:url(#linearGradient6733);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:8.50394;stroke-dasharray:none;stroke-opacity:0.603133;paint-order:stroke fill markers"
+         id="g1233"
+         transform="matrix(0.35277778,0,0,0.35277778,-47.966154,35.473965)">
+        <path
+           style="fill:url(#linearGradient23922);fill-opacity:1;stroke:#000000;stroke-width:8.50394;stroke-dasharray:none;stroke-opacity:0.603133;paint-order:stroke fill markers"
+           d="m 170.868,-74.3394 c 0,0 167.34,37.2314 333.221,37.2314 174.565,0 348.114,-37.2314 348.114,-37.2314 32.9,0 44.678,8.0547 44.678,40.9545 0,0 -111.694,785.5839 -390.93,785.5839 -279.236,0 -379.761,-785.5839 -379.761,-785.5839 0,-32.8998 11.778,-40.9545 44.678,-40.9545 z"
+           id="path1221" />
+      </g>
+      <g
+         style="fill:url(#linearGradient13982);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:8.50394;stroke-dasharray:none;stroke-opacity:0.349869;paint-order:stroke fill markers"
+         id="g194"
+         transform="matrix(0.35277778,0,0,0.35277778,-47.966154,35.474023)">
+        <path
+           style="fill:url(#linearGradient8804);fill-opacity:1;stroke:#000000;stroke-width:8.50394;stroke-dasharray:none;stroke-opacity:0.349869;paint-order:stroke fill markers"
+           d="m 239.001,8.31427 c 0,0 133.873,29.78523 266.578,29.78523 139.652,0 278.491,-29.78523 278.491,-29.78523 26.32,0 35.742,6.44393 35.742,32.76363 0,0 -89.356,628.4671 -312.744,628.4671 -223.389,0 -303.809,-628.4671 -303.809,-628.4671 0,-26.3197 9.423,-32.76363 35.742,-32.76363 z"
+           id="path182" />
+      </g>
+    </g>
+    <g
+       id="g947">
+      <path
+         style="fill:url(#linearGradient944);fill-opacity:1;stroke:#282828;stroke-width:15.90145826;stroke-linecap:square;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter6247);paint-order:stroke fill markers"
+         d="m 22.35664,154.68591 h 21.40019 v 26.89484 h 12.72445 v 39.33009 h 5.20546 v -39.33009 h 13.3028 v -26.89484 h 20.82182 v 31.8111 H 83.08693 v 40.19766 h -13.8812 v 26.31646 H 48.0947 V 226.69467 H 35.37028 V 186.49701 H 22.35664 Z"
+         id="path104" />
+      <path
+         style="fill:url(#linearGradient4820);fill-opacity:1;stroke:#282828;stroke-width:15.90145826;stroke-linecap:square;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter6259);paint-order:stroke fill markers"
+         d="m 125.01976,168.56711 h 14.4596 v -13.8812 h 60.44111 v 13.8812 h 13.592 v 17.9299 h -21.11101 v -13.30283 h -45.1139 v 61.16408 h 45.1139 v -13.44742 h 21.11101 v 18.50827 h -13.592 v 13.59202 h -60.44111 v -13.59202 h -14.4596 v -70.852 0"
+         id="path1189" />
+      <path
+         style="fill:url(#linearGradient4816);fill-opacity:1;stroke:#282828;stroke-width:15.90145826;stroke-linecap:square;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter6271);paint-order:stroke fill markers"
+         d="m 243.01007,154.68591 h 34.4138 v 26.89484 h 12.7244 v 27.18403 h 18.5083 v -27.18403 h 13.4474 v -26.89484 h 33.9801 v 98.32522 h -19.9543 v -66.51412 h -6.3622 v 27.18403 h -13.0136 v 25.73807 h -34.1247 v -25.73807 h -13.3028 v -27.18403 h -6.073 v 66.51412 h -20.2434 v -98.32522"
+         id="path1228" />
+      <path
+         style="fill:url(#linearGradient4818);fill-opacity:1;stroke:#282828;stroke-width:15.90145826;stroke-linecap:square;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter6283);paint-order:stroke fill markers"
+         d="m 387.89507,154.68591 h 21.9786 v 98.32522 h -21.9786 z"
+         id="path1263" />
+    </g>
+  </g>
+</svg>

+ 234 - 222
client/icons/vcmiclient.xpm

@@ -1,226 +1,238 @@
 /* XPM */
-static char *vcmiclient[] = {
+static char *x[] = {
 /* columns rows colors chars-per-pixel */
-"32 32 188 2 ",
-"   c #010101",
-".  c #090909",
-"X  c #140600",
-"o  c #180700",
-"O  c #140A06",
-"+  c #1B0901",
-"@  c #1E120C",
-"#  c #161414",
-"$  c #1C1C1B",
-"%  c #220B01",
-"&  c #2B0E00",
-"*  c #2E1002",
-"=  c #2C140A",
-"-  c #331507",
-";  c #341609",
-":  c #35180B",
-">  c #221612",
-",  c #221915",
-"<  c #2C1C15",
-"1  c #281F1A",
-"2  c #351C10",
-"3  c #391E11",
-"4  c #3D2214",
-"5  c #3C2519",
-"6  c #252424",
-"7  c #2D2D2C",
-"8  c #3B2B24",
-"9  c #3C302B",
-"0  c #343333",
-"q  c #3F3036",
-"w  c #393837",
-"e  c #3D3C3B",
-"r  c #402215",
-"t  c #422618",
-"y  c #442B1E",
-"u  c #482D1F",
-"i  c #452D21",
-"p  c #4A2F21",
-"a  c #4D3325",
-"s  c #4E372C",
-"d  c #503729",
-"f  c #52392C",
-"g  c #423433",
-"h  c #483C35",
-"j  c #443438",
-"k  c #443B3E",
-"l  c #533E32",
-"z  c #41403F",
-"x  c #4B433E",
-"c  c #514037",
-"v  c #5D4236",
-"b  c #53433B",
-"n  c #5E4438",
-"m  c #634F3F",
-"M  c #695337",
-"N  c #67523F",
-"B  c #6A543D",
-"V  c #6C583B",
-"C  c #795F36",
-"Z  c #725A3E",
-"A  c #795F3E",
-"S  c #413741",
-"D  c #473C46",
-"F  c #444242",
-"G  c #4A4845",
-"H  c #4C4B4B",
-"J  c #5A4D46",
-"K  c #54524F",
-"L  c #5B504C",
-"P  c #555454",
-"I  c #5A5956",
-"U  c #5B5B5B",
-"Y  c #645143",
-"T  c #6B5544",
-"R  c #6F5A45",
-"E  c #65544C",
-"W  c #6D564B",
-"Q  c #6A594F",
-"!  c #735D46",
-"~  c #6B5655",
-"^  c #6D5A53",
-"/  c #655D58",
-"(  c #6C595B",
-")  c #755E56",
-"_  c #735F59",
-"`  c #796143",
-"'  c #75624E",
-"]  c #7B624C",
-"[  c #67625D",
-"{  c #7B6356",
-"}  c #71645E",
-"|  c #7B665A",
-" . c #7E695E",
-".. c #715E60",
-"X. c #656362",
-"o. c #6A6762",
-"O. c #6D6A66",
-"+. c #6A6168",
-"@. c #6D6B6B",
-"#. c #726C67",
-"$. c #726E6A",
-"%. c #76726F",
-"&. c #79726D",
-"*. c #716F70",
-"=. c #747473",
-"-. c #7B7671",
-";. c #7D7976",
-":. c #7E7D7B",
-">. c #80673C",
-",. c #8D713F",
-"<. c #9F7E37",
-"1. c #816843",
-"2. c #886D41",
-"3. c #927745",
-"4. c #826B5E",
-"5. c #836E62",
-"6. c #877166",
-"7. c #887266",
-"8. c #8B756A",
-"9. c #8F796E",
-"0. c #907A6F",
-"q. c #857A73",
-"w. c #827E79",
-"e. c #927D73",
-"r. c #A38234",
-"t. c #A58439",
-"y. c #AF8B3E",
-"u. c #B08E39",
-"i. c #BD9738",
-"p. c #E3B101",
-"a. c #CAA021",
-"s. c #CEA43F",
-"d. c #E4B437",
-"f. c #E4B53E",
-"g. c #F4C23D",
-"h. c #A28343",
-"j. c #A88741",
-"k. c #B39040",
-"l. c #BF9940",
-"z. c #86837E",
-"x. c #948177",
-"c. c #94867E",
-"v. c #99847A",
-"b. c #9D897E",
-"n. c #BE9C6E",
-"m. c #D3AB6D",
-"M. c #E3B76C",
-"N. c #F0C26B",
-"B. c #F0C273",
-"V. c #858482",
-"C. c #888682",
-"Z. c #8C8985",
-"A. c #8E8D8D",
-"S. c #928C86",
-"D. c #918F8C",
-"F. c #95918D",
-"G. c #959492",
-"H. c #9A9792",
-"J. c #9B9995",
-"K. c #9E9B99",
-"L. c #A18D82",
-"P. c #A39086",
-"I. c #A6948A",
-"U. c #A9968C",
-"Y. c #AB988E",
-"T. c #AF9C92",
-"R. c #A19E9A",
-"E. c #A4A29E",
-"W. c #B4A298",
-"Q. c #A5A4A1",
-"!. c #A9A7A3",
-"~. c #ACA9A6",
-"^. c #ADACAB",
-"/. c #B1AEAB",
-"(. c #B2B0AD",
-"). c #B5B4B2",
-"_. c #BAB9B7",
-"`. c #BDBCBB",
-"'. c #C4C3C3",
-"]. c #C8C8C8",
-"[. c #D1D0CE",
-"{. c #D4D3D3",
-"}. c #DADADA",
-"|. c #E8E7E6",
-" X c #EBEBEA",
-".X c gray96",
-"XX c #FDFDFC",
-"oX c None",
+"32 32 200 2 ",
+"   c gray11",
+".  c #161616",
+"X  c #2C0E00",
+"o  c #2D1003",
+"O  c #25140C",
+"+  c #28130A",
+"@  c #311305",
+"#  c #331609",
+"$  c #34190C",
+"%  c #391C0D",
+"&  c #241610",
+"*  c #241A16",
+"=  c #251E1A",
+"-  c #2C1C14",
+";  c #391E11",
+":  c #2A241D",
+">  c #20201F",
+",  c #3D2112",
+"<  c #38231B",
+"1  c #3C351E",
+"2  c #242323",
+"3  c #2C2B2B",
+"4  c #282625",
+"5  c #332E20",
+"6  c #362D29",
+"7  c #302620",
+"8  c #363122",
+"9  c #3C3521",
+"0  c #3E352C",
+"q  c #36302D",
+"w  c #353433",
+"e  c #3D3B3B",
+"r  c #3B3431",
+"t  c #412516",
+"y  c #462A1B",
+"u  c #492E1E",
+"i  c #45271B",
+"p  c #443A1B",
+"a  c #4A3F1C",
+"s  c #4A2F20",
+"d  c #4D3323",
+"f  c #423B24",
+"g  c #48372E",
+"h  c #483F25",
+"j  c #503627",
+"k  c #513728",
+"l  c #543B2C",
+"z  c #593D2F",
+"x  c #483D37",
+"c  c #473C37",
+"v  c #573E30",
+"b  c #583F31",
+"n  c #5A4C1D",
+"m  c #63531C",
+"M  c #6F5C18",
+"N  c #725D13",
+"B  c #7D6515",
+"V  c #4E4426",
+"C  c #514623",
+"Z  c #44423F",
+"A  c #5C4234",
+"S  c #5A4438",
+"D  c #625220",
+"F  c #6C5A24",
+"G  c #6B5A29",
+"H  c #715E26",
+"J  c #674D3F",
+"K  c #604537",
+"L  c #7A6525",
+"P  c #746129",
+"I  c #444242",
+"U  c #494645",
+"Y  c #4C4B4A",
+"T  c #4A4845",
+"R  c #554A46",
+"E  c #5B4D45",
+"W  c #514742",
+"Q  c #555352",
+"!  c #595757",
+"~  c #5D5B5A",
+"^  c #694E40",
+"/  c #6B5549",
+"(  c #775D4F",
+")  c #705648",
+"_  c #6B5F58",
+"`  c #755E52",
+"'  c #62605E",
+"]  c #7E6557",
+"[  c #7A665A",
+"{  c #666564",
+"}  c #696766",
+"|  c #6D6B6A",
+" . c #6A6865",
+".. c #7B6B62",
+"X. c #726D69",
+"o. c #7A7674",
+"O. c #7D7B7B",
+"+. c #767471",
+"@. c #95750A",
+"#. c #98770A",
+"$. c #846B1B",
+"%. c #876D17",
+"&. c #8E731E",
+"*. c #93761D",
+"=. c #96781C",
+"-. c #9B7B10",
+";. c #A07F0F",
+":. c #A07D10",
+">. c #836C22",
+",. c #866F29",
+"<. c #8C7324",
+"1. c #997D22",
+"2. c #967A28",
+"3. c #826A5D",
+"4. c #80675A",
+"5. c #856D60",
+"6. c #897164",
+"7. c #8C7569",
+"8. c #8F786C",
+"9. c #927C6F",
+"0. c #827D79",
+"q. c #937E72",
+"w. c #A7840F",
+"e. c #AE8A16",
+"r. c #A5831A",
+"t. c #B08C1C",
+"y. c #B79015",
+"u. c #BD961A",
+"i. c #A88825",
+"p. c #B08E23",
+"a. c #BB9624",
+"s. c #BB9626",
+"d. c #C69D1B",
+"f. c #C29B22",
+"g. c #C29C2A",
+"h. c #CCA220",
+"j. c #CDA42A",
+"k. c #D9AD26",
+"l. c #D2A726",
+"z. c #E6B726",
+"x. c #86827D",
+"c. c #8A847F",
+"v. c #978175",
+"b. c #94867D",
+"n. c #9B867A",
+"m. c #9E897D",
+"M. c #998377",
+"N. c #848383",
+"B. c #8A8680",
+"V. c #8F8B86",
+"C. c #9B8D85",
+"Z. c #938E89",
+"A. c #918984",
+"S. c #96928E",
+"D. c #9A9693",
+"F. c #9C9996",
+"G. c #9D9B99",
+"H. c #939292",
+"J. c #A28E82",
+"K. c #A69287",
+"L. c #A5948A",
+"P. c #AC988D",
+"I. c #A9958A",
+"U. c #A69C96",
+"Y. c #AD9C93",
+"T. c #A29D99",
+"R. c #A89F99",
+"E. c #B19E93",
+"W. c #A5A29F",
+"Q. c #B3A196",
+"!. c #B8A69C",
+"~. c #B9A69C",
+"^. c #A4A3A2",
+"/. c #A9A6A3",
+"(. c #ADABA9",
+"). c #ABA8A5",
+"_. c #BCABA1",
+"`. c #B2AEAC",
+"'. c #B5A9A3",
+"]. c #B3B2AF",
+"[. c #B3B2B2",
+"{. c #B9B5B3",
+"}. c #BAB9B9",
+"|. c #BBB9B6",
+" X c #C0AFA5",
+".X c #C4B3AA",
+"XX c #C8B8AE",
+"oX c #C1BFBE",
+"OX c #CDBDB4",
+"+X c #CCC9C7",
+"@X c #CFCCCB",
+"#X c #C5C3C1",
+"$X c #D3D1CF",
+"%X c #D6D3D2",
+"&X c #DDDBDA",
+"*X c #EDECEB",
+"=X c #E4E3E3",
+"-X c #F3F3F3",
+";X c #F9F9F9",
+":X c None",
 /* pixels */
-"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoX0 I 0 oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXw H oXoXoXoX",
-"oXoXoXoX'.'.'.`.Q.D.:.+.P F F 6 6 w e H I @.:.Z.K.E.R.H.$.oXoXoX",
-"oXoXoXoX).).`.`.`._.)./.(.(.(.(.(./.~.!.E.R.H.G.D.Z.S.C.o.oXoXoX",
-"oXoXoXoXV.A.G.*.Z.K.^.).).^.~.Q.Q.E.K.K.J.F.C.-.$.$.S.S.K oXoXoX",
-"[email protected] & : f E } #.&.q.&.-.&.&.&.&.q.c.I.W.S.z.G.w oXoXoX",
-"oXoXoXoXH X.H = & * r n { 5.7.8.0.x.v.b.L.P.I.Y.T.q.G.H.$ oXoXoX",
-"oXoXoXoX7 X.H = * & & : a W 5.6.7.9.x.x.x.L.L.I.U.q.R.F.oXoXoXoX",
-"oXoXoXoXoXX.F , * & & & * 3 l { 5.6.8.0.x.x.b.L.P.-.Q.;.oXoXoXoX",
-"oXoXoXoXoXI e 1 & & & & & & ; p T |  .5.8.0.0.x.x.V.Q.U oXoXoXoX",
-"oXoXoXoX  F 0 # o & % o o o o & 3 8 g h ^ 5.J b x C.G.$ oXoXoXoX",
-"oXoXoXB.4.7 6 B.{ % X N.g.g.] o % { g.B.g Q 4.g.B.U U B.4.oXoXoX",
-"oXoXoXf.>.. $ d.` + M.y.A C f.) % A p.d.> 9 1.p.f.e e f.1.oXoXoX",
-"oXoXoX| s._ m.h.k @ s.Z + o ) g + Z a.<.m._ s.t.s.7 6 s.] oXoXoX",
-"oXoXoX  i.V i.' k > l.B = % o o % B l.B i.M l.R l.6 . i.! oXoXoX",
-"oXoXoXoX_ u.3.+.C.1 k.B @ O n.^ % N y.g ,.u.Q N y.$   k.! oXoXoX",
-"oXoXoXoX  j.Y '.}.F ^ j.j.t.2.j % Y j.o m j.X J j..   j.W oXoXoX",
-"oXoXoXoXoX..S Q..XK.< ( Y Y k 5 2 j ~ o q ~ O S (   oX..D oXoXoX",
-"oXoXoXoXoXoXoXK |.{.b i i y y i y 5 : * & & , 7 6 oXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoX_.[.&.a d a a a p p y 4 - - F e $ oXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoX@.(.H.c f d d a a p p u t L G.*.oXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXE.E./ f f d d a a a a c ].}.*.oXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXo.G.C.b f f f s d a s R.XX XoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXZ.Z.#.c f f f d f $.{. X=.oXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXe z.w.O.c l f l [ E.).K.oXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXP -.&.&.o.o.;.G.J.D.oXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXK $.$.%.-.z.z.w.$ oXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXoX7 I o.O.$.G oXoXoXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX# oXoXoXoXoXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX",
-"oXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoXoX"
+":X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X",
+":X:X:XO.V.| Q :X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:XZ Q ' T :X:X",
+":X:XI G.(.}.}.}.(.^.H.N.O.| } ~ ! ' { { } X.o.0.B.x.x.x.x.x.:X:X",
+":X:X3 N.H.^.[.}.}.}.}.}.}.}.}.[.`.(./.^.T.T.D.S.Z.V.B.x.x.o.:X:X",
+":X:X:X| O. .^ ..b.D./.[.{.}.}.}.{.[.`.(.^.F.S.D.W.'.'.c.c.' :X:X",
+":X:X:X! { c % s b ^ ( 5.7.q.b.C.C.L.L.I.Y.E.~. X XXXOXZ.V.~ :X:X",
+":X:X:XU ~ c X @ t j K ) [ 3.6.7.q.b.n.J.L.P.E.E.~. XXXZ.D.Y :X:X",
+":X:X:Xw Q Z X X X % y v ^ ( ] 5.6.8.q.M.C.J.I.E.Q.~.~.F.F.:X:X:X",
+":X:X:X4 Y U X X X X @ t d A ) ] 3.6.7.9.q.n.J.K.P.E.W.W.D.:X:X:X",
+":X:X:X:XI U @ X X X X X % i z ^ ( 4.3.6.8.q.M.n.m.I.U.(.x.:X:X:X",
+":X    . w 3 * + X + O & & & - d K g x Z ^ 7...U E R N.N.e   :X:X",
+":XG j.9 2 ,.s.* + = s.j.j.j.P * i F j.j.0 [ R i.l.i.' Y g.2.:X:X",
+":XH z.f 2 2.k.* * p.f.,.,.2.l.G X L z.z.8 x q p.z.s.{ Y k.i.:X:X",
+":Xh i.f.>.d.L : = h.1.O X : L V X H k.p.a.4 <.f.a.p.{ e h.1.:X:X",
+":X:XF d.<.d.w k = d.&.+ X X X X o F d.B d.2 <.t.<.r.{ w u.*.:X:X",
+":X:XF y.$.y.I ' : e.$.- # & = * X D y.V =.e.e.D %.=.{ 2 e.$.:X:X",
+":X:X9 %.w.n Q G.: -.B : : 1 w.n X n w.: M w.-.2 B %.Y > -.B :X:X",
+":X:X:Xm #.  -X-X6 a @.@.@.#.M 5 o n @.: 1 a a = N B w   @.N :X:X",
+":X:X:X8 a   #X;XC.7 p p p p 8 , # 8 p * X X X + 1 p     p 9 :X:X",
+":X:X:X:X:X:XO.*X@Xk d h u u u y t % # o X X X < Q Y :X:X:X:X:X:X",
+":X:X:X:X:X:X:X&X*X[ d j j d s u u t , % @ o X r Y 3 :X:X:X:X:X:X",
+":X:X:X:X:X:X:XF.&XW.z k k j j s d u y , , # - c I :X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X$X%X/ z l k k d d d u u t , 6 w 3 :X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:[email protected] l l l k d d d d u S  .Y :X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:XI |.#X..A z l l k j j d v F.F.! :X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:XO.{.]./ A z l z l j z {.=X}.:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:XF.].).` A A z l S `.-X;XO.:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:Xe G.).].V.....b.$X=X*X^.:X:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:X:XT D.W.(.{.}.+X%X&X/.:X:X:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:X:X:Xe x.T./.].|.}.O.:X:X:X:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:X:X:X:X:XY | o. .:X:X:X:X:X:X:X:X:X:X:X:X:X:X",
+":X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X:X"
 };

BIN
client/ios/vcmi_logo.png


BIN
client/vcmi.ico


+ 6 - 6
client/widgets/Buttons.cpp

@@ -57,15 +57,15 @@ void CButton::update()
 		redraw();
 }
 
-void CButton::setBorderColor(boost::optional<SDL_Color> borderColor)
+void CButton::setBorderColor(std::optional<SDL_Color> borderColor)
 {
 	setBorderColor(borderColor, borderColor, borderColor, borderColor);
 }
 
-void CButton::setBorderColor(boost::optional<SDL_Color> normalBorderColor,
-                             boost::optional<SDL_Color> pressedBorderColor,
-                             boost::optional<SDL_Color> blockedBorderColor,
-                             boost::optional<SDL_Color> highlightedBorderColor)
+void CButton::setBorderColor(std::optional<SDL_Color> normalBorderColor,
+							 std::optional<SDL_Color> pressedBorderColor,
+							 std::optional<SDL_Color> blockedBorderColor,
+							 std::optional<SDL_Color> highlightedBorderColor)
 {
 	stateToBorderColor[NORMAL] = normalBorderColor;
 	stateToBorderColor[PRESSED] = pressedBorderColor;
@@ -591,7 +591,7 @@ void CSlider::setScrollBounds(const Rect & bounds )
 
 void CSlider::clearScrollBounds()
 {
-	scrollBounds = boost::none;
+	scrollBounds = std::nullopt;
 }
 
 int CSlider::getAmount() const

+ 7 - 7
client/widgets/Buttons.h

@@ -52,7 +52,7 @@ private:
 
 	std::array<int, 4> stateToIndex; // mapping of button state to index of frame in animation
 	std::array<std::string, 4> hoverTexts; //texts for statusbar, if empty - first entry will be used
-	std::array<boost::optional<SDL_Color>, 4> stateToBorderColor; // mapping of button state to border color
+	std::array<std::optional<SDL_Color>, 4> stateToBorderColor; // mapping of button state to border color
 	std::string helpBox; //for right-click help
 
 	std::shared_ptr<CAnimImage> image; //image for this button
@@ -73,13 +73,13 @@ public:
 
 	// sets border color for each button state;
 	// if it's set, the button will have 1-px border around it with this color
-	void setBorderColor(boost::optional<SDL_Color> normalBorderColor,
-	                    boost::optional<SDL_Color> pressedBorderColor,
-	                    boost::optional<SDL_Color> blockedBorderColor,
-	                    boost::optional<SDL_Color> highlightedBorderColor);
+	void setBorderColor(std::optional<SDL_Color> normalBorderColor,
+						std::optional<SDL_Color> pressedBorderColor,
+						std::optional<SDL_Color> blockedBorderColor,
+						std::optional<SDL_Color> highlightedBorderColor);
 
 	// sets the same border color for all button states.
-	void setBorderColor(boost::optional<SDL_Color> borderColor);
+	void setBorderColor(std::optional<SDL_Color> borderColor);
 
 	/// adds one more callback to on-click actions
 	void addCallback(std::function<void()> callback);
@@ -229,7 +229,7 @@ class CSlider : public CIntObject
 	std::shared_ptr<CButton> right;
 	std::shared_ptr<CButton> slider;
 
-	boost::optional<Rect> scrollBounds;
+	std::optional<Rect> scrollBounds;
 
 	int capacity;//how many elements can be active at same time (e.g. hero list = 5)
 	int positions; //number of highest position (0 if there is only one)

+ 1 - 1
client/widgets/Images.cpp

@@ -85,7 +85,7 @@ void CPicture::show(SDL_Surface * to)
 void CPicture::showAll(SDL_Surface * to)
 {
 	if(bg && visible)
-		bg->draw(to, pos.x, pos.y, srcRect.get_ptr());
+		bg->draw(to, pos.x, pos.y, srcRect.has_value() ? &srcRect.value() : nullptr);
 }
 
 void CPicture::setAlpha(int value)

+ 1 - 1
client/widgets/Images.h

@@ -30,7 +30,7 @@ class CPicture : public CIntObject
 
 public:
 	/// if set, only specified section of internal image will be rendered
-	boost::optional<Rect> srcRect;
+	std::optional<Rect> srcRect;
 
 	/// If set to true, iamge will be redrawn on each frame
 	bool needRefresh;

+ 11 - 11
client/windows/CCreatureWindow.cpp

@@ -64,9 +64,9 @@ public:
 	const CGHeroInstance * owner;
 
 	// temporary objects which should be kept as copy if needed
-	boost::optional<CommanderLevelInfo> levelupInfo;
-	boost::optional<StackDismissInfo> dismissInfo;
-	boost::optional<StackUpgradeInfo> upgradeInfo;
+	std::optional<CommanderLevelInfo> levelupInfo;
+	std::optional<StackDismissInfo> dismissInfo;
+	std::optional<StackUpgradeInfo> upgradeInfo;
 
 	// misc fields
 	unsigned int creatureCount;
@@ -246,8 +246,8 @@ CStackWindow::BonusLineSection::BonusLineSection(CStackWindow * owner, size_t li
 	}
 }
 
-CStackWindow::BonusesSection::BonusesSection(CStackWindow * owner, int yOffset, boost::optional<size_t> preferredSize)
-	: CWindowSection(owner, "", yOffset)
+CStackWindow::BonusesSection::BonusesSection(CStackWindow * owner, int yOffset, std::optional<size_t> preferredSize):
+	CWindowSection(owner, "", yOffset)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
 
@@ -255,7 +255,7 @@ CStackWindow::BonusesSection::BonusesSection(CStackWindow * owner, int yOffset,
 	static const int itemHeight = 59;
 
 	size_t totalSize = (owner->activeBonuses.size() + 1) / 2;
-	size_t visibleSize = preferredSize ? preferredSize.get() : std::min<size_t>(3, totalSize);
+	size_t visibleSize = preferredSize.value_or(std::min<size_t>(3, totalSize));
 
 	pos.w = owner->pos.w;
 	pos.h = itemHeight * (int)visibleSize;
@@ -292,7 +292,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 		// used space overlaps with commander switch button
 		// besides - should commander really be upgradeable?
 
-		UnitView::StackUpgradeInfo & upgradeInfo = parent->info->upgradeInfo.get();
+		auto & upgradeInfo = parent->info->upgradeInfo.value();
 		const size_t buttonsToCreate = std::min<size_t>(upgradeInfo.info.newID.size(), upgrade.size());
 
 		for(size_t buttonIndex = 0; buttonIndex < buttonsToCreate; buttonIndex++)
@@ -686,8 +686,8 @@ CStackWindow::CStackWindow(const CStackInstance * stack, std::function<void()> d
 	info->creature = stack->type;
 	info->creatureCount = stack->count;
 
-	info->upgradeInfo = boost::make_optional(UnitView::StackUpgradeInfo());
-	info->dismissInfo = boost::make_optional(UnitView::StackDismissInfo());
+	info->upgradeInfo = std::make_optional(UnitView::StackUpgradeInfo());
+	info->dismissInfo = std::make_optional(UnitView::StackDismissInfo());
 	info->upgradeInfo->info = upgradeInfo;
 	info->upgradeInfo->callback = callback;
 	info->dismissInfo->callback = dismiss;
@@ -716,7 +716,7 @@ CStackWindow::CStackWindow(const CCommanderInstance * commander, std::vector<ui3
 	info->creature = commander->type;
 	info->commander = commander;
 	info->creatureCount = 1;
-	info->levelupInfo = boost::make_optional(UnitView::CommanderLevelInfo());
+	info->levelupInfo = std::make_optional(UnitView::CommanderLevelInfo());
 	info->levelupInfo->skills = skills;
 	info->levelupInfo->callback = callback;
 	info->owner = dynamic_cast<const CGHeroInstance *> (commander->armyObj);
@@ -814,7 +814,7 @@ void CStackWindow::initSections()
 
 		commanderMainSection = std::make_shared<CommanderMainSection>(this, 0);
 
-		auto size = boost::make_optional<size_t>((info->levelupInfo) ? 4 : 3);
+		auto size = std::make_optional<size_t>((info->levelupInfo) ? 4 : 3);
 		commanderBonusesSection = std::make_shared<BonusesSection>(this, 0, size);
 		deactivateObj(commanderBonusesSection);
 

+ 1 - 1
client/windows/CCreatureWindow.h

@@ -83,7 +83,7 @@ class CStackWindow : public CWindowObject
 	{
 		std::shared_ptr<CListBox> lines;
 	public:
-		BonusesSection(CStackWindow * owner, int yOffset, boost::optional<size_t> preferredSize = boost::optional<size_t>());
+		BonusesSection(CStackWindow * owner, int yOffset, std::optional<size_t> preferredSize = std::optional<size_t>());
 	};
 
 	class ButtonsSection : public CWindowSection

+ 19 - 23
lib/CArtHandler.cpp

@@ -740,15 +740,28 @@ void CArtHandler::erasePickedArt(const ArtifactID & id)
 {
 	CArtifact *art = objects[id];
 
-	if(auto artifactList = listFromClass(art->aClass))
+	if(!(art->aClass & CArtifact::ART_SPECIAL))
 	{
-		if(artifactList->empty())
-			fillList(*artifactList, art->aClass);
+		auto & artifactList = treasures;
+		switch(art->aClass)
+		{
+			case CArtifact::ART_MINOR:
+				artifactList = minors;
+				break;
+			case CArtifact::ART_MAJOR:
+				artifactList = majors;
+				break;
+			case CArtifact::ART_RELIC:
+				artifactList = relics;
+				break;
+		}
+		if(artifactList.empty())
+			fillList(artifactList, art->aClass);
 
-		auto itr = vstd::find(*artifactList, art);
-		if(itr != artifactList->end())
+		auto itr = vstd::find(artifactList, art);
+		if(itr != artifactList.end())
 		{
-			artifactList->erase(itr);
+			artifactList.erase(itr);
 		}
 		else
 			logMod->warn("Problem: cannot erase artifact %s from list, it was not present", art->getNameTranslated());
@@ -758,23 +771,6 @@ void CArtHandler::erasePickedArt(const ArtifactID & id)
 		logMod->warn("Problem: cannot find list for artifact %s, strange class. (special?)", art->getNameTranslated());
 }
 
-boost::optional<std::vector<CArtifact*>&> CArtHandler::listFromClass( CArtifact::EartClass artifactClass )
-{
-	switch(artifactClass)
-	{
-	case CArtifact::ART_TREASURE:
-		return treasures;
-	case CArtifact::ART_MINOR:
-		return minors;
-	case CArtifact::ART_MAJOR:
-		return majors;
-	case CArtifact::ART_RELIC:
-		return relics;
-	default: //special artifacts should not be erased
-		return boost::optional<std::vector<CArtifact*>&>();
-	}
-}
-
 void CArtHandler::fillList( std::vector<CArtifact*> &listToBeFilled, CArtifact::EartClass artifactClass )
 {
 	assert(listToBeFilled.empty());

+ 0 - 2
lib/CArtHandler.h

@@ -244,8 +244,6 @@ public:
 
 	void fillList(std::vector<CArtifact*> &listToBeFilled, CArtifact::EartClass artifactClass); //fills given empty list with allowed artifacts of given class. No side effects
 
-	boost::optional<std::vector<CArtifact*>&> listFromClass(CArtifact::EartClass artifactClass);
-
 	static CArtifact::EartClass stringToClass(const std::string & className); //TODO: rework EartClass to make this a constructor
 
 	/// Gets a artifact ID randomly and removes the selected artifact from this handler.

+ 1 - 1
lib/CCreatureHandler.cpp

@@ -408,7 +408,7 @@ CCreatureHandler::CCreatureHandler()
 
 const CCreature * CCreatureHandler::getCreature(const std::string & scope, const std::string & identifier) const
 {
-	boost::optional<si32> index = VLC->modh->identifiers.getIdentifier(scope, "creature", identifier);
+	std::optional<si32> index = VLC->modh->identifiers.getIdentifier(scope, "creature", identifier);
 
 	if(!index)
 		throw std::runtime_error("Creature not found "+identifier);

+ 2 - 2
lib/CCreatureSet.cpp

@@ -624,7 +624,7 @@ void CCreatureSet::armyChanged()
 
 }
 
-void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const boost::optional<int> fixedSize)
+void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const std::optional<int> fixedSize)
 {
 	if(handler.saving && stacks.empty())
 		return;
@@ -640,7 +640,7 @@ void CCreatureSet::serializeJson(JsonSerializeFormat & handler, const std::strin
 			vstd::amax(sz, p.first.getNum()+1);
 
 		if(fixedSize)
-			vstd::amax(sz, fixedSize.get());
+			vstd::amax(sz, fixedSize.value());
 
 		a.resize(sz, JsonNode::JsonType::DATA_STRUCT);
 

+ 2 - 2
lib/CCreatureSet.h

@@ -75,7 +75,7 @@ public:
 		uint8_t upgrade;
 	};
 	// helper variable used during loading map, when object (hero or town) have creatures that must have same alignment.
-	boost::optional<RandomStackInfo> randomStack;
+	std::optional<RandomStackInfo> randomStack;
 
 	const CArmedInstance * const & armyObj; //stack must be part of some army, army must be part of some object
 	TExpType experience;//commander needs same amount of exp as hero
@@ -286,7 +286,7 @@ public:
 		h & formation;
 	}
 
-	void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const boost::optional<int> fixedSize = boost::none);
+	void serializeJson(JsonSerializeFormat & handler, const std::string & fieldName, const std::optional<int> fixedSize = std::nullopt);
 
 	operator bool() const
 	{

+ 9 - 9
lib/CGameInfoCallback.cpp

@@ -401,7 +401,7 @@ int CGameInfoCallback::getDate(Date::EDateType mode) const
 	return gs->getDate(mode);
 }
 
-bool CGameInfoCallback::isVisible(int3 pos, const boost::optional<PlayerColor> & Player) const
+bool CGameInfoCallback::isVisible(int3 pos, const std::optional<PlayerColor> & Player) const
 {
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
 	return gs->isVisible(pos, Player);
@@ -412,7 +412,7 @@ bool CGameInfoCallback::isVisible(int3 pos) const
 	return isVisible(pos, player);
 }
 
-bool CGameInfoCallback::isVisible( const CGObjectInstance *obj,const boost::optional<PlayerColor> & Player) const
+bool CGameInfoCallback::isVisible(const CGObjectInstance * obj, const std::optional<PlayerColor> & Player) const
 {
 	return gs->isVisible(obj, Player);
 }
@@ -521,8 +521,8 @@ EDiggingStatus CGameInfoCallback::getTileDigStatus(int3 tile, bool verbose) cons
 //TODO: typedef?
 std::shared_ptr<const boost::multi_array<TerrainTile*, 3>> CGameInfoCallback::getAllVisibleTiles() const
 {
-	assert(player.is_initialized());
-	const auto * team = getPlayerTeam(player.get());
+	assert(player.has_value());
+	const auto * team = getPlayerTeam(player.value());
 
 	size_t width = gs->map->width;
 	size_t height = gs->map->height;
@@ -619,9 +619,9 @@ const CMapHeader * CGameInfoCallback::getMapHeader() const
 	return gs->map;
 }
 
-bool CGameInfoCallback::hasAccess(boost::optional<PlayerColor> playerId) const
+bool CGameInfoCallback::hasAccess(std::optional<PlayerColor> playerId) const
 {
-	return !player || player.get().isSpectator() || gs->getPlayerRelations( *playerId, *player ) != PlayerRelations::ENEMIES;
+	return !player || player->isSpectator() || gs->getPlayerRelations(*playerId, *player) != PlayerRelations::ENEMIES;
 }
 
 EPlayerStatus::EStatus CGameInfoCallback::getPlayerStatus(PlayerColor player, bool verbose) const
@@ -703,7 +703,7 @@ PlayerColor CGameInfoCallback::getCurrentPlayer() const
 	return gs->currentPlayer;
 }
 
-CGameInfoCallback::CGameInfoCallback(CGameState * GS, boost::optional<PlayerColor> Player):
+CGameInfoCallback::CGameInfoCallback(CGameState * GS, std::optional<PlayerColor> Player):
 	gs(GS)
 {
 	player = std::move(Player);
@@ -754,7 +754,7 @@ std::vector < const CGHeroInstance *> CPlayerSpecificInfoCallback::getHeroesInfo
 	return ret;
 }
 
-boost::optional<PlayerColor> CPlayerSpecificInfoCallback::getMyColor() const
+std::optional<PlayerColor> CPlayerSpecificInfoCallback::getMyColor() const
 {
 	return player;
 }
@@ -882,7 +882,7 @@ const TeamState * CGameInfoCallback::getTeam( TeamID teamID ) const
 	if (team != gs->teams.end())
 	{
 		const TeamState *ret = &team->second;
-		if (!player.is_initialized()) //neutral (or invalid) player
+		if(!player.has_value()) //neutral (or invalid) player
 			return ret;
 		else
 		{

+ 6 - 6
lib/CGameInfoCallback.h

@@ -133,8 +133,8 @@ protected:
 	CGameState * gs;//todo: replace with protected const getter, only actual Server and Client objects should hold game state
 
 	CGameInfoCallback() = default;
-	CGameInfoCallback(CGameState *GS, boost::optional<PlayerColor> Player);
-	bool hasAccess(boost::optional<PlayerColor> playerId) const;
+	CGameInfoCallback(CGameState * GS, std::optional<PlayerColor> Player);
+	bool hasAccess(std::optional<PlayerColor> playerId) const;
 
 	bool canGetFullInfo(const CGObjectInstance *obj) const; //true we player owns obj or ally owns obj or privileged mode
 	bool isOwnedOrVisited(const CGObjectInstance *obj) const;
@@ -157,9 +157,9 @@ public:
 	virtual const PlayerSettings * getPlayerSettings(PlayerColor color) const;
 
 	//map
-	virtual bool isVisible(int3 pos, const boost::optional<PlayerColor> & Player) const;
-	virtual bool isVisible(const CGObjectInstance *obj, const boost::optional<PlayerColor> & Player) const;
-	virtual bool isVisible(const CGObjectInstance *obj) const;
+	virtual bool isVisible(int3 pos, const std::optional<PlayerColor> & Player) const;
+	virtual bool isVisible(const CGObjectInstance * obj, const std::optional<PlayerColor> & Player) const;
+	virtual bool isVisible(const CGObjectInstance * obj) const;
 	virtual bool isVisible(int3 pos) const;
 
 
@@ -234,7 +234,7 @@ public:
 	virtual int howManyTowns() const;
 	virtual int howManyHeroes(bool includeGarrisoned = true) const;
 	virtual int3 getGrailPos(double *outKnownRatio);
-	virtual boost::optional<PlayerColor> getMyColor() const;
+	virtual std::optional<PlayerColor> getMyColor() const;
 
 	virtual std::vector <const CGTownInstance *> getTownsInfo(bool onlyOur = true) const; //true -> only owned; false -> all visible
 	virtual int getHeroSerial(const CGHeroInstance * hero, bool includeGarrisoned=true) const;

+ 2 - 2
lib/CGameInterface.h

@@ -110,9 +110,9 @@ public:
 
 	virtual void showWorldViewEx(const std::vector<ObjectPosInfo> & objectPositions, bool showTerrain){};
 
-	virtual boost::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
+	virtual std::optional<BattleAction> makeSurrenderRetreatDecision(const BattleStateInfoForRetreat & battleState)
 	{
-		return boost::none;
+		return std::nullopt;
 	}
 
 	virtual void saveGame(BinarySerializer & h, const int version) = 0;

+ 6 - 6
lib/CGameState.cpp

@@ -925,7 +925,7 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
 
 void CGameState::initCampaign()
 {
-	logGlobal->info("Open campaign map file: %d", scenarioOps->campState->currentMap.get());
+	logGlobal->info("Open campaign map file: %d", scenarioOps->campState->currentMap.value());
 	map = scenarioOps->campState->getMap();
 }
 
@@ -1068,7 +1068,7 @@ void CGameState::placeCampaignHeroes()
 	{
 		// place bonus hero
 		auto campaignBonus = scenarioOps->campState->getBonusForCurrentMap();
-		bool campaignGiveHero = campaignBonus && campaignBonus.get().type == CScenarioTravel::STravelBonus::HERO;
+		bool campaignGiveHero = campaignBonus && campaignBonus->type == CScenarioTravel::STravelBonus::HERO;
 
 		if(campaignGiveHero)
 		{
@@ -1568,7 +1568,7 @@ void CGameState::initHeroes()
 
 void CGameState::giveCampaignBonusToHero(CGHeroInstance * hero)
 {
-	const boost::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
+	const std::optional<CScenarioTravel::STravelBonus> & curBonus = scenarioOps->campState->getBonusForCurrentMap();
 	if(!curBonus)
 		return;
 
@@ -2234,7 +2234,7 @@ void CGameState::updateRumor()
 	while(!rumor.update(rumorId, rumorExtra));
 }
 
-bool CGameState::isVisible(int3 pos, const boost::optional<PlayerColor> & player) const
+bool CGameState::isVisible(int3 pos, const std::optional<PlayerColor> & player) const
 {
 	if (!map->isInTheMap(pos))
 		return false;
@@ -2248,7 +2248,7 @@ bool CGameState::isVisible(int3 pos, const boost::optional<PlayerColor> & player
 	return (*getPlayerTeam(*player)->fogOfWarMap)[pos.z][pos.x][pos.y];
 }
 
-bool CGameState::isVisible( const CGObjectInstance *obj, const boost::optional<PlayerColor> & player) const
+bool CGameState::isVisible(const CGObjectInstance * obj, const std::optional<PlayerColor> & player) const
 {
 	if(!player)
 		return true;
@@ -2433,7 +2433,7 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		case EventCondition::DAYS_WITHOUT_TOWN:
 		{
 			if (p->daysWithoutCastle)
-				return p->daysWithoutCastle.get() >= condition.value;
+				return p->daysWithoutCastle >= condition.value;
 			else
 				return false;
 		}

+ 2 - 3
lib/CGameState.h

@@ -202,9 +202,8 @@ public:
 	void obtainPlayersStats(SThievesGuildInfo & tgi, int level); //fills tgi with info about other players that is available at given level of thieves' guild
 	std::map<ui32, ConstTransitivePtr<CGHeroInstance> > unusedHeroesFromPool(); //heroes pool without heroes that are available in taverns
 
-
-	bool isVisible(int3 pos, const boost::optional<PlayerColor> & player) const override;
-	bool isVisible(const CGObjectInstance *obj, const boost::optional<PlayerColor> & player) const override;
+	bool isVisible(int3 pos, const std::optional<PlayerColor> & player) const override;
+	bool isVisible(const CGObjectInstance * obj, const std::optional<PlayerColor> & player) const override;
 
 	int getDate(Date::EDateType mode=Date::DAY) const override; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 

+ 8 - 8
lib/CModHandler.cpp

@@ -156,7 +156,7 @@ void CIdentifierStorage::tryRequestIdentifier(const std::string & type, const Js
 	requestIdentifier(ObjectCallback::fromNameAndType(name.meta, type, name.String(), callback, true));
 }
 
-boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent)
+std::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent)
 {
 	auto idList = getPossibleIdentifiers(ObjectCallback::fromNameAndType(scope, type, name, std::function<void(si32)>(), silent));
 
@@ -165,10 +165,10 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scop
 	if (!silent)
 		logMod->error("Failed to resolve identifier %s of type %s from mod %s", name , type ,scope);
 
-	return boost::optional<si32>();
+	return std::optional<si32>();
 }
 
-boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & type, const JsonNode & name, bool silent)
+std::optional<si32> CIdentifierStorage::getIdentifier(const std::string & type, const JsonNode & name, bool silent)
 {
 	auto idList = getPossibleIdentifiers(ObjectCallback::fromNameAndType(name.meta, type, name.String(), std::function<void(si32)>(), silent));
 
@@ -177,10 +177,10 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & type
 	if (!silent)
 		logMod->error("Failed to resolve identifier %s of type %s from mod %s", name.String(), type, name.meta);
 
-	return boost::optional<si32>();
+	return std::optional<si32>();
 }
 
-boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, bool silent)
+std::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, bool silent)
 {
 	auto idList = getPossibleIdentifiers(ObjectCallback::fromNameWithType(name.meta, name.String(), std::function<void(si32)>(), silent));
 
@@ -189,10 +189,10 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, b
 	if (!silent)
 		logMod->error("Failed to resolve identifier %s from mod %s", name.String(), name.meta);
 
-	return boost::optional<si32>();
+	return std::optional<si32>();
 }
 
-boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scope, const std::string & fullName, bool silent)
+std::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scope, const std::string & fullName, bool silent)
 {
 	auto idList = getPossibleIdentifiers(ObjectCallback::fromNameWithType(scope, fullName, std::function<void(si32)>(), silent));
 
@@ -201,7 +201,7 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(const std::string & scop
 	if (!silent)
 		logMod->error("Failed to resolve identifier %s from mod %s", fullName, scope);
 
-	return boost::optional<si32>();
+	return std::optional<si32>();
 }
 
 void CIdentifierStorage::registerObject(const std::string & scope, const std::string & type, const std::string & name, si32 identifier)

+ 4 - 4
lib/CModHandler.h

@@ -99,10 +99,10 @@ public:
 	void tryRequestIdentifier(const std::string & type, const JsonNode & name, const std::function<void(si32)> & callback);
 
 	/// get identifier immediately. If identifier is not know and not silent call will result in error message
-	boost::optional<si32> getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent = false);
-	boost::optional<si32> getIdentifier(const std::string & type, const JsonNode & name, bool silent = false);
-	boost::optional<si32> getIdentifier(const JsonNode & name, bool silent = false);
-	boost::optional<si32> getIdentifier(const std::string & scope, const std::string & fullName, bool silent = false);
+	std::optional<si32> getIdentifier(const std::string & scope, const std::string & type, const std::string & name, bool silent = false);
+	std::optional<si32> getIdentifier(const std::string & type, const JsonNode & name, bool silent = false);
+	std::optional<si32> getIdentifier(const JsonNode & name, bool silent = false);
+	std::optional<si32> getIdentifier(const std::string & scope, const std::string & fullName, bool silent = false);
 
 	/// registers new object
 	void registerObject(const std::string & scope, const std::string & type, const std::string & name, si32 identifier);

+ 7 - 3
lib/CPathfinder.cpp

@@ -897,7 +897,7 @@ void CPathfinderHelper::initializePatrol()
 		if(hero->patrol.patrolRadius)
 		{
 			state = PATROL_RADIUS;
-			gs->getTilesInRange(patrolTiles, hero->patrol.initialPos, hero->patrol.patrolRadius, boost::optional<PlayerColor>(), 0, int3::DIST_MANHATTAN);
+			gs->getTilesInRange(patrolTiles, hero->patrol.initialPos, hero->patrol.patrolRadius, std::optional<PlayerColor>(), 0, int3::DIST_MANHATTAN);
 		}
 		else
 			state = PATROL_LOCKED;
@@ -1106,8 +1106,12 @@ void TurnInfo::updateHeroBonuses(Bonus::BonusType type, const CSelector& sel) co
 	}
 }
 
-CPathfinderHelper::CPathfinderHelper(CGameState * gs, const CGHeroInstance * Hero, const PathfinderOptions & Options)
-	: CGameInfoCallback(gs, boost::optional<PlayerColor>()), turn(-1), hero(Hero), options(Options), owner(Hero->tempOwner)
+CPathfinderHelper::CPathfinderHelper(CGameState * gs, const CGHeroInstance * Hero, const PathfinderOptions & Options):
+	CGameInfoCallback(gs, std::optional<PlayerColor>()),
+	turn(-1),
+	hero(Hero),
+	options(Options),
+	owner(Hero->tempOwner)
 {
 	turnsInfo.reserve(16);
 	updateTurnInfo();

+ 1 - 1
lib/CPlayerState.h

@@ -38,7 +38,7 @@ public:
 
 	bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
 	EPlayerStatus::EStatus status;
-	boost::optional<ui8> daysWithoutCastle;
+	std::optional<ui8> daysWithoutCastle;
 
 	PlayerState();
 	PlayerState(PlayerState && other) noexcept;

+ 1 - 1
lib/CSkillHandler.cpp

@@ -262,7 +262,7 @@ si32 CSkillHandler::decodeSkill(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeMap(), "skill", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return -1;
 }

+ 2 - 2
lib/CTownHandler.cpp

@@ -1151,7 +1151,7 @@ void CTownHandler::initializeRequirements()
 				logMod->warn("Entry contains: ");
 				logMod->warn(node.toJson());
 			}
-			return BuildingID(VLC->modh->identifiers.getIdentifier(requirement.town->getBuildingScope(), node.Vector()[0]).get());
+			return BuildingID(VLC->modh->identifiers.getIdentifier(requirement.town->getBuildingScope(), node.Vector()[0]).value());
 		});
 	}
 	requirementsToLoad.clear();
@@ -1166,7 +1166,7 @@ void CTownHandler::initializeOverridden()
 
 		for(const auto & b : jsonNode.Vector())
 		{
-			auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).get());
+			auto bid = BuildingID(VLC->modh->identifiers.getIdentifier(scope, b).value());
 			bidHelper.building->overrideBids.insert(bid);
 		}
 	}

+ 7 - 7
lib/GameConstants.cpp

@@ -64,7 +64,7 @@ si32 HeroTypeID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeMap(), "hero", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return -1;
 }
@@ -88,7 +88,7 @@ si32 ArtifactID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "artifact", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return -1;
 }
@@ -112,7 +112,7 @@ si32 CreatureID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "creature", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return -1;
 }
@@ -141,7 +141,7 @@ si32 SpellID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "spell", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return -1;
 }
@@ -204,7 +204,7 @@ si32 FactionID::decode(const std::string & identifier)
 {
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeGame(), "faction", identifier);
 	if(rawId)
-		return rawId.get();
+		return rawId.value();
 	else
 		return FactionID::DEFAULT;
 }
@@ -292,7 +292,7 @@ BattleField BattleField::fromString(const std::string & identifier)
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeBuiltin(), "battlefield", identifier);
 
 	if(rawId)
-		return BattleField(rawId.get());
+		return BattleField(rawId.value());
 	else
 		return BattleField::NONE;
 }
@@ -312,7 +312,7 @@ Obstacle Obstacle::fromString(const std::string & identifier)
 	auto rawId = VLC->modh->identifiers.getIdentifier(CModHandler::scopeBuiltin(), "obstacle", identifier);
 
 	if(rawId)
-		return Obstacle(rawId.get());
+		return Obstacle(rawId.value());
 	else
 		return Obstacle(-1);
 }

+ 1 - 1
lib/HeroBonus.cpp

@@ -1520,7 +1520,7 @@ int64_t CBonusSystemNode::getTreeVersion() const
 	return treeChanged;
 }
 
-std::string Bonus::Description(boost::optional<si32> customValue) const
+std::string Bonus::Description(std::optional<si32> customValue) const
 {
 	std::ostringstream str;
 

+ 1 - 1
lib/HeroBonus.h

@@ -533,7 +533,7 @@ struct DLL_LINKAGE Bonus : public std::enable_shared_from_this<Bonus>
 		return sid & 0x0000FFFF;
 	}
 
-	std::string Description(boost::optional<si32> customValue = {}) const;
+	std::string Description(std::optional<si32> customValue = {}) const;
 	JsonNode toJsonNode() const;
 	std::string nameForBonus() const; // generate suitable name for bonus - e.g. for storing in json struct
 

+ 2 - 2
lib/IGameCallback.cpp

@@ -66,7 +66,7 @@ void CPrivilegedInfoCallback::getFreeTiles(std::vector<int3> & tiles) const
 void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3, ShashInt3> & tiles,
 											  const int3 & pos,
 											  int radious,
-											  boost::optional<PlayerColor> player,
+											  std::optional<PlayerColor> player,
 											  int mode,
 											  int3::EDistanceFormula distanceFormula) const
 {
@@ -100,7 +100,7 @@ void CPrivilegedInfoCallback::getTilesInRange(std::unordered_set<int3, ShashInt3
 	}
 }
 
-void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3, ShashInt3> & tiles, boost::optional<PlayerColor> Player, int level, MapTerrainFilterMode tileFilterMode) const
+void CPrivilegedInfoCallback::getAllTiles(std::unordered_set<int3, ShashInt3> & tiles, std::optional<PlayerColor> Player, int level, MapTerrainFilterMode tileFilterMode) const
 {
 	if(!!Player && *Player >= PlayerColor::PLAYER_LIMIT)
 	{

+ 2 - 2
lib/IGameCallback.h

@@ -62,12 +62,12 @@ public:
 	void getTilesInRange(std::unordered_set<int3, ShashInt3> & tiles,
 						 const int3 & pos,
 						 int radious,
-						 boost::optional<PlayerColor> player = boost::optional<PlayerColor>(),
+						 std::optional<PlayerColor> player = std::optional<PlayerColor>(),
 						 int mode = 0,
 						 int3::EDistanceFormula formula = int3::DIST_2D) const;
 
 	//returns all tiles on given level (-1 - both levels, otherwise number of level)
-	void getAllTiles(std::unordered_set<int3, ShashInt3> &tiles, boost::optional<PlayerColor> player = boost::optional<PlayerColor>(),
+	void getAllTiles(std::unordered_set<int3, ShashInt3> &tiles, std::optional<PlayerColor> player = std::optional<PlayerColor>(),
 					 int level = -1, MapTerrainFilterMode tileFilterMode = MapTerrainFilterMode::NONE) const;
 
 	//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant

+ 36 - 36
lib/LogicalExpression.h

@@ -21,7 +21,7 @@ namespace LogicalExpressionDetail
 	class ExpressionBase
 	{
 	public:
-		/// Possible logical operations, mostly needed to create different types for boost::variant
+		/// Possible logical operations, mostly needed to create different types for std::variant
 		enum EOperations
 		{
 			ANY_OF,
@@ -37,7 +37,7 @@ namespace LogicalExpressionDetail
 		typedef ContainedClass Value;
 
 		/// Variant that contains all possible elements from logical expression
-		typedef boost::variant<
+		typedef std::variant<
 			OperatorAll,
 			OperatorAny,
 			OperatorNone,
@@ -70,8 +70,8 @@ namespace LogicalExpressionDetail
 	};
 
 	/// Visitor to test result (true/false) of the expression
-	template <typename ContainedClass>
-	class TestVisitor : public boost::static_visitor<bool>
+	template<typename ContainedClass>
+	class TestVisitor
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -81,7 +81,7 @@ namespace LogicalExpressionDetail
 		{
 			return boost::range::count_if(element, [&](const typename Base::Variant & expr)
 			{
-				return boost::apply_visitor(*this, expr);
+				return std::visit(*this, expr);
 			});
 		}
 	public:
@@ -116,8 +116,8 @@ namespace LogicalExpressionDetail
 	template <typename ContainedClass>
 	class FalsifiabilityVisitor;
 
-	template <typename ContainedClass>
-	class PossibilityVisitor : public boost::static_visitor<bool>
+	template<typename ContainedClass>
+	class PossibilityVisitor
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -131,7 +131,7 @@ namespace LogicalExpressionDetail
 		{
 			return boost::range::count_if(element, [&](const typename Base::Variant & expr)
 			{
-				return boost::apply_visitor(*satisfiabilityVisitor, expr);
+				return std::visit(*satisfiabilityVisitor, expr);
 			});
 		}
 
@@ -139,7 +139,7 @@ namespace LogicalExpressionDetail
 		{
 			return boost::range::count_if(element, [&](const typename Base::Variant & expr)
 			{
-				return boost::apply_visitor(*falsifiabilityVisitor, expr);
+				return std::visit(*falsifiabilityVisitor, expr);
 			});
 		}
 
@@ -235,8 +235,8 @@ namespace LogicalExpressionDetail
 
 	/// visitor that is trying to generates candidates that must be fulfilled
 	/// to complete this expression
-	template <typename ContainedClass>
-	class CandidatesVisitor : public boost::static_visitor<std::vector<ContainedClass> >
+	template<typename ContainedClass>
+	class CandidatesVisitor
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 		typedef std::vector<typename Base::Value> TValueList;
@@ -254,7 +254,7 @@ namespace LogicalExpressionDetail
 			if (!classTest(element))
 			{
 				for (auto & elem : element.expressions)
-					boost::range::copy(boost::apply_visitor(*this, elem), std::back_inserter(ret));
+					boost::range::copy(std::visit(*this, elem), std::back_inserter(ret));
 			}
 			return ret;
 		}
@@ -265,7 +265,7 @@ namespace LogicalExpressionDetail
 			if (!classTest(element))
 			{
 				for (auto & elem : element.expressions)
-					boost::range::copy(boost::apply_visitor(*this, elem), std::back_inserter(ret));
+					boost::range::copy(std::visit(*this, elem), std::back_inserter(ret));
 			}
 			return ret;
 		}
@@ -285,8 +285,8 @@ namespace LogicalExpressionDetail
 	};
 
 	/// Simple foreach visitor
-	template <typename ContainedClass>
-	class ForEachVisitor : public boost::static_visitor<typename ExpressionBase<ContainedClass>::Variant>
+	template<typename ContainedClass>
+	class ForEachVisitor
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -306,14 +306,14 @@ namespace LogicalExpressionDetail
 		typename Base::Variant operator()(Type element) const
 		{
 			for (auto & entry : element.expressions)
-				entry = boost::apply_visitor(*this, entry);
+				entry = std::visit(*this, entry);
 			return element;
 		}
 	};
 
 	/// Minimizing visitor that removes all redundant elements from variant (e.g. AllOf inside another AllOf can be merged safely)
-	template <typename ContainedClass>
-	class MinimizingVisitor : public boost::static_visitor<typename ExpressionBase<ContainedClass>::Variant>
+	template<typename ContainedClass>
+	class MinimizingVisitor
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -330,15 +330,15 @@ namespace LogicalExpressionDetail
 
 			for (auto & entryRO : element.expressions)
 			{
-				auto entry = boost::apply_visitor(*this, entryRO);
+				auto entry = std::visit(*this, entryRO);
 
 				try
 				{
 					// copy entries from child of this type
-					auto sublist = boost::get<Type>(entry).expressions;
+					auto sublist = std::get<Type>(entry).expressions;
 					std::move(sublist.begin(), sublist.end(), std::back_inserter(ret.expressions));
 				}
-				catch (boost::bad_get &)
+				catch (std::bad_variant_access &)
 				{
 					// different type (e.g. allOf vs oneOf) just copy
 					ret.expressions.push_back(entry);
@@ -397,8 +397,8 @@ namespace LogicalExpressionDetail
 	};
 
 	/// Serializes expression in JSON format. Part of map format.
-	template <typename ContainedClass>
-	class Writer : public boost::static_visitor<JsonNode>
+	template<typename ContainedClass>
+	class Writer
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -410,7 +410,7 @@ namespace LogicalExpressionDetail
 			ret.Vector().resize(1);
 			ret.Vector().back().String() = name;
 			for (auto & expr : element)
-				ret.Vector().push_back(boost::apply_visitor(*this, expr));
+				ret.Vector().push_back(std::visit(*this, expr));
 			return ret;
 		}
 	public:
@@ -442,8 +442,8 @@ namespace LogicalExpressionDetail
 	std::string DLL_LINKAGE getTextForOperator(const std::string & operation);
 
 	/// Prints expression in human-readable format
-	template <typename ContainedClass>
-	class Printer : public boost::static_visitor<std::string>
+	template<typename ContainedClass>
+	class Printer
 	{
 		typedef ExpressionBase<ContainedClass> Base;
 
@@ -465,7 +465,7 @@ namespace LogicalExpressionDetail
 			std::string ret;
 			prefix.push_back('\t');
 			for (auto & expr : element)
-				ret += prefix + boost::apply_visitor(*this, expr) + "\n";
+				ret += prefix + std::visit(*this, expr) + "\n";
 			prefix.pop_back();
 			return ret;
 		}
@@ -552,14 +552,14 @@ public:
 	Variant morph(std::function<Variant(const Value &)> morpher) const
 	{
 		LogicalExpressionDetail::ForEachVisitor<Value> visitor(morpher);
-		return boost::apply_visitor(visitor, data);
+		return std::visit(visitor, data);
 	}
 
 	/// Minimizes expression, removing any redundant elements
 	void minimize()
 	{
 		LogicalExpressionDetail::MinimizingVisitor<Value> visitor;
-		data = boost::apply_visitor(visitor, data);
+		data = std::visit(visitor, data);
 	}
 
 	/// calculates if expression evaluates to "true".
@@ -567,7 +567,7 @@ public:
 	bool test(std::function<bool(const Value &)> toBool) const
 	{
 		LogicalExpressionDetail::TestVisitor<Value> testVisitor(toBool);
-		return boost::apply_visitor(testVisitor, data);
+		return std::visit(testVisitor, data);
 	}
 
 	/// calculates if expression can evaluate to "true".
@@ -579,7 +579,7 @@ public:
 		satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
 		falsifiabilityVisitor.setSatisfiabilityVisitor(&satisfiabilityVisitor);
 
-		return boost::apply_visitor(satisfiabilityVisitor, data);
+		return std::visit(satisfiabilityVisitor, data);
 	}
 
 	/// calculates if expression can evaluate to "false".
@@ -591,14 +591,14 @@ public:
 		satisfiabilityVisitor.setFalsifiabilityVisitor(&falsifiabilityVisitor);
 		falsifiabilityVisitor.setFalsifiabilityVisitor(&satisfiabilityVisitor);
 
-		return boost::apply_visitor(falsifiabilityVisitor, data);
+		return std::visit(falsifiabilityVisitor, data);
 	}
 
 	/// generates list of candidates that can be fulfilled by caller (like AI)
 	std::vector<Value> getFulfillmentCandidates(std::function<bool(const Value &)> toBool) const
 	{
 		LogicalExpressionDetail::CandidatesVisitor<Value> candidateVisitor(toBool);
-		return boost::apply_visitor(candidateVisitor, data);
+		return std::visit(candidateVisitor, data);
 	}
 
 	/// Converts expression in human-readable form
@@ -607,18 +607,18 @@ public:
 	std::string toString(std::function<std::string(const Value &)> toStr) const
 	{
 		LogicalExpressionDetail::Printer<Value> printVisitor(toStr);
-		return boost::apply_visitor(printVisitor, data);
+		return std::visit(printVisitor, data);
 	}
 	std::string toString(std::function<std::string(const Value &)> toStr, std::function<bool(const Value &)> toBool) const
 	{
 		LogicalExpressionDetail::Printer<Value> printVisitor(toStr, toBool);
-		return boost::apply_visitor(printVisitor, data);
+		return std::visit(printVisitor, data);
 	}
 
 	JsonNode toJson(std::function<JsonNode(const Value &)> toJson) const
 	{
 		LogicalExpressionDetail::Writer<Value> writeVisitor(toJson);
-		return boost::apply_visitor(writeVisitor, data);
+		return std::visit(writeVisitor, data);
 	}
 
 	template <typename Handler>

+ 6 - 6
lib/NetPacks.h

@@ -145,7 +145,7 @@ struct DLL_LINKAGE YourTurn : public CPackForClient
 	void applyGs(CGameState * gs) const;
 
 	PlayerColor player;
-	boost::optional<ui8> daysWithoutCastle;
+	std::optional<ui8> daysWithoutCastle;
 
 	virtual void visitTyped(ICPackVisitor & visitor) override;
 
@@ -591,7 +591,7 @@ struct DLL_LINKAGE TryMoveHero : public CPackForClient
 	EResult result = FAILED; //uses EResult
 	int3 start, end; //h3m format
 	std::unordered_set<int3, ShashInt3> fowRevealed; //revealed tiles
-	boost::optional<int3> attackedFrom; // Set when stepping into endangered tile.
+	std::optional<int3> attackedFrom; // Set when stepping into endangered tile.
 
 	virtual void visitTyped(ICPackVisitor & visitor) override;
 
@@ -930,17 +930,17 @@ struct DLL_LINKAGE BulkSmartRebalanceStacks : CGarrisonOperationPack
 	}
 };
 
-struct GetEngagedHeroIds : boost::static_visitor<boost::optional<ObjectInstanceID>>
+struct GetEngagedHeroIds
 {
-	boost::optional<ObjectInstanceID> operator()(const ConstTransitivePtr<CGHeroInstance> & h) const
+	std::optional<ObjectInstanceID> operator()(const ConstTransitivePtr<CGHeroInstance> & h) const
 	{
 		return h->id;
 	}
-	boost::optional<ObjectInstanceID> operator()(const ConstTransitivePtr<CStackInstance> & s) const
+	std::optional<ObjectInstanceID> operator()(const ConstTransitivePtr<CStackInstance> & s) const
 	{
 		if(s->armyObj && s->armyObj->ID == Obj::HERO)
 			return s->armyObj->id;
-		return boost::optional<ObjectInstanceID>();
+		return std::optional<ObjectInstanceID>();
 	}
 };
 

+ 3 - 3
lib/NetPacksBase.h

@@ -233,7 +233,7 @@ struct Component
 	}
 };
 
-using TArtHolder = boost::variant<ConstTransitivePtr<CGHeroInstance>, ConstTransitivePtr<CStackInstance>>;
+using TArtHolder = std::variant<ConstTransitivePtr<CGHeroInstance>, ConstTransitivePtr<CStackInstance>>;
 
 struct ArtifactLocation
 {
@@ -259,9 +259,9 @@ struct ArtifactLocation
 	template <typename T>
 	bool isHolder(const T *t) const
 	{
-		if(auto ptrToT = boost::get<ConstTransitivePtr<T> >(&artHolder))
+		if(auto ptrToT = std::get<ConstTransitivePtr<T>>(artHolder))
 		{
-			return ptrToT->get() == t;
+			return ptrToT == t;
 		}
 		return false;
 	}

+ 11 - 11
lib/NetPacksLib.cpp

@@ -1535,7 +1535,7 @@ const CStackInstance * StackLocation::getStack()
 	return &army->getStack(slot);
 }
 
-struct ObjectRetriever : boost::static_visitor<const CArmedInstance *>
+struct ObjectRetriever
 {
 	const CArmedInstance * operator()(const ConstTransitivePtr<CGHeroInstance> &h) const
 	{
@@ -1546,8 +1546,8 @@ struct ObjectRetriever : boost::static_visitor<const CArmedInstance *>
 		return s->armyObj;
 	}
 };
-template <typename T>
-struct GetBase : boost::static_visitor<T*>
+template<typename T>
+struct GetBase
 {
 	template <typename TArg>
 	T * operator()(TArg &arg) const
@@ -1566,7 +1566,7 @@ void ArtifactLocation::removeArtifact()
 
 const CArmedInstance * ArtifactLocation::relatedObj() const
 {
-	return boost::apply_visitor(ObjectRetriever(), artHolder);
+	return std::visit(ObjectRetriever(), artHolder);
 }
 
 PlayerColor ArtifactLocation::owningPlayer() const
@@ -1577,12 +1577,12 @@ PlayerColor ArtifactLocation::owningPlayer() const
 
 CArtifactSet *ArtifactLocation::getHolderArtSet()
 {
-	return boost::apply_visitor(GetBase<CArtifactSet>(), artHolder);
+	return std::visit(GetBase<CArtifactSet>(), artHolder);
 }
 
 CBonusSystemNode *ArtifactLocation::getHolderNode()
 {
-	return boost::apply_visitor(GetBase<CBonusSystemNode>(), artHolder);
+	return std::visit(GetBase<CBonusSystemNode>(), artHolder);
 }
 
 const CArtifactInstance *ArtifactLocation::getArt() const
@@ -2053,11 +2053,11 @@ void NewTurn::applyGs(CGameState *gs)
 				if (playerState.daysWithoutCastle)
 					++(*playerState.daysWithoutCastle);
 				else
-					playerState.daysWithoutCastle = boost::make_optional(0);
+					playerState.daysWithoutCastle = std::make_optional(0);
 			}
 			else
 			{
-				playerState.daysWithoutCastle = boost::none;
+				playerState.daysWithoutCastle = std::nullopt;
 			}
 		}
 	}
@@ -2088,7 +2088,7 @@ void SetObjectProperty::applyGs(CGameState * gs) const
 
 				//reset counter before NewTurn to avoid no town message if game loaded at turn when one already captured
 				if(p->daysWithoutCastle)
-					p->daysWithoutCastle = boost::none;
+					p->daysWithoutCastle = std::nullopt;
 			}
 		}
 
@@ -2536,12 +2536,12 @@ const CArtifactInstance * ArtSlotInfo::getArt() const
 
 CArtifactSet * BulkMoveArtifacts::getSrcHolderArtSet()
 {
-	return boost::apply_visitor(GetBase<CArtifactSet>(), srcArtHolder);
+	return std::visit(GetBase<CArtifactSet>(), srcArtHolder);
 }
 
 CArtifactSet * BulkMoveArtifacts::getDstHolderArtSet()
 {
-	return boost::apply_visitor(GetBase<CArtifactSet>(), dstArtHolder);
+	return std::visit(GetBase<CArtifactSet>(), dstArtHolder);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/battle/BattleHex.h

@@ -29,7 +29,7 @@ namespace GameConstants
 	const int BFIELD_SIZE = BFIELD_WIDTH * BFIELD_HEIGHT;
 }
 
-using BattleSideOpt =  boost::optional<ui8>;
+using BattleSideOpt = std::optional<ui8>;
 
 // for battle stacks' positions
 struct DLL_LINKAGE BattleHex //TODO: decide if this should be changed to class for better code design

+ 7 - 7
lib/battle/CBattleInfoCallback.cpp

@@ -106,7 +106,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
 	const auto side = playerToSide(player);
 	if(!side)
 		return ESpellCastProblem::INVALID;
-	if(!battleDoWeKnowAbout(side.get()))
+	if(!battleDoWeKnowAbout(side.value()))
 	{
 		logGlobal->warn("You can't check if enemy can cast given spell!");
 		return ESpellCastProblem::INVALID;
@@ -119,7 +119,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastSpell(con
 	{
 	case spells::Mode::HERO:
 	{
-		if(battleCastSpells(side.get()) > 0)
+		if(battleCastSpells(side.value()) > 0)
 			return ESpellCastProblem::CASTS_PER_TURN_LIMIT;
 
 		const auto * hero = dynamic_cast<const CGHeroInstance *>(caster);
@@ -229,7 +229,7 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
 		{
 			if(stack->hasBonusOfType(Bonus::SPELLCASTER))
 			{
-				for (auto const & spellID : data.creatureSpellsToCast)
+				for(const auto & spellID : data.creatureSpellsToCast)
 				{
 					const CSpell *spell = spellID.toSpell();
 					PossiblePlayerBattleAction act = getCasterAction(spell, stack, spells::Mode::CREATURE_ACTIVE);
@@ -767,7 +767,7 @@ DamageEstimation CBattleInfoCallback::battleEstimateDamage(const BattleAttackInf
 			//TODO: rewrite using boost::numeric::interval
 			//TODO: rewire once more using interval-based fuzzy arithmetic
 
-			auto const & estimateRetaliation = [&]( int64_t damage)
+			const auto & estimateRetaliation = [&](int64_t damage)
 			{
 				auto retaliationAttack = bai.reverse();
 				auto state = retaliationAttack.attacker->acquireState();
@@ -1763,7 +1763,7 @@ int CBattleInfoCallback::battleGetSurrenderCost(const PlayerColor & Player) cons
 	const auto sideOpt = playerToSide(Player);
 	if(!sideOpt)
 		return -1;
-	const auto side = sideOpt.get();
+	const auto side = sideOpt.value();
 
 	int ret = 0;
 	double discount = 0;
@@ -1816,7 +1816,7 @@ si8 CBattleInfoCallback::battleMaxSpellLevel(ui8 side) const
 	return GameConstants::SPELL_LEVELS;
 }
 
-boost::optional<int> CBattleInfoCallback::battleIsFinished() const
+std::optional<int> CBattleInfoCallback::battleIsFinished() const
 {
 	auto units = battleGetUnitsIf([=](const battle::Unit * unit)
 	{
@@ -1831,7 +1831,7 @@ boost::optional<int> CBattleInfoCallback::battleIsFinished() const
 		hasUnit.at(unit->unitSide()) = true;
 
 		if(hasUnit[0] && hasUnit[1])
-			return boost::none;
+			return std::nullopt;
 	}
 	
 	hasUnit = {false, false};

+ 1 - 1
lib/battle/CBattleInfoCallback.h

@@ -58,7 +58,7 @@ public:
 		RANDOM_GENIE, RANDOM_AIMED
 	};
 
-	boost::optional<int> battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
+	std::optional<int> 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>> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set<BattleHex> & passed) const override;

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä