浏览代码

- Added handler classes CRmgTemplateStorage and CTerrainViewPatternConfig to LibClasses
- Re-organized CMapGenerator
- Created CZone and CTemplate objects in the heap and used pointers
- Added stub classes CZoneGraphGenerator and CZonePlacer (include warnings of unused variables, please ignore them)
- Fixed CRandomGenerator bug that always the same number was produced
- Better structure of Visual Studio project files with using filters
- Updated project files (VS, CMake)
- Excluded compiler warning mismatched-tags (false positive)
- Fixed a bug when compiling with unit tests enabled

beegee1 12 年之前
父节点
当前提交
1ac328635a

+ 4 - 2
CMakeLists.txt

@@ -58,7 +58,9 @@ if (ENABLE_EDITOR)
 endif()
 
 if(ENABLE_TEST)
-	find_package(Boost 1.46.0 COMPONENTS unit_test_framework REQUIRED)
+	# find_package overwrites BOOST_* variables which are already set, so all components have to be
+	# included again
+	find_package(Boost 1.46.0 COMPONENTS program_options filesystem system thread unit_test_framework REQUIRED)
 endif()
 
 if(NOT WIN32)
@@ -80,7 +82,7 @@ if(NOT WIN32)
 endif()
 
 if(CMAKE_COMPILER_IS_GNUCXX OR NOT WIN32) #so far all *nix compilers support such parameters
-	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -Wpointer-arith -Wno-switch -Wno-sign-compare -Wno-unused-parameter -Wno-overloaded-virtual")
+	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -Wextra -Wpointer-arith -Wno-switch -Wno-sign-compare -Wno-unused-parameter -Wno-overloaded-virtual -Wno-mismatched-tags")
 endif()
 
 if(WIN32) # on Win everything goes into H3 root directory

+ 6 - 0
lib/CMakeLists.txt

@@ -27,6 +27,12 @@ set(lib_SRCS
 		mapping/MapFormatH3M.cpp
 
 		rmg/CMapGenerator.cpp
+		rmg/CMapGenOptions.cpp
+		rmg/CRmgTemplate.cpp
+		rmg/CRmgTemplateZone.cpp
+		rmg/CRmgTemplateStorage.cpp
+		rmg/CZoneGraphGenerator.cpp
+		rmg/CZonePlacer.cpp
 
 		BattleAction.cpp
 		BattleHex.cpp

+ 3 - 3
lib/CRandomGenerator.h

@@ -19,7 +19,7 @@ typedef std::function<double()> TRand;
 
 /// The random generator randomly generates integers and real numbers("doubles") between
 /// a given range. This is a header only class and mainly a wrapper for
-/// convenient usage of the boost random API.
+/// convenient usage of the standard random API.
 class CRandomGenerator
 {
 public:
@@ -38,7 +38,7 @@ public:
 	/// e.g.: auto a = gen.getRangeI(0,10); a(); a(); a();
 	TRandI getRangeI(int lower, int upper)
 	{
-		return boost::bind(TIntDist(lower, upper), gen);
+		return boost::bind(TIntDist(lower, upper), boost::ref(gen));
 	}
 	
 	int getInteger(int lower, int upper)
@@ -50,7 +50,7 @@ public:
 	/// e.g.: auto a = gen.getRangeI(0,10); a(); a(); a();
 	TRand getRange(double lower, double upper)
 	{
-		return boost::bind(TRealDist(lower, upper), gen);
+		return boost::bind(TRealDist(lower, upper), boost::ref(gen));
 	}
 	
 	double getDouble(double lower, double upper)

+ 1 - 0
lib/GameConstants.h

@@ -892,6 +892,7 @@ typedef std::pair<ui32, ui32> TDmgRange;
 typedef si32 TBonusSubtype;
 typedef si32 TQuantity;
 
+typedef int TRmgTemplateZoneId;
 
 #undef ID_LIKE_CLASS_COMMON
 #undef ID_LIKE_OPERATORS_DECLS

+ 10 - 0
lib/VCMI_Lib.cpp

@@ -27,6 +27,8 @@
 #include "VCMIDirs.h"
 #include "filesystem/Filesystem.h"
 #include "CConsoleHandler.h"
+#include "rmg/CRmgTemplateStorage.h"
+#include "mapping/CMapEditManager.h"
 
 LibClasses * VLC = nullptr;
 
@@ -111,6 +113,10 @@ void LibClasses::init()
 
 	createHandler(spellh, "Spell", pomtime);
 
+	createHandler(terviewh, "Terrain view pattern", pomtime);
+
+	createHandler(tplh, "Template", pomtime);
+
 	logGlobal->infoStream()<<"\tInitializing handlers: "<< totalTime.getDiff();
 
 	modh->loadGameContent();
@@ -133,6 +139,8 @@ void LibClasses::clear()
 	delete spellh;
 	delete modh;
 	delete bth;
+	delete tplh;
+	delete terviewh;
 	makeNull();
 }
 
@@ -148,6 +156,8 @@ void LibClasses::makeNull()
 	spellh = nullptr;
 	modh = nullptr;
 	bth = nullptr;
+	tplh = nullptr;
+	terviewh = nullptr;
 }
 
 LibClasses::LibClasses()

+ 4 - 0
lib/VCMI_Lib.h

@@ -22,6 +22,8 @@ class CGeneralTextHandler;
 class CModHandler;
 class IBonusTypeHandler;
 class CBonusTypeHandler;
+class CTerrainViewPatternConfig;
+class CRmgTemplateStorage;
 
 /// Loads and constructs several handlers
 class DLL_LINKAGE LibClasses
@@ -44,6 +46,8 @@ public:
 	CTownHandler * townh;
 	CGeneralTextHandler * generaltexth;
 	CModHandler * modh;
+	CTerrainViewPatternConfig * terviewh;
+	CRmgTemplateStorage * tplh;
 
 	LibClasses(); //c-tor, loads .lods and NULLs handlers
 	~LibClasses();

+ 12 - 0
lib/VCMI_lib.vcxproj

@@ -212,6 +212,12 @@
     <ClCompile Include="JsonNode.cpp" />
     <ClCompile Include="NetPacksLib.cpp" />
     <ClCompile Include="ResourceSet.cpp" />
+    <ClCompile Include="rmg\CMapGenOptions.cpp" />
+    <ClCompile Include="rmg\CRmgTemplate.cpp" />
+    <ClCompile Include="rmg\CRmgTemplateStorage.cpp" />
+    <ClCompile Include="rmg\CRmgTemplateZone.cpp" />
+    <ClCompile Include="rmg\CZoneGraphGenerator.cpp" />
+    <ClCompile Include="rmg\CZonePlacer.cpp" />
     <ClCompile Include="StdInc.cpp">
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">VCMI_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
@@ -287,6 +293,12 @@
     <ClInclude Include="NetPacks.h" />
     <ClInclude Include="RegisterTypes.h" />
     <ClInclude Include="ResourceSet.h" />
+    <ClInclude Include="rmg\CMapGenOptions.h" />
+    <ClInclude Include="rmg\CRmgTemplate.h" />
+    <ClInclude Include="rmg\CRmgTemplateStorage.h" />
+    <ClInclude Include="rmg\CRmgTemplateZone.h" />
+    <ClInclude Include="rmg\CZoneGraphGenerator.h" />
+    <ClInclude Include="rmg\CZonePlacer.h" />
     <ClInclude Include="StartInfo.h" />
     <ClInclude Include="StdInc.h" />
     <ClInclude Include="UnlockGuard.h" />

+ 252 - 0
lib/VCMI_lib.vcxproj.filters

@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <ClCompile Include="BattleAction.cpp" />
+    <ClCompile Include="BattleHex.cpp" />
+    <ClCompile Include="BattleState.cpp" />
+    <ClCompile Include="CArtHandler.cpp" />
+    <ClCompile Include="CBonusTypeHandler.cpp" />
+    <ClCompile Include="CBuildingHandler.cpp" />
+    <ClCompile Include="CConfigHandler.cpp" />
+    <ClCompile Include="CConsoleHandler.cpp" />
+    <ClCompile Include="CCreatureHandler.cpp" />
+    <ClCompile Include="CCreatureSet.cpp" />
+    <ClCompile Include="CDefObjInfoHandler.cpp" />
+    <ClCompile Include="CGameInterface.cpp" />
+    <ClCompile Include="CGameState.cpp" />
+    <ClCompile Include="CGeneralTextHandler.cpp" />
+    <ClCompile Include="CHeroHandler.cpp" />
+    <ClCompile Include="CModHandler.cpp" />
+    <ClCompile Include="CObjectHandler.cpp" />
+    <ClCompile Include="CObstacleInstance.cpp" />
+    <ClCompile Include="Connection.cpp" />
+    <ClCompile Include="CSpellHandler.cpp" />
+    <ClCompile Include="CThreadHelper.cpp" />
+    <ClCompile Include="CTownHandler.cpp" />
+    <ClCompile Include="GameConstants.cpp" />
+    <ClCompile Include="mapping\CCampaignHandler.cpp" />
+    <ClCompile Include="RegisterTypes.cpp" />
+    <ClCompile Include="HeroBonus.cpp" />
+    <ClCompile Include="CBattleCallback.cpp" />
+    <ClCompile Include="IGameCallback.cpp" />
+    <ClCompile Include="JsonNode.cpp" />
+    <ClCompile Include="NetPacksLib.cpp" />
+    <ClCompile Include="ResourceSet.cpp" />
+    <ClCompile Include="StdInc.cpp" />
+    <ClCompile Include="VCMIDirs.cpp" />
+    <ClCompile Include="VCMI_Lib.cpp" />
+    <ClCompile Include="rmg\CMapGenerator.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CMapGenOptions.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CRmgTemplate.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CRmgTemplateStorage.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CRmgTemplateZone.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CZoneGraphGenerator.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="rmg\CZonePlacer.cpp">
+      <Filter>rmg</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\AdapterLoaders.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CArchiveLoader.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="logging\CBasicLogConfigurator.cpp">
+      <Filter>logging</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CBinaryReader.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CCompressedStream.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CMemoryStream.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CZipLoader.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\Filesystem.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="mapping\MapFormatH3M.cpp">
+      <Filter>mapping</Filter>
+    </ClCompile>
+    <ClCompile Include="mapping\CMapService.cpp">
+      <Filter>mapping</Filter>
+    </ClCompile>
+    <ClCompile Include="mapping\CMapInfo.cpp">
+      <Filter>mapping</Filter>
+    </ClCompile>
+    <ClCompile Include="mapping\CMapEditManager.cpp">
+      <Filter>mapping</Filter>
+    </ClCompile>
+    <ClCompile Include="mapping\CMap.cpp">
+      <Filter>mapping</Filter>
+    </ClCompile>
+    <ClCompile Include="logging\CLogger.cpp">
+      <Filter>logging</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CFilesystemLoader.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CFileInputStream.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+    <ClCompile Include="filesystem\CFileInfo.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="..\Global.h" />
+    <ClInclude Include="AI_Base.h" />
+    <ClInclude Include="BattleAction.h" />
+    <ClInclude Include="BattleHex.h" />
+    <ClInclude Include="BattleState.h" />
+    <ClInclude Include="CArtHandler.h" />
+    <ClInclude Include="CBonusTypeHandler.h" />
+    <ClInclude Include="CBuildingHandler.h" />
+    <ClInclude Include="CConfigHandler.h" />
+    <ClInclude Include="CConsoleHandler.h" />
+    <ClInclude Include="CCreatureHandler.h" />
+    <ClInclude Include="CCreatureSet.h" />
+    <ClInclude Include="CDefObjInfoHandler.h" />
+    <ClInclude Include="CGameInterface.h" />
+    <ClInclude Include="CGameState.h" />
+    <ClInclude Include="CGeneralTextHandler.h" />
+    <ClInclude Include="CHeroHandler.h" />
+    <ClInclude Include="CModHandler.h" />
+    <ClInclude Include="CObjectHandler.h" />
+    <ClInclude Include="CObstacleInstance.h" />
+    <ClInclude Include="CondSh.h" />
+    <ClInclude Include="Connection.h" />
+    <ClInclude Include="ConstTransitivePtr.h" />
+    <ClInclude Include="CRandomGenerator.h" />
+    <ClInclude Include="CScriptingModule.h" />
+    <ClInclude Include="CSpellHandler.h" />
+    <ClInclude Include="CStopWatch.h" />
+    <ClInclude Include="CThreadHelper.h" />
+    <ClInclude Include="CTownHandler.h" />
+    <ClInclude Include="IBonusTypeHandler.h" />
+    <ClInclude Include="mapping\CCampaignHandler.h" />
+    <ClInclude Include="GameConstants.h" />
+    <ClInclude Include="HeroBonus.h" />
+    <ClInclude Include="CBattleCallback.h" />
+    <ClInclude Include="IGameCallback.h" />
+    <ClInclude Include="IGameEventsReceiver.h" />
+    <ClInclude Include="int3.h" />
+    <ClInclude Include="Interprocess.h" />
+    <ClInclude Include="JsonNode.h" />
+    <ClInclude Include="NetPacks.h" />
+    <ClInclude Include="RegisterTypes.h" />
+    <ClInclude Include="ResourceSet.h" />
+    <ClInclude Include="StartInfo.h" />
+    <ClInclude Include="StdInc.h" />
+    <ClInclude Include="UnlockGuard.h" />
+    <ClInclude Include="VCMI_Lib.h" />
+    <ClInclude Include="VCMIDirs.h" />
+    <ClInclude Include="rmg\CMapGenerator.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CMapGenOptions.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CRmgTemplate.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CRmgTemplateStorage.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CRmgTemplateZone.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CZoneGraphGenerator.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="rmg\CZonePlacer.h">
+      <Filter>rmg</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\AdapterLoaders.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CArchiveLoader.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="logging\CBasicLogConfigurator.h">
+      <Filter>logging</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CBinaryReader.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CCompressedStream.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CInputStream.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CMemoryStream.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CZipLoader.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\Filesystem.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\ISimpleResourceLoader.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\MapFormatH3M.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CMapService.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CMapInfo.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CMapEditManager.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="mapping\CMap.h">
+      <Filter>mapping</Filter>
+    </ClInclude>
+    <ClInclude Include="logging\CLogger.h">
+      <Filter>logging</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CFilesystemLoader.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CFileInputStream.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+    <ClInclude Include="filesystem\CFileInfo.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <Filter Include="rmg">
+      <UniqueIdentifier>{3d02cdc5-d660-4937-8753-9633a07ad25a}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="mapping">
+      <UniqueIdentifier>{00f77034-143f-4867-b422-c16e9f2bd3cb}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="logging">
+      <UniqueIdentifier>{e967e59c-781a-4794-9382-4a7a6d166cbf}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="filesystem">
+      <UniqueIdentifier>{96f9ac5c-05d9-43ae-b715-a1e6234075cd}</UniqueIdentifier>
+    </Filter>
+  </ItemGroup>
+</Project>

+ 7 - 15
lib/mapping/CMapEditManager.cpp

@@ -4,6 +4,7 @@
 #include "../JsonNode.h"
 #include "../filesystem/Filesystem.h"
 #include "../CDefObjInfoHandler.h"
+#include "../VCMI_Lib.h"
 
 MapRect::MapRect() : x(0), y(0), z(0), width(0), height(0)
 {
@@ -304,15 +305,6 @@ bool TerrainViewPattern::WeightedRule::isStandardRule() const
 		|| TerrainViewPattern::RULE_TRANSITION == name || TerrainViewPattern::RULE_NATIVE_STRONG == name;
 }
 
-boost::mutex CTerrainViewPatternConfig::smx;
-
-CTerrainViewPatternConfig & CTerrainViewPatternConfig::get()
-{
-	TLockGuard _(smx);
-	static CTerrainViewPatternConfig instance;
-	return instance;
-}
-
 CTerrainViewPatternConfig::CTerrainViewPatternConfig()
 {
 	const JsonNode config(ResourceID("config/terrainViewPatterns.json"));
@@ -565,7 +557,7 @@ void CDrawTerrainOperation::updateTerrainViews()
 	for(const auto & pos : invalidatedTerViews)
 	{
 		const auto & patterns =
-				CTerrainViewPatternConfig::get().getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType));
+				VLC->terviewh->getTerrainViewPatternsForGroup(getTerrainGroup(map->getTile(pos).terType));
 
 		// Detect a pattern which fits best
 		int bestPattern = -1;
@@ -696,7 +688,7 @@ CDrawTerrainOperation::ValidationResult CDrawTerrainOperation::validateTerrainVi
 				{
 					if(terType == centerTerType)
 					{
-						const auto & patternForRule = CTerrainViewPatternConfig::get().getTerrainViewPatternById(getTerrainGroup(centerTerType), rule.name);
+						const auto & patternForRule = VLC->terviewh->getTerrainViewPatternById(getTerrainGroup(centerTerType), rule.name);
 						if(patternForRule)
 						{
 							auto rslt = validateTerrainView(currentPos, *patternForRule, 1);
@@ -841,9 +833,9 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 	{
 		if(map->isInTheMap(pos))
 		{
-			auto & ptrConfig = CTerrainViewPatternConfig::get();
+			auto ptrConfig = VLC->terviewh;
 			auto terType = map->getTile(pos).terType;
-			auto valid = validateTerrainView(pos, ptrConfig.getTerrainTypePatternById("n1")).result;
+			auto valid = validateTerrainView(pos, ptrConfig->getTerrainTypePatternById("n1")).result;
 
 			// Special validity check for rock & water
 			if(valid && centerTerType != terType && (terType == ETerrainType::WATER || terType == ETerrainType::ROCK))
@@ -851,7 +843,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 				static const std::string patternIds[] = { "s1", "s2" };
 				for(auto & patternId : patternIds)
 				{
-					valid = !validateTerrainView(pos, ptrConfig.getTerrainTypePatternById(patternId)).result;
+					valid = !validateTerrainView(pos, ptrConfig->getTerrainTypePatternById(patternId)).result;
 					if(!valid) break;
 				}
 			}
@@ -861,7 +853,7 @@ CDrawTerrainOperation::InvalidTiles CDrawTerrainOperation::getInvalidTiles(const
 				static const std::string patternIds[] = { "n2", "n3" };
 				for(auto & patternId : patternIds)
 				{
-					valid = validateTerrainView(pos, ptrConfig.getTerrainTypePatternById(patternId)).result;
+					valid = validateTerrainView(pos, ptrConfig->getTerrainTypePatternById(patternId)).result;
 					if(valid) break;
 				}
 			}

+ 2 - 5
lib/mapping/CMapEditManager.h

@@ -279,7 +279,8 @@ struct DLL_LINKAGE TerrainViewPattern
 class DLL_LINKAGE CTerrainViewPatternConfig : public boost::noncopyable
 {
 public:
-	static CTerrainViewPatternConfig & get();
+	CTerrainViewPatternConfig();
+	~CTerrainViewPatternConfig();
 
 	const std::vector<TerrainViewPattern> & getTerrainViewPatternsForGroup(ETerrainGroup::ETerrainGroup terGroup) const;
 	boost::optional<const TerrainViewPattern &> getTerrainViewPatternById(ETerrainGroup::ETerrainGroup terGroup, const std::string & id) const;
@@ -287,12 +288,8 @@ public:
 	ETerrainGroup::ETerrainGroup getTerrainGroup(const std::string & terGroup) const;
 
 private:
-	CTerrainViewPatternConfig();
-	~CTerrainViewPatternConfig();
-
 	std::map<ETerrainGroup::ETerrainGroup, std::vector<TerrainViewPattern> > terrainViewPatterns;
 	std::map<std::string, TerrainViewPattern> terrainTypePatterns;
-	static boost::mutex smx;
 };
 
 /// The CDrawTerrainOperation class draws a terrain area on the map.

+ 410 - 0
lib/rmg/CMapGenOptions.cpp

@@ -0,0 +1,410 @@
+
+/*
+ * CMapGenOptions.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CMapGenOptions.h"
+
+#include "../GameConstants.h"
+#include "../mapping/CMap.h"
+#include "CRmgTemplateStorage.h"
+#include "CRmgTemplate.h"
+#include "../VCMI_Lib.h"
+#include "../CTownHandler.h"
+
+CMapGenOptions::CMapGenOptions() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), hasTwoLevels(false),
+	playerCount(RANDOM_SIZE), teamCount(RANDOM_SIZE), compOnlyPlayerCount(0), compOnlyTeamCount(RANDOM_SIZE),
+	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM), mapTemplate(nullptr)
+{
+	resetPlayersMap();
+}
+
+si32 CMapGenOptions::getWidth() const
+{
+	return width;
+}
+
+void CMapGenOptions::setWidth(si32 value)
+{
+	assert(value >= 1);
+	width = value;
+}
+
+si32 CMapGenOptions::getHeight() const
+{
+	return height;
+}
+
+void CMapGenOptions::setHeight(si32 value)
+{
+	assert(value >= 1);
+	height = value;
+}
+
+bool CMapGenOptions::getHasTwoLevels() const
+{
+	return hasTwoLevels;
+}
+
+void CMapGenOptions::setHasTwoLevels(bool value)
+{
+	hasTwoLevels = value;
+}
+
+si8 CMapGenOptions::getPlayerCount() const
+{
+	return playerCount;
+}
+
+void CMapGenOptions::setPlayerCount(si8 value)
+{
+	assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
+	playerCount = value;
+	resetPlayersMap();
+}
+
+si8 CMapGenOptions::getTeamCount() const
+{
+	return teamCount;
+}
+
+void CMapGenOptions::setTeamCount(si8 value)
+{
+	assert(playerCount == RANDOM_SIZE || (value >= 0 && value < playerCount) || value == RANDOM_SIZE);
+	teamCount = value;
+}
+
+si8 CMapGenOptions::getCompOnlyPlayerCount() const
+{
+	return compOnlyPlayerCount;
+}
+
+void CMapGenOptions::setCompOnlyPlayerCount(si8 value)
+{
+	assert(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playerCount));
+	compOnlyPlayerCount = value;
+	resetPlayersMap();
+}
+
+si8 CMapGenOptions::getCompOnlyTeamCount() const
+{
+	return compOnlyTeamCount;
+}
+
+void CMapGenOptions::setCompOnlyTeamCount(si8 value)
+{
+	assert(value == RANDOM_SIZE || compOnlyPlayerCount == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayerCount - 1, 0)));
+	compOnlyTeamCount = value;
+}
+
+EWaterContent::EWaterContent CMapGenOptions::getWaterContent() const
+{
+	return waterContent;
+}
+
+void CMapGenOptions::setWaterContent(EWaterContent::EWaterContent value)
+{
+	waterContent = value;
+}
+
+EMonsterStrength::EMonsterStrength CMapGenOptions::getMonsterStrength() const
+{
+	return monsterStrength;
+}
+
+void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value)
+{
+	monsterStrength = value;
+}
+
+void CMapGenOptions::resetPlayersMap()
+{
+	players.clear();
+	int realPlayersCnt = playerCount == RANDOM_SIZE ? static_cast<int>(PlayerColor::PLAYER_LIMIT_I) : playerCount;
+	int realCompOnlyPlayersCnt = compOnlyPlayerCount == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayerCount;
+	for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
+	{
+		CPlayerSettings player;
+		player.setColor(PlayerColor(color));
+		player.setPlayerType((color >= realPlayersCnt) ? EPlayerType::COMP_ONLY : EPlayerType::AI);
+		players[PlayerColor(color)] = player;
+	}
+}
+
+const std::map<PlayerColor, CMapGenOptions::CPlayerSettings> & CMapGenOptions::getPlayersSettings() const
+{
+	return players;
+}
+
+void CMapGenOptions::setStartingTownForPlayer(PlayerColor color, si32 town)
+{
+	auto it = players.find(color);
+	if(it == players.end()) assert(0);
+	it->second.setStartingTown(town);
+}
+
+void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
+{
+	assert(playerType != EPlayerType::COMP_ONLY);
+	auto it = players.find(color);
+	if(it == players.end()) assert(0);
+	it->second.setPlayerType(playerType);
+}
+
+const CRmgTemplate * CMapGenOptions::getMapTemplate() const
+{
+	return mapTemplate;
+}
+
+void CMapGenOptions::setMapTemplate(const CRmgTemplate * value)
+{
+	mapTemplate = value;
+	//TODO validate & adapt options according to template
+	assert(0);
+}
+
+const std::map<std::string, CRmgTemplate *> & CMapGenOptions::getAvailableTemplates() const
+{
+	return VLC->tplh->getTemplates();
+}
+
+void CMapGenOptions::finalize()
+{
+	CRandomGenerator gen;
+	finalize(gen);
+}
+
+void CMapGenOptions::finalize(CRandomGenerator & gen)
+{
+	if(!mapTemplate)
+	{
+		mapTemplate = getPossibleTemplate(gen);
+		assert(mapTemplate);
+	}
+
+	if(playerCount == RANDOM_SIZE)
+	{
+		auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
+		possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
+		assert(!possiblePlayers.empty());
+		playerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
+		updatePlayers();
+	}
+	if(teamCount == RANDOM_SIZE)
+	{
+		teamCount = gen.getInteger(0, playerCount - 1);
+	}
+	if(compOnlyPlayerCount == RANDOM_SIZE)
+	{
+		auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
+		compOnlyPlayerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
+		updateCompOnlyPlayers();
+	}
+	if(compOnlyTeamCount == RANDOM_SIZE)
+	{
+		compOnlyTeamCount = gen.getInteger(0, std::max(compOnlyPlayerCount - 1, 0));
+	}
+
+	// 1 team isn't allowed
+	if(teamCount == 1 && compOnlyPlayerCount == 0)
+	{
+		teamCount = 0;
+	}
+
+	if(waterContent == EWaterContent::RANDOM)
+	{
+		waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
+	}
+	if(monsterStrength == EMonsterStrength::RANDOM)
+	{
+		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
+	}
+}
+
+void CMapGenOptions::updatePlayers()
+{
+	// Remove AI players only from the end of the players map if necessary
+	for(auto itrev = players.end(); itrev != players.begin();)
+	{
+		auto it = itrev;
+		--it;
+		if(players.size() == playerCount) break;
+		if(it->second.getPlayerType() == EPlayerType::AI)
+		{
+			players.erase(it);
+		}
+		else
+		{
+			--itrev;
+		}
+	}
+}
+
+void CMapGenOptions::updateCompOnlyPlayers()
+{
+	auto totalPlayersCnt = playerCount + compOnlyPlayerCount;
+
+	// Remove comp only players only from the end of the players map if necessary
+	for(auto itrev = players.end(); itrev != players.begin();)
+	{
+		auto it = itrev;
+		--it;
+		if(players.size() <= totalPlayersCnt) break;
+		if(it->second.getPlayerType() == EPlayerType::COMP_ONLY)
+		{
+			players.erase(it);
+		}
+		else
+		{
+			--itrev;
+		}
+	}
+
+	// Add some comp only players if necessary
+	auto compOnlyPlayersToAdd = totalPlayersCnt - players.size();
+	for(int i = 0; i < compOnlyPlayersToAdd; ++i)
+	{
+		CPlayerSettings pSettings;
+		pSettings.setPlayerType(EPlayerType::COMP_ONLY);
+		pSettings.setColor(getNextPlayerColor());
+		players[pSettings.getColor()] = pSettings;
+	}
+}
+
+int CMapGenOptions::countHumanPlayers() const
+{
+	return static_cast<int>(boost::count_if(players, [](const std::pair<PlayerColor, CPlayerSettings> & pair)
+	{
+		return pair.second.getPlayerType() == EPlayerType::HUMAN;
+	}));
+}
+
+PlayerColor CMapGenOptions::getNextPlayerColor() const
+{
+	for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1))
+	{
+		if(!players.count(i))
+		{
+			return i;
+		}
+	}
+	assert(0);
+	return PlayerColor(0);
+}
+
+bool CMapGenOptions::checkOptions() const
+{
+	assert(countHumanPlayers() > 0);
+	if(mapTemplate)
+	{
+		return true;
+	}
+	else
+	{
+		CRandomGenerator gen;
+		return getPossibleTemplate(gen) != nullptr;
+	}
+}
+
+const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen) const
+{
+	// Find potential templates
+	const auto & tpls = getAvailableTemplates();
+	std::list<const CRmgTemplate *> potentialTpls;
+	for(const auto & tplPair : tpls)
+	{
+		const auto & tpl = tplPair.second;
+		CRmgTemplate::CSize tplSize(width, height, hasTwoLevels);
+		if(tplSize >= tpl->getMinSize() && tplSize <= tpl->getMaxSize())
+		{
+			bool isPlayerCountValid = false;
+			if(playerCount != RANDOM_SIZE)
+			{
+				if(tpl->getPlayers().isInRange(playerCount)) isPlayerCountValid = true;
+			}
+			else
+			{
+				// Human players shouldn't be banned when playing with random player count
+				auto playerNumbers = tpl->getPlayers().getNumbers();
+				if(playerNumbers.lower_bound(countHumanPlayers()) != playerNumbers.end())
+				{
+					isPlayerCountValid = true;
+				}
+			}
+
+			if(isPlayerCountValid)
+			{
+				bool isCpuPlayerCountValid = false;
+				if(compOnlyPlayerCount != RANDOM_SIZE)
+				{
+					if(tpl->getCpuPlayers().isInRange(compOnlyPlayerCount)) isCpuPlayerCountValid = true;
+				}
+				else
+				{
+					isCpuPlayerCountValid = true;
+				}
+
+				if(isCpuPlayerCountValid) potentialTpls.push_back(tpl);
+			}
+		}
+	}
+
+	// Select tpl
+	if(potentialTpls.empty())
+	{
+		return nullptr;
+	}
+	else
+	{
+		return *std::next(potentialTpls.begin(), gen.getInteger(0, potentialTpls.size() - 1));
+	}
+}
+
+CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
+{
+
+}
+
+PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
+{
+	return color;
+}
+
+void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
+{
+	assert(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT);
+	color = value;
+}
+
+si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
+{
+	return startingTown;
+}
+
+void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
+{
+	assert(value >= -1);
+	if(value >= 0)
+	{
+		assert(value < static_cast<int>(VLC->townh->factions.size()));
+		assert(VLC->townh->factions[value]->town != nullptr);
+	}
+	startingTown = value;
+}
+
+EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
+{
+	return playerType;
+}
+
+void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
+{
+	playerType = value;
+}

+ 177 - 0
lib/rmg/CMapGenOptions.h

@@ -0,0 +1,177 @@
+
+/*
+ * CMapGenOptions.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include "../GameConstants.h"
+#include "../CRandomGenerator.h"
+
+class CRmgTemplate;
+
+namespace EWaterContent
+{
+enum EWaterContent
+{
+	RANDOM = -1,
+	NONE,
+	NORMAL,
+	ISLANDS
+};
+}
+
+namespace EMonsterStrength
+{
+enum EMonsterStrength
+{
+	RANDOM = -1,
+	WEAK,
+	NORMAL,
+	STRONG
+};
+}
+
+namespace EPlayerType
+{
+enum EPlayerType
+{
+	HUMAN,
+	AI,
+	COMP_ONLY
+};
+}
+
+/// The map gen options class holds values about general map generation settings
+/// e.g. the size of the map, the count of players,...
+class DLL_LINKAGE CMapGenOptions
+{
+public:
+	/// The player settings class maps the player color, starting town and human player flag.
+	class DLL_LINKAGE CPlayerSettings
+	{
+	public:
+		CPlayerSettings();
+
+		/// The color of the player ranging from 0 to PlayerColor::PLAYER_LIMIT - 1.
+		/// The default value is 0.
+		PlayerColor getColor() const;
+		void setColor(PlayerColor value);
+
+		/// The starting town of the player ranging from 0 to town max count or RANDOM_TOWN.
+		/// The default value is RANDOM_TOWN.
+		si32 getStartingTown() const;
+		void setStartingTown(si32 value);
+
+		/// The default value is EPlayerType::AI.
+		EPlayerType::EPlayerType getPlayerType() const;
+		void setPlayerType(EPlayerType::EPlayerType value);
+
+		/// Constant for a random town selection.
+		static const si32 RANDOM_TOWN = -1;
+
+	private:
+		PlayerColor color;
+		si32 startingTown;
+		EPlayerType::EPlayerType playerType;
+
+	public:
+		template <typename Handler>
+		void serialize(Handler & h, const int version)
+		{
+			h & color & startingTown & playerType;
+		}
+	};
+
+	CMapGenOptions();
+
+	si32 getWidth() const;
+	void setWidth(si32 value);
+
+	si32 getHeight() const;
+	void setHeight(si32 value);
+
+	bool getHasTwoLevels() const;
+	void setHasTwoLevels(bool value);
+
+	/// The count of the players ranging from 1 to PlayerColor::PLAYER_LIMIT or RANDOM_SIZE for random. If you call
+	/// this method, all player settings are reset to default settings.
+	si8 getPlayerCount() const;
+	void setPlayerCount(si8 value);
+
+	/// The count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random.
+	si8 getTeamCount() const;
+	void setTeamCount(si8 value);
+
+	/// The count of the computer only players ranging from 0 to <PlayerColor::PLAYER_LIMIT - players count> or RANDOM_SIZE for random.
+	/// If you call this method, all player settings are reset to default settings.
+	si8 getCompOnlyPlayerCount() const;
+	void setCompOnlyPlayerCount(si8 value);
+
+	/// The count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random.
+	si8 getCompOnlyTeamCount() const;
+	void setCompOnlyTeamCount(si8 value);
+
+	EWaterContent::EWaterContent getWaterContent() const;
+	void setWaterContent(EWaterContent::EWaterContent value);
+
+	EMonsterStrength::EMonsterStrength getMonsterStrength() const;
+	void setMonsterStrength(EMonsterStrength::EMonsterStrength value);
+
+	/// The first player colors belong to standard players and the last player colors belong to comp only players.
+	/// All standard players are by default of type EPlayerType::AI.
+	const std::map<PlayerColor, CPlayerSettings> & getPlayersSettings() const;
+	void setStartingTownForPlayer(PlayerColor color, si32 town);
+	/// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The
+	/// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN.
+	void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType);
+
+	/// The random map template to generate the map with or empty/not set if the template should be chosen randomly.
+	/// Default: Not set/random.
+	const CRmgTemplate * getMapTemplate() const;
+	void setMapTemplate(const CRmgTemplate * value);
+
+	const std::map<std::string, CRmgTemplate *> & getAvailableTemplates() const;
+
+	/// Finalizes the options. All random sizes for various properties will be overwritten by numbers from
+	/// a random number generator by keeping the options in a valid state. Check options should return true, otherwise
+	/// this function fails.
+	void finalize();
+	void finalize(CRandomGenerator & gen);
+
+	/// Returns false if there is no template available which fits to the currently selected options.
+	bool checkOptions() const;
+
+	static const si8 RANDOM_SIZE = -1;
+
+private:
+	void resetPlayersMap();
+	int countHumanPlayers() const;
+	PlayerColor getNextPlayerColor() const;
+	void updateCompOnlyPlayers();
+	void updatePlayers();
+	const CRmgTemplate * getPossibleTemplate(CRandomGenerator & gen) const;
+
+	si32 width, height;
+	bool hasTwoLevels;
+	si8 playerCount, teamCount, compOnlyPlayerCount, compOnlyTeamCount;
+	EWaterContent::EWaterContent waterContent;
+	EMonsterStrength::EMonsterStrength monsterStrength;
+	std::map<PlayerColor, CPlayerSettings> players;
+	const CRmgTemplate * mapTemplate;
+
+public:
+	template <typename Handler>
+	void serialize(Handler & h, const int version)
+	{
+		h & width & height & hasTwoLevels & playerCount & teamCount & compOnlyPlayerCount;
+		h & compOnlyTeamCount & waterContent & monsterStrength & players;
+		//TODO add name of template to class, enables selection of a template by a user
+	}
+};

+ 12 - 1025
lib/rmg/CMapGenerator.cpp

@@ -1,3 +1,14 @@
+
+/*
+ * CMapGenerator.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
 #include "StdInc.h"
 #include "CMapGenerator.h"
 
@@ -9,397 +20,7 @@
 #include "../CDefObjInfoHandler.h"
 #include "../CTownHandler.h"
 #include "../StringConstants.h"
-#include "../filesystem/Filesystem.h"
-
-CMapGenOptions::CMapGenOptions() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), hasTwoLevels(false),
-	playerCount(RANDOM_SIZE), teamCount(RANDOM_SIZE), compOnlyPlayerCount(0), compOnlyTeamCount(RANDOM_SIZE),
-	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM), mapTemplate(nullptr)
-{
-	resetPlayersMap();
-}
-
-si32 CMapGenOptions::getWidth() const
-{
-	return width;
-}
-
-void CMapGenOptions::setWidth(si32 value)
-{
-	assert(value >= 1);
-	width = value;
-}
-
-si32 CMapGenOptions::getHeight() const
-{
-	return height;
-}
-
-void CMapGenOptions::setHeight(si32 value)
-{
-	assert(value >= 1);
-	height = value;
-}
-
-bool CMapGenOptions::getHasTwoLevels() const
-{
-	return hasTwoLevels;
-}
-
-void CMapGenOptions::setHasTwoLevels(bool value)
-{
-	hasTwoLevels = value;
-}
-
-si8 CMapGenOptions::getPlayerCount() const
-{
-	return playerCount;
-}
-
-void CMapGenOptions::setPlayerCount(si8 value)
-{
-	assert((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE);
-	playerCount = value;
-	resetPlayersMap();
-}
-
-si8 CMapGenOptions::getTeamCount() const
-{
-	return teamCount;
-}
-
-void CMapGenOptions::setTeamCount(si8 value)
-{
-	assert(playerCount == RANDOM_SIZE || (value >= 0 && value < playerCount) || value == RANDOM_SIZE);
-	teamCount = value;
-}
-
-si8 CMapGenOptions::getCompOnlyPlayerCount() const
-{
-	return compOnlyPlayerCount;
-}
-
-void CMapGenOptions::setCompOnlyPlayerCount(si8 value)
-{
-	assert(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playerCount));
-	compOnlyPlayerCount = value;
-	resetPlayersMap();
-}
-
-si8 CMapGenOptions::getCompOnlyTeamCount() const
-{
-	return compOnlyTeamCount;
-}
-
-void CMapGenOptions::setCompOnlyTeamCount(si8 value)
-{
-	assert(value == RANDOM_SIZE || compOnlyPlayerCount == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayerCount - 1, 0)));
-	compOnlyTeamCount = value;
-}
-
-EWaterContent::EWaterContent CMapGenOptions::getWaterContent() const
-{
-	return waterContent;
-}
-
-void CMapGenOptions::setWaterContent(EWaterContent::EWaterContent value)
-{
-	waterContent = value;
-}
-
-EMonsterStrength::EMonsterStrength CMapGenOptions::getMonsterStrength() const
-{
-	return monsterStrength;
-}
-
-void CMapGenOptions::setMonsterStrength(EMonsterStrength::EMonsterStrength value)
-{
-	monsterStrength = value;
-}
-
-void CMapGenOptions::resetPlayersMap()
-{
-	players.clear();
-	int realPlayersCnt = playerCount == RANDOM_SIZE ? static_cast<int>(PlayerColor::PLAYER_LIMIT_I) : playerCount;
-	int realCompOnlyPlayersCnt = compOnlyPlayerCount == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayerCount;
-	for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
-	{
-		CPlayerSettings player;
-		player.setColor(PlayerColor(color));
-		player.setPlayerType((color >= realPlayersCnt) ? EPlayerType::COMP_ONLY : EPlayerType::AI);
-		players[PlayerColor(color)] = player;
-	}
-}
-
-const std::map<PlayerColor, CMapGenOptions::CPlayerSettings> & CMapGenOptions::getPlayersSettings() const
-{
-	return players;
-}
-
-void CMapGenOptions::setStartingTownForPlayer(PlayerColor color, si32 town)
-{
-	auto it = players.find(color);
-	if(it == players.end()) assert(0);
-	it->second.setStartingTown(town);
-}
-
-void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
-{
-	assert(playerType != EPlayerType::COMP_ONLY);
-	auto it = players.find(color);
-	if(it == players.end()) assert(0);
-	it->second.setPlayerType(playerType);
-}
-
-const CRmgTemplate * CMapGenOptions::getMapTemplate() const
-{
-	return mapTemplate;
-}
-
-void CMapGenOptions::setMapTemplate(const CRmgTemplate * value)
-{
-    mapTemplate = value;
-	//TODO validate & adapt options according to template
-	assert(0);
-}
-
-const std::map<std::string, CRmgTemplate> & CMapGenOptions::getAvailableTemplates() const
-{
-	return CRmgTemplateStorage::get().getTemplates();
-}
-
-void CMapGenOptions::finalize()
-{
-	CRandomGenerator gen;
-	finalize(gen);
-}
-
-void CMapGenOptions::finalize(CRandomGenerator & gen)
-{
-	if(!mapTemplate)
-	{
-		mapTemplate = getPossibleTemplate(gen);
-		assert(mapTemplate);
-	}
-
-	if(playerCount == RANDOM_SIZE)
-	{
-		auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
-		possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
-		assert(!possiblePlayers.empty());
-		playerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
-		updatePlayers();
-	}
-	if(teamCount == RANDOM_SIZE)
-	{
-		teamCount = gen.getInteger(0, playerCount - 1);
-	}
-	if(compOnlyPlayerCount == RANDOM_SIZE)
-	{
-		auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
-		compOnlyPlayerCount = *std::next(possiblePlayers.begin(), gen.getInteger(0, possiblePlayers.size() - 1));
-		updateCompOnlyPlayers();
-	}
-	if(compOnlyTeamCount == RANDOM_SIZE)
-	{
-		compOnlyTeamCount = gen.getInteger(0, std::max(compOnlyPlayerCount - 1, 0));
-	}
-
-	// 1 team isn't allowed
-	if(teamCount == 1 && compOnlyPlayerCount == 0)
-	{
-		teamCount = 0;
-	}
-
-	if(waterContent == EWaterContent::RANDOM)
-	{
-		waterContent = static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2));
-	}
-	if(monsterStrength == EMonsterStrength::RANDOM)
-	{
-		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2));
-	}
-}
-
-void CMapGenOptions::updatePlayers()
-{
-	// Remove AI players only from the end of the players map if necessary
-	for(auto itrev = players.end(); itrev != players.begin();)
-	{
-		auto it = itrev;
-		--it;
-		if(players.size() == playerCount) break;
-		if(it->second.getPlayerType() == EPlayerType::AI)
-		{
-			players.erase(it);
-		}
-		else
-		{
-			--itrev;
-		}
-	}
-}
-
-void CMapGenOptions::updateCompOnlyPlayers()
-{
-	auto totalPlayersCnt = playerCount + compOnlyPlayerCount;
-
-	// Remove comp only players only from the end of the players map if necessary
-	for(auto itrev = players.end(); itrev != players.begin();)
-	{
-		auto it = itrev;
-		--it;
-		if(players.size() <= totalPlayersCnt) break;
-		if(it->second.getPlayerType() == EPlayerType::COMP_ONLY)
-		{
-			players.erase(it);
-		}
-		else
-		{
-			--itrev;
-		}
-	}
-
-	// Add some comp only players if necessary
-	auto compOnlyPlayersToAdd = totalPlayersCnt - players.size();
-	for(int i = 0; i < compOnlyPlayersToAdd; ++i)
-	{
-		CPlayerSettings pSettings;
-		pSettings.setPlayerType(EPlayerType::COMP_ONLY);
-		pSettings.setColor(getNextPlayerColor());
-		players[pSettings.getColor()] = pSettings;
-	}
-}
-
-int CMapGenOptions::countHumanPlayers() const
-{
-	return static_cast<int>(boost::count_if(players, [](const std::pair<PlayerColor, CPlayerSettings> & pair)
-	{
-		return pair.second.getPlayerType() == EPlayerType::HUMAN;
-	}));
-}
-
-PlayerColor CMapGenOptions::getNextPlayerColor() const
-{
-	for(PlayerColor i = PlayerColor(0); i < PlayerColor::PLAYER_LIMIT; i.advance(1))
-	{
-		if(!players.count(i))
-		{
-			return i;
-		}
-	}
-	assert(0);
-	return PlayerColor(0);
-}
-
-bool CMapGenOptions::checkOptions() const
-{
-	assert(countHumanPlayers() > 0);
-	if(mapTemplate)
-	{
-		return true;
-	}
-	else
-	{
-		CRandomGenerator gen;
-		return getPossibleTemplate(gen) != nullptr;
-	}
-}
-
-const CRmgTemplate * CMapGenOptions::getPossibleTemplate(CRandomGenerator & gen) const
-{
-	// Find potential templates
-	const auto & tpls = getAvailableTemplates();
-	std::list<const CRmgTemplate *> potentialTpls;
-	for(const auto & tplPair : tpls)
-	{
-		const auto & tpl = tplPair.second;
-		CRmgTemplate::CSize tplSize(width, height, hasTwoLevels);
-		if(tplSize >= tpl.getMinSize() && tplSize <= tpl.getMaxSize())
-		{
-			bool isPlayerCountValid = false;
-			if(playerCount != RANDOM_SIZE)
-			{
-				if(tpl.getPlayers().isInRange(playerCount)) isPlayerCountValid = true;
-			}
-			else
-			{
-				// Human players shouldn't be banned when playing with random player count
-				auto playerNumbers = tpl.getPlayers().getNumbers();
-				if(playerNumbers.lower_bound(countHumanPlayers()) != playerNumbers.end())
-				{
-					isPlayerCountValid = true;
-				}
-			}
-
-			if(isPlayerCountValid)
-			{
-				bool isCpuPlayerCountValid = false;
-				if(compOnlyPlayerCount != RANDOM_SIZE)
-				{
-					if(tpl.getCpuPlayers().isInRange(compOnlyPlayerCount)) isCpuPlayerCountValid = true;
-				}
-				else
-				{
-					isCpuPlayerCountValid = true;
-				}
-
-				if(isCpuPlayerCountValid) potentialTpls.push_back(&tpl);
-			}
-		}
-	}
-
-	// Select tpl
-	if(potentialTpls.empty())
-	{
-		return nullptr;
-	}
-	else
-	{
-		return *std::next(potentialTpls.begin(), gen.getInteger(0, potentialTpls.size() - 1));
-	}
-}
-
-CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
-{
-
-}
-
-PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
-{
-	return color;
-}
-
-void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
-{
-	assert(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT);
-	color = value;
-}
-
-si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
-{
-	return startingTown;
-}
-
-void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
-{
-	assert(value >= -1);
-	if(value >= 0)
-	{
-		assert(value < static_cast<int>(VLC->townh->factions.size()));
-		assert(VLC->townh->factions[value]->town != nullptr);
-	}
-	startingTown = value;
-}
-
-EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
-{
-	return playerType;
-}
-
-void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
-{
-	playerType = value;
-}
+#include "CRmgTemplate.h"
 
 CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
 	mapGenOptions(mapGenOptions), randomSeed(randomSeed)
@@ -563,637 +184,3 @@ void CMapGenerator::addHeaderInfo()
 	map->difficulty = 1;
 	addPlayerInfo();
 }
-
-CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
-{
-
-}
-
-int CRmgTemplateZone::CTownInfo::getTownCount() const
-{
-	return townCount;
-}
-
-void CRmgTemplateZone::CTownInfo::setTownCount(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for town count not allowed.");
-	townCount = value;
-}
-
-int CRmgTemplateZone::CTownInfo::getCastleCount() const
-{
-	return castleCount;
-}
-
-void CRmgTemplateZone::CTownInfo::setCastleCount(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for castle count not allowed.");
-	castleCount = value;
-}
-
-int CRmgTemplateZone::CTownInfo::getTownDensity() const
-{
-	return townDensity;
-}
-
-void CRmgTemplateZone::CTownInfo::setTownDensity(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for town density not allowed.");
-	townDensity = value;
-}
-
-int CRmgTemplateZone::CTownInfo::getCastleDensity() const
-{
-	return castleDensity;
-}
-
-void CRmgTemplateZone::CTownInfo::setCastleDensity(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for castle density not allowed.");
-	castleDensity = value;
-}
-
-CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
-	townsAreSameType(false), matchTerrainToTown(true)
-{
-	townTypes = getDefaultTownTypes();
-	terrainTypes = getDefaultTerrainTypes();
-}
-
-TRmgTemplateZoneId CRmgTemplateZone::getId() const
-{
-	return id;
-}
-
-void CRmgTemplateZone::setId(TRmgTemplateZoneId value)
-{
-	if(value <= 0) throw std::runtime_error("Zone id should be greater than 0.");
-	id = value;
-}
-
-ETemplateZoneType::ETemplateZoneType CRmgTemplateZone::getType() const
-{
-	return type;
-}
-void CRmgTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value)
-{
-	type = value;
-}
-
-int CRmgTemplateZone::getSize() const
-{
-	return size;
-}
-
-void CRmgTemplateZone::setSize(int value)
-{
-	if(value <= 0) throw std::runtime_error("Zone size needs to be greater than 0.");
-	size = value;
-}
-
-boost::optional<int> CRmgTemplateZone::getOwner() const
-{
-	return owner;
-}
-
-void CRmgTemplateZone::setOwner(boost::optional<int> value)
-{
-	if(!(*value >= 0 && *value <= PlayerColor::PLAYER_LIMIT_I)) throw std::runtime_error("Owner has to be in range 0 to max player count.");
-	owner = value;
-}
-
-const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getPlayerTowns() const
-{
-	return playerTowns;
-}
-
-void CRmgTemplateZone::setPlayerTowns(const CTownInfo & value)
-{
-	playerTowns = value;
-}
-
-const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getNeutralTowns() const
-{
-	return neutralTowns;
-}
-
-void CRmgTemplateZone::setNeutralTowns(const CTownInfo & value)
-{
-	neutralTowns = value;
-}
-
-bool CRmgTemplateZone::getTownsAreSameType() const
-{
-	return townsAreSameType;
-}
-
-void CRmgTemplateZone::setTownsAreSameType(bool value)
-{
-	townsAreSameType = value;
-}
-
-const std::set<TFaction> & CRmgTemplateZone::getTownTypes() const
-{
-	return townTypes;
-}
-
-void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
-{
-	townTypes = value;
-}
-
-std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
-{
-	std::set<TFaction> defaultTowns;
-	auto towns = VLC->townh->getDefaultAllowed();
-	for(int i = 0; i < towns.size(); ++i)
-	{
-		if(towns[i]) defaultTowns.insert(i);
-	}
-	return defaultTowns;
-}
-
-bool CRmgTemplateZone::getMatchTerrainToTown() const
-{
-	return matchTerrainToTown;
-}
-
-void CRmgTemplateZone::setMatchTerrainToTown(bool value)
-{
-	matchTerrainToTown = value;
-}
-
-const std::set<ETerrainType> & CRmgTemplateZone::getTerrainTypes() const
-{
-	return terrainTypes;
-}
-
-void CRmgTemplateZone::setTerrainTypes(const std::set<ETerrainType> & value)
-{
-	assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
-		   value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
-	terrainTypes = value;
-}
-
-std::set<ETerrainType> CRmgTemplateZone::getDefaultTerrainTypes() const
-{
-	std::set<ETerrainType> terTypes;
-	static const ETerrainType::EETerrainType allowedTerTypes[] = { ETerrainType::DIRT, ETerrainType::SAND, ETerrainType::GRASS, ETerrainType::SNOW,
-												   ETerrainType::SWAMP, ETerrainType::ROUGH, ETerrainType::SUBTERRANEAN, ETerrainType::LAVA };
-	for(auto & allowedTerType : allowedTerTypes) terTypes.insert(allowedTerType);
-	return terTypes;
-}
-
-boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTerrainTypeLikeZone() const
-{
-	return terrainTypeLikeZone;
-}
-
-void CRmgTemplateZone::setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
-{
-	terrainTypeLikeZone = value;
-}
-
-boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTownTypeLikeZone() const
-{
-	return townTypeLikeZone;
-}
-
-void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
-{
-	townTypeLikeZone = value;
-}
-
-CRmgTemplateZoneConnection::CRmgTemplateZoneConnection() : zoneA(0), zoneB(0), guardStrength(0)
-{
-
-}
-
-TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneA() const
-{
-	return zoneA;
-}
-
-void CRmgTemplateZoneConnection::setZoneA(TRmgTemplateZoneId value)
-{
-	zoneA = value;
-}
-
-TRmgTemplateZoneId CRmgTemplateZoneConnection::getZoneB() const
-{
-	return zoneB;
-}
-
-void CRmgTemplateZoneConnection::setZoneB(TRmgTemplateZoneId value)
-{
-	zoneB = value;
-}
-
-int CRmgTemplateZoneConnection::getGuardStrength() const
-{
-	return guardStrength;
-}
-
-void CRmgTemplateZoneConnection::setGuardStrength(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for guard strenth not allowed.");
-	guardStrength = value;
-}
-
-CRmgTemplate::CSize::CSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true)
-{
-
-}
-
-CRmgTemplate::CSize::CSize(int width, int height, bool under) : under(under)
-{
-	setWidth(width);
-	setHeight(height);
-}
-
-int CRmgTemplate::CSize::getWidth() const
-{
-	return width;
-}
-
-void CRmgTemplate::CSize::setWidth(int value)
-{
-	if(value <= 0) throw std::runtime_error("Width > 0 failed.");
-	width = value;
-}
-
-int CRmgTemplate::CSize::getHeight() const
-{
-	return height;
-}
-
-void CRmgTemplate::CSize::setHeight(int value)
-{
-	if(value <= 0) throw std::runtime_error("Height > 0 failed.");
-	height = value;
-}
-
-bool CRmgTemplate::CSize::getUnder() const
-{
-	return under;
-}
-
-void CRmgTemplate::CSize::setUnder(bool value)
-{
-	under = value;
-}
-
-bool CRmgTemplate::CSize::operator<=(const CSize & value) const
-{
-	if(width < value.width && height < value.height)
-	{
-		return true;
-	}
-	else if(width == value.width && height == value.height)
-	{
-		return under ? value.under : true;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-bool CRmgTemplate::CSize::operator>=(const CSize & value) const
-{
-	if(width > value.width && height > value.height)
-	{
-		return true;
-	}
-	else if(width == value.width && height == value.height)
-	{
-		return under ? true : !value.under;
-	}
-	else
-	{
-		return false;
-	}
-}
-
-CRmgTemplate::CRmgTemplate()
-{
-
-}
-
-const std::string & CRmgTemplate::getName() const
-{
-	return name;
-}
-
-void CRmgTemplate::setName(const std::string & value)
-{
-	name = value;
-}
-
-const CRmgTemplate::CSize & CRmgTemplate::getMinSize() const
-{
-	return minSize;
-}
-
-void CRmgTemplate::setMinSize(const CSize & value)
-{
-	minSize = value;
-}
-
-const CRmgTemplate::CSize & CRmgTemplate::getMaxSize() const
-{
-	return maxSize;
-}
-
-void CRmgTemplate::setMaxSize(const CSize & value)
-{
-	maxSize = value;
-}
-
-const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
-{
-	return players;
-}
-
-void CRmgTemplate::setPlayers(const CPlayerCountRange & value)
-{
-	players = value;
-}
-
-const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
-{
-	return cpuPlayers;
-}
-
-void CRmgTemplate::setCpuPlayers(const CPlayerCountRange & value)
-{
-	cpuPlayers = value;
-}
-
-const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & CRmgTemplate::getZones() const
-{
-	return zones;
-}
-
-void CRmgTemplate::setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & value)
-{
-	zones = value;
-}
-
-const std::list<CRmgTemplateZoneConnection> & CRmgTemplate::getConnections() const
-{
-	return connections;
-}
-
-void CRmgTemplate::setConnections(const std::list<CRmgTemplateZoneConnection> & value)
-{
-	connections = value;
-}
-
-void CRmgTemplate::validate() const
-{
-	//TODO add some validation checks, throw on failure
-}
-
-void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
-{
-	range.push_back(std::make_pair(lower, upper));
-}
-
-void CRmgTemplate::CPlayerCountRange::addNumber(int value)
-{
-	range.push_back(std::make_pair(value, value));
-}
-
-bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
-{
-	for(const auto & pair : range)
-	{
-		if(count >= pair.first && count <= pair.second) return true;
-	}
-	return false;
-}
-
-std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
-{
-	std::set<int> numbers;
-	for(const auto & pair : range)
-	{
-		for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
-	}
-	return numbers;
-}
-
-const std::map<std::string, CRmgTemplate> & CRmgTemplateLoader::getTemplates() const
-{
-	return templates;
-}
-
-void CJsonRmgTemplateLoader::loadTemplates()
-{
-	const JsonNode rootNode(ResourceID("config/rmg.json"));
-	for(const auto & templatePair : rootNode.Struct())
-	{
-		CRmgTemplate tpl;
-		try
-		{
-			tpl.setName(templatePair.first);
-			const auto & templateNode = templatePair.second;
-
-			// Parse main template data
-			tpl.setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
-			tpl.setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
-			tpl.setPlayers(parsePlayers(templateNode["players"].String()));
-			tpl.setCpuPlayers(parsePlayers(templateNode["cpu"].String()));
-
-			// Parse zones
-			std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones;
-			for(const auto & zonePair : templateNode["zones"].Struct())
-			{
-				CRmgTemplateZone zone;
-				auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
-				zone.setId(zoneId);
-				const auto & zoneNode = zonePair.second;
-				zone.setType(parseZoneType(zoneNode["type"].String()));
-				zone.setSize(zoneNode["size"].Float());
-				if(!zoneNode["owner"].isNull()) zone.setOwner(zoneNode["owner"].Float());
-				zone.setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
-				zone.setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
-				zone.setTownTypes(parseTownTypes(zoneNode["townTypes"].Vector(), zone.getDefaultTownTypes()));
-				zone.setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
-				zone.setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone.getDefaultTerrainTypes()));
-				zone.setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
-				if(!zoneNode["terrainTypeLikeZone"].isNull()) zone.setTerrainTypeLikeZone(boost::lexical_cast<int>(zoneNode["terrainTypeLikeZone"].String()));
-				if(!zoneNode["townTypeLikeZone"].isNull()) zone.setTownTypeLikeZone(boost::lexical_cast<int>(zoneNode["townTypeLikeZone"].String()));
-				zones[zone.getId()] = zone;
-			}
-			tpl.setZones(zones);
-
-			// Parse connections
-			std::list<CRmgTemplateZoneConnection> connections;
-			for(const auto & connPair : templateNode["connections"].Vector())
-			{
-				CRmgTemplateZoneConnection conn;
-				conn.setZoneA(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()));
-				conn.setZoneB(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()));
-				conn.setGuardStrength(connPair["guard"].Float());
-				connections.push_back(conn);
-			}
-			tpl.setConnections(connections);
-			tpl.validate();
-			templates[tpl.getName()] = tpl;
-		}
-		catch(const std::exception & e)
-		{
-			logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl.getName() % std::string(e.what());
-		}
-	}
-}
-
-CRmgTemplate::CSize CJsonRmgTemplateLoader::parseMapTemplateSize(const std::string & text) const
-{
-	CRmgTemplate::CSize size;
-	if(text.empty()) return size;
-
-	std::vector<std::string> parts;
-	boost::split(parts, text, boost::is_any_of("+"));
-	static const std::map<std::string, int> mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL)
-			("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE);
-	auto it = mapSizeMapping.find(parts[0]);
-	if(it == mapSizeMapping.end())
-	{
-		// Map size is given as a number representation
-		const auto & numericalRep = parts[0];
-		parts.clear();
-		boost::split(parts, numericalRep, boost::is_any_of("x"));
-		assert(parts.size() == 3);
-		size.setWidth(boost::lexical_cast<int>(parts[0]));
-		size.setHeight(boost::lexical_cast<int>(parts[1]));
-		size.setUnder(boost::lexical_cast<int>(parts[2]) == 1);
-	}
-	else
-	{
-		size.setWidth(it->second);
-		size.setHeight(it->second);
-		size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false);
-	}
-	return size;
-}
-
-ETemplateZoneType::ETemplateZoneType CJsonRmgTemplateLoader::parseZoneType(const std::string & type) const
-{
-	static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping = boost::assign::map_list_of
-			("playerStart", ETemplateZoneType::PLAYER_START)("cpuStart", ETemplateZoneType::CPU_START)
-			("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION);
-	auto it = zoneTypeMapping.find(type);
-	if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown.");
-	return it->second;
-}
-
-CRmgTemplateZone::CTownInfo CJsonRmgTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const
-{
-	CRmgTemplateZone::CTownInfo towns;
-	towns.setTownCount(node["towns"].Float());
-	towns.setCastleCount(node["castles"].Float());
-	towns.setTownDensity(node["townDensity"].Float());
-	towns.setCastleDensity(node["castleDensity"].Float());
-	return towns;
-}
-
-std::set<TFaction> CJsonRmgTemplateLoader::parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const
-{
-	std::set<TFaction> townTypes;
-	for(const auto & townTypeNode : townTypesVector)
-	{
-		auto townTypeStr = townTypeNode.String();
-		if(townTypeStr == "all") return defaultTownTypes;
-
-		bool foundFaction = false;
-		for(auto factionPtr : VLC->townh->factions)
-		{
-			if(factionPtr->town != nullptr && townTypeStr == factionPtr->name)
-			{
-				townTypes.insert(factionPtr->index);
-				foundFaction = true;
-			}
-		}
-		if(!foundFaction) throw std::runtime_error("Given faction is invalid.");
-	}
-	return townTypes;
-}
-
-std::set<ETerrainType> CJsonRmgTemplateLoader::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const
-{
-	std::set<ETerrainType> terTypes;
-	for(const auto & node : terTypeStrings)
-	{
-		const auto & terTypeStr = node.String();
-		if(terTypeStr == "all") return defaultTerrainTypes;
-		auto pos = vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr);
-		if (pos != -1)
-		{
-			terTypes.insert(ETerrainType(pos));
-		}
-		else
-		{
-			throw std::runtime_error("Terrain type is invalid.");
-		}
-	}
-	return terTypes;
-}
-
-CRmgTemplate::CPlayerCountRange CJsonRmgTemplateLoader::parsePlayers(const std::string & players) const
-{
-	CRmgTemplate::CPlayerCountRange playerRange;
-	if(players.empty())
-	{
-		playerRange.addNumber(0);
-		return playerRange;
-	}
-	std::vector<std::string> commaParts;
-	boost::split(commaParts, players, boost::is_any_of(","));
-	for(const auto & commaPart : commaParts)
-	{
-		std::vector<std::string> rangeParts;
-		boost::split(rangeParts, commaPart, boost::is_any_of("-"));
-		if(rangeParts.size() == 2)
-		{
-			auto lower = boost::lexical_cast<int>(rangeParts[0]);
-			auto upper = boost::lexical_cast<int>(rangeParts[1]);
-			playerRange.addRange(lower, upper);
-		}
-		else if(rangeParts.size() == 1)
-		{
-			auto val = boost::lexical_cast<int>(rangeParts.front());
-			playerRange.addNumber(val);
-		}
-	}
-	return playerRange;
-}
-
-boost::mutex CRmgTemplateStorage::smx;
-
-CRmgTemplateStorage & CRmgTemplateStorage::get()
-{
-	TLockGuard _(smx);
-	static CRmgTemplateStorage storage;
-	return storage;
-}
-
-const std::map<std::string, CRmgTemplate> & CRmgTemplateStorage::getTemplates() const
-{
-	return templates;
-}
-
-CRmgTemplateStorage::CRmgTemplateStorage()
-{
-	auto jsonLoader = make_unique<CJsonRmgTemplateLoader>();
-	jsonLoader->loadTemplates();
-	const auto & tpls = jsonLoader->getTemplates();
-	templates.insert(tpls.begin(), tpls.end());
-}
-
-CRmgTemplateStorage::~CRmgTemplateStorage()
-{
-
-}

+ 1 - 370
lib/rmg/CMapGenerator.h

@@ -11,333 +11,11 @@
 
 #pragma once
 
-#include "../GameConstants.h"
 #include "../CRandomGenerator.h"
+#include "CMapGenOptions.h"
 
 class CMap;
-class CTerrainViewPatternConfig;
 class CMapEditManager;
-class JsonNode;
-
-typedef std::vector<JsonNode> JsonVector;
-
-namespace ETemplateZoneType
-{
-enum ETemplateZoneType
-{
-	PLAYER_START,
-	CPU_START,
-	TREASURE,
-	JUNCTION
-};
-}
-
-typedef int TRmgTemplateZoneId;
-
-/// The CRmgTemplateZone describes a zone in a template.
-class DLL_LINKAGE CRmgTemplateZone
-{
-public:
-	class DLL_LINKAGE CTownInfo
-	{
-	public:
-		CTownInfo();
-
-		int getTownCount() const; /// Default: 0
-		void setTownCount(int value);
-		int getCastleCount() const; /// Default: 0
-		void setCastleCount(int value);
-		int getTownDensity() const; /// Default: 0
-		void setTownDensity(int value);
-		int getCastleDensity() const; /// Default: 0
-		void setCastleDensity(int value);
-
-	private:
-		int townCount, castleCount, townDensity, castleDensity;
-	};
-
-	CRmgTemplateZone();
-
-	TRmgTemplateZoneId getId() const; /// Default: 0
-	void setId(TRmgTemplateZoneId value);
-	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START
-	void setType(ETemplateZoneType::ETemplateZoneType value);
-	int getSize() const; /// Default: 1
-	void setSize(int value);
-	boost::optional<int> getOwner() const;
-	void setOwner(boost::optional<int> value);
-	const CTownInfo & getPlayerTowns() const;
-	void setPlayerTowns(const CTownInfo & value);
-	const CTownInfo & getNeutralTowns() const;
-	void setNeutralTowns(const CTownInfo & value);
-	bool getTownsAreSameType() const; /// Default: false
-	void setTownsAreSameType(bool value);
-	const std::set<TFaction> & getTownTypes() const; /// Default: all
-	void setTownTypes(const std::set<TFaction> & value);
-	std::set<TFaction> getDefaultTownTypes() const;
-	bool getMatchTerrainToTown() const; /// Default: true
-	void setMatchTerrainToTown(bool value);
-	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all
-	void setTerrainTypes(const std::set<ETerrainType> & value);
-	std::set<ETerrainType> getDefaultTerrainTypes() const;
-	boost::optional<TRmgTemplateZoneId> getTerrainTypeLikeZone() const;
-	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
-	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const;
-	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
-
-private:
-	TRmgTemplateZoneId id;
-	ETemplateZoneType::ETemplateZoneType type;
-	int size;
-	boost::optional<int> owner;
-	CTownInfo playerTowns, neutralTowns;
-	bool townsAreSameType;
-	std::set<TFaction> townTypes;
-	bool matchTerrainToTown;
-	std::set<ETerrainType> terrainTypes;
-	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone;
-};
-
-/// The CRmgTemplateZoneConnection describes the connection between two zones.
-class DLL_LINKAGE CRmgTemplateZoneConnection
-{
-public:
-	CRmgTemplateZoneConnection();
-
-	TRmgTemplateZoneId getZoneA() const; /// Default: 0
-	void setZoneA(TRmgTemplateZoneId value);
-	TRmgTemplateZoneId getZoneB() const; /// Default: 0
-	void setZoneB(TRmgTemplateZoneId value);
-	int getGuardStrength() const; /// Default: 0
-	void setGuardStrength(int value);
-
-private:
-	TRmgTemplateZoneId zoneA, zoneB;
-	int guardStrength;
-};
-
-/// The CRmgTemplate describes a random map template.
-class DLL_LINKAGE CRmgTemplate
-{
-public:
-	class CSize
-	{
-	public:
-		CSize();
-		CSize(int width, int height, bool under);
-
-		int getWidth() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE
-		void setWidth(int value);
-		int getHeight() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE
-		void setHeight(int value);
-		bool getUnder() const; /// Default: true
-		void setUnder(bool value);
-		bool operator<=(const CSize & value) const;
-		bool operator>=(const CSize & value) const;
-
-	private:
-		int width, height;
-		bool under;
-	};
-
-	class CPlayerCountRange
-	{
-	public:
-		void addRange(int lower, int upper);
-		void addNumber(int value);
-		bool isInRange(int count) const;
-		std::set<int> getNumbers() const;
-
-	private:
-		std::list<std::pair<int, int> > range;
-	};
-
-	CRmgTemplate();
-
-	const std::string & getName() const;
-	void setName(const std::string & value);
-	const CSize & getMinSize() const;
-	void setMinSize(const CSize & value);
-	const CSize & getMaxSize() const;
-	void setMaxSize(const CSize & value);
-	const CPlayerCountRange & getPlayers() const;
-	void setPlayers(const CPlayerCountRange & value);
-	const CPlayerCountRange & getCpuPlayers() const;
-	void setCpuPlayers(const CPlayerCountRange & value);
-	const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & getZones() const;
-	void setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone> & value);
-	const std::list<CRmgTemplateZoneConnection> & getConnections() const;
-	void setConnections(const std::list<CRmgTemplateZoneConnection> & value);
-
-	void validate() const; /// Tests template on validity and throws exception on failure
-
-private:
-	std::string name;
-	CSize minSize, maxSize;
-	CPlayerCountRange players, cpuPlayers;
-	std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones;
-	std::list<CRmgTemplateZoneConnection> connections;
-};
-
-namespace EWaterContent
-{
-enum EWaterContent
-{
-	RANDOM = -1,
-	NONE,
-	NORMAL,
-	ISLANDS
-};
-}
-
-namespace EMonsterStrength
-{
-enum EMonsterStrength
-{
-	RANDOM = -1,
-	WEAK,
-	NORMAL,
-	STRONG
-};
-}
-
-namespace EPlayerType
-{
-enum EPlayerType
-{
-	HUMAN,
-	AI,
-	COMP_ONLY
-};
-}
-
-/// The map gen options class holds values about general map generation settings
-/// e.g. the size of the map, the count of players,...
-class DLL_LINKAGE CMapGenOptions
-{
-public:
-	/// The player settings class maps the player color, starting town and human player flag.
-	class DLL_LINKAGE CPlayerSettings
-	{
-	public:
-		CPlayerSettings();
-
-		/// The color of the player ranging from 0 to PlayerColor::PLAYER_LIMIT - 1.
-		/// The default value is 0.
-		PlayerColor getColor() const;
-		void setColor(PlayerColor value);
-
-		/// The starting town of the player ranging from 0 to town max count or RANDOM_TOWN.
-		/// The default value is RANDOM_TOWN.
-		si32 getStartingTown() const;
-		void setStartingTown(si32 value);
-
-		/// The default value is EPlayerType::AI.
-		EPlayerType::EPlayerType getPlayerType() const;
-		void setPlayerType(EPlayerType::EPlayerType value);
-
-		/// Constant for a random town selection.
-		static const si32 RANDOM_TOWN = -1;
-
-	private:
-		PlayerColor color;
-		si32 startingTown;
-		EPlayerType::EPlayerType playerType;
-
-	public:
-		template <typename Handler>
-		void serialize(Handler & h, const int version)
-		{
-			h & color & startingTown & playerType;
-		}
-	};
-
-	CMapGenOptions();
-
-	si32 getWidth() const;
-	void setWidth(si32 value);
-
-	si32 getHeight() const;
-	void setHeight(si32 value);
-
-	bool getHasTwoLevels() const;
-	void setHasTwoLevels(bool value);
-
-	/// The count of the players ranging from 1 to PlayerColor::PLAYER_LIMIT or RANDOM_SIZE for random. If you call
-	/// this method, all player settings are reset to default settings.
-	si8 getPlayerCount() const;
-	void setPlayerCount(si8 value);
-
-	/// The count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random.
-	si8 getTeamCount() const;
-	void setTeamCount(si8 value);
-
-	/// The count of the computer only players ranging from 0 to <PlayerColor::PLAYER_LIMIT - players count> or RANDOM_SIZE for random.
-	/// If you call this method, all player settings are reset to default settings.
-	si8 getCompOnlyPlayerCount() const;
-	void setCompOnlyPlayerCount(si8 value);
-
-	/// The count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random.
-	si8 getCompOnlyTeamCount() const;
-	void setCompOnlyTeamCount(si8 value);
-
-	EWaterContent::EWaterContent getWaterContent() const;
-	void setWaterContent(EWaterContent::EWaterContent value);
-
-	EMonsterStrength::EMonsterStrength getMonsterStrength() const;
-	void setMonsterStrength(EMonsterStrength::EMonsterStrength value);
-
-	/// The first player colors belong to standard players and the last player colors belong to comp only players.
-	/// All standard players are by default of type EPlayerType::AI.
-	const std::map<PlayerColor, CPlayerSettings> & getPlayersSettings() const;
-	void setStartingTownForPlayer(PlayerColor color, si32 town);
-	/// Sets a player type for a standard player. A standard player is the opposite of a computer only player. The
-	/// values which can be chosen for the player type are EPlayerType::AI or EPlayerType::HUMAN.
-	void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType);
-
-	/// The random map template to generate the map with or empty/not set if the template should be chosen randomly.
-	/// Default: Not set/random.
-	const CRmgTemplate * getMapTemplate() const;
-	void setMapTemplate(const CRmgTemplate * value);
-
-	const std::map<std::string, CRmgTemplate> & getAvailableTemplates() const;
-
-	/// Finalizes the options. All random sizes for various properties will be overwritten by numbers from
-	/// a random number generator by keeping the options in a valid state. Check options should return true, otherwise
-	/// this function fails.
-	void finalize();
-	void finalize(CRandomGenerator & gen);
-
-	/// Returns false if there is no template available which fits to the currently selected options.
-	bool checkOptions() const;
-
-	static const si8 RANDOM_SIZE = -1;
-
-private:
-	void resetPlayersMap();
-	int countHumanPlayers() const;
-	PlayerColor getNextPlayerColor() const;
-	void updateCompOnlyPlayers();
-	void updatePlayers();
-	const CRmgTemplate * getPossibleTemplate(CRandomGenerator & gen) const;
-
-	si32 width, height;
-	bool hasTwoLevels;
-	si8 playerCount, teamCount, compOnlyPlayerCount, compOnlyTeamCount;
-	EWaterContent::EWaterContent waterContent;
-	EMonsterStrength::EMonsterStrength monsterStrength;
-	std::map<PlayerColor, CPlayerSettings> players;
-	const CRmgTemplate * mapTemplate;
-
-public:
-	template <typename Handler>
-	void serialize(Handler & h, const int version)
-	{
-		h & width & height & hasTwoLevels & playerCount & teamCount & compOnlyPlayerCount;
-		h & compOnlyTeamCount & waterContent & monsterStrength & players;
-        //TODO add name of template to class, enables selection of a template by a user
-	}
-};
 
 /// The map generator creates a map randomly.
 class DLL_LINKAGE CMapGenerator
@@ -362,50 +40,3 @@ private:
 	int randomSeed;
 	CMapEditManager * editManager;
 };
-
-/* ---------------------------------------------------------------------------- */
-/* Implementation/Detail classes, Private API */
-/* ---------------------------------------------------------------------------- */
-
-/// The CRmgTemplateLoader is a abstract base class for loading templates.
-class DLL_LINKAGE CRmgTemplateLoader
-{
-public:
-	virtual ~CRmgTemplateLoader() { };
-	virtual void loadTemplates() = 0;
-	const std::map<std::string, CRmgTemplate> & getTemplates() const;
-
-protected:
-	std::map<std::string, CRmgTemplate> templates;
-};
-
-/// The CJsonRmgTemplateLoader loads templates from a JSON file.
-class DLL_LINKAGE CJsonRmgTemplateLoader : public CRmgTemplateLoader
-{
-public:
-	void loadTemplates() override;
-
-private:
-	CRmgTemplate::CSize parseMapTemplateSize(const std::string & text) const;
-	CRmgTemplateZone::CTownInfo parseTemplateZoneTowns(const JsonNode & node) const;
-	ETemplateZoneType::ETemplateZoneType parseZoneType(const std::string & type) const;
-	std::set<TFaction> parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const;
-	std::set<ETerrainType> parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const;
-	CRmgTemplate::CPlayerCountRange parsePlayers(const std::string & players) const;
-};
-
-/// The CRmgTemplateStorage is a singleton object where templates are stored and which can be accessed from anywhere.
-class DLL_LINKAGE CRmgTemplateStorage
-{
-public:
-	static CRmgTemplateStorage & get();
-
-	const std::map<std::string, CRmgTemplate> & getTemplates() const;
-
-private:
-	CRmgTemplateStorage();
-	~CRmgTemplateStorage();
-
-	static boost::mutex smx;
-	std::map<std::string, CRmgTemplate> templates; /// Key: Template name
-};

+ 241 - 0
lib/rmg/CRmgTemplate.cpp

@@ -0,0 +1,241 @@
+
+/*
+ * CRmgTemplate.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CRmgTemplate.h"
+
+#include "CRmgTemplateZone.h"
+#include "../mapping/CMap.h"
+
+CRmgTemplateZoneConnection::CRmgTemplateZoneConnection() : zoneA(nullptr), zoneB(nullptr), guardStrength(0)
+{
+
+}
+
+CRmgTemplateZone * CRmgTemplateZoneConnection::getZoneA() const
+{
+	return zoneA;
+}
+
+void CRmgTemplateZoneConnection::setZoneA(CRmgTemplateZone * value)
+{
+	zoneA = value;
+}
+
+CRmgTemplateZone * CRmgTemplateZoneConnection::getZoneB() const
+{
+	return zoneB;
+}
+
+void CRmgTemplateZoneConnection::setZoneB(CRmgTemplateZone * value)
+{
+	zoneB = value;
+}
+
+int CRmgTemplateZoneConnection::getGuardStrength() const
+{
+	return guardStrength;
+}
+
+void CRmgTemplateZoneConnection::setGuardStrength(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for guard strenth not allowed.");
+	guardStrength = value;
+}
+
+CRmgTemplate::CSize::CSize() : width(CMapHeader::MAP_SIZE_MIDDLE), height(CMapHeader::MAP_SIZE_MIDDLE), under(true)
+{
+
+}
+
+CRmgTemplate::CSize::CSize(int width, int height, bool under) : under(under)
+{
+	setWidth(width);
+	setHeight(height);
+}
+
+int CRmgTemplate::CSize::getWidth() const
+{
+	return width;
+}
+
+void CRmgTemplate::CSize::setWidth(int value)
+{
+	if(value <= 0) throw std::runtime_error("Width > 0 failed.");
+	width = value;
+}
+
+int CRmgTemplate::CSize::getHeight() const
+{
+	return height;
+}
+
+void CRmgTemplate::CSize::setHeight(int value)
+{
+	if(value <= 0) throw std::runtime_error("Height > 0 failed.");
+	height = value;
+}
+
+bool CRmgTemplate::CSize::getUnder() const
+{
+	return under;
+}
+
+void CRmgTemplate::CSize::setUnder(bool value)
+{
+	under = value;
+}
+
+bool CRmgTemplate::CSize::operator<=(const CSize & value) const
+{
+	if(width < value.width && height < value.height)
+	{
+		return true;
+	}
+	else if(width == value.width && height == value.height)
+	{
+		return under ? value.under : true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+bool CRmgTemplate::CSize::operator>=(const CSize & value) const
+{
+	if(width > value.width && height > value.height)
+	{
+		return true;
+	}
+	else if(width == value.width && height == value.height)
+	{
+		return under ? true : !value.under;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+CRmgTemplate::CRmgTemplate()
+{
+
+}
+
+CRmgTemplate::~CRmgTemplate()
+{
+	for (auto & pair : zones) delete pair.second;
+}
+
+const std::string & CRmgTemplate::getName() const
+{
+	return name;
+}
+
+void CRmgTemplate::setName(const std::string & value)
+{
+	name = value;
+}
+
+const CRmgTemplate::CSize & CRmgTemplate::getMinSize() const
+{
+	return minSize;
+}
+
+void CRmgTemplate::setMinSize(const CSize & value)
+{
+	minSize = value;
+}
+
+const CRmgTemplate::CSize & CRmgTemplate::getMaxSize() const
+{
+	return maxSize;
+}
+
+void CRmgTemplate::setMaxSize(const CSize & value)
+{
+	maxSize = value;
+}
+
+const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getPlayers() const
+{
+	return players;
+}
+
+void CRmgTemplate::setPlayers(const CPlayerCountRange & value)
+{
+	players = value;
+}
+
+const CRmgTemplate::CPlayerCountRange & CRmgTemplate::getCpuPlayers() const
+{
+	return cpuPlayers;
+}
+
+void CRmgTemplate::setCpuPlayers(const CPlayerCountRange & value)
+{
+	cpuPlayers = value;
+}
+
+const std::map<TRmgTemplateZoneId, CRmgTemplateZone *> & CRmgTemplate::getZones() const
+{
+	return zones;
+}
+
+void CRmgTemplate::setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone *> & value)
+{
+	zones = value;
+}
+
+const std::list<CRmgTemplateZoneConnection> & CRmgTemplate::getConnections() const
+{
+	return connections;
+}
+
+void CRmgTemplate::setConnections(const std::list<CRmgTemplateZoneConnection> & value)
+{
+	connections = value;
+}
+
+void CRmgTemplate::validate() const
+{
+	//TODO add some validation checks, throw on failure
+}
+
+void CRmgTemplate::CPlayerCountRange::addRange(int lower, int upper)
+{
+	range.push_back(std::make_pair(lower, upper));
+}
+
+void CRmgTemplate::CPlayerCountRange::addNumber(int value)
+{
+	range.push_back(std::make_pair(value, value));
+}
+
+bool CRmgTemplate::CPlayerCountRange::isInRange(int count) const
+{
+	for(const auto & pair : range)
+	{
+		if(count >= pair.first && count <= pair.second) return true;
+	}
+	return false;
+}
+
+std::set<int> CRmgTemplate::CPlayerCountRange::getNumbers() const
+{
+	std::set<int> numbers;
+	for(const auto & pair : range)
+	{
+		for(int i = pair.first; i <= pair.second; ++i) numbers.insert(i);
+	}
+	return numbers;
+}

+ 98 - 0
lib/rmg/CRmgTemplate.h

@@ -0,0 +1,98 @@
+
+/*
+ * CRmgTemplate.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include "../GameConstants.h"
+
+class CRmgTemplateZone;
+
+/// The CRmgTemplateZoneConnection describes the connection between two zones.
+class DLL_LINKAGE CRmgTemplateZoneConnection
+{
+public:
+	CRmgTemplateZoneConnection();
+
+	CRmgTemplateZone * getZoneA() const;
+	void setZoneA(CRmgTemplateZone * value);
+	CRmgTemplateZone * getZoneB() const;
+	void setZoneB(CRmgTemplateZone * value);
+	int getGuardStrength() const; /// Default: 0
+	void setGuardStrength(int value);
+
+private:
+	CRmgTemplateZone * zoneA, * zoneB;
+	int guardStrength;
+};
+
+/// The CRmgTemplate describes a random map template.
+class DLL_LINKAGE CRmgTemplate
+{
+public:
+	class CSize
+	{
+	public:
+		CSize();
+		CSize(int width, int height, bool under);
+
+		int getWidth() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE
+		void setWidth(int value);
+		int getHeight() const; /// Default: CMapHeader::MAP_SIZE_MIDDLE
+		void setHeight(int value);
+		bool getUnder() const; /// Default: true
+		void setUnder(bool value);
+		bool operator<=(const CSize & value) const;
+		bool operator>=(const CSize & value) const;
+
+	private:
+		int width, height;
+		bool under;
+	};
+
+	class CPlayerCountRange
+	{
+	public:
+		void addRange(int lower, int upper);
+		void addNumber(int value);
+		bool isInRange(int count) const;
+		std::set<int> getNumbers() const;
+
+	private:
+		std::list<std::pair<int, int> > range;
+	};
+
+	CRmgTemplate();
+	~CRmgTemplate();
+
+	const std::string & getName() const;
+	void setName(const std::string & value);
+	const CSize & getMinSize() const;
+	void setMinSize(const CSize & value);
+	const CSize & getMaxSize() const;
+	void setMaxSize(const CSize & value);
+	const CPlayerCountRange & getPlayers() const;
+	void setPlayers(const CPlayerCountRange & value);
+	const CPlayerCountRange & getCpuPlayers() const;
+	void setCpuPlayers(const CPlayerCountRange & value);
+	const std::map<TRmgTemplateZoneId, CRmgTemplateZone *> & getZones() const;
+	void setZones(const std::map<TRmgTemplateZoneId, CRmgTemplateZone *> & value);
+	const std::list<CRmgTemplateZoneConnection> & getConnections() const;
+	void setConnections(const std::list<CRmgTemplateZoneConnection> & value);
+
+	void validate() const; /// Tests template on validity and throws exception on failure
+
+private:
+	std::string name;
+	CSize minSize, maxSize;
+	CPlayerCountRange players, cpuPlayers;
+	std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
+	std::list<CRmgTemplateZoneConnection> connections;
+};

+ 232 - 0
lib/rmg/CRmgTemplateStorage.cpp

@@ -0,0 +1,232 @@
+
+/*
+ * CRmgTemplateStorage.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CRmgTemplateStorage.h"
+
+#include "CRmgTemplate.h"
+#include "CRmgTemplateZone.h"
+#include "../filesystem/Filesystem.h"
+#include "../JsonNode.h"
+#include "../mapping/CMap.h"
+#include "../VCMI_Lib.h"
+#include "../CTownHandler.h"
+#include "../GameConstants.h"
+#include "../StringConstants.h"
+
+const std::map<std::string, CRmgTemplate *> & CRmgTemplateLoader::getTemplates() const
+{
+	return templates;
+}
+
+void CJsonRmgTemplateLoader::loadTemplates()
+{
+	const JsonNode rootNode(ResourceID("config/rmg.json"));
+	for(const auto & templatePair : rootNode.Struct())
+	{
+		auto tpl = new CRmgTemplate();
+		try
+		{
+			tpl->setName(templatePair.first);
+			const auto & templateNode = templatePair.second;
+
+			// Parse main template data
+			tpl->setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
+			tpl->setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
+			tpl->setPlayers(parsePlayers(templateNode["players"].String()));
+			tpl->setCpuPlayers(parsePlayers(templateNode["cpu"].String()));
+
+			// Parse zones
+			std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
+			for(const auto & zonePair : templateNode["zones"].Struct())
+			{
+				auto zone = new CRmgTemplateZone();
+				auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
+				zone->setId(zoneId);
+
+				const auto & zoneNode = zonePair.second;
+				zone->setType(parseZoneType(zoneNode["type"].String()));
+				zone->setSize(zoneNode["size"].Float());
+				if(!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
+
+				zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
+				zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
+				zone->setTownTypes(parseTownTypes(zoneNode["townTypes"].Vector(), zone->getDefaultTownTypes()));
+				zone->setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
+				zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes()));
+				zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
+				if(!zoneNode["terrainTypeLikeZone"].isNull()) zone->setTerrainTypeLikeZone(boost::lexical_cast<int>(zoneNode["terrainTypeLikeZone"].String()));
+				if(!zoneNode["townTypeLikeZone"].isNull()) zone->setTownTypeLikeZone(boost::lexical_cast<int>(zoneNode["townTypeLikeZone"].String()));
+
+				zones[zone->getId()] = zone;
+			}
+			tpl->setZones(zones);
+
+			// Parse connections
+			std::list<CRmgTemplateZoneConnection> connections;
+			for(const auto & connPair : templateNode["connections"].Vector())
+			{
+				CRmgTemplateZoneConnection conn;
+				conn.setZoneA(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()))->second);
+				conn.setZoneB(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()))->second);
+				conn.setGuardStrength(connPair["guard"].Float());
+				connections.push_back(conn);
+			}
+			tpl->setConnections(connections);
+			tpl->validate();
+			templates[tpl->getName()] = tpl;
+		}
+		catch(const std::exception & e)
+		{
+			logGlobal->errorStream() << boost::format("Template %s has errors. Message: %s.") % tpl->getName() % std::string(e.what());
+		}
+	}
+}
+
+CRmgTemplate::CSize CJsonRmgTemplateLoader::parseMapTemplateSize(const std::string & text) const
+{
+	CRmgTemplate::CSize size;
+	if(text.empty()) return size;
+
+	std::vector<std::string> parts;
+	boost::split(parts, text, boost::is_any_of("+"));
+	static const std::map<std::string, int> mapSizeMapping = boost::assign::map_list_of("s", CMapHeader::MAP_SIZE_SMALL)
+			("m", CMapHeader::MAP_SIZE_MIDDLE)("l", CMapHeader::MAP_SIZE_LARGE)("xl", CMapHeader::MAP_SIZE_XLARGE);
+	auto it = mapSizeMapping.find(parts[0]);
+	if(it == mapSizeMapping.end())
+	{
+		// Map size is given as a number representation
+		const auto & numericalRep = parts[0];
+		parts.clear();
+		boost::split(parts, numericalRep, boost::is_any_of("x"));
+		assert(parts.size() == 3);
+		size.setWidth(boost::lexical_cast<int>(parts[0]));
+		size.setHeight(boost::lexical_cast<int>(parts[1]));
+		size.setUnder(boost::lexical_cast<int>(parts[2]) == 1);
+	}
+	else
+	{
+		size.setWidth(it->second);
+		size.setHeight(it->second);
+		size.setUnder(parts.size() > 1 ? parts[1] == std::string("u") : false);
+	}
+	return size;
+}
+
+ETemplateZoneType::ETemplateZoneType CJsonRmgTemplateLoader::parseZoneType(const std::string & type) const
+{
+	static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping = boost::assign::map_list_of
+			("playerStart", ETemplateZoneType::PLAYER_START)("cpuStart", ETemplateZoneType::CPU_START)
+			("treasure", ETemplateZoneType::TREASURE)("junction", ETemplateZoneType::JUNCTION);
+	auto it = zoneTypeMapping.find(type);
+	if(it == zoneTypeMapping.end()) throw std::runtime_error("Zone type unknown.");
+	return it->second;
+}
+
+CRmgTemplateZone::CTownInfo CJsonRmgTemplateLoader::parseTemplateZoneTowns(const JsonNode & node) const
+{
+	CRmgTemplateZone::CTownInfo towns;
+	towns.setTownCount(node["towns"].Float());
+	towns.setCastleCount(node["castles"].Float());
+	towns.setTownDensity(node["townDensity"].Float());
+	towns.setCastleDensity(node["castleDensity"].Float());
+	return towns;
+}
+
+std::set<TFaction> CJsonRmgTemplateLoader::parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const
+{
+	std::set<TFaction> townTypes;
+	for(const auto & townTypeNode : townTypesVector)
+	{
+		auto townTypeStr = townTypeNode.String();
+		if(townTypeStr == "all") return defaultTownTypes;
+
+		bool foundFaction = false;
+		for(auto factionPtr : VLC->townh->factions)
+		{
+			if(factionPtr->town != nullptr && townTypeStr == factionPtr->name)
+			{
+				townTypes.insert(factionPtr->index);
+				foundFaction = true;
+			}
+		}
+		if(!foundFaction) throw std::runtime_error("Given faction is invalid.");
+	}
+	return townTypes;
+}
+
+std::set<ETerrainType> CJsonRmgTemplateLoader::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const
+{
+	std::set<ETerrainType> terTypes;
+	for(const auto & node : terTypeStrings)
+	{
+		const auto & terTypeStr = node.String();
+		if(terTypeStr == "all") return defaultTerrainTypes;
+		auto pos = vstd::find_pos(GameConstants::TERRAIN_NAMES, terTypeStr);
+		if (pos != -1)
+		{
+			terTypes.insert(ETerrainType(pos));
+		}
+		else
+		{
+			throw std::runtime_error("Terrain type is invalid.");
+		}
+	}
+	return terTypes;
+}
+
+CRmgTemplate::CPlayerCountRange CJsonRmgTemplateLoader::parsePlayers(const std::string & players) const
+{
+	CRmgTemplate::CPlayerCountRange playerRange;
+	if(players.empty())
+	{
+		playerRange.addNumber(0);
+		return playerRange;
+	}
+	std::vector<std::string> commaParts;
+	boost::split(commaParts, players, boost::is_any_of(","));
+	for(const auto & commaPart : commaParts)
+	{
+		std::vector<std::string> rangeParts;
+		boost::split(rangeParts, commaPart, boost::is_any_of("-"));
+		if(rangeParts.size() == 2)
+		{
+			auto lower = boost::lexical_cast<int>(rangeParts[0]);
+			auto upper = boost::lexical_cast<int>(rangeParts[1]);
+			playerRange.addRange(lower, upper);
+		}
+		else if(rangeParts.size() == 1)
+		{
+			auto val = boost::lexical_cast<int>(rangeParts.front());
+			playerRange.addNumber(val);
+		}
+	}
+	return playerRange;
+}
+
+const std::map<std::string, CRmgTemplate *> & CRmgTemplateStorage::getTemplates() const
+{
+	return templates;
+}
+
+CRmgTemplateStorage::CRmgTemplateStorage()
+{
+	auto jsonLoader = make_unique<CJsonRmgTemplateLoader>();
+	jsonLoader->loadTemplates();
+
+	const auto & tpls = jsonLoader->getTemplates();
+	templates.insert(tpls.begin(), tpls.end());
+}
+
+CRmgTemplateStorage::~CRmgTemplateStorage()
+{
+	for (auto & pair : templates) delete pair.second;
+}

+ 59 - 0
lib/rmg/CRmgTemplateStorage.h

@@ -0,0 +1,59 @@
+
+/*
+ * CRmgTemplateStorage.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include "CRmgTemplate.h"
+#include "CRmgTemplateZone.h"
+
+class JsonNode;
+
+typedef std::vector<JsonNode> JsonVector;
+
+/// The CRmgTemplateLoader is a abstract base class for loading templates.
+class DLL_LINKAGE CRmgTemplateLoader
+{
+public:
+	virtual ~CRmgTemplateLoader() { };
+	virtual void loadTemplates() = 0;
+	const std::map<std::string, CRmgTemplate *> & getTemplates() const;
+
+protected:
+	std::map<std::string, CRmgTemplate *> templates;
+};
+
+/// The CJsonRmgTemplateLoader loads templates from a JSON file.
+class DLL_LINKAGE CJsonRmgTemplateLoader : public CRmgTemplateLoader
+{
+public:
+	void loadTemplates() override;
+
+private:
+	CRmgTemplate::CSize parseMapTemplateSize(const std::string & text) const;
+	CRmgTemplateZone::CTownInfo parseTemplateZoneTowns(const JsonNode & node) const;
+	ETemplateZoneType::ETemplateZoneType parseZoneType(const std::string & type) const;
+	std::set<TFaction> parseTownTypes(const JsonVector & townTypesVector, const std::set<TFaction> & defaultTownTypes) const;
+	std::set<ETerrainType> parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const;
+	CRmgTemplate::CPlayerCountRange parsePlayers(const std::string & players) const;
+};
+
+/// The class CRmgTemplateStorage stores random map templates.
+class DLL_LINKAGE CRmgTemplateStorage
+{
+public:
+	CRmgTemplateStorage();
+	~CRmgTemplateStorage();
+
+	const std::map<std::string, CRmgTemplate *> & getTemplates() const;
+
+private:
+	std::map<std::string, CRmgTemplate *> templates; /// Key: Template name
+};

+ 216 - 0
lib/rmg/CRmgTemplateZone.cpp

@@ -0,0 +1,216 @@
+
+/*
+ * CRmgTemplateZone.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CRmgTemplateZone.h"
+
+#include "../VCMI_Lib.h"
+#include "../CTownHandler.h"
+
+CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
+{
+
+}
+
+int CRmgTemplateZone::CTownInfo::getTownCount() const
+{
+	return townCount;
+}
+
+void CRmgTemplateZone::CTownInfo::setTownCount(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for town count not allowed.");
+	townCount = value;
+}
+
+int CRmgTemplateZone::CTownInfo::getCastleCount() const
+{
+	return castleCount;
+}
+
+void CRmgTemplateZone::CTownInfo::setCastleCount(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for castle count not allowed.");
+	castleCount = value;
+}
+
+int CRmgTemplateZone::CTownInfo::getTownDensity() const
+{
+	return townDensity;
+}
+
+void CRmgTemplateZone::CTownInfo::setTownDensity(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for town density not allowed.");
+	townDensity = value;
+}
+
+int CRmgTemplateZone::CTownInfo::getCastleDensity() const
+{
+	return castleDensity;
+}
+
+void CRmgTemplateZone::CTownInfo::setCastleDensity(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for castle density not allowed.");
+	castleDensity = value;
+}
+
+CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
+	townsAreSameType(false), matchTerrainToTown(true)
+{
+	townTypes = getDefaultTownTypes();
+	terrainTypes = getDefaultTerrainTypes();
+}
+
+TRmgTemplateZoneId CRmgTemplateZone::getId() const
+{
+	return id;
+}
+
+void CRmgTemplateZone::setId(TRmgTemplateZoneId value)
+{
+	if(value <= 0) throw std::runtime_error("Zone id should be greater than 0.");
+	id = value;
+}
+
+ETemplateZoneType::ETemplateZoneType CRmgTemplateZone::getType() const
+{
+	return type;
+}
+void CRmgTemplateZone::setType(ETemplateZoneType::ETemplateZoneType value)
+{
+	type = value;
+}
+
+int CRmgTemplateZone::getSize() const
+{
+	return size;
+}
+
+void CRmgTemplateZone::setSize(int value)
+{
+	if(value <= 0) throw std::runtime_error("Zone size needs to be greater than 0.");
+	size = value;
+}
+
+boost::optional<int> CRmgTemplateZone::getOwner() const
+{
+	return owner;
+}
+
+void CRmgTemplateZone::setOwner(boost::optional<int> value)
+{
+	if(!(*value >= 0 && *value <= PlayerColor::PLAYER_LIMIT_I)) throw std::runtime_error("Owner has to be in range 0 to max player count.");
+	owner = value;
+}
+
+const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getPlayerTowns() const
+{
+	return playerTowns;
+}
+
+void CRmgTemplateZone::setPlayerTowns(const CTownInfo & value)
+{
+	playerTowns = value;
+}
+
+const CRmgTemplateZone::CTownInfo & CRmgTemplateZone::getNeutralTowns() const
+{
+	return neutralTowns;
+}
+
+void CRmgTemplateZone::setNeutralTowns(const CTownInfo & value)
+{
+	neutralTowns = value;
+}
+
+bool CRmgTemplateZone::getTownsAreSameType() const
+{
+	return townsAreSameType;
+}
+
+void CRmgTemplateZone::setTownsAreSameType(bool value)
+{
+	townsAreSameType = value;
+}
+
+const std::set<TFaction> & CRmgTemplateZone::getTownTypes() const
+{
+	return townTypes;
+}
+
+void CRmgTemplateZone::setTownTypes(const std::set<TFaction> & value)
+{
+	townTypes = value;
+}
+
+std::set<TFaction> CRmgTemplateZone::getDefaultTownTypes() const
+{
+	std::set<TFaction> defaultTowns;
+	auto towns = VLC->townh->getDefaultAllowed();
+	for(int i = 0; i < towns.size(); ++i)
+	{
+		if(towns[i]) defaultTowns.insert(i);
+	}
+	return defaultTowns;
+}
+
+bool CRmgTemplateZone::getMatchTerrainToTown() const
+{
+	return matchTerrainToTown;
+}
+
+void CRmgTemplateZone::setMatchTerrainToTown(bool value)
+{
+	matchTerrainToTown = value;
+}
+
+const std::set<ETerrainType> & CRmgTemplateZone::getTerrainTypes() const
+{
+	return terrainTypes;
+}
+
+void CRmgTemplateZone::setTerrainTypes(const std::set<ETerrainType> & value)
+{
+	assert(value.find(ETerrainType::WRONG) == value.end() && value.find(ETerrainType::BORDER) == value.end() &&
+		   value.find(ETerrainType::WATER) == value.end() && value.find(ETerrainType::ROCK) == value.end());
+	terrainTypes = value;
+}
+
+std::set<ETerrainType> CRmgTemplateZone::getDefaultTerrainTypes() const
+{
+	std::set<ETerrainType> terTypes;
+	static const ETerrainType::EETerrainType allowedTerTypes[] = { ETerrainType::DIRT, ETerrainType::SAND, ETerrainType::GRASS, ETerrainType::SNOW,
+												   ETerrainType::SWAMP, ETerrainType::ROUGH, ETerrainType::SUBTERRANEAN, ETerrainType::LAVA };
+	for(auto & allowedTerType : allowedTerTypes) terTypes.insert(allowedTerType);
+	return terTypes;
+}
+
+boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTerrainTypeLikeZone() const
+{
+	return terrainTypeLikeZone;
+}
+
+void CRmgTemplateZone::setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
+{
+	terrainTypeLikeZone = value;
+}
+
+boost::optional<TRmgTemplateZoneId> CRmgTemplateZone::getTownTypeLikeZone() const
+{
+	return townTypeLikeZone;
+}
+
+void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value)
+{
+	townTypeLikeZone = value;
+}

+ 92 - 0
lib/rmg/CRmgTemplateZone.h

@@ -0,0 +1,92 @@
+
+/*
+ * CRmgTemplateZone.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+#include "../GameConstants.h"
+
+namespace ETemplateZoneType
+{
+enum ETemplateZoneType
+{
+	PLAYER_START,
+	CPU_START,
+	TREASURE,
+	JUNCTION
+};
+}
+
+/// The CRmgTemplateZone describes a zone in a template.
+class DLL_LINKAGE CRmgTemplateZone
+{
+public:
+	class DLL_LINKAGE CTownInfo
+	{
+	public:
+		CTownInfo();
+
+		int getTownCount() const; /// Default: 0
+		void setTownCount(int value);
+		int getCastleCount() const; /// Default: 0
+		void setCastleCount(int value);
+		int getTownDensity() const; /// Default: 0
+		void setTownDensity(int value);
+		int getCastleDensity() const; /// Default: 0
+		void setCastleDensity(int value);
+
+	private:
+		int townCount, castleCount, townDensity, castleDensity;
+	};
+
+	CRmgTemplateZone();
+
+	TRmgTemplateZoneId getId() const; /// Default: 0
+	void setId(TRmgTemplateZoneId value);
+	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START
+	void setType(ETemplateZoneType::ETemplateZoneType value);
+
+	int getSize() const; /// Default: 1
+	void setSize(int value);
+	boost::optional<int> getOwner() const;
+	void setOwner(boost::optional<int> value);
+
+	const CTownInfo & getPlayerTowns() const;
+	void setPlayerTowns(const CTownInfo & value);
+	const CTownInfo & getNeutralTowns() const;
+	void setNeutralTowns(const CTownInfo & value);
+	bool getTownsAreSameType() const; /// Default: false
+	void setTownsAreSameType(bool value);
+	const std::set<TFaction> & getTownTypes() const; /// Default: all
+	void setTownTypes(const std::set<TFaction> & value);
+	std::set<TFaction> getDefaultTownTypes() const;
+	bool getMatchTerrainToTown() const; /// Default: true
+	void setMatchTerrainToTown(bool value);
+
+	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all
+	void setTerrainTypes(const std::set<ETerrainType> & value);
+	std::set<ETerrainType> getDefaultTerrainTypes() const;
+	boost::optional<TRmgTemplateZoneId> getTerrainTypeLikeZone() const;
+	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
+	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const;
+	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
+
+private:
+	TRmgTemplateZoneId id;
+	ETemplateZoneType::ETemplateZoneType type;
+	int size;
+	boost::optional<int> owner;
+	CTownInfo playerTowns, neutralTowns;
+	bool townsAreSameType;
+	std::set<TFaction> townTypes;
+	bool matchTerrainToTown;
+	std::set<ETerrainType> terrainTypes;
+	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone;
+};

+ 34 - 0
lib/rmg/CZoneGraphGenerator.cpp

@@ -0,0 +1,34 @@
+
+/*
+ * CZoneGraphGenerator.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CZoneGraphGenerator.h"
+
+CZoneCell::CZoneCell(CRmgTemplateZone * zone) : zone(zone)
+{
+
+}
+
+
+CZoneGraph::CZoneGraph()
+{
+
+}
+
+CZoneGraphGenerator::CZoneGraphGenerator() : gen(nullptr)
+{
+
+}
+
+unique_ptr<CZoneGraph> CZoneGraphGenerator::generate(const CMapGenOptions & options, CRandomGenerator * gen)
+{
+	return make_unique<CZoneGraph>();
+}

+ 48 - 0
lib/rmg/CZoneGraphGenerator.h

@@ -0,0 +1,48 @@
+
+/*
+ * CZoneGraphGenerator.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+class CRmgTemplateZone;
+class CRandomGenerator;
+class CMapGenOptions;
+
+class CZoneCell
+{
+public:
+	CZoneCell(CRmgTemplateZone * zone);
+
+private:
+	CRmgTemplateZone * zone;
+
+	//TODO additional data
+};
+
+class CZoneGraph
+{
+public:
+	CZoneGraph();
+
+private:
+	//TODO zone graph storage
+};
+
+class CZoneGraphGenerator
+{
+public:
+	CZoneGraphGenerator();
+
+	unique_ptr<CZoneGraph> generate(const CMapGenOptions & options, CRandomGenerator * gen);
+
+private:
+	unique_ptr<CZoneGraph> graph;
+	CRandomGenerator * gen;
+};

+ 35 - 0
lib/rmg/CZonePlacer.cpp

@@ -0,0 +1,35 @@
+
+/*
+ * CZonePlacer.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "CZonePlacer.h"
+
+#include "CZoneGraphGenerator.h"
+
+CPlacedZone::CPlacedZone(CRmgTemplateZone * zone) : zone(zone)
+{
+
+}
+
+CZonePlacer::CZonePlacer() : map(nullptr), gen(nullptr)
+{
+
+}
+
+CZonePlacer::~CZonePlacer()
+{
+
+}
+
+void CZonePlacer::placeZones(CMap * map, unique_ptr<CZoneGraph> graph, CRandomGenerator * gen)
+{
+
+}

+ 45 - 0
lib/rmg/CZonePlacer.h

@@ -0,0 +1,45 @@
+
+/*
+ * CZonePlacer.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#pragma once
+
+class CZoneGraph;
+class CMap;
+class CRandomGenerator;
+class CRmgTemplateZone;
+
+class CPlacedZone
+{
+public:
+	CPlacedZone(CRmgTemplateZone * zone);
+
+private:
+	CRmgTemplateZone * zone;
+
+	//TODO exact outline data of zone
+	//TODO perhaps further zone data, guards, obstacles, etc...
+};
+
+//TODO add voronoi helper classes(?), etc...
+
+class CZonePlacer
+{
+public:
+	CZonePlacer();
+	~CZonePlacer();
+
+	void placeZones(CMap * map, unique_ptr<CZoneGraph> graph, CRandomGenerator * gen);
+
+private:
+	CMap * map;
+	unique_ptr<CZoneGraph> graph;
+	CRandomGenerator * gen;
+};

+ 3 - 2
test/CMapEditManagerTest.cpp

@@ -21,6 +21,7 @@
 #include "../lib/mapping/CMapEditManager.h"
 #include "../lib/int3.h"
 #include "../lib/CRandomGenerator.h"
+#include "../lib/VCMI_Lib.h"
 
 BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_Type)
 {
@@ -102,10 +103,10 @@ BOOST_AUTO_TEST_CASE(CMapEditManager_DrawTerrain_View)
 			if(patternParts.size() != 2) throw std::runtime_error("A pattern should consist of two parts, the group and the id. Continue with next pattern.");
 			const auto & groupStr = patternParts[0];
 			const auto & id = patternParts[1];
-			auto terGroup = CTerrainViewPatternConfig::get().getTerrainGroup(groupStr);
+			auto terGroup = VLC->terviewh->getTerrainGroup(groupStr);
 
 			// Get mapping range
-			const auto & pattern = CTerrainViewPatternConfig::get().getTerrainViewPatternById(terGroup, id);
+			const auto & pattern = VLC->terviewh->getTerrainViewPatternById(terGroup, id);
 			const auto & mapping = (*pattern).mapping;
 
 			const auto & positionsNode = node["pos"].Vector();