| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 | 
							
- /*
 
-  * CRmgTemplateStorage.cpp, part of VCMI engine
 
-  *
 
-  * Authors: listed in file AUTHORS in main folder
 
-  *
 
-  * License: GNU General Public License v2.0 or later
 
-  * Full text of license available in license.txt file, in main folder
 
-  *
 
-  */
 
- #include "StdInc.h"
 
- #include "CRmgTemplateStorage.h"
 
- #include "CRmgTemplate.h"
 
- #include "CRmgTemplateZone.h"
 
- #include "../filesystem/Filesystem.h"
 
- #include "../JsonNode.h"
 
- #include "../mapping/CMap.h"
 
- #include "../VCMI_Lib.h"
 
- #include "../CModHandler.h"
 
- #include "../CTownHandler.h"
 
- #include "../GameConstants.h"
 
- #include "../StringConstants.h"
 
- const std::map<std::string, CRmgTemplate *> & CRmgTemplateStorage::getTemplates() const
 
- {
 
- 	return templates;
 
- }
 
- void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
 
- {
 
- 	//unused
 
- 	loadObject(scope, name, data);
 
- }
 
- void CRmgTemplateStorage::loadObject(std::string scope, std::string name, const JsonNode & data)
 
- {
 
- 	auto tpl = new CRmgTemplate();
 
- 	try
 
- 	{
 
- 		const auto & templateNode = data;
 
- 		if (!templateNode["name"].isNull())
 
- 			tpl->setName(templateNode["name"].String()); //name can be customised. Allow duplicated names for different template versions.
 
- 		else
 
- 			tpl->setName(name); //identifier becomes default name
 
- 		// Parse main template data
 
- 		tpl->setMinSize(parseMapTemplateSize(templateNode["minSize"].String()));
 
- 		tpl->setMaxSize(parseMapTemplateSize(templateNode["maxSize"].String()));
 
- 		tpl->setPlayers(parsePlayers(templateNode["players"].String()));
 
- 		tpl->setCpuPlayers(parsePlayers(templateNode["cpu"].String()));
 
- 		// Parse zones
 
- 		std::map<TRmgTemplateZoneId, CRmgTemplateZone *> zones;
 
- 		for (const auto & zonePair : templateNode["zones"].Struct())
 
- 		{
 
- 			auto zone = new CRmgTemplateZone();
 
- 			auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
 
- 			zone->setId(zoneId);
 
- 			const auto & zoneNode = zonePair.second;
 
- 			zone->setType(parseZoneType(zoneNode["type"].String()));
 
- 			zone->setSize(zoneNode["size"].Float());
 
- 			if (!zoneNode["owner"].isNull()) zone->setOwner(zoneNode["owner"].Float());
 
- 			zone->setPlayerTowns(parseTemplateZoneTowns(zoneNode["playerTowns"]));
 
- 			zone->setNeutralTowns(parseTemplateZoneTowns(zoneNode["neutralTowns"]));
 
- 			if (!zoneNode["matchTerrainToTown"].isNull()) //default : true
 
- 				zone->setMatchTerrainToTown(zoneNode["matchTerrainToTown"].Bool());
 
- 			zone->setTerrainTypes(parseTerrainTypes(zoneNode["terrainTypes"].Vector(), zone->getDefaultTerrainTypes()));
 
- 			if (!zoneNode["townsAreSameType"].isNull()) //default : false
 
- 				zone->setTownsAreSameType((zoneNode["townsAreSameType"].Bool()));
 
- 			for (int i = 0; i < 2; ++i)
 
- 			{
 
- 				std::set<TFaction> allowedTownTypes;
 
- 				if (i)
 
- 				{
 
- 					if (zoneNode["allowedTowns"].isNull())
 
- 						allowedTownTypes = zone->getDefaultTownTypes();
 
- 				}
 
- 				else
 
- 				{
 
- 					if (zoneNode["allowedMonsters"].isNull())
 
- 						allowedTownTypes = VLC->townh->getAllowedFactions(false);
 
- 				}
 
- 				if (allowedTownTypes.empty())
 
- 				{
 
- 					for (const JsonNode & allowedTown : zoneNode[i ? "allowedTowns" : "allowedMonsters"].Vector())
 
- 					{
 
- 						//complain if the town type is not present in our game
 
- 						if (auto id = VLC->modh->identifiers.getIdentifier("faction", allowedTown, false))
 
- 							allowedTownTypes.insert(id.get());
 
- 					}
 
- 				}
 
- 				if (!zoneNode[i ? "bannedTowns" : "bannedMonsters"].isNull())
 
- 				{
 
- 					for (const JsonNode & bannedTown : zoneNode[i ? "bannedTowns" : "bannedMonsters"].Vector())
 
- 					{
 
- 						//erase unindentified towns silently
 
- 						if (auto id = VLC->modh->identifiers.getIdentifier("faction", bannedTown, true))
 
- 							vstd::erase_if_present(allowedTownTypes, id.get());
 
- 					}
 
- 				}
 
- 				if (i)
 
- 					zone->setTownTypes(allowedTownTypes);
 
- 				else
 
- 					zone->setMonsterTypes(allowedTownTypes);
 
- 			}
 
- 			const std::string monsterStrength = zoneNode["monsters"].String();
 
- 			if (monsterStrength == "weak")
 
- 				zone->setMonsterStrength(EMonsterStrength::ZONE_WEAK);
 
- 			else if (monsterStrength == "normal")
 
- 				zone->setMonsterStrength(EMonsterStrength::ZONE_NORMAL);
 
- 			else if (monsterStrength == "strong")
 
- 				zone->setMonsterStrength(EMonsterStrength::ZONE_STRONG);
 
- 			else
 
- 				throw (rmgException("incorrect monster power"));
 
- 			if (!zoneNode["mines"].isNull())
 
- 			{
 
- 				auto mines = zoneNode["mines"].Struct();
 
- 				//FIXME: maybe there is a smarter way to parse it already?
 
- 				zone->setMinesAmount(Res::WOOD, mines["wood"].Float());
 
- 				zone->setMinesAmount(Res::ORE, mines["ore"].Float());
 
- 				zone->setMinesAmount(Res::GEMS, mines["gems"].Float());
 
- 				zone->setMinesAmount(Res::CRYSTAL, mines["crystal"].Float());
 
- 				zone->setMinesAmount(Res::SULFUR, mines["sulfur"].Float());
 
- 				zone->setMinesAmount(Res::MERCURY, mines["mercury"].Float());
 
- 				zone->setMinesAmount(Res::GOLD, mines["gold"].Float());
 
- 				//TODO: Mithril
 
- 			}
 
- 			//treasures
 
- 			if (!zoneNode["treasure"].isNull())
 
- 			{
 
- 				//TODO: parse vector of different treasure settings
 
- 				if (zoneNode["treasure"].getType() == JsonNode::DATA_STRUCT)
 
- 				{
 
- 					auto treasureInfo = zoneNode["treasure"].Struct();
 
- 					{
 
- 						CTreasureInfo ti;
 
- 						ti.min = treasureInfo["min"].Float();
 
- 						ti.max = treasureInfo["max"].Float();
 
- 						ti.density = treasureInfo["density"].Float(); //TODO: use me
 
- 						zone->addTreasureInfo(ti);
 
- 					}
 
- 				}
 
- 				else if (zoneNode["treasure"].getType() == JsonNode::DATA_VECTOR)
 
- 				{
 
- 					for (auto treasureInfo : zoneNode["treasure"].Vector())
 
- 					{
 
- 						CTreasureInfo ti;
 
- 						ti.min = treasureInfo["min"].Float();
 
- 						ti.max = treasureInfo["max"].Float();
 
- 						ti.density = treasureInfo["density"].Float();
 
- 						zone->addTreasureInfo(ti);
 
- 					}
 
- 				}
 
- 			}
 
- 			zones[zone->getId()] = zone;
 
- 		}
 
- 		//copy settings from already parsed zones
 
- 		for (const auto & zonePair : templateNode["zones"].Struct())
 
- 		{
 
- 			auto zoneId = boost::lexical_cast<TRmgTemplateZoneId>(zonePair.first);
 
- 			auto zone = zones[zoneId];
 
- 			const auto & zoneNode = zonePair.second;
 
- 			if (!zoneNode["terrainTypeLikeZone"].isNull())
 
- 			{
 
- 				int id = zoneNode["terrainTypeLikeZone"].Float();
 
- 				zone->setTerrainTypes(zones[id]->getTerrainTypes());
 
- 				zone->setMatchTerrainToTown(zones[id]->getMatchTerrainToTown());
 
- 			}
 
- 			if (!zoneNode["townTypeLikeZone"].isNull())
 
- 				zone->setTownTypes (zones[zoneNode["townTypeLikeZone"].Float()]->getTownTypes());
 
- 			if (!zoneNode["treasureLikeZone"].isNull())
 
- 			{
 
- 				for (auto treasureInfo : zones[zoneNode["treasureLikeZone"].Float()]->getTreasureInfo())
 
- 				{
 
- 					zone->addTreasureInfo(treasureInfo);
 
- 				}
 
- 			}
 
- 			if (!zoneNode["minesLikeZone"].isNull())
 
- 			{
 
- 				for (auto mineInfo : zones[zoneNode["minesLikeZone"].Float()]->getMinesInfo())
 
- 				{
 
- 					zone->setMinesAmount (mineInfo.first, mineInfo.second);
 
- 				}
 
- 			}
 
- 		}
 
- 		tpl->setZones(zones);
 
- 		// Parse connections
 
- 		std::list<CRmgTemplateZoneConnection> connections;
 
- 		for(const auto & connPair : templateNode["connections"].Vector())
 
- 		{
 
- 			CRmgTemplateZoneConnection conn;
 
- 			conn.setZoneA(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["a"].String()))->second);
 
- 			conn.setZoneB(zones.find(boost::lexical_cast<TRmgTemplateZoneId>(connPair["b"].String()))->second);
 
- 			conn.setGuardStrength(connPair["guard"].Float());
 
- 			connections.push_back(conn);
 
- 		}
 
- 		tpl->setConnections(connections);
 
- 		{
 
- 			auto zones = tpl->getZones();
 
- 			for (auto con : tpl->getConnections())
 
- 			{
 
- 				auto idA = con.getZoneA()->getId();
 
- 				auto idB = con.getZoneB()->getId();
 
- 				zones[idA]->addConnection(idB);
 
- 				zones[idB]->addConnection(idA);
 
- 			}
 
- 		}
 
- 		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 CRmgTemplateStorage::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 =
 
- 	{
 
- 		{"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 CRmgTemplateStorage::parseZoneType(const std::string & type) const
 
- {
 
- 	static const std::map<std::string, ETemplateZoneType::ETemplateZoneType> zoneTypeMapping =
 
- 	{
 
- 		{"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 CRmgTemplateStorage::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> CRmgTemplateStorage::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> CRmgTemplateStorage::parseTerrainTypes(const JsonVector & terTypeStrings, const std::set<ETerrainType> & defaultTerrainTypes) const
 
- {
 
- 	std::set<ETerrainType> terTypes;
 
- 	if (terTypeStrings.empty()) //nothing was specified
 
- 		return defaultTerrainTypes;
 
- 	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 CRmgTemplateStorage::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;
 
- }
 
- CRmgTemplateStorage::CRmgTemplateStorage()
 
- {
 
- 	//TODO: load all
 
- }
 
- CRmgTemplateStorage::~CRmgTemplateStorage()
 
- {
 
- 	for (auto & pair : templates) delete pair.second;
 
- }
 
- std::vector<bool> CRmgTemplateStorage::getDefaultAllowed() const
 
- {
 
- 	//all templates are allowed
 
- 	return std::vector<bool>();
 
- }
 
- std::vector<JsonNode> CRmgTemplateStorage::loadLegacyData(size_t dataSize)
 
- {
 
- 	return std::vector<JsonNode>();
 
- 	//it would be cool to load old rmg.txt files
 
- };
 
 
  |