mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Object class handler is now a proper "handler"
- Some changes in interfaces - Fixed some missing fields in serialization - Moved object names to new handler
This commit is contained in:
		| @@ -23,7 +23,7 @@ class CBuildingHandler; | ||||
| class CObjectHandler; | ||||
| class CSoundHandler; | ||||
| class CMusicHandler; | ||||
| class CObjectTypesHandler; | ||||
| class CObjectClassesHandler; | ||||
| class CTownHandler; | ||||
| class CGeneralTextHandler; | ||||
| class CConsoleHandler; | ||||
| @@ -57,7 +57,7 @@ public: | ||||
| 	ConstTransitivePtr<CCreatureHandler> creh; | ||||
| 	ConstTransitivePtr<CSpellHandler> spellh; | ||||
| 	ConstTransitivePtr<CObjectHandler> objh; | ||||
| 	ConstTransitivePtr<CObjectTypesHandler> objtypeh; | ||||
| 	ConstTransitivePtr<CObjectClassesHandler> objtypeh; | ||||
| 	CGeneralTextHandler * generaltexth; | ||||
| 	CMapHandler * mh; | ||||
| 	CTownHandler * townh; | ||||
|   | ||||
| @@ -1073,7 +1073,7 @@ void CMapHandler::getTerrainDescr( const int3 &pos, std::string & out, bool terN | ||||
| 	} | ||||
|  | ||||
| 	if(t.hasFavourableWinds()) | ||||
| 		out = CGI->generaltexth->names[Obj::FAVORABLE_WINDS]; | ||||
| 		out = CGI->objtypeh->getObjectName(Obj::FAVORABLE_WINDS); | ||||
| 	else if(terName) | ||||
|         out = CGI->generaltexth->terrainNames[t.terType]; | ||||
| } | ||||
|   | ||||
| @@ -11,6 +11,8 @@ | ||||
| #include "CModHandler.h" | ||||
| #include "JsonNode.h" | ||||
|  | ||||
| #include "CObjectConstructor.h" | ||||
|  | ||||
| /* | ||||
|  * CDefObjInfoHandler.cpp, part of VCMI engine | ||||
|  * | ||||
| @@ -350,29 +352,153 @@ CDefObjInfoHandler::CDefObjInfoHandler() | ||||
| 	readTextFile("Data/Heroes.txt"); | ||||
| } | ||||
| */ | ||||
| void CObjectTypesHandler::init() | ||||
| { | ||||
|  | ||||
| CObjectClassesHandler::CObjectClassesHandler() | ||||
| { | ||||
| 	// list of all known handlers, hardcoded for now since the only way to add new objects is via C++ code | ||||
| 	handlerConstructors["configurable"] = std::make_shared<CObjectWithRewardConstructor>; | ||||
|  | ||||
| #define SET_HANDLER(STRING, TYPENAME) handlerConstructors[STRING] = std::make_shared<CDefaultObjectTypeHandler<TYPENAME> > | ||||
|  | ||||
| 	SET_HANDLER("", CGObjectInstance); | ||||
| 	SET_HANDLER("generic", CGObjectInstance); | ||||
|  | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("bank", CBank); | ||||
| 	SET_HANDLER("cartographer", CCartographer); | ||||
| 	SET_HANDLER("artifact", CGArtifact); | ||||
| 	SET_HANDLER("blackMarket", CGBlackMarket); | ||||
| 	SET_HANDLER("boat", CGBoat); | ||||
| 	SET_HANDLER("bonusingObject", CGBonusingObject); | ||||
| 	SET_HANDLER("borderGate", CGBorderGate); | ||||
| 	SET_HANDLER("borderGuard", CGBorderGuard); | ||||
| 	SET_HANDLER("monster", CGCreature); | ||||
| 	SET_HANDLER("denOfThieves", CGDenOfthieves); | ||||
| 	SET_HANDLER("dwelling", CGDwelling); | ||||
| 	SET_HANDLER("event", CGEvent); | ||||
| 	SET_HANDLER("garrison", CGGarrison); | ||||
| 	SET_HANDLER("hero", CGHeroInstance); | ||||
| 	SET_HANDLER("heroPlaceholder", CGHeroPlaceholder); | ||||
| 	SET_HANDLER("keymaster", CGKeymasterTent); | ||||
| 	SET_HANDLER("lighthouse", CGLighthouse); | ||||
| 	SET_HANDLER("magi", CGMagi); | ||||
| 	SET_HANDLER("magicSpring", CGMagicSpring); | ||||
| 	SET_HANDLER("magicWell", CGMagicWell); | ||||
| 	SET_HANDLER("market", CGMarket); | ||||
| 	SET_HANDLER("mine", CGMine); | ||||
| 	SET_HANDLER("obelisk", CGObelisk); | ||||
| 	SET_HANDLER("observatory", CGObservatory); | ||||
| 	SET_HANDLER("onceVisitable", CGOnceVisitable); | ||||
| 	SET_HANDLER("pandora", CGPandoraBox); | ||||
| 	SET_HANDLER("pickable", CGPickable); | ||||
| 	SET_HANDLER("pyramid", CGPyramid); | ||||
| 	SET_HANDLER("questGuard", CGQuestGuard); | ||||
| 	SET_HANDLER("resource", CGResource); | ||||
| 	SET_HANDLER("scholar", CGScholar); | ||||
| 	SET_HANDLER("seerHut", CGSeerHut); | ||||
| 	SET_HANDLER("shipyard", CGShipyard); | ||||
| 	SET_HANDLER("shrine", CGShrine); | ||||
| 	SET_HANDLER("sign", CGSignBottle); | ||||
| 	SET_HANDLER("siren", CGSirens); | ||||
| 	SET_HANDLER("teleport", CGTeleport); | ||||
| 	SET_HANDLER("town", CGTownInstance); | ||||
| 	SET_HANDLER("university", CGUniversity); | ||||
| 	SET_HANDLER("oncePerHero", CGVisitableOPH); | ||||
| 	SET_HANDLER("oncePerWeek", CGVisitableOPW); | ||||
| 	SET_HANDLER("witch", CGWitchHut); | ||||
|  | ||||
| #undef SET_HANDLER | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectTypesHandler::getHandlerFor(si32 type, si32 subtype) const | ||||
| static std::vector<JsonNode> readTextFile(std::string path) | ||||
| { | ||||
| 	if (objectTypes.count(type)) | ||||
| 	//TODO | ||||
| } | ||||
|  | ||||
| std::vector<JsonNode> CObjectClassesHandler::loadLegacyData(size_t dataSize) | ||||
| { | ||||
| 	std::vector<JsonNode> ret(dataSize);// create storage for 256 objects | ||||
|  | ||||
| 	auto parseFile = [&](std::string filename) | ||||
| 	{ | ||||
| 		if (objectTypes.at(type).count(subtype)) | ||||
| 			return objectTypes.at(type).at(subtype); | ||||
| 		auto entries = readTextFile(filename); | ||||
| 		for (JsonNode & entry : entries) | ||||
| 		{ | ||||
| 			si32 id = entry["basebase"].Float(); | ||||
| 			si32 subid = entry["base"].Float(); | ||||
|  | ||||
| 			entry.Struct().erase("basebase"); | ||||
| 			entry.Struct().erase("base"); | ||||
|  | ||||
| 			if (ret[id].Vector().size() <= subid) | ||||
| 				ret[id].Vector().resize(subid+1); | ||||
| 			ret[id]["legacyTypes"].Vector()[subid][entry["animation"].String()].swap(entry); | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	parseFile("Data/Objects.txt"); | ||||
| 	parseFile("Data/Heroes.txt"); | ||||
|  | ||||
| 	CLegacyConfigParser parser("Data/ObjNames.txt"); | ||||
| 	for (size_t i=0; i<256; i++) | ||||
| 	{ | ||||
| 		ret[i]["name"].String() = parser.readString(); | ||||
| 		parser.endLine(); | ||||
| 	} | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| CObjectClassesHandler::ObjectContainter * CObjectClassesHandler::loadFromJson(const JsonNode & json) | ||||
| { | ||||
| 	auto obj = new ObjectContainter(); | ||||
| 	obj->name = json["name"].String(); | ||||
| 	obj->handlerName = json["handler"].String(); | ||||
| 	obj->base = json["base"]; | ||||
| 	for (auto entry : json["types"].Struct()) | ||||
| 	{ | ||||
| 		auto handler = handlerConstructors.at(obj->handlerName)(); | ||||
| 		handler->init(entry.second); | ||||
| 	} | ||||
| 	return obj; | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data) | ||||
| { | ||||
| } | ||||
|  | ||||
| void CObjectClassesHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) | ||||
| { | ||||
| } | ||||
|  | ||||
| std::vector<bool> CObjectClassesHandler::getDefaultAllowed() const | ||||
| { | ||||
| 	return std::vector<bool>(); //TODO? | ||||
| } | ||||
|  | ||||
| TObjectTypeHandler CObjectClassesHandler::getHandlerFor(si32 type, si32 subtype) const | ||||
| { | ||||
| 	if (objects.count(type)) | ||||
| 	{ | ||||
| 		if (objects.at(type)->objects.count(subtype)) | ||||
| 			return objects.at(type)->objects.at(subtype); | ||||
| 	} | ||||
| 	assert(0); // FIXME: throw error? | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::init(si32 type, si32 subtype) | ||||
| std::string CObjectClassesHandler::getObjectName(si32 type) const | ||||
| { | ||||
| 	assert(objects.count(type)); | ||||
| 	return objects.at(type)->name; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::setType(si32 type, si32 subtype) | ||||
| { | ||||
| 	this->type = type; | ||||
| 	this->subtype = subtype; | ||||
| } | ||||
|  | ||||
| void AObjectTypeHandler::load(const JsonNode & input) | ||||
| void AObjectTypeHandler::init(const JsonNode & input) | ||||
| { | ||||
| 	for (auto entry : input["templates"].Struct()) | ||||
| 	{ | ||||
| @@ -416,7 +542,7 @@ std::vector<ObjectTemplate> AObjectTypeHandler::getTemplates(si32 terrainType) c | ||||
| 	return filtered.empty() ? ret : filtered; | ||||
| } | ||||
|  | ||||
| ObjectTemplate AObjectTypeHandler::selectTemplate(si32 terrainType, CGObjectInstance * object) const | ||||
| boost::optional<ObjectTemplate> AObjectTypeHandler::getOverride(si32 terrainType, const CGObjectInstance * object) const | ||||
| { | ||||
| 	std::vector<ObjectTemplate> ret = getTemplates(terrainType); | ||||
| 	for (auto & tmpl : ret) | ||||
| @@ -424,6 +550,5 @@ ObjectTemplate AObjectTypeHandler::selectTemplate(si32 terrainType, CGObjectInst | ||||
| 		if (objectFilter(object, tmpl)) | ||||
| 			return tmpl; | ||||
| 	} | ||||
| 	// FIXME: no matches found. Warn? Ask for torches? Die? | ||||
| 	return ret.front(); | ||||
| 	return boost::optional<ObjectTemplate>(); | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| #include "GameConstants.h" | ||||
| #include "../lib/ConstTransitivePtr.h" | ||||
| #include "IHandlerBase.h" | ||||
|  | ||||
| /* | ||||
|  * CDefObjInfoHandler.h, part of VCMI engine | ||||
| @@ -105,15 +106,17 @@ class AObjectTypeHandler | ||||
| 	si32 type; | ||||
| 	si32 subtype; | ||||
|  | ||||
| 	JsonNode base; /// describes base template | ||||
|  | ||||
| 	std::vector<ObjectTemplate> templates; | ||||
| protected: | ||||
| 	void init(si32 type, si32 subtype); | ||||
|  | ||||
| 	/// loads templates from Json structure using fields "base" and "templates" | ||||
| 	void load(const JsonNode & input); | ||||
| 	void setType(si32 type, si32 subtype); | ||||
|  | ||||
| 	virtual bool objectFilter(const CGObjectInstance *, const ObjectTemplate &) const; | ||||
| public: | ||||
| 	/// loads templates from Json structure using fields "base" and "templates" | ||||
| 	virtual void init(const JsonNode & input); | ||||
|  | ||||
| 	void addTemplate(const ObjectTemplate & templ); | ||||
|  | ||||
| 	/// returns all templates, without any filters | ||||
| @@ -122,35 +125,96 @@ public: | ||||
| 	/// returns all templates that can be placed on specific terrain type | ||||
| 	std::vector<ObjectTemplate> getTemplates(si32 terrainType) const; | ||||
|  | ||||
| 	/// returns template suitable for object. If returned template is not equal to current one | ||||
| 	/// it must be replaced with this one (and properly updated on all clients) | ||||
| 	ObjectTemplate selectTemplate(si32 terrainType, CGObjectInstance * object) const; | ||||
|  | ||||
| 	/// returns preferred template for this object, if present (e.g. one of 3 possible templates for town - village, fort and castle) | ||||
| 	/// note that appearance will not be changed - this must be done separately (either by assignment or via pack from server) | ||||
| 	boost::optional<ObjectTemplate> getOverride(si32 terrainType, const CGObjectInstance * object) const; | ||||
|  | ||||
| 	/// Creates object and set up core properties (like ID/subID). Object is NOT initialized | ||||
| 	/// to allow creating objects before game start (e.g. map loading) | ||||
| 	virtual CGObjectInstance * create(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	/// Configures object properties. Should be re-entrable, resetting state of the object if necessarily | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const = 0; | ||||
|  | ||||
| 	/// Returns object configuration, if available. Othervice returns NULL | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const = 0; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & type & subtype & templates; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| template<class ObjectType> | ||||
| class CDefaultObjectTypeHandler : public AObjectTypeHandler | ||||
| { | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		auto obj = new ObjectType(); | ||||
| 		obj->ID = tmpl.id; | ||||
| 		obj->subID = tmpl.subid; | ||||
| 		obj->appearance = tmpl; | ||||
| 		return obj; | ||||
| 	} | ||||
|  | ||||
| 	virtual void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	virtual const IObjectInfo * getObjectInfo(ObjectTemplate tmpl) const | ||||
| 	{ | ||||
| 		return nullptr; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| typedef std::shared_ptr<AObjectTypeHandler> TObjectTypeHandler; | ||||
|  | ||||
| class CObjectTypesHandler | ||||
| class DLL_LINKAGE CObjectClassesHandler : public IHandlerBase | ||||
| { | ||||
| 	/// list of object handlers, each of them handles only one type | ||||
| 	std::map<si32, std::map<si32, TObjectTypeHandler> > objectTypes; | ||||
| 	/// Small internal structure that contains information on specific group of objects | ||||
| 	/// (creating separate entity is overcomplicating at least at this point) | ||||
| 	struct ObjectContainter | ||||
| 	{ | ||||
| 		si32 id; | ||||
|  | ||||
| 		std::string name; // human-readable name | ||||
| 		std::string handlerName; // ID of handler that controls this object, shoul be determined using hadlerConstructor map | ||||
|  | ||||
| 		JsonNode base; | ||||
| 		std::map<si32, TObjectTypeHandler> objects; | ||||
|  | ||||
| 		template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 		{ | ||||
| 			h & base & objects; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	/// list of object handlers, each of them handles only one type | ||||
| 	std::map<si32, ObjectContainter * > objects; | ||||
|  | ||||
| 	/// map that is filled during contruction with all known handlers. Not serializeable | ||||
| 	std::map<std::string, std::function<TObjectTypeHandler()> > handlerConstructors; | ||||
|  | ||||
| 	ObjectContainter * loadFromJson(const JsonNode & json); | ||||
| public: | ||||
| 	void init(); | ||||
| 	CObjectClassesHandler(); | ||||
|  | ||||
| 	virtual std::vector<JsonNode> loadLegacyData(size_t dataSize); | ||||
|  | ||||
| 	virtual void loadObject(std::string scope, std::string name, const JsonNode & data); | ||||
| 	virtual void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index); | ||||
|  | ||||
| 	virtual void afterLoadFinalization(){}; | ||||
|  | ||||
| 	virtual std::vector<bool> getDefaultAllowed() const; | ||||
|  | ||||
| 	/// returns handler for specified object (ID-based). ObjectHandler keeps ownership | ||||
| 	TObjectTypeHandler getHandlerFor(si32 type, si32 subtype) const; | ||||
|  | ||||
| 	std::string getObjectName(si32 type) const; | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		//h & objects; | ||||
| 		if (!h.saving) | ||||
| 			init(); // TODO: implement serialization | ||||
| 		h & objects; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -166,6 +166,10 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 	{ | ||||
| 		dst = VLC->arth->artifacts[ser]->EventText(); | ||||
| 	} | ||||
| 	else if (type == OBJ_NAMES) | ||||
| 	{ | ||||
| 		dst = VLC->objtypeh->getObjectName(ser); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		std::vector<std::string> *vec; | ||||
| @@ -177,9 +181,6 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst | ||||
| 		case XTRAINFO_TXT: | ||||
| 			vec = &VLC->generaltexth->xtrainfo; | ||||
| 			break; | ||||
| 		case OBJ_NAMES: | ||||
| 			vec = &VLC->generaltexth->names; | ||||
| 			break; | ||||
| 		case RES_NAMES: | ||||
| 			vec = &VLC->generaltexth->restypes; | ||||
| 			break; | ||||
| @@ -651,58 +652,25 @@ void CGameState::randomizeObject(CGObjectInstance *cur) | ||||
| 	std::pair<Obj,int> ran = pickObject(cur); | ||||
| 	if(ran.first == Obj::NO_OBJ || ran.second<0) //this is not a random object, or we couldn't find anything | ||||
| 	{ | ||||
| 		if(cur->ID==Obj::TOWN) //town - set def | ||||
| 		{ | ||||
| 			const TerrainTile &tile = map->getTile(cur->visitablePos()); | ||||
| 			CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur); | ||||
| 			t->town = VLC->townh->factions[t->subID]->town; | ||||
| 			t->appearance = VLC->objtypeh->getHandlerFor(Obj::TOWN, t->subID)->selectTemplate(tile.terType, t); | ||||
| 			t->updateAppearance(); | ||||
| 		} | ||||
| 		if(cur->ID==Obj::TOWN) | ||||
| 			cur->setType(cur->ID, cur->subID); // update def, if necessary | ||||
| 		return; | ||||
| 	} | ||||
| 	else if(ran.first==Obj::HERO)//special code for hero | ||||
| 	{ | ||||
| 		CGHeroInstance *h = dynamic_cast<CGHeroInstance *>(cur); | ||||
|         if(!h) {logGlobal->warnStream()<<"Wrong random hero at "<<cur->pos; return;} | ||||
| 		cur->ID = ran.first; | ||||
| 		cur->subID = ran.second; | ||||
| 		h->type = VLC->heroh->heroes[ran.second]; | ||||
| 		h->portrait = h->type->imageIndex; | ||||
| 		h->randomizeArmy(h->type->heroClass->faction); | ||||
| 		cur->setType(ran.first, ran.second); | ||||
| 		map->heroesOnMap.push_back(h); | ||||
| 		return; //TODO: maybe we should do something with definfo? | ||||
| 		return; | ||||
| 	} | ||||
| 	else if(ran.first==Obj::TOWN)//special code for town | ||||
| 	{ | ||||
| 		const TerrainTile &tile = map->getTile(cur->visitablePos()); | ||||
| 		CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur); | ||||
| 		if(!t) {logGlobal->warnStream()<<"Wrong random town at "<<cur->pos; return;} | ||||
| 		cur->ID = ran.first; | ||||
| 		cur->subID = ran.second; | ||||
| 		//FIXME: copy-pasted from above | ||||
| 		t->town = VLC->townh->factions[t->subID]->town; | ||||
| 		t->appearance = VLC->objtypeh->getHandlerFor(Obj::TOWN, t->subID)->selectTemplate(tile.terType, t); | ||||
| 		t->updateAppearance(); | ||||
|  | ||||
| 		t->randomizeArmy(t->subID); | ||||
| 		cur->setType(ran.first, ran.second); | ||||
| 		map->towns.push_back(t); | ||||
| 		return; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (ran.first  != cur->appearance.id || | ||||
| 			ran.second != cur->appearance.subid) | ||||
| 		{ | ||||
| 			const TerrainTile &tile = map->getTile(cur->visitablePos()); | ||||
| 			cur->appearance = VLC->objtypeh->getHandlerFor(ran.first, ran.second)->selectTemplate(tile.terType, cur); | ||||
| 		} | ||||
| 	} | ||||
| 	//we have to replace normal random object | ||||
| 	cur->ID = ran.first; | ||||
| 	cur->subID = ran.second; | ||||
| 	map->removeBlockVisTiles(cur, true); //recalculate blockvis tiles - picked object might have different than random placeholder | ||||
| 	map->addBlockVisTiles(cur); | ||||
| 	cur->setType(ran.first, ran.second); | ||||
| } | ||||
|  | ||||
| int CGameState::getDate(Date::EDateType mode) const | ||||
| @@ -1078,7 +1046,7 @@ void CGameState::randomizeMapObjects() | ||||
| 		if(!obj) continue; | ||||
|  | ||||
| 		randomizeObject(obj); | ||||
| 		obj->hoverName = VLC->generaltexth->names[obj->ID]; | ||||
| 		obj->hoverName = VLC->objtypeh->getObjectName(obj->ID); | ||||
|  | ||||
| 		//handle Favouring Winds - mark tiles under it | ||||
| 		if(obj->ID == Obj::FAVORABLE_WINDS) | ||||
|   | ||||
| @@ -287,7 +287,6 @@ CGeneralTextHandler::CGeneralTextHandler() | ||||
| 	readToVector("DATA/HEROSCRN.TXT", heroscrn); | ||||
| 	readToVector("DATA/TENTCOLR.TXT", tentColors); | ||||
| 	readToVector("DATA/SKILLLEV.TXT", levels); | ||||
| 	readToVector("DATA/OBJNAMES.TXT", names); | ||||
|  | ||||
| 	localizedTexts = JsonNode(ResourceID("config/translate.json", EResType::TEXT)); | ||||
|  | ||||
|   | ||||
| @@ -112,7 +112,6 @@ public: | ||||
| 	std::vector<std::string> victoryConditions; | ||||
|  | ||||
| 	//objects | ||||
| 	std::vector<std::string> names; //vector of objects; i-th object in vector has subnumber i | ||||
| 	std::vector<std::string> creGens; //names of creatures' generators | ||||
| 	std::vector<std::string> creGens4; //names of multiple creatures' generators | ||||
| 	std::vector<std::string> advobtxt; | ||||
|   | ||||
| @@ -138,8 +138,32 @@ void CRandomRewardObjectInfo::init(const JsonNode & objectConfig) | ||||
|  | ||||
| void CRandomRewardObjectInfo::configureObject(CObjectWithReward * object, CRandomGenerator & rng) const | ||||
| { | ||||
| 	std::map<si32, si32> thrownDice; | ||||
|  | ||||
| 	for (const JsonNode & reward : parameters["rewards"].Vector()) | ||||
| 	{ | ||||
| 		if (!reward["appearChance"].isNull()) | ||||
| 		{ | ||||
| 			JsonNode chance = reward["appearChance"]; | ||||
| 			si32 diceID = chance["dice"].Float(); | ||||
|  | ||||
| 			if (thrownDice.count(diceID) == 0) | ||||
| 				thrownDice[diceID] = rng.getIntRange(1, 100)(); | ||||
|  | ||||
| 			if (!chance["min"].isNull()) | ||||
| 			{ | ||||
| 				int min = chance["min"].Float(); | ||||
| 				if (min > thrownDice[diceID]) | ||||
| 					continue; | ||||
| 			} | ||||
| 			if (!chance["max"].isNull()) | ||||
| 			{ | ||||
| 				int max = chance["max"].Float(); | ||||
| 				if (max < thrownDice[diceID]) | ||||
| 					continue; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		const JsonNode & limiter = reward["limiter"]; | ||||
| 		CVisitInfo info; | ||||
| 		// load limiter | ||||
| @@ -172,6 +196,9 @@ void CRandomRewardObjectInfo::configureObject(CObjectWithReward * object, CRando | ||||
| 		info.reward.artifacts = loadArtifacts(reward["artifacts"], rng); | ||||
| 		info.reward.spells = loadSpells(reward["spells"], rng); | ||||
| 		info.reward.creatures = loadCreatures(reward["creatures"], rng); | ||||
|  | ||||
| 		info.message = loadMessage(reward["message"]); | ||||
| 		info.selectChance = loadValue(reward["selectChance"], rng); | ||||
| 	} | ||||
|  | ||||
| 	object->onSelect  = loadMessage(parameters["onSelectMessage"]); | ||||
| @@ -241,6 +268,7 @@ CObjectWithRewardConstructor::CObjectWithRewardConstructor() | ||||
|  | ||||
| void CObjectWithRewardConstructor::init(const JsonNode & config) | ||||
| { | ||||
| 	AObjectTypeHandler::init(config); | ||||
| 	objectInfo.init(config); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -47,7 +47,7 @@ class CObjectWithRewardConstructor : public AObjectTypeHandler | ||||
|  | ||||
| public: | ||||
| 	CObjectWithRewardConstructor(); | ||||
| 	void init(const JsonNode & config); | ||||
| 	void init(const JsonNode & config) override; | ||||
|  | ||||
| 	CGObjectInstance * create(ObjectTemplate tmpl) const override; | ||||
|  | ||||
|   | ||||
| @@ -372,6 +372,19 @@ bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const  //screen p | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void CGObjectInstance::setType(si32 ID, si32 subID) | ||||
| { | ||||
| 	const TerrainTile &tile = cb->gameState()->map->getTile(visitablePos()); | ||||
|  | ||||
| 	this->ID = Obj(ID); | ||||
| 	this->subID = subID; | ||||
| 	this->appearance = VLC->objtypeh->getHandlerFor(ID, subID)->getTemplates(tile.terType).front(); | ||||
|  | ||||
| 	//recalculate blockvis tiles - new appearance might have different blockmap than before | ||||
| 	cb->gameState()->map->removeBlockVisTiles(this, true); | ||||
| 	cb->gameState()->map->addBlockVisTiles(this); | ||||
| } | ||||
|  | ||||
| void CGObjectInstance::initObj() | ||||
| { | ||||
| 	switch(ID) | ||||
| @@ -456,7 +469,7 @@ int3 CGObjectInstance::getVisitableOffset() const | ||||
| void CGObjectInstance::getNameVis( std::string &hname ) const | ||||
| { | ||||
| 	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); | ||||
| 	hname = VLC->generaltexth->names[ID]; | ||||
| 	hname = VLC->objtypeh->getObjectName(ID); | ||||
| 	if(h) | ||||
| 	{ | ||||
| 		const bool visited = h->hasBonusFrom(Bonus::OBJECT,ID); | ||||
| @@ -720,6 +733,15 @@ void CGHeroInstance::initHero(HeroTypeID SUBID) | ||||
| 	initHero(); | ||||
| } | ||||
|  | ||||
| void CGHeroInstance::setType(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(ID == Obj::HERO); // just in case | ||||
| 	CGObjectInstance::setType(ID, subID); | ||||
| 	type = VLC->heroh->heroes[subID]; | ||||
| 	portrait = type->imageIndex; | ||||
| 	randomizeArmy(type->heroClass->faction); | ||||
| } | ||||
|  | ||||
| void CGHeroInstance::initHero() | ||||
| { | ||||
| 	assert(validTypes(true)); | ||||
| @@ -913,7 +935,7 @@ const std::string & CGHeroInstance::getHoverText() const | ||||
| 		return hoverName; | ||||
| 	} | ||||
| 	else | ||||
| 		hoverName = VLC->generaltexth->names[ID]; | ||||
| 		hoverName = VLC->objtypeh->getObjectName(ID); | ||||
|  | ||||
| 	return hoverName; | ||||
| } | ||||
| @@ -2497,6 +2519,15 @@ std::vector<int> CGTownInstance::availableItemsIds(EMarketMode::EMarketMode mode | ||||
| 		return IMarket::availableItemsIds(mode); | ||||
| } | ||||
|  | ||||
| void CGTownInstance::setType(si32 ID, si32 subID) | ||||
| { | ||||
| 	assert(ID == Obj::TOWN); // just in case | ||||
| 	CGObjectInstance::setType(ID, subID); | ||||
| 	town = VLC->townh->factions[subID]->town; | ||||
| 	randomizeArmy(subID); | ||||
| 	updateAppearance(); | ||||
| } | ||||
|  | ||||
| void CGTownInstance::updateAppearance() | ||||
| { | ||||
| 	if (!hasFort()) | ||||
| @@ -4126,10 +4157,10 @@ const std::string & CGSeerHut::getHoverText() const | ||||
| 			boost::algorithm::replace_first(hoverName,"%s", seerName); | ||||
| 		} | ||||
| 		else //just seer hut | ||||
| 			hoverName = VLC->generaltexth->names[ID]; | ||||
| 			hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 		break; | ||||
| 	case Obj::QUEST_GUARD: | ||||
| 		hoverName = VLC->generaltexth->names[ID]; | ||||
| 		hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 		break; | ||||
| 	default: | ||||
|         logGlobal->debugStream() << "unrecognized quest object"; | ||||
| @@ -4448,7 +4479,7 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const | ||||
|  | ||||
| const std::string & CGWitchHut::getHoverText() const | ||||
| { | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 	if(wasVisited(cb->getLocalPlayer())) | ||||
| 	{ | ||||
| 		hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s) | ||||
| @@ -4907,7 +4938,7 @@ void CGShrine::initObj() | ||||
|  | ||||
| const std::string & CGShrine::getHoverText() const | ||||
| { | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 	if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current | ||||
| 	{ | ||||
| 		hoverName += "\n" + VLC->generaltexth->allTexts[355]; // + (learn %s) | ||||
| @@ -5509,7 +5540,7 @@ const std::string& CGKeys::getHoverText() const | ||||
| const std::string CGKeys::getName() const | ||||
| { | ||||
| 	std::string name; | ||||
| 	name = VLC->generaltexth->tentColors[subID] + " " + VLC->generaltexth->names[ID]; | ||||
| 	name = VLC->generaltexth->tentColors[subID] + " " + VLC->objtypeh->getObjectName(ID); | ||||
| 	return name; | ||||
| } | ||||
|  | ||||
| @@ -5545,7 +5576,7 @@ void CGBorderGuard::getVisitText (MetaString &text, std::vector<Component> &comp | ||||
| void CGBorderGuard::getRolloverText (MetaString &text, bool onHover) const | ||||
| { | ||||
| 	if (!onHover) | ||||
| 		text << VLC->generaltexth->tentColors[subID] << " " << VLC->generaltexth->names[Obj::KEYMASTER]; | ||||
| 		text << VLC->generaltexth->tentColors[subID] << " " << VLC->objtypeh->getObjectName(Obj::KEYMASTER); | ||||
| } | ||||
|  | ||||
| bool CGBorderGuard::checkQuest (const CGHeroInstance * h) const | ||||
| @@ -5945,7 +5976,7 @@ void CGObelisk::initObj() | ||||
| const std::string & CGObelisk::getHoverText() const | ||||
| { | ||||
| 	bool visited = wasVisited(cb->getLocalPlayer()); | ||||
| 	hoverName = VLC->generaltexth->names[ID] + " " + visitedTxt(visited); | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID) + " " + visitedTxt(visited); | ||||
| 	return hoverName; | ||||
| } | ||||
|  | ||||
| @@ -5998,7 +6029,7 @@ void CGLighthouse::initObj() | ||||
|  | ||||
| const std::string & CGLighthouse::getHoverText() const | ||||
| { | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 	//TODO: owned by %s player | ||||
| 	return hoverName; | ||||
| } | ||||
|   | ||||
| @@ -234,6 +234,8 @@ public: | ||||
| 	//CGObjectInstance& operator=(const CGObjectInstance & right); | ||||
| 	virtual const std::string & getHoverText() const; | ||||
|  | ||||
| 	void setType(si32 ID, si32 subID); | ||||
|  | ||||
| 	///IObjectInterface | ||||
| 	void initObj() override; | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| @@ -355,7 +357,7 @@ public: | ||||
| 	//std::vector<const CArtifact*> artifacts; //hero's artifacts from bag | ||||
| 	//std::map<ui16, const CArtifact*> artifWorn; //map<position,artifact_id>; positions: 0 - head; 1 - shoulders; 2 - neck; 3 - right hand; 4 - left hand; 5 - torso; 6 - right ring; 7 - left ring; 8 - feet; 9 - misc1; 10 - misc2; 11 - misc3; 12 - misc4; 13 - mach1; 14 - mach2; 15 - mach3; 16 - mach4; 17 - spellbook; 18 - misc5 | ||||
| 	std::set<SpellID> spells; //known spells (spell IDs) | ||||
| 	std::set<ObjectInstanceID> visitedObjects; | ||||
| 	std::set<ObjectInstanceID> visitedObjects; | ||||
|  | ||||
| 	struct DLL_LINKAGE Patrol | ||||
| 	{ | ||||
| @@ -422,7 +424,7 @@ public: | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & static_cast<CArtifactSet&>(*this); | ||||
| 		h & exp & level & name & biography & portrait & mana & secSkills & movement | ||||
| 			& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo & visitedObjects; | ||||
| 			& sex & inTownGarrison & spells & patrol & moveDir & skillsInfo & visitedObjects; | ||||
| 		h & visitedTown & boat; | ||||
| 		h & type & specialty & commander; | ||||
| 		BONUS_TREE_DESERIALIZATION_FIX | ||||
| @@ -474,6 +476,8 @@ public: | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
| 	void setType(si32 ID, si32 subID); | ||||
|  | ||||
| 	void initHero(); | ||||
| 	void initHero(HeroTypeID SUBID); | ||||
|  | ||||
| @@ -698,6 +702,7 @@ public: | ||||
| 	bool allowsTrade(EMarketMode::EMarketMode mode) const; | ||||
| 	std::vector<int> availableItemsIds(EMarketMode::EMarketMode mode) const; | ||||
|  | ||||
| 	void setType(si32 ID, si32 subID); | ||||
| 	void updateAppearance(); | ||||
|  | ||||
| 	////////////////////////////////////////////////////////////////////////// | ||||
|   | ||||
| @@ -121,7 +121,6 @@ void CObjectWithReward::onHeroVisit(const CGHeroInstance *h) const | ||||
| 				else | ||||
| 					iw.text = onVisited; | ||||
| 				cb->showInfoDialog(&iw); | ||||
| 				onRewardGiven(h); // FIXME: dummy call to properly act on empty objects (e.g. Floatsam that must be removed after visit) | ||||
| 				break; | ||||
| 			} | ||||
| 			case 1: // one reward. Just give it with message | ||||
| @@ -141,7 +140,7 @@ void CObjectWithReward::onHeroVisit(const CGHeroInstance *h) const | ||||
| 					case SELECT_FIRST: // give first available | ||||
| 						grantRewardWithMessage(rewards[0]); | ||||
| 						break; | ||||
| 					case SELECT_RANDOM: // select one randomly | ||||
| 					case SELECT_RANDOM: // select one randomly //TODO: use weights | ||||
| 						grantRewardWithMessage(rewards[cb->gameState()->getRandomGenerator().nextInt(rewards.size()-1)]); | ||||
| 						break; | ||||
| 				} | ||||
| @@ -376,7 +375,7 @@ static std::string & visitedTxt(const bool visited) | ||||
| const std::string & CObjectWithReward::getHoverText() const | ||||
| { | ||||
| 	const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer()); | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 	if(visitMode != VISIT_UNLIMITED) | ||||
| 	{ | ||||
| 		bool visited = wasVisited(cb->getCurrentPlayer()); | ||||
| @@ -975,7 +974,7 @@ const std::string & CGVisitableOPH::getHoverText() const | ||||
| 	default: | ||||
| 		throw std::runtime_error("Wrong CGVisitableOPH object ID!\n"); | ||||
| 	} | ||||
| 	hoverName = VLC->generaltexth->names[ID]; | ||||
| 	hoverName = VLC->objtypeh->getObjectName(ID); | ||||
| 	if(pom >= 0) | ||||
| 		hoverName += ("\n" + VLC->generaltexth->xtrainfo[pom]); | ||||
| 	const CGHeroInstance *h = cb->getSelectedHero (cb->getCurrentPlayer()); | ||||
| @@ -1015,7 +1014,6 @@ void CGVisitableOPW::initObj() | ||||
| 		soundID = soundBase::GENIE; | ||||
| 		onEmpty.addTxt(MetaString::ADVOB_TXT, 169); | ||||
| 		// 3-6 of any resource but wood and gold | ||||
| 		// this is UGLY. TODO: find better way to describe this | ||||
| 		for (int resID = Res::MERCURY; resID < Res::GOLD; resID++) | ||||
| 		{ | ||||
| 			for (int val = 3; val <=6; val++) | ||||
| @@ -1045,7 +1043,7 @@ void CGVisitableOPW::initObj() | ||||
|  | ||||
| void CGMagicSpring::initObj() | ||||
| { | ||||
| 	CVisitInfo visit; // TODO: "player above max mana" limiter | ||||
| 	CVisitInfo visit; // TODO: "player above max mana" limiter. Use logical expressions for limiters? | ||||
| 	visit.reward.manaPercentage = 200; | ||||
| 	visit.message.addTxt(MetaString::ADVOB_TXT, 74); | ||||
| 	info.push_back(visit); // two rewards, one for each entrance | ||||
|   | ||||
| @@ -119,6 +119,7 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & resources & extraComponents & removeObject; | ||||
| 		h & manaPercentage & movePercentage; | ||||
| 		h & gainedExp & gainedLevels & manaDiff & movePoints; | ||||
| 		h & primary & secondary & bonuses; | ||||
| 		h & artifacts & spells & creatures; | ||||
| @@ -134,6 +135,9 @@ public: | ||||
| 	/// Message that will be displayed on granting of this reward, if not empty | ||||
| 	MetaString message; | ||||
|  | ||||
| 	/// Chance for this reward to be selected in case of random choice | ||||
| 	si32 selectChance; | ||||
|  | ||||
| 	/// How many times this reward has been granted since last reset | ||||
| 	si32 numOfGrants; | ||||
|  | ||||
| @@ -143,7 +147,7 @@ public: | ||||
|  | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & limiter & reward & message; | ||||
| 		h & limiter & reward & message & selectChance & numOfGrants; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| @@ -229,8 +233,8 @@ public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<CArmedInstance&>(*this); | ||||
| 		h & info & canRefuse; | ||||
| 		h & onSelect & onVisited & onEmpty; | ||||
| 		h & info & canRefuse & resetDuration; | ||||
| 		h & onSelect & onVisited & onEmpty & visitMode; | ||||
| 		h & soundID & selectMode & selectedReward; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -623,9 +623,9 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs ) | ||||
| 	o->subID = subID; | ||||
| 	o->pos = pos; | ||||
| 	const TerrainTile &t = gs->map->getTile(pos); | ||||
| 	o->appearance = VLC->objtypeh->getHandlerFor(o->ID, o->subID)->selectTemplate(t.terType, o); | ||||
| 	o->appearance = VLC->objtypeh->getHandlerFor(o->ID, o->subID)->getTemplates(t.terType).front(); | ||||
| 	id = o->id = ObjectInstanceID(gs->map->objects.size()); | ||||
| 	o->hoverName = VLC->generaltexth->names[ID]; | ||||
| 	o->hoverName = VLC->objtypeh->getObjectName(ID); | ||||
|  | ||||
| 	gs->map->objects.push_back(o); | ||||
| 	gs->map->addBlockVisTiles(o); | ||||
|   | ||||
| @@ -16,7 +16,7 @@ class CCreatureHandler; | ||||
| class CSpellHandler; | ||||
| class CBuildingHandler; | ||||
| class CObjectHandler; | ||||
| class CObjectTypesHandler; | ||||
| class CObjectClassesHandler; | ||||
| class CTownHandler; | ||||
| class CGeneralTextHandler; | ||||
| class CModHandler; | ||||
| @@ -42,7 +42,7 @@ public: | ||||
| 	CCreatureHandler * creh; | ||||
| 	CSpellHandler * spellh; | ||||
| 	CObjectHandler * objh; | ||||
| 	CObjectTypesHandler * objtypeh; | ||||
| 	CObjectClassesHandler * objtypeh; | ||||
| 	CTownHandler * townh; | ||||
| 	CGeneralTextHandler * generaltexth; | ||||
| 	CModHandler * modh; | ||||
|   | ||||
| @@ -166,7 +166,7 @@ void CMapGenerator::genTowns() | ||||
| 		} | ||||
| 		town->subID = townId; | ||||
| 		town->tempOwner = owner; | ||||
| 		town->appearance = VLC->objtypeh->getHandlerFor(town->ID, town->subID)->selectTemplate(map->getTile(townPos[side]).terType, town); | ||||
| 		town->appearance = VLC->objtypeh->getHandlerFor(town->ID, town->subID)->getTemplates(map->getTile(townPos[side]).terType).front(); | ||||
| 		town->builtBuildings.insert(BuildingID::FORT); | ||||
| 		town->builtBuildings.insert(BuildingID::DEFAULT); | ||||
| 		editManager->insertObject(town, int3(townPos[side].x, townPos[side].y + (i / 2) * 5, 0)); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user