SoundSSGood пре 1 година
родитељ
комит
ce9d2d8ab8

+ 0 - 2
CCallback.cpp

@@ -195,8 +195,6 @@ void CCallback::scrollBackpackArtifacts(ObjectInstanceID hero, bool left)
 
 
 void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume)
 void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume)
 {
 {
-	assert(costumeIndex < GameConstants::HERO_COSTUMES_ARTIFACTS);
-
 	ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume);
 	ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume);
 	sendRequest(&mea);
 	sendRequest(&mea);
 }
 }

+ 8 - 0
client/gui/CIntObject.cpp

@@ -314,12 +314,20 @@ CKeyShortcut::CKeyShortcut(EShortcut key)
 {
 {
 }
 }
 
 
+CKeyShortcut::CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback)
+	: CKeyShortcut(key)
+{
+	this->keyPressedCallback = keyPressedCallback;
+}
+
 void CKeyShortcut::keyPressed(EShortcut key)
 void CKeyShortcut::keyPressed(EShortcut key)
 {
 {
 	if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed)
 	if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed)
 	{
 	{
 		shortcutPressed = true;
 		shortcutPressed = true;
 		clickPressed(GH.getCursorPosition());
 		clickPressed(GH.getCursorPosition());
+		if(keyPressedCallback)
+			keyPressedCallback();
 	}
 	}
 }
 }
 
 

+ 6 - 1
client/gui/CIntObject.h

@@ -133,14 +133,19 @@ public:
 /// Classes wanting use it should have it as one of their base classes
 /// Classes wanting use it should have it as one of their base classes
 class CKeyShortcut : public virtual CIntObject
 class CKeyShortcut : public virtual CIntObject
 {
 {
-	bool shortcutPressed;
 public:
 public:
+	using KeyPressedFunctor = std::function<void()>;
+
 	EShortcut assignedKey;
 	EShortcut assignedKey;
 	CKeyShortcut();
 	CKeyShortcut();
 	CKeyShortcut(EShortcut key);
 	CKeyShortcut(EShortcut key);
+	CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback);
 	void keyPressed(EShortcut key) override;
 	void keyPressed(EShortcut key) override;
 	void keyReleased(EShortcut key) override;
 	void keyReleased(EShortcut key) override;
 
 
+private:
+	bool shortcutPressed;
+	KeyPressedFunctor keyPressedCallback;
 };
 };
 
 
 class WindowBase : public CIntObject
 class WindowBase : public CIntObject

+ 13 - 30
client/widgets/CArtifactsOfHeroMain.cpp

@@ -18,7 +18,7 @@
 #include "../../CCallback.h"
 #include "../../CCallback.h"
 #include "../../lib/networkPacks/ArtifactLocation.h"
 #include "../../lib/networkPacks/ArtifactLocation.h"
 
 
-CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumesEnabled)
+CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
 {
 {
 	init(
 	init(
 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
@@ -26,21 +26,6 @@ CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumes
 		position,
 		position,
 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
 	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
 	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
-
-	if(costumesEnabled)
-	{
-		size_t costumeIndex = 0;
-		for(const auto & hotkey : hotkeys)
-		{
-			auto keyProc = costumesSwitchers.emplace_back(std::make_shared<CKeyShortcutWrapper>(hotkey,
-				[this, hotkey, costumeIndex]()
-				{
-					CArtifactsOfHeroMain::onCostumeSelect(costumeIndex);
-				}));
-			keyProc->addUsedEvents(AEventsReceiver::KEYBOARD);
-			costumeIndex++;
-		}
-	}
 }
 }
 
 
 CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
 CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
@@ -48,19 +33,17 @@ CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
 	CArtifactsOfHeroBase::putBackPickedArtifact();
 	CArtifactsOfHeroBase::putBackPickedArtifact();
 }
 }
 
 
-void CArtifactsOfHeroMain::onCostumeSelect(const size_t costumeIndex)
-{
-	LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIndex, GH.isKeyboardCtrlDown());
-}
-
-CArtifactsOfHeroMain::CKeyShortcutWrapper::CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect)
-	: CKeyShortcut(key)
-	, onCostumeSelect(onCostumeSelect)
+void CArtifactsOfHeroMain::enableArtifactsCostumeSwitcher()
 {
 {
-}
-
-void CArtifactsOfHeroMain::CKeyShortcutWrapper::clickPressed(const Point & cursorPosition)
-{
-	if(onCostumeSelect)
-		onCostumeSelect();
+	size_t costumeIdx = 0;
+	for(const auto & hotkey : costumesSwitcherHotkeys)
+	{
+		auto keyProc = costumesSwitcherProcessors.emplace_back(std::make_shared<CKeyShortcut>(hotkey,
+			[this, costumeIdx]()
+			{
+				LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIdx, GH.isKeyboardCtrlDown());
+			}));
+		keyProc->addUsedEvents(AEventsReceiver::KEYBOARD);
+		costumeIdx++;
+	}
 }
 }

+ 4 - 18
client/widgets/CArtifactsOfHeroMain.h

@@ -16,24 +16,12 @@
 class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
 class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
 {
 {
 public:
 public:
-	CArtifactsOfHeroMain(const Point & position, bool costumesEnabled = false);
+	CArtifactsOfHeroMain(const Point & position);
 	~CArtifactsOfHeroMain() override;
 	~CArtifactsOfHeroMain() override;
+	void enableArtifactsCostumeSwitcher();
 
 
 private:
 private:
-	// TODO may be removed if CKeyShortcut supports callbacks
-	class CKeyShortcutWrapper : public CKeyShortcut
-	{
-	public:
-		using KeyPressedFunctor = std::function<void()>;
-
-		CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect);
-		void clickPressed(const Point & cursorPosition) override;
-
-	private:
-		KeyPressedFunctor onCostumeSelect;
-	};
-
-	const std::array<EShortcut, GameConstants::HERO_COSTUMES_ARTIFACTS> hotkeys =
+	const std::vector<EShortcut> costumesSwitcherHotkeys =
 	{
 	{
 		EShortcut::HERO_COSTUME_0,
 		EShortcut::HERO_COSTUME_0,
 		EShortcut::HERO_COSTUME_1,
 		EShortcut::HERO_COSTUME_1,
@@ -46,7 +34,5 @@ private:
 		EShortcut::HERO_COSTUME_8,
 		EShortcut::HERO_COSTUME_8,
 		EShortcut::HERO_COSTUME_9
 		EShortcut::HERO_COSTUME_9
 	};
 	};
-	std::vector<std::shared_ptr<CKeyShortcutWrapper>> costumesSwitchers;
-
-	void onCostumeSelect(const size_t costumeIndex);
+	std::vector<std::shared_ptr<CKeyShortcut>> costumesSwitcherProcessors;
 };
 };

+ 2 - 1
client/windows/CHeroWindow.cpp

@@ -218,9 +218,10 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 		}
 		}
 		if(!arts)
 		if(!arts)
 		{
 		{
-			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8), true);
+			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8));
 			arts->setHero(curHero);
 			arts->setHero(curHero);
 			addSetAndCallbacks(arts);
 			addSetAndCallbacks(arts);
+			enableArtifactsCostumeSwitcher();
 		}
 		}
 
 
 		int serial = LOCPLINT->cb->getHeroSerial(curHero, false);
 		int serial = LOCPLINT->cb->getHeroSerial(curHero, false);

+ 14 - 0
client/windows/CWindowWithArtifacts.cpp

@@ -343,6 +343,20 @@ void CWindowWithArtifacts::deactivate()
 	CWindowObject::deactivate();
 	CWindowObject::deactivate();
 }
 }
 
 
+void CWindowWithArtifacts::enableArtifactsCostumeSwitcher()
+{
+	for(auto artSet : artSets)
+		std::visit(
+			[](auto artSetWeak)
+			{
+				if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>>)
+				{
+					const auto artSetPtr = artSetWeak.lock();
+					artSetPtr->enableArtifactsCostumeSwitcher();
+				}
+			}, artSet);
+}
+
 void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
 void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
 {
 {
 	update();
 	update();

+ 1 - 0
client/windows/CWindowWithArtifacts.h

@@ -42,6 +42,7 @@ public:
 	void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
 	void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
 	void activate() override;
 	void activate() override;
 	void deactivate() override;
 	void deactivate() override;
+	void enableArtifactsCostumeSwitcher();
 
 
 	virtual void artifactRemoved(const ArtifactLocation & artLoc);
 	virtual void artifactRemoved(const ArtifactLocation & artLoc);
 	virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw);
 	virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw);

+ 1 - 1
lib/ArtifactUtils.cpp

@@ -52,7 +52,7 @@ DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::unmovableSlots(
 	return positions;
 	return positions;
 }
 }
 
 
-DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::constituentWornSlots()
+DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commonWornSlots()
 {
 {
 	static const std::vector<ArtifactPosition> positions =
 	static const std::vector<ArtifactPosition> positions =
 	{
 	{

+ 1 - 1
lib/ArtifactUtils.h

@@ -30,7 +30,7 @@ namespace ArtifactUtils
 	DLL_LINKAGE ArtifactPosition getArtBackpackPosition(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
 	// TODO: Make this constexpr when the toolset is upgraded
 	DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots();
 	DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots();
-	DLL_LINKAGE const std::vector<ArtifactPosition> & constituentWornSlots();
+	DLL_LINKAGE const std::vector<ArtifactPosition> & commonWornSlots();
 	DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots();
 	DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots();
 	DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots();
 	DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots();
 	DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);
 	DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);

+ 8 - 0
lib/CArtHandler.cpp

@@ -1086,6 +1086,14 @@ CArtifactFittingSet::CArtifactFittingSet(ArtBearer::ArtBearer Bearer):
 {
 {
 }
 }
 
 
+CArtifactFittingSet::CArtifactFittingSet(const CArtifactSet & artSet)
+	: CArtifactFittingSet(artSet.bearerType())
+{
+	artifactsWorn = artSet.artifactsWorn;
+	artifactsInBackpack = artSet.artifactsInBackpack;
+	artifactsTransitionPos = artSet.artifactsTransitionPos;
+}
+
 ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const
 ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const
 {
 {
 	return this->Bearer;
 	return this->Bearer;

+ 1 - 0
lib/CArtHandler.h

@@ -249,6 +249,7 @@ class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet
 {
 {
 public:
 public:
 	CArtifactFittingSet(ArtBearer::ArtBearer Bearer);
 	CArtifactFittingSet(ArtBearer::ArtBearer Bearer);
+	CArtifactFittingSet(const CArtifactSet & artSet);
 	ArtBearer::ArtBearer bearerType() const override;
 	ArtBearer::ArtBearer bearerType() const override;
 
 
 protected:
 protected:

+ 32 - 54
lib/networkPacks/NetPacksLib.cpp

@@ -1075,7 +1075,7 @@ void ChangeObjectVisitors::applyGs(CGameState * gs) const
 void ChangeArtifactsCostume::applyGs(CGameState * gs) const
 void ChangeArtifactsCostume::applyGs(CGameState * gs) const
 {
 {
 	auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts;
 	auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts;
-	if(auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end())
+	if(const auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end())
 		costume->second = costumeSet;
 		costume->second = costumeSet;
 	else
 	else
 		allCostumes.emplace(costumeIdx, costumeSet);
 		allCostumes.emplace(costumeIdx, costumeSet);
@@ -1802,69 +1802,47 @@ void MoveArtifact::applyGs(CGameState * gs)
 
 
 void BulkMoveArtifacts::applyGs(CGameState * gs)
 void BulkMoveArtifacts::applyGs(CGameState * gs)
 {
 {
-	enum class EBulkArtsOp
+	const auto bulkArtsRemove = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet)
 	{
 	{
-		BULK_MOVE,
-		BULK_REMOVE,
-		BULK_PUT
+		std::vector<ArtifactPosition> packToRemove;
+		for(const auto & slotsPair : artsPack)
+			packToRemove.push_back(slotsPair.srcPos);
+		std::sort(packToRemove.begin(), packToRemove.end(), [](const ArtifactPosition & slot0, const ArtifactPosition & slot1) -> bool
+			{
+				return slot0.num > slot1.num;
+			});
+
+		for(const auto & slot : packToRemove)
+		{
+			auto * art = artSet.getArt(slot);
+			assert(art);
+			art->removeFrom(artSet, slot);
+		}
 	};
 	};
 
 
-	auto bulkArtsOperation = [this, gs](std::vector<LinkedSlots> & artsPack, 
-		CArtifactSet & artSet, EBulkArtsOp operation) -> void
+	const auto bulkArtsPut = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet)
 	{
 	{
-		int numBackpackArtifactsMoved = 0;
-		for(auto & slot : artsPack)
+		for(const auto & slotsPair : artsPack)
 		{
 		{
-			// When an object gets removed from the backpack, the backpack shrinks
-			// so all the following indices will be affected. Thus, we need to update
-			// the subsequent artifact slots to account for that
-			auto srcPos = slot.srcPos;
-			if(ArtifactUtils::isSlotBackpack(srcPos) && (operation != EBulkArtsOp::BULK_PUT))
-			{
-				srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
-			}
-			auto * art = artSet.getArt(srcPos);
+			auto * art = initArtSet.getArt(slotsPair.srcPos);
 			assert(art);
 			assert(art);
-			switch(operation)
-			{
-			case EBulkArtsOp::BULK_MOVE:
-				art->move(artSet, srcPos, *gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)), slot.dstPos);
-				break;
-			case EBulkArtsOp::BULK_REMOVE:
-				art->removeFrom(artSet, srcPos);
-				break;
-			case EBulkArtsOp::BULK_PUT:
-				art->putAt(*gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)), slot.dstPos);
-				break;
-			default:
-				break;
-			}
-
-			if(srcPos >= ArtifactPosition::BACKPACK_START)
-			{
-				numBackpackArtifactsMoved++;
-			}
+			art->putAt(dstArtSet, slotsPair.dstPos);
 		}
 		}
 	};
 	};
 	
 	
 	auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature));
 	auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature));
-	if(swap)
-	{
-		// Swap
-		auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature));
-		CArtifactFittingSet artFittingSet(leftSet->bearerType());
-
-		artFittingSet.artifactsWorn = rightSet->artifactsWorn;
-		artFittingSet.artifactsInBackpack = rightSet->artifactsInBackpack;
-
-		bulkArtsOperation(artsPack1, *rightSet, EBulkArtsOp::BULK_REMOVE);
-		bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE);
-		bulkArtsOperation(artsPack1, artFittingSet, EBulkArtsOp::BULK_PUT);
-	}
-	else
-	{
-		bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE);
-	}
+	assert(leftSet);
+	auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature));
+	assert(rightSet);
+	CArtifactFittingSet artInitialSetLeft(*leftSet);
+	bulkArtsRemove(artsPack0, *leftSet);
+	if(!artsPack1.empty())
+	{
+		CArtifactFittingSet artInitialSetRight(*rightSet);
+		bulkArtsRemove(artsPack1, *rightSet);
+		bulkArtsPut(artsPack1, artInitialSetRight, *leftSet);
+	}
+	bulkArtsPut(artsPack0, artInitialSetLeft, *rightSet);
 }
 }
 
 
 void AssembledArtifact::applyGs(CGameState *gs)
 void AssembledArtifact::applyGs(CGameState *gs)

+ 2 - 2
lib/networkPacks/PacksForClient.h

@@ -1291,8 +1291,8 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient
 struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient
 struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient
 {
 {
 	std::map<ArtifactPosition, ArtifactID> costumeSet;
 	std::map<ArtifactPosition, ArtifactID> costumeSet;
-	size_t costumeIdx;
-	const PlayerColor player;
+	size_t costumeIdx = 0;
+	const PlayerColor player = PlayerColor::NEUTRAL;
 
 
 	void applyGs(CGameState * gs) const;
 	void applyGs(CGameState * gs) const;
 	void visitTyped(ICPackVisitor & visitor) override;
 	void visitTyped(ICPackVisitor & visitor) override;

+ 59 - 5
server/CGameHandler.cpp

@@ -2896,20 +2896,74 @@ bool CGameHandler::saveArtifactsCostume(const PlayerColor & player, const Object
 {
 {
 	auto artSet = getArtSet(heroID);
 	auto artSet = getArtSet(heroID);
 	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID");
 	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID");
-	COMPLAIN_RET_FALSE_IF(costumeIdx >= GameConstants::HERO_COSTUMES_ARTIFACTS, "saveArtifactsCostume: wrong costume index");
 
 
 	ChangeArtifactsCostume costume(player, costumeIdx);
 	ChangeArtifactsCostume costume(player, costumeIdx);
-	for(const auto & slot : ArtifactUtils::constituentWornSlots())
+	for(const auto & slot : ArtifactUtils::commonWornSlots())
 	{
 	{
-		if(const auto & slotInfo = artSet->getSlot(slot))
-			if(!slotInfo->locked)
-				costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId());
+		if(const auto slotInfo = artSet->getSlot(slot); slotInfo != nullptr && !slotInfo->locked)
+			costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId());
 	}
 	}
 
 
 	sendAndApply(&costume);
 	sendAndApply(&costume);
 	return true;
 	return true;
 }
 }
 
 
+bool CGameHandler::switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx)
+{
+	const auto artSet = getArtSet(heroID);
+	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "switchArtifactsCostume: wrong hero's ID");
+	const auto playerState = getPlayerState(player);
+	COMPLAIN_RET_FALSE_IF(playerState == nullptr, "switchArtifactsCostume: wrong player");
+
+	if(auto costume = playerState->costumesArtifacts.find(costumeIdx); costume != playerState->costumesArtifacts.end())
+	{
+		CArtifactFittingSet artFittingSet(*artSet);
+		BulkMoveArtifacts bma(player, heroID, heroID, false);
+		auto costumeArtMap = costume->second;
+		auto estimateBackpackSize = artSet->artifactsInBackpack.size();
+
+		// First, find those artifacts that are already in place
+		for(const auto & slot : ArtifactUtils::commonWornSlots())
+		{
+			if(const auto * slotInfo = artFittingSet.getSlot(slot); slotInfo != nullptr && !slotInfo->locked)
+				if(const auto artPos = costumeArtMap.find(slot); artPos != costumeArtMap.end() && artPos->second == slotInfo->getArt()->getTypeId())
+				{
+					costumeArtMap.erase(artPos);
+					artFittingSet.removeArtifact(slot);
+				}
+		}
+		
+		// Second, find the necessary artifacts for the costume
+		for(const auto & artPos : costumeArtMap)
+		{
+			if(const auto availableArts = artFittingSet.getAllArtPositions(artPos.second, false, false, false); !availableArts.empty())
+			{
+				bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots
+					{
+						artSet->getSlotByInstance(artFittingSet.getArt(availableArts.front())),
+						artPos.first
+					});
+				artFittingSet.removeArtifact(availableArts.front());
+				if(ArtifactUtils::isSlotBackpack(availableArts.front()))
+					estimateBackpackSize--;
+			}
+		}
+
+		// Third, put unnecessary artifacts into backpack
+		for(const auto & slot : ArtifactUtils::commonWornSlots())
+			if(artFittingSet.getArt(slot))
+			{
+				bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots{slot, ArtifactPosition::BACKPACK_START});
+				estimateBackpackSize++;
+			}
+		
+		const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
+		if((backpackCap < 0 || estimateBackpackSize <= backpackCap) && !bma.artsPack0.empty())
+			sendAndApply(&bma);
+	}
+	return true;
+}
+
 /**
 /**
  * Assembles or disassembles a combination artifact.
  * Assembles or disassembles a combination artifact.
  * @param heroID ID of hero holding the artifact(s).
  * @param heroID ID of hero holding the artifact(s).

+ 1 - 0
server/CGameHandler.h

@@ -131,6 +131,7 @@ public:
 	bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack);
 	bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack);
 	bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left);
 	bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left);
 	bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx);
 	bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx);
+	bool switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx);
 	bool eraseArtifactByClient(const ArtifactLocation & al);
 	bool eraseArtifactByClient(const ArtifactLocation & al);
 	void synchronizeArtifactHandlerLists();
 	void synchronizeArtifactHandlerLists();
 
 

+ 3 - 2
server/NetPacksServer.cpp

@@ -183,8 +183,9 @@ void ApplyGhNetPackVisitor::visitManageEquippedArtifacts(ManageEquippedArtifacts
 {
 {
 	gh.throwIfWrongOwner(&pack, pack.artHolder);
 	gh.throwIfWrongOwner(&pack, pack.artHolder);
 	if(pack.saveCostume)
 	if(pack.saveCostume)
-		gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
-	result = true;
+		result = gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
+	else
+		result = gh.switchArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
 }
 }
 
 
 void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack)
 void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack)