SoundSSGood 1 gadu atpakaļ
vecāks
revīzija
09bb9895ce

+ 17 - 3
client/widgets/CArtifactsOfHeroBase.cpp

@@ -90,20 +90,29 @@ void CArtifactsOfHeroBase::init(
 
 void CArtifactsOfHeroBase::clickPrassedArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
 {
+	if(artPlace.isLocked())
+		return;
+
 	if(clickPressedCallback)
-		clickPressedCallback(*this, artPlace, cursorPosition);
+		clickPressedCallback(artPlace, cursorPosition);
 }
 
 void CArtifactsOfHeroBase::showPopupArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
 {
+	if(artPlace.isLocked())
+		return;
+
 	if(showPopupCallback)
-		showPopupCallback(*this, artPlace, cursorPosition);
+		showPopupCallback(artPlace, cursorPosition);
 }
 
 void CArtifactsOfHeroBase::gestureArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
 {
+	if(artPlace.isLocked())
+		return;
+
 	if(gestureCallback)
-		gestureCallback(*this, artPlace, cursorPosition);
+		gestureCallback(artPlace, cursorPosition);
 }
 
 void CArtifactsOfHeroBase::setHero(const CGHeroInstance * hero)
@@ -226,6 +235,11 @@ void CArtifactsOfHeroBase::addGestureCallback(CArtPlace::ClickFunctor callback)
 	}
 }
 
+const CArtifactInstance * CArtifactsOfHeroBase::getArt(const ArtifactPosition & slot)
+{
+	return curHero ? curHero->getArt(slot) : nullptr;
+}
+
 void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot)
 {
 	// Spurious call from artifactMoved in attempt to update hidden backpack slot

+ 2 - 1
client/widgets/CArtifactsOfHeroBase.h

@@ -21,7 +21,7 @@ protected:
 
 public:
 	using ArtPlaceMap = std::map<ArtifactPosition, ArtPlacePtr>;
-	using ClickFunctor = std::function<void(CArtifactsOfHeroBase&, CArtPlace&, const Point&)>;
+	using ClickFunctor = std::function<void(CArtPlace&, const Point&)>;
 
 	ClickFunctor clickPressedCallback;
 	ClickFunctor showPopupCallback;
@@ -44,6 +44,7 @@ public:
 	virtual void updateSlot(const ArtifactPosition & slot);
 	virtual const CArtifactInstance * getPickedArtifact();
 	void addGestureCallback(CArtPlace::ClickFunctor callback);
+	const CArtifactInstance * getArt(const ArtifactPosition & slot);
 
 protected:
 	const CGHeroInstance * curHero;

+ 18 - 0
client/widgets/CArtifactsOfHeroMarket.cpp

@@ -25,3 +25,21 @@ CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position, const int
 	for(auto artPlace : backpack)
 		artPlace->setSelectionWidth(selectionWidth);
 };
+
+void CArtifactsOfHeroMarket::onClickPrassedArtPlace(CArtPlace & artPlace)
+{
+	if(const auto art = getArt(artPlace.slot))
+	{
+		if(onSelectArtCallback && art->artType->isTradable())
+		{
+			unmarkSlots();
+			artPlace.selectSlot(true);
+			onSelectArtCallback(&artPlace);
+		}
+		else
+		{
+			if(onClickNotTradableCallback)
+				onClickNotTradableCallback();
+		}
+	}
+}

+ 3 - 1
client/widgets/CArtifactsOfHeroMarket.h

@@ -14,7 +14,9 @@
 class CArtifactsOfHeroMarket : public CArtifactsOfHeroBase
 {
 public:
-	std::function<void(const CArtPlace*)> selectArtCallback;
+	std::function<void(const CArtPlace*)> onSelectArtCallback;
+	std::function<void()> onClickNotTradableCallback;
 
 	CArtifactsOfHeroMarket(const Point & position, const int selectionWidth);
+	void onClickPrassedArtPlace(CArtPlace & artPlace);
 };

+ 6 - 2
client/widgets/markets/CArtifactsSelling.cpp

@@ -55,14 +55,18 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 	// Hero's artifacts
 	heroArts = std::make_shared<CArtifactsOfHeroMarket>(Point(-361, 46), offerTradePanel->selectionWidth);
 	heroArts->setHero(hero);
-	heroArts->selectArtCallback = [this](const CArtPlace * artPlace)
+	heroArts->onSelectArtCallback = [this](const CArtPlace * artPlace)
 	{
 		assert(artPlace);
 		selectedHeroSlot = artPlace->slot;
 		CArtifactsSelling::highlightingChanged();
 		CIntObject::redraw();
 	};
-
+	heroArts->onClickNotTradableCallback = []()
+	{
+		// This item can't be traded
+		LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
+	};
 	CArtifactsSelling::updateShowcases();
 	CArtifactsSelling::deselect();
 }

+ 161 - 207
client/windows/CWindowWithArtifacts.cpp

@@ -29,7 +29,6 @@
 
 #include "../../lib/ArtifactUtils.h"
 #include "../../lib/CGeneralTextHandler.h"
-#include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/networkPacks/ArtifactLocation.h"
 #include "../../lib/CConfigHandler.h"
 
@@ -51,9 +50,65 @@ void CWindowWithArtifacts::addSetAndCallbacks(ArtifactsOfHeroVar newArtSet)
 	addSet(newArtSet);
 	std::visit([this](auto artSet)
 		{
-			artSet->clickPressedCallback = std::bind(&CWindowWithArtifacts::clickPressedArtPlaceHero, this, _1, _2, _3);
-			artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::showPopupArtPlaceHero, this, _1, _2, _3);
-			artSet->gestureCallback = std::bind(&CWindowWithArtifacts::gestureArtPlaceHero, this, _1, _2, _3);
+			if constexpr(std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMarket>>)
+			{
+				artSet->clickPressedCallback = [artSet](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					artSet->onClickPrassedArtPlace(artPlace);
+				};
+			}
+			if constexpr(std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroQuickBackpack>>)
+			{
+				artSet->clickPressedCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					if(const auto curHero = artSet->getHero())
+						swapArtifactAndClose(*artSet, artPlace, ArtifactLocation(curHero->id, artSet->getFilterSlot()));
+				};
+			}
+			if constexpr(
+					std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
+					std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
+					std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>> ||
+					std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>)
+			{
+				artSet->clickPressedCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					if(const auto curHero = artSet->getHero())
+						clickPressedOnArtPlace(*curHero, artPlace.slot,
+							!std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>>,
+							std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>>,
+							std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>);
+				};
+			}
+			if constexpr(
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMarket>> ||
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroQuickBackpack>>)
+			{
+				artSet->showPopupCallback = [this](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					showArifactInfo(artPlace, cursorPosition);
+				};
+			}
+			if constexpr(
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>> ||
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>)
+			{
+				artSet->showPopupCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					showArtifactAssembling(*artSet, artPlace, cursorPosition);
+				};
+			}
+			if constexpr(
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
+				std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>>)
+			{
+				artSet->gestureCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
+				{
+					showQuickBackpackWindow(*artSet, artPlace, cursorPosition);
+				};
+			}
 		}, newArtSet);
 }
 
@@ -94,218 +149,104 @@ const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact()
 	return art;
 }
 
-void CWindowWithArtifacts::clickPressedArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance & hero, const ArtifactPosition & slot,
+	bool allowExchange, bool altarTrading, bool closeWindow)
 {
-	const auto currentArtSet = findAOHbyRef(artsInst);
-	assert(currentArtSet.has_value());
-
-	if(artPlace.isLocked())
-		return;
-
 	if(!LOCPLINT->makingTurn)
 		return;
 
-	std::visit(
-		[this, &artPlace](auto artSetPtr)
+	if(const auto heroArtOwner = getHeroPickedArtifact())
+	{
+		if(allowExchange || hero.id == heroArtOwner->id)
+			putPickedArtifact(hero, slot);
+	}
+	else if(auto art = hero.getArt(slot))
+	{
+		if(hero.getOwner() == LOCPLINT->playerID)
 		{
-			// Hero(Main, Exchange) window, Kingdom window, Altar window, Backpack window left click handler
-			if constexpr(
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroMain>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroAltar>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroBackpack>>)
+			if(checkSpecialArts(*art, hero, altarTrading))
 			{
-				const auto pickedArtInst = getPickedArtifact();
-				const auto heroPickedArt = getHeroPickedArtifact();
-				const auto hero = artSetPtr->getHero();
-				auto isTransferAllowed = false;
-				std::string msg;
+				assert(hero.getArt(slot));
+				auto srcLoc = ArtifactLocation(hero.id, slot);
+				auto dstLoc = ArtifactLocation(hero.id, ArtifactPosition::TRANSITION_POS);
 
-				if(pickedArtInst)
+				if(GH.isKeyboardCtrlDown())
 				{
-					auto srcLoc = ArtifactLocation(heroPickedArt->id, ArtifactPosition::TRANSITION_POS);
-					auto dstLoc = ArtifactLocation(hero->id, artPlace.slot);
-
-					if(ArtifactUtils::isSlotBackpack(artPlace.slot))
-					{
-						if(pickedArtInst->artType->isBig())
+					for(auto & anotherSet : artSets)
+						if(std::holds_alternative<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet))
 						{
-							// War machines cannot go to backpack
-							msg = boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArtInst->artType->getNameTranslated());
-						}
-						else
-						{
-							if(ArtifactUtils::isBackpackFreeSlots(heroPickedArt))
-								isTransferAllowed = true;
-							else
-								msg = CGI->generaltexth->translate("core.genrltxt.152");
-						}
-					}
-					// Check if artifact transfer is possible
-					else if(pickedArtInst->canBePutAt(hero, artPlace.slot, true) && (!artPlace.getArt() || hero->tempOwner == LOCPLINT->playerID))
-					{
-						isTransferAllowed = true;
-					}
-					if constexpr(std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>>)
-					{
-						if(hero != heroPickedArt)
-							isTransferAllowed = false;
-					}
-					if(isTransferAllowed)
-						LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
-				}
-				else if(auto art = artPlace.getArt())
-				{
-					if(artSetPtr->getHero()->getOwner() == LOCPLINT->playerID)
-					{
-						if(checkSpecialArts(*art, hero, std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroAltar>> ? true : false))
-						{
-							assert(artSetPtr->getHero()->getSlotByInstance(art) != ArtifactPosition::PRE_FIRST);
-
-							auto srcLoc = ArtifactLocation(hero->id, artPlace.slot);
-							auto dstLoc = ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS);
-
-							if(GH.isKeyboardCtrlDown())
-							{
-								for(auto & anotherSet : artSets)
-									if(std::holds_alternative<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet))
-									{
-										auto anotherHeroEquipment = std::get<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet);
-										if(hero->id != anotherHeroEquipment->getHero()->id)
-										{
-											dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
-											dstLoc.artHolder = anotherHeroEquipment->getHero()->id;
-											break;
-										}
-									}
-							}
-							else if(GH.isKeyboardAltDown())
-							{
-								if(ArtifactUtils::isSlotEquipment(artPlace.slot))
-									dstLoc.slot = ArtifactUtils::getArtBackpackPosition(artSetPtr->getHero(), art->getTypeId());
-								else if(ArtifactUtils::isSlotBackpack(artPlace.slot))
-									dstLoc.slot = ArtifactUtils::getArtEquippedPosition(artSetPtr->getHero(), art->getTypeId());
-							}
-							if(dstLoc.slot != ArtifactPosition::PRE_FIRST)
-								LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
-						}
-					}
-					else
-					{
-						for(const auto & artSlot : ArtifactUtils::unmovableSlots())
-							if(artPlace.slot == artSlot)
+							const auto anotherHeroEquipment = std::get<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet);
+							if(hero.id != anotherHeroEquipment->getHero()->id)
 							{
-								msg = CGI->generaltexth->allTexts[21];
+								dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
+								dstLoc.artHolder = anotherHeroEquipment->getHero()->id;
 								break;
 							}
-					}
+						}
 				}
-
-				if constexpr(std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroBackpack>>)
+				else if(GH.isKeyboardAltDown())
 				{
-					if(!isTransferAllowed && artPlace.getArt() && !GH.isKeyboardCtrlDown() && !GH.isKeyboardAltDown() && closeCallback)
-						closeCallback();
+					const auto artId = hero.getArt(slot)->getTypeId();
+					if(ArtifactUtils::isSlotEquipment(slot))
+						dstLoc.slot = ArtifactUtils::getArtBackpackPosition(&hero, artId);
+					else if(ArtifactUtils::isSlotBackpack(slot))
+						dstLoc.slot = ArtifactUtils::getArtEquippedPosition(&hero, artId);
 				}
-				else
+				else if(closeWindow && closeCallback)
 				{
-					if(!msg.empty())
-						LOCPLINT->showInfoDialog(msg);
+					closeCallback();
 				}
+				if(dstLoc.slot != ArtifactPosition::PRE_FIRST)
+					LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
 			}
-			// Market window left click handler
-			else if constexpr(std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroMarket>>)
-			{
-				if(artSetPtr->selectArtCallback && artPlace.getArt())
+		}
+		else
+		{
+			for(const auto & artSlot : ArtifactUtils::unmovableSlots())
+				if(slot == artSlot)
 				{
-					if(artPlace.getArt()->artType->isTradable())
-					{
-						artSetPtr->unmarkSlots();
-						artPlace.selectSlot(true);
-						artSetPtr->selectArtCallback(&artPlace);
-					}
-					else
-					{
-						// This item can't be traded
-						LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
-					}
+					LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
+					break;
 				}
-			}
-			else if constexpr(std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroQuickBackpack>>)
-			{
-				const auto hero = artSetPtr->getHero();
-				LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero->id, artPlace.slot), ArtifactLocation(hero->id, artSetPtr->getFilterSlot()));
-				if(closeCallback)
-					closeCallback();
-			}
-		}, currentArtSet.value());
+		}
+	}
 }
 
-void CWindowWithArtifacts::showPopupArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+void CWindowWithArtifacts::swapArtifactAndClose(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const ArtifactLocation & dstLoc)
 {
-	const auto currentArtSet = findAOHbyRef(artsInst);
-	assert(currentArtSet.has_value());
+	LOCPLINT->cb->swapArtifacts(ArtifactLocation(artsInst.getHero()->id, artPlace.slot), dstLoc);
+	if(closeCallback)
+		closeCallback();
+}
 
-	if(artPlace.isLocked())
-		return;
+void CWindowWithArtifacts::showArtifactAssembling(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+{
+	if(artPlace.getArt())
+	{
+		if(ArtifactUtilsClient::askToDisassemble(artsInst.getHero(), artPlace.slot))
+			return;
+		if(ArtifactUtilsClient::askToAssemble(artsInst.getHero(), artPlace.slot))
+			return;
+		if(artPlace.text.size())
+			artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
+	}
+}
 
-	std::visit(
-		[&artPlace, &cursorPosition](auto artSetPtr)
-		{
-			// Hero (Main, Exchange) window, Kingdom window, Backpack window right click handler
-			if constexpr(
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroAltar>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroMain>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroBackpack>>)
-			{
-				if(artPlace.getArt())
-				{
-					if(ArtifactUtilsClient::askToDisassemble(artSetPtr->getHero(), artPlace.slot))
-					{
-						return;
-					}
-					if(ArtifactUtilsClient::askToAssemble(artSetPtr->getHero(), artPlace.slot))
-					{
-						return;
-					}
-					if(artPlace.text.size())
-						artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
-				}
-			}
-			// Altar window, Market window right click handler
-			else if constexpr(
-				std::is_same_v<decltype(artSetPtr), std::weak_ptr<CArtifactsOfHeroMarket>> ||
-				std::is_same_v<decltype(artSetPtr), std::weak_ptr<CArtifactsOfHeroQuickBackpack>>)
-			{
-				if(artPlace.getArt() && artPlace.text.size())
-					artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
-			}
-		}, currentArtSet.value());
+void CWindowWithArtifacts::showArifactInfo(CArtPlace & artPlace, const Point & cursorPosition)
+{
+	if(artPlace.getArt() && artPlace.text.size())
+		artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
 }
 
-void CWindowWithArtifacts::gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
+void CWindowWithArtifacts::showQuickBackpackWindow(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
 {
-	const auto currentArtSet = findAOHbyRef(artsInst);
-	assert(currentArtSet.has_value());
-	if(artPlace.isLocked())
+	if(!settings["general"]["enableUiEnhancements"].Bool())
 		return;
 
-	std::visit(
-		[&artPlace, cursorPosition](auto artSetPtr)
-		{
-			if constexpr(
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroMain>> ||
-				std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>>)
-			{
-				if(!settings["general"]["enableUiEnhancements"].Bool())
-					return;
-
-				GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(artSetPtr->getHero(), artPlace.slot);
-				auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
-				backpackWindow->moveTo(cursorPosition - Point(1, 1));
-				backpackWindow->fitToScreen(15);
-			}
-		}, currentArtSet.value());
+	GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(artsInst.getHero(), artPlace.slot);
+	auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
+	backpackWindow->moveTo(cursorPosition - Point(1, 1));
+	backpackWindow->fitToScreen(15);
 }
 
 void CWindowWithArtifacts::activate()
@@ -397,22 +338,6 @@ void CWindowWithArtifacts::update()
 			}, artSet);
 }
 
-std::optional<CWindowWithArtifacts::ArtifactsOfHeroVar> CWindowWithArtifacts::findAOHbyRef(const CArtifactsOfHeroBase & artsInst)
-{
-	std::optional<ArtifactsOfHeroVar> res;
-	for(auto & artSet : artSets)
-	{
-		std::visit([&res, &artsInst](auto & artSetPtr)
-			{
-				if(&artsInst == artSetPtr.get())
-					res = artSetPtr;
-			}, artSet);
-		if(res.has_value())
-			return res;
-	}
-	return res;
-}
-
 void CWindowWithArtifacts::markPossibleSlots()
 {
 	if(const auto pickedArtInst = getPickedArtifact())
@@ -423,23 +348,23 @@ void CWindowWithArtifacts::markPossibleSlots()
 			if(artSetPtr->isActive())
 			{
 				const auto hero = artSetPtr->getHero();
-				if(heroArtOwner == hero || !std::is_same_v<decltype(artSetPtr), std::weak_ptr<CArtifactsOfHeroKingdom>>)
+				if(heroArtOwner == hero || !std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>>)
 					artSetPtr->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID);
 			}
 		};
 
-		for(auto & artSetWeak : artSets)
-			std::visit(artifactAssembledBody, artSetWeak);
+		for(auto & artSet : artSets)
+			std::visit(artifactAssembledBody, artSet);
 	}
 }
 
-bool CWindowWithArtifacts::checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance * hero, bool isTrade) const
+bool CWindowWithArtifacts::checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance & hero, bool isTrade) const
 {
 	const auto artId = artInst.getTypeId();
 	
 	if(artId == ArtifactID::SPELLBOOK)
 	{
-		GH.windows().createAndPushWindow<CSpellWindow>(hero, LOCPLINT, LOCPLINT->battleInt.get());
+		GH.windows().createAndPushWindow<CSpellWindow>(&hero, LOCPLINT, LOCPLINT->battleInt.get());
 		return false;
 	}
 	if(artId == ArtifactID::CATAPULT)
@@ -473,3 +398,32 @@ void CWindowWithArtifacts::setCursorAnimation(const CArtifactInstance & artInst)
 		CCS->curh->dragAndDropCursor(AnimationPath::builtin("artifact"), artInst.artType->getIconIndex());
 	}
 }
+
+void CWindowWithArtifacts::putPickedArtifact(const CGHeroInstance & curHero, const ArtifactPosition & targetSlot)
+{
+	const auto heroArtOwner = getHeroPickedArtifact();
+	const auto pickedArt = getPickedArtifact();
+	auto srcLoc = ArtifactLocation(heroArtOwner->id, ArtifactPosition::TRANSITION_POS);
+	auto dstLoc = ArtifactLocation(curHero.id, targetSlot);
+
+	if(ArtifactUtils::isSlotBackpack(dstLoc.slot))
+	{
+		if(pickedArt->artType->isBig())
+		{
+			// War machines cannot go to backpack
+			LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArt->artType->getNameTranslated()));
+		}
+		else
+		{
+			if(ArtifactUtils::isBackpackFreeSlots(heroArtOwner))
+				LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+			else
+				LOCPLINT->showInfoDialog(CGI->generaltexth->translate("core.genrltxt.152"));
+		}
+	}
+	// Check if artifact transfer is possible
+	else if(pickedArt->canBePutAt(&curHero, dstLoc.slot, true) && (!curHero.getArt(targetSlot) || curHero.tempOwner == LOCPLINT->playerID))
+	{
+		LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+	}
+}

+ 8 - 5
client/windows/CWindowWithArtifacts.h

@@ -37,9 +37,12 @@ public:
 	void addCloseCallback(const CloseCallback & callback);
 	const CGHeroInstance * getHeroPickedArtifact();
 	const CArtifactInstance * getPickedArtifact();
-	void clickPressedArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
-	void showPopupArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
-	void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
+	void clickPressedOnArtPlace(const CGHeroInstance & hero, const ArtifactPosition & slot,
+		bool allowExchange, bool altarTrading, bool closeWindow);
+	void swapArtifactAndClose(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const ArtifactLocation & dstLoc);
+	void showArtifactAssembling(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
+	void showArifactInfo(CArtPlace & artPlace, const Point & cursorPosition);
+	void showQuickBackpackWindow(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
 	void activate() override;
 	void deactivate() override;
 	void enableArtifactsCostumeSwitcher() const;
@@ -51,8 +54,8 @@ public:
 
 protected:
 	void update();
-	std::optional<ArtifactsOfHeroVar> findAOHbyRef(const CArtifactsOfHeroBase & artsInst);
 	void markPossibleSlots();
-	bool checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance * hero, bool isTrade) const;
+	bool checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance & hero, bool isTrade) const;
 	void setCursorAnimation(const CArtifactInstance & artInst);
+	void putPickedArtifact(const CGHeroInstance & curHero, const ArtifactPosition & targetSlot);
 };