mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Line endings are now unix-style
This commit is contained in:
		| @@ -1,333 +1,333 @@ | ||||
| #include "StdInc.h" | ||||
| #include "CObjectClassesHandler.h" | ||||
|  | ||||
| #include "filesystem/Filesystem.h" | ||||
| #include "filesystem/CBinaryReader.h" | ||||
| #include "../lib/VCMI_Lib.h" | ||||
| #include "GameConstants.h" | ||||
| #include "StringConstants.h" | ||||
| #include "CGeneralTextHandler.h" | ||||
| #include "CModHandler.h" | ||||
| #include "JsonNode.h" | ||||
|  | ||||
| #include "CRewardableConstructor.h" | ||||
| #include "MapObjects.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectClassesHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| CObjectClassesHandler::CObjectClassesHandler() | ||||
| { | ||||
| #define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared<CLASSNAME>; | ||||
| #define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared<CDefaultObjectTypeHandler<TYPENAME> > | ||||
|  | ||||
| 	// list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code | ||||
| 	//WARNING: should be in sync with registerTypesMapObjectTypes function | ||||
| 	SET_HANDLER_CLASS("configurable", CRewardableConstructor); | ||||
|  | ||||
| 	SET_HANDLER("", CGObjectInstance); | ||||
| 	SET_HANDLER("generic", CGObjectInstance); | ||||
|  | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("bank", CBank); | ||||
| 	SET_HANDLER("cartographer", CCartographer); | ||||
| 	SET_HANDLER("artifact", CGArtifact); | ||||
| 	SET_HANDLER("blackMarket", CGBlackMarket); | ||||
| 	SET_HANDLER("boat", CGBoat); | ||||
| 	SET_HANDLER("bonusingObject", CGBonusingObject); | ||||
| 	SET_HANDLER("borderGate", CGBorderGate); | ||||
| 	SET_HANDLER("borderGuard", CGBorderGuard); | ||||
| 	SET_HANDLER("monster", CGCreature); | ||||
| 	SET_HANDLER("denOfThieves", CGDenOfthieves); | ||||
| 	SET_HANDLER("dwelling", CGDwelling); | ||||
| 	SET_HANDLER("event", CGEvent); | ||||
| 	SET_HANDLER("garrison", CGGarrison); | ||||
| 	SET_HANDLER("hero", CGHeroInstance); | ||||
| 	SET_HANDLER("heroPlaceholder", CGHeroPlaceholder); | ||||
| 	SET_HANDLER("keymaster", CGKeymasterTent); | ||||
| 	SET_HANDLER("lighthouse", CGLighthouse); | ||||
| 	SET_HANDLER("magi", CGMagi); | ||||
| 	SET_HANDLER("magicSpring", CGMagicSpring); | ||||
| 	SET_HANDLER("magicWell", CGMagicWell); | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("mine", CGMine); | ||||
| 	SET_HANDLER("obelisk", CGObelisk); | ||||
| 	SET_HANDLER("observatory", CGObservatory); | ||||
| 	SET_HANDLER("onceVisitable", CGOnceVisitable); | ||||
| 	SET_HANDLER("pandora", CGPandoraBox); | ||||
| 	SET_HANDLER("pickable", CGPickable); | ||||
| 	SET_HANDLER("pyramid", CGPyramid); | ||||
| 	SET_HANDLER("questGuard", CGQuestGuard); | ||||
| 	SET_HANDLER("resource", CGResource); | ||||
| 	SET_HANDLER("scholar", CGScholar); | ||||
| 	SET_HANDLER("seerHut", CGSeerHut); | ||||
| 	SET_HANDLER("shipyard", CGShipyard); | ||||
| 	SET_HANDLER("shrine", CGShrine); | ||||
| 	SET_HANDLER("sign", CGSignBottle); | ||||
| 	SET_HANDLER("siren", CGSirens); | ||||
| 	SET_HANDLER("teleport", CGTeleport); | ||||
| 	SET_HANDLER("town", CGTownInstance); | ||||
| 	SET_HANDLER("university", CGUniversity); | ||||
| 	SET_HANDLER("oncePerHero", CGVisitableOPH); | ||||
| 	SET_HANDLER("oncePerWeek", CGVisitableOPW); | ||||
| 	SET_HANDLER("witch", CGWitchHut); | ||||
|  | ||||
| #undef SET_HANDLER_CLASS | ||||
| #undef SET_HANDLER | ||||
| } | ||||
|  | ||||
| template<typename Container> | ||||
| void readTextFile(Container & objects, std::string path) | ||||
| { | ||||
| 	CLegacyConfigParser parser(path); | ||||
| 	size_t totalNumber = parser.readNumber(); // first line contains number of objects to read and nothing else | ||||
| 	parser.endLine(); | ||||
|  | ||||
| 	for (size_t i=0; i<totalNumber; i++) | ||||
| 	{ | ||||
| 		ObjectTemplate templ; | ||||
| 		templ.readTxt(parser); | ||||
| 		parser.endLine(); | ||||
| 		typename Container::key_type key(templ.id.num, templ.subid); | ||||
| 		objects.insert(std::make_pair(key, templ)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
| { | ||||
| 	readTextFile(legacyTemplates, "Data/Objects.txt"); | ||||
| 	readTextFile(legacyTemplates, "Data/Heroes.txt"); | ||||
|  | ||||
| 	std::vector<JsonNode> ret(dataSize);// create storage for 256 objects | ||||
| 	assert(dataSize == 256); | ||||
|  | ||||
| 	CLegacyConfigParser parser("Data/ObjNames.txt"); | ||||
| 	for (size_t i=0; i<256; i++) | ||||
| 	{ | ||||
| 		ret[i]["name"].String() = parser.readString(); | ||||
| 		parser.endLine(); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /// selects preferred ID (or subID) for new object | ||||
| template<typename Map> | ||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | ||||
| { | ||||
| 	if (!fixedID.isNull() && fixedID.Float() < defaultID) | ||||
| 		return fixedID.Float(); // H3M object with fixed ID | ||||
|  | ||||
| 	if (map.empty()) | ||||
| 		return defaultID; // no objects loaded, keep gap for H3M objects | ||||
| 	if (map.rbegin()->first > defaultID) | ||||
| 		return map.rbegin()->first + 1; // some modded objects loaded, return next available | ||||
|  | ||||
| 	return defaultID; // some H3M objects loaded, first modded found | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) | ||||
| { | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->init(entry); | ||||
|  | ||||
| 	si32 id = selectNextID(entry["index"], obj->objects, 1000); | ||||
| 	handler->setType(obj->id, id); | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
| 	 | ||||
| 	obj->objects[id] = handler; | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(); | ||||
| 	obj->name = json["name"].String(); | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; // FIXME: when this data will be actually merged? | ||||
| 	obj->id = selectNextID(json["index"], objects, 256); | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 	{ | ||||
| 		loadObjectEntry(entry.second, obj); | ||||
| 	} | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| 	auto object = loadFromJson(data); | ||||
| 	objects[object->id] = 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(data); | ||||
|  | ||||
| 	assert(objects[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	objects[index] = object; | ||||
|  | ||||
| 	VLC->modh->identifiers.registerObject(scope, "object", name, object->id); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::createObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||
| { | ||||
| 	config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL | ||||
| 	assert(objects.count(ID)); | ||||
| 	if (subID) | ||||
| 	{ | ||||
| 		assert(objects.at(ID)->objects.count(subID.get()) == 0); | ||||
| 		assert(config["index"].isNull()); | ||||
| 		config["index"].Float() = subID.get(); | ||||
| 	} | ||||
|  | ||||
| 	JsonUtils::inherit(config, objects.at(ID)->base); | ||||
|  | ||||
| 	loadObjectEntry(config, objects[ID]); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::eraseObject(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(objects.count(ID)); | ||||
| 	assert(objects.at(ID)->objects.count(subID)); | ||||
| 	objects.at(ID)->objects.erase(subID); | ||||
| } | ||||
|  | ||||
| std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
| { | ||||
| 	return std::vector<bool>(); //TODO? | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 	{ | ||||
| 		if (objects.at(type)->objects.count(subtype)) | ||||
| 			return objects.at(type)->objects.at(subtype); | ||||
| 	} | ||||
| 	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; | ||||
| 	assert(0); // FIXME: throw error? | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::beforeValidate(JsonNode & object) | ||||
| { | ||||
| 	for (auto & entry : object["types"].Struct()) | ||||
| 	{ | ||||
| 		JsonUtils::inherit(entry.second, object["base"]); | ||||
| 		for (auto & templ : entry.second["templates"].Struct()) | ||||
| 		{ | ||||
| 			JsonUtils::inherit(templ.second, entry.second["base"]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::afterLoadFinalization() | ||||
| { | ||||
| 	legacyTemplates.clear(); // whatever left there is no longer needed | ||||
| 	for (auto entry : objects) | ||||
| 	{ | ||||
| 		for (auto obj : entry.second->objects) | ||||
| 		{ | ||||
| 			if (obj.second->getTemplates().empty()) | ||||
| 				logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::getObjectName(si32 type) const | ||||
| { | ||||
| 	assert(objects.count(type)); | ||||
| 	return objects.at(type)->name; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::setType(si32 type, si32 subtype) | ||||
| { | ||||
| 	this->type = type; | ||||
| 	this->subtype = subtype; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::init(const JsonNode & input) | ||||
| { | ||||
| 	base = input["base"]; | ||||
| 	for (auto entry : input["templates"].Struct()) | ||||
| 	{ | ||||
| 		entry.second.setType(JsonNode::DATA_STRUCT); | ||||
| 		JsonUtils::inherit(entry.second, base); | ||||
|  | ||||
| 		ObjectTemplate tmpl; | ||||
| 		tmpl.id = Obj(type); | ||||
| 		tmpl.subid = subtype; | ||||
| 		tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template? | ||||
| 		tmpl.readJson(entry.second); | ||||
| 		templates.push_back(tmpl); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const | ||||
| { | ||||
| 	return true; // by default - accept all. | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(ObjectTemplate templ) | ||||
| { | ||||
| 	templ.id = Obj(type); | ||||
| 	templ.subid = subtype; | ||||
| 	templates.push_back(templ); | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(JsonNode config) | ||||
| { | ||||
| 	config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null | ||||
| 	JsonUtils::inherit(config, base); | ||||
| 	ObjectTemplate tmpl; | ||||
| 	tmpl.id = Obj(type); | ||||
| 	tmpl.subid = subtype; | ||||
| 	tmpl.stringID = ""; // TODO? | ||||
| 	tmpl.readJson(config); | ||||
| 	addTemplate(tmpl); | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const | ||||
| { | ||||
| 	return templates; | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(); | ||||
| 	std::vector<ObjectTemplate> filtered; | ||||
|  | ||||
| 	std::copy_if(ret.begin(), ret.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) | ||||
| 	{ | ||||
| 		return obj.canBePlacedAt(ETerrainType(terrainType)); | ||||
| 	}); | ||||
| 	// it is possible that there are no templates usable on specific terrain. In this case - return list before filtering | ||||
| 	return filtered.empty() ? ret : filtered; | ||||
| } | ||||
|  | ||||
| boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(terrainType); | ||||
| 	for (auto & tmpl : ret) | ||||
| 	{ | ||||
| 		if (objectFilter(object, tmpl)) | ||||
| 			return tmpl; | ||||
| 	} | ||||
| 	return boost::optional<ObjectTemplate>(); | ||||
| } | ||||
| #include "StdInc.h" | ||||
| #include "CObjectClassesHandler.h" | ||||
|  | ||||
| #include "filesystem/Filesystem.h" | ||||
| #include "filesystem/CBinaryReader.h" | ||||
| #include "../lib/VCMI_Lib.h" | ||||
| #include "GameConstants.h" | ||||
| #include "StringConstants.h" | ||||
| #include "CGeneralTextHandler.h" | ||||
| #include "CModHandler.h" | ||||
| #include "JsonNode.h" | ||||
|  | ||||
| #include "CRewardableConstructor.h" | ||||
| #include "MapObjects.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectClassesHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| CObjectClassesHandler::CObjectClassesHandler() | ||||
| { | ||||
| #define SET_HANDLER_CLASS(STRING, CLASSNAME) handlerConstructors[STRING] = std::make_shared<CLASSNAME>; | ||||
| #define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared<CDefaultObjectTypeHandler<TYPENAME> > | ||||
|  | ||||
| 	// list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code | ||||
| 	//WARNING: should be in sync with registerTypesMapObjectTypes function | ||||
| 	SET_HANDLER_CLASS("configurable", CRewardableConstructor); | ||||
|  | ||||
| 	SET_HANDLER("", CGObjectInstance); | ||||
| 	SET_HANDLER("generic", CGObjectInstance); | ||||
|  | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("bank", CBank); | ||||
| 	SET_HANDLER("cartographer", CCartographer); | ||||
| 	SET_HANDLER("artifact", CGArtifact); | ||||
| 	SET_HANDLER("blackMarket", CGBlackMarket); | ||||
| 	SET_HANDLER("boat", CGBoat); | ||||
| 	SET_HANDLER("bonusingObject", CGBonusingObject); | ||||
| 	SET_HANDLER("borderGate", CGBorderGate); | ||||
| 	SET_HANDLER("borderGuard", CGBorderGuard); | ||||
| 	SET_HANDLER("monster", CGCreature); | ||||
| 	SET_HANDLER("denOfThieves", CGDenOfthieves); | ||||
| 	SET_HANDLER("dwelling", CGDwelling); | ||||
| 	SET_HANDLER("event", CGEvent); | ||||
| 	SET_HANDLER("garrison", CGGarrison); | ||||
| 	SET_HANDLER("hero", CGHeroInstance); | ||||
| 	SET_HANDLER("heroPlaceholder", CGHeroPlaceholder); | ||||
| 	SET_HANDLER("keymaster", CGKeymasterTent); | ||||
| 	SET_HANDLER("lighthouse", CGLighthouse); | ||||
| 	SET_HANDLER("magi", CGMagi); | ||||
| 	SET_HANDLER("magicSpring", CGMagicSpring); | ||||
| 	SET_HANDLER("magicWell", CGMagicWell); | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("mine", CGMine); | ||||
| 	SET_HANDLER("obelisk", CGObelisk); | ||||
| 	SET_HANDLER("observatory", CGObservatory); | ||||
| 	SET_HANDLER("onceVisitable", CGOnceVisitable); | ||||
| 	SET_HANDLER("pandora", CGPandoraBox); | ||||
| 	SET_HANDLER("pickable", CGPickable); | ||||
| 	SET_HANDLER("pyramid", CGPyramid); | ||||
| 	SET_HANDLER("questGuard", CGQuestGuard); | ||||
| 	SET_HANDLER("resource", CGResource); | ||||
| 	SET_HANDLER("scholar", CGScholar); | ||||
| 	SET_HANDLER("seerHut", CGSeerHut); | ||||
| 	SET_HANDLER("shipyard", CGShipyard); | ||||
| 	SET_HANDLER("shrine", CGShrine); | ||||
| 	SET_HANDLER("sign", CGSignBottle); | ||||
| 	SET_HANDLER("siren", CGSirens); | ||||
| 	SET_HANDLER("teleport", CGTeleport); | ||||
| 	SET_HANDLER("town", CGTownInstance); | ||||
| 	SET_HANDLER("university", CGUniversity); | ||||
| 	SET_HANDLER("oncePerHero", CGVisitableOPH); | ||||
| 	SET_HANDLER("oncePerWeek", CGVisitableOPW); | ||||
| 	SET_HANDLER("witch", CGWitchHut); | ||||
|  | ||||
| #undef SET_HANDLER_CLASS | ||||
| #undef SET_HANDLER | ||||
| } | ||||
|  | ||||
| template<typename Container> | ||||
| void readTextFile(Container & objects, std::string path) | ||||
| { | ||||
| 	CLegacyConfigParser parser(path); | ||||
| 	size_t totalNumber = parser.readNumber(); // first line contains number of objects to read and nothing else | ||||
| 	parser.endLine(); | ||||
|  | ||||
| 	for (size_t i=0; i<totalNumber; i++) | ||||
| 	{ | ||||
| 		ObjectTemplate templ; | ||||
| 		templ.readTxt(parser); | ||||
| 		parser.endLine(); | ||||
| 		typename Container::key_type key(templ.id.num, templ.subid); | ||||
| 		objects.insert(std::make_pair(key, templ)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
| { | ||||
| 	readTextFile(legacyTemplates, "Data/Objects.txt"); | ||||
| 	readTextFile(legacyTemplates, "Data/Heroes.txt"); | ||||
|  | ||||
| 	std::vector<JsonNode> ret(dataSize);// create storage for 256 objects | ||||
| 	assert(dataSize == 256); | ||||
|  | ||||
| 	CLegacyConfigParser parser("Data/ObjNames.txt"); | ||||
| 	for (size_t i=0; i<256; i++) | ||||
| 	{ | ||||
| 		ret[i]["name"].String() = parser.readString(); | ||||
| 		parser.endLine(); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| /// selects preferred ID (or subID) for new object | ||||
| template<typename Map> | ||||
| si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | ||||
| { | ||||
| 	if (!fixedID.isNull() && fixedID.Float() < defaultID) | ||||
| 		return fixedID.Float(); // H3M object with fixed ID | ||||
|  | ||||
| 	if (map.empty()) | ||||
| 		return defaultID; // no objects loaded, keep gap for H3M objects | ||||
| 	if (map.rbegin()->first > defaultID) | ||||
| 		return map.rbegin()->first + 1; // some modded objects loaded, return next available | ||||
|  | ||||
| 	return defaultID; // some H3M objects loaded, first modded found | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) | ||||
| { | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->init(entry); | ||||
|  | ||||
| 	si32 id = selectNextID(entry["index"], obj->objects, 1000); | ||||
| 	handler->setType(obj->id, id); | ||||
|  | ||||
| 	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); | ||||
| 	} | ||||
| 	 | ||||
| 	obj->objects[id] = handler; | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(); | ||||
| 	obj->name = json["name"].String(); | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; // FIXME: when this data will be actually merged? | ||||
| 	obj->id = selectNextID(json["index"], objects, 256); | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 	{ | ||||
| 		loadObjectEntry(entry.second, obj); | ||||
| 	} | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| 	auto object = loadFromJson(data); | ||||
| 	objects[object->id] = 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(data); | ||||
|  | ||||
| 	assert(objects[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	objects[index] = object; | ||||
|  | ||||
| 	VLC->modh->identifiers.registerObject(scope, "object", name, object->id); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::createObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||
| { | ||||
| 	config.setType(JsonNode::DATA_STRUCT); // ensure that input is not NULL | ||||
| 	assert(objects.count(ID)); | ||||
| 	if (subID) | ||||
| 	{ | ||||
| 		assert(objects.at(ID)->objects.count(subID.get()) == 0); | ||||
| 		assert(config["index"].isNull()); | ||||
| 		config["index"].Float() = subID.get(); | ||||
| 	} | ||||
|  | ||||
| 	JsonUtils::inherit(config, objects.at(ID)->base); | ||||
|  | ||||
| 	loadObjectEntry(config, objects[ID]); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::eraseObject(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(objects.count(ID)); | ||||
| 	assert(objects.at(ID)->objects.count(subID)); | ||||
| 	objects.at(ID)->objects.erase(subID); | ||||
| } | ||||
|  | ||||
| std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
| { | ||||
| 	return std::vector<bool>(); //TODO? | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 	{ | ||||
| 		if (objects.at(type)->objects.count(subtype)) | ||||
| 			return objects.at(type)->objects.at(subtype); | ||||
| 	} | ||||
| 	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; | ||||
| 	assert(0); // FIXME: throw error? | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::beforeValidate(JsonNode & object) | ||||
| { | ||||
| 	for (auto & entry : object["types"].Struct()) | ||||
| 	{ | ||||
| 		JsonUtils::inherit(entry.second, object["base"]); | ||||
| 		for (auto & templ : entry.second["templates"].Struct()) | ||||
| 		{ | ||||
| 			JsonUtils::inherit(templ.second, entry.second["base"]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::afterLoadFinalization() | ||||
| { | ||||
| 	legacyTemplates.clear(); // whatever left there is no longer needed | ||||
| 	for (auto entry : objects) | ||||
| 	{ | ||||
| 		for (auto obj : entry.second->objects) | ||||
| 		{ | ||||
| 			if (obj.second->getTemplates().empty()) | ||||
| 				logGlobal->warnStream() << "No templates found for " << entry.first << ":" << obj.first; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::string CObjectClassesHandler::getObjectName(si32 type) const | ||||
| { | ||||
| 	assert(objects.count(type)); | ||||
| 	return objects.at(type)->name; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::setType(si32 type, si32 subtype) | ||||
| { | ||||
| 	this->type = type; | ||||
| 	this->subtype = subtype; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::init(const JsonNode & input) | ||||
| { | ||||
| 	base = input["base"]; | ||||
| 	for (auto entry : input["templates"].Struct()) | ||||
| 	{ | ||||
| 		entry.second.setType(JsonNode::DATA_STRUCT); | ||||
| 		JsonUtils::inherit(entry.second, base); | ||||
|  | ||||
| 		ObjectTemplate tmpl; | ||||
| 		tmpl.id = Obj(type); | ||||
| 		tmpl.subid = subtype; | ||||
| 		tmpl.stringID = entry.first; // FIXME: create "fullID" - type.object.template? | ||||
| 		tmpl.readJson(entry.second); | ||||
| 		templates.push_back(tmpl); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const | ||||
| { | ||||
| 	return true; // by default - accept all. | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(ObjectTemplate templ) | ||||
| { | ||||
| 	templ.id = Obj(type); | ||||
| 	templ.subid = subtype; | ||||
| 	templates.push_back(templ); | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(JsonNode config) | ||||
| { | ||||
| 	config.setType(JsonNode::DATA_STRUCT); // ensure that input is not null | ||||
| 	JsonUtils::inherit(config, base); | ||||
| 	ObjectTemplate tmpl; | ||||
| 	tmpl.id = Obj(type); | ||||
| 	tmpl.subid = subtype; | ||||
| 	tmpl.stringID = ""; // TODO? | ||||
| 	tmpl.readJson(config); | ||||
| 	addTemplate(tmpl); | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const | ||||
| { | ||||
| 	return templates; | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) const// FIXME: replace with ETerrainType | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(); | ||||
| 	std::vector<ObjectTemplate> filtered; | ||||
|  | ||||
| 	std::copy_if(ret.begin(), ret.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) | ||||
| 	{ | ||||
| 		return obj.canBePlacedAt(ETerrainType(terrainType)); | ||||
| 	}); | ||||
| 	// it is possible that there are no templates usable on specific terrain. In this case - return list before filtering | ||||
| 	return filtered.empty() ? ret : filtered; | ||||
| } | ||||
|  | ||||
| boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(terrainType); | ||||
| 	for (auto & tmpl : ret) | ||||
| 	{ | ||||
| 		if (objectFilter(object, tmpl)) | ||||
| 			return tmpl; | ||||
| 	} | ||||
| 	return boost::optional<ObjectTemplate>(); | ||||
| } | ||||
|   | ||||
| @@ -1,174 +1,174 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "ObjectTemplate.h" | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "../ConstTransitivePtr.h" | ||||
| #include "../IHandlerBase.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectClassesHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class JsonNode; | ||||
| class CRandomGenerator; | ||||
|  | ||||
| class IObjectInfo | ||||
| { | ||||
| public: | ||||
| 	virtual bool givesResources() const = 0; | ||||
|  | ||||
| 	virtual bool givesExperience() const = 0; | ||||
| 	virtual bool givesMana() const = 0; | ||||
| 	virtual bool givesMovement() const = 0; | ||||
|  | ||||
| 	virtual bool givesPrimarySkills() const = 0; | ||||
| 	virtual bool givesSecondarySkills() const = 0; | ||||
|  | ||||
| 	virtual bool givesArtifacts() const = 0; | ||||
| 	virtual bool givesCreatures() const = 0; | ||||
| 	virtual bool givesSpells() const = 0; | ||||
|  | ||||
| 	virtual bool givesBonuses() const = 0; | ||||
| }; | ||||
|  | ||||
| class CGObjectInstance; | ||||
|  | ||||
| class AObjectTypeHandler | ||||
| { | ||||
| 	si32 type; | ||||
| 	si32 subtype; | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| protected: | ||||
|  | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| public: | ||||
| 	virtual ~AObjectTypeHandler(){} | ||||
|  | ||||
| 	void setType(si32 type, si32 subtype); | ||||
|  | ||||
| 	/// loads templates from Json structure using fields "base" and "templates" | ||||
| 	virtual void init(const JsonNode & input); | ||||
|  | ||||
| 	void addTemplate(ObjectTemplate templ); | ||||
| 	void addTemplate(JsonNode config); | ||||
|  | ||||
| 	/// returns all templates, without any filters | ||||
| 	std::vector<ObjectTemplate> getTemplates() const; | ||||
|  | ||||
| 	/// returns all templates that can be placed on specific terrain type | ||||
| 	std::vector<ObjectTemplate> getTemplates(si32 terrainType) 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) | ||||
| 	boost::optional<ObjectTemplate> getOverride(si32 terrainType, const CGObjectInstance * object) const; | ||||
|  | ||||
| 	/// Creates object and set up core properties (like ID/subID). Object is NOT initialized | ||||
| 	/// to allow creating objects before game start (e.g. map loading) | ||||
| 	virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; | ||||
|  | ||||
| 	/// Returns object configuration, if available. Othervice returns NULL | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & type & subtype & templates; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /// Class that is used for objects that do not have dedicated handler | ||||
| template<class ObjectType> | ||||
| class CDefaultObjectTypeHandler : public AObjectTypeHandler | ||||
| { | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		auto obj = new ObjectType(); | ||||
| 		obj->ID = tmpl.id; | ||||
| 		obj->subID = tmpl.subid; | ||||
| 		obj->appearance = tmpl; | ||||
| 		return obj; | ||||
| 	} | ||||
|  | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| typedef std::shared_ptr<AObjectTypeHandler> TObjectTypeHandler; | ||||
|  | ||||
| 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) | ||||
| 	struct ObjectContainter | ||||
| 	{ | ||||
| 		si32 id; | ||||
|  | ||||
| 		std::string name; // human-readable name | ||||
| 		std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map | ||||
|  | ||||
| 		JsonNode base; | ||||
| 		std::map<si32, TObjectTypeHandler> objects; | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & base & objects; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer; | ||||
|  | ||||
| 	/// list of object handlers, each of them handles only one type | ||||
| 	std::map<si32, ObjectContainter * > objects; | ||||
|  | ||||
| 	/// map that is filled during contruction with all known handlers. Not serializeable | ||||
| 	std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors; | ||||
|  | ||||
| 	/// container with H3 templates, used only during loading | ||||
| 	TTemplatesContainer legacyTemplates; | ||||
|  | ||||
| 	void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); | ||||
| 	ObjectContainter * loadFromJson(const JsonNode & json); | ||||
| public: | ||||
| 	CObjectClassesHandler(); | ||||
|  | ||||
| 	std::vector<JsonNode> loadLegacyData(size_t dataSize) override; | ||||
|  | ||||
| 	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 createObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>()); | ||||
| 	void eraseObject(si32 ID, si32 subID); | ||||
|  | ||||
| 	void beforeValidate(JsonNode & object) override; | ||||
| 	void afterLoadFinalization() override; | ||||
|  | ||||
| 	std::vector<bool> getDefaultAllowed() const override; | ||||
|  | ||||
| 	/// returns handler for specified object (ID-based). ObjectHandler keeps ownership | ||||
| 	TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; | ||||
|  | ||||
| 	std::string getObjectName(si32 type) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & objects; | ||||
| 	} | ||||
| }; | ||||
| #pragma once | ||||
|  | ||||
| #include "ObjectTemplate.h" | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "../ConstTransitivePtr.h" | ||||
| #include "../IHandlerBase.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectClassesHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class JsonNode; | ||||
| class CRandomGenerator; | ||||
|  | ||||
| class IObjectInfo | ||||
| { | ||||
| public: | ||||
| 	virtual bool givesResources() const = 0; | ||||
|  | ||||
| 	virtual bool givesExperience() const = 0; | ||||
| 	virtual bool givesMana() const = 0; | ||||
| 	virtual bool givesMovement() const = 0; | ||||
|  | ||||
| 	virtual bool givesPrimarySkills() const = 0; | ||||
| 	virtual bool givesSecondarySkills() const = 0; | ||||
|  | ||||
| 	virtual bool givesArtifacts() const = 0; | ||||
| 	virtual bool givesCreatures() const = 0; | ||||
| 	virtual bool givesSpells() const = 0; | ||||
|  | ||||
| 	virtual bool givesBonuses() const = 0; | ||||
| }; | ||||
|  | ||||
| class CGObjectInstance; | ||||
|  | ||||
| class AObjectTypeHandler | ||||
| { | ||||
| 	si32 type; | ||||
| 	si32 subtype; | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| protected: | ||||
|  | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| public: | ||||
| 	virtual ~AObjectTypeHandler(){} | ||||
|  | ||||
| 	void setType(si32 type, si32 subtype); | ||||
|  | ||||
| 	/// loads templates from Json structure using fields "base" and "templates" | ||||
| 	virtual void init(const JsonNode & input); | ||||
|  | ||||
| 	void addTemplate(ObjectTemplate templ); | ||||
| 	void addTemplate(JsonNode config); | ||||
|  | ||||
| 	/// returns all templates, without any filters | ||||
| 	std::vector<ObjectTemplate> getTemplates() const; | ||||
|  | ||||
| 	/// returns all templates that can be placed on specific terrain type | ||||
| 	std::vector<ObjectTemplate> getTemplates(si32 terrainType) 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) | ||||
| 	boost::optional<ObjectTemplate> getOverride(si32 terrainType, const CGObjectInstance * object) const; | ||||
|  | ||||
| 	/// Creates object and set up core properties (like ID/subID). Object is NOT initialized | ||||
| 	/// to allow creating objects before game start (e.g. map loading) | ||||
| 	virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; | ||||
|  | ||||
| 	/// Returns object configuration, if available. Othervice returns NULL | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & type & subtype & templates; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| /// Class that is used for objects that do not have dedicated handler | ||||
| template<class ObjectType> | ||||
| class CDefaultObjectTypeHandler : public AObjectTypeHandler | ||||
| { | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		auto obj = new ObjectType(); | ||||
| 		obj->ID = tmpl.id; | ||||
| 		obj->subID = tmpl.subid; | ||||
| 		obj->appearance = tmpl; | ||||
| 		return obj; | ||||
| 	} | ||||
|  | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| typedef std::shared_ptr<AObjectTypeHandler> TObjectTypeHandler; | ||||
|  | ||||
| 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) | ||||
| 	struct ObjectContainter | ||||
| 	{ | ||||
| 		si32 id; | ||||
|  | ||||
| 		std::string name; // human-readable name | ||||
| 		std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map | ||||
|  | ||||
| 		JsonNode base; | ||||
| 		std::map<si32, TObjectTypeHandler> objects; | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & base & objects; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer; | ||||
|  | ||||
| 	/// list of object handlers, each of them handles only one type | ||||
| 	std::map<si32, ObjectContainter * > objects; | ||||
|  | ||||
| 	/// map that is filled during contruction with all known handlers. Not serializeable | ||||
| 	std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors; | ||||
|  | ||||
| 	/// container with H3 templates, used only during loading | ||||
| 	TTemplatesContainer legacyTemplates; | ||||
|  | ||||
| 	void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); | ||||
| 	ObjectContainter * loadFromJson(const JsonNode & json); | ||||
| public: | ||||
| 	CObjectClassesHandler(); | ||||
|  | ||||
| 	std::vector<JsonNode> loadLegacyData(size_t dataSize) override; | ||||
|  | ||||
| 	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 createObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>()); | ||||
| 	void eraseObject(si32 ID, si32 subID); | ||||
|  | ||||
| 	void beforeValidate(JsonNode & object) override; | ||||
| 	void afterLoadFinalization() override; | ||||
|  | ||||
| 	std::vector<bool> getDefaultAllowed() const override; | ||||
|  | ||||
| 	/// returns handler for specified object (ID-based). ObjectHandler keeps ownership | ||||
| 	TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; | ||||
|  | ||||
| 	std::string getObjectName(si32 type) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & objects; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,204 +1,204 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "ObjectTemplate.h" | ||||
|  | ||||
| #include "../IGameCallback.h" | ||||
| #include "../int3.h" | ||||
| #include "../HeroBonus.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class CGHeroInstance; | ||||
| struct BattleResult; | ||||
|  | ||||
| class DLL_LINKAGE IObjectInterface | ||||
| { | ||||
| public: | ||||
| 	static IGameCallback *cb; | ||||
|  | ||||
| 	IObjectInterface(); | ||||
| 	virtual ~IObjectInterface(); | ||||
|  | ||||
| 	virtual void onHeroVisit(const CGHeroInstance * h) const; | ||||
| 	virtual void onHeroLeave(const CGHeroInstance * h) const; | ||||
| 	virtual void newTurn() const; | ||||
| 	virtual void initObj(); //synchr | ||||
| 	virtual void setProperty(ui8 what, ui32 val);//synchr | ||||
| 	 | ||||
| 	//Called when queries created DURING HERO VISIT are resolved | ||||
| 	//First parameter is always hero that visited object and triggered the query | ||||
| 	virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const; | ||||
| 	virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const; | ||||
| 	virtual void garrisonDialogClosed(const CGHeroInstance *hero) const; | ||||
| 	virtual void heroLevelUpDone(const CGHeroInstance *hero) const; | ||||
|  | ||||
| //unified interface, AI helpers | ||||
| 	virtual bool wasVisited (PlayerColor player) const; | ||||
| 	virtual bool wasVisited (const CGHeroInstance * h) const; | ||||
|  | ||||
| 	static void preInit(); //called before objs receive their initObj | ||||
| 	static void postInit();//called after objs receive their initObj | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!"; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	const CGObjectInstance *o; | ||||
|  | ||||
| 	IBoatGenerator(const CGObjectInstance *O); | ||||
| 	virtual ~IBoatGenerator() {} | ||||
|  | ||||
| 	virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral | ||||
| 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed | ||||
| 	int3 bestLocation() const; //returns location when the boat should be placed | ||||
|  | ||||
| 	enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; | ||||
| 	EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water | ||||
| 	void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & o; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE IShipyard : public IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	IShipyard(const CGObjectInstance *O); | ||||
| 	virtual ~IShipyard() {} | ||||
|  | ||||
| 	virtual void getBoatCost(std::vector<si32> &cost) const; | ||||
|  | ||||
| 	static const IShipyard *castFrom(const CGObjectInstance *obj); | ||||
| 	static IShipyard *castFrom(CGObjectInstance *obj); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<IBoatGenerator&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGObjectInstance : public IObjectInterface | ||||
| { | ||||
| public: | ||||
| 	mutable std::string hoverName; | ||||
| 	int3 pos; //h3m pos | ||||
| 	Obj ID; | ||||
| 	si32 subID; //normal subID (this one from OH3 maps ;]) | ||||
| 	ObjectInstanceID id;//number of object in map's vector | ||||
| 	ObjectTemplate appearance; | ||||
|  | ||||
| 	PlayerColor tempOwner; | ||||
| 	bool blockVisit; //if non-zero then blocks the tile but is visitable from neighbouring tile | ||||
|  | ||||
| 	virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used | ||||
| 	virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated | ||||
| 	virtual int getSightRadious() const; //sight distance (should be used if player-owned structure) | ||||
| 	bool passableFor(PlayerColor color) const; | ||||
| 	void getSightTiles(std::unordered_set<int3, ShashInt3> &tiles) const; //returns reference to the set | ||||
| 	PlayerColor getOwner() const; | ||||
| 	void setOwner(PlayerColor ow); | ||||
| 	int getWidth() const; //returns width of object graphic in tiles | ||||
| 	int getHeight() const; //returns height of object graphic in tiles | ||||
| 	virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) | ||||
| 	virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos) | ||||
| 	int3 visitablePos() const; | ||||
| 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos) | ||||
| 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) | ||||
| 	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object | ||||
| 	std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object | ||||
| 	bool isVisitable() const; //returns true if object is visitable | ||||
| 	bool operator<(const CGObjectInstance & cmp) const;  //screen printing priority comparing | ||||
| 	void hideTiles(PlayerColor ourplayer, int radius) const; | ||||
| 	CGObjectInstance(); | ||||
| 	virtual ~CGObjectInstance(); | ||||
| 	//CGObjectInstance(const CGObjectInstance & right); | ||||
| 	//CGObjectInstance& operator=(const CGObjectInstance & right); | ||||
| 	virtual const std::string & getHoverText() const; | ||||
|  | ||||
| 	void setType(si32 ID, si32 subID); | ||||
|  | ||||
| 	///IObjectInterface | ||||
| 	void initObj() override; | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| 	void setProperty(ui8 what, ui32 val) override;//synchr | ||||
|  | ||||
| 	friend class CGameHandler; | ||||
|  | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance; | ||||
| 		//definfo is handled by map serializer | ||||
| 	} | ||||
| protected: | ||||
| 	virtual void setPropertyDer(ui8 what, ui32 val);//synchr | ||||
|  | ||||
| 	void getNameVis(std::string &hname) const; | ||||
| 	void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; | ||||
| }; | ||||
|  | ||||
| /// function object which can be used to find an object with an specific sub ID | ||||
| class CGObjectInstanceBySubIdFinder | ||||
| { | ||||
| public: | ||||
| 	CGObjectInstanceBySubIdFinder(CGObjectInstance * obj); | ||||
| 	bool operator()(CGObjectInstance * obj) const; | ||||
|  | ||||
| private: | ||||
| 	CGObjectInstance * obj; | ||||
| }; | ||||
|  | ||||
| struct BankConfig | ||||
| { | ||||
| 	BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; | ||||
| 	ui8 level; //1 - 4, how hard the battle will be | ||||
| 	ui8 chance; //chance for this level being chosen | ||||
| 	ui8 upgradeChance; //chance for creatures to be in upgraded versions | ||||
| 	std::vector< std::pair <CreatureID, ui32> > guards; //creature ID, amount | ||||
| 	ui32 combatValue; //how hard are guards of this level | ||||
| 	Res::ResourceSet resources; //resources given in case of victory | ||||
| 	std::vector< std::pair <CreatureID, ui32> > creatures; //creatures granted in case of victory (creature ID, amount) | ||||
| 	std::vector<ui16> artifacts; //number of artifacts given in case of victory [0] -> treasure, [1] -> minor [2] -> major [3] -> relic | ||||
| 	ui32 value; //overall value of given things | ||||
| 	ui32 rewardDifficulty; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config | ||||
| 	ui16 easiest; //?!? | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & level & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & rewardDifficulty & easiest; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CObjectHandler | ||||
| { | ||||
| public: | ||||
| 	std::map<si32, CreatureID> cregens; //type 17. dwelling subid -> creature ID | ||||
| 	std::map <ui32, std::vector < ConstTransitivePtr<BankConfig> > > banksInfo; //[index][preset] | ||||
| 	std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank | ||||
| 	std::vector<ui32> resVals; //default values of resources in gold | ||||
|  | ||||
| 	CObjectHandler(); | ||||
| 	~CObjectHandler(); | ||||
|  | ||||
| 	int bankObjToIndex (const CGObjectInstance * obj); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & cregens & banksInfo & creBanksNames & resVals; | ||||
| 	} | ||||
| }; | ||||
| #pragma once | ||||
|  | ||||
| #include "ObjectTemplate.h" | ||||
|  | ||||
| #include "../IGameCallback.h" | ||||
| #include "../int3.h" | ||||
| #include "../HeroBonus.h" | ||||
|  | ||||
| /* | ||||
|  * CObjectHandler.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 | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| class CGHeroInstance; | ||||
| struct BattleResult; | ||||
|  | ||||
| class DLL_LINKAGE IObjectInterface | ||||
| { | ||||
| public: | ||||
| 	static IGameCallback *cb; | ||||
|  | ||||
| 	IObjectInterface(); | ||||
| 	virtual ~IObjectInterface(); | ||||
|  | ||||
| 	virtual void onHeroVisit(const CGHeroInstance * h) const; | ||||
| 	virtual void onHeroLeave(const CGHeroInstance * h) const; | ||||
| 	virtual void newTurn() const; | ||||
| 	virtual void initObj(); //synchr | ||||
| 	virtual void setProperty(ui8 what, ui32 val);//synchr | ||||
| 	 | ||||
| 	//Called when queries created DURING HERO VISIT are resolved | ||||
| 	//First parameter is always hero that visited object and triggered the query | ||||
| 	virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const; | ||||
| 	virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const; | ||||
| 	virtual void garrisonDialogClosed(const CGHeroInstance *hero) const; | ||||
| 	virtual void heroLevelUpDone(const CGHeroInstance *hero) const; | ||||
|  | ||||
| //unified interface, AI helpers | ||||
| 	virtual bool wasVisited (PlayerColor player) const; | ||||
| 	virtual bool wasVisited (const CGHeroInstance * h) const; | ||||
|  | ||||
| 	static void preInit(); //called before objs receive their initObj | ||||
| 	static void postInit();//called after objs receive their initObj | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "IObjectInterface serialized, unexpected, should not happen!"; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	const CGObjectInstance *o; | ||||
|  | ||||
| 	IBoatGenerator(const CGObjectInstance *O); | ||||
| 	virtual ~IBoatGenerator() {} | ||||
|  | ||||
| 	virtual int getBoatType() const; //0 - evil (if a ship can be evil...?), 1 - good, 2 - neutral | ||||
| 	virtual void getOutOffsets(std::vector<int3> &offsets) const =0; //offsets to obj pos when we boat can be placed | ||||
| 	int3 bestLocation() const; //returns location when the boat should be placed | ||||
|  | ||||
| 	enum EGeneratorState {GOOD, BOAT_ALREADY_BUILT, TILE_BLOCKED, NO_WATER}; | ||||
| 	EGeneratorState shipyardStatus() const; //0 - can buid, 1 - there is already a boat at dest tile, 2 - dest tile is blocked, 3 - no water | ||||
| 	void getProblemText(MetaString &out, const CGHeroInstance *visitor = nullptr) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & o; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE IShipyard : public IBoatGenerator | ||||
| { | ||||
| public: | ||||
| 	IShipyard(const CGObjectInstance *O); | ||||
| 	virtual ~IShipyard() {} | ||||
|  | ||||
| 	virtual void getBoatCost(std::vector<si32> &cost) const; | ||||
|  | ||||
| 	static const IShipyard *castFrom(const CGObjectInstance *obj); | ||||
| 	static IShipyard *castFrom(CGObjectInstance *obj); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<IBoatGenerator&>(*this); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CGObjectInstance : public IObjectInterface | ||||
| { | ||||
| public: | ||||
| 	mutable std::string hoverName; | ||||
| 	int3 pos; //h3m pos | ||||
| 	Obj ID; | ||||
| 	si32 subID; //normal subID (this one from OH3 maps ;]) | ||||
| 	ObjectInstanceID id;//number of object in map's vector | ||||
| 	ObjectTemplate appearance; | ||||
|  | ||||
| 	PlayerColor tempOwner; | ||||
| 	bool blockVisit; //if non-zero then blocks the tile but is visitable from neighbouring tile | ||||
|  | ||||
| 	virtual ui8 getPassableness() const; //bitmap - if the bit is set the corresponding player can pass through the visitable tiles of object, even if it's blockvis; if not set - default properties from definfo are used | ||||
| 	virtual int3 getSightCenter() const; //"center" tile from which the sight distance is calculated | ||||
| 	virtual int getSightRadious() const; //sight distance (should be used if player-owned structure) | ||||
| 	bool passableFor(PlayerColor color) const; | ||||
| 	void getSightTiles(std::unordered_set<int3, ShashInt3> &tiles) const; //returns reference to the set | ||||
| 	PlayerColor getOwner() const; | ||||
| 	void setOwner(PlayerColor ow); | ||||
| 	int getWidth() const; //returns width of object graphic in tiles | ||||
| 	int getHeight() const; //returns height of object graphic in tiles | ||||
| 	virtual bool visitableAt(int x, int y) const; //returns true if object is visitable at location (x, y) (h3m pos) | ||||
| 	virtual int3 getVisitableOffset() const; //returns (x,y,0) offset to first visitable tile from bottom right obj tile (0,0,0) (h3m pos) | ||||
| 	int3 visitablePos() const; | ||||
| 	bool blockingAt(int x, int y) const; //returns true if object is blocking location (x, y) (h3m pos) | ||||
| 	bool coveringAt(int x, int y) const; //returns true if object covers with picture location (x, y) (h3m pos) | ||||
| 	std::set<int3> getBlockedPos() const; //returns set of positions blocked by this object | ||||
| 	std::set<int3> getBlockedOffsets() const; //returns set of relative positions blocked by this object | ||||
| 	bool isVisitable() const; //returns true if object is visitable | ||||
| 	bool operator<(const CGObjectInstance & cmp) const;  //screen printing priority comparing | ||||
| 	void hideTiles(PlayerColor ourplayer, int radius) const; | ||||
| 	CGObjectInstance(); | ||||
| 	virtual ~CGObjectInstance(); | ||||
| 	//CGObjectInstance(const CGObjectInstance & right); | ||||
| 	//CGObjectInstance& operator=(const CGObjectInstance & right); | ||||
| 	virtual const std::string & getHoverText() const; | ||||
|  | ||||
| 	void setType(si32 ID, si32 subID); | ||||
|  | ||||
| 	///IObjectInterface | ||||
| 	void initObj() override; | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| 	void setProperty(ui8 what, ui32 val) override;//synchr | ||||
|  | ||||
| 	friend class CGameHandler; | ||||
|  | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & hoverName & pos & ID & subID & id & tempOwner & blockVisit & appearance; | ||||
| 		//definfo is handled by map serializer | ||||
| 	} | ||||
| protected: | ||||
| 	virtual void setPropertyDer(ui8 what, ui32 val);//synchr | ||||
|  | ||||
| 	void getNameVis(std::string &hname) const; | ||||
| 	void giveDummyBonus(ObjectInstanceID heroID, ui8 duration = Bonus::ONE_DAY) const; | ||||
| }; | ||||
|  | ||||
| /// function object which can be used to find an object with an specific sub ID | ||||
| class CGObjectInstanceBySubIdFinder | ||||
| { | ||||
| public: | ||||
| 	CGObjectInstanceBySubIdFinder(CGObjectInstance * obj); | ||||
| 	bool operator()(CGObjectInstance * obj) const; | ||||
|  | ||||
| private: | ||||
| 	CGObjectInstance * obj; | ||||
| }; | ||||
|  | ||||
| struct BankConfig | ||||
| { | ||||
| 	BankConfig() {level = chance = upgradeChance = combatValue = value = rewardDifficulty = easiest = 0; }; | ||||
| 	ui8 level; //1 - 4, how hard the battle will be | ||||
| 	ui8 chance; //chance for this level being chosen | ||||
| 	ui8 upgradeChance; //chance for creatures to be in upgraded versions | ||||
| 	std::vector< std::pair <CreatureID, ui32> > guards; //creature ID, amount | ||||
| 	ui32 combatValue; //how hard are guards of this level | ||||
| 	Res::ResourceSet resources; //resources given in case of victory | ||||
| 	std::vector< std::pair <CreatureID, ui32> > creatures; //creatures granted in case of victory (creature ID, amount) | ||||
| 	std::vector<ui16> artifacts; //number of artifacts given in case of victory [0] -> treasure, [1] -> minor [2] -> major [3] -> relic | ||||
| 	ui32 value; //overall value of given things | ||||
| 	ui32 rewardDifficulty; //proportion of reward value to difficulty of guards; how profitable is this creature Bank config | ||||
| 	ui16 easiest; //?!? | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & level & chance & upgradeChance & guards & combatValue & resources & creatures & artifacts & value & rewardDifficulty & easiest; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CObjectHandler | ||||
| { | ||||
| public: | ||||
| 	std::map<si32, CreatureID> cregens; //type 17. dwelling subid -> creature ID | ||||
| 	std::map <ui32, std::vector < ConstTransitivePtr<BankConfig> > > banksInfo; //[index][preset] | ||||
| 	std::map <ui32, std::string> creBanksNames; //[crebank index] -> name of this creature bank | ||||
| 	std::vector<ui32> resVals; //default values of resources in gold | ||||
|  | ||||
| 	CObjectHandler(); | ||||
| 	~CObjectHandler(); | ||||
|  | ||||
| 	int bankObjToIndex (const CGObjectInstance * obj); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & cregens & banksInfo & creBanksNames & resVals; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user