mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Spell shrines can now be configured in json
This commit is contained in:
		| @@ -70,6 +70,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/CObjectClassesHandler.cpp | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/CommonConstructors.cpp | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/CRewardableConstructor.cpp | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.cpp | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/mapObjects/CArmedInstance.cpp | ||||
| 		${MAIN_LIB_DIR}/mapObjects/CBank.cpp | ||||
| @@ -377,6 +378,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/CRewardableConstructor.h | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/IObjectInfo.h | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/RandomMapInfo.h | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.h | ||||
| 		${MAIN_LIB_DIR}/mapObjectConstructors/SObjectSounds.h | ||||
|  | ||||
| 		${MAIN_LIB_DIR}/mapObjects/CArmedInstance.h | ||||
|   | ||||
| @@ -311,6 +311,10 @@ | ||||
| 					"value"		: 500, | ||||
| 					"rarity"	: 100 | ||||
| 				} | ||||
| 				"visitText" : 127, | ||||
| 				"spell" : { | ||||
| 					"level" : 1 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| @@ -330,6 +334,10 @@ | ||||
| 				"rmg" : { | ||||
| 					"value"		: 2000, | ||||
| 					"rarity"	: 100 | ||||
| 				}, | ||||
| 				"visitText" : 128, | ||||
| 				"spell" : { | ||||
| 					"level" : 2 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @@ -350,6 +358,10 @@ | ||||
| 				"rmg" : { | ||||
| 					"value"		: 3000, | ||||
| 					"rarity"	: 100 | ||||
| 				}, | ||||
| 				"visitText" : 129, | ||||
| 				"spell" : { | ||||
| 					"level" : 3 | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|   | ||||
| @@ -15,6 +15,7 @@ | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class SpellID; | ||||
| enum class ESpellSchool: int8_t; | ||||
|  | ||||
| namespace spells | ||||
| { | ||||
| @@ -43,6 +44,7 @@ public: | ||||
| 	virtual bool isSpecial() const = 0; | ||||
| 	virtual bool isMagical() const = 0; //Should this spell considered as magical effect or as ability (like dendroid's bind) | ||||
|  | ||||
| 	virtual bool hasSchool(ESpellSchool school) const = 0; | ||||
| 	virtual void forEachSchool(const SchoolCallback & cb) const = 0; | ||||
| 	virtual const std::string & getCastSound() const = 0; | ||||
| 	virtual int32_t getCost(const int32_t skillLevel) const = 0; | ||||
|   | ||||
| @@ -170,16 +170,19 @@ void CPrivilegedInfoCallback::pickAllowedArtsSet(std::vector<const CArtifact *> | ||||
| 	out.push_back(VLC->arth->objects[VLC->arth->pickRandomArtifact(rand, CArtifact::ART_MAJOR)]); | ||||
| } | ||||
|  | ||||
| void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, ui16 level) | ||||
| void CPrivilegedInfoCallback::getAllowedSpells(std::vector<SpellID> & out, std::optional<ui16> level) | ||||
| { | ||||
| 	for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?) | ||||
| 	{ | ||||
|  | ||||
| 		const spells::Spell * spell = SpellID(i).toSpell(); | ||||
| 		if(isAllowed(0, spell->getIndex()) && spell->getLevel() == level) | ||||
| 		{ | ||||
| 			out.push_back(spell->getId()); | ||||
| 		} | ||||
|  | ||||
| 		if (!isAllowed(0, spell->getIndex())) | ||||
| 			continue; | ||||
|  | ||||
| 		if (level.has_value() && spell->getLevel() != level) | ||||
| 			continue; | ||||
|  | ||||
| 		out.push_back(spell->getId()); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -71,7 +71,7 @@ public: | ||||
|  | ||||
| 	//gives 3 treasures, 3 minors, 1 major -> used by Black Market and Artifact Merchant | ||||
| 	void pickAllowedArtsSet(std::vector<const CArtifact *> & out, CRandomGenerator & rand) const;  | ||||
| 	void getAllowedSpells(std::vector<SpellID> &out, ui16 level); | ||||
| 	void getAllowedSpells(std::vector<SpellID> &out, std::optional<ui16> level = std::nullopt); | ||||
|  | ||||
| 	template<typename Saver> | ||||
| 	void saveCommonState(Saver &out) const; //stores GS and VLC | ||||
|   | ||||
| @@ -243,21 +243,36 @@ namespace JsonRandom | ||||
| 		if (value.getType() == JsonNode::JsonType::DATA_STRING) | ||||
| 			return SpellID(VLC->modh->identifiers.getIdentifier("spell", value).value()); | ||||
|  | ||||
| 		vstd::erase_if(spells, [=](const SpellID & spell) | ||||
| 		if (!value["level"].isNull()) | ||||
| 		{ | ||||
| 			return VLC->spellh->getById(spell)->getLevel() != si32(value["level"].Float()); | ||||
| 		}); | ||||
| 			int32_t spellLevel = value["level"].Float(); | ||||
|  | ||||
| 			vstd::erase_if(spells, [=](const SpellID & spell) | ||||
| 			{ | ||||
| 				return VLC->spellh->getById(spell)->getLevel() != spellLevel; | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		if (!value["school"].isNull()) | ||||
| 		{ | ||||
| 			int32_t schoolID = VLC->modh->identifiers.getIdentifier("spellSchool", value["school"]).value(); | ||||
|  | ||||
| 			vstd::erase_if(spells, [=](const SpellID & spell) | ||||
| 			{ | ||||
| 				return !VLC->spellh->getById(spell)->hasSchool(ESpellSchool(schoolID)); | ||||
| 			}); | ||||
| 		} | ||||
|  | ||||
| 		if (spells.empty()) | ||||
| 		{ | ||||
| 			logMod->warn("Failed to select suitable random spell!"); | ||||
| 			return SpellID::NONE; | ||||
| 		} | ||||
| 		return SpellID(*RandomGeneratorUtil::nextItem(spells, rng)); | ||||
| 	} | ||||
|  | ||||
| 	std::vector<SpellID> loadSpells(const JsonNode & value, CRandomGenerator & rng, const std::vector<SpellID> & spells) | ||||
| 	{ | ||||
| 		// possible extensions: (taken from spell json config) | ||||
| 		// "type": "adventure",//"adventure", "combat", "ability" | ||||
| 		// "school": {"air":true, "earth":true, "fire":true, "water":true}, | ||||
| 		// "level": 1, | ||||
|  | ||||
| 		std::vector<SpellID> ret; | ||||
| 		for (const JsonNode & entry : value.Vector()) | ||||
| 		{ | ||||
|   | ||||
| @@ -24,6 +24,7 @@ | ||||
| #include "../mapObjectConstructors/CRewardableConstructor.h" | ||||
| #include "../mapObjectConstructors/CommonConstructors.h" | ||||
| #include "../mapObjectConstructors/CBankInstanceConstructor.h" | ||||
| #include "../mapObjectConstructors/ShrineInstanceConstructor.h" | ||||
| #include "../mapObjects/CQuest.h" | ||||
| #include "../mapObjects/CGPandoraBox.h" | ||||
| #include "../mapObjects/ObjectTemplate.h" | ||||
| @@ -44,6 +45,7 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	SET_HANDLER_CLASS("bank", CBankInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("boat", BoatInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("market", MarketInstanceConstructor); | ||||
| 	SET_HANDLER_CLASS("shrine", ShrineInstanceConstructor); | ||||
|  | ||||
| 	SET_HANDLER_CLASS("static", CObstacleConstructor); | ||||
| 	SET_HANDLER_CLASS("", CObstacleConstructor); | ||||
| @@ -78,7 +80,6 @@ CObjectClassesHandler::CObjectClassesHandler() | ||||
| 	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("monolith", CGMonolith); | ||||
|   | ||||
							
								
								
									
										65
									
								
								lib/mapObjectConstructors/ShrineInstanceConstructor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								lib/mapObjectConstructors/ShrineInstanceConstructor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| /* | ||||
| * ShrineInstanceConstructor.cpp, part of VCMI engine | ||||
| * | ||||
| * Authors: listed in file AUTHORS in main folder | ||||
| * | ||||
| * License: GNU General Public License v2.0 or later | ||||
| * Full text of license available in license.txt file, in main folder | ||||
| * | ||||
| */ | ||||
| #include "StdInc.h" | ||||
| #include "ShrineInstanceConstructor.h" | ||||
|  | ||||
| #include "IObjectInfo.h" | ||||
| #include "../mapObjects/MiscObjects.h" | ||||
| #include "../JsonRandom.h" | ||||
| #include "../IGameCallback.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| void ShrineInstanceConstructor::initTypeData(const JsonNode & config) | ||||
| { | ||||
| 	parameters = config; | ||||
| } | ||||
|  | ||||
| CGObjectInstance * ShrineInstanceConstructor::create(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	CGShrine * shrine = new CGShrine; | ||||
|  | ||||
| 	preInitObject(shrine); | ||||
|  | ||||
| 	if(tmpl) | ||||
| 		shrine->appearance = tmpl; | ||||
|  | ||||
| 	return shrine; | ||||
| } | ||||
|  | ||||
| void ShrineInstanceConstructor::configureObject(CGObjectInstance * object, CRandomGenerator & rng) const | ||||
| { | ||||
| 	CGShrine * shrine = dynamic_cast<CGShrine*>(object); | ||||
|  | ||||
| 	if (!shrine) | ||||
| 		throw std::runtime_error("Unexpected object instance in ShrineInstanceConstructor!"); | ||||
|  | ||||
| 	auto visitTextParameter = parameters["visitText"]; | ||||
|  | ||||
| 	if (visitTextParameter.isNumber()) | ||||
| 		shrine->visitText.addTxt(MetaString::ADVOB_TXT, static_cast<ui32>(visitTextParameter.Float())); | ||||
| 	else | ||||
| 		shrine->visitText << visitTextParameter.String(); | ||||
|  | ||||
| 	if(shrine->spell == SpellID::NONE) // shrine has no predefined spell | ||||
| 	{ | ||||
| 		std::vector<SpellID> possibilities; | ||||
| 		shrine->cb->getAllowedSpells(possibilities); | ||||
|  | ||||
| 		shrine->spell =JsonRandom::loadSpell(parameters["spell"], rng, possibilities); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| std::unique_ptr<IObjectInfo> ShrineInstanceConstructor::getObjectInfo(std::shared_ptr<const ObjectTemplate> tmpl) const | ||||
| { | ||||
| 	return nullptr; | ||||
| } | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
							
								
								
									
										34
									
								
								lib/mapObjectConstructors/ShrineInstanceConstructor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								lib/mapObjectConstructors/ShrineInstanceConstructor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
| * ShrineInstanceConstructor.h, part of VCMI engine | ||||
| * | ||||
| * Authors: listed in file AUTHORS in main folder | ||||
| * | ||||
| * License: GNU General Public License v2.0 or later | ||||
| * Full text of license available in license.txt file, in main folder | ||||
| * | ||||
| */ | ||||
| #pragma once | ||||
|  | ||||
| #include "AObjectTypeHandler.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| class ShrineInstanceConstructor final : public AObjectTypeHandler | ||||
| { | ||||
| 	JsonNode parameters; | ||||
|  | ||||
| protected: | ||||
| 	void initTypeData(const JsonNode & config) 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(std::shared_ptr<const ObjectTemplate> tmpl) const override; | ||||
|  | ||||
| public: | ||||
| 	template <typename Handler> void serialize(Handler &h, const int version) | ||||
| 	{ | ||||
| 		h & static_cast<AObjectTypeHandler&>(*this); | ||||
| 		h & parameters; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_END | ||||
| @@ -26,6 +26,8 @@ | ||||
| #include "../CPlayerState.h" | ||||
| #include "../GameSettings.h" | ||||
| #include "../serializer/JsonSerializeFormat.h" | ||||
| #include "../mapObjectConstructors/AObjectTypeHandler.h" | ||||
| #include "../mapObjectConstructors/CObjectClassesHandler.h" | ||||
|  | ||||
| VCMI_LIB_NAMESPACE_BEGIN | ||||
|  | ||||
| @@ -1530,7 +1532,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 	InfoWindow iw; | ||||
| 	iw.type = EInfoWindowMode::AUTO; | ||||
| 	iw.player = h->getOwner(); | ||||
| 	iw.text.addTxt(MetaString::ADVOB_TXT,127 + ID - 88); | ||||
| 	iw.text = visitText; | ||||
| 	iw.text.addTxt(MetaString::SPELL_NAME,spell); | ||||
| 	iw.text << "."; | ||||
|  | ||||
| @@ -1542,7 +1544,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const | ||||
| 	{ | ||||
| 		iw.text.addTxt(MetaString::ADVOB_TXT,174); | ||||
| 	} | ||||
| 	else if(ID == Obj::SHRINE_OF_MAGIC_THOUGHT  && h->maxSpellLevel() < 3) //it's third level spell and hero doesn't have wisdom | ||||
| 	else if(spell.toSpell()->getLevel() > h->maxSpellLevel()) //it's third level spell and hero doesn't have wisdom | ||||
| 	{ | ||||
| 		iw.text.addTxt(MetaString::ADVOB_TXT,130); | ||||
| 	} | ||||
| @@ -1560,20 +1562,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const | ||||
|  | ||||
| void CGShrine::initObj(CRandomGenerator & rand) | ||||
| { | ||||
| 	if(spell == SpellID::NONE) //spell not set | ||||
| 	{ | ||||
| 		int level = ID-87; | ||||
| 		std::vector<SpellID> possibilities; | ||||
| 		cb->getAllowedSpells (possibilities, level); | ||||
|  | ||||
| 		if(possibilities.empty()) | ||||
| 		{ | ||||
| 			logGlobal->error("Error: cannot init shrine, no allowed spells!"); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		spell = *RandomGeneratorUtil::nextItem(possibilities, rand); | ||||
| 	} | ||||
| 	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand); | ||||
| } | ||||
|  | ||||
| std::string CGShrine::getHoverText(PlayerColor player) const | ||||
| @@ -1693,8 +1682,7 @@ void CGScholar::initObj(CRandomGenerator & rand) | ||||
| 			break; | ||||
| 		case SPELL: | ||||
| 			std::vector<SpellID> possibilities; | ||||
| 			for (int i = 1; i < 6; ++i) | ||||
| 				cb->getAllowedSpells (possibilities, i); | ||||
| 			cb->getAllowedSpells (possibilities); | ||||
| 			bonusID = *RandomGeneratorUtil::nextItem(possibilities, rand); | ||||
| 			break; | ||||
| 		} | ||||
|   | ||||
| @@ -246,7 +246,9 @@ protected: | ||||
| class DLL_LINKAGE CGShrine : public CTeamVisited | ||||
| { | ||||
| public: | ||||
| 	MetaString visitText; | ||||
| 	SpellID spell; //id of spell or NONE if random | ||||
|  | ||||
| 	void onHeroVisit(const CGHeroInstance * h) const override; | ||||
| 	void initObj(CRandomGenerator & rand) override; | ||||
| 	std::string getHoverText(PlayerColor player) const override; | ||||
| @@ -256,6 +258,7 @@ public: | ||||
| 	{ | ||||
| 		h & static_cast<CTeamVisited&>(*this);; | ||||
| 		h & spell; | ||||
| 		h & visitText; | ||||
| 	} | ||||
| protected: | ||||
| 	void serializeJsonOptions(JsonSerializeFormat & handler) override; | ||||
|   | ||||
| @@ -74,8 +74,7 @@ Rewardable::LimitersList Rewardable::Info::configureSublimiters(Rewardable::Conf | ||||
| void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRandomGenerator & rng, Rewardable::Limiter & limiter, const JsonNode & source) const | ||||
| { | ||||
| 	std::vector<SpellID> spells; | ||||
| 	for (size_t i=0; i<6; i++) | ||||
| 		IObjectInterface::cb->getAllowedSpells(spells, static_cast<ui16>(i)); | ||||
| 	IObjectInterface::cb->getAllowedSpells(spells); | ||||
|  | ||||
|  | ||||
| 	limiter.dayOfWeek = JsonRandom::loadValue(source["dayOfWeek"], rng); | ||||
| @@ -124,8 +123,7 @@ void Rewardable::Info::configureReward(Rewardable::Configuration & object, CRand | ||||
| 	reward.secondary = JsonRandom::loadSecondary(source["secondary"], rng); | ||||
|  | ||||
| 	std::vector<SpellID> spells; | ||||
| 	for (size_t i=0; i<6; i++) | ||||
| 		IObjectInterface::cb->getAllowedSpells(spells, static_cast<ui16>(i)); | ||||
| 	IObjectInterface::cb->getAllowedSpells(spells); | ||||
|  | ||||
| 	reward.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng); | ||||
| 	reward.spells = JsonRandom::loadSpells(source["spells"], rng, spells); | ||||
|   | ||||
| @@ -127,6 +127,11 @@ int64_t CSpell::calculateDamage(const spells::Caster * caster) const | ||||
| 	return caster->getSpellBonus(this, rawDamage, nullptr); | ||||
| } | ||||
|  | ||||
| bool CSpell::hasSchool(ESpellSchool which) const | ||||
| { | ||||
| 	return school.count(which) && school.at(which); | ||||
| } | ||||
|  | ||||
| bool CSpell::canBeCast(const CBattleInfoCallback * cb, spells::Mode mode, const spells::Caster * caster) const | ||||
| { | ||||
| 	//if caller do not interested in description just discard it and do not pollute even debug log | ||||
|   | ||||
| @@ -209,6 +209,8 @@ public: | ||||
|  | ||||
| 	int64_t calculateDamage(const spells::Caster * caster) const override; | ||||
|  | ||||
| 	bool hasSchool(ESpellSchool school) const override; | ||||
|  | ||||
| 	/** | ||||
| 	 * Calls cb for each school this spell belongs to | ||||
| 	 * | ||||
|   | ||||
		Reference in New Issue
	
	Block a user