Răsfoiți Sursa

CMap put move and remove artifact method

SoundSSGood 1 an în urmă
părinte
comite
b9ae7f1138

+ 1 - 1
client/Client.h

@@ -188,7 +188,7 @@ public:
 	bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;};
 	bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override {return false;};
 	bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;};
-	bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override {return false;};
+	bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override {return false;};
 	void removeArtifact(const ArtifactLocation & al) override {};
 	bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;};
 

+ 2 - 2
client/widgets/CArtifactsOfHeroBase.cpp

@@ -137,9 +137,9 @@ void CArtifactsOfHeroBase::scrollBackpack(bool left)
 	LOCPLINT->cb->scrollBackpackArtifacts(curHero->id, left);
 }
 
-void CArtifactsOfHeroBase::markPossibleSlots(const CArtifactInstance * art, bool assumeDestRemoved)
+void CArtifactsOfHeroBase::markPossibleSlots(const CArtifact * art, bool assumeDestRemoved)
 {
-	for(auto artPlace : artWorn)
+	for(const auto & artPlace : artWorn)
 		artPlace.second->selectSlot(art->canBePutAt(curHero, artPlace.second->slot, assumeDestRemoved));
 }
 

+ 1 - 1
client/widgets/CArtifactsOfHeroBase.h

@@ -39,7 +39,7 @@ public:
 	virtual void setHero(const CGHeroInstance * hero);
 	virtual const CGHeroInstance * getHero() const;
 	virtual void scrollBackpack(bool left);
-	virtual void markPossibleSlots(const CArtifactInstance * art, bool assumeDestRemoved = true);
+	virtual void markPossibleSlots(const CArtifact * art, bool assumeDestRemoved = true);
 	virtual void unmarkSlots();
 	virtual ArtPlacePtr getArtPlace(const ArtifactPosition & slot);
 	virtual ArtPlacePtr getArtPlace(const Point & cursorPosition);

+ 3 - 6
client/windows/CWindowWithArtifacts.cpp

@@ -62,15 +62,12 @@ const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact() const
 
 const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const
 {
-	const CArtifactInstance * art = nullptr;
-
 	for(const auto & artSet : artSets)
 		if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
 		{
-			art = pickedArt;
-			break;
+			return pickedArt;
 		}
-	return art;
+	return nullptr;
 }
 
 void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot,
@@ -202,7 +199,7 @@ void CWindowWithArtifacts::markPossibleSlots() const
 				continue;
 
 			if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast<CArtifactsOfHeroKingdom>(artSet))
-				artSet->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID);
+				artSet->markPossibleSlots(pickedArtInst->artType, hero->tempOwner == LOCPLINT->playerID);
 		}
 	}
 }

+ 3 - 25
lib/CArtifactInstance.cpp

@@ -49,13 +49,13 @@ const std::vector<CCombinedArtifactInstance::PartInfo> & CCombinedArtifactInstan
 	return partsInfo;
 }
 
-void CCombinedArtifactInstance::addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap)
+void CCombinedArtifactInstance::addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap)
 {
 	if(!placementMap.empty())
 		for(auto & part : partsInfo)
 		{
-			assert(placementMap.find(part.art) != placementMap.end());
-			part.slot = placementMap.at(part.art);
+			if(placementMap.find(part.art) != placementMap.end())
+				part.slot = placementMap.at(part.art);
 		}
 }
 
@@ -167,28 +167,6 @@ bool CArtifactInstance::isScroll() const
 	return artType->isScroll();
 }
 
-void CArtifactInstance::putAt(CArtifactSet & set, const ArtifactPosition slot)
-{
-	auto placementMap = set.putArtifact(slot, this);
-	addPlacementMap(placementMap);
-}
-
-void CArtifactInstance::removeFrom(CArtifactSet & set, const ArtifactPosition slot)
-{
-	set.removeArtifact(slot);
-	for(auto & part : partsInfo)
-	{
-		if(part.slot != ArtifactPosition::PRE_FIRST)
-			part.slot = ArtifactPosition::PRE_FIRST;
-	}
-}
-
-void CArtifactInstance::move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot)
-{
-	removeFrom(srcSet, srcSlot);
-	putAt(dstSet, dstSlot);
-}
-
 void CArtifactInstance::deserializationFix()
 {
 	setType(artType);

+ 2 - 5
lib/CArtifactInstance.h

@@ -25,7 +25,7 @@ protected:
 public:
 	struct PartInfo
 	{
-		ConstTransitivePtr<CArtifactInstance> art;
+		CArtifactInstance * art;
 		ArtifactPosition slot;
 		template <typename Handler> void serialize(Handler & h)
 		{
@@ -39,7 +39,7 @@ public:
 	// Checks if supposed part inst is part of this combined art inst
 	bool isPart(const CArtifactInstance * supposedPart) const;
 	const std::vector<PartInfo> & getPartsInfo() const;
-	void addPlacementMap(CArtifactSet::ArtPlacementMap & placementMap);
+	void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap);
 
 	template <typename Handler> void serialize(Handler & h)
 	{
@@ -88,9 +88,6 @@ public:
 		bool assumeDestRemoved = false) const;
 	bool isCombined() const;
 	bool isScroll() const;
-	void putAt(CArtifactSet & set, const ArtifactPosition slot);
-	void removeFrom(CArtifactSet & set, const ArtifactPosition slot);
-	void move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot);
 	
 	void deserializationFix();
 	template <typename Handler> void serialize(Handler & h)

+ 1 - 1
lib/IGameCallback.h

@@ -122,7 +122,7 @@ public:
 
 	virtual bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) = 0;
 	virtual bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) = 0;
-	virtual bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble = std::nullopt) = 0;
+	virtual bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble = std::nullopt) = 0;
 	virtual void removeArtifact(const ArtifactLocation& al) = 0;
 	virtual bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) = 0;
 

+ 1 - 1
lib/gameState/CGameState.cpp

@@ -1638,7 +1638,7 @@ bool CGameState::giveHeroArtifact(CGHeroInstance * h, const ArtifactID & aid)
 	 auto slot = ArtifactUtils::getArtAnyPosition(h, aid);
 	 if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
 	 {
-		 ai->putAt(*h, slot);
+		 map->putArtifactInstance(*h, ai, slot);
 		 return true;
 	 }
 	 else

+ 4 - 4
lib/gameState/CGameStateCampaign.cpp

@@ -147,7 +147,7 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr
 				if (!locked && !takeable)
 				{
 					logGlobal->debug("Removing artifact %s from slot %d of hero %s", art->artType->getJsonKey(), al.slot.getNum(), hero.hero->getHeroTypeName());
-					hero.hero->getArt(al.slot)->removeFrom(*hero.hero, al.slot);
+					gameState->map->removeArtifactInstance(*hero.hero, al.slot);
 					return true;
 				}
 				return false;
@@ -327,7 +327,7 @@ void CGameStateCampaign::giveCampaignBonusToHero(CGHeroInstance * hero)
 			CArtifactInstance * scroll = ArtifactUtils::createScroll(SpellID(curBonus->info2));
 			const auto slot = ArtifactUtils::getArtAnyPosition(hero, scroll->getTypeId());
 			if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
-				scroll->putAt(*hero, slot);
+				gameState->map->putArtifactInstance(*hero, scroll, slot);
 			else
 				logGlobal->error("Cannot give starting scroll - no free slots!");
 			break;
@@ -423,7 +423,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO
 			auto * artifact = donorHero->getArt(artLocation);
 
 			logGlobal->debug("Removing artifact %s from slot %d of hero %s for transfer", artifact->artType->getJsonKey(), artLocation.getNum(), donorHero->getHeroTypeName());
-			artifact->removeFrom(*donorHero, artLocation);
+			gameState->map->removeArtifactInstance(*donorHero, artLocation);
 
 			if (receiver)
 			{
@@ -431,7 +431,7 @@ void CGameStateCampaign::transferMissingArtifacts(const CampaignTravel & travelO
 
 				const auto slot = ArtifactUtils::getArtAnyPosition(receiver, artifact->getTypeId());
 				if(ArtifactUtils::isSlotEquipment(slot) || ArtifactUtils::isSlotBackpack(slot))
-					artifact->putAt(*receiver, slot);
+					gameState->map->putArtifactInstance(*receiver, artifact, slot);
 				else
 					logGlobal->error("Cannot transfer artifact - no free slots!");
 			}

+ 1 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -1201,7 +1201,7 @@ void CGHeroInstance::removeSpellbook()
 
 	if(hasSpellbook())
 	{
-		getArt(ArtifactPosition::SPELLBOOK)->removeFrom(*this, ArtifactPosition::SPELLBOOK);
+		//VLC->arth->removeArtifactFrom(*this, ArtifactPosition::SPELLBOOK);
 	}
 }
 

+ 3 - 4
lib/mapObjects/MiscObjects.cpp

@@ -772,9 +772,8 @@ void CGArtifact::initObj(vstd::RNG & rand)
 	{
 		if (!storedArtifact)
 		{
-			auto * a = new CArtifactInstance();
-			cb->gameState()->map->addNewArtifactInstance(a);
-			storedArtifact = a;
+			storedArtifact = ArtifactUtils::createArtifact(ArtifactID());
+			cb->gameState()->map->addNewArtifactInstance(storedArtifact);
 		}
 		if(!storedArtifact->artType)
 			storedArtifact->setType(getArtifact().toArtifact());
@@ -901,7 +900,7 @@ void CGArtifact::onHeroVisit(const CGHeroInstance * h) const
 
 void CGArtifact::pick(const CGHeroInstance * h) const
 {
-	if(cb->putArtifact(ArtifactLocation(h->id, ArtifactPosition::FIRST_AVAILABLE), storedArtifact))
+	if(cb->putArtifact(ArtifactLocation(h->id, ArtifactPosition::FIRST_AVAILABLE), storedArtifact->getId()))
 		cb->removeObject(this, h->getOwner());
 }
 

+ 28 - 0
lib/mapping/CMap.cpp

@@ -552,6 +552,34 @@ void CMap::eraseArtifactInstance(CArtifactInstance * art)
 	artInstances[art->getId().getNum()].dellNull();
 }
 
+void CMap::moveArtifactInstance(
+	CArtifactSet & srcSet, const ArtifactPosition & srcSlot,
+	CArtifactSet & dstSet, const ArtifactPosition & dstSlot)
+{
+	auto art = srcSet.getArt(srcSlot);
+	removeArtifactInstance(srcSet, srcSlot);
+	putArtifactInstance(dstSet, art, dstSlot);
+}
+
+void CMap::putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot)
+{
+	art->addPlacementMap(set.putArtifact(slot, art));
+}
+
+void CMap::removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot)
+{
+	auto art = set.getArt(slot);
+	assert(art);
+	set.removeArtifact(slot);
+	CArtifactSet::ArtPlacementMap partsMap;
+	for(auto & part : art->getPartsInfo())
+	{
+		if(part.slot != ArtifactPosition::PRE_FIRST)
+			partsMap.try_emplace(part.art, ArtifactPosition::PRE_FIRST);
+	}
+	art->addPlacementMap(partsMap);
+}
+
 void CMap::addNewQuestInstance(CQuest* quest)
 {
 	quest->qid = static_cast<si32>(quests.size());

+ 3 - 0
lib/mapping/CMap.h

@@ -110,6 +110,9 @@ public:
 	void addNewArtifactInstance(CArtifactSet & artSet);
 	void addNewArtifactInstance(ConstTransitivePtr<CArtifactInstance> art);
 	void eraseArtifactInstance(CArtifactInstance * art);
+	void moveArtifactInstance(CArtifactSet & srcSet, const ArtifactPosition & srcSlot, CArtifactSet & dstSet, const ArtifactPosition & dstSlot);
+	void putArtifactInstance(CArtifactSet & set, CArtifactInstance * art, const ArtifactPosition & slot);
+	void removeArtifactInstance(CArtifactSet & set, const ArtifactPosition & slot);
 
 	void addNewQuestInstance(CQuest * quest);
 	void removeQuestInstance(CQuest * quest);

+ 1 - 1
lib/mapping/MapFormatH3M.cpp

@@ -959,7 +959,7 @@ bool CMapLoaderH3M::loadArtifactToSlot(CGHeroInstance * hero, int slot)
 	if(ArtifactID(artifactID).toArtifact()->canBePutAt(hero, ArtifactPosition(slot)))
 	{
 		auto * artifact = ArtifactUtils::createArtifact(artifactID);
-		artifact->putAt(*hero, ArtifactPosition(slot));
+		map->putArtifactInstance(*hero, artifact, slot);
 		map->addNewArtifactInstance(artifact);
 	}
 	else

+ 17 - 25
lib/networkPacks/NetPacksLib.cpp

@@ -1471,8 +1471,7 @@ void NewArtifact::applyGs(CGameState *gs)
 {
 	auto art = ArtifactUtils::createArtifact(artId, spellId);
 	gs->map->addNewArtifactInstance(art);
-	PutArtifact pa(ArtifactLocation(artHolder, pos), false);
-	pa.art = art;
+	PutArtifact pa(art->getId(), ArtifactLocation(artHolder, pos), false);
 	pa.applyGs(gs);
 }
 
@@ -1591,14 +1590,14 @@ void RebalanceStacks::applyGs(CGameState *gs)
 			const auto dstHero = dynamic_cast<CGHeroInstance*>(dst.army.get());
 			auto srcStack = const_cast<CStackInstance*>(src.getStack());
 			auto dstStack = const_cast<CStackInstance*>(dst.getStack());
-			if(auto srcArt = srcStack->getArt(ArtifactPosition::CREATURE_SLOT))
+			if(srcStack->getArt(ArtifactPosition::CREATURE_SLOT))
 			{
 				if(auto dstArt = dstStack->getArt(ArtifactPosition::CREATURE_SLOT))
 				{
 					auto dstSlot = ArtifactUtils::getArtBackpackPosition(srcHero, dstArt->getTypeId());
 					if(srcHero && dstSlot != ArtifactPosition::PRE_FIRST)
 					{
-						dstArt->move(*dstStack, ArtifactPosition::CREATURE_SLOT, *srcHero, dstSlot);
+						gs->map->moveArtifactInstance(*dstStack, ArtifactPosition::CREATURE_SLOT, *srcHero, dstSlot);
 					}
 					//else - artifact can be lost :/
 					else
@@ -1610,12 +1609,12 @@ void RebalanceStacks::applyGs(CGameState *gs)
 						ea.applyGs(gs);
 						logNetwork->warn("Cannot move artifact! No free slots");
 					}
-					srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
+					gs->map->moveArtifactInstance(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
 					//TODO: choose from dialog
 				}
 				else //just move to the other slot before stack gets erased
 				{
-					srcArt->move(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
+					gs->map->moveArtifactInstance(*srcStack, ArtifactPosition::CREATURE_SLOT, *dstStack, ArtifactPosition::CREATURE_SLOT);
 				}
 			}
 			if (stackExp)
@@ -1685,14 +1684,13 @@ void BulkSmartRebalanceStacks::applyGs(CGameState *gs)
 
 void PutArtifact::applyGs(CGameState *gs)
 {
-	// Ensure that artifact has been correctly added via NewArtifact pack
-	assert(vstd::contains(gs->map->artInstances, art));
+	auto art = gs->getArtInstance(id);
 	assert(!art->getParentNodes().empty());
 	auto hero = gs->getHero(al.artHolder);
 	assert(hero);
 	assert(art && art->canBePutAt(hero, al.slot));
 	assert(ArtifactUtils::checkIfSlotValid(*hero, al.slot));
-	art->putAt(*hero, al.slot);
+	gs->map->putArtifactInstance(*hero, art, al.slot);
 }
 
 void BulkEraseArtifacts::applyGs(CGameState *gs)
@@ -1731,15 +1729,13 @@ void BulkEraseArtifacts::applyGs(CGameState *gs)
 		{
 			logGlobal->debug("Erasing artifact %s", slotInfo->artifact->artType->getNameTranslated());
 		}
-		auto art = artSet->getArt(slot);
-		assert(art);
-		art->removeFrom(*artSet, slot);
+		gs->map->removeArtifactInstance(*artSet, slot);
 	}
 }
 
 void BulkMoveArtifacts::applyGs(CGameState *gs)
 {
-	const auto bulkArtsRemove = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet)
+	const auto bulkArtsRemove = [gs](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet)
 	{
 		std::vector<ArtifactPosition> packToRemove;
 		for(const auto & slotsPair : artsPack)
@@ -1750,20 +1746,16 @@ void BulkMoveArtifacts::applyGs(CGameState *gs)
 			});
 
 		for(const auto & slot : packToRemove)
-		{
-			auto * art = artSet.getArt(slot);
-			assert(art);
-			art->removeFrom(artSet, slot);
-		}
+			gs->map->removeArtifactInstance(artSet, slot);
 	};
 
-	const auto bulkArtsPut = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet)
+	const auto bulkArtsPut = [gs](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet)
 	{
 		for(const auto & slotsPair : artsPack)
 		{
 			auto * art = initArtSet.getArt(slotsPair.srcPos);
 			assert(art);
-			art->putAt(dstArtSet, slotsPair.dstPos);
+			gs->map->putArtifactInstance(dstArtSet, art, slotsPair.dstPos);
 		}
 	};
 	
@@ -1840,7 +1832,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
 	for(const auto slot : slotsInvolved)
 	{
 		const auto constituentInstance = hero->getArt(slot);
-		constituentInstance->removeFrom(*hero, slot);
+		gs->map->removeArtifactInstance(*hero, slot);
 
 		if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot)
 			combinedArt->addPart(constituentInstance, slot);
@@ -1849,7 +1841,7 @@ void AssembledArtifact::applyGs(CGameState *gs)
 	}
 
 	// Put new combined artifacts
-	combinedArt->putAt(*hero, al.slot);
+	gs->map->putArtifactInstance(*hero, combinedArt, al.slot);
 }
 
 void DisassembledArtifact::applyGs(CGameState *gs)
@@ -1859,14 +1851,14 @@ void DisassembledArtifact::applyGs(CGameState *gs)
 	auto disassembledArt = hero->getArt(al.slot);
 	assert(disassembledArt);
 
-	auto parts = disassembledArt->getPartsInfo();
-	disassembledArt->removeFrom(*hero, al.slot);
+	const auto parts = disassembledArt->getPartsInfo();
+	gs->map->removeArtifactInstance(*hero, al.slot);
 	for(auto & part : parts)
 	{
 		// 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);
-		part.art->putAt(*hero, slot);
+		gs->map->putArtifactInstance(*hero, part.art, slot);
 	}
 	gs->map->eraseArtifactInstance(disassembledArt);
 }

+ 4 - 4
lib/networkPacks/PacksForClient.h

@@ -965,14 +965,14 @@ struct DLL_LINKAGE CArtifactOperationPack : CPackForClient
 struct DLL_LINKAGE PutArtifact : CArtifactOperationPack
 {
 	PutArtifact() = default;
-	explicit PutArtifact(const ArtifactLocation & dst, bool askAssemble = true)
-		: al(dst), askAssemble(askAssemble)
+	explicit PutArtifact(const ArtifactInstanceID & id, const ArtifactLocation & dst, bool askAssemble = true)
+		: id(id), al(dst), askAssemble(askAssemble)
 	{
 	}
 
 	ArtifactLocation al;
 	bool askAssemble;
-	ConstTransitivePtr<CArtifactInstance> art;
+	ArtifactInstanceID id;
 
 	void applyGs(CGameState * gs) override;
 	void visitTyped(ICPackVisitor & visitor) override;
@@ -981,7 +981,7 @@ struct DLL_LINKAGE PutArtifact : CArtifactOperationPack
 	{
 		h & al;
 		h & askAssemble;
-		h & art;
+		h & id;
 	}
 };
 

+ 7 - 7
server/CGameHandler.cpp

@@ -3757,9 +3757,10 @@ bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & s
 	}
 }
 
-bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble)
+bool CGameHandler::putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble)
 {
-	assert(art && art->artType);
+	const auto artInst = getArtInstance(id);
+	assert(artInst && artInst->artType);
 	ArtifactLocation dst(al.artHolder, ArtifactPosition::PRE_FIRST);
 	dst.creature = al.creature;
 	auto putTo = getArtSet(al);
@@ -3767,11 +3768,11 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta
 
 	if(al.slot == ArtifactPosition::FIRST_AVAILABLE)
 	{
-		dst.slot = ArtifactUtils::getArtAnyPosition(putTo, art->getTypeId());
+		dst.slot = ArtifactUtils::getArtAnyPosition(putTo, artInst->getTypeId());
 	}
 	else if(ArtifactUtils::isSlotBackpack(al.slot) && !al.creature.has_value())
 	{
-		dst.slot = ArtifactUtils::getArtBackpackPosition(putTo, art->getTypeId());
+		dst.slot = ArtifactUtils::getArtBackpackPosition(putTo, artInst->getTypeId());
 	}
 	else
 	{
@@ -3786,10 +3787,9 @@ bool CGameHandler::putArtifact(const ArtifactLocation & al, const CArtifactInsta
 			askAssemble = false;
 	}
 
-	if(art->canBePutAt(putTo, dst.slot))
+	if(artInst->canBePutAt(putTo, dst.slot))
 	{
-		PutArtifact pa(dst, askAssemble.value());
-		pa.art = art;
+		PutArtifact pa(id, dst, askAssemble.value());
 		sendAndApply(&pa);
 		return true;
 	}

+ 1 - 1
server/CGameHandler.h

@@ -136,7 +136,7 @@ public:
 	bool giveHeroNewArtifact(const CGHeroInstance * h, const CArtifact * artType, const SpellID & spellId, const ArtifactPosition & pos);
 	bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override;
 	bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override;
-	bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override;
+	bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override;
 	void removeArtifact(const ArtifactLocation &al) override;
 	void removeArtifact(const ObjectInstanceID & srcId, const std::vector<ArtifactPosition> & slotsPack);
 	bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override;

+ 1 - 1
test/mock/mock_IGameCallback.h

@@ -72,7 +72,7 @@ public:
 
 	bool giveHeroNewArtifact(const CGHeroInstance * h, const ArtifactID & artId, const ArtifactPosition & pos) override {return false;}
 	bool giveHeroNewScroll(const CGHeroInstance * h, const SpellID & spellId, const ArtifactPosition & pos) override {return false;}
-	bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override {return false;}
+	bool putArtifact(const ArtifactLocation & al, const ArtifactInstanceID & id, std::optional<bool> askAssemble) override {return false;}
 	void removeArtifact(const ArtifactLocation &al) override {}
 	bool moveArtifact(const PlayerColor & player, const ArtifactLocation & al1, const ArtifactLocation & al2) override {return false;}