mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Support for overriding victory/defeat conditions from h3m map or
campaign: - new file MapFormatJson that implements small subset of Json map format, as described on wiki - vcmi will read overrides from file config/mapOverrides.json (currently empty) - Json writer for logical expressions TODO: write data for map overrides
This commit is contained in:
		| @@ -3306,11 +3306,15 @@ void CBonusSelection::selectMap(int mapNr, bool initialSelect) | ||||
| 		selectedMap = mapNr; | ||||
| 		selectedBonus = boost::none; | ||||
|  | ||||
| 		std::string scenarioName = ourCampaign->camp->header.filename.substr(0, ourCampaign->camp->header.filename.find('.')); | ||||
| 		boost::to_lower(scenarioName); | ||||
| 		scenarioName += ':' + boost::lexical_cast<std::string>(selectedMap); | ||||
|  | ||||
| 		//get header | ||||
| 		delete ourHeader; | ||||
| 		std::string & headerStr = ourCampaign->camp->mapPieces.find(mapNr)->second; | ||||
| 		auto buffer = reinterpret_cast<const ui8 *>(headerStr.data()); | ||||
| 		ourHeader = CMapService::loadMapHeader(buffer, headerStr.size()).release(); | ||||
| 		ourHeader = CMapService::loadMapHeader(buffer, headerStr.size(), scenarioName).release(); | ||||
|  | ||||
| 		std::map<ui8, std::string> names; | ||||
| 		names[1] = settings["general"]["playerName"].String(); | ||||
|   | ||||
							
								
								
									
										2
									
								
								config/mapOverrides.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								config/mapOverrides.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| { | ||||
| } | ||||
| @@ -869,9 +869,13 @@ void CGameState::initCampaign() | ||||
| 	auto campaign = scenarioOps->campState; | ||||
| 	assert(vstd::contains(campaign->camp->mapPieces, *scenarioOps->campState->currentMap)); | ||||
|  | ||||
| 	std::string & mapContent = campaign->camp->mapPieces[*scenarioOps->campState->currentMap]; | ||||
| 	std::string scenarioName = scenarioOps->mapname.substr(0, scenarioOps->mapname.find('.')); | ||||
| 	boost::to_lower(scenarioName); | ||||
| 	scenarioName += ':' + boost::lexical_cast<std::string>(*campaign->currentMap); | ||||
|  | ||||
| 	std::string & mapContent = campaign->camp->mapPieces[*campaign->currentMap]; | ||||
| 	auto buffer = reinterpret_cast<const ui8 *>(mapContent.data()); | ||||
| 	map = CMapService::loadMap(buffer, mapContent.size()).release(); | ||||
| 	map = CMapService::loadMap(buffer, mapContent.size(), scenarioName).release(); | ||||
| } | ||||
|  | ||||
| void CGameState::initDuel() | ||||
|   | ||||
| @@ -33,6 +33,7 @@ set(lib_SRCS | ||||
| 		mapping/CMapInfo.cpp | ||||
| 		mapping/CMapService.cpp | ||||
| 		mapping/MapFormatH3M.cpp | ||||
| 		mapping/MapFormatJson.cpp | ||||
|  | ||||
| 		rmg/CMapGenerator.cpp | ||||
| 		rmg/CMapGenOptions.cpp | ||||
|   | ||||
| @@ -122,7 +122,7 @@ void CIdentifierStorage::tryRequestIdentifier(std::string type, const JsonNode & | ||||
| boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const JsonNode & name, bool silent) | ||||
| { | ||||
| 	auto pair = splitString(name.String(), ':'); // remoteScope:name | ||||
| 	auto idList = getIdentifier(ObjectCallback(name.meta, pair.first, type, pair.second, std::function<void(si32)>(), silent)); | ||||
| 	auto idList = getPossibleIdentifiers(ObjectCallback(name.meta, pair.first, type, pair.second, std::function<void(si32)>(), silent)); | ||||
|  | ||||
| 	if (idList.size() == 1) | ||||
| 		return idList.front().id; | ||||
| @@ -132,6 +132,20 @@ boost::optional<si32> CIdentifierStorage::getIdentifier(std::string type, const | ||||
| 	return boost::optional<si32>(); | ||||
| } | ||||
|  | ||||
| boost::optional<si32> CIdentifierStorage::getIdentifier(const JsonNode & name, bool silent) | ||||
| { | ||||
| 	auto pair  = splitString(name.String(), ':'); // remoteScope:<type.name> | ||||
| 	auto pair2 = splitString(pair.second,   '.'); // type.name | ||||
| 	auto idList = getPossibleIdentifiers(ObjectCallback(name.meta, pair.first, pair2.first, pair2.second, std::function<void(si32)>(), silent)); | ||||
|  | ||||
| 	if (idList.size() == 1) | ||||
| 		return idList.front().id; | ||||
| 	if (!silent) | ||||
| 		logGlobal->errorStream() << "Failed to resolve identifier " << name.String() << " from mod " << pair2.first; | ||||
|  | ||||
| 	return boost::optional<si32>(); | ||||
| } | ||||
|  | ||||
| void CIdentifierStorage::registerObject(std::string scope, std::string type, std::string name, si32 identifier) | ||||
| { | ||||
| 	ObjectData data; | ||||
| @@ -144,14 +158,14 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std | ||||
| 	registeredObjects.insert(std::make_pair(fullID, data)); | ||||
| } | ||||
|  | ||||
| std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getIdentifier(const ObjectCallback & request) | ||||
| std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdentifiers(const ObjectCallback & request) | ||||
| { | ||||
| 	std::set<std::string> allowedScopes; | ||||
|  | ||||
| 	if (request.remoteScope.empty()) | ||||
| 	{ | ||||
| 		// normally ID's from all required mods, own mod and virtual "core" mod are allowed | ||||
| 		if (request.localScope != "core") | ||||
| 		if (request.localScope != "core" && request.localScope != "") | ||||
| 			allowedScopes = VLC->modh->getModData(request.localScope).dependencies; | ||||
|  | ||||
| 		allowedScopes.insert(request.localScope); | ||||
| @@ -187,7 +201,7 @@ std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getIdentifier(co | ||||
|  | ||||
| bool CIdentifierStorage::resolveIdentifier(const ObjectCallback & request) | ||||
| { | ||||
| 	auto identifiers = getIdentifier(request); | ||||
| 	auto identifiers = getPossibleIdentifiers(request); | ||||
| 	if (identifiers.size() == 1) // normally resolved ID | ||||
| 	{ | ||||
| 		request.callback(identifiers.front().id); | ||||
|   | ||||
| @@ -51,7 +51,7 @@ class CIdentifierStorage | ||||
|  | ||||
| 	void requestIdentifier(ObjectCallback callback); | ||||
| 	bool resolveIdentifier(const ObjectCallback & callback); | ||||
| 	std::vector<ObjectData> getIdentifier(const ObjectCallback & callback); | ||||
| 	std::vector<ObjectData> getPossibleIdentifiers(const ObjectCallback & callback); | ||||
| public: | ||||
| 	/// request identifier for specific object name. | ||||
| 	/// Function callback will be called during ID resolution phase of loading | ||||
| @@ -65,6 +65,7 @@ public: | ||||
|  | ||||
| 	/// get identifier immediately. If identifier is not know and not silent call will result in error message | ||||
| 	boost::optional<si32> getIdentifier(std::string type, const JsonNode & name, bool silent = false); | ||||
| 	boost::optional<si32> getIdentifier(const JsonNode & name, bool silent = false); | ||||
|  | ||||
| 	/// registers new object | ||||
| 	void registerObject(std::string scope, std::string type, std::string name, si32 identifier); | ||||
|   | ||||
| @@ -223,6 +223,49 @@ namespace LogicalExpressionDetail | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// Prints expression in human-readable format | ||||
| 	template <typename ContainedClass> | ||||
| 	class Writer : public boost::static_visitor<JsonNode> | ||||
| 	{ | ||||
| 		typedef ExpressionBase<ContainedClass> Base; | ||||
|  | ||||
| 		std::function<JsonNode(const typename Base::Value &)> classPrinter; | ||||
|  | ||||
| 		JsonNode printExpressionList(std::string name, const std::vector<typename Base::Variant> & element) const | ||||
| 		{ | ||||
| 			JsonNode ret; | ||||
| 			ret.Vector().resize(1); | ||||
| 			ret.Vector().back().String() = name; | ||||
| 			for (auto & expr : element) | ||||
| 				ret.Vector().push_back(boost::apply_visitor(*this, expr)); | ||||
| 			return ret; | ||||
| 		} | ||||
| 	public: | ||||
| 		Writer(std::function<JsonNode(const typename Base::Value &)> classPrinter): | ||||
| 			classPrinter(classPrinter) | ||||
| 		{} | ||||
|  | ||||
| 		JsonNode operator()(const typename Base::OperatorAny & element) const | ||||
| 		{ | ||||
| 			return printExpressionList("anyOf", element.expressions); | ||||
| 		} | ||||
|  | ||||
| 		JsonNode operator()(const typename Base::OperatorAll & element) const | ||||
| 		{ | ||||
| 			return printExpressionList("allOf", element.expressions); | ||||
| 		} | ||||
|  | ||||
| 		JsonNode operator()(const typename Base::OperatorNone & element) const | ||||
| 		{ | ||||
| 			return printExpressionList("noneOf", element.expressions); | ||||
| 		} | ||||
|  | ||||
| 		JsonNode operator()(const typename Base::Value & element) const | ||||
| 		{ | ||||
| 			return classPrinter(element); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	std::string DLL_LINKAGE getTextForOperator(std::string operation); | ||||
|  | ||||
| 	/// Prints expression in human-readable format | ||||
| @@ -368,6 +411,12 @@ public: | ||||
| 		return boost::apply_visitor(printVisitor, data); | ||||
| 	} | ||||
|  | ||||
| 	JsonNode toJson(std::function<JsonNode(const Value &)> toJson) const | ||||
| 	{ | ||||
| 		LogicalExpressionDetail::Writer<Value> writeVisitor(toJson); | ||||
| 		return boost::apply_visitor(writeVisitor, data); | ||||
| 	} | ||||
|  | ||||
| 	template <typename Handler> | ||||
| 	void serialize(Handler & h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -64,9 +64,13 @@ unique_ptr<CCampaign> CCampaignHandler::getCampaign( const std::string & name ) | ||||
| 			scenarioID++; | ||||
| 		} | ||||
|  | ||||
| 		std::string scenarioName = name.substr(0, name.find('.')); | ||||
| 		boost::to_lower(scenarioName); | ||||
| 		scenarioName += ':' + boost::lexical_cast<std::string>(g-1); | ||||
|  | ||||
| 		//set map piece appropriately, convert vector to string | ||||
| 		ret->mapPieces[scenarioID].assign(reinterpret_cast< const char* >(file[g].data()), file[g].size()); | ||||
| 		ret->scenarios[scenarioID].scenarioName = CMapService::loadMapHeader((const ui8*)ret->mapPieces[scenarioID].c_str(), ret->mapPieces[scenarioID].size())->name; | ||||
| 		ret->scenarios[scenarioID].scenarioName = CMapService::loadMapHeader((const ui8*)ret->mapPieces[scenarioID].c_str(), ret->mapPieces[scenarioID].size(), scenarioName)->name; | ||||
| 		scenarioID++; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -8,30 +8,47 @@ | ||||
| #include "CMap.h" | ||||
|  | ||||
| #include "MapFormatH3M.h" | ||||
| #include "MapFormatJson.h" | ||||
|  | ||||
|  | ||||
| std::unique_ptr<CMap> CMapService::loadMap(const std::string & name) | ||||
| { | ||||
| 	auto stream = getStreamFromFS(name); | ||||
| 	return getMapLoader(stream)->loadMap(); | ||||
| 	std::unique_ptr<CMap> map(getMapLoader(stream)->loadMap()); | ||||
| 	std::unique_ptr<CMapHeader> header(map.get()); | ||||
|  | ||||
| 	getMapPatcher(name)->patchMapHeader(header); | ||||
| 	header.release(); | ||||
|  | ||||
| 	return std::move(map); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const std::string & name) | ||||
| { | ||||
| 	auto stream = getStreamFromFS(name); | ||||
| 	return getMapLoader(stream)->loadMapHeader(); | ||||
| 	std::unique_ptr<CMapHeader> header = getMapLoader(stream)->loadMapHeader(); | ||||
| 	getMapPatcher(name)->patchMapHeader(header); | ||||
| 	return std::move(header); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMap> CMapService::loadMap(const ui8 * buffer, int size) | ||||
| std::unique_ptr<CMap> CMapService::loadMap(const ui8 * buffer, int size, const std::string & name) | ||||
| { | ||||
| 	auto stream = getStreamFromMem(buffer, size); | ||||
| 	return getMapLoader(stream)->loadMap(); | ||||
| 	std::unique_ptr<CMap> map(getMapLoader(stream)->loadMap()); | ||||
| 	std::unique_ptr<CMapHeader> header(map.get()); | ||||
|  | ||||
| 	getMapPatcher(name)->patchMapHeader(header); | ||||
| 	header.release(); | ||||
|  | ||||
| 	return std::move(map); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const ui8 * buffer, int size) | ||||
| std::unique_ptr<CMapHeader> CMapService::loadMapHeader(const ui8 * buffer, int size, const std::string & name) | ||||
| { | ||||
| 	auto stream = getStreamFromMem(buffer, size); | ||||
| 	return getMapLoader(stream)->loadMapHeader(); | ||||
| 	std::unique_ptr<CMapHeader> header = getMapLoader(stream)->loadMapHeader(); | ||||
| 	getMapPatcher(name)->patchMapHeader(header); | ||||
| 	return std::move(header); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CInputStream> CMapService::getStreamFromFS(const std::string & name) | ||||
| @@ -68,3 +85,11 @@ std::unique_ptr<IMapLoader> CMapService::getMapLoader(std::unique_ptr<CInputStre | ||||
| 			throw std::runtime_error("Unknown map format"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::unique_ptr<IMapPatcher> CMapService::getMapPatcher(std::string scenarioName) | ||||
| { | ||||
| 	boost::to_lower(scenarioName); | ||||
| 	logGlobal->debugStream() << "Request to patch map " << scenarioName; | ||||
| 	JsonNode node = JsonUtils::assembleFromFiles("config/mapOverrides.json"); | ||||
| 	return std::unique_ptr<IMapPatcher>(new CMapLoaderJson(node[scenarioName])); | ||||
| } | ||||
|   | ||||
| @@ -16,6 +16,7 @@ class CMapHeader; | ||||
| class CInputStream; | ||||
|  | ||||
| class IMapLoader; | ||||
| class IMapPatcher; | ||||
|  | ||||
| /** | ||||
|  * The map service provides loading of VCMI/H3 map files. It can | ||||
| @@ -49,9 +50,10 @@ public: | ||||
| 	 * | ||||
| 	 * @param buffer a pointer to a buffer containing the map data | ||||
| 	 * @param size the size of the buffer | ||||
| 	 * @param name indicates name of file that will be used during map header patching | ||||
| 	 * @return a unique ptr to the loaded map class | ||||
| 	 */ | ||||
| 	static std::unique_ptr<CMap> loadMap(const ui8 * buffer, int size); | ||||
| 	static std::unique_ptr<CMap> loadMap(const ui8 * buffer, int size, const std::string & name); | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads the VCMI/H3 map header from a buffer. This method is temporarily | ||||
| @@ -62,9 +64,10 @@ public: | ||||
| 	 * | ||||
| 	 * @param buffer a pointer to a buffer containing the map header data | ||||
| 	 * @param size the size of the buffer | ||||
| 	 * @param name indicates name of file that will be used during map header patching | ||||
| 	 * @return a unique ptr to the loaded map class | ||||
| 	 */ | ||||
| 	static std::unique_ptr<CMapHeader> loadMapHeader(const ui8 * buffer, int size); | ||||
| 	static std::unique_ptr<CMapHeader> loadMapHeader(const ui8 * buffer, int size, const std::string & name); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| @@ -92,6 +95,14 @@ private: | ||||
| 	 * @return the constructed map loader | ||||
| 	 */ | ||||
| 	static std::unique_ptr<IMapLoader> getMapLoader(std::unique_ptr<CInputStream> & stream); | ||||
|  | ||||
| 	/** | ||||
| 	 * Gets a map patcher for specified scenario | ||||
| 	 * | ||||
| 	 * @param scenarioName for patcher | ||||
| 	 * @return the constructed map patcher | ||||
| 	 */ | ||||
| 	static std::unique_ptr<IMapPatcher> getMapPatcher(std::string scenarioName); | ||||
| }; | ||||
|  | ||||
| /** | ||||
| @@ -115,4 +126,12 @@ public: | ||||
| 	virtual std::unique_ptr<CMapHeader> loadMapHeader() = 0; | ||||
| }; | ||||
|  | ||||
|  | ||||
| class DLL_LINKAGE IMapPatcher : public IMapLoader | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * Modifies supplied map header using Json data | ||||
| 	 * | ||||
| 	 */ | ||||
| 	virtual void patchMapHeader(std::unique_ptr<CMapHeader> & header) = 0; | ||||
| }; | ||||
|   | ||||
| @@ -1563,9 +1563,11 @@ void CMapLoaderH3M::readObjects() | ||||
| 				if(htid == 0xff) | ||||
| 				{ | ||||
| 					hp->power = reader.readUInt8(); | ||||
| 					logGlobal->infoStream() << "Hero placeholder: by power at " << objPos; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					logGlobal->infoStream() << "Hero placeholder: " << VLC->heroh->heroes[htid]->name << " at " << objPos; | ||||
| 					hp->power = 0; | ||||
| 				} | ||||
|  | ||||
| @@ -1684,6 +1686,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 		} | ||||
| 		if(nobj->ID == Obj::HERO) | ||||
| 		{ | ||||
| 			logGlobal->infoStream() << "Hero: " << VLC->heroh->heroes[nobj->subID]->name << " at " << objPos; | ||||
| 			map->heroesOnMap.push_back(static_cast<CGHeroInstance*>(nobj)); | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										171
									
								
								lib/mapping/MapFormatJson.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								lib/mapping/MapFormatJson.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| /* | ||||
| * MapFormatJson.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 "MapFormatJson.h" | ||||
|  | ||||
| #include "CMap.h" | ||||
| #include "../CModHandler.h" | ||||
| #include "../VCMI_Lib.h" | ||||
|  | ||||
| static const std::string conditionNames[] = { | ||||
| "haveArtifact", "haveCreatures", "haveResources",   "haveBuilding", | ||||
| "control",      "destroy",       "transport", | ||||
| "daysPassed",   "isHuman",       "daysWithoutTown", "standardWin" | ||||
| }; | ||||
|  | ||||
| static const std::string typeNames[] = { "victory", "defeat" }; | ||||
|  | ||||
| CMapLoaderJson::CMapLoaderJson(JsonNode stream): | ||||
| 	input(stream) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMap> CMapLoaderJson::loadMap() | ||||
| { | ||||
| 	map = new CMap(); | ||||
| 	mapHeader.reset(map); | ||||
| 	readMap(); | ||||
| 	mapHeader.reset(); | ||||
| 	return std::unique_ptr<CMap>(map); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<CMapHeader> CMapLoaderJson::loadMapHeader() | ||||
| { | ||||
| 	mapHeader.reset(new CMapHeader); | ||||
| 	readHeader(); | ||||
| 	return std::move(mapHeader); | ||||
| } | ||||
|  | ||||
| /* | ||||
| 	//This code can be used to write map header to console or file in its Json representation | ||||
|  | ||||
| 	JsonNode out; | ||||
| 	JsonNode data; | ||||
| 	data["victoryString"].String() = mapHeader->victoryMessage; | ||||
| 	data["defeatString"].String() = mapHeader->defeatMessage; | ||||
|  | ||||
| 	data["victoryIconIndex"].Float() = mapHeader->victoryIconIndex; | ||||
| 	data["defeatIconIndex"].Float() = mapHeader->defeatIconIndex; | ||||
|  | ||||
| 	for (const TriggeredEvent & entry : mapHeader->triggeredEvents) | ||||
| 	{ | ||||
| 		JsonNode event; | ||||
| 		event["message"].String() = entry.onFulfill; | ||||
| 		event["effect"]["messageToSend"].String() = entry.effect.toOtherMessage; | ||||
| 		event["effect"]["type"].String() = typeNames[entry.effect.type]; | ||||
| 		event["condition"] = entry.trigger.toJson(eventToJson); | ||||
| 		data["triggeredEvents"][entry.identifier] = event; | ||||
| 	} | ||||
|  | ||||
| 	out[mapHeader->name] = data; | ||||
| 	logGlobal->errorStream() << out; | ||||
|  | ||||
| JsonNode eventToJson(const EventCondition & cond) | ||||
| { | ||||
| 	JsonNode ret; | ||||
| 	ret.Vector().resize(2); | ||||
| 	ret.Vector()[0].String() = conditionNames[size_t(cond.condition)]; | ||||
| 	JsonNode & data = ret.Vector()[1]; | ||||
| 	data["type"].Float() = cond.objectType; | ||||
| 	data["value"].Float() = cond.value; | ||||
| 	data["position"].Vector().resize(3); | ||||
| 	data["position"].Vector()[0].Float() = cond.position.x; | ||||
| 	data["position"].Vector()[1].Float() = cond.position.y; | ||||
| 	data["position"].Vector()[2].Float() = cond.position.z; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
| */ | ||||
| void CMapLoaderJson::patchMapHeader(std::unique_ptr<CMapHeader> & header) | ||||
| { | ||||
| 	header.swap(mapHeader); | ||||
| 	if (!input.isNull()) | ||||
| 		readPatchData(); | ||||
| 	header.swap(mapHeader); | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readMap() | ||||
| { | ||||
| 	readHeader(); | ||||
| 	assert(0); // Not implemented, vcmi does not have its own map format right now | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readHeader() | ||||
| { | ||||
| 	//TODO: read such data like map name & size | ||||
| 	readPatchData(); | ||||
| 	readPlayerInfo(); | ||||
| 	assert(0); // Not implemented | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readPatchData() | ||||
| { | ||||
| 	mapHeader->victoryMessage = input["victoryString"].String(); | ||||
| 	mapHeader->victoryIconIndex = input["victoryIconIndex"].Float(); | ||||
|  | ||||
| 	mapHeader->defeatMessage = input["defeatString"].String(); | ||||
| 	mapHeader->defeatIconIndex = input["defeatIconIndex"].Float(); | ||||
|  | ||||
| 	readTriggeredEvents(); | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readTriggeredEvents() | ||||
| { | ||||
| 	mapHeader->triggeredEvents.clear(); | ||||
|  | ||||
| 	for (auto & entry : input["triggeredEvents"].Struct()) | ||||
| 	{ | ||||
| 		TriggeredEvent event; | ||||
| 		event.identifier = entry.first; | ||||
| 		readTriggeredEvent(event, entry.second); | ||||
| 		mapHeader->triggeredEvents.push_back(event); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static EventCondition JsonToCondition(const JsonNode & node) | ||||
| { | ||||
| 	EventCondition event; | ||||
| 	event.condition = EventCondition::EWinLoseType(vstd::find_pos(conditionNames, node.Vector()[0].String())); | ||||
| 	if (node.Vector().size() > 1) | ||||
| 	{ | ||||
| 		const JsonNode & data = node.Vector()[1]; | ||||
| 		if (data["type"].getType() == JsonNode::DATA_STRING) | ||||
| 			event.objectType = VLC->modh->identifiers.getIdentifier(data["type"]).get(); | ||||
| 		if (data["type"].getType() == JsonNode::DATA_FLOAT) | ||||
| 			event.objectType = data["type"].Float(); | ||||
|  | ||||
| 		if (!data["value"].isNull()) | ||||
| 			event.value = data["value"].Float(); | ||||
|  | ||||
| 		if (!data["position"].isNull()) | ||||
| 		{ | ||||
| 			event.position.x = data["position"].Vector()[0].Float(); | ||||
| 			event.position.y = data["position"].Vector()[1].Float(); | ||||
| 			event.position.z = data["position"].Vector()[2].Float(); | ||||
| 		} | ||||
| 	} | ||||
| 	return event; | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readTriggeredEvent(TriggeredEvent & event, const JsonNode & source) | ||||
| { | ||||
| 	event.onFulfill = source["message"].String(); | ||||
| 	event.description = source["description"].String(); | ||||
| 	event.effect.type = vstd::find_pos(typeNames, source["effect"]["type"].String()); | ||||
| 	event.effect.toOtherMessage = source["effect"]["messageToSend"].String(); | ||||
| 	event.trigger = EventExpression(source["condition"], JsonToCondition); // logical expression | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readPlayerInfo() | ||||
| { | ||||
| 	assert(0); // Not implemented | ||||
| } | ||||
							
								
								
									
										91
									
								
								lib/mapping/MapFormatJson.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								lib/mapping/MapFormatJson.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
|  | ||||
| /* | ||||
|  * MapFormatH3M.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 "CMapService.h" | ||||
| #include "../JsonNode.h" | ||||
|  | ||||
| class TriggeredEvent; | ||||
|  | ||||
| class DLL_LINKAGE CMapLoaderJson : public IMapPatcher | ||||
| { | ||||
| public: | ||||
| 	/** | ||||
| 	 * Default constructor. | ||||
| 	 * | ||||
| 	 * @param stream a stream containing the map data | ||||
| 	 */ | ||||
| 	CMapLoaderJson(JsonNode stream); | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads the VCMI/Json map file. | ||||
| 	 * | ||||
| 	 * @return a unique ptr of the loaded map class | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMap> loadMap(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads the VCMI/Json map header. | ||||
| 	 * | ||||
| 	 * @return a unique ptr of the loaded map header class | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMapHeader> loadMapHeader(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Modifies supplied map header using Json data | ||||
| 	 * | ||||
| 	 */ | ||||
| 	void patchMapHeader(std::unique_ptr<CMapHeader> & header); | ||||
|  | ||||
| private: | ||||
| 	/** | ||||
| 	 * Reads complete map. | ||||
| 	 */ | ||||
| 	void readMap(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads the map header. | ||||
| 	 */ | ||||
| 	void readHeader(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads subset of header that can be replaced by patching. | ||||
| 	 */ | ||||
| 	void readPatchData(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads player information. | ||||
| 	 */ | ||||
| 	void readPlayerInfo(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads triggered events, including victory/loss conditions | ||||
| 	 */ | ||||
| 	void readTriggeredEvents(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Reads one of triggered events | ||||
| 	 */ | ||||
| 	void readTriggeredEvent(TriggeredEvent & event, const JsonNode & source); | ||||
|  | ||||
|  | ||||
| 	/** ptr to the map object which gets filled by data from the buffer */ | ||||
| 	CMap * map; | ||||
|  | ||||
| 	/** | ||||
| 	 * ptr to the map header object which gets filled by data from the buffer. | ||||
| 	 * (when loading map and mapHeader point to the same object) | ||||
| 	 */ | ||||
| 	std::unique_ptr<CMapHeader> mapHeader; | ||||
|  | ||||
| 	const JsonNode input; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user