Browse Source

ArtifactPosition::TRANSITION_POS now is simple ArtSlotInfo

SoundSSGood 1 year ago
parent
commit
7abfa7b42a

+ 1 - 1
client/widgets/CArtifactsOfHeroBackpack.cpp

@@ -126,7 +126,7 @@ size_t CArtifactsOfHeroBackpack::calcRows(size_t slots)
 CArtifactsOfHeroQuickBackpack::CArtifactsOfHeroQuickBackpack(const ArtifactPosition filterBySlot)
 	: CArtifactsOfHeroBackpack(0, 0)
 {
-	assert(filterBySlot != ArtifactPosition::FIRST_AVAILABLE);
+	assert(ArtifactUtils::checkIfSlotValid(*getHero(), filterBySlot));
 
 	if(!ArtifactUtils::isSlotEquipment(filterBySlot))
 		return;

+ 5 - 5
client/widgets/CArtifactsOfHeroBase.cpp

@@ -32,9 +32,9 @@ CArtifactsOfHeroBase::CArtifactsOfHeroBase()
 void CArtifactsOfHeroBase::putBackPickedArtifact()
 {
 	// Artifact located in artifactsTransitionPos should be returned
-	if(getPickedArtifact())
+	if(const auto art = getPickedArtifact())
 	{
-		auto slot = ArtifactUtils::getArtAnyPosition(curHero, curHero->artifactsTransitionPos.begin()->artifact->getTypeId());
+		auto slot = ArtifactUtils::getArtAnyPosition(curHero, art->getTypeId());
 		if(slot == ArtifactPosition::PRE_FIRST)
 		{
 			LOCPLINT->cb->eraseArtifactByClient(ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
@@ -196,10 +196,10 @@ void CArtifactsOfHeroBase::updateSlot(const ArtifactPosition & slot)
 const CArtifactInstance * CArtifactsOfHeroBase::getPickedArtifact()
 {
 	// Returns only the picked up artifact. Not just highlighted like in the trading window.
-	if(!curHero || curHero->artifactsTransitionPos.empty())
-		return nullptr;
-	else
+	if(curHero)
 		return curHero->getArt(ArtifactPosition::TRANSITION_POS);
+	else
+		return nullptr;
 }
 
 void CArtifactsOfHeroBase::addGestureCallback(CArtPlace::ClickFunctor callback)

+ 2 - 1
client/widgets/markets/CAltarArtifacts.cpp

@@ -222,7 +222,8 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 		assert(tradeSlotsMap.at(altarSlot));
 		const auto slot = altarArtifacts->getSlotByInstance(tradeSlotsMap.at(altarSlot));
 		assert(slot != ArtifactPosition::PRE_FIRST);
-		LOCPLINT->cb->swapArtifacts(ArtifactLocation(altarId, slot), ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS));
+		LOCPLINT->cb->swapArtifacts(ArtifactLocation(altarId, slot),
+			ArtifactLocation(hero->id, GH.isKeyboardCtrlDown() ? ArtifactPosition::FIRST_AVAILABLE : ArtifactPosition::TRANSITION_POS));
 		tradeSlotsMap.erase(altarSlot);
 	}
 }

+ 1 - 1
client/windows/CHeroBackpackWindow.cpp

@@ -20,7 +20,7 @@
 #include "render/Canvas.h"
 #include "CPlayerInterface.h"
 
-CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero, const std::vector<CArtifactsOfHeroPtr> & artsSets)
+CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero, const std::vector<ArtifactsOfHeroVar> & artsSets)
 	: CWindowWithArtifacts(&artsSets)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);

+ 1 - 1
client/windows/CHeroBackpackWindow.h

@@ -16,7 +16,7 @@ class CFilledTexture;
 class CHeroBackpackWindow : public CStatusbarWindow, public CWindowWithArtifacts
 {
 public:
-	CHeroBackpackWindow(const CGHeroInstance * hero, const std::vector<CArtifactsOfHeroPtr> & artsSets);
+	CHeroBackpackWindow(const CGHeroInstance * hero, const std::vector<ArtifactsOfHeroVar> & artsSets);
 	
 protected:
 	std::shared_ptr<CArtifactsOfHeroBackpack> arts;

+ 1 - 1
client/windows/CKingdomInterface.cpp

@@ -548,7 +548,7 @@ std::shared_ptr<CIntObject> CKingdomInterface::createMainTab(size_t index)
 	switch(index)
 	{
 	case 0:
-		return std::make_shared<CKingdHeroList>(size, [this](const CWindowWithArtifacts::CArtifactsOfHeroPtr & newHeroSet)
+		return std::make_shared<CKingdHeroList>(size, [this](const CWindowWithArtifacts::ArtifactsOfHeroVar & newHeroSet)
 			{
 				addSetAndCallbacks(newHeroSet);
 			});

+ 1 - 1
client/windows/CKingdomInterface.h

@@ -334,7 +334,7 @@ private:
 	std::shared_ptr<CLabel> skillsLabel;
 
 public:
-	using CreateHeroItemFunctor = std::function<void(const CWindowWithArtifacts::CArtifactsOfHeroPtr)>;
+	using CreateHeroItemFunctor = std::function<void(const CWindowWithArtifacts::ArtifactsOfHeroVar)>;
 
 	CKingdHeroList(size_t maxSize, const CreateHeroItemFunctor & onCreateHeroItemCallback);
 	void updateGarrisons() override;

+ 0 - 2
client/windows/CMarketWindow.cpp

@@ -106,8 +106,6 @@ void CMarketWindow::artifactRemoved(const ArtifactLocation & artLoc)
 
 void CMarketWindow::artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw)
 {
-	if(!getState().has_value())
-		return;
 	CWindowWithArtifacts::artifactMoved(srcLoc, destLoc, withRedraw);
 	assert(marketWidget);
 	marketWidget->update();

+ 51 - 101
client/windows/CWindowWithArtifacts.cpp

@@ -35,18 +35,18 @@
 
 #include "../../CCallback.h"
 
-CWindowWithArtifacts::CWindowWithArtifacts(const std::vector<CArtifactsOfHeroPtr> * artSets)
+CWindowWithArtifacts::CWindowWithArtifacts(const std::vector<ArtifactsOfHeroVar> * artSets)
 {
 	if(artSets)
 		this->artSets.insert(this->artSets.end(), artSets->begin(), artSets->end());
 }
 
-void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr newArtSet)
+void CWindowWithArtifacts::addSet(ArtifactsOfHeroVar newArtSet)
 {
 	artSets.emplace_back(newArtSet);
 }
 
-void CWindowWithArtifacts::addSetAndCallbacks(CArtifactsOfHeroPtr newArtSet)
+void CWindowWithArtifacts::addSetAndCallbacks(ArtifactsOfHeroVar newArtSet)
 {
 	addSet(newArtSet);
 	std::visit([this](auto artSetWeak)
@@ -65,20 +65,36 @@ void CWindowWithArtifacts::addCloseCallback(const CloseCallback & callback)
 
 const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact()
 {
-	auto res = getState();
-	if(res.has_value())
-		return std::get<const CGHeroInstance*>(res.value());
-	else
-		return nullptr;
+	const CGHeroInstance * hero = nullptr;
+
+	for(auto artSetWeak : artSets)
+		std::visit([&hero](auto artSetWeak)
+			{
+				if(auto artSetPtr = artSetWeak.lock())
+					if(const auto pickedArt = artSetPtr->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
+					{
+						hero = artSetPtr->getHero();
+						return;
+					}
+			}, artSetWeak);
+	return hero;
 }
 
 const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact()
 {
-	auto res = getState();
-	if(res.has_value())
-		return std::get<const CArtifactInstance*>(res.value());
-	else
-		return nullptr;
+	const CArtifactInstance * art = nullptr;
+
+	for (auto artSetWeak : artSets)
+		std::visit([&art](auto artSetWeak)
+			{
+				if(auto artSetPtr = artSetWeak.lock())
+					if(const auto pickedArt = artSetPtr->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
+					{
+						art = pickedArt;
+						return;
+					}
+			}, artSetWeak);
+	return art;
 }
 
 void CWindowWithArtifacts::clickPressedArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
@@ -151,70 +167,46 @@ void CWindowWithArtifacts::clickPressedArtPlaceHero(const CArtifactsOfHeroBase &
 						{
 							assert(artSetPtr->getHero()->getSlotByInstance(art) != ArtifactPosition::PRE_FIRST);
 
-							if(GH.isKeyboardCmdDown())
+							auto srcLoc = ArtifactLocation(artSetPtr->getHero()->id, artPlace.slot);
+							auto dstLoc = ArtifactLocation(artSetPtr->getHero()->id, ArtifactPosition::TRANSITION_POS);
+
+							if(GH.isKeyboardCtrlDown())
 							{
-								std::shared_ptr<CArtifactsOfHeroMain> anotherHeroEquipmentPointer = nullptr;
+								std::shared_ptr<CArtifactsOfHeroBase> anotherArtSet = nullptr;
 
 								for(auto set : artSets)
 								{
 									if(std::holds_alternative<std::weak_ptr<CArtifactsOfHeroMain>>(set))
 									{
-										std::shared_ptr<CArtifactsOfHeroMain> heroEquipmentPointer = std::get<std::weak_ptr<CArtifactsOfHeroMain>>(set).lock();
+										std::shared_ptr<CArtifactsOfHeroBase> heroEquipmentPointer = std::get<std::weak_ptr<CArtifactsOfHeroMain>>(set).lock();
 										if(heroEquipmentPointer->getHero()->id != artSetPtr->getHero()->id)
 										{
-											anotherHeroEquipmentPointer = heroEquipmentPointer;
+											anotherArtSet = heroEquipmentPointer;
 											break;
 										}
 									}
 								}
 
-								if(anotherHeroEquipmentPointer != nullptr)
+								if(anotherArtSet != nullptr)
 								{
-									ArtifactPosition availablePosition = ArtifactUtils::getArtAnyPosition(anotherHeroEquipmentPointer->getHero(), art->getTypeId());
-									if(availablePosition != ArtifactPosition::PRE_FIRST)
-									{
-										LOCPLINT->cb->swapArtifacts(ArtifactLocation(artSetPtr->getHero()->id, artSetPtr->getHero()->getSlotByInstance(art)),
-										ArtifactLocation(anotherHeroEquipmentPointer->getHero()->id, availablePosition));
-									}
+									dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
+									dstLoc.artHolder = anotherArtSet->getHero()->id;
 								}
 							}
 							else if(GH.isKeyboardAltDown())
 							{
-								ArtifactPosition destinationPosition = ArtifactPosition::PRE_FIRST;
-
 								if(ArtifactUtils::isSlotEquipment(artPlace.slot))
-								{
-									ArtifactPosition availablePosition = ArtifactUtils::getArtBackpackPosition(artSetPtr->getHero(), art->getTypeId());
-									if(availablePosition != ArtifactPosition::PRE_FIRST)
-									{
-										destinationPosition = availablePosition;
-									}
-								}
+									dstLoc.slot = ArtifactUtils::getArtBackpackPosition(artSetPtr->getHero(), art->getTypeId());
 								else if(ArtifactUtils::isSlotBackpack(artPlace.slot))
-								{
-									ArtifactPosition availablePosition = ArtifactUtils::getArtAnyPosition(artSetPtr->getHero(), art->getTypeId());
-									if(availablePosition != ArtifactPosition::PRE_FIRST && availablePosition != ArtifactPosition::BACKPACK_START)
-									{
-										destinationPosition = availablePosition;
-									}
-								}
-
-								if(destinationPosition != ArtifactPosition::PRE_FIRST)
-								{
-									LOCPLINT->cb->swapArtifacts(ArtifactLocation(artSetPtr->getHero()->id, artPlace.slot),
-										ArtifactLocation(artSetPtr->getHero()->id, destinationPosition));
-								}
-							}
-							else
-							{
-								LOCPLINT->cb->swapArtifacts(ArtifactLocation(artSetPtr->getHero()->id, artPlace.slot),
-									ArtifactLocation(artSetPtr->getHero()->id, ArtifactPosition::TRANSITION_POS));
+									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())
+						for(const auto & artSlot : ArtifactUtils::unmovableSlots())
 							if(artPlace.slot == artSlot)
 							{
 								msg = CGI->generaltexth->allTexts[21];
@@ -225,7 +217,7 @@ void CWindowWithArtifacts::clickPressedArtPlaceHero(const CArtifactsOfHeroBase &
 
 				if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroBackpack>>)
 				{
-					if(!isTransferAllowed && artPlace.getArt() && closeCallback)
+					if(!isTransferAllowed && artPlace.getArt() && !GH.isKeyboardCtrlDown() && !GH.isKeyboardAltDown() && closeCallback)
 						closeCallback();
 				}
 				else
@@ -354,8 +346,8 @@ void CWindowWithArtifacts::enableArtifactsCostumeSwitcher() const
 			{
 				if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>>)
 				{
-					const auto artSetPtr = artSetWeak.lock();
-					artSetPtr->enableArtifactsCostumeSwitcher();
+					if(auto artSetPtr = artSetWeak.lock())
+						artSetPtr->enableArtifactsCostumeSwitcher();
 				}
 			}, artSet);
 }
@@ -367,16 +359,10 @@ void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
 
 void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw)
 {
-	auto curState = getState();
-	if(!curState.has_value())
-		// Transition state. Nothing to do here. Just skip. Need to wait for final state.
-		return;
-
-	auto pickedArtInst = std::get<const CArtifactInstance*>(curState.value());
+	const auto pickedArtInst = getPickedArtifact();
 	auto artifactMovedBody = [this, withRedraw, &destLoc, &pickedArtInst](auto artSetWeak) -> void
 	{
-		auto artSetPtr = artSetWeak.lock();
-		if(artSetPtr)
+		if(auto artSetPtr = artSetWeak.lock())
 		{
 			const auto hero = artSetPtr->getHero();
 			if(pickedArtInst)
@@ -446,45 +432,9 @@ void CWindowWithArtifacts::update() const
 		std::visit(updateSlotBody, artSetWeak);
 }
 
-std::optional<std::tuple<const CGHeroInstance*, const CArtifactInstance*>> CWindowWithArtifacts::getState()
-{
-	const CArtifactInstance * artInst = nullptr;
-	std::map<const CGHeroInstance*, size_t> pickedCnt;
-
-	auto getHeroArtBody = [&artInst, &pickedCnt](auto artSetWeak) -> void
-	{
-		auto artSetPtr = artSetWeak.lock();
-		if(artSetPtr)
-		{
-			if(const auto art = artSetPtr->getPickedArtifact())
-			{
-				const auto hero = artSetPtr->getHero();
-				if(pickedCnt.count(hero) == 0)
-				{
-					pickedCnt.insert({ hero, hero->artifactsTransitionPos.size() });
-					artInst = art;
-				}
-			}
-		}
-	};
-	for(auto artSetWeak : artSets)
-		std::visit(getHeroArtBody, artSetWeak);
-
-	// The state is possible when the hero has placed an artifact in the ArtifactPosition::TRANSITION_POS,
-	// and the previous artifact has not yet removed from the ArtifactPosition::TRANSITION_POS.
-	// This is a transitional state. Then return nullopt.
-	if(std::accumulate(std::begin(pickedCnt), std::end(pickedCnt), 0, [](size_t accum, const auto & value)
-		{
-			return accum + value.second;
-		}) > 1)
-		return std::nullopt;
-	else
-		return std::make_tuple(pickedCnt.begin()->first, artInst);
-}
-
-std::optional<CWindowWithArtifacts::CArtifactsOfHeroPtr> CWindowWithArtifacts::findAOHbyRef(const CArtifactsOfHeroBase & artsInst)
+std::optional<CWindowWithArtifacts::ArtifactsOfHeroVar> CWindowWithArtifacts::findAOHbyRef(const CArtifactsOfHeroBase & artsInst)
 {
-	std::optional<CArtifactsOfHeroPtr> res;
+	std::optional<ArtifactsOfHeroVar> res;
 
 	auto findAOHBody = [&res, &artsInst](auto & artSetWeak) -> void
 	{

+ 6 - 7
client/windows/CWindowWithArtifacts.h

@@ -19,7 +19,7 @@
 class CWindowWithArtifacts : virtual public CWindowObject
 {
 public:
-	using CArtifactsOfHeroPtr = std::variant<
+	using ArtifactsOfHeroVar = std::variant<
 		std::weak_ptr<CArtifactsOfHeroMarket>,
 		std::weak_ptr<CArtifactsOfHeroAltar>,
 		std::weak_ptr<CArtifactsOfHeroKingdom>,
@@ -28,12 +28,12 @@ public:
 		std::weak_ptr<CArtifactsOfHeroQuickBackpack>>;
 	using CloseCallback = std::function<void()>;
 
-	std::vector<CArtifactsOfHeroPtr> artSets;
+	std::vector<ArtifactsOfHeroVar> artSets;
 	CloseCallback closeCallback;
 
-	explicit CWindowWithArtifacts(const std::vector<CArtifactsOfHeroPtr> * artSets = nullptr);
-	void addSet(CArtifactsOfHeroPtr newArtSet);
-	void addSetAndCallbacks(CArtifactsOfHeroPtr newArtSet);
+	explicit CWindowWithArtifacts(const std::vector<ArtifactsOfHeroVar> * artSets = nullptr);
+	void addSet(ArtifactsOfHeroVar newArtSet);
+	void addSetAndCallbacks(ArtifactsOfHeroVar newArtSet);
 	void addCloseCallback(const CloseCallback & callback);
 	const CGHeroInstance * getHeroPickedArtifact();
 	const CArtifactInstance * getPickedArtifact();
@@ -51,8 +51,7 @@ public:
 
 protected:
 	void update() const;
-	std::optional<std::tuple<const CGHeroInstance*, const CArtifactInstance*>> getState();
-	std::optional<CArtifactsOfHeroPtr> findAOHbyRef(const CArtifactsOfHeroBase & artsInst);
+	std::optional<ArtifactsOfHeroVar> findAOHbyRef(const CArtifactsOfHeroBase & artsInst);
 	void markPossibleSlots();
 	bool checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance * hero, bool isTrade) const;
 	void setCursorAnimation(const CArtifactInstance & artInst);

+ 33 - 1
lib/ArtifactUtils.cpp

@@ -19,7 +19,39 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
+DLL_LINKAGE bool ArtifactUtils::checkIfSlotValid(const CArtifactSet & artSet, const ArtifactPosition & slot)
+{
+	if(artSet.bearerType() == ArtBearer::HERO)
+	{
+		if(isSlotEquipment(slot) || isSlotBackpack(slot) || slot == ArtifactPosition::TRANSITION_POS)
+			return true;
+	}
+	else if(artSet.bearerType() == ArtBearer::ALTAR)
+	{
+		if(isSlotBackpack(slot))
+			return true;
+	}
+	else if(artSet.bearerType() == ArtBearer::COMMANDER)
+	{
+		if(vstd::contains(commanderSlots(), slot))
+			return true;
+	}
+	else if(artSet.bearerType() == ArtBearer::CREATURE)
+	{
+		if(slot == ArtifactPosition::CREATURE_SLOT)
+			return true;
+	}
+	return false;
+}
+
 DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtAnyPosition(const CArtifactSet * target, const ArtifactID & aid)
+{
+	if(auto targetSlot = getArtEquippedPosition(target, aid); targetSlot != ArtifactPosition::PRE_FIRST)
+		return targetSlot;
+	return getArtBackpackPosition(target, aid);
+}
+
+DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtEquippedPosition(const CArtifactSet * target, const ArtifactID & aid)
 {
 	const auto * art = aid.toArtifact();
 	for(const auto & slot : art->getPossibleSlots().at(target->bearerType()))
@@ -27,7 +59,7 @@ DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtAnyPosition(const CArtifactSet
 		if(art->canBePutAt(target, slot))
 			return slot;
 	}
-	return getArtBackpackPosition(target, aid);
+	return ArtifactPosition::PRE_FIRST;
 }
 
 DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid)

+ 2 - 1
lib/ArtifactUtils.h

@@ -25,8 +25,9 @@ class CMap;
 
 namespace ArtifactUtils
 {
-	// Calculates where an artifact gets placed when it gets transferred from one hero to another.
+	DLL_LINKAGE bool checkIfSlotValid(const CArtifactSet & artSet, const ArtifactPosition & slot);
 	DLL_LINKAGE ArtifactPosition getArtAnyPosition(const CArtifactSet * target, const ArtifactID & aid);
+	DLL_LINKAGE ArtifactPosition getArtEquippedPosition(const CArtifactSet * target, const ArtifactID & aid);
 	DLL_LINKAGE ArtifactPosition getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid);
 	// TODO: Make this constexpr when the toolset is upgraded
 	DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots();

+ 3 - 12
lib/CArtHandler.cpp

@@ -897,13 +897,7 @@ const CArtifactInstance * CArtifactSet::getAssemblyByConstituent(const ArtifactI
 const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
 {
 	if(pos == ArtifactPosition::TRANSITION_POS)
-	{
-		// Always add to the end. Always take from the beginning.
-		if(artifactsTransitionPos.empty())
-			return nullptr;
-		else
-			return &(*artifactsTransitionPos.begin());
-	}
+		return &artifactsTransitionPos;
 	if(vstd::contains(artifactsWorn, pos))
 		return &artifactsWorn.at(pos);
 	if(ArtifactUtils::isSlotBackpack(pos))
@@ -936,9 +930,7 @@ void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, ConstTransitiveP
 	ArtSlotInfo * slotInfo;
 	if(slot == ArtifactPosition::TRANSITION_POS)
 	{
-		// Always add to the end. Always take from the beginning.
-		artifactsTransitionPos.emplace_back();
-		slotInfo = &artifactsTransitionPos.back();
+		slotInfo = &artifactsTransitionPos;
 	}
 	else if(ArtifactUtils::isSlotEquipment(slot))
 	{
@@ -957,8 +949,7 @@ void CArtifactSet::eraseArtSlot(const ArtifactPosition & slot)
 {
 	if(slot == ArtifactPosition::TRANSITION_POS)
 	{
-		assert(!artifactsTransitionPos.empty());
-		artifactsTransitionPos.erase(artifactsTransitionPos.begin());
+		artifactsTransitionPos.artifact = nullptr;
 	}
 	else if(ArtifactUtils::isSlotBackpack(slot))
 	{

+ 1 - 1
lib/CArtHandler.h

@@ -194,7 +194,7 @@ public:
 
 	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
-	std::vector<ArtSlotInfo> artifactsTransitionPos; // Used as transition position for dragAndDrop artifact exchange
+	ArtSlotInfo artifactsTransitionPos; // Used as transition position for dragAndDrop artifact exchange
 
 	void setNewArtSlot(const ArtifactPosition & slot, ConstTransitivePtr<CArtifactInstance> art, bool locked);
 	void eraseArtSlot(const ArtifactPosition & slot);

+ 12 - 6
server/CGameHandler.cpp

@@ -2721,10 +2721,16 @@ bool CGameHandler::moveArtifact(const PlayerColor & player, const ArtifactLocati
 	if(!isAllowedExchange(src.artHolder, dst.artHolder))
 		COMPLAIN_RET("That heroes cannot make any exchange!");
 
+	COMPLAIN_RET_FALSE_IF(!ArtifactUtils::checkIfSlotValid(*srcArtSet, src.slot), "moveArtifact: wrong artifact source slot");
 	const auto srcArtifact = srcArtSet->getArt(src.slot);
-	const auto dstArtifact = dstArtSet->getArt(dst.slot);
+	auto dstSlot = dst.slot;
+	if(dstSlot == ArtifactPosition::FIRST_AVAILABLE)
+		dstSlot = ArtifactUtils::getArtAnyPosition(dstArtSet, srcArtifact->getTypeId());
+	if(!ArtifactUtils::checkIfSlotValid(*dstArtSet, dstSlot))
+		return true;
+	const auto dstArtifact = dstArtSet->getArt(dstSlot);
 	const bool isDstSlotOccupied = dstArtSet->bearerType() == ArtBearer::ALTAR ? false : dstArtifact != nullptr;
-	const bool isDstSlotBackpack = dstArtSet->bearerType() == ArtBearer::HERO ? ArtifactUtils::isSlotBackpack(dst.slot) : false;
+	const bool isDstSlotBackpack = dstArtSet->bearerType() == ArtBearer::HERO ? ArtifactUtils::isSlotBackpack(dstSlot) : false;
 
 	if(srcArtifact == nullptr)
 		COMPLAIN_RET("No artifact to move!");
@@ -2733,23 +2739,23 @@ bool CGameHandler::moveArtifact(const PlayerColor & player, const ArtifactLocati
 
 	// Check if src/dest slots are appropriate for the artifacts exchanged.
 	// Moving to the backpack is always allowed.
-	if((!srcArtifact || !isDstSlotBackpack) && !srcArtifact->canBePutAt(dstArtSet, dst.slot, true))
+	if((!srcArtifact || !isDstSlotBackpack) && !srcArtifact->canBePutAt(dstArtSet, dstSlot, true))
 		COMPLAIN_RET("Cannot move artifact!");
 
 	auto srcSlotInfo = srcArtSet->getSlot(src.slot);
-	auto dstSlotInfo = dstArtSet->getSlot(dst.slot);
+	auto dstSlotInfo = dstArtSet->getSlot(dstSlot);
 
 	if((srcSlotInfo && srcSlotInfo->locked) || (dstSlotInfo && dstSlotInfo->locked))
 		COMPLAIN_RET("Cannot move artifact locks.");
 
 	if(isDstSlotBackpack && srcArtifact->artType->isBig())
 		COMPLAIN_RET("Cannot put big artifacts in backpack!");
-	if(src.slot == ArtifactPosition::MACH4 || dst.slot == ArtifactPosition::MACH4)
+	if(src.slot == ArtifactPosition::MACH4 || dstSlot == ArtifactPosition::MACH4)
 		COMPLAIN_RET("Cannot move catapult!");
 	if(isDstSlotBackpack && !ArtifactUtils::isBackpackFreeSlots(dstArtSet))
 		COMPLAIN_RET("Backpack is full!");
 
-	auto dstSlot = std::min(dst.slot, ArtifactPosition(ArtifactPosition::BACKPACK_START + dstArtSet->artifactsInBackpack.size()));
+	dstSlot = std::min(dstSlot, ArtifactPosition(ArtifactPosition::BACKPACK_START + dstArtSet->artifactsInBackpack.size()));
 
 	if(src.slot == dstSlot && src.artHolder == dst.artHolder)
 		COMPLAIN_RET("Won't move artifact: Dest same as source!");