瀏覽代碼

Implemented configurable shrine

Ivan Savenko 2 年之前
父節點
當前提交
bb05c2dea5

+ 0 - 2
cmake_modules/VCMI_lib.cmake

@@ -81,7 +81,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/mapObjectConstructors/DwellingInstanceConstructor.cpp
 		${MAIN_LIB_DIR}/mapObjectConstructors/HillFortInstanceConstructor.cpp
 		${MAIN_LIB_DIR}/mapObjectConstructors/ShipyardInstanceConstructor.cpp
-		${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.cpp
 
 		${MAIN_LIB_DIR}/mapObjects/CArmedInstance.cpp
 		${MAIN_LIB_DIR}/mapObjects/CBank.cpp
@@ -425,7 +424,6 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/mapObjectConstructors/IObjectInfo.h
 		${MAIN_LIB_DIR}/mapObjectConstructors/RandomMapInfo.h
 		${MAIN_LIB_DIR}/mapObjectConstructors/ShipyardInstanceConstructor.h
-		${MAIN_LIB_DIR}/mapObjectConstructors/ShrineInstanceConstructor.h
 		${MAIN_LIB_DIR}/mapObjectConstructors/SObjectSounds.h
 
 		${MAIN_LIB_DIR}/mapObjects/CArmedInstance.h

+ 3 - 1
config/gameConfig.json

@@ -52,7 +52,9 @@
 		"config/objects/moddables.json",
 		"config/objects/creatureBanks.json",
 		"config/objects/dwellings.json",
-		"config/objects/rewardableGeneric.json",
+		"config/objects/rewardableObservatories.json",
+		"config/objects/rewardableWitchHut.json",
+		"config/objects/rewardableShrine.json",
 		"config/objects/rewardableOncePerWeek.json",
 		"config/objects/rewardablePickable.json",
 		"config/objects/rewardableOnceVisitable.json",

+ 0 - 72
config/objects/generic.json

@@ -230,78 +230,6 @@
 			}
 		}
 	},
-	"shrineOfMagicLevel1" : {//incantation
-		"index" :88,
-		"handler" : "shrine",
-		"base" : {
-			"sounds" : {
-				"ambient" : ["LOOPSHRIN"],
-				"visit" : ["TEMPLE"]
-			}
-		},
-		"types" : {
-			"object" : {
-				"index" : 0,
-				"aiValue" : 500,
-				"rmg" : {
-					"value"		: 500,
-					"rarity"	: 100
-				},
-				"visitText" : 127,
-				"spell" : {
-					"level" : 1
-				}
-			}
-		}
-	},
-	"shrineOfMagicLevel2" : {//gesture
-		"index" :89,
-		"handler" : "shrine",
-		"base" : {
-			"sounds" : {
-				"ambient" : ["LOOPSHRIN"],
-				"visit" : ["TEMPLE"]
-			}
-		},
-		"types" : {
-			"object" : {
-				"index" : 0,
-				"aiValue" : 2000,
-				"rmg" : {
-					"value"		: 2000,
-					"rarity"	: 100
-				},
-				"visitText" : 128,
-				"spell" : {
-					"level" : 2
-				}
-			}
-		}
-	},
-	"shrineOfMagicLevel3" : {//thinking
-		"index" :90,
-		"handler" : "shrine",
-		"base" : {
-			"sounds" : {
-				"ambient" : ["LOOPSHRIN"],
-				"visit" : ["TEMPLE"]
-			}
-		},
-		"types" : {
-			"object" : {
-				"index" : 0,
-				"aiValue" : 3000,
-				"rmg" : {
-					"value"		: 3000,
-					"rarity"	: 100
-				},
-				"visitText" : 129,
-				"spell" : {
-					"level" : 3
-				}
-			}
-		}
-	},
 	"eyeOfTheMagi" : {
 		"index" :27,
 		"handler" : "magi",

+ 0 - 277
config/objects/rewardableGeneric.json

@@ -1,277 +0,0 @@
-{
-	"witchHut" : {
-		"index" :113,
-		"handler" : "configurable",
-		"base" : {
-			"sounds" : {
-				"visit" : ["GAZEBO"]
-			}
-		},
-		"types" : {
-			"witchHut" : {
-				"index" : 0,
-				"aiValue" : 1500,
-				"rmg" : {
-					"zoneLimit"	: 3,
-					"value"		: 1500,
-					"rarity"	: 80
-				},
-				"compatibilityIdentifiers" : [ "object" ],
-				
-				"visitMode" : "limiter",
-
-				"variables" : {
-					"secondarySkill" : {
-						"gainedSkill" : { // Note: this variable name is used by engine for H3M loading and by AI
-							"noneOf" : [
-								"leadership",
-								"necromancy"
-							]
-						}
-					}
-				},
-				"visitLimiter" : {
-					"secondary" : {
-						"@gainedSkill" : 1
-					}
-				},
-				"rewards" : [
-					{
-						"limiter" : {
-							"canLearnSkills" : true,
-							"noneOf" : [
-								{
-									"secondary" : {
-										"@gainedSkill" : 1
-									}
-								}
-							]
-						},
-						"secondary" : {
-							"@gainedSkill" : 1
-						},
-						"message" : 171 // Witch teaches you skill
-					}
-				],
-				"onVisited" : [
-					{
-						"message" : 172 // You already known this skill
-					}
-				],
-				"onEmpty" : [
-					{
-						"message" : 173 // You know too much (no free slots)
-					}
-				]
-			}
-		}
-	},
-
-	"redwoodObservatory" : {
-		"index" :58,
-		"handler" : "configurable",
-		"base" : {
-			"sounds" : {
-				"visit" : ["LIGHTHOUSE"]
-			}
-		},
-		"types" : {
-			"redwoodObservatory" : {
-				"index" : 0,
-				"aiValue" : 750,
-				"templates" :
-				{
-					"base" : { "animation" : "avxredw.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["grass", "swamp", "dirt", "sand", "lava", "rough"] },
-					"snow" : { "animation" : "avxreds0.def", "visitableFrom" : [ "---", "+++", "+++" ], "mask" : [ "VV", "VV", "VA"], "allowedTerrains":["snow"] }
-				},
-				"rmg" : {
-					"zoneLimit"	: 1,
-					"value"		: 750,
-					"rarity"	: 100
-				},
-				
-				"compatibilityIdentifiers" : [ "object" ],
-				"visitMode" : "unlimited",
-				"rewards" : [
-					{
-						"message" : 98,
-						"revealTiles" : {
-							"radius" : 20,
-							"surface" : 1,
-							"subterra" : 1,
-							"water" : 1,
-							"rock" : 1
-						}
-					}
-				]
-			}
-		}
-	},
-
-	"pillarOfFire" : {
-		"index" :60,
-		"handler" : "configurable",
-		"base" : {
-			"sounds" : {
-				"ambient" : ["LOOPFIRE"],
-				"visit" : ["LIGHTHOUSE"]
-			}
-		},
-		"types" : {
-			"pillarOfFire" : {
-				"index" : 0,
-				"aiValue" : 750,
-				"rmg" : {
-					"zoneLimit"	: 1,
-					"value"		: 750,
-					"rarity"	: 100
-				},
-				
-				"compatibilityIdentifiers" : [ "object" ],
-				"visitMode" : "unlimited",
-				"rewards" : [
-					{
-						"message" : 99,
-						"revealTiles" : {
-							"radius" : 20,
-							"surface" : 1,
-							"subterra" : 1,
-							"water" : 1,
-							"rock" : 1
-						}
-					}
-				]
-			}
-		}
-	},
-
-	"coverOfDarkness" : {
-		"index" :15,
-		"handler" : "configurable",
-		"base" : {
-			"sounds" : {
-				"visit" : ["LIGHTHOUSE"]
-			}
-		},
-		"types" : {
-			"coverOfDarkness" : {
-				"index" : 0,
-				"aiValue" : 100,
-				"rmg" : {
-				},
-				
-				"compatibilityIdentifiers" : [ "object" ],
-				"visitMode" : "unlimited",
-				"rewards" : [
-					{
-						"message" : 31,
-						"revealTiles" : {
-							"radius" : 20,
-							"surface" : 1,
-							"subterra" : 1,
-							"water" : 1,
-							"rock" : 1,
-							"hide" : true
-						}
-					}
-				]
-			}
-		}
-	},
-	
-	"cartographer" : {
-		"index" :13,
-		"handler": "configurable",
-		"lastReservedIndex" : 2,
-		"base" : {
-			"sounds" : {
-				"visit" : ["LIGHTHOUSE"]
-			}
-		},
-		"types" : {
-			"cartographerWater" : {
-				"index" : 0,
-				"aiValue" : 5000,
-				"rmg" : {
-					"zoneLimit" : 1,
-					"value" : 5000,
-					"rarity" : 20
-				},
-				"compatibilityIdentifiers" : [ "water" ],
-				"visitMode" : "unlimited",
-				"canRefuse" : true,
-				"rewards" : [
-					{
-						"limiter" : { "resources" : { "gold" : 1000 } },
-						"message" : 25,
-						"resources" : {
-							"gold" : -1000
-						},
-						"revealTiles" : {
-							"water" : 1
-						}
-					}
-				],
-				"onEmptyMessage" : 28,
-				"onVisitedMessage" : 24
-			},
-			"cartographerLand" : {
-				"index" : 1,
-				"aiValue": 10000,
-				"rmg" : {
-					"zoneLimit" : 1,
-					"value" : 10000,
-					"rarity" : 2
-				},
-				"compatibilityIdentifiers" : [ "land" ],
-				"visitMode" : "unlimited",
-				"canRefuse" : true,
-				"rewards" : [
-					{
-						"limiter" : { "resources" : { "gold" : 1000 } },
-						"message" : 26,
-						"resources" : {
-							"gold" : -1000
-						},
-						"revealTiles" : {
-							"surface" : 1,
-							"water" : -1,
-							"rock" : -1
-						}
-					}
-				],
-				"onEmptyMessage" : 28,
-				"onVisitedMessage" : 24
-			},
-			"cartographerSubterranean" : {
-				"index" : 2,
-				"aiValue" : 7500,
-				"rmg" : {
-					"zoneLimit" : 1,
-					"value" : 7500,
-					"rarity" : 20
-				},
-				"compatibilityIdentifiers" : [ "subterra" ],
-				"visitMode" : "unlimited",
-				"canRefuse" : true,
-				"rewards" : [
-					{
-						"limiter" : { "resources" : { "gold" : 1000 } },
-						"message" : 27,
-						"resources" : {
-							"gold" : -1000
-						},
-						"revealTiles" : {
-							"subterra" : 1,
-							"water" : -1,
-							"rock" : -1,
-							"surface" : -1
-						}
-					}
-				],
-				"onEmptyMessage" : 28,
-				"onVisitedMessage" : 24
-			}
-		}
-	}
-}

+ 0 - 2
lib/mapObjectConstructors/CObjectClassesHandler.cpp

@@ -26,7 +26,6 @@
 #include "../mapObjectConstructors/DwellingInstanceConstructor.h"
 #include "../mapObjectConstructors/HillFortInstanceConstructor.h"
 #include "../mapObjectConstructors/ShipyardInstanceConstructor.h"
-#include "../mapObjectConstructors/ShrineInstanceConstructor.h"
 #include "../mapObjects/CGCreature.h"
 #include "../mapObjects/CGPandoraBox.h"
 #include "../mapObjects/CQuest.h"
@@ -54,7 +53,6 @@ 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("hillFort", HillFortInstanceConstructor);
 	SET_HANDLER_CLASS("shipyard", ShipyardInstanceConstructor);
 	SET_HANDLER_CLASS("monster", CreatureInstanceConstructor);

+ 0 - 39
lib/mapObjectConstructors/ShrineInstanceConstructor.cpp

@@ -1,39 +0,0 @@
-/*
-* 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 "../mapObjects/MiscObjects.h"
-#include "../JsonRandom.h"
-#include "../IGameCallback.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-void ShrineInstanceConstructor::initTypeData(const JsonNode & config)
-{
-	parameters = config;
-}
-
-void ShrineInstanceConstructor::randomizeObject(CGShrine * shrine, CRandomGenerator & rng) const
-{
-	JsonRandom::Variables emptyVariables;
-
-	auto visitTextParameter = parameters["visitText"];
-
-	if (visitTextParameter.isNumber())
-		shrine->visitText.appendLocalString(EMetaText::ADVOB_TXT, static_cast<ui32>(visitTextParameter.Float()));
-	else
-		shrine->visitText.appendRawString(visitTextParameter.String());
-
-	if(shrine->spell == SpellID::NONE) // shrine has no predefined spell
-		shrine->spell =JsonRandom::loadSpell(parameters["spell"], rng, emptyVariables);
-}
-
-VCMI_LIB_NAMESPACE_END

+ 0 - 34
lib/mapObjectConstructors/ShrineInstanceConstructor.h

@@ -1,34 +0,0 @@
-/*
-* 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 "CDefaultObjectTypeHandler.h"
-
-VCMI_LIB_NAMESPACE_BEGIN
-
-class CGShrine;
-
-class ShrineInstanceConstructor final : public CDefaultObjectTypeHandler<CGShrine>
-{
-	JsonNode parameters;
-
-protected:
-	void initTypeData(const JsonNode & config) override;
-	void randomizeObject(CGShrine * object, CRandomGenerator & rng) const override;
-
-public:
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & static_cast<AObjectTypeHandler&>(*this);
-		h & parameters;
-	}
-};
-
-VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -772,7 +772,7 @@ bool CGHeroInstance::canCastThisSpell(const spells::Spell * spell) const
 
 bool CGHeroInstance::canLearnSpell(const spells::Spell * spell) const
 {
-    if(!hasSpellbook())
+	if(!hasSpellbook())
 		return false;
 
 	if(spell->getLevel() > maxSpellLevel()) //not enough wisdom

+ 0 - 71
lib/mapObjects/MiscObjects.cpp

@@ -842,77 +842,6 @@ void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
 	}
 }
 
-void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
-{
-	if(spell == SpellID::NONE)
-	{
-		logGlobal->error("Not initialized shrine visited!");
-		return;
-	}
-
-	if(!wasVisited(h->tempOwner))
-		cb->setObjProperty(id, CGShrine::OBJPROP_VISITED, h->tempOwner.getNum());
-
-	InfoWindow iw;
-	iw.type = EInfoWindowMode::AUTO;
-	iw.player = h->getOwner();
-	iw.text = visitText;
-	iw.text.appendLocalString(EMetaText::SPELL_NAME,spell);
-	iw.text.appendRawString(".");
-
-	if(!h->getArt(ArtifactPosition::SPELLBOOK))
-	{
-		iw.text.appendLocalString(EMetaText::ADVOB_TXT,131);
-	}
-	else if(h->spellbookContainsSpell(spell))//hero already knows the spell
-	{
-		iw.text.appendLocalString(EMetaText::ADVOB_TXT,174);
-	}
-	else if(spell.toSpell()->getLevel() > h->maxSpellLevel()) //it's third level spell and hero doesn't have wisdom
-	{
-		iw.text.appendLocalString(EMetaText::ADVOB_TXT,130);
-	}
-	else //give spell
-	{
-		std::set<SpellID> spells;
-		spells.insert(spell);
-		cb->changeSpells(h, true, spells);
-
-		iw.components.emplace_back(Component::EComponentType::SPELL, spell, 0, 0);
-	}
-
-	cb->showInfoDialog(&iw);
-}
-
-void CGShrine::initObj(CRandomGenerator & rand)
-{
-	VLC->objtypeh->getHandlerFor(ID, subID)->configureObject(this, rand);
-}
-
-std::string CGShrine::getHoverText(PlayerColor player) const
-{
-	std::string hoverName = getObjectName();
-	if(wasVisited(player))
-	{
-		hoverName += "\n" + VLC->generaltexth->allTexts[355]; // + (learn %s)
-		boost::algorithm::replace_first(hoverName,"%s", spell.toSpell()->getNameTranslated());
-	}
-	return hoverName;
-}
-
-std::string CGShrine::getHoverText(const CGHeroInstance * hero) const
-{
-	std::string hoverName = getHoverText(hero->tempOwner);
-	if(wasVisited(hero->tempOwner) && hero->spellbookContainsSpell(spell)) //know what spell there is and hero knows that spell
-		hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned)
-	return hoverName;
-}
-
-void CGShrine::serializeJsonOptions(JsonSerializeFormat & handler)
-{
-	handler.serializeId("spell", spell, SpellID::NONE);
-}
-
 void CGSignBottle::initObj(CRandomGenerator & rand)
 {
 	//if no text is set than we pick random from the predefined ones

+ 0 - 21
lib/mapObjects/MiscObjects.h

@@ -149,27 +149,6 @@ protected:
 	void serializeJsonOptions(JsonSerializeFormat & handler) override;
 };
 
-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;
-	std::string getHoverText(const CGHeroInstance * hero) const override;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & static_cast<CTeamVisited&>(*this);;
-		h & spell;
-		h & visitText;
-	}
-protected:
-	void serializeJsonOptions(JsonSerializeFormat & handler) override;
-};
-
 class DLL_LINKAGE CGMine : public CArmedInstance
 {
 public:

+ 16 - 4
lib/mapping/MapFormatH3M.cpp

@@ -1325,10 +1325,22 @@ CGObjectInstance * CMapLoaderH3M::readDwellingRandom(const int3 & mapPosition, s
 	return object;
 }
 
-CGObjectInstance * CMapLoaderH3M::readShrine()
+CGObjectInstance * CMapLoaderH3M::readShrine(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate)
 {
-	auto * object = new CGShrine();
-	object->spell = reader->readSpell32();
+	auto * object = readGeneric(position, objectTemplate);
+	auto * rewardable = dynamic_cast<CRewardableObject*>(object);
+
+	assert(rewardable);
+
+	SpellID spell = reader->readSpell32();
+
+	if(spell != SpellID::NONE)
+	{
+		JsonNode variable;
+		variable.String() = VLC->spells()->getById(spell)->getJsonKey();
+		variable.setMeta(ModScope::scopeGame()); // list may include spells from all mods
+		rewardable->configuration.presetVariable("spell", "gainedSpell", variable);
+	}
 	return object;
 }
 
@@ -1514,7 +1526,7 @@ CGObjectInstance * CMapLoaderH3M::readObject(std::shared_ptr<const ObjectTemplat
 		case Obj::SHRINE_OF_MAGIC_INCANTATION:
 		case Obj::SHRINE_OF_MAGIC_GESTURE:
 		case Obj::SHRINE_OF_MAGIC_THOUGHT:
-			return readShrine();
+			return readShrine(mapPosition, objectTemplate);
 
 		case Obj::PANDORAS_BOX:
 			return readPandora(mapPosition, objectInstanceID);

+ 1 - 1
lib/mapping/MapFormatH3M.h

@@ -174,7 +174,7 @@ private:
 	CGObjectInstance * readPandora(const int3 & position, const ObjectInstanceID & idToBeGiven);
 	CGObjectInstance * readDwelling(const int3 & position);
 	CGObjectInstance * readDwellingRandom(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);
-	CGObjectInstance * readShrine();
+	CGObjectInstance * readShrine(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
 	CGObjectInstance * readHeroPlaceholder(const int3 & position);
 	CGObjectInstance * readGrail(const int3 & position, std::shared_ptr<const ObjectTemplate> objectTemplate);
 	CGObjectInstance * readPyramid(const int3 & position, std::shared_ptr<const ObjectTemplate> objTempl);

+ 0 - 4
lib/registerTypes/RegisterTypes.h

@@ -23,7 +23,6 @@
 #include "../mapObjectConstructors/DwellingInstanceConstructor.h"
 #include "../mapObjectConstructors/HillFortInstanceConstructor.h"
 #include "../mapObjectConstructors/ShipyardInstanceConstructor.h"
-#include "../mapObjectConstructors/ShrineInstanceConstructor.h"
 #include "../mapObjects/MapObjects.h"
 #include "../mapObjects/CGCreature.h"
 #include "../mapObjects/CGTownBuilding.h"
@@ -102,7 +101,6 @@ void registerTypesMapObjectTypes(Serializer &s)
 	s.template registerType<AObjectTypeHandler, BoatInstanceConstructor>();
 	s.template registerType<AObjectTypeHandler, MarketInstanceConstructor>();
 	s.template registerType<AObjectTypeHandler, CObstacleConstructor>();
-	s.template registerType<AObjectTypeHandler, ShrineInstanceConstructor>();
 	s.template registerType<AObjectTypeHandler, ShipyardInstanceConstructor>();
 	s.template registerType<AObjectTypeHandler, HillFortInstanceConstructor>();
 	s.template registerType<AObjectTypeHandler, CreatureInstanceConstructor>();
@@ -136,7 +134,6 @@ void registerTypesMapObjectTypes(Serializer &s)
 	REGISTER_GENERIC_HANDLER(CGScholar);
 	REGISTER_GENERIC_HANDLER(CGSeerHut);
 	REGISTER_GENERIC_HANDLER(CGShipyard);
-	REGISTER_GENERIC_HANDLER(CGShrine);
 	REGISTER_GENERIC_HANDLER(CGSignBottle);
 	REGISTER_GENERIC_HANDLER(CGSirens);
 	REGISTER_GENERIC_HANDLER(CGMonolith);
@@ -173,7 +170,6 @@ void registerTypesMapObjects2(Serializer &s)
 	s.template registerType<CGObjectInstance, CRewardableObject>();
 
 	s.template registerType<CGObjectInstance, CTeamVisited>();
-		s.template registerType<CTeamVisited, CGShrine>();
 		s.template registerType<CTeamVisited, CGObelisk>();
 
 	//s.template registerType<CQuest>();

+ 1 - 0
lib/rewardable/Info.cpp

@@ -119,6 +119,7 @@ void Rewardable::Info::configureLimiter(Rewardable::Configuration & object, CRan
 	limiter.secondary = JsonRandom::loadSecondaries(source["secondary"], rng, variables);
 	limiter.artifacts = JsonRandom::loadArtifacts(source["artifacts"], rng, variables);
 	limiter.spells  = JsonRandom::loadSpells(source["spells"], rng, variables);
+	limiter.canLearnSpells  = JsonRandom::loadSpells(source["canLearnSpells"], rng, variables);
 	limiter.creatures = JsonRandom::loadCreatures(source["creatures"], rng, variables);
 	
 	limiter.players = JsonRandom::loadColors(source["colors"], rng);

+ 6 - 0
lib/rewardable/Limiter.cpp

@@ -125,6 +125,12 @@ bool Rewardable::Limiter::heroAllowed(const CGHeroInstance * hero) const
 			return false;
 	}
 
+	for(const auto & spell : canLearnSpells)
+	{
+		if (!hero->canLearnSpell(spell.toSpell(VLC->spells())))
+			return false;
+	}
+
 	{
 		std::unordered_map<ArtifactID, unsigned int, ArtifactID::hash> artifactsRequirements; // artifact ID -> required count
 		for(const auto & art : artifacts)

+ 6 - 0
lib/rewardable/Limiter.h

@@ -61,6 +61,9 @@ struct DLL_LINKAGE Limiter final
 	/// Spells that hero must have in the spellbook
 	std::vector<SpellID> spells;
 
+	/// Spells that hero must be able to learn
+	std::vector<SpellID> canLearnSpells;
+
 	/// creatures that hero needs to have
 	std::vector<CStackBasicDescriptor> creatures;
 	
@@ -97,10 +100,13 @@ struct DLL_LINKAGE Limiter final
 		h & heroLevel;
 		h & manaPoints;
 		h & manaPercentage;
+		h & canLearnSkills;
 		h & resources;
 		h & primary;
 		h & secondary;
 		h & artifacts;
+		h & spells;
+		h & canLearnSpells;
 		h & creatures;
 		h & heroes;
 		h & heroClasses;

+ 2 - 2
test/mock/mock_IGameCallback.h

@@ -85,8 +85,8 @@ public:
 	void giveHero(ObjectInstanceID id, PlayerColor player, ObjectInstanceID boatId = ObjectInstanceID()) override {}
 	void changeObjPos(ObjectInstanceID objid, int3 newPos, const PlayerColor & initiator) override {}
 	void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) override {} //when two heroes meet on adventure map
-	void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, bool hide) override {}
-	void changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor player, bool hide) override {}
+	void changeFogOfWar(int3 center, ui32 radius, PlayerColor player, ETileVisibility mode) override {}
+	void changeFogOfWar(std::unordered_set<int3> &tiles, PlayerColor player, ETileVisibility mode) override {}
 	void castSpell(const spells::Caster * caster, SpellID spellID, const int3 &pos) override {}
 
 	///useful callback methods