mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Switch ObjectTemplate to shared_ptr<const> (#870)
This commit is contained in:
		
				
					committed by
					
						 Andrii Danylchenko
						Andrii Danylchenko
					
				
			
			
				
	
			
			
			
						parent
						
							cedc9a92ed
						
					
				
				
					commit
					3d2dc2335b
				
			| @@ -173,8 +173,8 @@ void Graphics::loadHeroAnimations() | ||||
| 	{ | ||||
| 		for (auto & templ : VLC->objtypeh->getHandlerFor(Obj::HERO, elem->getIndex())->getTemplates()) | ||||
| 		{ | ||||
| 			if (!heroAnimations.count(templ.animationFile)) | ||||
| 				heroAnimations[templ.animationFile] = loadHeroAnimation(templ.animationFile); | ||||
| 			if (!heroAnimations.count(templ->animationFile)) | ||||
| 				heroAnimations[templ->animationFile] = loadHeroAnimation(templ->animationFile); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -381,21 +381,21 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const CGObjectInstance* obj) | ||||
| 	return getAnimation(obj->appearance); | ||||
| } | ||||
|  | ||||
| std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info) | ||||
| std::shared_ptr<CAnimation> Graphics::getAnimation(std::shared_ptr<const ObjectTemplate> info) | ||||
| { | ||||
| 	//the only(?) invisible object | ||||
| 	if(info.id == Obj::EVENT) | ||||
| 	if(info->id == Obj::EVENT) | ||||
| 	{ | ||||
| 		return std::shared_ptr<CAnimation>(); | ||||
| 	} | ||||
|  | ||||
| 	if(info.animationFile.empty()) | ||||
| 	if(info->animationFile.empty()) | ||||
| 	{ | ||||
| 		logGlobal->warn("Def name for obj (%d,%d) is empty!", info.id, info.subid); | ||||
| 		logGlobal->warn("Def name for obj (%d,%d) is empty!", info->id, info->subid); | ||||
| 		return std::shared_ptr<CAnimation>(); | ||||
| 	} | ||||
|  | ||||
| 	std::shared_ptr<CAnimation> ret = mapObjectAnimations[info.animationFile]; | ||||
| 	std::shared_ptr<CAnimation> ret = mapObjectAnimations[info->animationFile]; | ||||
|  | ||||
| 	//already loaded | ||||
| 	if(ret) | ||||
| @@ -404,8 +404,8 @@ std::shared_ptr<CAnimation> Graphics::getAnimation(const ObjectTemplate & info) | ||||
| 		return ret; | ||||
| 	} | ||||
|  | ||||
| 	ret = std::make_shared<CAnimation>(info.animationFile); | ||||
| 	mapObjectAnimations[info.animationFile] = ret; | ||||
| 	ret = std::make_shared<CAnimation>(info->animationFile); | ||||
| 	mapObjectAnimations[info->animationFile] = ret; | ||||
|  | ||||
| 	ret->preload(); | ||||
| 	return ret; | ||||
|   | ||||
| @@ -98,7 +98,7 @@ public: | ||||
| 	void blueToPlayersAdv(SDL_Surface * sur, PlayerColor player); //replaces blue interface colour with a color of player | ||||
|  | ||||
| 	std::shared_ptr<CAnimation> getAnimation(const CGObjectInstance * obj); | ||||
| 	std::shared_ptr<CAnimation> getAnimation(const ObjectTemplate & info); | ||||
| 	std::shared_ptr<CAnimation> getAnimation(std::shared_ptr<const ObjectTemplate> info); | ||||
| }; | ||||
|  | ||||
| extern Graphics * graphics; | ||||
|   | ||||
| @@ -979,7 +979,7 @@ CMapHandler::AnimBitmapHolder CMapHandler::CMapBlitter::findHeroBitmap(const CGH | ||||
| 		if (hero->boat) | ||||
| 			animation = graphics->boatAnimations[hero->boat->subID]; | ||||
| 		else | ||||
| 			animation = graphics->heroAnimations[hero->appearance.animationFile]; | ||||
| 			animation = graphics->heroAnimations[hero->appearance->animationFile]; | ||||
|  | ||||
| 		bool moving = !hero->isStanding; | ||||
| 		int group = getHeroFrameGroup(hero->moveDir, moving); | ||||
| @@ -1486,8 +1486,8 @@ bool CMapHandler::compareObjectBlitOrder(const CGObjectInstance * a, const CGObj | ||||
| 		return true; | ||||
| 	if (!b) | ||||
| 		return false; | ||||
| 	if (a->appearance.printPriority != b->appearance.printPriority) | ||||
| 		return a->appearance.printPriority > b->appearance.printPriority; | ||||
| 	if (a->appearance->printPriority != b->appearance->printPriority) | ||||
| 		return a->appearance->printPriority > b->appearance->printPriority; | ||||
|  | ||||
| 	if(a->pos.y != b->pos.y) | ||||
| 		return a->pos.y < b->pos.y; | ||||
|   | ||||
| @@ -533,7 +533,7 @@ void CGHeroInstance::initObj(CRandomGenerator & rand) | ||||
| 	{ | ||||
| 		auto customApp = VLC->objtypeh->getHandlerFor(ID, type->heroClass->getIndex())->getOverride(cb->gameState()->getTile(visitablePos())->terType, this); | ||||
| 		if (customApp) | ||||
| 			appearance = customApp.get(); | ||||
| 			appearance = customApp; | ||||
| 	} | ||||
|  | ||||
| 	//copy active (probably growing) bonuses from hero prototype to hero object | ||||
|   | ||||
| @@ -1133,7 +1133,7 @@ void CGTownInstance::updateAppearance() | ||||
| 	//FIXME: not the best way to do this | ||||
| 	auto app = VLC->objtypeh->getHandlerFor(ID, subID)->getOverride(cb->gameState()->getTile(visitablePos())->terType, this); | ||||
| 	if (app) | ||||
| 		appearance = app.get(); | ||||
| 		appearance = app; | ||||
| } | ||||
|  | ||||
| std::string CGTownInstance::nodeName() const | ||||
|   | ||||
| @@ -117,11 +117,11 @@ std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
|  | ||||
| 	for (size_t i=0; i<totalNumber; i++) | ||||
| 	{ | ||||
| 		ObjectTemplate templ; | ||||
| 		templ.readTxt(parser); | ||||
| 		auto templ = new ObjectTemplate; | ||||
| 		templ->readTxt(parser); | ||||
| 		parser.endLine(); | ||||
| 		std::pair<si32, si32> key(templ.id.num, templ.subid); | ||||
| 		legacyTemplates.insert(std::make_pair(key, templ)); | ||||
| 		std::pair<si32, si32> key(templ->id.num, templ->subid); | ||||
| 		legacyTemplates.insert(std::make_pair(key, std::shared_ptr<const ObjectTemplate>(templ))); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<JsonNode> ret(dataSize);// create storage for 256 objects | ||||
| @@ -448,7 +448,6 @@ AObjectTypeHandler::AObjectTypeHandler(): | ||||
|  | ||||
| AObjectTypeHandler::~AObjectTypeHandler() | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::setType(si32 type, si32 subtype) | ||||
| @@ -488,12 +487,12 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin | ||||
| 		entry.second.setType(JsonNode::JsonType::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); | ||||
| 		auto tmpl = new ObjectTemplate; | ||||
| 		tmpl->id = Obj(type); | ||||
| 		tmpl->subid = subtype; | ||||
| 		tmpl->stringID = entry.first; // FIXME: create "fullID" - type.object.template? | ||||
| 		tmpl->readJson(entry.second); | ||||
| 		templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl)); | ||||
| 	} | ||||
|  | ||||
| 	if (input["name"].isNull()) | ||||
| @@ -523,7 +522,7 @@ void AObjectTypeHandler::init(const JsonNode & input, boost::optional<std::strin | ||||
| 	initTypeData(input); | ||||
| } | ||||
|  | ||||
| bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const | ||||
| bool AObjectTypeHandler::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const | ||||
| { | ||||
| 	return false; // by default there are no overrides | ||||
| } | ||||
| @@ -551,26 +550,28 @@ SObjectSounds AObjectTypeHandler::getSounds() const | ||||
| 	return sounds; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(const ObjectTemplate & templ) | ||||
| void AObjectTypeHandler::addTemplate(std::shared_ptr<const ObjectTemplate> templ) | ||||
| { | ||||
| 	//Otherwise the template remains constant | ||||
| 	auto ptr = const_cast<ObjectTemplate*>(templ.get()); | ||||
| 	ptr->id = Obj(type); | ||||
| 	ptr->subid = subtype; | ||||
| 	templates.push_back(templ); | ||||
| 	templates.back().id = Obj(type); | ||||
| 	templates.back().subid = subtype; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::addTemplate(JsonNode config) | ||||
| { | ||||
| 	config.setType(JsonNode::JsonType::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); | ||||
| 	templates.push_back(tmpl); | ||||
| 	auto tmpl = new ObjectTemplate; | ||||
| 	tmpl->id = Obj(type); | ||||
| 	tmpl->subid = subtype; | ||||
| 	tmpl->stringID = ""; // TODO? | ||||
| 	tmpl->readJson(config); | ||||
| 	templates.emplace_back(tmpl); | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates() const | ||||
| std::vector<std::shared_ptr<const ObjectTemplate>> AObjectTypeHandler::getTemplates() const | ||||
| { | ||||
| 	return templates; | ||||
| } | ||||
| @@ -580,14 +581,14 @@ BattleField AObjectTypeHandler::getBattlefield() const | ||||
| 	return battlefield ? BattleField::fromString(battlefield.get()) : BattleField::NONE; | ||||
| } | ||||
|  | ||||
| std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & terrainType) const | ||||
| std::vector<std::shared_ptr<const ObjectTemplate>>AObjectTypeHandler::getTemplates(const Terrain & terrainType) const | ||||
| { | ||||
| 	std::vector<ObjectTemplate> templates = getTemplates(); | ||||
| 	std::vector<ObjectTemplate> filtered; | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> templates = getTemplates(); | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> filtered; | ||||
|  | ||||
| 	std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](const ObjectTemplate & obj) | ||||
| 	std::copy_if(templates.begin(), templates.end(), std::back_inserter(filtered), [&](std::shared_ptr<const ObjectTemplate> obj) | ||||
| 	{ | ||||
| 		return obj.canBePlacedAt(terrainType); | ||||
| 		return obj->canBePlacedAt(terrainType); | ||||
| 	}); | ||||
| 	// H3 defines allowed terrains in a weird way - artifacts, monsters and resources have faulty masks here | ||||
| 	// Perhaps we should re-define faulty templates and remove this workaround (already done for resources) | ||||
| @@ -597,15 +598,15 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(const Terrain & ter | ||||
| 		return filtered; | ||||
| } | ||||
|  | ||||
| boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const | ||||
| std::shared_ptr<const ObjectTemplate> AObjectTypeHandler::getOverride(const Terrain & terrainType, const CGObjectInstance * object) const | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(terrainType); | ||||
| 	for (auto & tmpl : ret) | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> ret = getTemplates(terrainType); | ||||
| 	for (const auto & tmpl: ret) | ||||
| 	{ | ||||
| 		if (objectFilter(object, tmpl)) | ||||
| 			return tmpl; | ||||
| 	} | ||||
| 	return boost::optional<ObjectTemplate>(); | ||||
| 	return std::shared_ptr<const ObjectTemplate>(); //empty | ||||
| } | ||||
|  | ||||
| const RandomMapInfo & AObjectTypeHandler::getRMGInfo() | ||||
|   | ||||
| @@ -144,7 +144,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> templates; | ||||
|  | ||||
| 	SObjectSounds sounds; | ||||
|  | ||||
| @@ -154,7 +154,7 @@ class DLL_LINKAGE AObjectTypeHandler : public boost::noncopyable | ||||
|  | ||||
| protected: | ||||
| 	void preInitObject(CGObjectInstance * obj) const; | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const; | ||||
|  | ||||
| 	/// initialization for classes that inherit this one | ||||
| 	virtual void initTypeData(const JsonNode & input); | ||||
| @@ -177,17 +177,21 @@ public: | ||||
| 	boost::optional<std::string> getCustomName() const; | ||||
| 	SObjectSounds getSounds() const; | ||||
|  | ||||
| 	void addTemplate(const ObjectTemplate & templ); | ||||
| 	void addTemplate(std::shared_ptr<const ObjectTemplate> templ); | ||||
| 	void addTemplate(JsonNode config); | ||||
|  | ||||
| 	/// returns all templates matching parameters | ||||
| 	std::vector<ObjectTemplate> getTemplates() const; | ||||
| 	std::vector<ObjectTemplate> getTemplates(const Terrain & terrainType) const; | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates() const; | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> getTemplates(const Terrain & 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) | ||||
| 	std::shared_ptr<const ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const; | ||||
|  | ||||
| 	BattleField getBattlefield() const; | ||||
|  | ||||
| 	/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) | ||||
| 	/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) | ||||
| 	boost::optional<ObjectTemplate> getOverride(const Terrain & terrainType, const CGObjectInstance * object) const; | ||||
|  | ||||
| 	const RandomMapInfo & getRMGInfo(); | ||||
|  | ||||
| @@ -199,14 +203,14 @@ public: | ||||
|  | ||||
| 	/// 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(const ObjectTemplate & tmpl) const = 0; | ||||
| 	virtual CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const = 0; | ||||
|  | ||||
| 	/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily | ||||
| 	/// 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. Otherwise returns NULL | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const = 0; | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| @@ -264,7 +268,7 @@ class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| 	std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors; | ||||
|  | ||||
| 	/// container with H3 templates, used only during loading, no need to serialize it | ||||
| 	typedef std::multimap<std::pair<si32, si32>, ObjectTemplate> TTemplatesContainer; | ||||
| 	typedef std::multimap<std::pair<si32, si32>, std::shared_ptr<const ObjectTemplate>> TTemplatesContainer; | ||||
| 	TTemplatesContainer legacyTemplates; | ||||
|  | ||||
| 	/// contains list of custom names for H3 objects (e.g. Dwellings), used to load H3 data | ||||
|   | ||||
| @@ -152,24 +152,24 @@ void CGObjectInstance::setOwner(PlayerColor ow) | ||||
| } | ||||
| int CGObjectInstance::getWidth() const//returns width of object graphic in tiles | ||||
| { | ||||
| 	return appearance.getWidth(); | ||||
| 	return appearance->getWidth(); | ||||
| } | ||||
| int CGObjectInstance::getHeight() const //returns height of object graphic in tiles | ||||
| { | ||||
| 	return appearance.getHeight(); | ||||
| 	return appearance->getHeight(); | ||||
| } | ||||
| bool CGObjectInstance::visitableAt(int x, int y) const //returns true if object is visitable at location (x, y) form left top tile of image (x, y in tiles) | ||||
| { | ||||
| 	return appearance.isVisitableAt(pos.x - x, pos.y - y); | ||||
| 	return appearance->isVisitableAt(pos.x - x, pos.y - y); | ||||
| } | ||||
| bool CGObjectInstance::blockingAt(int x, int y) const | ||||
| { | ||||
| 	return appearance.isBlockedAt(pos.x - x, pos.y - y); | ||||
| 	return appearance->isBlockedAt(pos.x - x, pos.y - y); | ||||
| } | ||||
|  | ||||
| bool CGObjectInstance::coveringAt(int x, int y) const | ||||
| { | ||||
| 	return appearance.isVisibleAt(pos.x - x, pos.y - y); | ||||
| 	return appearance->isVisibleAt(pos.x - x, pos.y - y); | ||||
| } | ||||
|  | ||||
| std::set<int3> CGObjectInstance::getBlockedPos() const | ||||
| @@ -179,7 +179,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const | ||||
| 	{ | ||||
| 		for(int h=0; h<getHeight(); ++h) | ||||
| 		{ | ||||
| 			if(appearance.isBlockedAt(w, h)) | ||||
| 			if(appearance->isBlockedAt(w, h)) | ||||
| 				ret.insert(int3(pos.x - w, pos.y - h, pos.z)); | ||||
| 		} | ||||
| 	} | ||||
| @@ -188,7 +188,7 @@ std::set<int3> CGObjectInstance::getBlockedPos() const | ||||
|  | ||||
| std::set<int3> CGObjectInstance::getBlockedOffsets() const | ||||
| { | ||||
| 	return appearance.getBlockedOffsets(); | ||||
| 	return appearance->getBlockedOffsets(); | ||||
| } | ||||
|  | ||||
| void CGObjectInstance::setType(si32 ID, si32 subID) | ||||
| @@ -264,7 +264,7 @@ int CGObjectInstance::getSightRadius() const | ||||
|  | ||||
| int3 CGObjectInstance::getVisitableOffset() const | ||||
| { | ||||
| 	return appearance.getVisitableOffset(); | ||||
| 	return appearance->getVisitableOffset(); | ||||
| } | ||||
|  | ||||
| void CGObjectInstance::giveDummyBonus(ObjectInstanceID heroID, ui8 duration) const | ||||
| @@ -350,7 +350,7 @@ int3 CGObjectInstance::visitablePos() const | ||||
|  | ||||
| bool CGObjectInstance::isVisitable() const | ||||
| { | ||||
| 	return appearance.isVisitable(); | ||||
| 	return appearance->isVisitable(); | ||||
| } | ||||
|  | ||||
| bool CGObjectInstance::passableFor(PlayerColor color) const | ||||
| @@ -375,7 +375,7 @@ void CGObjectInstance::serializeJson(JsonSerializeFormat & handler) | ||||
| 		handler.serializeInt("y", pos.y); | ||||
| 		handler.serializeInt("l", pos.z); | ||||
| 		JsonNode app; | ||||
| 		appearance.writeJson(app, false); | ||||
| 		appearance->writeJson(app, false); | ||||
| 		handler.serializeRaw("template",app, boost::none); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -123,7 +123,7 @@ public: | ||||
| 	/// Index of object in map's list of objects | ||||
| 	ObjectInstanceID id; | ||||
| 	/// Defines appearance of object on map (animation, blocked tiles, blit order, etc) | ||||
| 	ObjectTemplate appearance; | ||||
| 	std::shared_ptr<const ObjectTemplate> appearance; | ||||
| 	/// If true hero can visit this object only from neighbouring tiles and can't stand on this object | ||||
| 	bool blockVisit; | ||||
|  | ||||
|   | ||||
| @@ -183,7 +183,7 @@ void CRewardableConstructor::initTypeData(const JsonNode & config) | ||||
| 	objectInfo.init(config); | ||||
| } | ||||
|  | ||||
| CGObjectInstance * CRewardableConstructor::create(const ObjectTemplate & tmpl) const | ||||
| CGObjectInstance * CRewardableConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	auto ret = new CRewardableObject(); | ||||
| 	preInitObject(ret); | ||||
| @@ -196,7 +196,7 @@ void CRewardableConstructor::configureObject(CGObjectInstance * object, CRandomG | ||||
| 	objectInfo.configureObject(dynamic_cast<CRewardableObject*>(object), rng); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(const ObjectTemplate & tmpl) const | ||||
| std::unique_ptr<IObjectInfo> CRewardableConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	return std::unique_ptr<IObjectInfo>(new CRandomRewardObjectInfo(objectInfo)); | ||||
| } | ||||
|   | ||||
| @@ -49,9 +49,9 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler | ||||
| public: | ||||
| 	CRewardableConstructor(); | ||||
|  | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override; | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
|  | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
|  | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override; | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override; | ||||
| }; | ||||
|   | ||||
| @@ -1122,7 +1122,7 @@ std::vector<int3> CGMagicSpring::getVisitableOffsets() const | ||||
|  | ||||
| 	for(int y = 0; y < 6; y++) | ||||
| 		for (int x = 0; x < 8; x++) //starting from left | ||||
| 			if (appearance.isVisitableAt(x, y)) | ||||
| 			if (appearance->isVisitableAt(x, y)) | ||||
| 				visitableTiles.push_back (int3(x, y , 0)); | ||||
|  | ||||
| 	return visitableTiles; | ||||
|   | ||||
| @@ -56,7 +56,7 @@ void CTownInstanceConstructor::afterLoadFinalization() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const | ||||
| bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const | ||||
| { | ||||
| 	auto town = dynamic_cast<const CGTownInstance *>(object); | ||||
|  | ||||
| @@ -65,10 +65,10 @@ bool CTownInstanceConstructor::objectFilter(const CGObjectInstance * object, con | ||||
| 		return town->hasBuilt(id); | ||||
| 	}; | ||||
|  | ||||
| 	return filters.count(templ.stringID) != 0 && filters.at(templ.stringID).test(buildTest); | ||||
| 	return filters.count(templ->stringID) != 0 && filters.at(templ->stringID).test(buildTest); | ||||
| } | ||||
|  | ||||
| CGObjectInstance * CTownInstanceConstructor::create(const ObjectTemplate & tmpl) const | ||||
| CGObjectInstance * CTownInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	CGTownInstance * obj = createTyped(tmpl); | ||||
| 	obj->town = faction->town; | ||||
| @@ -80,7 +80,7 @@ void CTownInstanceConstructor::configureObject(CGObjectInstance * object, CRando | ||||
| { | ||||
| 	auto templ = getOverride(object->cb->getTile(object->pos)->terType, object); | ||||
| 	if(templ) | ||||
| 		object->appearance = templ.get(); | ||||
| 		object->appearance = templ; | ||||
| } | ||||
|  | ||||
| CHeroInstanceConstructor::CHeroInstanceConstructor() | ||||
| @@ -110,7 +110,7 @@ void CHeroInstanceConstructor::afterLoadFinalization() | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, const ObjectTemplate & templ) const | ||||
| bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, std::shared_ptr<const ObjectTemplate> templ) const | ||||
| { | ||||
| 	auto hero = dynamic_cast<const CGHeroInstance *>(object); | ||||
|  | ||||
| @@ -119,14 +119,14 @@ bool CHeroInstanceConstructor::objectFilter(const CGObjectInstance * object, con | ||||
| 		return hero->type->ID == id; | ||||
| 	}; | ||||
|  | ||||
| 	if(filters.count(templ.stringID)) | ||||
| 	if(filters.count(templ->stringID)) | ||||
| 	{ | ||||
| 		return filters.at(templ.stringID).test(heroTest); | ||||
| 		return filters.at(templ->stringID).test(heroTest); | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CGObjectInstance * CHeroInstanceConstructor::create(const ObjectTemplate & tmpl) const | ||||
| CGObjectInstance * CHeroInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	CGHeroInstance * obj = createTyped(tmpl); | ||||
| 	obj->type = nullptr; //FIXME: set to valid value. somehow. | ||||
| @@ -167,12 +167,12 @@ void CDwellingInstanceConstructor::initTypeData(const JsonNode & input) | ||||
| 	guards = input["guards"]; | ||||
| } | ||||
|  | ||||
| bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, const ObjectTemplate &) const | ||||
| bool CDwellingInstanceConstructor::objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| CGObjectInstance * CDwellingInstanceConstructor::create(const ObjectTemplate & tmpl) const | ||||
| CGObjectInstance * CDwellingInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	CGDwelling * obj = createTyped(tmpl); | ||||
|  | ||||
| @@ -272,7 +272,7 @@ void CBankInstanceConstructor::initTypeData(const JsonNode & input) | ||||
| 	bankResetDuration = static_cast<si32>(input["resetDuration"].Float()); | ||||
| } | ||||
|  | ||||
| CGObjectInstance *CBankInstanceConstructor::create(const ObjectTemplate & tmpl) const | ||||
| CGObjectInstance *CBankInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	return createTyped(tmpl); | ||||
| } | ||||
| @@ -494,7 +494,7 @@ bool CBankInfo::givesSpells() const | ||||
| } | ||||
|  | ||||
|  | ||||
| std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(const ObjectTemplate & tmpl) const | ||||
| std::unique_ptr<IObjectInfo> CBankInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	return std::unique_ptr<IObjectInfo>(new CBankInfo(levels)); | ||||
| } | ||||
|   | ||||
| @@ -26,17 +26,31 @@ template<class ObjectType> | ||||
| class CDefaultObjectTypeHandler : public AObjectTypeHandler | ||||
| { | ||||
| protected: | ||||
| 	ObjectType * createTyped(const ObjectTemplate & tmpl) const | ||||
| 	ObjectType * createTyped(std::shared_ptr<const ObjectTemplate> tmpl /* = nullptr */) const | ||||
| 	{ | ||||
| 		auto obj = new ObjectType(); | ||||
| 		preInitObject(obj); | ||||
| 		obj->appearance = tmpl; | ||||
|  | ||||
| 		if (tmpl) | ||||
| 		{ | ||||
| 			obj->appearance = tmpl; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			auto templates = getTemplates(); | ||||
| 			if (templates.empty()) | ||||
| 			{ | ||||
| 				throw std::runtime_error("No handler for created object"); | ||||
| 			} | ||||
| 			obj->appearance = templates.front(); //just any template for now, will be initialized later | ||||
| 		} | ||||
|  | ||||
| 		return obj; | ||||
| 	} | ||||
| public: | ||||
| 	CDefaultObjectTypeHandler() {} | ||||
|  | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override | ||||
| 	{ | ||||
| 		return createTyped(tmpl); | ||||
| 	} | ||||
| @@ -45,7 +59,7 @@ public: | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override | ||||
| 	virtual std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| @@ -62,7 +76,7 @@ class CTownInstanceConstructor : public CDefaultObjectTypeHandler<CGTownInstance | ||||
| { | ||||
| 	JsonNode filtersJson; | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override; | ||||
| 	bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override; | ||||
| 	void initTypeData(const JsonNode & input) override; | ||||
|  | ||||
| public: | ||||
| @@ -70,7 +84,7 @@ public: | ||||
| 	std::map<std::string, LogicalExpression<BuildingID>> filters; | ||||
|  | ||||
| 	CTownInstanceConstructor(); | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override; | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
| 	void afterLoadFinalization() override; | ||||
|  | ||||
| @@ -87,7 +101,7 @@ class CHeroInstanceConstructor : public CDefaultObjectTypeHandler<CGHeroInstance | ||||
| { | ||||
| 	JsonNode filtersJson; | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override; | ||||
| 	bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate>) const override; | ||||
| 	void initTypeData(const JsonNode & input) override; | ||||
|  | ||||
| public: | ||||
| @@ -95,7 +109,7 @@ public: | ||||
| 	std::map<std::string, LogicalExpression<HeroTypeID>> filters; | ||||
|  | ||||
| 	CHeroInstanceConstructor(); | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override; | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
| 	void afterLoadFinalization() override; | ||||
|  | ||||
| @@ -115,13 +129,13 @@ class CDwellingInstanceConstructor : public CDefaultObjectTypeHandler<CGDwelling | ||||
| 	JsonNode guards; | ||||
|  | ||||
| protected: | ||||
| 	bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const override; | ||||
| 	bool objectFilter(const CGObjectInstance *, std::shared_ptr<const ObjectTemplate> tmpl) const override; | ||||
| 	void initTypeData(const JsonNode & input) override; | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	CDwellingInstanceConstructor(); | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override; | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
|  | ||||
| 	bool producesCreature(const CCreature * crea) const; | ||||
| @@ -207,10 +221,10 @@ public: | ||||
|  | ||||
| 	CBankInstanceConstructor(); | ||||
|  | ||||
| 	CGObjectInstance * create(const ObjectTemplate & tmpl) const override; | ||||
| 	CGObjectInstance * create(std::shared_ptr<const ObjectTemplate> tmpl = nullptr) const override; | ||||
| 	void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override; | ||||
|  | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(const ObjectTemplate & tmpl) const override; | ||||
| 	std::unique_ptr<IObjectInfo> getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const override; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
|   | ||||
| @@ -53,7 +53,9 @@ ObjectTemplate::ObjectTemplate(): | ||||
| 	id(Obj::NO_OBJ), | ||||
| 	subid(0), | ||||
| 	printPriority(0), | ||||
| 	stringID("") | ||||
| 	width(0), | ||||
| 	height(0), | ||||
| 	visitable(false) | ||||
| { | ||||
| } | ||||
|  | ||||
| @@ -65,7 +67,13 @@ ObjectTemplate::ObjectTemplate(const ObjectTemplate& other): | ||||
| 	printPriority(other.printPriority), | ||||
| 	animationFile(other.animationFile), | ||||
| 	editorAnimationFile(other.editorAnimationFile), | ||||
| 	stringID(other.stringID) | ||||
| 	stringID(other.stringID), | ||||
| 	width(other.width), | ||||
| 	height(other.height), | ||||
| 	visitable(other.visitable), | ||||
| 	blockedOffsets(other.blockedOffsets), | ||||
| 	blockMapOffset(other.blockMapOffset), | ||||
| 	visitableOffset(other.visitableOffset) | ||||
| { | ||||
| 	//default copy constructor is failing with usedTiles this for unknown reason | ||||
|  | ||||
| @@ -84,11 +92,18 @@ ObjectTemplate & ObjectTemplate::operator=(const ObjectTemplate & rhs) | ||||
| 	animationFile = rhs.animationFile; | ||||
| 	editorAnimationFile = rhs.editorAnimationFile; | ||||
| 	stringID = rhs.stringID; | ||||
| 	width = rhs.width; | ||||
| 	height = rhs.height; | ||||
| 	visitable = rhs.visitable; | ||||
| 	blockedOffsets = rhs.blockedOffsets; | ||||
| 	blockMapOffset = rhs.blockMapOffset; | ||||
| 	visitableOffset = rhs.visitableOffset; | ||||
|  | ||||
| 	usedTiles.clear(); | ||||
| 	usedTiles.resize(rhs.usedTiles.size()); | ||||
| 	for(size_t i = 0; i < usedTiles.size(); i++) | ||||
| 		std::copy(rhs.usedTiles[i].begin(), rhs.usedTiles[i].end(), std::back_inserter(usedTiles[i])); | ||||
|  | ||||
| 	return *this; | ||||
| } | ||||
|  | ||||
| @@ -121,9 +136,9 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser) | ||||
| 	assert(visitStr.size() == 6*8); | ||||
|  | ||||
| 	setSize(8, 6); | ||||
| 	for (size_t i=0; i<6; i++) // 6 rows | ||||
| 	for(size_t i = 0; i < 6; i++) // 6 rows | ||||
| 	{ | ||||
| 		for (size_t j=0; j<8; j++) // 8 columns | ||||
| 		for(size_t j = 0; j < 8; j++) // 8 columns | ||||
| 		{ | ||||
| 			auto & tile = usedTiles[i][j]; | ||||
| 			tile |= VISIBLE; // assume that all tiles are visible | ||||
| @@ -141,7 +156,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser) | ||||
| 	std::string & terrStr = strings[4]; // allowed terrains, 1 = object can be placed on this terrain | ||||
|  | ||||
| 	assert(terrStr.size() == 9); // all terrains but rock | ||||
| 	for (size_t i=0; i<9; i++) | ||||
| 	for(size_t i = 0; i < 9; i++) | ||||
| 	{ | ||||
| 		if (terrStr[8-i] == '1') | ||||
| 			allowedTerrains.insert(Terrain::createTerrainTypeH3M(i)); | ||||
| @@ -168,6 +183,7 @@ void ObjectTemplate::readTxt(CLegacyConfigParser & parser) | ||||
| 		visitDir = (8|16|32|64|128); | ||||
|  | ||||
| 	readMsk(); | ||||
| 	recalculate(); | ||||
| } | ||||
|  | ||||
| void ObjectTemplate::readMsk() | ||||
| @@ -197,9 +213,9 @@ void ObjectTemplate::readMap(CBinaryReader & reader) | ||||
| 	for(auto & byte : visitMask) | ||||
| 		byte = reader.readUInt8(); | ||||
|  | ||||
| 	for (size_t i=0; i<6; i++) // 6 rows | ||||
| 	for(size_t i = 0; i < 6; i++) // 6 rows | ||||
| 	{ | ||||
| 		for (size_t j=0; j<8; j++) // 8 columns | ||||
| 		for(size_t j = 0; j < 8; j++) // 8 columns | ||||
| 		{ | ||||
| 			auto & tile = usedTiles[5 - i][7 - j]; | ||||
| 			tile |= VISIBLE; // assume that all tiles are visible | ||||
| @@ -213,7 +229,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader) | ||||
|  | ||||
| 	reader.readUInt16(); | ||||
| 	ui16 terrMask = reader.readUInt16(); | ||||
| 	for (size_t i=0; i<9; i++) | ||||
| 	for(size_t i = 0; i < 9; i++) | ||||
| 	{ | ||||
| 		if (((terrMask >> i) & 1 ) != 0) | ||||
| 			allowedTerrains.insert(Terrain::createTerrainTypeH3M(i)); | ||||
| @@ -243,6 +259,7 @@ void ObjectTemplate::readMap(CBinaryReader & reader) | ||||
| 	readMsk(); | ||||
|  | ||||
| 	afterLoadFixup(); | ||||
| 	recalculate(); | ||||
| } | ||||
|  | ||||
| void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain) | ||||
| @@ -288,16 +305,16 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain) | ||||
| 	{ | ||||
| 		switch (ch) | ||||
| 		{ | ||||
| 			case ' ' : return 0; | ||||
| 			case '0' : return 0; | ||||
| 			case 'V' : return VISIBLE; | ||||
| 			case 'B' : return VISIBLE | BLOCKED; | ||||
| 			case 'H' : return BLOCKED; | ||||
| 			case 'A' : return VISIBLE | BLOCKED | VISITABLE; | ||||
| 			case 'T' : return BLOCKED | VISITABLE; | ||||
| 			default: | ||||
| 				logGlobal->error("Unrecognized char %s in template mask", ch); | ||||
| 				return 0; | ||||
| 		case ' ' : return 0; | ||||
| 		case '0' : return 0; | ||||
| 		case 'V' : return VISIBLE; | ||||
| 		case 'B' : return VISIBLE | BLOCKED; | ||||
| 		case 'H' : return BLOCKED; | ||||
| 		case 'A' : return VISIBLE | BLOCKED | VISITABLE; | ||||
| 		case 'T' : return BLOCKED | VISITABLE; | ||||
| 		default: | ||||
| 			logGlobal->error("Unrecognized char %s in template mask", ch); | ||||
| 			return 0; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| @@ -320,6 +337,7 @@ void ObjectTemplate::readJson(const JsonNode &node, const bool withTerrain) | ||||
| 	printPriority = static_cast<si32>(node["zIndex"].Float()); | ||||
|  | ||||
| 	afterLoadFixup(); | ||||
| 	recalculate(); | ||||
| } | ||||
|  | ||||
| void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const | ||||
| @@ -413,38 +431,42 @@ void ObjectTemplate::writeJson(JsonNode & node, const bool withTerrain) const | ||||
| 		node["zIndex"].Float() = printPriority; | ||||
| } | ||||
|  | ||||
| ui32 ObjectTemplate::getWidth() const | ||||
| void ObjectTemplate::calculateWidth() | ||||
| { | ||||
| 	//TODO: Use 2D array | ||||
| 	//TODO: better precalculate and store constant value | ||||
| 	ui32 ret = 0; | ||||
| 	for (const auto &row : usedTiles) //copy is expensive | ||||
| 	for(const auto& row : usedTiles) //copy is expensive | ||||
| 	{ | ||||
| 		ret = std::max<ui32>(ret, (ui32)row.size()); | ||||
| 		width = std::max<ui32>(width, (ui32)row.size()); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| ui32 ObjectTemplate::getHeight() const | ||||
| void ObjectTemplate::calculateHeight() | ||||
| { | ||||
| 	//TODO: Use 2D array | ||||
| 	return static_cast<ui32>(usedTiles.size()); | ||||
| 	height = static_cast<ui32>(usedTiles.size()); | ||||
| } | ||||
|  | ||||
| void ObjectTemplate::setSize(ui32 width, ui32 height) | ||||
| { | ||||
| 	usedTiles.resize(height); | ||||
| 	for (auto & line : usedTiles) | ||||
| 	for(auto & line : usedTiles) | ||||
| 		line.resize(width, 0); | ||||
| } | ||||
|  | ||||
| bool ObjectTemplate::isVisitable() const | ||||
| void ObjectTemplate::calculateVsitable() | ||||
| { | ||||
| 	for (auto & line : usedTiles) | ||||
| 		for (auto & tile : line) | ||||
| 	for(auto& line : usedTiles) | ||||
| 	{ | ||||
| 		for(auto& tile : line) | ||||
| 		{ | ||||
| 			if (tile & VISITABLE) | ||||
| 				return true; | ||||
| 	return false; | ||||
| 			{ | ||||
| 				visitable = true; | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	visitable = false; | ||||
| } | ||||
|  | ||||
| bool ObjectTemplate::isWithin(si32 X, si32 Y) const | ||||
| @@ -469,31 +491,33 @@ bool ObjectTemplate::isBlockedAt(si32 X, si32 Y) const | ||||
| 	return isWithin(X, Y) && usedTiles[Y][X] & BLOCKED; | ||||
| } | ||||
|  | ||||
| std::set<int3> ObjectTemplate::getBlockedOffsets() const | ||||
| void ObjectTemplate::calculateBlockedOffsets() | ||||
| { | ||||
| 	std::set<int3> ret; | ||||
| 	blockedOffsets.clear(); | ||||
| 	for(int w = 0; w < (int)getWidth(); ++w) | ||||
| 	{ | ||||
| 		for(int h = 0; h < (int)getHeight(); ++h) | ||||
| 		{ | ||||
| 			if (isBlockedAt(w, h)) | ||||
| 				ret.insert(int3(-w, -h, 0)); | ||||
| 				blockedOffsets.insert(int3(-w, -h, 0)); | ||||
| 		} | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| int3 ObjectTemplate::getBlockMapOffset() const | ||||
| void ObjectTemplate::calculateBlockMapOffset() | ||||
| { | ||||
| 	for(int w = 0; w < (int)getWidth(); ++w) | ||||
| 	{ | ||||
| 		for(int h = 0; h < (int)getHeight(); ++h) | ||||
| 		{ | ||||
| 			if (isBlockedAt(w, h)) | ||||
| 				return int3(w, h, 0); | ||||
| 			{ | ||||
| 				blockMapOffset = int3(w, h, 0); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return int3(0,0,0); | ||||
| 	blockMapOffset = int3(0, 0, 0); | ||||
| } | ||||
|  | ||||
| bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const | ||||
| @@ -502,6 +526,7 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const | ||||
| 	// 1 2 3 | ||||
| 	// 8   4 | ||||
| 	// 7 6 5 | ||||
| 	//TODO: static? cached? | ||||
| 	int dirMap[3][3] = | ||||
| 	{ | ||||
| 		{ visitDir &   1, visitDir &   2, visitDir &   4 }, | ||||
| @@ -515,22 +540,20 @@ bool ObjectTemplate::isVisitableFrom(si8 X, si8 Y) const | ||||
| 	return dirMap[dy][dx] != 0; | ||||
| } | ||||
|  | ||||
| int3 ObjectTemplate::getVisitableOffset() const | ||||
| void ObjectTemplate::calculateVisitableOffset() | ||||
| { | ||||
| 	for(int y = 0; y < (int)getHeight(); y++) | ||||
| 		for (int x = 0; x < (int)getWidth(); x++) | ||||
| 	{ | ||||
| 		for(int x = 0; x < (int)getWidth(); x++) | ||||
| 		{ | ||||
| 			if (isVisitableAt(x, y)) | ||||
| 				return int3(x,y,0); | ||||
|  | ||||
|     //logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!"); | ||||
| 	return int3(0,0,0); | ||||
| } | ||||
|  | ||||
| bool ObjectTemplate::isVisitableFromTop() const | ||||
| { | ||||
| 	return visitDir & 2; | ||||
| 	//for some reason the line below is never called :? | ||||
| 	//return isVisitableFrom (0, 1); | ||||
| 			{ | ||||
| 				visitableOffset = int3(x, y, 0); | ||||
| 				return; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	visitableOffset = int3(0, 0, 0); | ||||
| } | ||||
|  | ||||
| bool ObjectTemplate::canBePlacedAt(Terrain terrain) const | ||||
| @@ -538,3 +561,14 @@ bool ObjectTemplate::canBePlacedAt(Terrain terrain) const | ||||
| 	return allowedTerrains.count(terrain) != 0; | ||||
| } | ||||
|  | ||||
| void ObjectTemplate::recalculate() | ||||
| { | ||||
| 	calculateWidth(); | ||||
| 	calculateHeight(); | ||||
| 	calculateVsitable(); | ||||
| 	//The lines below use width and height | ||||
| 	calculateBlockedOffsets(); | ||||
| 	calculateBlockMapOffset(); | ||||
| 	calculateVisitableOffset(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -10,6 +10,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../GameConstants.h" | ||||
| #include "../int3.h" | ||||
|  | ||||
| class CBinaryReader; | ||||
| class CLegacyConfigParser; | ||||
| @@ -50,11 +51,22 @@ public: | ||||
| 	/// string ID, equals to def base name for h3m files (lower case, no extension) or specified in mod data | ||||
| 	std::string stringID; | ||||
|  | ||||
| 	ui32 getWidth() const; | ||||
| 	ui32 getHeight() const; | ||||
| 	inline ui32 getWidth() const | ||||
| 	{ | ||||
| 		return width; | ||||
| 	}; | ||||
|  | ||||
| 	inline ui32 getHeight() const | ||||
| 	{  | ||||
| 		return height; | ||||
| 	}; | ||||
|  | ||||
| 	void setSize(ui32 width, ui32 height); | ||||
|  | ||||
| 	bool isVisitable() const; | ||||
| 	inline bool isVisitable() const | ||||
| 	{ | ||||
| 		return visitable; | ||||
| 	}; | ||||
|  | ||||
| 	// Checks object used tiles | ||||
| 	// Position is relative to bottom-right corner of the object, can not be negative | ||||
| @@ -62,13 +74,29 @@ public: | ||||
| 	bool isVisitableAt(si32 X, si32 Y) const; | ||||
| 	bool isVisibleAt(si32 X, si32 Y) const; | ||||
| 	bool isBlockedAt(si32 X, si32 Y) const; | ||||
| 	std::set<int3> getBlockedOffsets() const; | ||||
| 	int3 getBlockMapOffset() const; //bottom-right corner when firts blocked tile is | ||||
|  | ||||
| 	inline std::set<int3> getBlockedOffsets() const | ||||
| 	{ | ||||
| 		return blockedOffsets; | ||||
| 	}; | ||||
|  | ||||
| 	inline int3 getBlockMapOffset() const | ||||
| 	{ | ||||
| 		return blockMapOffset;  | ||||
| 	};  | ||||
|  | ||||
| 	// Checks if object is visitable from certain direction. X and Y must be between -1..+1 | ||||
| 	bool isVisitableFrom(si8 X, si8 Y) const; | ||||
| 	int3 getVisitableOffset() const; | ||||
| 	bool isVisitableFromTop() const; | ||||
| 	inline int3 getVisitableOffset() const | ||||
| 	{ | ||||
| 		//logGlobal->warn("Warning: getVisitableOffset called on non-visitable obj!"); | ||||
| 		return visitableOffset; | ||||
| 	}; | ||||
|  | ||||
| 	inline bool isVisitableFromTop() const | ||||
| 	{ | ||||
| 		return visitDir & 2; | ||||
| 	}; | ||||
|  | ||||
| 	// Checks if object can be placed on specific terrain | ||||
| 	bool canBePlacedAt(Terrain terrain) const; | ||||
| @@ -87,6 +115,25 @@ public: | ||||
|  | ||||
| 	bool operator==(const ObjectTemplate& ot) const { return (id == ot.id && subid == ot.subid); } | ||||
|  | ||||
| private: | ||||
| 	ui32 width; | ||||
| 	ui32 height; | ||||
| 	bool visitable; | ||||
|  | ||||
| 	std::set<int3> blockedOffsets; | ||||
| 	int3 blockMapOffset; | ||||
| 	int3 visitableOffset; | ||||
|  | ||||
| 	void recalculate(); | ||||
|  | ||||
| 	void calculateWidth(); | ||||
| 	void calculateHeight(); | ||||
| 	void calculateVsitable(); | ||||
| 	void calculateBlockedOffsets(); | ||||
| 	void calculateBlockMapOffset(); | ||||
| 	void calculateVisitableOffset(); | ||||
|  | ||||
| public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & usedTiles; | ||||
| @@ -98,6 +145,11 @@ public: | ||||
| 		h & printPriority; | ||||
| 		h & visitDir; | ||||
| 		h & editorAnimationFile; | ||||
|  | ||||
| 		if (!h.saving) | ||||
| 		{ | ||||
| 			recalculate(); | ||||
| 		} | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -146,7 +146,7 @@ public: | ||||
| 	// FIXME: due to usage of JsonNode I can't make these methods const | ||||
| 	const CGHeroInstance * strongestHero(PlayerColor owner); | ||||
| 	std::vector<CGHeroInstance *> getLostCrossoverHeroes(); /// returns a list of crossover heroes which started the scenario, but didn't complete it | ||||
| 	 | ||||
|  | ||||
| 	CCampaignScenario(); | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int formatVersion) | ||||
|   | ||||
| @@ -417,7 +417,7 @@ bool CMap::checkForVisitableDir(const int3 & src, const TerrainTile *pom, const | ||||
| 		if(!vstd::contains(pom->blockingObjects, obj)) //this visitable object is not blocking, ignore | ||||
| 			continue; | ||||
|  | ||||
| 		if (!obj->appearance.isVisitableFrom(src.x - dst.x, src.y - dst.y)) | ||||
| 		if (!obj->appearance->isVisitableFrom(src.x - dst.x, src.y - dst.y)) | ||||
| 			return false; | ||||
| 	} | ||||
| 	return true; | ||||
|   | ||||
| @@ -958,9 +958,9 @@ void CMapLoaderH3M::readDefInfo() | ||||
| 	// Read custom defs | ||||
| 	for(int idd = 0; idd < defAmount; ++idd) | ||||
| 	{ | ||||
| 		ObjectTemplate tmpl; | ||||
| 		tmpl.readMap(reader); | ||||
| 		templates.push_back(tmpl); | ||||
| 		auto tmpl = new ObjectTemplate; | ||||
| 		tmpl->readMap(reader); | ||||
| 		templates.push_back(std::shared_ptr<const ObjectTemplate>(tmpl)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -977,10 +977,10 @@ void CMapLoaderH3M::readObjects() | ||||
| 		int defnum = reader.readUInt32(); | ||||
| 		ObjectInstanceID idToBeGiven = ObjectInstanceID((si32)map->objects.size()); | ||||
|  | ||||
| 		ObjectTemplate & objTempl = templates.at(defnum); | ||||
| 		std::shared_ptr<const ObjectTemplate> objTempl = templates.at(defnum); | ||||
| 		reader.skip(5); | ||||
|  | ||||
| 		switch(objTempl.id) | ||||
| 		switch(objTempl->id) | ||||
| 		{ | ||||
| 		case Obj::EVENT: | ||||
| 			{ | ||||
| @@ -1212,15 +1212,15 @@ void CMapLoaderH3M::readObjects() | ||||
|  | ||||
| 				readMessageAndGuards(art->message, art); | ||||
|  | ||||
| 				if(objTempl.id == Obj::SPELL_SCROLL) | ||||
| 				if(objTempl->id == Obj::SPELL_SCROLL) | ||||
| 				{ | ||||
| 					spellID = reader.readUInt32(); | ||||
| 					artID = ArtifactID::SPELL_SCROLL; | ||||
| 				} | ||||
| 				else if(objTempl.id == Obj::ARTIFACT) | ||||
| 				else if(objTempl->id == Obj::ARTIFACT) | ||||
| 				{ | ||||
| 					//specific artifact | ||||
| 					artID = objTempl.subid; | ||||
| 					artID = objTempl->subid; | ||||
| 				} | ||||
|  | ||||
| 				art->storedArtifact = CArtifactInstance::createArtifact(map, artID, spellID); | ||||
| @@ -1235,7 +1235,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 				readMessageAndGuards(res->message, res); | ||||
|  | ||||
| 				res->amount = reader.readUInt32(); | ||||
| 				if(objTempl.subid == Res::GOLD) | ||||
| 				if(objTempl->subid == Res::GOLD) | ||||
| 				{ | ||||
| 					// Gold is multiplied by 100. | ||||
| 					res->amount *= 100; | ||||
| @@ -1246,7 +1246,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 		case Obj::RANDOM_TOWN: | ||||
| 		case Obj::TOWN: | ||||
| 			{ | ||||
| 				nobj = readTown(objTempl.subid); | ||||
| 				nobj = readTown(objTempl->subid); | ||||
| 				break; | ||||
| 			} | ||||
| 		case Obj::MINE: | ||||
| @@ -1347,7 +1347,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 				auto dwelling = new CGDwelling(); | ||||
| 				nobj = dwelling; | ||||
| 				CSpecObjInfo * spec = nullptr; | ||||
| 				switch(objTempl.id) | ||||
| 				switch(objTempl->id) | ||||
| 				{ | ||||
| 				case Obj::RANDOM_DWELLING: | ||||
| 					spec = new CCreGenLeveledCastleInfo(); | ||||
| @@ -1450,7 +1450,7 @@ void CMapLoaderH3M::readObjects() | ||||
| 			} | ||||
| 		case Obj::PYRAMID: //Pyramid of WoG object | ||||
| 			{ | ||||
| 				if(objTempl.subid == 0) | ||||
| 				if(objTempl->subid == 0) | ||||
| 				{ | ||||
| 					nobj = new CBank(); | ||||
| 				} | ||||
| @@ -1470,13 +1470,13 @@ void CMapLoaderH3M::readObjects() | ||||
| 			} | ||||
| 		default: //any other object | ||||
| 			{ | ||||
| 				if (VLC->objtypeh->knownSubObjects(objTempl.id).count(objTempl.subid)) | ||||
| 				if (VLC->objtypeh->knownSubObjects(objTempl->id).count(objTempl->subid)) | ||||
| 				{ | ||||
| 					nobj = VLC->objtypeh->getHandlerFor(objTempl.id, objTempl.subid)->create(objTempl); | ||||
| 					nobj = VLC->objtypeh->getHandlerFor(objTempl->id, objTempl->subid)->create(objTempl); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl.id.toEnum(), objTempl.subid, objPos.toString(), map->name); | ||||
| 					logGlobal->warn("Unrecognized object: %d:%d at %s on map %s", objTempl->id.toEnum(), objTempl->subid, objPos.toString(), map->name); | ||||
| 					nobj = new CGObjectInstance(); | ||||
| 				} | ||||
| 				break; | ||||
| @@ -1484,11 +1484,11 @@ void CMapLoaderH3M::readObjects() | ||||
| 		} | ||||
|  | ||||
| 		nobj->pos = objPos; | ||||
| 		nobj->ID = objTempl.id; | ||||
| 		nobj->ID = objTempl->id; | ||||
| 		nobj->id = idToBeGiven; | ||||
| 		if(nobj->ID != Obj::HERO && nobj->ID != Obj::HERO_PLACEHOLDER && nobj->ID != Obj::PRISON) | ||||
| 		{ | ||||
| 			nobj->subID = objTempl.subid; | ||||
| 			nobj->subID = objTempl->subid; | ||||
| 		} | ||||
| 		nobj->appearance = objTempl; | ||||
| 		assert(idToBeGiven == ObjectInstanceID((si32)map->objects.size())); | ||||
|   | ||||
| @@ -245,7 +245,7 @@ private: | ||||
|  | ||||
| 	/** List of templates loaded from the map, used on later stage to create | ||||
| 	 *  objects but not needed for fully functional CMap */ | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| 	std::vector<std::shared_ptr<const ObjectTemplate>> templates; | ||||
|  | ||||
| 	/** ptr to the map object which gets filled by data from the buffer */ | ||||
| 	CMap * map; | ||||
|   | ||||
| @@ -1110,13 +1110,14 @@ void CMapLoaderJson::MapObjectLoader::construct() | ||||
|  | ||||
| 	auto handler = VLC->objtypeh->getHandlerFor(typeName, subtypeName); | ||||
|  | ||||
| 	ObjectTemplate appearance; | ||||
| 	auto appearance = new ObjectTemplate; | ||||
|  | ||||
| 	appearance.id = Obj(handler->type); | ||||
| 	appearance.subid = handler->subtype; | ||||
| 	appearance.readJson(configuration["template"], false); | ||||
| 	appearance->id = Obj(handler->type); | ||||
| 	appearance->subid = handler->subtype; | ||||
| 	appearance->readJson(configuration["template"], false); | ||||
|  | ||||
| 	instance = handler->create(appearance); | ||||
| 	// Will be destroyed soon and replaced with shared template | ||||
| 	instance = handler->create(std::shared_ptr<const ObjectTemplate>(appearance)); | ||||
|  | ||||
| 	instance->id = ObjectInstanceID((si32)owner->map->objects.size()); | ||||
| 	instance->instanceName = jsonKey; | ||||
|   | ||||
| @@ -204,8 +204,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c | ||||
| 			auto & managerOther = *otherZone->getModificator<ObjectManager>(); | ||||
| 			 | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::SUBTERRANEAN_GATE, 0); | ||||
| 			auto gate1 = factory->create(ObjectTemplate()); | ||||
| 			auto gate2 = factory->create(ObjectTemplate()); | ||||
| 			auto gate1 = factory->create(); | ||||
| 			auto gate2 = factory->create(); | ||||
| 			rmg::Object rmgGate1(*gate1), rmgGate2(*gate2); | ||||
| 			rmgGate1.setTemplate(zone.getTerrainType()); | ||||
| 			rmgGate2.setTemplate(otherZone->getTerrainType()); | ||||
| @@ -249,8 +249,8 @@ void ConnectionsPlacer::selfSideIndirectConnection(const rmg::ZoneConnection & c | ||||
| 	if(!success) | ||||
| 	{ | ||||
| 		auto factory = VLC->objtypeh->getHandlerFor(Obj::MONOLITH_TWO_WAY, generator.getNextMonlithIndex()); | ||||
| 		auto teleport1 = factory->create(ObjectTemplate()); | ||||
| 		auto teleport2 = factory->create(ObjectTemplate()); | ||||
| 		auto teleport1 = factory->create(); | ||||
| 		auto teleport2 = factory->create(); | ||||
| 		 | ||||
| 		zone.getModificator<ObjectManager>()->addRequiredObject(teleport1, connection.getGuardStrength()); | ||||
| 		otherZone->getModificator<ObjectManager>()->addRequiredObject(teleport2, connection.getGuardStrength()); | ||||
|   | ||||
| @@ -367,7 +367,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD | ||||
| 		objects.push_back(&instance->object()); | ||||
| 		if(auto * m = zone.getModificator<RoadPlacer>()) | ||||
| 		{ | ||||
| 			if(instance->object().appearance.isVisitableFromTop()) | ||||
| 			if(instance->object().appearance->isVisitableFromTop()) | ||||
| 				m->areaForRoads().add(instance->getVisitablePosition()); | ||||
| 			else | ||||
| 			{ | ||||
| @@ -449,7 +449,7 @@ CGCreature * ObjectManager::chooseGuard(si32 strength, bool zoneGuard) | ||||
| 	 | ||||
| 	auto guardFactory = VLC->objtypeh->getHandlerFor(Obj::MONSTER, creId); | ||||
| 	 | ||||
| 	auto guard = (CGCreature *) guardFactory->create(ObjectTemplate()); | ||||
| 	auto guard = (CGCreature *) guardFactory->create(); | ||||
| 	guard->character = CGCreature::HOSTILE; | ||||
| 	auto  hlp = new CStackInstance(creId, amount); | ||||
| 	//will be set during initialization | ||||
|   | ||||
| @@ -31,7 +31,7 @@ void ObstaclePlacer::process() | ||||
| 	 | ||||
| 	auto * riverManager = zone.getModificator<RiverPlacer>(); | ||||
| 	 | ||||
| 	typedef std::vector<ObjectTemplate> ObstacleVector; | ||||
| 	typedef std::vector<std::shared_ptr<const ObjectTemplate>> ObstacleVector; | ||||
| 	//obstacleVector possibleObstacles; | ||||
| 	 | ||||
| 	std::map<int, ObstacleVector> obstaclesBySize; | ||||
| @@ -48,8 +48,8 @@ void ObstaclePlacer::process() | ||||
| 			{ | ||||
| 				for(auto temp : handler->getTemplates()) | ||||
| 				{ | ||||
| 					if(temp.canBePlacedAt(zone.getTerrainType()) && temp.getBlockMapOffset().valid()) | ||||
| 						obstaclesBySize[temp.getBlockedOffsets().size()].push_back(temp); | ||||
| 					if(temp->canBePlacedAt(zone.getTerrainType()) && temp->getBlockMapOffset().valid()) | ||||
| 						obstaclesBySize[temp->getBlockedOffsets().size()].push_back(temp); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -93,7 +93,7 @@ void ObstaclePlacer::process() | ||||
| 			 | ||||
| 			for(auto & temp : shuffledObstacles) | ||||
| 			{ | ||||
| 				auto handler = VLC->objtypeh->getHandlerFor(temp.id, temp.subid); | ||||
| 				auto handler = VLC->objtypeh->getHandlerFor(temp->id, temp->subid); | ||||
| 				auto obj = handler->create(temp); | ||||
| 				allObjects.emplace_back(*obj); | ||||
| 				rmg::Object * rmgObject = &allObjects.back(); | ||||
|   | ||||
| @@ -374,10 +374,10 @@ void RiverPlacer::connectRiver(const int3 & tile) | ||||
| 		auto handler = VLC->objtypeh->getHandlerFor(RIVER_DELTA_ID, RIVER_DELTA_SUBTYPE); | ||||
| 		assert(handler->isStaticObject()); | ||||
| 		 | ||||
| 		std::vector<ObjectTemplate> tmplates; | ||||
| 		std::vector<std::shared_ptr<const ObjectTemplate>> tmplates; | ||||
| 		for(auto & temp : handler->getTemplates()) | ||||
| 		{ | ||||
| 			if(temp.canBePlacedAt(zone.getTerrainType())) | ||||
| 			if(temp->canBePlacedAt(zone.getTerrainType())) | ||||
| 			   tmplates.push_back(temp); | ||||
| 		} | ||||
| 		 | ||||
| @@ -389,7 +389,7 @@ void RiverPlacer::connectRiver(const int3 & tile) | ||||
| 			std::string targetTemplateName = RIVER_DELTA_TEMPLATE_NAME.at(river) + std::to_string(deltaOrientations[pos]) + ".def"; | ||||
| 			for(auto & templ : tmplates) | ||||
| 			{ | ||||
| 				if(templ.animationFile == targetTemplateName) | ||||
| 				if(templ->animationFile == targetTemplateName) | ||||
| 				{ | ||||
| 					auto obj = handler->create(templ); | ||||
| 					rmg::Object deltaObj(*obj, deltaPositions[pos]); | ||||
|   | ||||
| @@ -105,7 +105,7 @@ void Object::Instance::setPositionRaw(const int3 & position) | ||||
|  | ||||
| void Object::Instance::setTemplate(const Terrain & terrain) | ||||
| { | ||||
| 	if(dObject.appearance.id == Obj::NO_OBJ) | ||||
| 	if(dObject.appearance->id == Obj::NO_OBJ) | ||||
| 	{ | ||||
| 		auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrain); | ||||
| 		if(templates.empty()) | ||||
| @@ -130,7 +130,7 @@ void Object::Instance::clear() | ||||
| bool Object::Instance::isVisitableFrom(const int3 & position) const | ||||
| { | ||||
| 	auto relPosition = position - getPosition(true); | ||||
| 	return dObject.appearance.isVisitableFrom(relPosition.x, relPosition.y); | ||||
| 	return dObject.appearance->isVisitableFrom(relPosition.x, relPosition.y); | ||||
| } | ||||
|  | ||||
| CGObjectInstance & Object::Instance::object() | ||||
| @@ -286,7 +286,7 @@ void Object::Instance::finalize(RmgMap & map) | ||||
| 			throw rmgException(boost::to_string(boost::format("Tile %s of object %d at %s is outside the map") % tile.toString() % dObject.id % dObject.pos.toString())); | ||||
| 	} | ||||
| 	 | ||||
| 	if (dObject.appearance.id == Obj::NO_OBJ) | ||||
| 	if (dObject.appearance->id == Obj::NO_OBJ) | ||||
| 	{ | ||||
| 		auto terrainType = map.map().getTile(getPosition(true)).terType; | ||||
| 		auto templates = VLC->objtypeh->getHandlerFor(dObject.ID, dObject.subID)->getTemplates(terrainType); | ||||
|   | ||||
| @@ -69,7 +69,7 @@ void TownPlacer::placeTowns(ObjectManager & manager) | ||||
| 		 | ||||
| 		auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, zone.getTownType()); | ||||
| 		 | ||||
| 		CGTownInstance * town = (CGTownInstance *) townFactory->create(ObjectTemplate()); | ||||
| 		CGTownInstance * town = (CGTownInstance *) townFactory->create(); | ||||
| 		town->tempOwner = player; | ||||
| 		town->builtBuildings.insert(BuildingID::FORT); | ||||
| 		town->builtBuildings.insert(BuildingID::DEFAULT); | ||||
| @@ -163,7 +163,7 @@ bool TownPlacer::placeMines(ObjectManager & manager) | ||||
| 		{ | ||||
| 			auto mineHandler = VLC->objtypeh->getHandlerFor(Obj::MINE, res); | ||||
| 			auto & rmginfo = mineHandler->getRMGInfo(); | ||||
| 			auto mine = (CGMine*)mineHandler->create(ObjectTemplate()); | ||||
| 			auto mine = (CGMine*)mineHandler->create(); | ||||
| 			mine->producedResource = res; | ||||
| 			mine->tempOwner = PlayerColor::NEUTRAL; | ||||
| 			mine->producedQuantity = mine->defaultResProduction(); | ||||
| @@ -184,7 +184,7 @@ bool TownPlacer::placeMines(ObjectManager & manager) | ||||
| 		{ | ||||
| 			for(int rc = generator.rand.nextInt(1, extraRes); rc > 0; --rc) | ||||
| 			{ | ||||
| 				auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(ObjectTemplate()); | ||||
| 				auto resourse = (CGResource*) VLC->objtypeh->getHandlerFor(Obj::RESOURCE, mine->producedResource)->create(); | ||||
| 				resourse->amount = CGResource::RANDOM_AMOUNT; | ||||
| 				manager.addNearbyObject(resourse, mine); | ||||
| 			} | ||||
| @@ -225,7 +225,7 @@ void TownPlacer::addNewTowns(int count, bool hasFort, PlayerColor player, Object | ||||
| 		} | ||||
| 		 | ||||
| 		auto townFactory = VLC->objtypeh->getHandlerFor(Obj::TOWN, subType); | ||||
| 		auto town = (CGTownInstance *) townFactory->create(ObjectTemplate()); | ||||
| 		auto town = (CGTownInstance *) townFactory->create(); | ||||
| 		town->ID = Obj::TOWN; | ||||
| 		 | ||||
| 		town->tempOwner = player; | ||||
|   | ||||
| @@ -59,11 +59,11 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 			{ | ||||
| 				for(auto temp : handler->getTemplates()) | ||||
| 				{ | ||||
| 					if(temp.canBePlacedAt(zone.getTerrainType())) | ||||
| 					if(temp->canBePlacedAt(zone.getTerrainType())) | ||||
| 					{ | ||||
| 						oi.generateObject = [temp]() -> CGObjectInstance * | ||||
| 						{ | ||||
| 							return VLC->objtypeh->getHandlerFor(temp.id, temp.subid)->create(temp); | ||||
| 							return VLC->objtypeh->getHandlerFor(temp->id, temp->subid)->create(temp); | ||||
| 						}; | ||||
| 						auto rmgInfo = handler->getRMGInfo(); | ||||
| 						oi.value = rmgInfo.value; | ||||
| @@ -97,7 +97,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 			 | ||||
| 			auto hid = *RandomGeneratorUtil::nextItem(possibleHeroes, generator.rand); | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PRISON, 0); | ||||
| 			auto obj = (CGHeroInstance *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGHeroInstance *) factory->create(); | ||||
| 			 | ||||
| 			 | ||||
| 			obj->subID = hid; //will be initialized later | ||||
| @@ -159,7 +159,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 				 | ||||
| 				for(auto tmplate : dwellingHandler->getTemplates()) | ||||
| 				{ | ||||
| 					if(tmplate.canBePlacedAt(zone.getTerrainType())) | ||||
| 					if(tmplate->canBePlacedAt(zone.getTerrainType())) | ||||
| 					{ | ||||
| 						oi.generateObject = [tmplate, secondaryID, dwellingType]() -> CGObjectInstance * | ||||
| 						{ | ||||
| @@ -181,7 +181,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [i, this]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::SPELL_SCROLL, 0); | ||||
| 			auto obj = (CGArtifact *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGArtifact *) factory->create(); | ||||
| 			std::vector<SpellID> out; | ||||
| 			 | ||||
| 			for(auto spell : VLC->spellh->objects) //spellh size appears to be greater (?) | ||||
| @@ -207,7 +207,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [i]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(); | ||||
| 			obj->resources[Res::GOLD] = i * 5000; | ||||
| 			return obj; | ||||
| 		}; | ||||
| @@ -223,7 +223,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [i]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(); | ||||
| 			obj->gainedExp = i * 5000; | ||||
| 			return obj; | ||||
| 		}; | ||||
| @@ -275,7 +275,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [creature, creaturesAmount]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(); | ||||
| 			auto stack = new CStackInstance(creature, creaturesAmount); | ||||
| 			obj->creatures.putStack(SlotID(0), stack); | ||||
| 			return obj; | ||||
| @@ -292,7 +292,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [i, this]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(); | ||||
| 			 | ||||
| 			std::vector <CSpell *> spells; | ||||
| 			for(auto spell : VLC->spellh->objects) | ||||
| @@ -321,7 +321,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 		oi.generateObject = [i, this]() -> CGObjectInstance * | ||||
| 		{ | ||||
| 			auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 			auto obj = (CGPandoraBox *) factory->create(); | ||||
| 			 | ||||
| 			std::vector <CSpell *> spells; | ||||
| 			for(auto spell : VLC->spellh->objects) | ||||
| @@ -349,7 +349,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 	oi.generateObject = [this]() -> CGObjectInstance * | ||||
| 	{ | ||||
| 		auto factory = VLC->objtypeh->getHandlerFor(Obj::PANDORAS_BOX, 0); | ||||
| 		auto obj = (CGPandoraBox *) factory->create(ObjectTemplate()); | ||||
| 		auto obj = (CGPandoraBox *) factory->create(); | ||||
| 		 | ||||
| 		std::vector <CSpell *> spells; | ||||
| 		for(auto spell : VLC->spellh->objects) | ||||
| @@ -421,7 +421,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 			oi.generateObject = [creature, creaturesAmount, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
| 				auto obj = (CGSeerHut *) factory->create(); | ||||
| 				obj->rewardType = CGSeerHut::CREATURE; | ||||
| 				obj->rID = creature->idNumber; | ||||
| 				obj->rVal = creaturesAmount; | ||||
| @@ -457,7 +457,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
| 				auto obj = (CGSeerHut *) factory->create(); | ||||
| 				 | ||||
| 				obj->rewardType = CGSeerHut::EXPERIENCE; | ||||
| 				obj->rID = 0; //unitialized? | ||||
| @@ -481,7 +481,7 @@ void TreasurePlacer::addAllPossibleObjects() | ||||
| 			oi.generateObject = [i, randomAppearance, this, generateArtInfo]() -> CGObjectInstance * | ||||
| 			{ | ||||
| 				auto factory = VLC->objtypeh->getHandlerFor(Obj::SEER_HUT, randomAppearance); | ||||
| 				auto obj = (CGSeerHut *) factory->create(ObjectTemplate()); | ||||
| 				auto obj = (CGSeerHut *) factory->create(); | ||||
| 				obj->rewardType = CGSeerHut::RESOURCES; | ||||
| 				obj->rID = Res::GOLD; | ||||
| 				obj->rVal = generator.getConfig().questRewardValues[i]; | ||||
| @@ -525,7 +525,7 @@ std::vector<ObjectInfo*> TreasurePlacer::prepareTreasurePile(const CTreasureInfo | ||||
| 		if(!oi) //fail | ||||
| 			break; | ||||
| 		 | ||||
| 		if(oi->templ.isVisitableFromTop()) | ||||
| 		if(oi->templ->isVisitableFromTop()) | ||||
| 		{ | ||||
| 			objectInfos.push_back(oi); | ||||
| 		} | ||||
| @@ -599,7 +599,7 @@ rmg::Object TreasurePlacer::constructTreasurePile(const std::vector<ObjectInfo*> | ||||
| 			auto instanceAccessibleArea = instance.getAccessibleArea(); | ||||
| 			if(instance.getBlockedArea().getTilesVector().size() == 1) | ||||
| 			{ | ||||
| 				if(instance.object().appearance.isVisitableFromTop() && instance.object().ID != Obj::CORPSE) | ||||
| 				if(instance.object().appearance->isVisitableFromTop() && instance.object().ID != Obj::CORPSE) | ||||
| 					instanceAccessibleArea.add(instance.getVisitablePosition()); | ||||
| 			} | ||||
| 			 | ||||
| @@ -632,7 +632,7 @@ ObjectInfo * TreasurePlacer::getRandomObject(ui32 desiredValue, ui32 currentValu | ||||
| 		if(oi.value > maxVal) | ||||
| 			break; //this assumes values are sorted in ascending order | ||||
| 		 | ||||
| 		if(!oi.templ.isVisitableFromTop() && !allowLargeObjects) | ||||
| 		if(!oi.templ->isVisitableFromTop() && !allowLargeObjects) | ||||
| 			continue; | ||||
| 		 | ||||
| 		if(oi.value >= minValue && oi.maxPerZone > 0) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ class CMapGenerator; | ||||
|  | ||||
| struct ObjectInfo | ||||
| { | ||||
| 	ObjectTemplate templ; | ||||
| 	std::shared_ptr<const ObjectTemplate> templ; | ||||
| 	ui32 value = 0; | ||||
| 	ui16 probability = 0; | ||||
| 	ui32 maxPerZone = -1; | ||||
|   | ||||
| @@ -200,7 +200,7 @@ bool WaterProxy::placeBoat(Zone & land, const Lake & lake, RouteInfo & info) | ||||
| 		return false; | ||||
| 	 | ||||
| 	auto subObjects = VLC->objtypeh->knownSubObjects(Obj::BOAT); | ||||
| 	auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create(ObjectTemplate()); | ||||
| 	auto* boat = (CGBoat*)VLC->objtypeh->getHandlerFor(Obj::BOAT, *RandomGeneratorUtil::nextItem(subObjects, generator.rand))->create(); | ||||
| 	 | ||||
| 	rmg::Object rmgObject(*boat); | ||||
| 	rmgObject.setTemplate(zone.getTerrainType()); | ||||
| @@ -259,7 +259,7 @@ bool WaterProxy::placeShipyard(Zone & land, const Lake & lake, si32 guard, Route | ||||
| 		return false; | ||||
| 	 | ||||
| 	int subtype = chooseRandomAppearance(generator.rand, Obj::SHIPYARD, land.getTerrainType()); | ||||
| 	auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create(ObjectTemplate()); | ||||
| 	auto shipyard = (CGShipyard*) VLC->objtypeh->getHandlerFor(Obj::SHIPYARD, subtype)->create(); | ||||
| 	shipyard->tempOwner = PlayerColor::NEUTRAL; | ||||
| 	 | ||||
| 	rmg::Object rmgObject(*shipyard); | ||||
|   | ||||
| @@ -382,6 +382,56 @@ public: | ||||
| 			else | ||||
| 			{ | ||||
| 				auto hlp = std::shared_ptr<NonConstT>(internalPtr); | ||||
| 				data = hlp; | ||||
| 				loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp); | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 			data.reset(); | ||||
| 	} | ||||
| 	template <typename T> | ||||
| 	void load(std::shared_ptr<const T> &data) //version of the above for const ptr | ||||
| 	{ | ||||
| 		typedef typename std::remove_const<T>::type NonConstT; | ||||
| 		NonConstT *internalPtr; | ||||
| 		load(internalPtr); | ||||
|  | ||||
| 		void *internalPtrDerived = typeList.castToMostDerived(internalPtr); | ||||
|  | ||||
| 		if(internalPtr) | ||||
| 		{ | ||||
| 			auto itr = loadedSharedPointers.find(internalPtrDerived); | ||||
| 			if(itr != loadedSharedPointers.end()) | ||||
| 			{ | ||||
| 				// This pointer is already loaded. The "data" needs to be pointed to it, | ||||
| 				// so their shared state is actually shared. | ||||
| 				try | ||||
| 				{ | ||||
| 					auto actualType = typeList.getTypeInfo(internalPtr); | ||||
| 					auto typeWeNeedToReturn = typeList.getTypeInfo<T>(); | ||||
| 					if(*actualType == *typeWeNeedToReturn) | ||||
| 					{ | ||||
| 						// No casting needed, just unpack already stored shared_ptr and return it | ||||
| 						data = boost::any_cast<std::shared_ptr<const T>>(itr->second); | ||||
| 					} | ||||
| 					else | ||||
| 					{ | ||||
| 						// We need to perform series of casts | ||||
| 						auto ret = typeList.castShared(itr->second, actualType, typeWeNeedToReturn); | ||||
| 						data = boost::any_cast<std::shared_ptr<const T>>(ret); | ||||
| 					} | ||||
| 				} | ||||
| 				catch(std::exception &e) | ||||
| 				{ | ||||
| 					logGlobal->error(e.what()); | ||||
| 					logGlobal->error("Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME", itr->second.type().name(), typeid(std::shared_ptr<T>).name()); | ||||
| 					//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa) | ||||
| 					throw; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				auto hlp = std::shared_ptr<const T>(internalPtr); | ||||
| 				data = hlp; //possibly adds const | ||||
| 				loadedSharedPointers[internalPtrDerived] = typeList.castSharedToMostDerived(hlp); | ||||
| 			} | ||||
|   | ||||
| @@ -245,6 +245,12 @@ public: | ||||
| 		save(internalPtr); | ||||
| 	} | ||||
| 	template <typename T> | ||||
| 	void save(const std::shared_ptr<const T> &data) | ||||
| 	{ | ||||
| 		const T *internalPtr = data.get(); | ||||
| 		save(internalPtr); | ||||
| 	} | ||||
| 	template <typename T> | ||||
| 	void save(const std::unique_ptr<T> &data) | ||||
| 	{ | ||||
| 		T *internalPtr = data.get(); | ||||
|   | ||||
| @@ -12,8 +12,8 @@ | ||||
| #include "../ConstTransitivePtr.h" | ||||
| #include "../GameConstants.h" | ||||
|  | ||||
| const ui32 SERIALIZATION_VERSION = 803; | ||||
| const ui32 MINIMAL_SERIALIZATION_VERSION = 803; | ||||
| const ui32 SERIALIZATION_VERSION = 804; | ||||
| const ui32 MINIMAL_SERIALIZATION_VERSION = 804; | ||||
| const std::string SAVEGAME_MAGIC = "VCMISVG"; | ||||
|  | ||||
| class CHero; | ||||
|   | ||||
| @@ -1017,4 +1017,4 @@ std::vector<bool> CSpellHandler::getDefaultAllowed() const | ||||
| 	} | ||||
|  | ||||
| 	return allowedSpells; | ||||
| } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user