mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Implemented (basic) object construction and placement
* contain refactoring of RMG and class handling (will be more)
This commit is contained in:
		| @@ -207,6 +207,28 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode | ||||
|  | ||||
| 	artifacts.push_back(object); | ||||
|  | ||||
| 	VLC->modh->identifiers.requestIdentifier(scope, "object", "artifact", [=](si32 index) | ||||
| 	{ | ||||
| 		JsonNode conf; | ||||
| 		conf.setMeta(scope); | ||||
|  | ||||
| 		VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::ARTIFACT, object->id.num); | ||||
|  | ||||
| 		if (!object->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ.setMeta(scope); | ||||
| 			templ["animation"].String() = object->advMapDef; | ||||
|  | ||||
| 			// add new template. | ||||
| 			// Necessary for objects added via mods that don't have any templates in H3 | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->addTemplate(templ); | ||||
| 		} | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-art like lock) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id); | ||||
| 	}); | ||||
|  | ||||
| 	registerObject(scope, "artifact", object->identifier, object->id); | ||||
| } | ||||
|  | ||||
| @@ -219,6 +241,27 @@ void CArtHandler::loadObject(std::string scope, std::string name, const JsonNode | ||||
| 	assert(artifacts[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	artifacts[index] = object; | ||||
|  | ||||
| 	VLC->modh->identifiers.requestIdentifier(scope, "object", "artifact", [=](si32 index) | ||||
| 	{ | ||||
| 		JsonNode conf; | ||||
| 		conf.setMeta(scope); | ||||
|  | ||||
| 		VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::ARTIFACT, object->id.num); | ||||
|  | ||||
| 		if (!object->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ.setMeta(scope); | ||||
| 			templ["animation"].String() = object->advMapDef; | ||||
|  | ||||
| 			// add new template. | ||||
| 			// Necessary for objects added via mods that don't have any templates in H3 | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->addTemplate(templ); | ||||
| 		} | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-art like lock) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, object->id)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::ARTIFACT, object->id); | ||||
| 	}); | ||||
| 	registerObject(scope, "artifact", object->identifier, object->id); | ||||
| } | ||||
|  | ||||
| @@ -280,16 +323,16 @@ ArtifactPosition CArtHandler::stringToSlot(std::string slotName) | ||||
|  | ||||
| void CArtHandler::addSlot(CArtifact * art, const std::string & slotID) | ||||
| { | ||||
| 	static const std::vector<ArtifactPosition> miscSlots =  | ||||
| 	static const std::vector<ArtifactPosition> miscSlots = | ||||
| 	{ | ||||
| 		ArtifactPosition::MISC1, ArtifactPosition::MISC2, ArtifactPosition::MISC3, ArtifactPosition::MISC4, ArtifactPosition::MISC5 | ||||
| 	}; | ||||
| 	 | ||||
|  | ||||
| 	static const std::vector<ArtifactPosition> ringSlots = | ||||
| 	{ | ||||
| 		ArtifactPosition::LEFT_RING, ArtifactPosition::RIGHT_RING | ||||
| 	}; | ||||
| 	 | ||||
|  | ||||
| 	if (slotID == "MISC") | ||||
| 	{ | ||||
| 		vstd::concatenate(art->possibleSlots[ArtBearer::HERO], miscSlots); | ||||
| @@ -323,7 +366,7 @@ void CArtHandler::loadSlots(CArtifact * art, const JsonNode & node) | ||||
| CArtifact::EartClass CArtHandler::stringToClass(std::string className) | ||||
| { | ||||
| 	static const std::map<std::string, CArtifact::EartClass> artifactClassMap = | ||||
| 	{	 | ||||
| 	{ | ||||
| 		{"TREASURE", CArtifact::ART_TREASURE}, | ||||
| 		{"MINOR", CArtifact::ART_MINOR}, | ||||
| 		{"MAJOR", CArtifact::ART_MAJOR}, | ||||
| @@ -694,24 +737,6 @@ void CArtHandler::afterLoadFinalization() | ||||
| 			bonus->sid = art->id; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for (CArtifact * art : artifacts) | ||||
| 	{ | ||||
| 		VLC->objtypeh->loadSubObject(art->Name(), JsonNode(), Obj::ARTIFACT, art->id.num); | ||||
|  | ||||
| 		if (!art->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ["animation"].String() = art->advMapDef; | ||||
|  | ||||
| 			// add new template. | ||||
| 			// Necessary for objects added via mods that don't have any templates in H3 | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->addTemplate(templ); | ||||
| 		} | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-art like lock) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::ARTIFACT, art->id)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::ARTIFACT, art->id); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| CArtifactInstance::CArtifactInstance() | ||||
|   | ||||
| @@ -166,12 +166,12 @@ static void AddAbility(CCreature *cre, const JsonVector &ability_vec) | ||||
| 	} | ||||
|  | ||||
| 	nsf->type = it->second; | ||||
| 	 | ||||
|  | ||||
| 	JsonUtils::parseTypedBonusShort(ability_vec,nsf); | ||||
|  | ||||
| 	nsf->source = Bonus::CREATURE_ABILITY; | ||||
| 	nsf->sid = cre->idNumber; | ||||
| 	 | ||||
|  | ||||
| 	cre->addNewBonus(nsf); | ||||
| } | ||||
|  | ||||
| @@ -363,6 +363,24 @@ void CCreatureHandler::loadObject(std::string scope, std::string name, const Jso | ||||
|  | ||||
| 	creatures.push_back(object); | ||||
|  | ||||
| 	VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index) | ||||
| 	{ | ||||
| 		JsonNode conf; | ||||
| 		conf.setMeta(scope); | ||||
|  | ||||
| 		VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::MONSTER, object->idNumber.num); | ||||
| 		if (!object->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ["animation"].String() = object->advMapDef; | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->addTemplate(templ); | ||||
| 		} | ||||
|  | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::MONSTER, object->idNumber.num); | ||||
| 	}); | ||||
|  | ||||
| 	registerObject(scope, "creature", name, object->idNumber); | ||||
|  | ||||
| 	for(auto node : data["extraNames"].Vector()) | ||||
| @@ -385,6 +403,24 @@ void CCreatureHandler::loadObject(std::string scope, std::string name, const Jso | ||||
| 	assert(creatures[index] == nullptr); // ensure that this id was not loaded before | ||||
| 	creatures[index] = object; | ||||
|  | ||||
| 	VLC->modh->identifiers.requestIdentifier(scope, "object", "monster", [=](si32 index) | ||||
| 	{ | ||||
| 		JsonNode conf; | ||||
| 		conf.setMeta(scope); | ||||
|  | ||||
| 		VLC->objtypeh->loadSubObject(object->identifier, conf, Obj::MONSTER, object->idNumber.num); | ||||
| 		if (!object->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ["animation"].String() = object->advMapDef; | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->addTemplate(templ); | ||||
| 		} | ||||
|  | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, object->idNumber.num)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::MONSTER, object->idNumber.num); | ||||
| 	}); | ||||
|  | ||||
| 	registerObject(scope, "creature", name, object->idNumber); | ||||
| 	for(auto & node : data["extraNames"].Vector()) | ||||
| 	{ | ||||
| @@ -1124,20 +1160,7 @@ void CCreatureHandler::buildBonusTreeForTiers() | ||||
|  | ||||
| void CCreatureHandler::afterLoadFinalization() | ||||
| { | ||||
| 	for (CCreature * crea : creatures) | ||||
| 	{ | ||||
| 		VLC->objtypeh->loadSubObject(crea->nameSing, JsonNode(), Obj::MONSTER, crea->idNumber.num); | ||||
| 		if (!crea->advMapDef.empty()) | ||||
| 		{ | ||||
| 			JsonNode templ; | ||||
| 			templ["animation"].String() = crea->advMapDef; | ||||
| 			VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber)->addTemplate(templ); | ||||
| 		} | ||||
|  | ||||
| 		// object does not have any templates - this is not usable object (e.g. pseudo-creature like Arrow Tower) | ||||
| 		if (VLC->objtypeh->getHandlerFor(Obj::MONSTER, crea->idNumber.num)->getTemplates().empty()) | ||||
| 			VLC->objtypeh->removeSubObject(Obj::MONSTER, crea->idNumber.num); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CCreatureHandler::deserializationFix() | ||||
|   | ||||
| @@ -205,6 +205,13 @@ void CHeroClassHandler::loadObject(std::string scope, std::string name, const Js | ||||
| 		VLC->objtypeh->loadSubObject(name, classConf, index, object->id); | ||||
| 	}); | ||||
|  | ||||
| //	VLC->modh->identifiers.requestIdentifier(scope, "object", "prison", [=](si32 index) | ||||
| //	{ | ||||
| //		JsonNode conf; | ||||
| //		conf.setMeta(scope); | ||||
| //		VLC->objtypeh->loadSubObject(name, conf, index, object->id); | ||||
| //	}); | ||||
|  | ||||
| 	VLC->modh->identifiers.registerObject(scope, "heroClass", name, object->id); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -101,9 +101,9 @@ void CIdentifierStorage::requestIdentifier(std::string scope, std::string type, | ||||
|  | ||||
| void CIdentifierStorage::requestIdentifier(std::string scope, std::string fullName, const std::function<void(si32)>& callback) | ||||
| { | ||||
| 	auto scopeAndFullName = splitString(fullName, ':');	 | ||||
| 	auto typeAndName = splitString(scopeAndFullName.second, '.');	 | ||||
| 	 | ||||
| 	auto scopeAndFullName = splitString(fullName, ':'); | ||||
| 	auto typeAndName = splitString(scopeAndFullName.second, '.'); | ||||
|  | ||||
| 	requestIdentifier(ObjectCallback(scope, scopeAndFullName.first, typeAndName.first, typeAndName.second, callback, false)); | ||||
| } | ||||
|  | ||||
| @@ -186,6 +186,7 @@ void CIdentifierStorage::registerObject(std::string scope, std::string type, std | ||||
| 	checkIdentifier(fullID); | ||||
|  | ||||
| 	registeredObjects.insert(std::make_pair(fullID, data)); | ||||
| 	logGlobal->traceStream() << scope << "::" << fullID; | ||||
| } | ||||
|  | ||||
| std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdentifiers(const ObjectCallback & request) | ||||
| @@ -331,11 +332,11 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali | ||||
| { | ||||
| 	ModInfo & modInfo = modData[modName]; | ||||
| 	bool result = true; | ||||
| 	 | ||||
|  | ||||
| 	auto performValidate = [&,this](JsonNode & data, const std::string & name){ | ||||
| 		handler->beforeValidate(data); | ||||
| 		if (validate) | ||||
| 			result &= JsonUtils::validate(data, "vcmi:" + objectName, name);	 | ||||
| 			result &= JsonUtils::validate(data, "vcmi:" + objectName, name); | ||||
| 	}; | ||||
|  | ||||
| 	// apply patches | ||||
| @@ -355,7 +356,7 @@ bool CContentHandler::ContentTypeHandler::loadMod(std::string modName, bool vali | ||||
| 			if (originalData.size() > index) | ||||
| 			{ | ||||
| 				JsonUtils::merge(originalData[index], data); | ||||
| 				 | ||||
|  | ||||
| 				performValidate(originalData[index],name); | ||||
| 				handler->loadObject(modName, name, originalData[index], index); | ||||
|  | ||||
|   | ||||
| @@ -74,7 +74,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER("pandora", CGPandoraBox); | ||||
| 	SET_HANDLER("pickable", CGPickable); | ||||
| 	SET_HANDLER("prison", CGHeroInstance); | ||||
| 	SET_HANDLER("prison", CGHeroInstance); | ||||
| 	SET_HANDLER("questGuard", CGQuestGuard); | ||||
| 	SET_HANDLER("resource", CGResource); | ||||
| 	SET_HANDLER("scholar", CGScholar); | ||||
| @@ -148,17 +147,18 @@ si32 selectNextID(const JsonNode & fixedID, const Map & map, si32 defaultID) | ||||
| 	return defaultID; // some H3M objects loaded, first modded found | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContainter * obj) | ||||
| void CObjectClassesHandler::loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj) | ||||
| { | ||||
| 	if (!handlerConstructors.count(obj->handlerName)) | ||||
| 	{ | ||||
| 		logGlobal->errorStream() << "Handler with name " << obj->handlerName << " was not found!"; | ||||
| 		return; | ||||
| 	} | ||||
| 	si32 id = selectNextID(entry["index"], obj->objects, 1000); | ||||
| 	si32 id = selectNextID(entry["index"], obj->subObjects, 1000); | ||||
|  | ||||
| 	auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 	handler->setType(obj->id, id); | ||||
| 	handler->setTypeName(obj->identifier, identifier); | ||||
|  | ||||
| 	if (customNames.count(obj->id) && customNames.at(obj->id).size() > id) | ||||
| 		handler->init(entry, customNames.at(obj->id).at(id)); | ||||
| @@ -175,50 +175,49 @@ void CObjectClassesHandler::loadObjectEntry(const JsonNode & entry, ObjectContai | ||||
| 		legacyTemplates.erase(range.first, range.second); | ||||
| 	} | ||||
|  | ||||
| 	logGlobal->debugStream() << "Loaded object " << obj->id << ":" << id; | ||||
| 	assert(!obj->objects.count(id)); // DO NOT override | ||||
| 	obj->objects[id] = handler; | ||||
| 	logGlobal->debugStream() << "Loaded object " << obj->identifier << "(" << obj->id << ")" << ":" << identifier << "(" << id << ")" ; | ||||
| 	assert(!obj->subObjects.count(id)); // DO NOT override | ||||
| 	obj->subObjects[id] = handler; | ||||
| 	obj->subIds[identifier] = id;//todo: scope | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json, const std::string & name) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(); | ||||
| 	obj->identifier = name; | ||||
| 	obj->name = json["name"].String(); | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; | ||||
| 	obj->id = selectNextID(json["index"], objects, 256); | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 	{ | ||||
| 		loadObjectEntry(entry.second, obj); | ||||
| 		loadObjectEntry(entry.first, entry.second, obj); | ||||
| 	} | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| 	auto object = loadFromJson(data); | ||||
| 	auto object = loadFromJson(data, name); | ||||
| 	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); | ||||
|  | ||||
| 	auto object = loadFromJson(data, name); | ||||
| 	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::loadSubObject(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID) | ||||
| void CObjectClassesHandler::loadSubObject(const std::string & identifier, 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(objects.at(ID)->subObjects.count(subID.get()) == 0); | ||||
| 		assert(config["index"].isNull()); | ||||
| 		config["index"].Float() = subID.get(); | ||||
| 	} | ||||
| @@ -227,14 +226,14 @@ void CObjectClassesHandler::loadSubObject(std::string name, JsonNode config, si3 | ||||
| 	JsonUtils::inherit(config, objects.at(ID)->base); | ||||
| 	config.setMeta(oldMeta); | ||||
|  | ||||
| 	loadObjectEntry(config, objects[ID]); | ||||
| 	loadObjectEntry(identifier, config, objects[ID]); | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::removeSubObject(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(objects.count(ID)); | ||||
| 	assert(objects.at(ID)->objects.count(subID)); | ||||
| 	objects.at(ID)->objects.erase(subID); | ||||
| 	assert(objects.at(ID)->subObjects.count(subID)); | ||||
| 	objects.at(ID)->subObjects.erase(subID); //TODO: cleanup string id map | ||||
| } | ||||
|  | ||||
| std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
| @@ -246,14 +245,28 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 	{ | ||||
| 		if (objects.at(type)->objects.count(subtype)) | ||||
| 			return objects.at(type)->objects.at(subtype); | ||||
| 		if (objects.at(type)->subObjects.count(subtype)) | ||||
| 			return objects.at(type)->subObjects.at(subtype); | ||||
| 	} | ||||
| 	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; | ||||
| 	assert(0); // FIXME: throw error? | ||||
| 	throw std::runtime_error("Object type handler not found"); | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(std::string type, std::string subtype) const | ||||
| { | ||||
| 	boost::optional<si32> id = VLC->modh->identifiers.getIdentifier("core", "object", type, false); | ||||
| 	if(id) | ||||
| 	{ | ||||
| 		si32 subId = objects.at(id.get())->subIds.at(subtype); | ||||
| 		return objects.at(id.get())->subObjects.at(subId); | ||||
| 	} | ||||
| 	logGlobal->errorStream() << "Failed to find object of type " << type << ":" << subtype; | ||||
| 	throw std::runtime_error("Object type handler not found"); | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
|  | ||||
| std::set<si32> CObjectClassesHandler::knownObjects() const | ||||
| { | ||||
| 	std::set<si32> ret; | ||||
| @@ -270,7 +283,7 @@ std::set<si32> CObjectClassesHandler::knownSubObjects(si32 primaryID) const | ||||
|  | ||||
| 	if (objects.count(primaryID)) | ||||
| 	{ | ||||
| 		for (auto entry : objects.at(primaryID)->objects) | ||||
| 		for (auto entry : objects.at(primaryID)->subObjects) | ||||
| 			ret.insert(entry.first); | ||||
| 	} | ||||
| 	return ret; | ||||
| @@ -292,7 +305,7 @@ void CObjectClassesHandler::afterLoadFinalization() | ||||
| { | ||||
| 	for (auto entry : objects) | ||||
| 	{ | ||||
| 		for (auto obj : entry.second->objects) | ||||
| 		for (auto obj : entry.second->subObjects) | ||||
| 		{ | ||||
| 			obj.second->afterLoadFinalization(); | ||||
| 			if (obj.second->getTemplates().empty()) | ||||
| @@ -331,6 +344,12 @@ void AObjectTypeHandler::setType(si32 type, si32 subtype) | ||||
| 	this->subtype = subtype; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::setTypeName(std::string type, std::string subtype) | ||||
| { | ||||
| 	this->typeName = type; | ||||
| 	this->subTypeName = subtype; | ||||
| } | ||||
|  | ||||
| static ui32 loadJsonOrMax(const JsonNode & input) | ||||
| { | ||||
| 	if (input.isNull()) | ||||
| @@ -377,6 +396,14 @@ bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemp | ||||
| 	return false; // by default there are no overrides | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::preInitObject(CGObjectInstance * obj) const | ||||
| { | ||||
| 	obj->ID = Obj(type); | ||||
| 	obj->subID = subtype; | ||||
| 	obj->typeName = typeName; | ||||
| 	obj->subTypeName = subTypeName; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::initTypeData(const JsonNode & input) | ||||
| { | ||||
| 	// empty implementation for overrides | ||||
|   | ||||
| @@ -104,11 +104,14 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable | ||||
| 	si32 type; | ||||
| 	si32 subtype; | ||||
|  | ||||
| 	std::string typeName; | ||||
| 	std::string subTypeName; | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| protected: | ||||
|  | ||||
| 	void preInitObject(CGObjectInstance * obj) const; | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
|  | ||||
| 	/// initialization for classes that inherit this one | ||||
| @@ -117,6 +120,7 @@ public: | ||||
| 	virtual ~AObjectTypeHandler(){} | ||||
|  | ||||
| 	void setType(si32 type, si32 subtype); | ||||
| 	void setTypeName(std::string type, std::string subtype); | ||||
|  | ||||
| 	/// 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>()); | ||||
| @@ -149,12 +153,16 @@ public: | ||||
| 	/// This should set remaining properties, including randomized or depending on map | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; | ||||
|  | ||||
| 	/// Returns object configuration, if available. Othervice returns NULL | ||||
| 	/// Returns object configuration, if available. Otherwise returns NULL | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & type & subtype & templates & rmgInfo & objectName; | ||||
| 		if(version >= 755) | ||||
| 		{ | ||||
| 			h & typeName & subTypeName; | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -167,16 +175,21 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| 	struct ObjectContainter | ||||
| 	{ | ||||
| 		si32 id; | ||||
|  | ||||
| 		std::string identifier; | ||||
| 		std::string name; // human-readable name | ||||
| 		std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map | ||||
| 		std::string handlerName; // ID of handler that controls this object, should be determined using handlerConstructor map | ||||
|  | ||||
| 		JsonNode base; | ||||
| 		std::map<si32, TObjectTypeHandler> objects; | ||||
| 		std::map<si32, TObjectTypeHandler> subObjects; | ||||
| 		std::map<std::string, si32> subIds;//full id from core scope -> subtype | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & name & handlerName & base & objects; | ||||
| 			h & name & handlerName & base & subObjects; | ||||
| 			if(version >= 755) | ||||
| 			{ | ||||
| 				h & identifier & subIds; | ||||
| 			} | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| @@ -194,8 +207,8 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| 	/// format: customNames[primaryID][secondaryID] -> name | ||||
| 	std::map<si32, std::vector<std::string>> customNames; | ||||
|  | ||||
| 	void loadObjectEntry(const JsonNode & entry, ObjectContainter * obj); | ||||
| 	ObjectContainter * loadFromJson(const JsonNode & json); | ||||
| 	void loadObjectEntry(const std::string & identifier, const JsonNode & entry, ObjectContainter * obj); | ||||
| 	ObjectContainter * loadFromJson(const JsonNode & json, const std::string & name); | ||||
| public: | ||||
| 	CObjectClassesHandler(); | ||||
|  | ||||
| @@ -204,7 +217,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(std::string name, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>()); | ||||
| 	void loadSubObject(const std::string & identifier, JsonNode config, si32 ID, boost::optional<si32> subID = boost::optional<si32>()); | ||||
| 	void removeSubObject(si32 ID, si32 subID); | ||||
|  | ||||
| 	void beforeValidate(JsonNode & object) override; | ||||
| @@ -218,10 +231,11 @@ public: | ||||
|  | ||||
| 	/// returns handler for specified object (ID-based). ObjectHandler keeps ownership | ||||
| 	TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; | ||||
| 	TObjectTypeHandler getHandlerFor(std::string type, std::string subtype) const; | ||||
|  | ||||
| 	std::string getObjectName(si32 type) const; | ||||
| 	std::string getObjectName(si32 type, si32 subtype) const; | ||||
| 	 | ||||
|  | ||||
| 	/// Returns handler string describing the handler (for use in client) | ||||
| 	std::string getObjectHandlerName(si32 type) const; | ||||
|  | ||||
|   | ||||
| @@ -326,7 +326,14 @@ bool CGObjectInstance::passableFor(PlayerColor color) const | ||||
|  | ||||
| void CGObjectInstance::writeJson(JsonNode & json, bool withState) const | ||||
| { | ||||
| 	logGlobal->debugStream() <<"Save: [" << pos << "] " << id << " " << ID << " " << subID << " " << typeName << " " << subTypeName; | ||||
|  | ||||
| 	json.setType(JsonNode::DATA_STRUCT); | ||||
| 	json["type"].String() = typeName; | ||||
| 	json["subType"].String() = subTypeName; | ||||
| 	json["x"].Float() = pos.x; | ||||
| 	json["y"].Float() = pos.y; | ||||
| 	json["l"].Float() = pos.z; | ||||
|  | ||||
| 	appearance.writeJson(json["template"]); | ||||
| 	writeJsonOptions(json["options"]); | ||||
| @@ -341,10 +348,16 @@ void CGObjectInstance::readJson(const JsonNode & json, bool withState) | ||||
| 		logGlobal->error("Invalid object instance data"); | ||||
| 		return; | ||||
| 	} | ||||
| 	pos.x = json["x"].Float(); | ||||
| 	pos.y = json["y"].Float(); | ||||
| 	pos.z = json["l"].Float(); | ||||
|  | ||||
| 	appearance.readJson(json["template"]); | ||||
| 	readJsonOptions(json["options"]); | ||||
| 	if(withState) | ||||
| 		readJsonState(json["state"]); | ||||
|  | ||||
| 	logGlobal->debugStream() <<"Load: [" << pos << "] " << id << " " << ID << " " << subID << " " << typeName << " " << subTypeName; | ||||
| } | ||||
|  | ||||
| void CGObjectInstance::writeJsonOptions(JsonNode & json) const | ||||
|   | ||||
| @@ -113,6 +113,9 @@ public: | ||||
| 	/// If true hero can visit this object only from neighbouring tiles and can't stand on this object | ||||
| 	bool blockVisit; | ||||
|  | ||||
| 	std::string typeName; | ||||
| 	std::string subTypeName; | ||||
|  | ||||
| 	CGObjectInstance(); | ||||
| 	~CGObjectInstance(); | ||||
|  | ||||
| @@ -171,6 +174,11 @@ public: | ||||
| 	{ | ||||
| 		h & pos & ID & subID & id & tempOwner & blockVisit & appearance; | ||||
| 		//definfo is handled by map serializer | ||||
|  | ||||
| 		if(version >= 755) | ||||
| 		{ | ||||
| 			h & typeName & subTypeName; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	///Entry point of Json serialization | ||||
|   | ||||
| @@ -188,6 +188,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config) | ||||
| CGObjectInstance * CRewardableConstructor::create(ObjectTemplate tmpl) const | ||||
| { | ||||
| 	auto ret = new CRewardableObject(); | ||||
| 	preInitObject(ret); | ||||
| 	ret->appearance = tmpl; | ||||
| 	return ret; | ||||
| } | ||||
|   | ||||
| @@ -31,8 +31,7 @@ protected: | ||||
| 	ObjectType * createTyped(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		auto obj = new ObjectType(); | ||||
| 		obj->ID = tmpl.id; | ||||
| 		obj->subID = tmpl.subid; | ||||
| 		preInitObject(obj); | ||||
| 		obj->appearance = tmpl; | ||||
| 		return obj; | ||||
| 	} | ||||
|   | ||||
| @@ -284,6 +284,13 @@ void CMapLoaderJson::readMap() | ||||
| 	map->initTerrain(); | ||||
| 	readTerrain(); | ||||
| 	readObjects(); | ||||
|  | ||||
| 	// Calculate blocked / visitable positions | ||||
| 	for(auto & elem : map->objects) | ||||
| 	{ | ||||
| 		map->addBlockVisTiles(elem); | ||||
| 	} | ||||
| 	map->calculateGuardingGreaturePositions(); | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readHeader() | ||||
| @@ -569,6 +576,7 @@ CMapLoaderJson::MapObjectLoader::MapObjectLoader(CMapLoaderJson * _owner, const | ||||
|  | ||||
| void CMapLoaderJson::MapObjectLoader::construct() | ||||
| { | ||||
| 	//TODO:consider move to ObjectTypeHandler | ||||
| 	//find type handler | ||||
| 	std::string typeName = configuration["type"].String(), subTypeName = configuration["subType"].String(); | ||||
| 	if(typeName.empty()) | ||||
| @@ -584,13 +592,16 @@ void CMapLoaderJson::MapObjectLoader::construct() | ||||
|  | ||||
| 	si32 type = owner->getIdentifier("object", typeName); | ||||
|  | ||||
| //	VLC->objtypeh->getHandlerFor() | ||||
| //TODO:MapObjectLoader::construct() | ||||
| 	handler = VLC->objtypeh->getHandlerFor(typeName, subTypeName); | ||||
|  | ||||
| 	instance = handler->create(ObjectTemplate()); | ||||
| 	instance->id = ObjectInstanceID(owner->map->objects.size()); | ||||
| 	owner->map->objects.push_back(instance); | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::MapObjectLoader::configure() | ||||
| { | ||||
| //TODO:MapObjectLoader::configure() | ||||
| 	instance->readJson(configuration, false); | ||||
| } | ||||
|  | ||||
| void CMapLoaderJson::readObjects() | ||||
|   | ||||
| @@ -32,7 +32,7 @@ void CMapGenerator::foreachDirectNeighbour(const int3& pos, std::function<void(i | ||||
| 		int3 n = pos + dir; | ||||
| 		if(map->isInTheMap(n)) | ||||
| 			foo(n); | ||||
| 	}	 | ||||
| 	} | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -189,7 +189,7 @@ void CMapGenerator::addPlayerInfo() | ||||
| 			playerCount = mapGenOptions->getCompOnlyPlayerCount(); | ||||
| 			teamCount = mapGenOptions->getCompOnlyTeamCount(); | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		if(playerCount == 0) | ||||
| 		{ | ||||
| 			continue; | ||||
| @@ -259,7 +259,7 @@ void CMapGenerator::genZones() | ||||
| } | ||||
|  | ||||
| void CMapGenerator::fillZones() | ||||
| {	 | ||||
| { | ||||
| 	//init native town count with 0 | ||||
| 	for (auto faction : VLC->townh->getAllowedFactions()) | ||||
| 		zonesPerFaction[faction] = 0; | ||||
| @@ -495,8 +495,8 @@ void CMapGenerator::createConnections() | ||||
| 					zoneA->addMonster (this, guardPos, connection.getGuardStrength(), false, true); | ||||
| 					//zones can make paths only in their own area | ||||
| 					zoneA->crunchPath(this, guardPos, posA, true, zoneA->getFreePaths()); //make connection towards our zone center | ||||
| 					zoneB->crunchPath(this, guardPos, posB, true, zoneB->getFreePaths()); //make connection towards other zone center		 | ||||
| 					 | ||||
| 					zoneB->crunchPath(this, guardPos, posB, true, zoneB->getFreePaths()); //make connection towards other zone center | ||||
|  | ||||
| 					zoneA->addRoadNode(guardPos); | ||||
| 					zoneB->addRoadNode(guardPos); | ||||
| 					break; //we're done with this connection | ||||
| @@ -504,7 +504,7 @@ void CMapGenerator::createConnections() | ||||
| 			} | ||||
| 		} | ||||
| 		else //create subterranean gates between two zones | ||||
| 		{	 | ||||
| 		{ | ||||
| 			//find point on the path between zones | ||||
| 			float3 offset (posB.x - posA.x, posB.y - posA.y, 0); | ||||
|  | ||||
| @@ -563,15 +563,14 @@ void CMapGenerator::createConnections() | ||||
| 		} | ||||
| 		if (!guardPos.valid()) | ||||
| 		{ | ||||
| 			auto teleport1 = new CGMonolith; | ||||
| 			teleport1->ID = Obj::MONOLITH_TWO_WAY; | ||||
| 			teleport1->subID = getNextMonlithIndex(); | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, getNextMonlithIndex()); | ||||
| 			auto teleport1 = factory->create(ObjectTemplate()); | ||||
|  | ||||
| 			auto teleport2 = new CGMonolith(*teleport1); | ||||
| 			auto teleport2 = factory->create(ObjectTemplate()); | ||||
|  | ||||
| 			zoneA->addRequiredObject (teleport1, connection.getGuardStrength()); | ||||
| 			zoneB->addRequiredObject (teleport2, connection.getGuardStrength()); | ||||
| 		}		 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -590,7 +589,7 @@ void CMapGenerator::addHeaderInfo() | ||||
| void CMapGenerator::checkIsOnMap(const int3& tile) const | ||||
| { | ||||
| 	if (!map->isInTheMap(tile)) | ||||
| 		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile));	 | ||||
| 		throw  rmgException(boost::to_string(boost::format("Tile %s is outside the map") % tile)); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -633,8 +632,8 @@ bool CMapGenerator::isUsed(const int3 &tile) const | ||||
| bool CMapGenerator::isRoad(const int3& tile) const | ||||
| { | ||||
| 	checkIsOnMap(tile); | ||||
| 	 | ||||
| 	return tiles[tile.x][tile.y][tile.z].isRoad();	 | ||||
|  | ||||
| 	return tiles[tile.x][tile.y][tile.z].isRoad(); | ||||
| } | ||||
|  | ||||
| void CMapGenerator::setOccupied(const int3 &tile, ETileType::ETileType state) | ||||
| @@ -648,7 +647,7 @@ void CMapGenerator::setRoad(const int3& tile, ERoadType::ERoadType roadType) | ||||
| { | ||||
| 	checkIsOnMap(tile); | ||||
|  | ||||
| 	tiles[tile.x][tile.y][tile.z].setRoadType(roadType);	 | ||||
| 	tiles[tile.x][tile.y][tile.z].setRoadType(roadType); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -86,7 +86,7 @@ void CRmgTemplateZone::CTownInfo::setCastleDensity(int value) | ||||
| 	castleDensity = value; | ||||
| } | ||||
|  | ||||
| CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), terrain(ETerrainType::WRONG),roadType(ERoadType::NO_ROAD)  | ||||
| CTileInfo::CTileInfo():nearestObjectDistance(INT_MAX), terrain(ETerrainType::WRONG),roadType(ERoadType::NO_ROAD) | ||||
| { | ||||
| 	occupied = ETileType::POSSIBLE; //all tiles are initially possible to place objects or passages | ||||
| } | ||||
| @@ -638,7 +638,7 @@ do not leave zone border | ||||
| 		} | ||||
|  | ||||
| 		auto lastDistance = distance; | ||||
| 			 | ||||
|  | ||||
| 		auto processNeighbours = [this, gen, ¤tPos, dst, &distance, &result, &end, clearedTiles](int3 &pos) | ||||
| 		{ | ||||
| 			if (!result) //not sure if lambda is worth it... | ||||
| @@ -672,19 +672,19 @@ do not leave zone border | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 		 | ||||
|  | ||||
| 		if (onlyStraight) | ||||
| 			gen->foreachDirectNeighbour (currentPos, processNeighbours); | ||||
| 		else | ||||
| 			gen->foreach_neighbour (currentPos,processNeighbours); | ||||
| 						 | ||||
|  | ||||
| 		int3 anotherPos(-1, -1, -1); | ||||
|  | ||||
| 		if (!(result || distance < lastDistance)) //we do not advance, use more advanced pathfinding algorithm? | ||||
| 		{ | ||||
| 			//try any nearby tiles, even if its not closer than current | ||||
| 			float lastDistance = 2 * distance; //start with significantly larger value | ||||
| 			 | ||||
|  | ||||
| 			auto processNeighbours2 = [this, gen, ¤tPos, dst, &lastDistance, &anotherPos, &end, clearedTiles](int3 &pos) | ||||
| 			{ | ||||
| 				if (currentPos.dist2dSQ(dst) < lastDistance) //try closest tiles from all surrounding unused tiles | ||||
| @@ -700,13 +700,13 @@ do not leave zone border | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			};			 | ||||
| 			}; | ||||
| 			if (onlyStraight) | ||||
| 				gen->foreachDirectNeighbour(currentPos, processNeighbours2); | ||||
| 			else | ||||
| 				gen->foreach_neighbour(currentPos, processNeighbours2); | ||||
| 						 | ||||
| 			 | ||||
|  | ||||
|  | ||||
| 			if (anotherPos.valid()) | ||||
| 			{ | ||||
| 				if (clearedTiles) | ||||
| @@ -878,7 +878,7 @@ bool CRmgTemplateZone::connectPath(CMapGenerator* gen, const int3& src, bool onl | ||||
|  | ||||
| 			if (onlyStraight) | ||||
| 				gen->foreachDirectNeighbour(currentNode, foo); | ||||
| 			else  | ||||
| 			else | ||||
| 				gen->foreach_neighbour(currentNode, foo); | ||||
| 		} | ||||
|  | ||||
| @@ -997,8 +997,8 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, | ||||
| 	static const float multiplier1[] = {0.5, 0.75, 1.0, 1.5, 1.5}; | ||||
| 	static const float multiplier2[] = {0.5, 0.75, 1.0, 1.0, 1.5}; | ||||
|  | ||||
| 	int strength1 = std::max(0.f, (strength - value1[monsterStrength]) * multiplier1[monsterStrength]);  | ||||
| 	int strength2 = std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength]);  | ||||
| 	int strength1 = std::max(0.f, (strength - value1[monsterStrength]) * multiplier1[monsterStrength]); | ||||
| 	int strength2 = std::max(0.f, (strength - value2[monsterStrength]) * multiplier2[monsterStrength]); | ||||
|  | ||||
| 	strength = strength1 + strength2; | ||||
| 	if (strength < 2000) | ||||
| @@ -1031,10 +1031,9 @@ bool CRmgTemplateZone::addMonster(CMapGenerator* gen, int3 &pos, si32 strength, | ||||
| 		amount = strength / VLC->creh->creatures[creId]->AIValue; | ||||
| 	} | ||||
|  | ||||
| 	auto guardFactory = VLC->objtypeh->getHandlerFor(Obj::MONSTER, creId); | ||||
|  | ||||
| 	auto guard = new CGCreature(); | ||||
| 	guard->ID = Obj::MONSTER; | ||||
| 	guard->subID = creId; | ||||
| 	auto guard = (CGCreature *) guardFactory->create(ObjectTemplate()); | ||||
| 	guard->character = CGCreature::HOSTILE; | ||||
| 	auto  hlp = new CStackInstance(creId, amount); | ||||
| 	//will be set during initialization | ||||
| @@ -1132,7 +1131,7 @@ bool CRmgTemplateZone::createTreasurePile(CMapGenerator* gen, int3 &pos, float m | ||||
| 			info.occupiedPositions.insert(visitablePos); | ||||
|  | ||||
| 			currentValue += oi.value; | ||||
| 		 | ||||
|  | ||||
| 			treasures[info.nextTreasurePos] = object; | ||||
|  | ||||
| 			//now find place for next object | ||||
| @@ -1313,19 +1312,23 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) | ||||
| 	{ | ||||
| 		for (int i = 0; i < count; i++) | ||||
| 		{ | ||||
| 			auto town = new CGTownInstance(); | ||||
| 			town->ID = Obj::TOWN; | ||||
| 			si32 subType = townType; | ||||
|  | ||||
| 			if (this->townsAreSameType) | ||||
| 				town->subID = townType; | ||||
| 			else | ||||
| 			if(totalTowns>0) | ||||
| 			{ | ||||
| 				if (townTypes.size()) | ||||
| 					town->subID = *RandomGeneratorUtil::nextItem(townTypes, gen->rand); | ||||
| 				else | ||||
| 					town->subID = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed | ||||
| 				if(!this->townsAreSameType) | ||||
| 				{ | ||||
| 					if (townTypes.size()) | ||||
| 						subType = *RandomGeneratorUtil::nextItem(townTypes, gen->rand); | ||||
| 					else | ||||
| 						subType = *RandomGeneratorUtil::nextItem(getDefaultTownTypes(), gen->rand); //it is possible to have zone with no towns allowed | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, subType); | ||||
| 			auto town = (CGTownInstance *) townFactory->create(ObjectTemplate()); | ||||
| 			town->ID = Obj::TOWN; | ||||
|  | ||||
| 			town->tempOwner = player; | ||||
| 			if (hasFort) | ||||
| 				town->builtBuildings.insert(BuildingID::FORT); | ||||
| @@ -1337,10 +1340,8 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) | ||||
| 					town->possibleSpells.push_back(spell->id); | ||||
| 			} | ||||
|  | ||||
| 			if (!totalTowns)  | ||||
| 			if (totalTowns <= 0) | ||||
| 			{ | ||||
| 				//first town in zone sets the facton of entire zone | ||||
| 				town->subID = townType; | ||||
| 				//register MAIN town of zone | ||||
| 				gen->registerZone(town->subID); | ||||
| 				//first town in zone goes in the middle | ||||
| @@ -1376,10 +1377,9 @@ void CRmgTemplateZone::initTownType (CMapGenerator* gen) | ||||
| 			randomizeTownType(gen); | ||||
| 		} | ||||
|  | ||||
| 		auto  town = new CGTownInstance(); | ||||
| 		town->ID = Obj::TOWN; | ||||
| 		auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, townType); | ||||
|  | ||||
| 		town->subID = townType; | ||||
| 		CGTownInstance * town = (CGTownInstance *) townFactory->create(ObjectTemplate()); | ||||
| 		town->tempOwner = player; | ||||
| 		town->builtBuildings.insert(BuildingID::FORT); | ||||
| 		town->builtBuildings.insert(BuildingID::DEFAULT); | ||||
| @@ -1490,20 +1490,25 @@ void CRmgTemplateZone::paintZoneTerrain (CMapGenerator* gen, ETerrainType terrai | ||||
|  | ||||
| bool CRmgTemplateZone::placeMines (CMapGenerator* gen) | ||||
| { | ||||
| 	std::vector<Res::ERes> required_mines; | ||||
| 	required_mines.push_back(Res::ERes::WOOD); | ||||
| 	required_mines.push_back(Res::ERes::ORE); | ||||
|  | ||||
| 	static const Res::ERes woodOre[] = {Res::ERes::WOOD, Res::ERes::ORE}; | ||||
| 	static const Res::ERes preciousResources[] = {Res::ERes::GEMS, Res::ERes::CRYSTAL, Res::ERes::MERCURY, Res::ERes::SULFUR}; | ||||
|  | ||||
| 	std::array<TObjectTypeHandler, 7> factory = | ||||
| 	{ | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 0), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 1), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 2), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 3), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 4), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 5), | ||||
| 		VLC->objtypeh->getHandlerFor(Obj::MINE, 6) | ||||
| 	}; | ||||
|  | ||||
| 	for (const auto & res : woodOre) | ||||
| 	{ | ||||
| 		for (int i = 0; i < mines[res]; i++) | ||||
| 		{ | ||||
| 			auto mine = new CGMine(); | ||||
| 			mine->ID = Obj::MINE; | ||||
| 			mine->subID = static_cast<si32>(res); | ||||
| 			auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate()); | ||||
| 			mine->producedResource = res; | ||||
| 			mine->producedQuantity = mine->defaultResProduction(); | ||||
| 			if (!i) | ||||
| @@ -1516,9 +1521,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen) | ||||
| 	{ | ||||
| 		for (int i = 0; i < mines[res]; i++) | ||||
| 		{ | ||||
| 			auto mine = new CGMine(); | ||||
| 			mine->ID = Obj::MINE; | ||||
| 			mine->subID = static_cast<si32>(res); | ||||
| 			auto mine = (CGMine *) factory.at(static_cast<si32>(res))->create(ObjectTemplate()); | ||||
| 			mine->producedResource = res; | ||||
| 			mine->producedQuantity = mine->defaultResProduction(); | ||||
| 			addRequiredObject(mine, 3500); | ||||
| @@ -1526,9 +1529,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen) | ||||
| 	} | ||||
| 	for (int i = 0; i < mines[Res::GOLD]; i++) | ||||
| 	{ | ||||
| 		auto mine = new CGMine(); | ||||
| 		mine->ID = Obj::MINE; | ||||
| 		mine->subID = static_cast<si32>(Res::GOLD); | ||||
| 		auto mine = (CGMine *) factory.at(Res::GOLD)->create(ObjectTemplate()); | ||||
| 		mine->producedResource = Res::GOLD; | ||||
| 		mine->producedQuantity = mine->defaultResProduction(); | ||||
| 		addRequiredObject(mine, 7000); | ||||
| @@ -1540,7 +1541,7 @@ bool CRmgTemplateZone::placeMines (CMapGenerator* gen) | ||||
| bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen) | ||||
| { | ||||
| 	logGlobal->traceStream() << "Creating required objects"; | ||||
| 	 | ||||
|  | ||||
| 	for(const auto &object : requiredObjects) | ||||
| 	{ | ||||
| 		auto obj = object.first; | ||||
| @@ -1577,16 +1578,16 @@ bool CRmgTemplateZone::createRequiredObjects(CMapGenerator* gen) | ||||
| 				break; | ||||
| 		} | ||||
|  | ||||
| 	 | ||||
|  | ||||
| 		placeObject(gen, obj, pos); | ||||
| 		guardObject (gen, obj, object.second, (obj->ID == Obj::MONOLITH_TWO_WAY), true); | ||||
| 		//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones	 | ||||
| 		//paths to required objects constitute main paths of zone. otherwise they just may lead to middle and create dead zones | ||||
| 	} | ||||
|  | ||||
| 	for (const auto &obj : closeObjects) | ||||
| 	{ | ||||
| 		std::vector<int3> tiles(possibleTiles.begin(), possibleTiles.end()); //new tiles vector after each object has been placed | ||||
| 		 | ||||
|  | ||||
| 		// smallest distance to zone center, greatest distance to nearest object | ||||
| 		auto isCloser = [this, gen](const int3 & lhs, const int3 & rhs) -> bool | ||||
| 		{ | ||||
| @@ -1675,7 +1676,7 @@ void CRmgTemplateZone::createTreasures(CMapGenerator* gen) | ||||
| 				return !gen->isPossible(tile); | ||||
| 			}); | ||||
|  | ||||
| 			 | ||||
|  | ||||
| 			int3 treasureTilePos; | ||||
| 			//If we are able to place at least one object with value lower than minGuardedValue, it's ok | ||||
| 			do | ||||
| @@ -1722,11 +1723,11 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen) | ||||
| 	std::vector<obstaclePair> possibleObstacles; | ||||
|  | ||||
| 	//get all possible obstacles for this terrain | ||||
| 	for (auto primaryID : VLC->objtypeh->knownObjects())  | ||||
| 	{  | ||||
| 		for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID))  | ||||
| 		{  | ||||
| 			auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID);  | ||||
| 	for (auto primaryID : VLC->objtypeh->knownObjects()) | ||||
| 	{ | ||||
| 		for (auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) | ||||
| 		{ | ||||
| 			auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); | ||||
| 			if (handler->isStaticObject()) | ||||
| 			{ | ||||
| 				for (auto temp : handler->getTemplates()) | ||||
| @@ -1735,7 +1736,7 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen) | ||||
| 						obstaclesBySize[temp.getBlockedOffsets().size()].push_back(temp); | ||||
| 				} | ||||
| 			} | ||||
| 		}  | ||||
| 		} | ||||
| 	} | ||||
| 	for (auto o : obstaclesBySize) | ||||
| 	{ | ||||
| @@ -1789,13 +1790,13 @@ void CRmgTemplateZone::createObstacles2(CMapGenerator* gen) | ||||
| void CRmgTemplateZone::connectRoads(CMapGenerator* gen) | ||||
| { | ||||
| 	logGlobal->debug("Started building roads"); | ||||
| 	 | ||||
|  | ||||
| 	std::set<int3> roadNodesCopy(roadNodes); | ||||
| 	std::set<int3> processed; | ||||
| 	 | ||||
|  | ||||
| 	while(!roadNodesCopy.empty()) | ||||
| 	{ | ||||
| 		int3 node = *roadNodesCopy.begin();  | ||||
| 		int3 node = *roadNodesCopy.begin(); | ||||
| 		roadNodesCopy.erase(node); | ||||
| 		int3 cross(-1, -1, -1); | ||||
|  | ||||
| @@ -1818,13 +1819,13 @@ void CRmgTemplateZone::connectRoads(CMapGenerator* gen) | ||||
| 			processed.insert(cross); //don't draw road starting at end point which is already connected | ||||
| 			vstd::erase_if_present(roadNodesCopy, cross); | ||||
| 		} | ||||
| 		 | ||||
| 		processed.insert(node);  | ||||
|  | ||||
| 		processed.insert(node); | ||||
| 	} | ||||
|  | ||||
| 	drawRoads(gen); | ||||
| 	 | ||||
| 	logGlobal->debug("Finished building roads");	 | ||||
|  | ||||
| 	logGlobal->debug("Finished building roads"); | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::drawRoads(CMapGenerator* gen) | ||||
| @@ -1832,7 +1833,7 @@ void CRmgTemplateZone::drawRoads(CMapGenerator* gen) | ||||
| 	std::vector<int3> tiles; | ||||
| 	for (auto tile : roads) | ||||
| 	{ | ||||
| 		if(gen->map->isInTheMap(tile))	 | ||||
| 		if(gen->map->isInTheMap(tile)) | ||||
| 			tiles.push_back (tile); | ||||
| 	} | ||||
| 	for (auto tile : roadNodes) | ||||
| @@ -1841,8 +1842,8 @@ void CRmgTemplateZone::drawRoads(CMapGenerator* gen) | ||||
| 			tiles.push_back(tile); | ||||
| 	} | ||||
|  | ||||
| 	gen->editManager->getTerrainSelection().setSelection(tiles);	 | ||||
| 	gen->editManager->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand);	 | ||||
| 	gen->editManager->getTerrainSelection().setSelection(tiles); | ||||
| 	gen->editManager->drawRoad(ERoadType::COBBLESTONE_ROAD, &gen->rand); | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -1852,7 +1853,7 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen) | ||||
|  | ||||
| 	//zone center should be always clear to allow other tiles to connect | ||||
| 	gen->setOccupied(this->getPos(), ETileType::FREE); | ||||
| 	freePaths.insert(pos);  | ||||
| 	freePaths.insert(pos); | ||||
|  | ||||
| 	addAllPossibleObjects (gen); | ||||
|  | ||||
| @@ -1861,7 +1862,7 @@ bool CRmgTemplateZone::fill(CMapGenerator* gen) | ||||
| 	placeMines(gen); | ||||
| 	createRequiredObjects(gen); | ||||
| 	createTreasures(gen); | ||||
| 	 | ||||
|  | ||||
| 	logGlobal->infoStream() << boost::format ("Zone %d filled successfully") %id; | ||||
| 	return true; | ||||
| } | ||||
| @@ -2040,7 +2041,7 @@ void CRmgTemplateZone::checkAndPlaceObject(CMapGenerator* gen, CGObjectInstance* | ||||
| 		auto templates = VLC->objtypeh->getHandlerFor(object->ID, object->subID)->getTemplates(terrainType); | ||||
| 		if (templates.empty()) | ||||
| 			throw rmgException(boost::to_string(boost::format("Did not find graphics for object (%d,%d) at %s (terrain %d)") %object->ID %object->subID %pos %terrainType)); | ||||
| 	 | ||||
|  | ||||
| 		object->appearance = templates.front(); | ||||
| 	} | ||||
|  | ||||
| @@ -2059,7 +2060,7 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, | ||||
| 		points.insert(pos + object->getVisitableOffset()); | ||||
| 	points.insert(pos); | ||||
| 	for(auto p : points) | ||||
| 	{		 | ||||
| 	{ | ||||
| 		if (gen->map->isInTheMap(p)) | ||||
| 		{ | ||||
| 			gen->setOccupied(p, ETileType::USED); | ||||
| @@ -2068,7 +2069,7 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, | ||||
| 	if (updateDistance) | ||||
| 	{ | ||||
| 		for(auto tile : possibleTiles) //don't need to mark distance for not possible tiles | ||||
| 		{		 | ||||
| 		{ | ||||
| 			si32 d = pos.dist2dSQ(tile); //optimization, only relative distance is interesting | ||||
| 			gen->setNearestObjectDistance(tile, std::min<float>(d, gen->getNearestObjectDistance(tile))); | ||||
| 		} | ||||
| @@ -2080,7 +2081,7 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, | ||||
| 		logGlobal->warnStream() << boost::format("Placed Seer Hut at %s, quest artifact %d is %s") % object->pos % artid % VLC->arth->artifacts[artid]->Name(); | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
|  | ||||
| 	switch (object->ID) | ||||
| 	{ | ||||
| 	case Obj::TOWN: | ||||
| @@ -2093,10 +2094,10 @@ void CRmgTemplateZone::placeObject(CMapGenerator* gen, CGObjectInstance* object, | ||||
| 			addRoadNode(object->visitablePos()); | ||||
| 		} | ||||
| 		break; | ||||
| 	 | ||||
|  | ||||
| 	default: | ||||
| 		break; | ||||
| 	}		 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void CRmgTemplateZone::placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* object, const int3 &pos, si32 str, bool zoneGuard) | ||||
| @@ -2107,9 +2108,8 @@ void CRmgTemplateZone::placeAndGuardObject(CMapGenerator* gen, CGObjectInstance* | ||||
|  | ||||
| void CRmgTemplateZone::placeSubterraneanGate(CMapGenerator* gen, int3 pos, si32 guardStrength) | ||||
| { | ||||
| 	auto gate = new CGSubterraneanGate; | ||||
| 	gate->ID = Obj::SUBTERRANEAN_GATE; | ||||
| 	gate->subID = 0; | ||||
| 	auto factory = VLC->objtypeh->getHandlerFor(Obj::SUBTERRANEAN_GATE, 0); | ||||
| 	auto gate = factory->create(ObjectTemplate()); | ||||
| 	placeObject (gen, gate, pos, true); | ||||
| 	addToConnectLater (getAccessibleOffset (gen, gate->appearance, pos)); //guard will be placed on accessibleOffset | ||||
| 	guardObject (gen, gate, guardStrength, true); | ||||
| @@ -2123,7 +2123,7 @@ std::vector<int3> CRmgTemplateZone::getAccessibleOffsets (CMapGenerator* gen, CG | ||||
|  | ||||
| 	auto tilesBlockedByObject = object->getBlockedPos(); //absolue value, as object is already placed | ||||
|  | ||||
| 	gen->foreach_neighbour(visitable, [&](int3& pos)  | ||||
| 	gen->foreach_neighbour(visitable, [&](int3& pos) | ||||
| 	{ | ||||
| 		if (gen->isPossible(pos) || gen->isFree(pos)) | ||||
| 		{ | ||||
| @@ -2166,7 +2166,7 @@ bool CRmgTemplateZone::guardObject(CMapGenerator* gen, CGObjectInstance* object, | ||||
| 			if (!gen->isFree(pos)) | ||||
| 				gen->setOccupied(pos, ETileType::BLOCKED); | ||||
| 		} | ||||
| 		gen->foreach_neighbour (guardTile, [&](int3& pos)  | ||||
| 		gen->foreach_neighbour (guardTile, [&](int3& pos) | ||||
| 		{ | ||||
| 			if (gen->isPossible(pos)) | ||||
| 				gen->setOccupied (pos, ETileType::FREE); | ||||
| @@ -2303,9 +2303,8 @@ ObjectInfo CRmgTemplateZone::getRandomObject(CMapGenerator* gen, CTreasurePileIn | ||||
| 		{ | ||||
| 			oi.generateObject = [minValue]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto obj = new CGPandoraBox(); | ||||
| 				obj->ID = Obj::PANDORAS_BOX; | ||||
| 				obj->subID = 0; | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 				auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 				obj->resources[Res::GOLD] = minValue; | ||||
| 				return obj; | ||||
| 			}; | ||||
| @@ -2393,9 +2392,6 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i, gen, this]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGHeroInstance; | ||||
| 			obj->ID = Obj::PRISON; | ||||
|  | ||||
| 			std::vector<ui32> possibleHeroes; | ||||
| 			for (int j = 0; j < gen->map->allowedHeroes.size(); j++) | ||||
| 			{ | ||||
| @@ -2404,6 +2400,10 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 			} | ||||
|  | ||||
| 			auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, gen->rand); | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0); | ||||
| 			auto obj = (CGHeroInstance *) factory->create(ObjectTemplate()); | ||||
|  | ||||
|  | ||||
| 			obj->subID = hid; //will be initialized later | ||||
| 			obj->exp = prisonExp[i]; | ||||
| 			obj->setOwner(PlayerColor::NEUTRAL); | ||||
| @@ -2471,9 +2471,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i, gen]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGArtifact(); | ||||
| 			obj->ID = Obj::SPELL_SCROLL; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::SPELL_SCROLL, 0); | ||||
| 			auto obj = (CGArtifact *) factory->create(ObjectTemplate()); | ||||
| 			std::vector<SpellID> out; | ||||
|  | ||||
| 			for (auto spell : VLC->spellh->objects) //spellh size appears to be greater (?) | ||||
| @@ -2499,9 +2498,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGPandoraBox(); | ||||
| 			obj->ID = Obj::PANDORAS_BOX; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			obj->resources[Res::GOLD] = i * 5000; | ||||
| 			return obj; | ||||
| 		}; | ||||
| @@ -2516,9 +2514,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGPandoraBox(); | ||||
| 			obj->ID = Obj::PANDORAS_BOX; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			obj->gainedExp = i * 5000; | ||||
| 			return obj; | ||||
| 		}; | ||||
| @@ -2564,9 +2561,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
|  | ||||
| 		oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGPandoraBox(); | ||||
| 			obj->ID = Obj::PANDORAS_BOX; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto stack = new CStackInstance(creature, creaturesAmount); | ||||
| 			obj->creatures.putStack(SlotID(0), stack); | ||||
| 			return obj; | ||||
| @@ -2582,9 +2578,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i, gen]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGPandoraBox(); | ||||
| 			obj->ID = Obj::PANDORAS_BOX; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
|  | ||||
| 			std::vector <CSpell *> spells; | ||||
| 			for (auto spell : VLC->spellh->objects) | ||||
| @@ -2612,9 +2607,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
| 	{ | ||||
| 		oi.generateObject = [i,gen]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto obj = new CGPandoraBox(); | ||||
| 			obj->ID = Obj::PANDORAS_BOX; | ||||
| 			obj->subID = 0; | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
|  | ||||
| 			std::vector <CSpell *> spells; | ||||
| 			for (auto spell : VLC->spellh->objects) | ||||
| @@ -2642,9 +2636,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
|  | ||||
| 	oi.generateObject = [gen]() -> CGObjectInstance * | ||||
| 	{ | ||||
| 		auto obj = new CGPandoraBox(); | ||||
| 		obj->ID = Obj::PANDORAS_BOX; | ||||
| 		obj->subID = 0; | ||||
| 		auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 		auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
|  | ||||
| 		std::vector <CSpell *> spells; | ||||
| 		for (auto spell : VLC->spellh->objects) | ||||
| @@ -2716,9 +2709,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
|  | ||||
| 			oi.generateObject = [creature, creaturesAmount, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto obj = new CGSeerHut(); | ||||
| 				obj->ID = Obj::SEER_HUT; | ||||
| 				obj->subID = randomAppearance; | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
| 				obj->rewardType = CGSeerHut::CREATURE; | ||||
| 				obj->rID = creature->idNumber; | ||||
| 				obj->rVal = creaturesAmount; | ||||
| @@ -2752,9 +2744,9 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
|  | ||||
| 			oi.generateObject = [i, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto obj = new CGSeerHut(); | ||||
| 				obj->ID = Obj::SEER_HUT; | ||||
| 				obj->subID = randomAppearance; | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
|  | ||||
| 				obj->rewardType = CGSeerHut::EXPERIENCE; | ||||
| 				obj->rID = 0; //unitialized? | ||||
| 				obj->rVal = seerExpGold[i]; | ||||
| @@ -2774,9 +2766,8 @@ void CRmgTemplateZone::addAllPossibleObjects(CMapGenerator* gen) | ||||
|  | ||||
| 			oi.generateObject = [i, randomAppearance, gen, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto obj = new CGSeerHut(); | ||||
| 				obj->ID = Obj::SEER_HUT; | ||||
| 				obj->subID = randomAppearance; | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
| 				obj->rewardType = CGSeerHut::RESOURCES; | ||||
| 				obj->rID = Res::GOLD; | ||||
| 				obj->rVal = seerExpGold[i]; | ||||
|   | ||||
| @@ -152,6 +152,12 @@ void MapComparer::compareObject(const CGObjectInstance * actual, const CGObjectI | ||||
| { | ||||
| 	BOOST_CHECK_EQUAL(actual->getStringId(), expected->getStringId()); | ||||
| 	BOOST_CHECK_EQUAL(typeid(actual).name(), typeid(expected).name());//todo: remove and use just comparison | ||||
|  | ||||
| 	std::string actualFullID = boost::to_string(boost::format("%s(%d)|%s(%d)") % actual->typeName % actual->id % actual->subTypeName % actual->subID); | ||||
| 	std::string expectedFullID = boost::to_string(boost::format("%s(%d)|%s(%d)") % expected->typeName % expected->id % expected->subTypeName % expected->subID); | ||||
|  | ||||
| 	BOOST_CHECK_EQUAL(actualFullID, expectedFullID); | ||||
| 	BOOST_CHECK_EQUAL(actual->pos, expected->pos); | ||||
| } | ||||
|  | ||||
| void MapComparer::compareObjects() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user