mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Refactoring of ObjectClassesHandler
This commit is contained in:
		| @@ -32,10 +32,6 @@ MapObjectsEvaluator::MapObjectsEvaluator() | ||||
| 				{ | ||||
| 					objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = handler->getAiValue().get(); | ||||
| 				} | ||||
| 				else if(VLC->objtypeh->getObjGroupAiValue(primaryID) != boost::none) //if value is not initialized - fallback to default value for this object family if it exists | ||||
| 				{ | ||||
| 					objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = VLC->objtypeh->getObjGroupAiValue(primaryID).get(); | ||||
| 				} | ||||
| 				else //some default handling when aiValue not found, objects that require advanced properties (unavailable from handler) get their value calculated in getObjectValue | ||||
| 				{ | ||||
| 					objectDatabase[CompoundMapObjectID(primaryID, secondaryID)] = 0; | ||||
|   | ||||
| @@ -1371,7 +1371,7 @@ void CMapHandler::getTerrainDescr(const int3 & pos, std::string & out, bool isRM | ||||
|  | ||||
| 	if(t.hasFavorableWinds()) | ||||
| 	{ | ||||
| 		out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS); | ||||
| 		out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS, 0); | ||||
| 		return; | ||||
| 	} | ||||
| 	const TerrainTile2 & tt = ttiles[pos.z][pos.x][pos.y]; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| 	"creatureBank" : { | ||||
| 		"index" :16, | ||||
| 		"handler": "bank", | ||||
| 		"lastReservedIndex" : 6, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["ROGUE"] | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| 	"creatureGeneratorCommon" : { | ||||
| 		"index" :17, | ||||
| 		"handler": "dwelling", | ||||
| 		"lastReservedIndex" : 79, | ||||
| 		"base" : { | ||||
| 			"base" : { | ||||
| 				"visitableFrom" : [ "---", "+++", "+++" ], | ||||
| @@ -528,6 +529,7 @@ | ||||
| 	"creatureGeneratorSpecial" : { | ||||
| 		"index" :20, | ||||
| 		"handler": "dwelling", | ||||
| 		"lastReservedIndex" : 1, | ||||
| 		"types" : { | ||||
| 			"elementalConflux" : { | ||||
| 				"index" : 0, | ||||
|   | ||||
| @@ -230,6 +230,7 @@ | ||||
| 	"subterraneanGate" : { | ||||
| 		"index" :103, | ||||
| 		"handler" : "subterraneanGate", | ||||
| 		"lastReservedIndex" : 1, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"ambient" : ["LOOPGATE"], | ||||
| @@ -559,6 +560,7 @@ | ||||
| 	"witchHut" : { | ||||
| 		"index" :113, | ||||
| 		"handler" : "witch", | ||||
| 		"lastReservedIndex" : 1, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["GAZEBO"] | ||||
|   | ||||
| @@ -23,8 +23,8 @@ | ||||
| 	"hero" : { | ||||
| 		"index" :34, | ||||
| 		"handler": "hero", | ||||
| 		"defaultAiValue" : 7500, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 7500, | ||||
| 			"base" : { | ||||
| 				"visitableFrom" : [ "+++", "+-+", "+++" ], | ||||
| 				"mask" : [ "VVV", "VAV"] | ||||
| @@ -54,6 +54,7 @@ | ||||
| 	"resource" : { | ||||
| 		"index" :79, | ||||
| 		"handler": "resource", | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"base" : { | ||||
| 				"visitableFrom" : [ "+++", "+-+", "+++" ], | ||||
| @@ -76,8 +77,8 @@ | ||||
| 	"town" : { | ||||
| 		"index" :98, | ||||
| 		"handler": "town", | ||||
| 		"defaultAiValue" : 20000, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 20000, | ||||
| 			"filters" : { | ||||
| 				// village image - fort not present | ||||
| 				"village" : [ "noneOf", [ "fort" ] ], | ||||
| @@ -106,8 +107,9 @@ | ||||
| 	"boat" : { | ||||
| 		"index" :8, | ||||
| 		"handler": "boat", | ||||
| 		"defaultAiValue" : 0, | ||||
| 		"lastReservedIndex" : 2, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 0, | ||||
| 			"base" : { | ||||
| 				"visitableFrom" : [ "+++", "+-+", "+++" ], | ||||
| 				"mask" : [ "VVV", "VAV" ] | ||||
| @@ -124,8 +126,9 @@ | ||||
| 	"borderGuard" : { | ||||
| 		"index" :9, | ||||
| 		"handler": "borderGuard", | ||||
| 		"defaultAiValue" : 0, | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 0, | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["CAVEHEAD"], | ||||
| 				"removal" : [ "PICKUP01", "PICKUP02", "PICKUP03", "PICKUP04", "PICKUP05", "PICKUP06", "PICKUP07" ] | ||||
| @@ -145,8 +148,9 @@ | ||||
| 	"borderGate" : { | ||||
| 		"index" :212, | ||||
| 		"handler": "borderGate", | ||||
| 		"defaultAiValue" : 0, | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 0, | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["CAVEHEAD"] | ||||
| 			} | ||||
| @@ -165,8 +169,9 @@ | ||||
| 	"keymasterTent" : { | ||||
| 		"index" :10, | ||||
| 		"handler": "keymaster", | ||||
| 		"defaultAiValue" : 10000, | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 10000, | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["CAVEHEAD"] | ||||
| 			} | ||||
| @@ -186,8 +191,9 @@ | ||||
| 	"seerHut" : { | ||||
| 		"index" :83, | ||||
| 		"handler": "seerHut", | ||||
| 		"defaultAiValue" : 10000, | ||||
| 		"lastReservedIndex" : 2, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 10000, | ||||
| 			"base" : { | ||||
| 				"visitableFrom" : [ "---", "+++", "+++" ], | ||||
| 				"mask" : [ "VVV", "VVV", "VAV" ] | ||||
| @@ -207,6 +213,7 @@ | ||||
| 	"cartographer" : { | ||||
| 		"index" :13, | ||||
| 		"handler": "cartographer", | ||||
| 		"lastReservedIndex" : 2, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["LIGHTHOUSE"] | ||||
| @@ -223,6 +230,7 @@ | ||||
| 	"mine" : { | ||||
| 		"index" :53, | ||||
| 		"handler": "mine", | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["FLAGMINE"] | ||||
| @@ -320,8 +328,8 @@ | ||||
| 	"abandonedMine" : { | ||||
| 		"index" :220, | ||||
| 		"handler": "mine", | ||||
| 		"defaultAiValue" : 3500, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 3500, | ||||
| 			"sounds" : { | ||||
| 				"ambient" : ["LOOPCAVE"] | ||||
| 			} | ||||
| @@ -334,8 +342,9 @@ | ||||
| 	"garrisonHorizontal": { | ||||
| 		"index" :33, | ||||
| 		"handler": "garrison", | ||||
| 		"defaultAiValue" : 0, | ||||
| 		"lastReservedIndex" : 1, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 0, | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["MILITARY"] | ||||
| 			} | ||||
| @@ -358,8 +367,9 @@ | ||||
| 	"garrisonVertical" : { | ||||
| 		"index" :219, | ||||
| 		"handler": "garrison", | ||||
| 		"defaultAiValue" : 0, | ||||
| 		"lastReservedIndex" : 1, | ||||
| 		"base" : { | ||||
| 			"aiValue" : 0, | ||||
| 			"sounds" : { | ||||
| 				"visit" : ["MILITARY"] | ||||
| 			} | ||||
| @@ -384,6 +394,7 @@ | ||||
| 	"monolithOneWayEntrance" : { | ||||
| 		"index" :43, | ||||
| 		"handler": "monolith", | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"ambient" : ["LOOPMON1"], | ||||
| @@ -404,6 +415,7 @@ | ||||
| 	"monolithOneWayExit" : { | ||||
| 		"index" :44, | ||||
| 		"handler": "monolith", | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"sounds" : { "ambient" : ["LOOPMON1"] } | ||||
| 		}, | ||||
| @@ -421,6 +433,7 @@ | ||||
| 	"monolithTwoWay" : { | ||||
| 		"index" :45, | ||||
| 		"handler": "monolith", | ||||
| 		"lastReservedIndex" : 7, | ||||
| 		"base" : { | ||||
| 			"sounds" : { | ||||
| 				"ambient" : ["LOOPMON2"], | ||||
| @@ -441,7 +454,9 @@ | ||||
|  | ||||
| 	// subtype: level | ||||
| 	"randomDwellingLvl" : { | ||||
| 		"index" :217, "handler": "randomDwelling", | ||||
| 		"index" :217,  | ||||
| 		"handler": "randomDwelling", | ||||
| 		"lastReservedIndex" : 6, | ||||
| 			"types" : { | ||||
| 				"objectLvl1" : { "index" : 0}, | ||||
| 				"objectLvl2" : { "index" : 1}, | ||||
| @@ -457,6 +472,7 @@ | ||||
| 	"randomDwellingFaction" : { | ||||
| 		"index" :218, | ||||
| 		"handler": "randomDwelling", | ||||
| 		"lastReservedIndex" : 8, | ||||
| 			"types" : { | ||||
| 				"objectCastle"     : { "index" : 0}, | ||||
| 				"objectRampart"    : { "index" : 1}, | ||||
|   | ||||
| @@ -10,46 +10,9 @@ | ||||
| 		"index": { | ||||
| 			"type":"number" | ||||
| 		}, | ||||
| 		"name": { | ||||
| 			"type":"string" | ||||
| 		}, | ||||
| 		"defaultAiValue": { | ||||
| 			"type":"number" | ||||
| 		}, | ||||
|  | ||||
| 		"handler": { | ||||
| 			"type":"string" | ||||
| 		}, | ||||
|  | ||||
| 		"sounds": { | ||||
| 			"type":"object", | ||||
| 			"additionalProperties" : false, | ||||
| 			"description": "Sounds used by this object", | ||||
| 			"properties" : { | ||||
| 				"ambient": { | ||||
| 					"type":"array", | ||||
| 					"description": "Background sound of an object", | ||||
| 					"items": { | ||||
| 						"type": "string" | ||||
| 					} | ||||
| 				}, | ||||
| 				"visit": { | ||||
| 					"type":"array", | ||||
| 					"description": "Sound that played on object visit", | ||||
| 					"items": { | ||||
| 						"type": "string" | ||||
| 					} | ||||
| 				}, | ||||
| 				"removal": { | ||||
| 					"type":"array", | ||||
| 					"description": "Sound that played on object removal", | ||||
| 					"items": { | ||||
| 						"type": "string" | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
|  | ||||
| 		"base": { | ||||
| 			"type" : "object" | ||||
| 		}, | ||||
|   | ||||
| @@ -129,7 +129,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 	} | ||||
| 	else if(type == OBJ_NAMES) | ||||
| 	{ | ||||
| 		dst = VLC->objtypeh->getObjectName(ser); | ||||
| 		dst = VLC->objtypeh->getObjectName(ser, 0); | ||||
| 	} | ||||
| 	else if(type == SEC_SKILL_NAME) | ||||
| 	{ | ||||
|   | ||||
| @@ -92,7 +92,7 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| CObjectClassesHandler::~CObjectClassesHandler() | ||||
| { | ||||
| 	for(auto p : objects) | ||||
| 		delete p.second; | ||||
| 		delete p; | ||||
| } | ||||
|  | ||||
| std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
| @@ -118,190 +118,149 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
| 	CLegacyConfigParser namesParser("Data/ObjNames.txt"); | ||||
| 	for (size_t i=0; i<256; i++) | ||||
| 	{ | ||||
| 		ret[i]["name"].String() = namesParser.readString(); | ||||
| 		ret[i]["base"]["name"].String() = namesParser.readString(); | ||||
| 		namesParser.endLine(); | ||||
| 	} | ||||
|  | ||||
| 	JsonNode cregen1; | ||||
| 	JsonNode cregen4; | ||||
|  | ||||
| 	CLegacyConfigParser cregen1Parser("data/crgen1"); | ||||
| 	do | ||||
| 		customNames[Obj::CREATURE_GENERATOR1].push_back(cregen1Parser.readString()); | ||||
| 	{ | ||||
| 		JsonNode subObject; | ||||
| 		subObject["name"].String() = cregen1Parser.readString(); | ||||
| 		cregen1.Vector().push_back(subObject); | ||||
| 	} | ||||
| 	while(cregen1Parser.endLine()); | ||||
|  | ||||
| 	CLegacyConfigParser cregen4Parser("data/crgen4"); | ||||
| 	do | ||||
| 		customNames[Obj::CREATURE_GENERATOR4].push_back(cregen4Parser.readString()); | ||||
| 	{ | ||||
| 		JsonNode subObject; | ||||
| 		subObject["name"].String() = cregen4Parser.readString(); | ||||
| 		cregen4.Vector().push_back(subObject); | ||||
| 	} | ||||
| 	while(cregen4Parser.endLine()); | ||||
|  | ||||
| 	ret[Obj::CREATURE_GENERATOR1]["subObjects"] = cregen1; | ||||
| 	ret[Obj::CREATURE_GENERATOR4]["subObjects"] = cregen4; | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /// selects preferred ID (or subID) for new object | ||||
| template<typename Map> | ||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 fixedObjectsBound) | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj) | ||||
| { | ||||
| 	assert(fixedObjectsBound > 0); | ||||
| 	if(fixedID.isNull()) | ||||
| 	{ | ||||
| 		auto lastID = map.empty() ? 0 : map.rbegin()->first; | ||||
| 		return lastID < fixedObjectsBound ? fixedObjectsBound : lastID + 1; | ||||
| 	} | ||||
| 	auto id = static_cast<si32>(fixedID.Float()); | ||||
| 	if(id >= fixedObjectsBound) | ||||
| 		logGlobal->error("Getting next ID overflowed: %d >= %d", id, fixedObjectsBound); | ||||
| 	auto object = loadSubObjectFromJson(scope, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), identifier), entry, obj, obj->objects.size()); | ||||
|  | ||||
| 	return id; | ||||
| 	assert(object); | ||||
| 	obj->objects.push_back(object); | ||||
|  | ||||
| 	registerObject(scope, obj->getIdentifier(), identifier, object->subtype); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject) | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index) | ||||
| { | ||||
| 	static const si32 fixedObjectsBound = 1000; // legacy value for backward compatibilitty | ||||
| 	static const si32 fixedSubobjectsBound = 10000000; // large enough arbitrary value to avoid ID-collisions | ||||
| 	si32 usedBound = fixedObjectsBound; | ||||
| 	//TODO: load name for subobjects | ||||
| 	auto object = loadSubObjectFromJson(scope, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), identifier), entry, obj, index); | ||||
|  | ||||
| 	assert(object); | ||||
| 	assert(obj->objects[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	obj->objects[index] = object; | ||||
|  | ||||
| 	registerObject(scope, obj->getIdentifier(), identifier, object->subtype); | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::loadSubObjectFromJson(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index) | ||||
| { | ||||
| 	if(!handlerConstructors.count(obj->handlerName)) | ||||
| 	{ | ||||
| 		logGlobal->error("Handler with name %s was not found!", obj->handlerName); | ||||
| 		return; | ||||
| 	} | ||||
| 	const auto convertedId = VLC->modh->normalizeIdentifier(entry.meta, CModHandler::scopeBuiltin(), identifier); | ||||
| 	const auto & entryIndex = entry["index"]; | ||||
| 	bool useSelectNextID = !isSubobject || entryIndex.isNull(); | ||||
|  | ||||
| 	if(useSelectNextID && isSubobject) | ||||
| 	{ | ||||
| 		usedBound = fixedSubobjectsBound; | ||||
| 		logGlobal->error("Subobject index is Null. convertedId = '%s' obj->id = %d", convertedId, obj->id); | ||||
| 	} | ||||
| 	si32 id = useSelectNextID ? selectNextID(entryIndex, obj->subObjects, usedBound)  | ||||
| 		: (si32)entryIndex.Float(); | ||||
|  | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->setType(obj->id, id); | ||||
| 	handler->setTypeName(obj->getIdentifier(), convertedId); | ||||
|  | ||||
| 	if (customNames.count(obj->id) && customNames.at(obj->id).size() > id) | ||||
| 		handler->init(entry, customNames.at(obj->id).at(id)); | ||||
| 	else | ||||
| 		handler->init(entry); | ||||
|  | ||||
| 	//if (handler->getTemplates().empty()) | ||||
| 	{ | ||||
| 		auto range = legacyTemplates.equal_range(std::make_pair(obj->id, id)); | ||||
| 		for (auto & templ : boost::make_iterator_range(range.first, range.second)) | ||||
| 		{ | ||||
| 			handler->addTemplate(templ.second); | ||||
| 		} | ||||
| 		legacyTemplates.erase(range.first, range.second); | ||||
| 		return nullptr; | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->debug("Loaded object %s(%d)::%s(%d)", obj->getIdentifier(), obj->id, convertedId, id); | ||||
| 	auto createdObject = handlerConstructors.at(obj->handlerName)(); | ||||
| 	createdObject->setType(obj->id, index); | ||||
| 	createdObject->setTypeName(obj->getIdentifier(), identifier); | ||||
| 	createdObject->init(entry); | ||||
|  | ||||
| 	//some mods redefine content handlers in the decoration.json in such way: | ||||
| 	//"core:sign" : { "types" : { "forgeSign" : { ... | ||||
| 	static const std::vector<std::string> breakersRMG | ||||
| 	auto range = legacyTemplates.equal_range(std::make_pair(obj->id, index)); | ||||
| 	for (auto & templ : boost::make_iterator_range(range.first, range.second)) | ||||
| 	{ | ||||
| 		"hota.hota decorations:hotaPandoraBox" | ||||
| 		, "hota.hota decorations:hotaSubterreanGate" | ||||
| 	}; | ||||
| 	const bool isExistingKey = obj->subObjects.count(id) > 0; | ||||
| 	const bool isBreaker = std::any_of(breakersRMG.begin(), breakersRMG.end(), | ||||
| 		[&handler](const std::string & str) | ||||
| 		{ | ||||
| 			return str.compare(handler->subTypeName) == 0; | ||||
| 		}); | ||||
| 	const bool passedHandler = !isExistingKey && !isBreaker; | ||||
| 		createdObject->addTemplate(templ.second); | ||||
| 	} | ||||
| 	legacyTemplates.erase(range.first, range.second); | ||||
|  | ||||
| 	if(passedHandler) | ||||
| 	{ | ||||
| 		obj->subObjects[id] = handler; | ||||
| 		obj->subIds[convertedId] = id; | ||||
| 	} | ||||
| 	else if(isExistingKey) //It's supposed that fan mods handlers are not overridden by default handlers | ||||
| 	{ | ||||
| 		logGlobal->trace("Handler '%s' has not been overridden with handler '%s' in object %s(%d)::%s(%d)", | ||||
| 			obj->subObjects[id]->subTypeName, obj->handlerName, obj->getIdentifier(), obj->id, convertedId, id); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		logGlobal->warn("Handler '%s' for object %s(%d)::%s(%d) has not been activated as RMG breaker", | ||||
| 			obj->handlerName, obj->getIdentifier(), obj->id, convertedId, id); | ||||
| 	} | ||||
| 	logGlobal->debug("Loaded object %s(%d)::%s(%d)", obj->getIdentifier(), obj->id, identifier, index); | ||||
|  | ||||
| 	return createdObject; | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::ObjectContainter::getIdentifier() const | ||||
| std::string ObjectClass::getIdentifier() const | ||||
| { | ||||
| 	return modScope + ":" + identifier; | ||||
| 	return identifier + "Object"; | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::ObjectContainter::getNameTextID() const | ||||
| ObjectClass * CObjectClassesHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index) | ||||
| { | ||||
| 	return TextIdentifier ("object", modScope, identifier, "name").get(); | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::ObjectContainter::getNameTranslated() const | ||||
| { | ||||
| 	return VLC->generaltexth->translate(getNameTextID()); | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(scope, name); | ||||
| 	static const si32 fixedObjectsBound = 256; //Legacy value for backward compatibility | ||||
|  | ||||
| 	VLC->generaltexth->registerString( obj->getNameTextID(), json["name"].String()); | ||||
| 	auto obj = new ObjectClass(scope, name); | ||||
|  | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; | ||||
| 	obj->id = selectNextID(json["index"], objects, fixedObjectsBound); | ||||
| 	obj->id = index; | ||||
|  | ||||
| 	if(json["defaultAiValue"].isNull()) | ||||
| 		obj->groupDefaultAiValue = boost::none; | ||||
| 	else | ||||
| 		obj->groupDefaultAiValue = static_cast<boost::optional<si32>>(json["defaultAiValue"].Integer()); | ||||
|  | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 		loadObjectEntry(entry.first, entry.second, obj); | ||||
| 	obj->objects.resize(json["lastReservedIndex"].Float() + 1); | ||||
| 	auto originalData = json["subObjects"].Vector(); | ||||
|  | ||||
| 	for (auto subData : json["types"].Struct()) | ||||
| 	{ | ||||
| 		if (!subData.second["index"].isNull()) | ||||
| 		{ | ||||
| 			size_t subIndex = subData.second["index"].Integer(); | ||||
| 			if (subIndex < originalData.size()) | ||||
| 			{ | ||||
| 				JsonUtils::merge(originalData[subIndex], subData.second); | ||||
| 				std::swap(originalData[subIndex], subData.second); | ||||
| 			} | ||||
| 			loadSubObject(scope, subData.first, subData.second, obj, subIndex); | ||||
| 		} | ||||
| 		else | ||||
| 			loadSubObject(scope, subData.first, subData.second, obj); | ||||
| 	} | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| 	auto object = loadFromJson(scope, data, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), name)); | ||||
| 	objects[object->id] = object; | ||||
| 	auto object = loadFromJson(scope, data, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), name), objects.size()); | ||||
| 	objects.push_back(object); | ||||
| 	VLC->modh->identifiers.registerObject(scope, "object", name, object->id); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) | ||||
| { | ||||
| 	auto object = loadFromJson(scope, data, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), name)); | ||||
| 	auto object = loadFromJson(scope, data, VLC->modh->normalizeIdentifier(scope, CModHandler::scopeBuiltin(), name), index); | ||||
| 	assert(objects[(si32)index] == nullptr); // ensure that this id was not loaded before | ||||
| 	objects[(si32)index] = object; | ||||
| 	VLC->modh->identifiers.registerObject(scope, "object", name, object->id); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & identifier, JsonNode config, si32 ID, si32 subID) | ||||
| { | ||||
| 	static const bool isSubObject = true; | ||||
|  | ||||
| 	config.setType(JsonNode::JsonType::DATA_STRUCT); // ensure that input is not NULL | ||||
| 	assert(objects.count(ID)); | ||||
| 	if (subID) | ||||
| 	{ | ||||
| 		assert(objects.at(ID)->subObjects.count(subID.get()) == 0); | ||||
| 		assert(config["index"].isNull()); | ||||
| 		config["index"].Float() = subID.get(); | ||||
| 		config["index"].setMeta(config.meta); | ||||
| 	} | ||||
| 	assert(ID < objects.size()); | ||||
| 	assert(objects[ID]); | ||||
|  | ||||
| 	JsonUtils::inherit(config, objects.at(ID)->base); | ||||
| 	loadObjectEntry(identifier, config, objects[ID], isSubObject); | ||||
| 	loadSubObject(config.meta, identifier, config, objects[ID], subID); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(objects.count(ID)); | ||||
| 	assert(objects.at(ID)->subObjects.count(subID)); | ||||
| 	objects.at(ID)->subObjects.erase(subID); //TODO: cleanup string id map | ||||
| 	assert(ID < objects.size()); | ||||
| 	assert(objects[ID]); | ||||
| 	assert(subID < objects[ID]->objects.size()); | ||||
| 	objects[ID]->objects[subID] = nullptr; | ||||
| } | ||||
|  | ||||
| std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
| @@ -311,14 +270,11 @@ std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 	{ | ||||
| 		if (objects.at(type)->subObjects.count(subtype)) | ||||
| 			return objects.at(type)->subObjects.at(subtype); | ||||
| 	} | ||||
| 	std::string errorString = "Failed to find object of type " + std::to_string(type) + "::" + std::to_string(subtype); | ||||
| 	logGlobal->error(errorString); | ||||
| 	throw std::runtime_error(errorString); | ||||
| 	assert(type < objects.size()); | ||||
| 	assert(objects[type]); | ||||
| 	assert(subtype < objects[type]->objects.size()); | ||||
|  | ||||
| 	return objects.at(type)->objects.at(subtype); | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string scope, std::string type, std::string subtype) const | ||||
| @@ -326,14 +282,13 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string scope, std:: | ||||
| 	boost::optional<si32> id = VLC->modh->identifiers.getIdentifier(scope, "object", type, false); | ||||
| 	if(id) | ||||
| 	{ | ||||
| 		auto object = objects.at(id.get()); | ||||
| 		if(object->subIds.count(subtype)) | ||||
| 		{ | ||||
| 			si32 subId = object->subIds.at(subtype); | ||||
| 		auto object = objects[id.get()]; | ||||
| 		boost::optional<si32> subID = VLC->modh->identifiers.getIdentifier(scope, object->getIdentifier(), subtype, false); | ||||
|  | ||||
| 			return object->subObjects.at(subId); | ||||
| 		} | ||||
| 		if (subID) | ||||
| 			return object->objects[subID.get()]; | ||||
| 	} | ||||
|  | ||||
| 	std::string errorString = "Failed to find object of type " + type + "::" + subtype; | ||||
| 	logGlobal->error(errorString); | ||||
| 	throw std::runtime_error(errorString); | ||||
| @@ -349,20 +304,23 @@ std::set<si32> CObjectClassesHandler::knownObjects() const | ||||
| 	std::set<si32> ret; | ||||
|  | ||||
| 	for (auto entry : objects) | ||||
| 		ret.insert(entry.first); | ||||
| 		if (entry) | ||||
| 			ret.insert(entry->id); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| std::set<si32> CObjectClassesHandler::knownSubObjects(si32 primaryID) const | ||||
| { | ||||
| 	assert(primaryID < objects.size()); | ||||
| 	assert(objects[primaryID]); | ||||
|  | ||||
| 	std::set<si32> ret; | ||||
|  | ||||
| 	if (objects.count(primaryID)) | ||||
| 	{ | ||||
| 		for (auto entry : objects.at(primaryID)->subObjects) | ||||
| 			ret.insert(entry.first); | ||||
| 	} | ||||
| 	for (auto entry : objects.at(primaryID)->objects) | ||||
| 		if (entry) | ||||
| 			ret.insert(entry->subtype); | ||||
|  | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| @@ -380,16 +338,19 @@ void CObjectClassesHandler::afterLoadFinalization() | ||||
| { | ||||
| 	for(auto entry : objects) | ||||
| 	{ | ||||
| 		for(auto obj : entry.second->subObjects) | ||||
| 		if (!entry) | ||||
| 			continue; | ||||
|  | ||||
| 		for(auto obj : entry->objects) | ||||
| 		{ | ||||
| 			obj.second->afterLoadFinalization(); | ||||
| 			if(obj.second->getTemplates().empty()) | ||||
| 				logGlobal->warn("No templates found for %d:%d", entry.first, obj.first); | ||||
| 			obj->afterLoadFinalization(); | ||||
| 			if(obj->getTemplates().empty()) | ||||
| 				logGlobal->warn("No templates found for %s:%s", entry->getIdentifier(), obj->getIdentifier()); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	//duplicate existing two-way portals to make reserve for RMG | ||||
| 	auto& portalVec = objects[Obj::MONOLITH_TWO_WAY]->subObjects; | ||||
| 	auto& portalVec = objects[Obj::MONOLITH_TWO_WAY]->objects; | ||||
| 	size_t portalCount = portalVec.size(); | ||||
| 	size_t currentIndex = portalCount; | ||||
| 	while(portalVec.size() < 100) | ||||
| @@ -399,39 +360,18 @@ void CObjectClassesHandler::afterLoadFinalization() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::getObjectName(si32 type) const | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 		return  objects.at(type)->getNameTranslated(); | ||||
| 	logGlobal->error("Access to non existing object of type %d", type); | ||||
| 	return ""; | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::getObjectName(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if (knownSubObjects(type).count(subtype)) | ||||
| 	{ | ||||
| 		auto name = getHandlerFor(type, subtype)->getCustomName(); | ||||
| 		if (name) | ||||
| 			return name.get(); | ||||
| 	} | ||||
| 	return getObjectName(type); | ||||
| } | ||||
|  | ||||
| SObjectSounds CObjectClassesHandler::getObjectSounds(si32 type) const | ||||
| { | ||||
| 	if(objects.count(type)) | ||||
| 		return objects.at(type)->sounds; | ||||
| 	logGlobal->error("Access to non existing object of type %d", type); | ||||
| 	return SObjectSounds(); | ||||
| 	return getHandlerFor(type, subtype)->getNameTranslated(); | ||||
| } | ||||
|  | ||||
| SObjectSounds CObjectClassesHandler::getObjectSounds(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if(knownSubObjects(type).count(subtype)) | ||||
| 		return getHandlerFor(type, subtype)->getSounds(); | ||||
| 	else | ||||
| 		return getObjectSounds(type); | ||||
| 	assert(type < objects.size()); | ||||
| 	assert(objects[type]); | ||||
| 	assert(subtype < objects[type]->objects.size()); | ||||
|  | ||||
| 	return getHandlerFor(type, subtype)->getSounds(); | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::getObjectHandlerName(si32 type) const | ||||
| @@ -439,11 +379,6 @@ std::string CObjectClassesHandler::getObjectHandlerName(si32 type) const | ||||
| 	return objects.at(type)->handlerName; | ||||
| } | ||||
|  | ||||
| boost::optional<si32> CObjectClassesHandler::getObjGroupAiValue(si32 primaryID) const | ||||
| { | ||||
| 	return objects.at(primaryID)->groupDefaultAiValue; | ||||
| } | ||||
|  | ||||
| AObjectTypeHandler::AObjectTypeHandler(): | ||||
| 	type(-1), subtype(-1) | ||||
| { | ||||
| @@ -466,6 +401,21 @@ void AObjectTypeHandler::setTypeName(std::string type, std::string subtype) | ||||
| 	this->subTypeName = subtype; | ||||
| } | ||||
|  | ||||
| std::string AObjectTypeHandler::getIdentifier() const | ||||
| { | ||||
| 	return modName + ":" + subTypeName; | ||||
| } | ||||
|  | ||||
| std::string AObjectTypeHandler::getTypeName() | ||||
| { | ||||
| 	return typeName; | ||||
| } | ||||
|  | ||||
| std::string AObjectTypeHandler::getSubTypeName() | ||||
| { | ||||
| 	return subTypeName; | ||||
| } | ||||
|  | ||||
| static ui32 loadJsonOrMax(const JsonNode & input) | ||||
| { | ||||
| 	if (input.isNull()) | ||||
| @@ -474,7 +424,7 @@ static ui32 loadJsonOrMax(const JsonNode & input) | ||||
| 		return static_cast<ui32>(input.Float()); | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::string> name) | ||||
| void AObjectTypeHandler::init(const JsonNode & input) | ||||
| { | ||||
| 	base = input["base"]; | ||||
|  | ||||
| @@ -506,10 +456,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (input["name"].isNull()) | ||||
| 		objectName = name; | ||||
| 	else | ||||
| 		objectName.reset(input["name"].String()); | ||||
| 	VLC->generaltexth->registerString(getNameTextID(), input["name"].String()); | ||||
|  | ||||
| 	for(const JsonNode & node : input["sounds"]["ambient"].Vector()) | ||||
| 		sounds.ambient.push_back(node.String()); | ||||
| @@ -551,9 +498,14 @@ void AObjectTypeHandler::initTypeData(const JsonNode & input) | ||||
| 	// empty implementation for overrides | ||||
| } | ||||
|  | ||||
| boost::optional<std::string> AObjectTypeHandler::getCustomName() const | ||||
| std::string AObjectTypeHandler::getNameTextID() const | ||||
| { | ||||
| 	return objectName; | ||||
| 	return TextIdentifier( typeName, modName, subTypeName, "name" ).get(); | ||||
| } | ||||
|  | ||||
| std::string AObjectTypeHandler::getNameTranslated() const | ||||
| { | ||||
| 	return VLC->generaltexth->translate(getNameTextID()); | ||||
| } | ||||
|  | ||||
| SObjectSounds AObjectTypeHandler::getSounds() const | ||||
|   | ||||
| @@ -136,12 +136,13 @@ public: | ||||
|  | ||||
| class CGObjectInstance; | ||||
|  | ||||
| /// Class responsible for creation of objects of specific type & subtype | ||||
| class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable | ||||
| { | ||||
| 	RandomMapInfo rmgInfo; | ||||
|  | ||||
| 	/// Human-readable name of this object, used for objects like banks and dwellings, if set | ||||
| 	boost::optional<std::string> objectName; | ||||
| 	/// Text ID for human-readable name of this object, used for objects like banks and dwellings, if set | ||||
| 	boost::optional<std::string> nameTextID; | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| @@ -150,7 +151,6 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable | ||||
| 	SObjectSounds sounds; | ||||
|  | ||||
| 	boost::optional<si32> aiValue; | ||||
|  | ||||
| 	boost::optional<std::string> battlefield; | ||||
|  | ||||
| protected: | ||||
| @@ -159,9 +159,10 @@ protected: | ||||
|  | ||||
| 	/// initialization for classes that inherit this one | ||||
| 	virtual void initTypeData(const JsonNode & input); | ||||
| public: | ||||
| 	std::string modName; | ||||
| 	std::string typeName; | ||||
| 	std::string subTypeName; | ||||
| public: | ||||
|  | ||||
| 	si32 type; | ||||
| 	si32 subtype; | ||||
| @@ -171,11 +172,20 @@ public: | ||||
| 	void setType(si32 type, si32 subtype); | ||||
| 	void setTypeName(std::string type, std::string subtype); | ||||
|  | ||||
| 	std::string getTypeName(); | ||||
| 	std::string getSubTypeName(); | ||||
|  | ||||
| 	/// loads generic data from Json structure and passes it towards type-specific constructors | ||||
| 	void init(const JsonNode & input, boost::optional<std::string> name = boost::optional<std::string>()); | ||||
| 	void init(const JsonNode & input); | ||||
|  | ||||
| 	/// returns full form of identifier of this object in form of modName:objectName | ||||
| 	std::string getIdentifier() const; | ||||
|  | ||||
| 	/// returns objet's name in form of translatable text ID | ||||
| 	std::string getNameTextID() const; | ||||
| 	std::string getNameTranslated() const; | ||||
|  | ||||
| 	/// Returns object-specific name, if set | ||||
| 	boost::optional<std::string> getCustomName() const; | ||||
| 	SObjectSounds getSounds() const; | ||||
|  | ||||
| 	void addTemplate(std::shared_ptr<const ObjectTemplate> templ); | ||||
| @@ -191,9 +201,6 @@ public: | ||||
|  | ||||
| 	BattleField getBattlefield() const; | ||||
|  | ||||
| 	/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) | ||||
| 	/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) | ||||
|  | ||||
| 	const RandomMapInfo & getRMGInfo(); | ||||
|  | ||||
| 	boost::optional<si32> getAiValue() const; | ||||
| @@ -219,7 +226,8 @@ public: | ||||
| 		h & subtype; | ||||
| 		h & templates; | ||||
| 		h & rmgInfo; | ||||
| 		h & objectName; | ||||
| 		h & nameTextID; | ||||
| 		h & modName; | ||||
| 		h & typeName; | ||||
| 		h & subTypeName; | ||||
| 		h & sounds; | ||||
| @@ -230,52 +238,42 @@ public: | ||||
|  | ||||
| typedef std::shared_ptr<AObjectTypeHandler> TObjectTypeHandler; | ||||
|  | ||||
| /// Class responsible for creation of adventure map objects of specific type | ||||
| class DLL_LINKAGE ObjectClass | ||||
| { | ||||
| 	std::string modScope; | ||||
| 	std::string identifier; | ||||
|  | ||||
| public: | ||||
| 	ObjectClass() = default; | ||||
| 	ObjectClass(const std::string & modScope, const std::string & identifier): | ||||
| 		identifier(identifier), | ||||
| 		modScope(modScope) | ||||
| 	{} | ||||
|  | ||||
| 	si32 id; | ||||
| 	std::string handlerName; // ID of handler that controls this object, should be determined using handlerConstructor map | ||||
|  | ||||
| 	JsonNode base; | ||||
| 	std::vector<TObjectTypeHandler> objects; | ||||
|  | ||||
| 	std::string getIdentifier() const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & handlerName; | ||||
| 		h & base; | ||||
| 		h & objects; | ||||
| 		h & identifier; | ||||
| 		h & modScope; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /// Main class responsible for creation of all adventure map objects | ||||
| class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| { | ||||
| 	/// Small internal structure that contains information on specific group of objects | ||||
| 	/// (creating separate entity is overcomplicating at least at this point) | ||||
| 	class DLL_LINKAGE ObjectContainter | ||||
| 	{ | ||||
| 		std::string identifier; | ||||
| 		std::string modScope; | ||||
|  | ||||
| 	public: | ||||
| 		ObjectContainter() = default; | ||||
| 		ObjectContainter(const std::string & modScope, const std::string & identifier): | ||||
| 			identifier(identifier), | ||||
| 			modScope(modScope) | ||||
| 		{} | ||||
|  | ||||
| 		si32 id; | ||||
| 		std::string handlerName; // ID of handler that controls this object, should be determined using handlerConstructor map | ||||
|  | ||||
| 		JsonNode base; | ||||
| 		std::map<si32, TObjectTypeHandler> subObjects; | ||||
| 		std::map<std::string, si32> subIds;//full id from core scope -> subtype | ||||
|  | ||||
| 		SObjectSounds sounds; | ||||
|  | ||||
| 		boost::optional<si32> groupDefaultAiValue; | ||||
|  | ||||
| 		std::string getIdentifier() const; | ||||
| 		std::string getNameTextID() const; // {scope, "objects", name, "name"} | ||||
| 		std::string getNameTranslated() const; | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & handlerName; | ||||
| 			h & base; | ||||
| 			h & subObjects; | ||||
| 			h & identifier; | ||||
| 			h & modScope; | ||||
| 			h & subIds; | ||||
| 			h & sounds; | ||||
| 			h & groupDefaultAiValue; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// list of object handlers, each of them handles only one type | ||||
| 	std::map<si32, ObjectContainter * > objects; | ||||
| 	std::vector<ObjectClass * > objects; | ||||
|  | ||||
| 	/// map that is filled during contruction with all known handlers. Not serializeable due to usage of std::function | ||||
| 	std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors; | ||||
| @@ -284,12 +282,12 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| 	typedef std::multimap<std::pair<si32, si32>, std::shared_ptr<const ObjectTemplate>> TTemplatesContainer; | ||||
| 	TTemplatesContainer legacyTemplates; | ||||
|  | ||||
| 	/// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data | ||||
| 	/// format: customNames[primaryID][secondaryID] -> name | ||||
| 	std::map<si32, std::vector<std::string>> customNames; | ||||
| 	TObjectTypeHandler loadSubObjectFromJson(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index); | ||||
|  | ||||
| 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj, bool isSubobject = false); | ||||
| 	ObjectContainter * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name); | ||||
| 	void loadSubObject(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj); | ||||
| 	void loadSubObject(const std::string & scope, const std::string & identifier, const JsonNode & entry, ObjectClass * obj, size_t index); | ||||
|  | ||||
| 	ObjectClass * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & name, size_t index); | ||||
|  | ||||
| public: | ||||
| 	CObjectClassesHandler(); | ||||
| @@ -300,7 +298,7 @@ public: | ||||
| 	void loadObject(std::string scope, std::string name, const JsonNode & data) override; | ||||
| 	void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; | ||||
|  | ||||
| 	void loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>()); | ||||
| 	void loadSubObject(const std::string & identifier, JsonNode config, si32 ID, si32 subID); | ||||
| 	void removeSubObject(si32 ID, si32 subID); | ||||
|  | ||||
| 	void beforeValidate(JsonNode & object) override; | ||||
| @@ -317,17 +315,13 @@ public: | ||||
| 	TObjectTypeHandler getHandlerFor(std::string scope, std::string type, std::string subtype) const; | ||||
| 	TObjectTypeHandler getHandlerFor(CompoundMapObjectID compoundIdentifier) const; | ||||
|  | ||||
| 	std::string getObjectName(si32 type) const; | ||||
| 	std::string getObjectName(si32 type, si32 subtype) const; | ||||
|  | ||||
| 	SObjectSounds getObjectSounds(si32 type) const; | ||||
| 	SObjectSounds getObjectSounds(si32 type, si32 subtype) const; | ||||
|  | ||||
| 	/// Returns handler string describing the handler (for use in client) | ||||
| 	std::string getObjectHandlerName(si32 type) const; | ||||
|  | ||||
| 	boost::optional<si32> getObjGroupAiValue(si32 primaryID) const; //default AI value of objects belonging to particular primaryID | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & objects; | ||||
|   | ||||
| @@ -1171,7 +1171,7 @@ void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &comp | ||||
| void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const | ||||
| { | ||||
| 	if (!onHover) | ||||
| 		text << VLC->generaltexth->tentColors[subID] << " " << VLC->objtypeh->getObjectName(Obj::KEYMASTER); | ||||
| 		text << VLC->generaltexth->tentColors[subID] << " " << VLC->objtypeh->getObjectName(Obj::KEYMASTER, subID); | ||||
| } | ||||
|  | ||||
| bool CGBorderGuard::checkQuest(const CGHeroInstance * h) const | ||||
|   | ||||
| @@ -172,7 +172,7 @@ namespace TriggeredEventsDetail | ||||
| 				{ | ||||
| 					si32 subtype = *subtypes.begin(); | ||||
| 					auto handler = VLC->objtypeh->getHandlerFor(type, subtype); | ||||
| 					identifier = handler->typeName; | ||||
| 					identifier = handler->getTypeName(); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| @@ -1141,7 +1141,7 @@ void CMapLoaderJson::MapObjectLoader::construct() | ||||
| 	pos.z = static_cast<si32>(configuration["l"].Float()); | ||||
|  | ||||
| 	//special case for grail | ||||
|     if(typeName == "grail") | ||||
| 	if(typeName == "grail") | ||||
| 	{ | ||||
| 		owner->map->grailPos = pos; | ||||
|  | ||||
|   | ||||
| @@ -477,10 +477,7 @@ void MainWindow::addGroupIntoCatalog(const std::string & groupName, bool useCust | ||||
| 		if(staticOnly && !factory->isStaticObject()) | ||||
| 			continue; | ||||
|  | ||||
| 		auto subGroupName = QString::fromStdString(factory->subTypeName); | ||||
| 		auto customName = factory->getCustomName(); | ||||
| 		if(customName) | ||||
| 			subGroupName = tr(customName->c_str()); | ||||
| 		auto subGroupName = QString::fromStdString(factory->getNameTranslated()); | ||||
| 		 | ||||
| 		auto * itemType = new QStandardItem(subGroupName); | ||||
| 		for(int templateId = 0; templateId < templates.size(); ++templateId) | ||||
|   | ||||
| @@ -106,8 +106,8 @@ void MapController::repairMap() | ||||
| 		if(obj->ID != Obj::HERO && obj->ID != Obj::PRISON && (obj->typeName.empty() || obj->subTypeName.empty())) | ||||
| 		{ | ||||
| 			auto handler = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID); | ||||
| 			obj->typeName = handler->typeName; | ||||
| 			obj->subTypeName = handler->subTypeName; | ||||
| 			obj->typeName = handler->getTypeName(); | ||||
| 			obj->subTypeName = handler->getSubTypeName(); | ||||
| 		} | ||||
| 		//fix flags | ||||
| 		if(obj->getOwner() == PlayerColor::UNFLAGGABLE) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user