mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- Added basic mock/test generation - Added stub for terrain editing
This commit is contained in:
		| @@ -1,8 +1,10 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CMapGenOptions.h" | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
|  | ||||
| CMapGenOptions::CMapGenOptions() : width(72), height(72), hasTwoLevels(true), | ||||
| 	playersCnt(-1), teamsCnt(-1), compOnlyPlayersCnt(0), compOnlyTeamsCnt(-1), | ||||
| 	playersCnt(RANDOM_SIZE), teamsCnt(RANDOM_SIZE), compOnlyPlayersCnt(0), compOnlyTeamsCnt(RANDOM_SIZE), | ||||
| 	waterContent(EWaterContent::RANDOM), monsterStrength(EMonsterStrength::RANDOM) | ||||
| { | ||||
|  | ||||
| @@ -13,7 +15,7 @@ si32 CMapGenOptions::getWidth() const | ||||
| 	return width; | ||||
| } | ||||
|  | ||||
| void CMapGenOptions::setWidth(int value) | ||||
| void CMapGenOptions::setWidth(si32 value) | ||||
| { | ||||
| 	if(value > 0) | ||||
| 	{ | ||||
| @@ -21,7 +23,7 @@ void CMapGenOptions::setWidth(int value) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Map width lower than 1 not allowed."); | ||||
| 		throw std::runtime_error("A map width lower than 1 is not allowed."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -38,7 +40,7 @@ void CMapGenOptions::setHeight(si32 value) | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Map height lower than 1 not allowed."); | ||||
| 		throw std::runtime_error("A map height lower than 1 is not allowed."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -59,13 +61,14 @@ si8 CMapGenOptions::getPlayersCnt() const | ||||
|  | ||||
| void CMapGenOptions::setPlayersCnt(si8 value) | ||||
| { | ||||
| 	if((value >= 1 && value <= 8) || value == RANDOM_SIZE) | ||||
| 	if((value >= 1 && value <= GameConstants::PLAYER_LIMIT) || value == RANDOM_SIZE) | ||||
| 	{ | ||||
| 		playersCnt = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("Players count of RMG options should be between 1 and 8 or -1 for random."); | ||||
| 		throw std::runtime_error("Players count of RMG options should be between 1 and " + | ||||
| 			boost::lexical_cast<std::string>(GameConstants::PLAYER_LIMIT) + " or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -83,7 +86,7 @@ void CMapGenOptions::setTeamsCnt(si8 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 -1 for random."); | ||||
| 			boost::lexical_cast<std::string>(playersCnt) + "(players count) - 1> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -94,15 +97,15 @@ si8 CMapGenOptions::getCompOnlyPlayersCnt() const | ||||
|  | ||||
| void CMapGenOptions::setCompOnlyPlayersCnt(si8 value) | ||||
| { | ||||
| 	if(value == RANDOM_SIZE || (value >= 0 && value <= 8 - playersCnt)) | ||||
| 	if(value == RANDOM_SIZE || (value >= 0 && value <= GameConstants::PLAYER_LIMIT - playersCnt)) | ||||
| 	{ | ||||
| 		compOnlyPlayersCnt = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error(std::string("Computer only players count of RMG options should be ") + | ||||
| 			"between 0 and <8 - " + boost::lexical_cast<std::string>(playersCnt) + | ||||
| 			"(playersCount)> or -1 for random."); | ||||
| 			"between 0 and <GameConstants::PLAYER_LIMIT - " + boost::lexical_cast<std::string>(playersCnt) + | ||||
| 			"(playersCount)> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -113,7 +116,7 @@ si8 CMapGenOptions::getCompOnlyTeamsCnt() const | ||||
|  | ||||
| void CMapGenOptions::setCompOnlyTeamsCnt(si8 value) | ||||
| { | ||||
| 	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= compOnlyPlayersCnt - 1)) | ||||
| 	if(value == RANDOM_SIZE || compOnlyPlayersCnt == RANDOM_SIZE || (value >= 0 && value <= std::max(compOnlyPlayersCnt - 1, 0))) | ||||
| 	{ | ||||
| 		compOnlyTeamsCnt = value; | ||||
| 	} | ||||
| @@ -121,7 +124,7 @@ void CMapGenOptions::setCompOnlyTeamsCnt(si8 value) | ||||
| 	{ | ||||
| 		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 -1 for random."); | ||||
| 			"(compOnlyPlayersCnt) - 1> or CMapGenOptions::RANDOM_SIZE for random."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -89,61 +89,61 @@ public: | ||||
| 	void setHasTwoLevels(bool value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the players. The default value is -1 representing a random | ||||
| 	 * Gets the count of the players. The default value is RANDOM_SIZE representing a random | ||||
| 	 * player count. | ||||
| 	 * | ||||
| 	 * @return the count of the players ranging from 1 to 8 or -1 for random | ||||
| 	 * @return the count of the players ranging from 1 to GameConstants::PLAYER_LIMIT or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	si8 getPlayersCnt() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the count of the players. | ||||
| 	 * | ||||
| 	 * @param value the count of the players ranging from 1 to 8, -1 for random | ||||
| 	 * @param value the count of the players ranging from 1 to GameConstants::PLAYER_LIMIT, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setPlayersCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the teams. The default value is -1 representing a random | ||||
| 	 * Gets the count of the teams. The default value is RANDOM_SIZE representing a random | ||||
| 	 * team count. | ||||
| 	 * | ||||
| 	 * @return the count of the teams ranging from 0 to <players count - 1> or -1 for random | ||||
| 	 * @return the count of the teams ranging from 0 to <players count - 1> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	si8 getTeamsCnt() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the count of the teams | ||||
| 	 * | ||||
| 	 * @param value the count of the teams ranging from 0 to <players count - 1>, -1 for random | ||||
| 	 * @param value the count of the teams ranging from 0 to <players count - 1>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setTeamsCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the computer only players. The default value is 0. | ||||
| 	 * | ||||
| 	 * @return the count of the computer only players ranging from 0 to <8 - players count> or -1 for random | ||||
| 	 * @return the count of the computer only players ranging from 0 to <GameConstants::PLAYER_LIMIT - players count> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	si8 getCompOnlyPlayersCnt() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the count of the computer only players. | ||||
| 	 * | ||||
| 	 * @param value the count of the computer only players ranging from 0 to <8 - players count>, -1 for random | ||||
| 	 * @param value the count of the computer only players ranging from 0 to <GameConstants::PLAYER_LIMIT - players count>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setCompOnlyPlayersCnt(si8 value); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the count of the computer only teams. The default value is -1 representing | ||||
| 	 * Gets the count of the computer only teams. The default value is RANDOM_SIZE representing | ||||
| 	 * a random computer only team count. | ||||
| 	 * | ||||
| 	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1> or -1 for random | ||||
| 	 * @return the count of the computer only teams ranging from 0 to <comp only players - 1> or RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	si8 getCompOnlyTeamsCnt() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the count of the computer only teams. | ||||
| 	 * | ||||
| 	 * @param value the count of the computer only teams ranging from 0 to <comp only players - 1>, -1 for random | ||||
| 	 * @param value the count of the computer only teams ranging from 0 to <comp only players - 1>, RANDOM_SIZE for random | ||||
| 	 */ | ||||
| 	void setCompOnlyTeamsCnt(si8 value); | ||||
|  | ||||
| @@ -213,6 +213,8 @@ 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; | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										399
									
								
								lib/RMG/CMapGenerator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										399
									
								
								lib/RMG/CMapGenerator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,399 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CMapGenerator.h" | ||||
|  | ||||
| #include "../Mapping/CMap.h" | ||||
| #include "../VCMI_Lib.h" | ||||
| #include "../CGeneralTextHandler.h" | ||||
| #include "../Mapping/CMapEditManager.h" | ||||
| #include "../CObjectHandler.h" | ||||
| #include "../CDefObjInfoHandler.h" | ||||
| #include "../GameConstants.h" | ||||
| #include "../CTownHandler.h" | ||||
| #include "../StringConstants.h" | ||||
|  | ||||
| CMapGenerator::CMapGenerator(const CMapGenOptions & mapGenOptions, const std::map<TPlayerColor, CPlayerSettings> & players, int randomSeed) : | ||||
| 	mapGenOptions(mapGenOptions), randomSeed(randomSeed), players(players) | ||||
| { | ||||
| 	gen.seed(randomSeed); | ||||
| 	validateOptions(); | ||||
| } | ||||
|  | ||||
| CMapGenerator::~CMapGenerator() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMap> CMapGenerator::generate() | ||||
| { | ||||
| 	finalizeMapGenOptions(); | ||||
|  | ||||
| 	//TODO select a template based on the map gen options or adapt it if necessary | ||||
|  | ||||
| 	map = std::unique_ptr<CMap>(new CMap()); | ||||
| 	addHeaderInfo(); | ||||
|  | ||||
| 	terViewPatternConfig = std::unique_ptr<CTerrainViewPatternConfig>(new CTerrainViewPatternConfig()); | ||||
| 	mapMgr = std::unique_ptr<CMapEditManager>(new CMapEditManager(terViewPatternConfig.get(), map.get(), randomSeed)); | ||||
| 	genTerrain(); | ||||
| 	genTowns(); | ||||
|  | ||||
| 	return std::move(map); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::validateOptions() const | ||||
| { | ||||
| 	int playersCnt = 0; | ||||
| 	int compOnlyPlayersCnt = 0; | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		if(pair.second.getPlayerType() == CPlayerSettings::COMP_ONLY) | ||||
| 		{ | ||||
| 			++compOnlyPlayersCnt; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			++playersCnt; | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		if(playersCnt != GameConstants::PLAYER_LIMIT) | ||||
| 		{ | ||||
| 			throw std::runtime_error(std::string("If the count of players is random size, ") | ||||
| 				+ "the count of the items in the players map should equal GameConstants::PLAYER_LIMIT."); | ||||
| 		} | ||||
| 		if(playersCnt == mapGenOptions.getPlayersCnt()) | ||||
| 		{ | ||||
| 			throw std::runtime_error(std::string("If the count of players is random size, ") | ||||
| 				+ "all items in the players map should be either of player type AI or HUMAN."); | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if(mapGenOptions.getCompOnlyPlayersCnt() != CMapGenOptions::RANDOM_SIZE) | ||||
| 		{ | ||||
| 			if(playersCnt != mapGenOptions.getPlayersCnt() || compOnlyPlayersCnt != mapGenOptions.getCompOnlyPlayersCnt()) | ||||
| 			{ | ||||
| 				throw std::runtime_error(std::string("The count of players and computer only players in the players map ") | ||||
| 					+ "doesn't conform with the specified map gen options."); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if(playersCnt != mapGenOptions.getPlayersCnt() || (playersCnt == mapGenOptions.getPlayersCnt() | ||||
| 				&& compOnlyPlayersCnt != GameConstants::PLAYER_LIMIT - playersCnt)) | ||||
| 			{ | ||||
| 				throw std::runtime_error(std::string("If the count of players is fixed and the count of comp only players random, ") | ||||
| 					+ "the items in the players map should equal GameConstants::PLAYER_LIMIT."); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if(countHumanPlayers() < 1) | ||||
| 	{ | ||||
| 		throw std::runtime_error("1 human player is required at least"); | ||||
| 	} | ||||
|  | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		if(pair.first != pair.second.getColor()) | ||||
| 		{ | ||||
| 			throw std::runtime_error("The color of an item in player settings and the key of it has to be the same."); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapGenerator::finalizeMapGenOptions() | ||||
| { | ||||
| 	if(mapGenOptions.getPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setPlayersCnt(gen.getInteger(countHumanPlayers(), GameConstants::PLAYER_LIMIT)); | ||||
|  | ||||
| 		// 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() == mapGenOptions.getPlayersCnt()) | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 			const CPlayerSettings & pSettings = it->second; | ||||
| 			if(pSettings.getPlayerType() == CPlayerSettings::AI) | ||||
| 			{ | ||||
| 				players.erase(it); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				--itrev; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getTeamsCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setTeamsCnt(gen.getInteger(0, mapGenOptions.getPlayersCnt() - 1)); | ||||
| 	} | ||||
| 	if(mapGenOptions.getCompOnlyPlayersCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setCompOnlyPlayersCnt(gen.getInteger(0, 8 - mapGenOptions.getPlayersCnt())); | ||||
| 		int totalPlayersCnt = mapGenOptions.getPlayersCnt() + mapGenOptions.getCompOnlyPlayersCnt(); | ||||
|  | ||||
| 		// 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; | ||||
| 			} | ||||
| 			const CPlayerSettings & pSettings = it->second; | ||||
| 			if(pSettings.getPlayerType() == CPlayerSettings::COMP_ONLY) | ||||
| 			{ | ||||
| 				players.erase(it); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				--itrev; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		// Add some comp only players if necessary | ||||
| 		int compOnlyPlayersToAdd = totalPlayersCnt - players.size(); | ||||
| 		for(int i = 0; i < compOnlyPlayersToAdd; ++i) | ||||
| 		{ | ||||
| 			CPlayerSettings pSettings; | ||||
| 			pSettings.setPlayerType(CPlayerSettings::COMP_ONLY); | ||||
| 			pSettings.setColor(getNextPlayerColor()); | ||||
| 			players[pSettings.getColor()] = pSettings; | ||||
| 		} | ||||
| 	} | ||||
| 	if(mapGenOptions.getCompOnlyTeamsCnt() == CMapGenOptions::RANDOM_SIZE) | ||||
| 	{ | ||||
| 		mapGenOptions.setCompOnlyTeamsCnt(gen.getInteger(0, std::max(mapGenOptions.getCompOnlyPlayersCnt() - 1, 0))); | ||||
| 	} | ||||
|  | ||||
| 	// There should be at least 2 players (1-player-maps aren't allowed) | ||||
| 	if(mapGenOptions.getPlayersCnt() + mapGenOptions.getCompOnlyPlayersCnt() < 2) | ||||
| 	{ | ||||
| 		CPlayerSettings pSettings; | ||||
| 		pSettings.setPlayerType(CPlayerSettings::AI); | ||||
| 		pSettings.setColor(getNextPlayerColor()); | ||||
| 		players[pSettings.getColor()] = pSettings; | ||||
| 		mapGenOptions.setPlayersCnt(2); | ||||
| 	} | ||||
|  | ||||
| 	// 1 team isn't allowed | ||||
| 	if(mapGenOptions.getTeamsCnt() == 1 && mapGenOptions.getCompOnlyPlayersCnt() == 0) | ||||
| 	{ | ||||
| 		mapGenOptions.setTeamsCnt(0); | ||||
| 	} | ||||
|  | ||||
| 	if(mapGenOptions.getWaterContent() == EWaterContent::RANDOM) | ||||
| 	{ | ||||
| 		mapGenOptions.setWaterContent(static_cast<EWaterContent::EWaterContent>(gen.getInteger(0, 2))); | ||||
| 	} | ||||
| 	if(mapGenOptions.getMonsterStrength() == EMonsterStrength::RANDOM) | ||||
| 	{ | ||||
| 		mapGenOptions.setMonsterStrength(static_cast<EMonsterStrength::EMonsterStrength>(gen.getInteger(0, 2))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string CMapGenerator::getMapDescription() const | ||||
| { | ||||
| 	const std::string waterContentStr[3] = { "none", "normal", "islands" }; | ||||
| 	const std::string monsterStrengthStr[3] = { "weak", "normal", "strong" }; | ||||
|  | ||||
| 	std::stringstream ss; | ||||
| 	ss << "Map created by the Random Map Generator.\nTemplate was <MOCK>, "; | ||||
| 	ss << "Random seed was " << randomSeed << ", size " << map->width << "x"; | ||||
| 	ss << map->height << ", levels " << (map->twoLevel ? "2" : "1") << ", "; | ||||
| 	ss << "humans " << static_cast<int>(mapGenOptions.getPlayersCnt()) << ", computers "; | ||||
| 	ss << static_cast<int>(mapGenOptions.getCompOnlyPlayersCnt()) << ", water " << waterContentStr[mapGenOptions.getWaterContent()]; | ||||
| 	ss << ", monster " << monsterStrengthStr[mapGenOptions.getMonsterStrength()] << ", second expansion map"; | ||||
|  | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		const CPlayerSettings & pSettings = pair.second; | ||||
| 		if(pSettings.getPlayerType() == CPlayerSettings::HUMAN) | ||||
| 		{ | ||||
| 			ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor()] << " is human"; | ||||
| 		} | ||||
| 		if(pSettings.getStartingTown() != CPlayerSettings::RANDOM_TOWN) | ||||
| 		{ | ||||
| 			ss << ", " << GameConstants::PLAYER_COLOR_NAMES[pSettings.getColor()] | ||||
| 				<< " town choice is " << ETownType::names[pSettings.getStartingTown()]; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ss.str(); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::addPlayerInfo() | ||||
| { | ||||
| 	// Calculate which team numbers exist | ||||
| 	std::array<std::list<int>, 2> teamNumbers; // 0= cpu/human, 1= cpu only | ||||
| 	int teamOffset = 0; | ||||
| 	for(int i = 0; i < 2; ++i) | ||||
| 	{ | ||||
| 		int playersCnt = i == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getCompOnlyPlayersCnt(); | ||||
| 		int teamsCnt = i == 0 ? mapGenOptions.getTeamsCnt() : mapGenOptions.getCompOnlyTeamsCnt(); | ||||
|  | ||||
| 		if(playersCnt == 0) | ||||
| 		{ | ||||
| 			continue; | ||||
| 		} | ||||
| 		int playersPerTeam = playersCnt / | ||||
| 				(teamsCnt == 0 ? playersCnt : teamsCnt); | ||||
| 		int teamsCntNorm = teamsCnt; | ||||
| 		if(teamsCntNorm == 0) | ||||
| 		{ | ||||
| 			teamsCntNorm = playersCnt; | ||||
| 		} | ||||
| 		for(int j = 0; j < teamsCntNorm; ++j) | ||||
| 		{ | ||||
| 			for(int k = 0; k < playersPerTeam; ++k) | ||||
| 			{ | ||||
| 				teamNumbers[i].push_back(j + teamOffset); | ||||
| 			} | ||||
| 		} | ||||
| 		for(int j = 0; j < playersCnt - teamsCntNorm * playersPerTeam; ++j) | ||||
| 		{ | ||||
| 			teamNumbers[i].push_back(j + teamOffset); | ||||
| 		} | ||||
| 		teamOffset += teamsCntNorm; | ||||
| 	} | ||||
|  | ||||
| 	// Team numbers are assigned randomly to every player | ||||
| 	BOOST_FOREACH(const tPlayersMap::value_type & pair, players) | ||||
| 	{ | ||||
| 		const CPlayerSettings & pSettings = pair.second; | ||||
| 		PlayerInfo player; | ||||
| 		player.canComputerPlay = true; | ||||
| 		int j = pSettings.getPlayerType() == CPlayerSettings::COMP_ONLY ? 1 : 0; | ||||
| 		if(j == 0) | ||||
| 		{ | ||||
| 			player.canHumanPlay = true; | ||||
| 		} | ||||
| 		auto itTeam = std::next(teamNumbers[j].begin(), gen.getInteger(0, teamNumbers[j].size() - 1)); | ||||
| 		player.team = *itTeam; | ||||
| 		teamNumbers[j].erase(itTeam); | ||||
| 		map->players[pSettings.getColor()] = player; | ||||
| 	} | ||||
|  | ||||
| 	map->howManyTeams = (mapGenOptions.getTeamsCnt() == 0 ? mapGenOptions.getPlayersCnt() : mapGenOptions.getTeamsCnt()) | ||||
| 			+ (mapGenOptions.getCompOnlyTeamsCnt() == 0 ? mapGenOptions.getCompOnlyPlayersCnt() : mapGenOptions.getCompOnlyTeamsCnt()); | ||||
| } | ||||
|  | ||||
| int CMapGenerator::countHumanPlayers() const | ||||
| { | ||||
| 	return static_cast<int>(std::count_if(players.begin(), players.end(), [](const std::pair<TPlayerColor, CPlayerSettings> & pair) | ||||
| 	{ | ||||
| 		return pair.second.getPlayerType() == CPlayerSettings::HUMAN; | ||||
| 	})); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::genTerrain() | ||||
| { | ||||
| 	map->initTerrain(); //FIXME nicer solution | ||||
| 	mapMgr->clearTerrain(); | ||||
| 	mapMgr->drawTerrain(ETerrainType::GRASS, 10, 10, 20, 30, false); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::genTowns() | ||||
| { | ||||
| 	//FIXME mock gen | ||||
| 	const int3 townPos[2] = { int3(17, 13, 0), int3(25,13, 0) }; | ||||
| 	const TFaction townTypes[2] = { ETownType::CASTLE, ETownType::DUNGEON }; | ||||
|  | ||||
| 	for(auto it = players.begin(); it != players.end(); ++it) | ||||
| 	{ | ||||
| 		TPlayerColor owner = it->first; | ||||
| 		int pos = std::distance(players.begin(), it); | ||||
| 		int side = pos % 2; | ||||
| 		CGTownInstance * town = new CGTownInstance(); | ||||
| 		town->ID = Obj::TOWN; | ||||
| 		town->subID = townTypes[side]; | ||||
| 		town->tempOwner = owner; | ||||
| 		town->defInfo = VLC->dobjinfo->gobjs[town->ID][town->subID]; | ||||
| 		town->builtBuildings.insert(EBuilding::FORT); | ||||
| 		town->builtBuildings.insert(-50); | ||||
| 		mapMgr->insertObject(town, townPos[side].x, townPos[side].y + (pos / 2) * 5, false); | ||||
| 		map->players[owner].allowedFactions.clear(); | ||||
| 		map->players[owner].allowedFactions.insert(townTypes[side]); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CMapGenerator::addHeaderInfo() | ||||
| { | ||||
| 	map->version = EMapFormat::SOD; | ||||
| 	map->width = mapGenOptions.getWidth(); | ||||
| 	map->height = mapGenOptions.getHeight(); | ||||
| 	map->twoLevel = mapGenOptions.getHasTwoLevels(); | ||||
| 	map->name = VLC->generaltexth->allTexts[740]; | ||||
| 	map->description = getMapDescription(); | ||||
| 	map->difficulty = 1; | ||||
| 	addPlayerInfo(); | ||||
| } | ||||
|  | ||||
| TPlayerColor CMapGenerator::getNextPlayerColor() const | ||||
| { | ||||
| 	for(TPlayerColor i = 0; i < GameConstants::PLAYER_LIMIT; ++i) | ||||
| 	{ | ||||
| 		if(players.find(i) == players.end()) | ||||
| 		{ | ||||
| 			return i; | ||||
| 		} | ||||
| 	} | ||||
| 	throw std::runtime_error("Shouldn't happen. No free player color exists."); | ||||
| } | ||||
|  | ||||
| CMapGenerator::CPlayerSettings::CPlayerSettings() : color(0), startingTown(RANDOM_TOWN), playerType(AI) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| int CMapGenerator::CPlayerSettings::getColor() const | ||||
| { | ||||
| 	return color; | ||||
| } | ||||
|  | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setColor(int value) | ||||
| { | ||||
| 	if(value >= 0 && value < GameConstants::PLAYER_LIMIT) | ||||
| 	{ | ||||
| 		color = value; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		throw std::runtime_error("The color of the player is not in a valid range."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int CMapGenerator::CPlayerSettings::getStartingTown() const | ||||
| { | ||||
| 	return startingTown; | ||||
| } | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setStartingTown(int 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."); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CMapGenerator::CPlayerSettings::EPlayerType CMapGenerator::CPlayerSettings::getPlayerType() const | ||||
| { | ||||
| 	return playerType; | ||||
| } | ||||
|  | ||||
| void CMapGenerator::CPlayerSettings::setPlayerType(EPlayerType value) | ||||
| { | ||||
| 	playerType = value; | ||||
| } | ||||
							
								
								
									
										199
									
								
								lib/RMG/CMapGenerator.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								lib/RMG/CMapGenerator.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
|  | ||||
| /* | ||||
|  * CMapGenerator.h, part of VCMI engine | ||||
|  * | ||||
|  * Authors: listed in file AUTHORS in main folder | ||||
|  * | ||||
|  * License: GNU General Public License v2.0 or later | ||||
|  * Full text of license available in license.txt file, in main folder | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "CMapGenOptions.h" | ||||
| #include "../CRandomGenerator.h" | ||||
|  | ||||
| class CMap; | ||||
| class CTerrainViewPatternConfig; | ||||
| class CMapEditManager; | ||||
|  | ||||
| /** | ||||
|  * The map generator creates a map randomly. | ||||
|  */ | ||||
| class CMapGenerator | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * The player settings class maps the player color, starting town and human player flag. | ||||
| 	 */ | ||||
| 	class CPlayerSettings | ||||
| 	{ | ||||
| 	public: | ||||
| 		enum EPlayerType | ||||
| 		{ | ||||
| 			HUMAN, | ||||
| 			AI, | ||||
| 			COMP_ONLY | ||||
| 		}; | ||||
|  | ||||
| 		/** | ||||
| 		 * Constructor. | ||||
| 		 */ | ||||
| 		CPlayerSettings(); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the color of the player. The default value is 0. | ||||
| 		 * | ||||
| 		 * @return the color of the player ranging from 0 to GameConstants::PLAYER_LIMIT - 1 | ||||
| 		 */ | ||||
| 		int getColor() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the color of the player. | ||||
| 		 * | ||||
| 		 * @param value the color of the player ranging from 0 to GameConstants::PLAYER_LIMIT - 1 | ||||
| 		 */ | ||||
| 		void setColor(int value); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the starting town of the player. The default value is RANDOM_TOWN. | ||||
| 		 * | ||||
| 		 * @return the starting town of the player ranging from 0 to town max count or RANDOM_TOWN | ||||
| 		 */ | ||||
| 		int getStartingTown() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the starting town of the player. | ||||
| 		 * | ||||
| 		 * @param value the starting town of the player ranging from 0 to town max count or RANDOM_TOWN | ||||
| 		 */ | ||||
| 		void setStartingTown(int value); | ||||
|  | ||||
| 		/** | ||||
| 		 * Gets the type of the player. The default value is EPlayerType::AI. | ||||
| 		 * | ||||
| 		 * @return the type of the player | ||||
| 		 */ | ||||
| 		EPlayerType getPlayerType() const; | ||||
|  | ||||
| 		/** | ||||
| 		 * Sets the type of the player. | ||||
| 		 * | ||||
| 		 * @param playerType the type of the player | ||||
| 		 */ | ||||
| 		void setPlayerType(EPlayerType value); | ||||
|  | ||||
| 		/** Constant for a random town selection. */ | ||||
| 		static const int RANDOM_TOWN = -1; | ||||
|  | ||||
| 	private: | ||||
| 		/** The color of the player. */ | ||||
| 		int color; | ||||
|  | ||||
| 		/** The starting town of the player. */ | ||||
| 		int startingTown; | ||||
|  | ||||
| 		/** The type of the player e.g. human, comp only,... */ | ||||
| 		EPlayerType playerType; | ||||
| 	}; | ||||
|  | ||||
| 	/** | ||||
| 	 * Constructor. | ||||
| 	 * | ||||
| 	 * @param mapGenOptions these options describe how to generate the map. | ||||
| 	 * @param players the random gen player settings | ||||
| 	 * @param randomSeed a random seed is required to get random numbers. | ||||
| 	 */ | ||||
| 	CMapGenerator(const CMapGenOptions & mapGenOptions, const std::map<TPlayerColor, CPlayerSettings> & players, int randomSeed); | ||||
|  | ||||
| 	/** | ||||
| 	 * Destructor. | ||||
| 	 */ | ||||
| 	~CMapGenerator(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Generates a map. | ||||
| 	 * | ||||
| 	 * @return the generated map object stored in a unique ptr | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMap> generate(); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * Validates map gen options and players options. On errors exceptions will be thrown. | ||||
| 	 */ | ||||
| 	void validateOptions() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Finalizes map generation options. Random sizes for various properties are | ||||
| 	 * converted to fixed values. | ||||
| 	 */ | ||||
| 	void finalizeMapGenOptions(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the map description of the generated map. | ||||
| 	 * | ||||
| 	 * @return the map description of the generated map | ||||
| 	 */ | ||||
| 	std::string getMapDescription() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Adds player information.(teams, colors, etc...) | ||||
| 	 */ | ||||
| 	void addPlayerInfo(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Counts the amount of human players. | ||||
| 	 * | ||||
| 	 * @return the amount of human players ranging from 0 to GameConstants::PLAYER_LIMIT | ||||
| 	 */ | ||||
| 	int countHumanPlayers() const; | ||||
|  | ||||
| 	/** | ||||
| 	 * Generate terrain. | ||||
| 	 */ | ||||
| 	void genTerrain(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Generate towns. | ||||
| 	 */ | ||||
| 	void genTowns(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Adds header info(size, description, etc...) | ||||
| 	 */ | ||||
| 	void addHeaderInfo(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets the next free player color. | ||||
| 	 * | ||||
| 	 * @return the next free player color | ||||
| 	 */ | ||||
| 	TPlayerColor getNextPlayerColor() const; | ||||
|  | ||||
| 	/** The map options which describes the size of the map and contain player info. */ | ||||
| 	CMapGenOptions mapGenOptions; | ||||
|  | ||||
| 	/** The generated map. */ | ||||
| 	std::unique_ptr<CMap> map; | ||||
|  | ||||
| 	/** The random number generator. */ | ||||
| 	CRandomGenerator gen; | ||||
|  | ||||
| 	/** The random seed, it is used for the map description. */ | ||||
| 	int randomSeed; | ||||
|  | ||||
| 	/** The terrain view pattern config. */ | ||||
| 	std::unique_ptr<CTerrainViewPatternConfig> terViewPatternConfig; | ||||
|  | ||||
| 	/** The map edit manager. */ | ||||
| 	std::unique_ptr<CMapEditManager> mapMgr; | ||||
|  | ||||
| 	/** The random gen player settings. */ | ||||
| 	std::map<TPlayerColor, CPlayerSettings> players; | ||||
|  | ||||
| 	/** Typedef of the players map, so that boost foreach can be used. */ | ||||
| 	typedef std::map<TPlayerColor, CPlayerSettings> tPlayersMap; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user