Selaa lähdekoodia

Artifact instances are now owned solely by CMap

Ivan Savenko 7 kuukautta sitten
vanhempi
sitoutus
2ca1748e96

+ 0 - 43
lib/ArtifactUtils.cpp

@@ -223,49 +223,6 @@ DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities(
 	return arts;
 }
 
-DLL_LINKAGE CArtifactInstance * ArtifactUtils::createScroll(const SpellID & spellId)
-{
-	return ArtifactUtils::createArtifact(ArtifactID::SPELL_SCROLL, spellId);
-}
-
-DLL_LINKAGE CArtifactInstance * ArtifactUtils::createArtifact(const ArtifactID & artId, const SpellID & spellId)
-{
-	const std::function<CArtifactInstance*(const CArtifact*)> createArtInst =
-		[&createArtInst, &spellId](const CArtifact * art) -> CArtifactInstance*
-	{
-		assert(art);
-
-		auto * artInst = new CArtifactInstance(art);
-		if(art->isCombined() && !art->isFused())
-		{
-			for(const auto & part : art->getConstituents())
-				artInst->addPart(createArtInst(part), ArtifactPosition::PRE_FIRST);
-		}
-		if(art->isGrowing())
-		{
-			auto bonus = std::make_shared<Bonus>();
-			bonus->type = BonusType::LEVEL_COUNTER;
-			bonus->val = 0;
-			artInst->addNewBonus(bonus);
-		}
-		if(art->isScroll())
-		{
-			artInst->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
-				BonusSource::ARTIFACT_INSTANCE, -1, BonusSourceID(ArtifactID(ArtifactID::SPELL_SCROLL)), BonusSubtypeID(spellId)));
-		}
-		return artInst;
-	};
-
-	if(artId.getNum() >= 0)
-	{
-		return createArtInst(artId.toArtifact());
-	}
-	else
-	{
-		return new CArtifactInstance(); // random, empty
-	}
-}
-
 DLL_LINKAGE void ArtifactUtils::insertScrrollSpellName(std::string & description, const SpellID & sid)
 {
 	// We expect scroll description to be like this: This scroll contains the [spell name] spell which is added

+ 0 - 2
lib/ArtifactUtils.h

@@ -39,8 +39,6 @@ namespace ArtifactUtils
 	DLL_LINKAGE bool isSlotEquipment(const ArtifactPosition & slot);
 	DLL_LINKAGE bool isBackpackFreeSlots(const CArtifactSet * target, const size_t reqSlots = 1);
 	DLL_LINKAGE std::vector<const CArtifact*> assemblyPossibilities(const CArtifactSet * artSet, const ArtifactID & aid, const bool onlyEquiped = false);
-	DLL_LINKAGE CArtifactInstance * createScroll(const SpellID & spellId);
-	DLL_LINKAGE CArtifactInstance * createArtifact(const ArtifactID & artId, const SpellID & spellId = SpellID::NONE);
 	DLL_LINKAGE void insertScrrollSpellName(std::string & description, const SpellID & sid);
 }
 

+ 22 - 13
lib/CArtHandler.cpp

@@ -18,6 +18,7 @@
 #include "json/JsonBonus.h"
 #include "mapObjectConstructors/AObjectTypeHandler.h"
 #include "mapObjectConstructors/CObjectClassesHandler.h"
+#include "mapping/CMap.h"
 #include "serializer/JsonSerializeFormat.h"
 #include "texts/CGeneralTextHandler.h"
 #include "texts/CLegacyConfigParser.h"
@@ -705,20 +706,28 @@ void CArtHandler::afterLoadFinalization()
 		}
 		art->nodeHasChanged();
 	}
-
 }
 
-CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
+const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
 {
 	if(const ArtSlotInfo * si = getSlot(pos))
 	{
 		if(si->artifact && (!excludeLocked || !si->locked))
 			return si->artifact;
 	}
-
 	return nullptr;
 }
 
+ArtifactInstanceID CArtifactSet::getArtID(const ArtifactPosition & pos, bool excludeLocked) const
+{
+	if(const ArtSlotInfo * si = getSlot(pos))
+	{
+		if(si->artifact && (!excludeLocked || !si->locked))
+			return si->artifact->getId();
+	}
+	return {};
+}
+
 ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const
 {
 	for(const auto & [slot, slotInfo] : artifactsWorn)
@@ -781,10 +790,10 @@ bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchComb
 	return false;
 }
 
-CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art)
+CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art)
 {
 	ArtPlacementMap resArtPlacement;
-	const auto putToSlot = [this](const ArtifactPosition & targetSlot, CArtifactInstance * targetArt, bool locked)
+	const auto putToSlot = [this](const ArtifactPosition & targetSlot, const CArtifactInstance * targetArt, bool locked)
 	{
 		ArtSlotInfo * slotInfo;
 		if(targetSlot == ArtifactPosition::TRANSITION_POS)
@@ -939,10 +948,10 @@ void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
 {
 	for(auto & elem : artifactsWorn)
 		if(elem.second.artifact && !elem.second.locked)
-			node->attachTo(*elem.second.artifact);
+			node->attachToSource(*elem.second.artifact);
 }
 
-void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName)
+void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
 {
 	//todo: creature and commander artifacts
 	if(handler.saving && artifactsInBackpack.empty() && artifactsWorn.empty())
@@ -959,7 +968,7 @@ void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const s
 	switch(bearerType())
 	{
 	case ArtBearer::HERO:
-		serializeJsonHero(handler);
+		serializeJsonHero(handler, map);
 		break;
 	case ArtBearer::CREATURE:
 		serializeJsonCreature(handler);
@@ -973,11 +982,11 @@ void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const s
 	}
 }
 
-void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler)
+void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
 {
 	for(const auto & slot : ArtifactUtils::allWornSlots())
 	{
-		serializeJsonSlot(handler, slot);
+		serializeJsonSlot(handler, slot, map);
 	}
 
 	std::vector<ArtifactID> backpackTemp;
@@ -993,7 +1002,7 @@ void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler)
 	{
 		for(const ArtifactID & artifactID : backpackTemp)
 		{
-			auto * artifact = ArtifactUtils::createArtifact(artifactID);
+			auto * artifact = map->createArtifact(artifactID);
 			auto slot = ArtifactPosition::BACKPACK_START + artifactsInBackpack.size();
 			if(artifact->getType()->canBePutAt(this, slot))
 			{
@@ -1014,7 +1023,7 @@ void CArtifactSet::serializeJsonCommander(JsonSerializeFormat & handler)
 	logGlobal->error("CArtifactSet::serializeJsonCommander not implemented");
 }
 
-void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot)
+void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map)
 {
 	ArtifactID artifactID;
 
@@ -1034,7 +1043,7 @@ void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const Artifa
 
 		if(artifactID != ArtifactID::NONE)
 		{
-			auto * artifact = ArtifactUtils::createArtifact(artifactID.toEnum());
+			auto * artifact = map->createArtifact(artifactID.toEnum());
 
 			if(artifact->getType()->canBePutAt(this, slot))
 			{

+ 10 - 7
lib/CArtHandler.h

@@ -22,6 +22,7 @@ VCMI_LIB_NAMESPACE_BEGIN
 
 class CArtHandler;
 class CGHeroInstance;
+class CMap;
 class CArtifactSet;
 class CArtifactInstance;
 class JsonSerializeFormat;
@@ -179,11 +180,12 @@ private:
 
 struct DLL_LINKAGE ArtSlotInfo
 {
-	CArtifactInstance * artifact;
+	const CArtifactInstance * artifact;
 	bool locked; //if locked, then artifact points to the combined artifact
 
 	ArtSlotInfo() : artifact(nullptr), locked(false) {}
 	const CArtifactInstance * getArt() const;
+	ArtifactInstanceID getID() const;
 
 	template <typename Handler> void serialize(Handler & h)
 	{
@@ -195,7 +197,7 @@ struct DLL_LINKAGE ArtSlotInfo
 class DLL_LINKAGE CArtifactSet : public virtual Serializeable
 {
 public:
-	using ArtPlacementMap = std::map<CArtifactInstance*, ArtifactPosition>;
+	using ArtPlacementMap = std::map<const CArtifactInstance*, ArtifactPosition>;
 
 	std::vector<ArtSlotInfo> artifactsInBackpack; //hero's artifacts from bag
 	std::map<ArtifactPosition, ArtSlotInfo> artifactsWorn; //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
@@ -203,7 +205,8 @@ public:
 
 	const ArtSlotInfo * getSlot(const ArtifactPosition & pos) const;
 	void lockSlot(const ArtifactPosition & pos);
-	CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const;
+	const CArtifactInstance * getArt(const ArtifactPosition & pos, bool excludeLocked = true) const;
+	ArtifactInstanceID getArtID(const ArtifactPosition & pos, bool excludeLocked = true) const;
 	/// Looks for first artifact with given ID
 	ArtifactPosition getArtPos(const ArtifactID & aid, bool onlyWorn = true, bool allowLocked = true) const;
 	ArtifactPosition getArtPos(const CArtifactInstance * art) const;
@@ -212,7 +215,7 @@ public:
 	bool isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck = false) const;
 
 	virtual ArtBearer::ArtBearer bearerType() const = 0;
-	virtual ArtPlacementMap putArtifact(const ArtifactPosition & slot, CArtifactInstance * art);
+	virtual ArtPlacementMap putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art);
 	virtual void removeArtifact(const ArtifactPosition & slot);
 	virtual ~CArtifactSet() = default;
 
@@ -224,15 +227,15 @@ public:
 
 	void artDeserializationFix(CBonusSystemNode *node);
 
-	void serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName);
+	void serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map);
 	const CArtifactInstance * getCombinedArtWithPart(const ArtifactID & partId) const;
 
 private:
-	void serializeJsonHero(JsonSerializeFormat & handler);
+	void serializeJsonHero(JsonSerializeFormat & handler, CMap * map);
 	void serializeJsonCreature(JsonSerializeFormat & handler);
 	void serializeJsonCommander(JsonSerializeFormat & handler);
 
-	void serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot);//normal slots
+	void serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map);//normal slots
 };
 
 // Used to try on artifacts before the claimed changes have been applied

+ 3 - 3
lib/CArtifactInstance.cpp

@@ -17,7 +17,7 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-void CCombinedArtifactInstance::addPart(CArtifactInstance * art, const ArtifactPosition & slot)
+void CCombinedArtifactInstance::addPart(const CArtifactInstance * art, const ArtifactPosition & slot)
 {
 	auto artInst = static_cast<CArtifactInstance*>(this);
 	assert(vstd::contains_if(artInst->getType()->getConstituents(),
@@ -27,7 +27,7 @@ void CCombinedArtifactInstance::addPart(CArtifactInstance * art, const ArtifactP
 		}));
 	assert(art->getParentNodes().size() == 1  &&  art->getParentNodes().front() == art->getType());
 	partsInfo.emplace_back(art, slot);
-	artInst->attachTo(*art);
+	artInst->attachToSource(*art);
 }
 
 bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) const
@@ -173,7 +173,7 @@ void CArtifactInstance::deserializationFix()
 {
 	setType(artTypeID.toArtifact());
 	for(PartInfo & part : partsInfo)
-		attachTo(*part.art);
+		attachToSource(*part.art);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 4 - 5
lib/CArtifactInstance.h

@@ -10,7 +10,6 @@
 #pragma once
 
 #include "bonuses/CBonusSystemNode.h"
-#include "GameConstants.h"
 #include "CArtHandler.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -24,17 +23,17 @@ protected:
 public:
 	struct PartInfo
 	{
-		CArtifactInstance * art;
+		const CArtifactInstance * art;
 		ArtifactPosition slot;
 		template <typename Handler> void serialize(Handler & h)
 		{
 			h & art;
 			h & slot;
 		}
-		PartInfo(CArtifactInstance * art = nullptr, const ArtifactPosition & slot = ArtifactPosition::PRE_FIRST)
+		PartInfo(const CArtifactInstance * art = nullptr, const ArtifactPosition & slot = ArtifactPosition::PRE_FIRST)
 			: art(art), slot(slot) {};
 	};
-	void addPart(CArtifactInstance * art, const ArtifactPosition & slot);
+	void addPart(const CArtifactInstance * art, const ArtifactPosition & slot);
 	// Checks if supposed part inst is part of this combined art inst
 	bool isPart(const CArtifactInstance * supposedPart) const;
 	bool hasParts() const;
@@ -65,7 +64,7 @@ public:
 	void growingUp();
 };
 
-class DLL_LINKAGE CArtifactInstance
+class DLL_LINKAGE CArtifactInstance final
 	: public CBonusSystemNode, public CCombinedArtifactInstance, public CScrollArtifactInstance, public CGrowingArtifactInstance
 {
 protected:

+ 3 - 3
lib/CCreatureSet.cpp

@@ -901,12 +901,12 @@ ArtBearer::ArtBearer CStackInstance::bearerType() const
 	return ArtBearer::CREATURE;
 }
 
-CStackInstance::ArtPlacementMap CStackInstance::putArtifact(const ArtifactPosition & pos, CArtifactInstance * art)
+CStackInstance::ArtPlacementMap CStackInstance::putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art)
 {
 	assert(!getArt(pos));
 	assert(art->canBePutAt(this, pos));
 
-	attachTo(*art);
+	attachToSource(*art);
 	return CArtifactSet::putArtifact(pos, art);
 }
 
@@ -914,7 +914,7 @@ void CStackInstance::removeArtifact(const ArtifactPosition & pos)
 {
 	assert(getArt(pos));
 
-	detachFrom(*getArt(pos));
+	detachFromSource(*getArt(pos));
 	CArtifactSet::removeArtifact(pos);
 }
 

+ 1 - 1
lib/CCreatureSet.h

@@ -132,7 +132,7 @@ public:
 	void setArmyObj(const CArmedInstance *ArmyObj);
 	virtual void giveStackExp(TExpType exp);
 	bool valid(bool allowUnrandomized) const;
-	ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override;//from CArtifactSet
+	ArtPlacementMap putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art) override;//from CArtifactSet
 	void removeArtifact(const ArtifactPosition & pos) override;
 	ArtBearer::ArtBearer bearerType() const override; //from CArtifactSet
 	std::string nodeName() const override; //from CBonusSystemnode

+ 1 - 1
lib/CGameInfoCallback.cpp

@@ -951,7 +951,7 @@ void CGameInfoCallback::calculatePaths(const std::shared_ptr<PathfinderConfig> &
 
 const CArtifactInstance * CGameInfoCallback::getArtInstance( ArtifactInstanceID aid ) const
 {
-	return gs->getMap().artInstances.at(aid.num);
+	return gs->getMap().getArtifactInstance(aid);
 }
 
 const CGObjectInstance * CGameInfoCallback::getObjInstance( ObjectInstanceID oid ) const

+ 1 - 1
lib/IGameCallback.cpp

@@ -251,7 +251,7 @@ PlayerState * CNonConstInfoCallback::getPlayerState(const PlayerColor & color, b
 
 CArtifactInstance * CNonConstInfoCallback::getArtInstance(const ArtifactInstanceID & aid)
 {
-	return gs->getMap().artInstances.at(aid.num);
+	return gs->getMap().getArtifactInstance(aid);
 }
 
 CGObjectInstance * CNonConstInfoCallback::getObjInstance(const ObjectInstanceID & oid)

+ 1 - 2
lib/campaign/CampaignState.cpp

@@ -483,8 +483,7 @@ CGHeroInstance * CampaignState::crossoverDeserialize(const JsonNode & node, CMap
 	hero->serializeJsonOptions(handler);
 	if (map)
 	{
-		hero->serializeJsonArtifacts(handler, "artifacts");
-		map->addNewArtifactInstance(*hero);
+		hero->serializeJsonArtifacts(handler, "artifacts", map);
 	}
 	return hero;
 }

+ 12 - 3
lib/gameState/CGameState.cpp

@@ -1618,12 +1618,11 @@ void CGameState::attachArmedObjects()
 
 bool CGameState::giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid)
 {
-	 CArtifactInstance * ai = ArtifactUtils::createArtifact(aid);
-	 map->addNewArtifactInstance(ai);
+	 CArtifactInstance * ai = createArtifact(aid);
 	 auto slot = ArtifactUtils::getArtAnyPosition(h, aid);
 	 if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
 	 {
-		 map->putArtifactInstance(*h, ai, slot);
+		 map->putArtifactInstance(*h, ai->getId(), slot);
 		 return true;
 	 }
 	 else
@@ -1766,4 +1765,14 @@ ArtifactID CGameState::pickRandomArtifact(vstd::RNG & rand, int flags)
 	return pickRandomArtifact(rand, flags, [](const ArtifactID &) { return true; });
 }
 
+CArtifactInstance * CGameState::createScroll(const SpellID & spellId)
+{
+	return map->createScroll(spellId);
+}
+
+CArtifactInstance * CGameState::createArtifact(const ArtifactID & artID, const SpellID & spellId)
+{
+	return map->createArtifact(artID, spellId);
+}
+
 VCMI_LIB_NAMESPACE_END

+ 3 - 0
lib/gameState/CGameState.h

@@ -107,6 +107,9 @@ public:
 	ArtifactID pickRandomArtifact(vstd::RNG & rand, int flags, std::function<bool(ArtifactID)> accepts);
 	ArtifactID pickRandomArtifact(vstd::RNG & rand, std::set<ArtifactID> filtered);
 
+	CArtifactInstance * createScroll(const SpellID & spellId);
+	CArtifactInstance * createArtifact(const ArtifactID & artId, const SpellID & spellId = SpellID::NONE);
+
 	/// Returns battle in which selected player is engaged, or nullptr if none.
 	/// Can NOT be used with neutral player, use battle by ID instead
 	const BattleInfo * getBattle(const PlayerColor & player) const;

+ 3 - 3
lib/gameState/CGameStateCampaign.cpp

@@ -325,10 +325,10 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
 		}
 		case CampaignBonusType::SPELL_SCROLL:
 		{
-			CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2));
+			const auto scroll = gameState->createScroll(SpellID(curBonus->info2));
 			const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId());
 			if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
-				gameState->map->putArtifactInstance(*hero, scroll, slot);
+				gameState->map->putArtifactInstance(*hero, scroll->getId(), slot);
 			else
 				logGlobal->error("Cannot give starting scroll - no free slots!");
 			break;
@@ -432,7 +432,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO
 
 				const auto slot = ArtifactUtils::getArtAnyPosition(receiver, artifact->getTypeId());
 				if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
-					gameState->map->putArtifactInstance(*receiver, artifact, slot);
+					gameState->map->putArtifactInstance(*receiver, artifact->getId(), slot);
 				else
 					logGlobal->error("Cannot transfer artifact - no free slots!");
 			}

+ 7 - 7
lib/mapObjects/CGHeroInstance.cpp

@@ -405,7 +405,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
 		// hero starts with default spellbook presence status
 		if(!getArt(ArtifactPosition::SPELLBOOK) && getHeroType()->haveSpellBook)
 		{
-			auto artifact = ArtifactUtils::createArtifact(ArtifactID::SPELLBOOK);
+			auto artifact = cb->gameState()->createArtifact(ArtifactID::SPELLBOOK);
 			putArtifact(ArtifactPosition::SPELLBOOK, artifact);
 		}
 	}
@@ -414,7 +414,7 @@ void CGHeroInstance::initHero(vstd::RNG & rand)
 
 	if(!getArt(ArtifactPosition::MACH4))
 	{
-		auto artifact = ArtifactUtils::createArtifact(ArtifactID::CATAPULT);
+		auto artifact = cb->gameState()->createArtifact(ArtifactID::CATAPULT);
 		putArtifact(ArtifactPosition::MACH4, artifact); //everyone has a catapult
 	}
 
@@ -527,7 +527,7 @@ void CGHeroInstance::initArmy(vstd::RNG & rand, IArmyDescriptor * dst)
 
 				if(!getArt(slot))
 				{
-					auto artifact = ArtifactUtils::createArtifact(aid);
+					auto artifact = cb->gameState()->createArtifact(aid);
 					putArtifact(slot, artifact);
 				}
 				else
@@ -1236,12 +1236,12 @@ std::string CGHeroInstance::getBiographyTextID() const
 	return ""; //for random hero
 }
 
-CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(const ArtifactPosition & pos, CArtifactInstance * art)
+CGHeroInstance::ArtPlacementMap CGHeroInstance::putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art)
 {
 	assert(art->canBePutAt(this, pos));
 
 	if(ArtifactUtils::isSlotEquipment(pos))
-		attachTo(*art);
+		attachToSource(*art);
 	return CArtifactSet::putArtifact(pos, art);
 }
 
@@ -1252,7 +1252,7 @@ void CGHeroInstance::removeArtifact(const ArtifactPosition & pos)
 
 	CArtifactSet::removeArtifact(pos);
 	if(ArtifactUtils::isSlotEquipment(pos))
-		detachFrom(*art);
+		detachFromSource(*art);
 }
 
 bool CGHeroInstance::hasSpellbook() const
@@ -1768,7 +1768,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
 	handler.serializeIdArray("spellBook", spells);
 
 	if(handler.saving)
-		CArtifactSet::serializeJsonArtifacts(handler, "artifacts");
+		CArtifactSet::serializeJsonArtifacts(handler, "artifacts", &cb->gameState()->getMap());
 }
 
 void CGHeroInstance::serializeJsonOptions(JsonSerializeFormat & handler)

+ 1 - 1
lib/mapObjects/CGHeroInstance.h

@@ -260,7 +260,7 @@ public:
 	void initHero(vstd::RNG & rand);
 	void initHero(vstd::RNG & rand, const HeroTypeID & SUBID);
 
-	ArtPlacementMap putArtifact(const ArtifactPosition & pos, CArtifactInstance * art) override;
+	ArtPlacementMap putArtifact(const ArtifactPosition & pos, const CArtifactInstance * art) override;
 	void removeArtifact(const ArtifactPosition & pos) override;
 	void initExp(vstd::RNG & rand);
 	void initArmy(vstd::RNG & rand, IArmyDescriptor *dst = nullptr);

+ 2 - 13
lib/mapObjects/MiscObjects.cpp

@@ -663,10 +663,8 @@ void CGArtifact::initObj(vstd::RNG & rand)
 	if(ID == Obj::ARTIFACT)
 	{
 		if (!storedArtifact)
-		{
-			storedArtifact = ArtifactUtils::createArtifact(ArtifactID());
-			cb->gameState()->getMap().addNewArtifactInstance(storedArtifact);
-		}
+			storedArtifact = cb->gameState()->createArtifact(ArtifactID());
+
 		if(!storedArtifact->getType())
 			storedArtifact->setType(getArtifact().toArtifact());
 	}
@@ -813,15 +811,6 @@ void CGArtifact::blockingDialogAnswered(const CGHeroInstance *hero, int32_t answ
 		cb->startBattle(hero, this);
 }
 
-void CGArtifact::afterAddToMap(CMap * map)
-{
-	//Artifacts from map objects are never removed
-	//FIXME: This should be revertible in map editor
-
-	if(ID == Obj::SPELL_SCROLL && storedArtifact && storedArtifact->getId().getNum() < 0)
-        map->addNewArtifactInstance(storedArtifact);
-}
-
 void CGArtifact::serializeJsonOptions(JsonSerializeFormat& handler)
 {
 	handler.serializeStruct("guardMessage", message);

+ 0 - 1
lib/mapObjects/MiscObjects.h

@@ -109,7 +109,6 @@ public:
 	void initObj(vstd::RNG & rand) override;
 	void pickRandomObject(vstd::RNG & rand) override;
 
-	void afterAddToMap(CMap * map) override;
 	BattleField getBattlefield() const override;
 
 	ArtifactID getArtifact() const;

+ 60 - 35
lib/mapping/CMap.cpp

@@ -194,9 +194,6 @@ CMap::~CMap()
 	for(auto obj : objects)
 		obj.dellNull();
 
-	for(auto artInstance : artInstances)
-		artInstance.dellNull();
-
 	resetStaticData();
 }
 
@@ -467,33 +464,10 @@ void CMap::checkForObjectives()
 	}
 }
 
-void CMap::addNewArtifactInstance(CArtifactSet & artSet)
-{
-	for(const auto & [slot, slotInfo] : artSet.artifactsWorn)
-	{
-		if(!slotInfo.locked && slotInfo.getArt())
-			addNewArtifactInstance(slotInfo.artifact);
-	}
-	for(const auto & slotInfo : artSet.artifactsInBackpack)
-		addNewArtifactInstance(slotInfo.artifact);
-}
-
-void CMap::addNewArtifactInstance(ConstTransitivePtr<CArtifactInstance> art)
-{
-	assert(art);
-	assert(art->getId() == -1);
-	art->setId(static_cast<ArtifactInstanceID>(artInstances.size()));
-	artInstances.emplace_back(art);
-		
-	for(const auto & partInfo : art->getPartsInfo())
-		addNewArtifactInstance(partInfo.art);
-}
-
-void CMap::eraseArtifactInstance(CArtifactInstance * art)
+void CMap::eraseArtifactInstance(ArtifactInstanceID art)
 {
 	//TODO: handle for artifacts removed in map editor
-	assert(artInstances[art->getId().getNum()] == art);
-	artInstances[art->getId().getNum()].dellNull();
+	artInstances[art.getNum()] = nullptr;
 }
 
 void CMap::moveArtifactInstance(
@@ -502,26 +476,29 @@ void CMap::moveArtifactInstance(
 {
 	auto art = srcSet.getArt(srcSlot);
 	removeArtifactInstance(srcSet, srcSlot);
-	putArtifactInstance(dstSet, art, dstSlot);
+	putArtifactInstance(dstSet, art->getId(), dstSlot);
 }
 
-void CMap::putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot)
+void CMap::putArtifactInstance(CArtifactSet & set, ArtifactInstanceID artID, const ArtifactPosition & slot)
 {
-	art->addPlacementMap(set.putArtifact(slot, art));
+	auto artifact = artInstances.at(artID.getNum());
+
+	artifact->addPlacementMap(set.putArtifact(slot, artifact.get()));
 }
 
 void CMap::removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot)
 {
-	auto art = set.getArt(slot);
-	assert(art);
+	ArtifactInstanceID artID = set.getArtID(slot);
+	auto artifact = artInstances.at(artID.getNum());
+	assert(artifact);
 	set.removeArtifact(slot);
 	CArtifactSet::ArtPlacementMap partsMap;
-	for(auto & part : art->getPartsInfo())
+	for(auto & part : artifact->getPartsInfo())
 	{
 		if(part.slot != ArtifactPosition::PRE_FIRST)
 			partsMap.try_emplace(part.art, ArtifactPosition::PRE_FIRST);
 	}
-	art->addPlacementMap(partsMap);
+	artifact->addPlacementMap(partsMap);
 }
 
 void CMap::addNewQuestInstance(std::shared_ptr<CQuest> quest)
@@ -777,4 +754,52 @@ void CMap::overrideGameSettings(const JsonNode & input)
 	return gameSettings->loadOverrides(input);
 }
 
+CArtifactInstance * CMap::createScroll(const SpellID & spellId)
+{
+	return createArtifact(ArtifactID::SPELL_SCROLL, spellId);
+}
+
+CArtifactInstance * CMap::createSingleArtifact(const ArtifactID & artId, const SpellID & spellId)
+{
+	return new CArtifactInstance();
+}
+
+CArtifactInstance * CMap::createArtifact(const ArtifactID & artID, const SpellID & spellId)
+{
+	if(!artID.hasValue())
+		return new CArtifactInstance(); // random, empty //TODO: make this illegal & remove?
+
+	auto art = artID.toArtifact();
+
+	auto artInst = new CArtifactInstance(art);
+	if(art->isCombined() && !art->isFused())
+	{
+		for(const auto & part : art->getConstituents())
+			artInst->addPart(createArtifact(part->getId(), spellId), ArtifactPosition::PRE_FIRST);
+	}
+	if(art->isGrowing())
+	{
+		auto bonus = std::make_shared<Bonus>();
+		bonus->type = BonusType::LEVEL_COUNTER;
+		bonus->val = 0;
+		artInst->addNewBonus(bonus);
+	}
+	if(art->isScroll())
+	{
+		artInst->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
+													 BonusSource::ARTIFACT_INSTANCE, -1, BonusSourceID(ArtifactID(ArtifactID::SPELL_SCROLL)), BonusSubtypeID(spellId)));
+	}
+	return artInst;
+}
+
+CArtifactInstance * CMap::getArtifactInstance(const ArtifactInstanceID & artifactID)
+{
+	return artInstances.at(artifactID.getNum()).get();
+}
+
+const CArtifactInstance * CMap::getArtifactInstance(const ArtifactInstanceID & artifactID) const
+{
+	return artInstances.at(artifactID.getNum()).get();
+}
+
 VCMI_LIB_NAMESPACE_END

+ 11 - 5
lib/mapping/CMap.h

@@ -64,6 +64,8 @@ class DLL_LINKAGE CMap : public CMapHeader, public GameCallbackHolder
 	std::unique_ptr<GameSettings> gameSettings;
 
 	std::vector< std::shared_ptr<CQuest> > quests;
+	std::vector< std::shared_ptr<CArtifactInstance> > artInstances;
+
 public:
 	explicit CMap(IGameCallback *cb);
 	~CMap();
@@ -83,11 +85,16 @@ public:
 	void removeBlockVisTiles(CGObjectInstance * obj, bool total = false);
 	void calculateGuardingGreaturePositions();
 
-	void addNewArtifactInstance(CArtifactSet & artSet);
-	void addNewArtifactInstance(ConstTransitivePtr<CArtifactInstance> art);
-	void eraseArtifactInstance(CArtifactInstance * art);
+	CArtifactInstance * createScroll(const SpellID & spellId);
+	CArtifactInstance * createArtifact(const ArtifactID & artId, const SpellID & spellId = SpellID::NONE);
+	CArtifactInstance * createSingleArtifact(const ArtifactID & artId, const SpellID & spellId = SpellID::NONE);
+
+	CArtifactInstance * getArtifactInstance(const ArtifactInstanceID & artifactID);
+	const CArtifactInstance * getArtifactInstance(const ArtifactInstanceID & artifactID) const;
+
+	void eraseArtifactInstance(const ArtifactInstanceID art);
 	void moveArtifactInstance(CArtifactSet & srcSet, const ArtifactPosition & srcSlot, CArtifactSet & dstSet, const ArtifactPosition & dstSlot);
-	void putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot);
+	void putArtifactInstance(CArtifactSet & set, const ArtifactInstanceID art, const ArtifactPosition & slot);
 	void removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot);
 
 	void addNewQuestInstance(std::shared_ptr<CQuest> quest);
@@ -134,7 +141,6 @@ public:
 	//Central lists of items in game. Position of item in the vectors below is their (instance) id.
 	std::vector< ConstTransitivePtr<CGObjectInstance> > objects;
 	std::vector< ConstTransitivePtr<CGTownInstance> > towns;
-	std::vector< ConstTransitivePtr<CArtifactInstance> > artInstances;
 	std::vector< ConstTransitivePtr<CGHeroInstance> > allHeroes; //indexed by [hero_type_id]; on map, disposed, prisons, etc.
 
 	//Helper lists

+ 4 - 7
lib/mapping/MapFormatH3M.cpp

@@ -1006,9 +1006,8 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
 	// Artifact seems to be missing in game, so skip artifacts that don't fit target slot
 	if(ArtifactID(artifactID).toArtifact()->canBePutAt(hero, ArtifactPosition(slot)))
 	{
-		auto * artifact = ArtifactUtils::createArtifact(artifactID, scrollSpell);
-		map->putArtifactInstance(*hero, artifact, slot);
-		map->addNewArtifactInstance(artifact);
+		auto * artifact = map->createArtifact(artifactID, scrollSpell);
+		map->putArtifactInstance(*hero, artifact->getId(), slot);
 	}
 	else
 	{
@@ -1407,8 +1406,7 @@ CGObjectInstance * CMapLoaderH3M::readArtifact(const int3 & mapPosition, std::sh
 			logGlobal->warn("Map '%s': Artifact %s: not implemented pickup mode %d (flags: %d)", mapName, mapPosition.toString(), pickupMode, static_cast<int>(pickupFlags));
 	}
 
-	object->storedArtifact = ArtifactUtils::createArtifact(artID, SpellID::NONE);
-	map->addNewArtifactInstance(object->storedArtifact);
+	object->storedArtifact = map->createArtifact(artID, SpellID::NONE);
 	return object;
 }
 
@@ -1418,8 +1416,7 @@ CGObjectInstance * CMapLoaderH3M::readScroll(const int3 & mapPosition, std::shar
 	readMessageAndGuards(object->message, object, mapPosition);
 	SpellID spellID = reader->readSpell32();
 
-	object->storedArtifact = ArtifactUtils::createArtifact(ArtifactID::SPELL_SCROLL, spellID.getNum());
-	map->addNewArtifactInstance(object->storedArtifact);
+	object->storedArtifact = map->createArtifact(ArtifactID::SPELL_SCROLL, spellID.getNum());
 	return object;
 }
 

+ 2 - 4
lib/mapping/MapFormatJson.cpp

@@ -1105,15 +1105,13 @@ void CMapLoaderJson::MapObjectLoader::configure()
 			artID = art->getArtifact();
 		}
 
-		art->storedArtifact = ArtifactUtils::createArtifact(artID, spellID.getNum());
-		owner->map->addNewArtifactInstance(art->storedArtifact);
+		art->storedArtifact = owner->map->createArtifact(artID, spellID.getNum());
 	}
 
 	if(auto * hero = dynamic_cast<CGHeroInstance *>(instance))
 	{
 		auto o = handler.enterStruct("options");
-		hero->serializeJsonArtifacts(handler, "artifacts");
-		owner->map->addNewArtifactInstance(*hero);
+		hero->serializeJsonArtifacts(handler, "artifacts", owner->map);
 	}
 }
 

+ 19 - 15
lib/networkPacks/NetPacksLib.cpp

@@ -1513,8 +1513,7 @@ void NewObject::applyGs(CGameState *gs)
 
 void NewArtifact::applyGs(CGameState *gs)
 {
-	auto art = ArtifactUtils::createArtifact(artId, spellId);
-	gs->getMap().addNewArtifactInstance(art);
+	auto art = gs->createArtifact(artId, spellId);
 	PutArtifact pa(art->getId(), ArtifactLocation(artHolder, pos), false);
 	pa.applyGs(gs);
 }
@@ -1732,7 +1731,7 @@ void PutArtifact::applyGs(CGameState *gs)
 	assert(hero);
 	assert(art && art->canBePutAt(hero, al.slot));
 	assert(ArtifactUtils::checkIfSlotValid(*hero, al.slot));
-	gs->getMap().putArtifactInstance(*hero, art, al.slot);
+	gs->getMap().putArtifactInstance(*hero, art->getId(), al.slot);
 }
 
 void BulkEraseArtifacts::applyGs(CGameState *gs)
@@ -1797,7 +1796,7 @@ void BulkMoveArtifacts::applyGs(CGameState *gs)
 		{
 			auto * art = initArtSet.getArt(slotsPair.srcPos);
 			assert(art);
-			gs->getMap().putArtifactInstance(dstArtSet, art, slotsPair.dstPos);
+			gs->getMap().putArtifactInstance(dstArtSet, art->getId(), slotsPair.dstPos);
 		}
 	};
 	
@@ -1828,8 +1827,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
 			return art->getId() == builtArt->getId();
 		}));
 
-	auto * combinedArt = new CArtifactInstance(builtArt);
-	gs->getMap().addNewArtifactInstance(combinedArt);
+	auto * combinedArt = gs->getMap().createSingleArtifact(artId);
 
 	// Find slots for all involved artifacts
 	std::set<ArtifactPosition, std::greater<>> slotsInvolved = { al.slot };
@@ -1882,14 +1880,15 @@ void AssembledArtifact::applyGs(CGameState *gs)
 	}
 
 	// Put new combined artifacts
-	gs->getMap().putArtifactInstance(*artSet, combinedArt, al.slot);
+	gs->getMap().putArtifactInstance(*artSet, combinedArt->getId(), al.slot);
 }
 
 void DisassembledArtifact::applyGs(CGameState *gs)
 {
 	auto hero = gs->getHero(al.artHolder);
 	assert(hero);
-	auto disassembledArt = hero->getArt(al.slot);
+	auto disassembledArtID = hero->getArtID(al.slot);
+	auto disassembledArt = gs->getArtInstance(disassembledArtID);
 	assert(disassembledArt);
 
 	const auto parts = disassembledArt->getPartsInfo();
@@ -1898,10 +1897,10 @@ void DisassembledArtifact::applyGs(CGameState *gs)
 	{
 		// ArtifactPosition::PRE_FIRST is value of main part slot -> it'll replace combined artifact in its pos
 		auto slot = (ArtifactUtils::isSlotEquipment(part.slot) ? part.slot : al.slot);
-		disassembledArt->detachFrom(*part.art);
-		gs->getMap().putArtifactInstance(*hero, part.art, slot);
+		disassembledArt->detachFromSource(*part.art);
+		gs->getMap().putArtifactInstance(*hero, part.art->getId(), slot);
 	}
-	gs->getMap().eraseArtifactInstance(disassembledArt);
+	gs->getMap().eraseArtifactInstance(disassembledArt->getId());
 }
 
 void HeroVisit::applyGs(CGameState *gs)
@@ -2130,12 +2129,10 @@ void BattleResultAccepted::applyGs(CGameState *gs)
 			if(winnerHero->getCommander() && winnerHero->getCommander()->alive)
 			{
 				for(auto & art : winnerHero->getCommander()->artifactsWorn)
-					art.second.artifact->growingUp();
+					gs->getArtInstance(art.second.getID())->growingUp();
 			}
 			for(auto & art : winnerHero->artifactsWorn)
-			{
-				art.second.artifact->growingUp();
-			}
+				gs->getArtInstance(art.second.getID())->growingUp();
 		}
 	}
 
@@ -2503,4 +2500,11 @@ const CArtifactInstance * ArtSlotInfo::getArt() const
 	return artifact;
 }
 
+ArtifactInstanceID ArtSlotInfo::getID() const
+{
+	if(locked || artifact == nullptr)
+		return {};
+	return artifact->getId();
+}
+
 VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/rmg/modificators/TreasurePlacer.cpp

@@ -278,7 +278,7 @@ void TreasurePlacer::addScrolls()
 				if(map.isAllowedSpell(spellID) && spellID.toSpell()->getLevel() == i + 1)
 					out.push_back(spellID);
 			}
-			auto * a = ArtifactUtils::createScroll(*RandomGeneratorUtil::nextItem(out, zone.getRand()));
+			auto * a = map.mapInstance->createScroll(*RandomGeneratorUtil::nextItem(out, zone.getRand()));
 			obj->storedArtifact = a;
 			return obj;
 		};

+ 1 - 1
lib/serializer/BinaryDeserializer.h

@@ -330,7 +330,7 @@ public:
 			{
 				// This pointers is already loaded. The "data" needs to be pointed to it,
 				// so their shared state is actually shared.
-				data = std::static_pointer_cast<T>(itr->second);
+				data = std::dynamic_pointer_cast<T>(itr->second);
 			}
 			else
 			{

+ 2 - 2
lib/serializer/CSerializer.cpp

@@ -27,8 +27,8 @@ void CSerializer::addStdVecItems(CGameState *gs, GameLibrary *lib)
 		[](const CGObjectInstance &obj){ return obj.id; });
 	registerVectoredType<CGHeroInstance, HeroTypeID>(&gs->getMap().allHeroes,
 		[](const CGHeroInstance &h){ return h.getHeroType()->getId(); });
-	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->getMap().artInstances,
-		[](const CArtifactInstance &artInst){ return artInst.getId(); });
+//	registerVectoredType<CArtifactInstance, ArtifactInstanceID>(&gs->getMap().artInstances,
+//		[](const CArtifactInstance &artInst){ return artInst.getId(); });
 // TODO
 //	registerVectoredType<CQuest, si32>(&gs->getMap().quests,
 //		[](const CQuest &q){ return q.qid; });

+ 11 - 4
mapeditor/inspector/heroartifactswidget.cpp

@@ -13,12 +13,16 @@
 #include "ui_heroartifactswidget.h"
 #include "inspector.h"
 #include "mapeditorroles.h"
+#include "../mapcontroller.h"
+
 #include "../../lib/ArtifactUtils.h"
 #include "../../lib/constants/StringConstants.h"
+#include "../../lib/mapping/CMap.h"
 
-HeroArtifactsWidget::HeroArtifactsWidget(CGHeroInstance & h, QWidget * parent) :
+HeroArtifactsWidget::HeroArtifactsWidget(MapController & controller, CGHeroInstance & h, QWidget * parent) :
 	QDialog(parent),
 	ui(new Ui::HeroArtifactsWidget),
+	controller(controller),
 	hero(h),
 	fittingSet(CArtifactFittingSet(h))
 {
@@ -52,7 +56,7 @@ void HeroArtifactsWidget::on_removeButton_clicked()
 
 void HeroArtifactsWidget::onSaveArtifact(int32_t artifactIndex, ArtifactPosition slot) 
 {
-	auto artifact = ArtifactUtils::createArtifact(LIBRARY->arth->getByIndex(artifactIndex)->getId());
+	auto artifact = controller.map()->createArtifact(LIBRARY->arth->getByIndex(artifactIndex)->getId());
 	fittingSet.putArtifact(slot, artifact);
 	addArtifactToTable(artifactIndex, slot);
 }
@@ -110,13 +114,16 @@ void HeroArtifactsWidget::commitChanges()
 	}
 }
 
-HeroArtifactsDelegate::HeroArtifactsDelegate(CGHeroInstance & h) : BaseInspectorItemDelegate(), hero(h)
+HeroArtifactsDelegate::HeroArtifactsDelegate(MapController & controller, CGHeroInstance & h)
+	: BaseInspectorItemDelegate()
+	, controller(controller)
+	, hero(h)
 {
 }
 
 QWidget * HeroArtifactsDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const
 {
-	return new HeroArtifactsWidget(hero, parent);
+	return new HeroArtifactsWidget(controller, hero, parent);
 }
 
 void HeroArtifactsDelegate::setEditorData(QWidget * editor, const QModelIndex & index) const

+ 6 - 2
mapeditor/inspector/heroartifactswidget.h

@@ -17,12 +17,14 @@ namespace Ui {
 class HeroArtifactsWidget;
 }
 
+class MapController;
+
 class HeroArtifactsWidget : public QDialog
 {
 	Q_OBJECT
 
 public:
-	explicit HeroArtifactsWidget(CGHeroInstance &, QWidget *parent = nullptr);
+	explicit HeroArtifactsWidget(MapController & controller, CGHeroInstance &, QWidget *parent = nullptr);
 	~HeroArtifactsWidget();
 	
 	void obtainData();
@@ -42,6 +44,7 @@ private:
 	};
 	Ui::HeroArtifactsWidget * ui;
 	
+	MapController & controller;
 	CGHeroInstance & hero;
 	CArtifactFittingSet fittingSet;
 
@@ -55,7 +58,7 @@ class HeroArtifactsDelegate : public BaseInspectorItemDelegate
 public:
 	using BaseInspectorItemDelegate::BaseInspectorItemDelegate;
 	
-	HeroArtifactsDelegate(CGHeroInstance &);
+	HeroArtifactsDelegate(MapController & controller, CGHeroInstance &);
 	
 	QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
 	void setEditorData(QWidget * editor, const QModelIndex & index) const override;
@@ -63,5 +66,6 @@ public:
 	void updateModelData(QAbstractItemModel * model, const QModelIndex & index) const override;
 	
 private:
+	MapController & controller;
 	CGHeroInstance & hero;
 };

+ 6 - 4
mapeditor/inspector/inspector.cpp

@@ -38,7 +38,9 @@
 #include "../mapcontroller.h"
 
 //===============IMPLEMENT OBJECT INITIALIZATION FUNCTIONS================
-Initializer::Initializer(CGObjectInstance * o, const PlayerColor & pl) : defaultPlayer(pl)
+Initializer::Initializer(MapController & controller, CGObjectInstance * o, const PlayerColor & pl)
+	: defaultPlayer(pl)
+	, controller(controller)
 {
 	logGlobal->info("New object instance initialized");
 ///IMPORTANT! initialize order should be from base objects to derived objects
@@ -203,7 +205,7 @@ void Initializer::initialize(CGArtifact * o)
 				out.push_back(spell->id);
 			}
 		}
-		auto a = ArtifactUtils::createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
+		auto a = controller.map()->createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
 		o->storedArtifact = a;
 	}
 }
@@ -320,7 +322,7 @@ void Inspector::updateProperties(CGHeroInstance * o)
 	auto * delegate = new HeroSkillsDelegate(*o);
 	addProperty(QObject::tr("Skills"), PropertyEditorPlaceholder(), delegate, false);
 	addProperty(QObject::tr("Spells"), PropertyEditorPlaceholder(), new HeroSpellDelegate(*o), false);
-	addProperty(QObject::tr("Artifacts"), PropertyEditorPlaceholder(), new HeroArtifactsDelegate(*o), false);
+	addProperty(QObject::tr("Artifacts"), PropertyEditorPlaceholder(), new HeroArtifactsDelegate(controller, *o), false);
 	
 	if(o->getHeroTypeID().hasValue() || o->ID == Obj::PRISON)
 	{ //Hero type
@@ -640,7 +642,7 @@ void Inspector::setProperty(CGArtifact * o, const QString & key, const QVariant
 	
 	if(o->storedArtifact && key == QObject::tr("Spell"))
 	{
-		o->storedArtifact = ArtifactUtils::createScroll(SpellID(value.toInt()));
+		o->storedArtifact = controller.map()->createScroll(SpellID(value.toInt()));
 	}
 }
 

+ 2 - 1
mapeditor/inspector/inspector.h

@@ -57,9 +57,10 @@ public:
 	//DECLARE_OBJ_TYPE(CGPandoraBox);
 	//DECLARE_OBJ_TYPE(CGSeerHut);
 	
-	Initializer(CGObjectInstance *, const PlayerColor &);
+	Initializer(MapController & controller, CGObjectInstance *, const PlayerColor &);
 
 private:
+	MapController & controller;
 	PlayerColor defaultPlayer;
 };
 

+ 4 - 4
mapeditor/mapcontroller.cpp

@@ -144,7 +144,7 @@ void MapController::repairMap(CMap * map)
 			{
 				nih->removeSpellFromSpellbook(SpellID::SPELLBOOK_PRESET);
 				if(!nih->getArt(ArtifactPosition::SPELLBOOK) && type->haveSpellBook)
-					nih->putArtifact(ArtifactPosition::SPELLBOOK, ArtifactUtils::createArtifact(ArtifactID::SPELLBOOK));
+					nih->putArtifact(ArtifactPosition::SPELLBOOK, map->createArtifact(ArtifactID::SPELLBOOK));
 			}
 			
 		}
@@ -177,7 +177,7 @@ void MapController::repairMap(CMap * map)
 						out.push_back(spell->id);
 					}
 				}
-				auto a = ArtifactUtils::createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
+				auto a = map->createScroll(*RandomGeneratorUtil::nextItem(out, CRandomGenerator::getDefault()));
 				art->storedArtifact = a;
 			}
 		}
@@ -376,7 +376,7 @@ void MapController::pasteFromClipboard(int level)
 			obj->pos = newPos;
 		obj->pos.z = level;
 		
-		Initializer init(obj, defaultPlayer);
+		Initializer init(*this, obj, defaultPlayer);
 		_map->getEditManager()->insertObject(obj);
 		_scenes[level]->selectionObjectsView.selectObject(obj);
 		_mapHandler->invalidate(obj);
@@ -521,7 +521,7 @@ void MapController::commitObjectCreate(int level)
 	
 	newObj->pos = pos;
 	
-	Initializer init(newObj, defaultPlayer);
+	Initializer init(*this, newObj, defaultPlayer);
 	
 	_map->getEditManager()->insertObject(newObj);
 	_mapHandler->invalidate(newObj);