浏览代码

- Bug-fixing for last commit - Moved CMapGenOptions to CMapGenerator

beegee1 12 年之前
父节点
当前提交
feea589648

+ 1 - 0
client/CPreGame.cpp

@@ -1856,6 +1856,7 @@ void RandomMapTab::updateMapInfo()
 		player.team = TeamID(i);
 		player.hasMainTown = true;
 		player.generateHeroAtMainTown = true;
+		player.isFactionRandom = true;
 		mapInfo.mapHeader->players.push_back(player);
 	}
 

+ 1 - 1
client/CPreGame.h

@@ -6,7 +6,7 @@
 #include "GUIClasses.h"
 #include "FunctionList.h"
 #include "../lib/mapping/CMapInfo.h"
-#include "../lib/rmg/CMapGenOptions.h"
+#include "../lib/rmg/CMapGenerator.h"
 
 /*
  * CPreGame.h, part of VCMI engine

+ 0 - 1
lib/CGameState.cpp

@@ -25,7 +25,6 @@
 #include "JsonNode.h"
 #include "filesystem/CResourceLoader.h"
 #include "GameConstants.h"
-#include "rmg/CMapGenOptions.h"
 #include "rmg/CMapGenerator.h"
 
 DLL_LINKAGE boost::rand48 ran;

+ 0 - 1
lib/CMakeLists.txt

@@ -21,7 +21,6 @@ set(lib_SRCS
 		mapping/CMapInfo.cpp
 		mapping/CMapService.cpp
 		mapping/MapFormatH3M.cpp
-		rmg/CMapGenOptions.cpp
 		rmg/CMapGenerator.cpp
 		BattleAction.cpp
 		BattleHex.cpp

+ 1 - 0
lib/Connection.h

@@ -25,6 +25,7 @@
 #include "CCreatureSet.h" //for CStackInstance
 #include "CObjectHandler.h" //for CArmedInstance
 #include "mapping/CCampaignHandler.h" //for CCampaignState
+#include "rmg/CMapGenerator.h" // for CMapGenOptions
 
 const ui32 version = 739;
 

+ 1 - 2
lib/StartInfo.h

@@ -12,8 +12,7 @@
  *
  */
 
-#include "rmg/CMapGenOptions.h"
-
+class CMapGenOptions;
 class CCampaignState;
 
 /// Struct which describes the name, the color, the starting bonus of a player

+ 0 - 2
lib/VCMI_lib.cbp

@@ -159,8 +159,6 @@
 		<Unit filename="mapping/MapFormatH3M.h" />
 		<Unit filename="NetPacks.h" />
 		<Unit filename="NetPacksLib.cpp" />
-		<Unit filename="rmg/CMapGenOptions.cpp" />
-		<Unit filename="rmg/CMapGenOptions.h" />
 		<Unit filename="rmg/CMapGenerator.cpp" />
 		<Unit filename="rmg/CMapGenerator.h" />
 		<Unit filename="logging/CLogger.cpp" />

+ 0 - 2
lib/VCMI_lib.vcxproj

@@ -201,7 +201,6 @@
     <ClCompile Include="mapping\CMapEditManager.cpp" />
     <ClCompile Include="mapping\MapFormatH3M.cpp" />
     <ClCompile Include="RegisterTypes.cpp" />
-    <ClCompile Include="rmg\CMapGenOptions.cpp" />
     <ClCompile Include="rmg\CMapGenerator.cpp" />
     <ClCompile Include="logging\CLogger.cpp" />
     <ClCompile Include="logging\CBasicLogConfigurator.cpp" />
@@ -270,7 +269,6 @@
     <ClInclude Include="mapping\CMapService.h" />
     <ClInclude Include="mapping\CMapEditManager.h" />
     <ClInclude Include="mapping\MapFormatH3M.h" />
-    <ClInclude Include="rmg\CMapGenOptions.h" />
     <ClInclude Include="rmg\CMapGenerator.h" />
     <ClInclude Include="logging\CLogger.h" />
     <ClInclude Include="logging\CBasicLogConfigurator.h" />

+ 0 - 354
lib/rmg/CMapGenOptions.cpp

@@ -1,354 +0,0 @@
-#include "StdInc.h"
-#include "CMapGenOptions.h"
-
-#include "../GameConstants.h"
-#include "../CRandomGenerator.h"
-#include "../VCMI_Lib.h"
-#include "../CTownHandler.h"
-
-CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true),
-	playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE),
-	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM)
-{
-
-}
-
-si32 CMapGenOptions::getWidth() const
-{
-	return width;
-}
-
-void CMapGenOptions::setWidth(si32 value)
-{
-	if(value > 0)
-	{
-		width = value;
-	}
-	else
-	{
-		throw std::runtime_error("A map width lower than 1 is not allowed.");
-	}
-}
-
-si32 CMapGenOptions::getHeight() const
-{
-	return height;
-}
-
-void CMapGenOptions::setHeight(si32 value)
-{
-	if(value > 0)
-	{
-		height = value;
-	}
-	else
-	{
-		throw std::runtime_error("A map height lower than 1 is not allowed.");
-	}
-}
-
-bool CMapGenOptions::getHasTwoLevels() const
-{
-	return hasTwoLevels;
-}
-
-void CMapGenOptions::setHasTwoLevels(bool value)
-{
-	hasTwoLevels = value;
-}
-
-si8 CMapGenOptions::getPlayersCnt() const
-{
-	return playersCnt;
-}
-
-void CMapGenOptions::setPlayersCnt(si8 value)
-{
-	if((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE)
-	{
-		playersCnt = value;
-		resetPlayersMap();
-	}
-	else
-	{
-		throw std::runtime_error("Players count of RMG options should be between 1 and " +
-								 boost::lexical_cast<std::string>(PlayerColor::PLAYER_LIMIT) + " or CMapGenOptions::RANDOM_SIZE for random.");
-	}
-}
-
-si8 CMapGenOptions::getTeamsCnt() const
-{
-	return teamsCnt;
-}
-
-void CMapGenOptions::setTeamsCnt(si8 value)
-{
-	if(playersCnt == RANDOM_SIZE || (value >= 0 && value < playersCnt) || value == RANDOM_SIZE)
-	{
-		teamsCnt = value;
-	}
-	else
-	{
-		throw std::runtime_error("Teams count of RMG options should be between 0 and <" +
-								 boost::lexical_cast<std::string>(playersCnt) + "(players count) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
-	}
-}
-
-si8 CMapGenOptions::getCompOnlyPlayersCnt() const
-{
-	return compOnlyPlayersCnt;
-}
-
-void CMapGenOptions::setCompOnlyPlayersCnt(si8 value)
-{
-	if(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playersCnt))
-	{
-		compOnlyPlayersCnt = value;
-		resetPlayersMap();
-	}
-	else
-	{
-		throw std::runtime_error(std::string("Computer only players count of RMG options should be ") +
-								 "between 0 and <PlayerColor::PLAYER_LIMIT - " + boost::lexical_cast<std::string>(playersCnt) +
-								 "(playersCount)> or CMapGenOptions::RANDOM_SIZE for random.");
-	}
-}
-
-si8 CMapGenOptions::getCompOnlyTeamsCnt() const
-{
-	return compOnlyTeamsCnt;
-}
-
-void CMapGenOptions::setCompOnlyTeamsCnt(si8 value)
-{
-	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0)))
-	{
-		compOnlyTeamsCnt = value;
-	}
-	else
-	{
-		throw std::runtime_error(std::string("Computer only teams count of RMG options should be ") +
-								 "between 0 and <" + boost::lexical_cast<std::string>(compOnlyPlayersCnt) +
-								 "(compOnlyPlayersCnt) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
-	}
-}
-
-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 = playersCnt == RANDOM_SIZE ? PlayerColor::PLAYER_LIMIT_I : playersCnt;
-	int realCompOnlyPlayersCnt = compOnlyPlayersCnt == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayersCnt;
-	for(int color = 0; color < (realPlayersCnt + realCompOnlyPlayersCnt); ++color)
-	{
-		CPlayerSettings player;
-		player.setColor(PlayerColor(color));
-		player.setPlayerType((color >= playersCnt) ? 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()) throw std::runtime_error(boost::str(boost::format("Cannot set starting town for the player with the color '%i'.") % color));
-	it->second.setStartingTown(town);
-}
-
-void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
-{
-	auto it = players.find(color);
-	if(it == players.end()) throw std::runtime_error(boost::str(boost::format("Cannot set player type for the player with the color '%i'.") % color));
-	if(playerType == EPlayerType::COMP_ONLY) throw std::runtime_error("Cannot set player type computer only to a standard player.");
-	it->second.setPlayerType(playerType);
-}
-
-void CMapGenOptions::finalize()
-{
-	CRandomGenerator gen;
-	finalize(gen);
-}
-
-void CMapGenOptions::finalize(CRandomGenerator & gen)
-{
-	if(playersCnt == RANDOM_SIZE)
-	{
-		// 1 human is required at least
-		auto humanPlayers = countHumanPlayers();
-		if(humanPlayers == 0) humanPlayers = 1;
-		playersCnt = gen.getInteger(humanPlayers, PlayerColor::PLAYER_LIMIT_I);
-
-		// 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() == playersCnt) break;
-			if(it->second.getPlayerType() == EPlayerType::AI)
-			{
-				players.erase(it);
-			}
-			else
-			{
-				--itrev;
-			}
-		}
-	}
-	if(teamsCnt == RANDOM_SIZE)
-	{
-		teamsCnt = gen.getInteger(0, playersCnt - 1);
-	}
-	if(compOnlyPlayersCnt == RANDOM_SIZE)
-	{
-		compOnlyPlayersCnt = gen.getInteger(0, 8 - playersCnt);
-		auto totalPlayersCnt = playersCnt + compOnlyPlayersCnt;
-
-		// 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;
-		}
-	}
-	if(compOnlyTeamsCnt == RANDOM_SIZE)
-	{
-		compOnlyTeamsCnt = gen.getInteger(0, std::max(compOnlyPlayersCnt - 1, 0));
-	}
-
-	// There should be at least 2 players (1-player-maps aren't allowed)
-	if(playersCnt + compOnlyPlayersCnt < 2)
-	{
-		CPlayerSettings pSettings;
-		pSettings.setPlayerType(EPlayerType::AI);
-		pSettings.setColor(getNextPlayerColor());
-		players[pSettings.getColor()] = pSettings;
-		playersCnt = 2;
-	}
-
-	// 1 team isn't allowed
-	if(teamsCnt == 1 && compOnlyPlayersCnt == 0)
-	{
-		teamsCnt = 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));
-	}
-}
-
-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;
-		}
-	}
-	throw std::runtime_error("Shouldn't happen. No free player color exists.");
-}
-
-CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
-{
-
-}
-
-PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
-{
-	return color;
-}
-
-void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
-{
-	if(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT)
-	{
-		color = value;
-	}
-	else
-	{
-		throw std::runtime_error("The color of the player is not in a valid range.");
-	}
-}
-
-si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
-{
-	return startingTown;
-}
-
-void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
-{
-	if(value >= -1 && value < static_cast<int>(VLC->townh->towns.size()))
-	{
-		startingTown = value;
-	}
-	else
-	{
-		throw std::runtime_error("The starting town of the player is not in a valid range.");
-	}
-}
-
-EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
-{
-	return playerType;
-}
-
-void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
-{
-	playerType = value;
-}

+ 0 - 163
lib/rmg/CMapGenOptions.h

@@ -1,163 +0,0 @@
-
-/*
- * 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"
-
-class CRandomGenerator;
-
-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 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 getPlayersCnt() const;
-	void setPlayersCnt(si8 value);
-
-	/// The count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random.
-	si8 getTeamsCnt() const;
-	void setTeamsCnt(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 getCompOnlyPlayersCnt() const;
-	void setCompOnlyPlayersCnt(si8 value);
-
-	/// The count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random.
-	si8 getCompOnlyTeamsCnt() const;
-	void setCompOnlyTeamsCnt(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. Calling this method
-	/// has no effect for the map itself, but it adds some informational text for the map description.
-	void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType);
-
-	/// 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.
-	void finalize();
-	void finalize(CRandomGenerator & gen);
-
-	static const si8 RANDOM_SIZE = -1;
-
-private:
-	void resetPlayersMap();
-	int countHumanPlayers() const;
-	PlayerColor getNextPlayerColor() const;
-
-	si32 width, height;
-	bool hasTwoLevels;
-	si8 playersCnt, teamsCnt, compOnlyPlayersCnt, compOnlyTeamsCnt;
-	EWaterContent::EWaterContent waterContent;
-	EMonsterStrength::EMonsterStrength monsterStrength;
-	std::map<PlayerColor, CPlayerSettings> players;
-
-public:
-	template <typename Handler>
-	void serialize(Handler & h, const int version)
-	{
-		//FIXME: Enum is not a fixed with data type. Add enum class to both enums
-		// later. For now it is ok.
-		h & width & height & hasTwoLevels & playersCnt & teamsCnt & compOnlyPlayersCnt;
-		h & compOnlyTeamsCnt & waterContent & monsterStrength & players;
-	}
-};

+ 347 - 1
lib/rmg/CMapGenerator.cpp

@@ -7,10 +7,356 @@
 #include "../mapping/CMapEditManager.h"
 #include "../CObjectHandler.h"
 #include "../CDefObjInfoHandler.h"
-#include "../GameConstants.h"
 #include "../CTownHandler.h"
 #include "../StringConstants.h"
 
+CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true),
+	playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE),
+	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM)
+{
+	resetPlayersMap();
+}
+
+si32 CMapGenOptions::getWidth() const
+{
+	return width;
+}
+
+void CMapGenOptions::setWidth(si32 value)
+{
+	if(value > 0)
+	{
+		width = value;
+	}
+	else
+	{
+		throw std::runtime_error("A map width lower than 1 is not allowed.");
+	}
+}
+
+si32 CMapGenOptions::getHeight() const
+{
+	return height;
+}
+
+void CMapGenOptions::setHeight(si32 value)
+{
+	if(value > 0)
+	{
+		height = value;
+	}
+	else
+	{
+		throw std::runtime_error("A map height lower than 1 is not allowed.");
+	}
+}
+
+bool CMapGenOptions::getHasTwoLevels() const
+{
+	return hasTwoLevels;
+}
+
+void CMapGenOptions::setHasTwoLevels(bool value)
+{
+	hasTwoLevels = value;
+}
+
+si8 CMapGenOptions::getPlayersCnt() const
+{
+	return playersCnt;
+}
+
+void CMapGenOptions::setPlayersCnt(si8 value)
+{
+	if((value >= 1 && value <= PlayerColor::PLAYER_LIMIT_I) || value == RANDOM_SIZE)
+	{
+		playersCnt = value;
+		resetPlayersMap();
+	}
+	else
+	{
+		throw std::runtime_error("Players count of RMG options should be between 1 and " +
+								 std::to_string(PlayerColor::PLAYER_LIMIT_I) + " or CMapGenOptions::RANDOM_SIZE for random.");
+	}
+}
+
+si8 CMapGenOptions::getTeamsCnt() const
+{
+	return teamsCnt;
+}
+
+void CMapGenOptions::setTeamsCnt(si8 value)
+{
+	if(playersCnt == RANDOM_SIZE || (value >= 0 && value < playersCnt) || value == RANDOM_SIZE)
+	{
+		teamsCnt = value;
+	}
+	else
+	{
+		throw std::runtime_error("Teams count of RMG options should be between 0 and <" +
+								 std::to_string(playersCnt) + "(players count) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
+	}
+}
+
+si8 CMapGenOptions::getCompOnlyPlayersCnt() const
+{
+	return compOnlyPlayersCnt;
+}
+
+void CMapGenOptions::setCompOnlyPlayersCnt(si8 value)
+{
+	if(value == RANDOM_SIZE || (value >= 0 && value <= PlayerColor::PLAYER_LIMIT_I - playersCnt))
+	{
+		compOnlyPlayersCnt = value;
+		resetPlayersMap();
+	}
+	else
+	{
+		throw std::runtime_error(std::string("Computer only players count of RMG options should be ") +
+								 "between 0 and <PlayerColor::PLAYER_LIMIT - " + std::to_string(playersCnt) +
+								 "(playersCount)> or CMapGenOptions::RANDOM_SIZE for random.");
+	}
+}
+
+si8 CMapGenOptions::getCompOnlyTeamsCnt() const
+{
+	return compOnlyTeamsCnt;
+}
+
+void CMapGenOptions::setCompOnlyTeamsCnt(si8 value)
+{
+	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0)))
+	{
+		compOnlyTeamsCnt = value;
+	}
+	else
+	{
+		throw std::runtime_error(std::string("Computer only teams count of RMG options should be ") +
+								 "between 0 and <" + std::to_string(compOnlyPlayersCnt) +
+								 "(compOnlyPlayersCnt) - 1> or CMapGenOptions::RANDOM_SIZE for random.");
+	}
+}
+
+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 = playersCnt == RANDOM_SIZE ? PlayerColor::PLAYER_LIMIT_I : playersCnt;
+	int realCompOnlyPlayersCnt = compOnlyPlayersCnt == RANDOM_SIZE ? (PlayerColor::PLAYER_LIMIT_I - realPlayersCnt) : compOnlyPlayersCnt;
+	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()) throw std::runtime_error(boost::str(boost::format("Cannot set starting town for the player with the color '%s'.") % std::to_string(color.getNum())));
+	it->second.setStartingTown(town);
+}
+
+void CMapGenOptions::setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType)
+{
+	auto it = players.find(color);
+	if(it == players.end()) throw std::runtime_error(boost::str(boost::format("Cannot set player type for the player with the color '%s'.") % std::to_string(color.getNum())));
+	if(playerType == EPlayerType::COMP_ONLY) throw std::runtime_error("Cannot set player type computer only to a standard player.");
+	it->second.setPlayerType(playerType);
+}
+
+void CMapGenOptions::finalize()
+{
+	CRandomGenerator gen;
+	finalize(gen);
+}
+
+void CMapGenOptions::finalize(CRandomGenerator & gen)
+{
+	if(playersCnt == RANDOM_SIZE)
+	{
+		// 1 human is required at least
+		auto humanPlayers = countHumanPlayers();
+		if(humanPlayers == 0) humanPlayers = 1;
+		playersCnt = gen.getInteger(humanPlayers, PlayerColor::PLAYER_LIMIT_I);
+
+		// 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() == playersCnt) break;
+			if(it->second.getPlayerType() == EPlayerType::AI)
+			{
+				players.erase(it);
+			}
+			else
+			{
+				--itrev;
+			}
+		}
+	}
+	if(teamsCnt == RANDOM_SIZE)
+	{
+		teamsCnt = gen.getInteger(0, playersCnt - 1);
+	}
+	if(compOnlyPlayersCnt == RANDOM_SIZE)
+	{
+		compOnlyPlayersCnt = gen.getInteger(0, 8 - playersCnt);
+		auto totalPlayersCnt = playersCnt + compOnlyPlayersCnt;
+
+		// 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;
+		}
+	}
+	if(compOnlyTeamsCnt == RANDOM_SIZE)
+	{
+		compOnlyTeamsCnt = gen.getInteger(0, std::max(compOnlyPlayersCnt - 1, 0));
+	}
+
+	// There should be at least 2 players (1-player-maps aren't allowed)
+	if(playersCnt + compOnlyPlayersCnt < 2)
+	{
+		CPlayerSettings pSettings;
+		pSettings.setPlayerType(EPlayerType::AI);
+		pSettings.setColor(getNextPlayerColor());
+		players[pSettings.getColor()] = pSettings;
+		playersCnt = 2;
+	}
+
+	// 1 team isn't allowed
+	if(teamsCnt == 1 && compOnlyPlayersCnt == 0)
+	{
+		teamsCnt = 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));
+	}
+}
+
+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;
+		}
+	}
+	throw std::runtime_error("Shouldn't happen. No free player color exists.");
+}
+
+CMapGenOptions::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(EPlayerType::AI)
+{
+
+}
+
+PlayerColor CMapGenOptions::CPlayerSettings::getColor() const
+{
+	return color;
+}
+
+void CMapGenOptions::CPlayerSettings::setColor(PlayerColor value)
+{
+	if(value >= PlayerColor(0) && value < PlayerColor::PLAYER_LIMIT)
+	{
+		color = value;
+	}
+	else
+	{
+		throw std::runtime_error("The color of the player is not in a valid range.");
+	}
+}
+
+si32 CMapGenOptions::CPlayerSettings::getStartingTown() const
+{
+	return startingTown;
+}
+
+void CMapGenOptions::CPlayerSettings::setStartingTown(si32 value)
+{
+	if(value >= -1 && value < static_cast<int>(VLC->townh->towns.size()))
+	{
+		startingTown = value;
+	}
+	else
+	{
+		throw std::runtime_error("The starting town of the player is not in a valid range.");
+	}
+}
+
+EPlayerType::EPlayerType CMapGenOptions::CPlayerSettings::getPlayerType() const
+{
+	return playerType;
+}
+
+void CMapGenOptions::CPlayerSettings::setPlayerType(EPlayerType::EPlayerType value)
+{
+	playerType = value;
+}
+
 CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, int randomSeed) :
 	mapGenOptions(mapGenOptions), randomSeed(randomSeed)
 {

+ 147 - 1
lib/rmg/CMapGenerator.h

@@ -12,13 +12,159 @@
 #pragma once
 
 #include "../GameConstants.h"
-#include "CMapGenOptions.h"
 #include "../CRandomGenerator.h"
 
 class CMap;
 class CTerrainViewPatternConfig;
 class CMapEditManager;
 
+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 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 getPlayersCnt() const;
+	void setPlayersCnt(si8 value);
+
+	/// The count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random.
+	si8 getTeamsCnt() const;
+	void setTeamsCnt(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 getCompOnlyPlayersCnt() const;
+	void setCompOnlyPlayersCnt(si8 value);
+
+	/// The count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random.
+	si8 getCompOnlyTeamsCnt() const;
+	void setCompOnlyTeamsCnt(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. Calling this method
+	/// has no effect for the map itself, but it adds some informational text for the map description.
+	void setPlayerTypeForStandardPlayer(PlayerColor color, EPlayerType::EPlayerType playerType);
+
+	/// 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.
+	void finalize();
+	void finalize(CRandomGenerator & gen);
+
+	static const si8 RANDOM_SIZE = -1;
+
+private:
+	void resetPlayersMap();
+	int countHumanPlayers() const;
+	PlayerColor getNextPlayerColor() const;
+
+	si32 width, height;
+	bool hasTwoLevels;
+	si8 playersCnt, teamsCnt, compOnlyPlayersCnt, compOnlyTeamsCnt;
+	EWaterContent::EWaterContent waterContent;
+	EMonsterStrength::EMonsterStrength monsterStrength;
+	std::map<PlayerColor, CPlayerSettings> players;
+
+public:
+	template <typename Handler>
+	void serialize(Handler & h, const int version)
+	{
+		//FIXME: Enum is not a fixed with data type. Add enum class to both enums
+		// later. For now it is ok.
+		h & width & height & hasTwoLevels & playersCnt & teamsCnt & compOnlyPlayersCnt;
+		h & compOnlyTeamsCnt & waterContent & monsterStrength & players;
+	}
+};
+
 /// The map generator creates a map randomly.
 class DLL_LINKAGE CMapGenerator
 {