Преглед на файлове

Something that compiles, but crashes when launching RMG map.

DjWarmonger преди 11 години
родител
ревизия
1e1dce20a8
променени са 8 файла, в които са добавени 417 реда и са изтрити 1793 реда
  1. 2 2
      lib/CGameState.cpp
  2. 5 5
      lib/rmg/CMapGenOptions.cpp
  3. 22 20
      lib/rmg/CMapGenOptions.h
  4. 15 1365
      lib/rmg/CMapGenerator.cpp
  5. 8 397
      lib/rmg/CMapGenerator.h
  6. 1 1
      lib/rmg/CRmgTemplateStorage.cpp
  7. 328 0
      lib/rmg/CRmgTemplateZone.cpp
  8. 36 3
      lib/rmg/CRmgTemplateZone.h

+ 2 - 2
lib/CGameState.cpp

@@ -840,8 +840,8 @@ void CGameState::initNewGame()
 		CStopWatch sw;
 		CStopWatch sw;
 
 
 		// Gen map
 		// Gen map
-		CMapGenerator mapGenerator;
-		map = mapGenerator.generate(scenarioOps->mapGenOptions.get(), scenarioOps->seedToBeUsed).release();
+		CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, std::time(nullptr));
+		map = mapGenerator.generate();
 
 
 		// Update starting options
 		// Update starting options
 		for(int i = 0; i < map->players.size(); ++i)
 		for(int i = 0; i < map->players.size(); ++i)

+ 5 - 5
lib/rmg/CMapGenOptions.cpp

@@ -194,17 +194,17 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
 		auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
 		auto possiblePlayers = mapTemplate->getPlayers().getNumbers();
 		possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
 		possiblePlayers.erase(possiblePlayers.begin(), possiblePlayers.lower_bound(countHumanPlayers()));
 		assert(!possiblePlayers.empty());
 		assert(!possiblePlayers.empty());
-		playerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand);
+		playerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8));
 		updatePlayers();
 		updatePlayers();
 	}
 	}
 	if(teamCount == RANDOM_SIZE)
 	if(teamCount == RANDOM_SIZE)
 	{
 	{
-		teamCount = rand.nextInt(playerCount - 1);
+		teamCount = rand.nextInt(8);
 	}
 	}
 	if(compOnlyPlayerCount == RANDOM_SIZE)
 	if(compOnlyPlayerCount == RANDOM_SIZE)
 	{
 	{
 		auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
 		auto possiblePlayers = mapTemplate->getCpuPlayers().getNumbers();
-		compOnlyPlayerCount = *RandomGeneratorUtil::nextItem(possiblePlayers, rand);
+		compOnlyPlayerCount = *std::next(possiblePlayers.begin(), rand.nextInt(8));
 		updateCompOnlyPlayers();
 		updateCompOnlyPlayers();
 	}
 	}
 	if(compOnlyTeamCount == RANDOM_SIZE)
 	if(compOnlyTeamCount == RANDOM_SIZE)
@@ -220,11 +220,11 @@ void CMapGenOptions::finalize(CRandomGenerator & rand)
 
 
 	if(waterContent == EWaterContent::RANDOM)
 	if(waterContent == EWaterContent::RANDOM)
 	{
 	{
-		waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(2));
+		waterContent = static_cast<EWaterContent::EWaterContent>(rand.nextInt(EWaterContent::TOTAL_COUNT));
 	}
 	}
 	if(monsterStrength == EMonsterStrength::RANDOM)
 	if(monsterStrength == EMonsterStrength::RANDOM)
 	{
 	{
-		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(2));
+		monsterStrength = static_cast<EMonsterStrength::EMonsterStrength>(rand.nextInt(EMonsterStrength::TOTAL_COUNT));
 	}
 	}
 }
 }
 
 

+ 22 - 20
lib/rmg/CMapGenOptions.h

@@ -18,34 +18,36 @@ class CRmgTemplate;
 
 
 namespace EWaterContent
 namespace EWaterContent
 {
 {
-enum EWaterContent
-{
-	RANDOM = -1,
-	NONE,
-	NORMAL,
-	ISLANDS
-};
+	enum EWaterContent
+	{
+		RANDOM = -1,
+		NONE,
+		NORMAL,
+		ISLANDS,
+		TOTAL_COUNT
+	};
 }
 }
 
 
 namespace EMonsterStrength
 namespace EMonsterStrength
 {
 {
-enum EMonsterStrength
-{
-	RANDOM = -1,
-	WEAK,
-	NORMAL,
-	STRONG
-};
+	enum EMonsterStrength
+	{
+		RANDOM = -1,
+		WEAK,
+		NORMAL,
+		STRONG,
+		TOTAL_COUNT
+	};
 }
 }
 
 
 namespace EPlayerType
 namespace EPlayerType
 {
 {
-enum EPlayerType
-{
-	HUMAN,
-	AI,
-	COMP_ONLY
-};
+	enum EPlayerType
+	{
+		HUMAN,
+		AI,
+		COMP_ONLY
+	};
 }
 }
 
 
 /// The map gen options class holds values about general map generation settings
 /// The map gen options class holds values about general map generation settings

+ 15 - 1365
lib/rmg/CMapGenerator.cpp

@@ -10,401 +10,13 @@
 #include "../CTownHandler.h"
 #include "../CTownHandler.h"
 #include "../StringConstants.h"
 #include "../StringConstants.h"
 #include "../filesystem/Filesystem.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"
+#include "CRmgTemplateZone.h"
 
 
 CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
 CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed /*= std::time(nullptr)*/) :
 	mapGenOptions(mapGenOptions), randomSeed(randomSeed)
 	mapGenOptions(mapGenOptions), randomSeed(randomSeed)
 {
 {
-	gen.seed(randomSeed);
+	rand.setSeed(randomSeed);
 }
 }
 
 
 CMapGenerator::~CMapGenerator()
 CMapGenerator::~CMapGenerator()
@@ -412,11 +24,11 @@ CMapGenerator::~CMapGenerator()
 
 
 }
 }
 
 
-std::unique_ptr<CMap> CMapGenerator::generate()
+ConstTransitivePtr<CMap> CMapGenerator::generate()
 {
 {
-	mapGenOptions.finalize(gen);
+	mapGenOptions.finalize(rand);
 
 
-	map = make_unique<CMap>();
+	//map = make_unique<CMap>();
 	editManager = map->getEditManager();
 	editManager = map->getEditManager();
 	editManager->getUndoManager().setUndoRedoLimit(0);
 	editManager->getUndoManager().setUndoRedoLimit(0);
 	addHeaderInfo();
 	addHeaderInfo();
@@ -502,7 +114,7 @@ void CMapGenerator::addPlayerInfo()
 		{
 		{
 			player.canHumanPlay = true;
 			player.canHumanPlay = true;
 		}
 		}
-		auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1));
+		auto itTeam = std::next(teamNumbers[j].begin(), rand.nextInt (teamNumbers[j].size()));
 		player.team = TeamID(*itTeam);
 		player.team = TeamID(*itTeam);
 		teamNumbers[j].erase(itTeam);
 		teamNumbers[j].erase(itTeam);
 		map->players[pSettings.getColor().getNum()] = player;
 		map->players[pSettings.getColor().getNum()] = player;
@@ -515,9 +127,9 @@ void CMapGenerator::addPlayerInfo()
 void CMapGenerator::genZones()
 void CMapGenerator::genZones()
 {
 {
 	map->initTerrain();
 	map->initTerrain();
-	editManager->clearTerrain(&gen);
+	editManager->clearTerrain(&rand);
 	editManager->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
 	editManager->getTerrainSelection().selectRange(MapRect(int3(0, 0, 0), mapGenOptions.getWidth(), mapGenOptions.getHeight()));
-	editManager->drawTerrain(ETerrainType::GRASS, &gen);
+	editManager->drawTerrain(ETerrainType::GRASS, &rand);
 
 
 	auto pcnt = mapGenOptions.getPlayerCount();
 	auto pcnt = mapGenOptions.getPlayerCount();
 	auto w = mapGenOptions.getWidth();
 	auto w = mapGenOptions.getWidth();
@@ -537,7 +149,7 @@ void CMapGenerator::genZones()
 	int part_h = h/player_per_side;
 	int part_h = h/player_per_side;
 	for(auto const it : zones)
 	for(auto const it : zones)
 	{
 	{
-		CRmgTemplateZone zone = it.second;
+		CRmgTemplateZone * zone = it.second;
 		std::vector<int3> shape;
 		std::vector<int3> shape;
 		int left = part_w*(i%player_per_side);
 		int left = part_w*(i%player_per_side);
 		int top = part_h*(i/player_per_side);
 		int top = part_h*(i/player_per_side);
@@ -545,8 +157,8 @@ void CMapGenerator::genZones()
 		shape.push_back(int3(left + part_w, top,  0));
 		shape.push_back(int3(left + part_w, top,  0));
 		shape.push_back(int3(left + part_w, top + part_h,  0));
 		shape.push_back(int3(left + part_w, top + part_h,  0));
 		shape.push_back(int3(left, top + part_h,  0));
 		shape.push_back(int3(left, top + part_h,  0));
-		zone.setShape(shape);
-		zone.setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE);
+		zone->setShape(shape);
+		zone->setType(i < pcnt ? ETemplateZoneType::PLAYER_START : ETemplateZoneType::TREASURE);
 		this->zones[it.first] = zone;
 		this->zones[it.first] = zone;
 		++i;
 		++i;
 	}
 	}
@@ -556,9 +168,9 @@ void CMapGenerator::genZones()
 void CMapGenerator::fillZones()
 void CMapGenerator::fillZones()
 {	
 {	
 	logGlobal->infoStream() << "Started filling zones";
 	logGlobal->infoStream() << "Started filling zones";
-	for(auto it = zones.begin(); it != zones.end(); ++it)
+	for(auto it : zones)
 	{
 	{
-		it->second.fill(this);
+		it.second->fill(this);
 	}	
 	}	
 	logGlobal->infoStream() << "Zones filled successfully";
 	logGlobal->infoStream() << "Zones filled successfully";
 }
 }
@@ -573,966 +185,4 @@ void CMapGenerator::addHeaderInfo()
 	map->description = getMapDescription();
 	map->description = getMapDescription();
 	map->difficulty = 1;
 	map->difficulty = 1;
 	addPlayerInfo();
 	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::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG) 
-{
-
-}
-
-int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const
-{
-	return nearestObjectDistance;
-}
-
-void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value)
-{
-	if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed.");
-	nearestObjectDistance = value;
-}
-
-bool CRmgTemplateZone::CTileInfo::isObstacle() const
-{
-	return obstacle;
-}
-
-void CRmgTemplateZone::CTileInfo::setObstacle(bool value)
-{
-	obstacle = value;
-}
-
-bool CRmgTemplateZone::CTileInfo::isOccupied() const
-{
-	return occupied;
-}
-
-void CRmgTemplateZone::CTileInfo::setOccupied(bool value)
-{
-	occupied = value;
-}
-
-ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const
-{
-	return terrain;
-}
-
-void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value)
-{
-	terrain = 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;
-}
-
-bool CRmgTemplateZone::pointIsIn(int x, int y)
-{
-	int i, j;
-	bool c = false;
-	int nvert = shape.size();
-	for (i = 0, j = nvert-1; i < nvert; j = i++) {
-		if ( ((shape[i].y>y) != (shape[j].y>y)) &&
-			(x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) )
-			c = !c;
-	}
-	return c;
-}
-
-void CRmgTemplateZone::setShape(std::vector<int3> shape)
-{
-	int z = -1;
-	si32 minx = INT_MAX;
-	si32 maxx = -1;
-	si32 miny = INT_MAX;
-	si32 maxy = -1;
-	for(auto &point : shape)
-	{
-		if (z == -1)
-			z = point.z;
-		if (point.z != z)
-			throw std::runtime_error("Zone shape points should lie on same z.");
-		minx = std::min(minx, point.x);
-		maxx = std::max(maxx, point.x);
-		miny = std::min(miny, point.y);
-		maxy = std::max(maxy, point.y);
-	}
-	this->shape = shape;
-	for(int x = minx; x <= maxx; ++x)
-	{
-		for(int y = miny; y <= maxy; ++y)
-		{
-			if (pointIsIn(x, y))
-			{
-				tileinfo[int3(x,y,z)] = CTileInfo();
-			}
-		}
-	}
-}
-
-int3 CRmgTemplateZone::getCenter()
-{
-	si32 cx = 0;
-	si32 cy = 0;
-	si32 area = 0;
-	si32 sz = shape.size();
-	//include last->first too
-	for(si32 i = 0, j = sz-1; i < sz; j = i++) {
-		si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y);
-		cx += (shape[i].x + shape[j].x) * sf;
-		cy += (shape[i].y + shape[j].y) * sf;
-		area += sf;
-	}
-	area /= 2;
-	return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
-}
-
-bool CRmgTemplateZone::fill(CMapGenerator* gen)
-{
-	std::vector<CGObjectInstance*> required_objects;
-	if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START))
-	{
-		logGlobal->infoStream() << "Preparing playing zone";
-		int player_id = *owner - 1;
-		auto & playerInfo = gen->map->players[player_id];
-		if (playerInfo.canAnyonePlay())
-		{
-			PlayerColor player(player_id);
-			auto  town = new CGTownInstance();
-			town->ID = Obj::TOWN;
-			int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown();
-			
-			static auto town_gen = gen->gen.getRangeI(0, 8);
-
-			if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN) townId = town_gen(); // Default towns
-			town->subID = townId;
-			town->tempOwner = player;
-			town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID];
-			town->builtBuildings.insert(BuildingID::FORT);
-			town->builtBuildings.insert(BuildingID::DEFAULT);
-			
-			placeObject(gen, town, getCenter());
-			logGlobal->infoStream() << "Placed object";
-
-			logGlobal->infoStream() << "Fill player info " << player_id;
-			auto & playerInfo = gen->map->players[player_id];
-			// Update player info
-			playerInfo.allowedFactions.clear();
-			playerInfo.allowedFactions.insert(town->subID);
-			playerInfo.hasMainTown = true;
-			playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
-			playerInfo.generateHeroAtMainTown = true;
-
-			//required_objects.push_back(town);
-
-			std::vector<Res::ERes> required_mines;
-			required_mines.push_back(Res::ERes::WOOD);
-			required_mines.push_back(Res::ERes::ORE);
-
-			for(const auto res : required_mines)
-			{			
-				auto mine = new CGMine();
-				mine->ID = Obj::MINE;
-				mine->subID = static_cast<si32>(res);
-				mine->producedResource = res;
-				mine->producedQuantity = mine->defaultResProduction();
-				mine->defInfo = VLC->dobjinfo->gobjs[mine->ID][mine->subID];
-				required_objects.push_back(mine);
-			}
-		}
-		else
-		{			
-			type = ETemplateZoneType::TREASURE;
-			logGlobal->infoStream() << "Skipping this zone cause no player";
-		}
-	}
-	logGlobal->infoStream() << "Creating required objects";
-	for(const auto &obj : required_objects)
-	{
-		int3 pos;
-		logGlobal->infoStream() << "Looking for place";
-		if ( ! findPlaceForObject(gen, obj, 3, pos))		
-		{
-			logGlobal->errorStream() << "Failed to fill zone due to lack of space";
-			//TODO CLEANUP!
-			return false;
-		}
-		logGlobal->infoStream() << "Place found";
-
-		placeObject(gen, obj, pos);
-		logGlobal->infoStream() << "Placed object";
-	}
-	std::vector<CGObjectInstance*> guarded_objects;
-	static auto res_gen = gen->gen.getRangeI(Res::ERes::WOOD, Res::ERes::GOLD);
-	const double res_mindist = 5;
-	do {
-		auto obj = new CGResource();
-		auto restype = static_cast<Res::ERes>(res_gen());
-		obj->ID = Obj::RESOURCE;
-		obj->subID = static_cast<si32>(restype);
-		obj->amount = 0;
-		obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID];
-		
-		int3 pos;
-		if ( ! findPlaceForObject(gen, obj, res_mindist, pos))		
-		{
-			delete obj;
-			break;
-		}
-		placeObject(gen, obj, pos);		
-		if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE))
-		{
-			guarded_objects.push_back(obj);
-		}
-	} while(true);
-
-	for(const auto &obj : guarded_objects)
-	{
-		if ( ! guardObject(gen, obj, 500))
-		{
-			//TODO, DEL obj from map
-		}
-	}
-
-	auto sel = gen->editManager->getTerrainSelection();
-	sel.clearSelection();
-	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
-	{
-		if (it->second.isObstacle())
-		{
-			auto obj = new CGObjectInstance();
-			obj->ID = static_cast<Obj>(130);
-			obj->subID = 0;
-			obj->defInfo = VLC->dobjinfo->gobjs[obj->ID][obj->subID];
-			placeObject(gen, obj, it->first);
-		}
-	}
-	logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size();
-	//gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen);
-	logGlobal->infoStream() << "Zone filled successfully";
-	return true;
-}
-
-bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
-{
-	//si32 min_dist = sqrt(tileinfo.size()/density);
-	int best_distance = 0;
-	bool result = false;
-	si32 w = gen->map->width;
-	si32 h = gen->map->height; 
-	auto ow = obj->getWidth();
-	auto oh = obj->getHeight();
-	//logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist;
-	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
-	{
-		auto &ti = it->second;
-		auto p = it->first;
-		auto dist = ti.getNearestObjectDistance();
-		//avoid borders
-		if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3))
-			continue;
-		if (!ti.isOccupied() && !ti.isObstacle()  && (dist >= min_dist) && (dist > best_distance))
-		{
-			best_distance = dist;
-			pos = p;
-			result = true;
-		}
-	}
-	return result;
-}
-
-void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
-{
-	logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y;
-	object->pos = pos;
-	gen->editManager->insertObject(object, pos);
-	logGlobal->infoStream() << "Inserted object";
-	auto points = object->getBlockedPos();
-	if (object->isVisitable())
-		points.emplace(pos + object->getVisitableOffset());
-	points.emplace(pos);
-	for(auto const &p : points)
-	{		
-		if (tileinfo.find(pos + p) != tileinfo.end())
-		{
-			tileinfo[pos + p].setOccupied(true);
-		}
-	}
-	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
-	{		
-		si32 d = pos.dist2d(it->first);
-		it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance()));
-	}
-}
-
-bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str)
-{
-	
-	logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y;
-	int3 visitable = object->pos + object->getVisitableOffset();
-	std::vector<int3> tiles;
-	for(int i = -1; i < 2; ++i)
-	{
-		for(int j = -1; j < 2; ++j)
-		{
-			auto it = tileinfo.find(visitable + int3(i, j, 0));
-			if (it != tileinfo.end())
-			{
-				logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y;
-				if ( ! it->second.isOccupied() &&  ! it->second.isObstacle())
-				{
-					tiles.push_back(it->first);
-					it->second.setObstacle(true);
-				}
-			}
-		}
-	}
-	if ( ! tiles.size())
-	{		
-		logGlobal->infoStream() << "Failed";
-		return false;
-	}
-	auto guard_tile = *std::next(tiles.begin(), gen->gen.getInteger(0, tiles.size() - 1));
-	tileinfo[guard_tile].setObstacle(false);
-	auto guard = new CGCreature();
-	guard->ID = Obj::RANDOM_MONSTER;
-	guard->subID = 0;
-	auto  hlp = new CStackInstance();
-	hlp->count = 10;
-	//type will be set during initialization
-	guard->putStack(SlotID(0), hlp);
-
-	guard->defInfo = VLC->dobjinfo->gobjs[guard->ID][guard->subID];
-	guard->pos = guard_tile;
-	gen->editManager->insertObject(guard, guard->pos);
-	return true;
-}
-
-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()
-{
-
-}
+}

+ 8 - 397
lib/rmg/CMapGenerator.h

@@ -13,369 +13,22 @@
 
 
 #include "../GameConstants.h"
 #include "../GameConstants.h"
 #include "../CRandomGenerator.h"
 #include "../CRandomGenerator.h"
+#include "CMapGenOptions.h"
 #include "../CObjectHandler.h"
 #include "../CObjectHandler.h"
 #include "../int3.h"
 #include "../int3.h"
 
 
 class CMap;
 class CMap;
+class CRmgTemplate;
+class CRmgTemplateZone;
+class CMapGenOptions;
 class CTerrainViewPatternConfig;
 class CTerrainViewPatternConfig;
 class CMapEditManager;
 class CMapEditManager;
 class JsonNode;
 class JsonNode;
 
 
 typedef std::vector<JsonNode> JsonVector;
 typedef std::vector<JsonNode> JsonVector;
 
 
-namespace ETemplateZoneType
-{
-enum ETemplateZoneType
-{
-	PLAYER_START,
-	CPU_START,
-	TREASURE,
-	JUNCTION
-};
-}
-
-typedef int TRmgTemplateZoneId;
-
 class CMapGenerator;
 class CMapGenerator;
 
 
-/// 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;
-	};
-	
-	class DLL_LINKAGE CTileInfo
-	{
-	public:
-		CTileInfo();
-
-		int getNearestObjectDistance() const;
-		void setNearestObjectDistance(int value);
-		bool isObstacle() const;
-		void setObstacle(bool value);
-		bool isOccupied() const;
-		void setOccupied(bool value);
-		ETerrainType getTerrainType() const;
-		void setTerrainType(ETerrainType value);
-
-	private:
-		int nearestObjectDistance;
-		bool obstacle;
-		bool occupied;
-		ETerrainType terrain;
-	};
-
-	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);
-	void setShape(std::vector<int3> shape);
-	bool fill(CMapGenerator* gen);
-
-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;
-
-	std::vector<int3> shape;
-	std::map<int3, CTileInfo> tileinfo;
-	std::vector<CGObjectInstance*> objects;
-
-	int3 getCenter();
-	bool pointIsIn(int x, int y);
-	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
-	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
-	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str);
-};
-
-/// 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.
 /// The map generator creates a map randomly.
 class DLL_LINKAGE CMapGenerator
 class DLL_LINKAGE CMapGenerator
 {
 {
@@ -383,16 +36,16 @@ public:
 	explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr));
 	explicit CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed = std::time(nullptr));
 	~CMapGenerator(); // required due to unique_ptr
 	~CMapGenerator(); // required due to unique_ptr
 
 
-	std::unique_ptr<CMap> generate();
+	ConstTransitivePtr<CMap> generate();
 	
 	
 	CMapGenOptions mapGenOptions;
 	CMapGenOptions mapGenOptions;
-	std::unique_ptr<CMap> map;
-	CRandomGenerator gen;
+	ConstTransitivePtr<CMap> map;
+	CRandomGenerator rand;
 	int randomSeed;
 	int randomSeed;
 	CMapEditManager * editManager;
 	CMapEditManager * editManager;
 
 
 private:
 private:
-	std::map<TRmgTemplateZoneId, CRmgTemplateZone> zones;
+	std::map<TRmgTemplateZoneId, CRmgTemplateZone*> zones;
 
 
 	/// Generation methods
 	/// Generation methods
 	std::string getMapDescription() const;
 	std::string getMapDescription() const;
@@ -407,45 +60,3 @@ private:
 /* Implementation/Detail classes, Private API */
 /* 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
-};

+ 1 - 1
lib/rmg/CRmgTemplateStorage.cpp

@@ -229,4 +229,4 @@ CRmgTemplateStorage::CRmgTemplateStorage()
 CRmgTemplateStorage::~CRmgTemplateStorage()
 CRmgTemplateStorage::~CRmgTemplateStorage()
 {
 {
 	for (auto & pair : templates) delete pair.second;
 	for (auto & pair : templates) delete pair.second;
-}
+}

+ 328 - 0
lib/rmg/CRmgTemplateZone.cpp

@@ -11,10 +11,15 @@
 
 
 #include "StdInc.h"
 #include "StdInc.h"
 #include "CRmgTemplateZone.h"
 #include "CRmgTemplateZone.h"
+#include "../mapping/CMapEditManager.h"
+#include "../mapping/CMap.h"
 
 
 #include "../VCMI_Lib.h"
 #include "../VCMI_Lib.h"
 #include "../CTownHandler.h"
 #include "../CTownHandler.h"
 
 
+class CMap;
+class CMapEditManager;
+
 CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
 CRmgTemplateZone::CTownInfo::CTownInfo() : townCount(0), castleCount(0), townDensity(0), castleDensity(0)
 {
 {
 
 
@@ -64,6 +69,52 @@ void CRmgTemplateZone::CTownInfo::setCastleDensity(int value)
 	castleDensity = value;
 	castleDensity = value;
 }
 }
 
 
+CRmgTemplateZone::CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), obstacle(false), occupied(false), terrain(ETerrainType::WRONG) 
+{
+
+}
+
+int CRmgTemplateZone::CTileInfo::getNearestObjectDistance() const
+{
+	return nearestObjectDistance;
+}
+
+void CRmgTemplateZone::CTileInfo::setNearestObjectDistance(int value)
+{
+	if(value < 0) throw std::runtime_error("Negative value for nearest object distance not allowed.");
+	nearestObjectDistance = value;
+}
+
+bool CRmgTemplateZone::CTileInfo::isObstacle() const
+{
+	return obstacle;
+}
+
+void CRmgTemplateZone::CTileInfo::setObstacle(bool value)
+{
+	obstacle = value;
+}
+
+bool CRmgTemplateZone::CTileInfo::isOccupied() const
+{
+	return occupied;
+}
+
+void CRmgTemplateZone::CTileInfo::setOccupied(bool value)
+{
+	occupied = value;
+}
+
+ETerrainType CRmgTemplateZone::CTileInfo::getTerrainType() const
+{
+	return terrain;
+}
+
+void CRmgTemplateZone::CTileInfo::setTerrainType(ETerrainType value)
+{
+	terrain = value;
+}
+
 CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
 CRmgTemplateZone::CRmgTemplateZone() : id(0), type(ETemplateZoneType::PLAYER_START), size(1),
 	townsAreSameType(false), matchTerrainToTown(true)
 	townsAreSameType(false), matchTerrainToTown(true)
 {
 {
@@ -214,3 +265,280 @@ void CRmgTemplateZone::setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> v
 {
 {
 	townTypeLikeZone = value;
 	townTypeLikeZone = value;
 }
 }
+
+bool CRmgTemplateZone::pointIsIn(int x, int y)
+{
+	int i, j;
+	bool c = false;
+	int nvert = shape.size();
+	for (i = 0, j = nvert-1; i < nvert; j = i++) {
+		if ( ((shape[i].y>y) != (shape[j].y>y)) &&
+			(x < (shape[j].x-shape[i].x) * (y-shape[i].y) / (shape[j].y-shape[i].y) + shape[i].x) )
+			c = !c;
+	}
+	return c;
+}
+
+void CRmgTemplateZone::setShape(std::vector<int3> shape)
+{
+	int z = -1;
+	si32 minx = INT_MAX;
+	si32 maxx = -1;
+	si32 miny = INT_MAX;
+	si32 maxy = -1;
+	for(auto &point : shape)
+	{
+		if (z == -1)
+			z = point.z;
+		if (point.z != z)
+			throw std::runtime_error("Zone shape points should lie on same z.");
+		minx = std::min(minx, point.x);
+		maxx = std::max(maxx, point.x);
+		miny = std::min(miny, point.y);
+		maxy = std::max(maxy, point.y);
+	}
+	this->shape = shape;
+	for(int x = minx; x <= maxx; ++x)
+	{
+		for(int y = miny; y <= maxy; ++y)
+		{
+			if (pointIsIn(x, y))
+			{
+				tileinfo[int3(x,y,z)] = CTileInfo();
+			}
+		}
+	}
+}
+
+int3 CRmgTemplateZone::getCenter()
+{
+	si32 cx = 0;
+	si32 cy = 0;
+	si32 area = 0;
+	si32 sz = shape.size();
+	//include last->first too
+	for(si32 i = 0, j = sz-1; i < sz; j = i++) {
+		si32 sf = (shape[i].x * shape[j].y - shape[j].x * shape[i].y);
+		cx += (shape[i].x + shape[j].x) * sf;
+		cy += (shape[i].y + shape[j].y) * sf;
+		area += sf;
+	}
+	area /= 2;
+	return int3(std::abs(cx/area/6), std::abs(cy/area/6), shape[0].z);
+}
+
+bool CRmgTemplateZone::fill(CMapGenerator* gen)
+{
+	std::vector<CGObjectInstance*> required_objects;
+	if ((type == ETemplateZoneType::CPU_START) || (type == ETemplateZoneType::PLAYER_START))
+	{
+		logGlobal->infoStream() << "Preparing playing zone";
+		int player_id = *owner - 1;
+		auto & playerInfo = gen->map->players[player_id];
+		if (playerInfo.canAnyonePlay())
+		{
+			PlayerColor player(player_id);
+			auto  town = new CGTownInstance();
+			town->ID = Obj::TOWN;
+			int townId = gen->mapGenOptions.getPlayersSettings().find(player)->second.getStartingTown();
+
+			if(townId == CMapGenOptions::CPlayerSettings::RANDOM_TOWN)
+				townId = gen->rand.nextInt (VLC->townh->factions.size()); // all possible towns
+
+			town->subID = townId;
+			town->tempOwner = player;
+			town->builtBuildings.insert(BuildingID::FORT);
+			town->builtBuildings.insert(BuildingID::DEFAULT);
+			
+			placeObject(gen, town, getCenter());
+			logGlobal->infoStream() << "Placed object";
+
+			logGlobal->infoStream() << "Fill player info " << player_id;
+			auto & playerInfo = gen->map->players[player_id];
+			// Update player info
+			playerInfo.allowedFactions.clear();
+			playerInfo.allowedFactions.insert(town->subID);
+			playerInfo.hasMainTown = true;
+			playerInfo.posOfMainTown = town->pos - int3(2, 0, 0);
+			playerInfo.generateHeroAtMainTown = true;
+
+			//required_objects.push_back(town);
+
+			std::vector<Res::ERes> required_mines;
+			required_mines.push_back(Res::ERes::WOOD);
+			required_mines.push_back(Res::ERes::ORE);
+
+			for(const auto res : required_mines)
+			{			
+				auto mine = new CGMine();
+				mine->ID = Obj::MINE;
+				mine->subID = static_cast<si32>(res);
+				mine->producedResource = res;
+				mine->producedQuantity = mine->defaultResProduction();
+				required_objects.push_back(mine);
+			}
+		}
+		else
+		{			
+			type = ETemplateZoneType::TREASURE;
+			logGlobal->infoStream() << "Skipping this zone cause no player";
+		}
+	}
+	logGlobal->infoStream() << "Creating required objects";
+	for(const auto &obj : required_objects)
+	{
+		int3 pos;
+		logGlobal->infoStream() << "Looking for place";
+		if ( ! findPlaceForObject(gen, obj, 3, pos))		
+		{
+			logGlobal->errorStream() << "Failed to fill zone due to lack of space";
+			//TODO CLEANUP!
+			return false;
+		}
+		logGlobal->infoStream() << "Place found";
+
+		placeObject(gen, obj, pos);
+		logGlobal->infoStream() << "Placed object";
+	}
+	std::vector<CGObjectInstance*> guarded_objects;
+	static auto res_gen = gen->rand.getIntRange(Res::ERes::WOOD, Res::ERes::GOLD);
+	const double res_mindist = 5;
+	do {
+		auto obj = new CGResource();
+		auto restype = static_cast<Res::ERes>(res_gen());
+		obj->ID = Obj::RESOURCE;
+		obj->subID = static_cast<si32>(restype);
+		obj->amount = 0;
+		
+		int3 pos;
+		if ( ! findPlaceForObject(gen, obj, res_mindist, pos))		
+		{
+			delete obj;
+			break;
+		}
+		placeObject(gen, obj, pos);		
+		if ((restype != Res::ERes::WOOD) && (restype != Res::ERes::ORE))
+		{
+			guarded_objects.push_back(obj);
+		}
+	} while(true);
+
+	for(const auto &obj : guarded_objects)
+	{
+		if ( ! guardObject(gen, obj, 500))
+		{
+			//TODO, DEL obj from map
+		}
+	}
+
+	auto sel = gen->editManager->getTerrainSelection();
+	sel.clearSelection();
+	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
+	{
+		if (it->second.isObstacle())
+		{
+			auto obj = new CGObjectInstance();
+			obj->ID = static_cast<Obj>(130);
+			obj->subID = 0;
+			placeObject(gen, obj, it->first);
+		}
+	}
+	logGlobal->infoStream() << boost::format("Filling %d with ROCK") % sel.getSelectedItems().size();
+	//gen->editManager->drawTerrain(ETerrainType::ROCK, &gen->gen);
+	logGlobal->infoStream() << "Zone filled successfully";
+	return true;
+}
+
+bool CRmgTemplateZone::findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos)
+{
+	//si32 min_dist = sqrt(tileinfo.size()/density);
+	int best_distance = 0;
+	bool result = false;
+	si32 w = gen->map->width;
+	si32 h = gen->map->height; 
+	auto ow = obj->getWidth();
+	auto oh = obj->getHeight();
+	//logGlobal->infoStream() << boost::format("Min dist for density %f is %d") % density % min_dist;
+	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
+	{
+		auto &ti = it->second;
+		auto p = it->first;
+		auto dist = ti.getNearestObjectDistance();
+		//avoid borders
+		if ((p.x < 3) || (w - p.x < 3) || (p.y < 3) || (h - p.y < 3))
+			continue;
+		if (!ti.isOccupied() && !ti.isObstacle()  && (dist >= min_dist) && (dist > best_distance))
+		{
+			best_distance = dist;
+			pos = p;
+			result = true;
+		}
+	}
+	return result;
+}
+
+void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos)
+{
+	logGlobal->infoStream() << boost::format("Insert object at %d %d") % pos.x % pos.y;
+	object->pos = pos;
+	gen->editManager->insertObject(object, pos);
+	logGlobal->infoStream() << "Inserted object";
+	auto points = object->getBlockedPos();
+	if (object->isVisitable())
+		points.emplace(pos + object->getVisitableOffset());
+	points.emplace(pos);
+	for(auto const &p : points)
+	{		
+		if (tileinfo.find(pos + p) != tileinfo.end())
+		{
+			tileinfo[pos + p].setOccupied(true);
+		}
+	}
+	for(auto it = tileinfo.begin(); it != tileinfo.end(); ++it)
+	{		
+		si32 d = pos.dist2d(it->first);
+		it->second.setNearestObjectDistance(std::min(d, it->second.getNearestObjectDistance()));
+	}
+}
+
+bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str)
+{
+	
+	logGlobal->infoStream() << boost::format("Guard object at %d %d") % object->pos.x % object->pos.y;
+	int3 visitable = object->pos + object->getVisitableOffset();
+	std::vector<int3> tiles;
+	for(int i = -1; i < 2; ++i)
+	{
+		for(int j = -1; j < 2; ++j)
+		{
+			auto it = tileinfo.find(visitable + int3(i, j, 0));
+			if (it != tileinfo.end())
+			{
+				logGlobal->infoStream() << boost::format("Block at %d %d") % it->first.x % it->first.y;
+				if ( ! it->second.isOccupied() &&  ! it->second.isObstacle())
+				{
+					tiles.push_back(it->first);
+					it->second.setObstacle(true);
+				}
+			}
+		}
+	}
+	if ( ! tiles.size())
+	{		
+		logGlobal->infoStream() << "Failed";
+		return false;
+	}
+	auto guard_tile = *std::next(tiles.begin(), gen->rand.nextInt(tiles.size()));
+	tileinfo[guard_tile].setObstacle(false);
+	auto guard = new CGCreature();
+	guard->ID = Obj::RANDOM_MONSTER;
+	guard->subID = 0;
+	auto  hlp = new CStackInstance();
+	hlp->count = 10;
+	//type will be set during initialization
+	guard->putStack(SlotID(0), hlp);
+
+	guard->pos = guard_tile;
+	gen->editManager->insertObject(guard, guard->pos);
+	return true;
+}

+ 36 - 3
lib/rmg/CRmgTemplateZone.h

@@ -12,6 +12,9 @@
 #pragma once
 #pragma once
 
 
 #include "../GameConstants.h"
 #include "../GameConstants.h"
+#include "CMapGenerator.h"
+
+class CMapgenerator;
 
 
 namespace ETemplateZoneType
 namespace ETemplateZoneType
 {
 {
@@ -45,6 +48,27 @@ public:
 	private:
 	private:
 		int townCount, castleCount, townDensity, castleDensity;
 		int townCount, castleCount, townDensity, castleDensity;
 	};
 	};
+	
+	class DLL_LINKAGE CTileInfo
+	{
+	public:
+		CTileInfo();
+
+		int getNearestObjectDistance() const;
+		void setNearestObjectDistance(int value);
+		bool isObstacle() const;
+		void setObstacle(bool value);
+		bool isOccupied() const;
+		void setOccupied(bool value);
+		ETerrainType getTerrainType() const;
+		void setTerrainType(ETerrainType value);
+
+	private:
+		int nearestObjectDistance;
+		bool obstacle;
+		bool occupied;
+		ETerrainType terrain;
+	};
 
 
 	CRmgTemplateZone();
 	CRmgTemplateZone();
 
 
@@ -52,12 +76,10 @@ public:
 	void setId(TRmgTemplateZoneId value);
 	void setId(TRmgTemplateZoneId value);
 	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START
 	ETemplateZoneType::ETemplateZoneType getType() const; /// Default: ETemplateZoneType::PLAYER_START
 	void setType(ETemplateZoneType::ETemplateZoneType value);
 	void setType(ETemplateZoneType::ETemplateZoneType value);
-
 	int getSize() const; /// Default: 1
 	int getSize() const; /// Default: 1
 	void setSize(int value);
 	void setSize(int value);
 	boost::optional<int> getOwner() const;
 	boost::optional<int> getOwner() const;
 	void setOwner(boost::optional<int> value);
 	void setOwner(boost::optional<int> value);
-
 	const CTownInfo & getPlayerTowns() const;
 	const CTownInfo & getPlayerTowns() const;
 	void setPlayerTowns(const CTownInfo & value);
 	void setPlayerTowns(const CTownInfo & value);
 	const CTownInfo & getNeutralTowns() const;
 	const CTownInfo & getNeutralTowns() const;
@@ -69,7 +91,6 @@ public:
 	std::set<TFaction> getDefaultTownTypes() const;
 	std::set<TFaction> getDefaultTownTypes() const;
 	bool getMatchTerrainToTown() const; /// Default: true
 	bool getMatchTerrainToTown() const; /// Default: true
 	void setMatchTerrainToTown(bool value);
 	void setMatchTerrainToTown(bool value);
-
 	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all
 	const std::set<ETerrainType> & getTerrainTypes() const; /// Default: all
 	void setTerrainTypes(const std::set<ETerrainType> & value);
 	void setTerrainTypes(const std::set<ETerrainType> & value);
 	std::set<ETerrainType> getDefaultTerrainTypes() const;
 	std::set<ETerrainType> getDefaultTerrainTypes() const;
@@ -77,6 +98,8 @@ public:
 	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
 	void setTerrainTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
 	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const;
 	boost::optional<TRmgTemplateZoneId> getTownTypeLikeZone() const;
 	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
 	void setTownTypeLikeZone(boost::optional<TRmgTemplateZoneId> value);
+	void setShape(std::vector<int3> shape);
+	bool fill(CMapGenerator* gen);
 
 
 private:
 private:
 	TRmgTemplateZoneId id;
 	TRmgTemplateZoneId id;
@@ -89,4 +112,14 @@ private:
 	bool matchTerrainToTown;
 	bool matchTerrainToTown;
 	std::set<ETerrainType> terrainTypes;
 	std::set<ETerrainType> terrainTypes;
 	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone;
 	boost::optional<TRmgTemplateZoneId> terrainTypeLikeZone, townTypeLikeZone;
+
+	std::vector<int3> shape;
+	std::map<int3, CTileInfo> tileinfo;
+	std::vector<CGObjectInstance*> objects;
+
+	int3 getCenter();
+	bool pointIsIn(int x, int y);
+	bool findPlaceForObject(CMapGenerator* gen, CGObjectInstance* obj, si32 min_dist, int3 &pos);
+	void placeObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos);
+	bool guardObject(CMapGenerator* gen, CGObjectInstance* object, si32 str);
 };
 };