Explorar o código

Saving costume

SoundSSGood hai 1 ano
pai
achega
25dea7e364

+ 8 - 0
CCallback.cpp

@@ -193,6 +193,14 @@ void CCallback::scrollBackpackArtifacts(ObjectInstanceID hero, bool left)
 	sendRequest(&mba);
 	sendRequest(&mba);
 }
 }
 
 
+void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume)
+{
+	assert(costumeIndex < GameConstants::HERO_COSTUMES_ARTIFACTS);
+
+	ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume);
+	sendRequest(&mea);
+}
+
 void CCallback::eraseArtifactByClient(const ArtifactLocation & al)
 void CCallback::eraseArtifactByClient(const ArtifactLocation & al)
 {
 {
 	EraseArtifactByClient ea(al);
 	EraseArtifactByClient ea(al);

+ 2 - 0
CCallback.h

@@ -92,6 +92,7 @@ public:
 	//virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
 	//virtual bool swapArtifacts(const CGHeroInstance * hero1, ui16 pos1, const CGHeroInstance * hero2, ui16 pos2)=0; //swaps artifacts between two given heroes
 	virtual bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)=0;
 	virtual bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2)=0;
 	virtual void scrollBackpackArtifacts(ObjectInstanceID hero, bool left) = 0;
 	virtual void scrollBackpackArtifacts(ObjectInstanceID hero, bool left) = 0;
+	virtual void manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume) = 0;
 	virtual void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0;
 	virtual void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo)=0;
 	virtual void eraseArtifactByClient(const ArtifactLocation & al)=0;
 	virtual void eraseArtifactByClient(const ArtifactLocation & al)=0;
 	virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0;
 	virtual bool dismissCreature(const CArmedInstance *obj, SlotID stackPos)=0;
@@ -178,6 +179,7 @@ public:
 	void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override;
 	void assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override;
 	void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped = true, bool backpack = true) override;
 	void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped = true, bool backpack = true) override;
 	void scrollBackpackArtifacts(ObjectInstanceID hero, bool left) override;
 	void scrollBackpackArtifacts(ObjectInstanceID hero, bool left) override;
+	void manageHeroCostume(ObjectInstanceID hero, size_t costumeIdx, bool saveCostume) override;
 	void eraseArtifactByClient(const ArtifactLocation & al) override;
 	void eraseArtifactByClient(const ArtifactLocation & al) override;
 	bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override;
 	bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override;
 	void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;
 	void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;

+ 10 - 0
client/gui/Shortcut.h

@@ -158,6 +158,16 @@ enum class EShortcut
 	HERO_TIGHT_FORMATION,
 	HERO_TIGHT_FORMATION,
 	HERO_TOGGLE_TACTICS, // b
 	HERO_TOGGLE_TACTICS, // b
 	HERO_BACKPACK,
 	HERO_BACKPACK,
+	HERO_COSTUME_0,
+	HERO_COSTUME_1,
+	HERO_COSTUME_2,
+	HERO_COSTUME_3,
+	HERO_COSTUME_4,
+	HERO_COSTUME_5,
+	HERO_COSTUME_6,
+	HERO_COSTUME_7,
+	HERO_COSTUME_8,
+	HERO_COSTUME_9,
 
 
 	// Spellbook screen
 	// Spellbook screen
 	SPELLBOOK_TAB_ADVENTURE,
 	SPELLBOOK_TAB_ADVENTURE,

+ 10 - 0
client/gui/ShortcutHandler.cpp

@@ -180,6 +180,16 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const
 		{"heroLooseFormation",       EShortcut::HERO_LOOSE_FORMATION      },
 		{"heroLooseFormation",       EShortcut::HERO_LOOSE_FORMATION      },
 		{"heroTightFormation",       EShortcut::HERO_TIGHT_FORMATION      },
 		{"heroTightFormation",       EShortcut::HERO_TIGHT_FORMATION      },
 		{"heroToggleTactics",        EShortcut::HERO_TOGGLE_TACTICS       },
 		{"heroToggleTactics",        EShortcut::HERO_TOGGLE_TACTICS       },
+		{"heroCostume0",             EShortcut::HERO_COSTUME_0            },
+		{"heroCostume1",             EShortcut::HERO_COSTUME_1            },
+		{"heroCostume2",             EShortcut::HERO_COSTUME_2            },
+		{"heroCostume3",             EShortcut::HERO_COSTUME_3            },
+		{"heroCostume4",             EShortcut::HERO_COSTUME_4            },
+		{"heroCostume5",             EShortcut::HERO_COSTUME_5            },
+		{"heroCostume6",             EShortcut::HERO_COSTUME_6            },
+		{"heroCostume7",             EShortcut::HERO_COSTUME_7            },
+		{"heroCostume8",             EShortcut::HERO_COSTUME_8            },
+		{"heroCostume9",             EShortcut::HERO_COSTUME_9            },
 		{"spellbookTabAdventure",    EShortcut::SPELLBOOK_TAB_ADVENTURE   },
 		{"spellbookTabAdventure",    EShortcut::SPELLBOOK_TAB_ADVENTURE   },
 		{"spellbookTabCombat",       EShortcut::SPELLBOOK_TAB_COMBAT      }
 		{"spellbookTabCombat",       EShortcut::SPELLBOOK_TAB_COMBAT      }
 	};
 	};

+ 35 - 1
client/widgets/CArtifactsOfHeroMain.cpp

@@ -10,13 +10,15 @@
 #include "StdInc.h"
 #include "StdInc.h"
 #include "CArtifactsOfHeroMain.h"
 #include "CArtifactsOfHeroMain.h"
 
 
+#include "../gui/CGuiHandler.h"
+
 #include "../CPlayerInterface.h"
 #include "../CPlayerInterface.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 
 
 #include "../../CCallback.h"
 #include "../../CCallback.h"
 #include "../../lib/networkPacks/ArtifactLocation.h"
 #include "../../lib/networkPacks/ArtifactLocation.h"
 
 
-CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
+CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumesEnabled)
 {
 {
 	init(
 	init(
 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
@@ -24,9 +26,41 @@ CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
 		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()
 {
 {
 	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::CKeyShortcutWrapper::clickPressed(const Point & cursorPosition)
+{
+	if(onCostumeSelect)
+		onCostumeSelect();
+}

+ 33 - 6
client/widgets/CArtifactsOfHeroMain.h

@@ -11,15 +11,42 @@
 
 
 #include "CArtifactsOfHeroBase.h"
 #include "CArtifactsOfHeroBase.h"
 
 
-VCMI_LIB_NAMESPACE_BEGIN
-
-struct ArtifactLocation;
-
-VCMI_LIB_NAMESPACE_END
+#include "../gui/Shortcut.h"
 
 
 class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
 class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
 {
 {
 public:
 public:
-	CArtifactsOfHeroMain(const Point & position);
+	CArtifactsOfHeroMain(const Point & position, bool costumesEnabled = false);
 	~CArtifactsOfHeroMain() override;
 	~CArtifactsOfHeroMain() override;
+
+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 =
+	{
+		EShortcut::HERO_COSTUME_0,
+		EShortcut::HERO_COSTUME_1,
+		EShortcut::HERO_COSTUME_2,
+		EShortcut::HERO_COSTUME_3,
+		EShortcut::HERO_COSTUME_4,
+		EShortcut::HERO_COSTUME_5,
+		EShortcut::HERO_COSTUME_6,
+		EShortcut::HERO_COSTUME_7,
+		EShortcut::HERO_COSTUME_8,
+		EShortcut::HERO_COSTUME_9
+	};
+	std::vector<std::shared_ptr<CKeyShortcutWrapper>> costumesSwitchers;
+
+	void onCostumeSelect(const size_t costumeIndex);
 };
 };

+ 1 - 1
client/windows/CHeroWindow.cpp

@@ -218,7 +218,7 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded)
 		}
 		}
 		if(!arts)
 		if(!arts)
 		{
 		{
-			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8));
+			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8), true);
 			arts->setHero(curHero);
 			arts->setHero(curHero);
 			addSetAndCallbacks(arts);
 			addSetAndCallbacks(arts);
 		}
 		}

+ 11 - 1
config/shortcutsConfig.json

@@ -125,6 +125,16 @@
 		"heroTightFormation":       "T",
 		"heroTightFormation":       "T",
 		"heroToggleTactics":        "B",
 		"heroToggleTactics":        "B",
 		"spellbookTabAdventure":    "A",
 		"spellbookTabAdventure":    "A",
-		"spellbookTabCombat":       "C"
+		"spellbookTabCombat":       "C",
+		"heroCostume0":             "0",
+		"heroCostume1":             "1",
+		"heroCostume2":             "2",
+		"heroCostume3":             "3",
+		"heroCostume4":             "4",
+		"heroCostume5":             "5",
+		"heroCostume6":             "6",
+		"heroCostume7":             "7",
+		"heroCostume8":             "8",
+		"heroCostume9":             "9"
 	}
 	}
 }
 }

+ 2 - 0
lib/CPlayerState.h

@@ -63,6 +63,7 @@ public:
 	std::vector<ConstTransitivePtr<CGDwelling> > dwellings; //used for town growth
 	std::vector<ConstTransitivePtr<CGDwelling> > dwellings; //used for town growth
 	std::vector<QuestInfo> quests; //store info about all received quests
 	std::vector<QuestInfo> quests; //store info about all received quests
 	std::vector<Bonus> battleBonuses; //additional bonuses to be added during battle with neutrals
 	std::vector<Bonus> battleBonuses; //additional bonuses to be added during battle with neutrals
+	std::map<size_t, std::map<ArtifactPosition, ArtifactID>> costumesArtifacts;
 
 
 	bool cheated;
 	bool cheated;
 	bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
 	bool enteredWinningCheatCode, enteredLosingCheatCode; //if true, this player has entered cheat codes for loss / victory
@@ -111,6 +112,7 @@ public:
 		h & daysWithoutCastle;
 		h & daysWithoutCastle;
 		h & cheated;
 		h & cheated;
 		h & battleBonuses;
 		h & battleBonuses;
+		h & costumesArtifacts;
 		h & enteredLosingCheatCode;
 		h & enteredLosingCheatCode;
 		h & enteredWinningCheatCode;
 		h & enteredWinningCheatCode;
 		h & static_cast<CBonusSystemNode&>(*this);
 		h & static_cast<CBonusSystemNode&>(*this);

+ 2 - 0
lib/networkPacks/NetPackVisitor.h

@@ -87,6 +87,7 @@ public:
 	virtual void visitInfoWindow(InfoWindow & pack) {}
 	virtual void visitInfoWindow(InfoWindow & pack) {}
 	virtual void visitSetObjectProperty(SetObjectProperty & pack) {}
 	virtual void visitSetObjectProperty(SetObjectProperty & pack) {}
 	virtual void visitChangeObjectVisitors(ChangeObjectVisitors & pack) {}
 	virtual void visitChangeObjectVisitors(ChangeObjectVisitors & pack) {}
+	virtual void visitChangeArtifactsCostume(ChangeArtifactsCostume & pack) {}
 	virtual void visitHeroLevelUp(HeroLevelUp & pack) {}
 	virtual void visitHeroLevelUp(HeroLevelUp & pack) {}
 	virtual void visitCommanderLevelUp(CommanderLevelUp & pack) {}
 	virtual void visitCommanderLevelUp(CommanderLevelUp & pack) {}
 	virtual void visitBlockingDialog(BlockingDialog & pack) {}
 	virtual void visitBlockingDialog(BlockingDialog & pack) {}
@@ -132,6 +133,7 @@ public:
 	virtual void visitExchangeArtifacts(ExchangeArtifacts & pack) {}
 	virtual void visitExchangeArtifacts(ExchangeArtifacts & pack) {}
 	virtual void visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) {}
 	virtual void visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) {}
 	virtual void visitManageBackpackArtifacts(ManageBackpackArtifacts & pack) {}
 	virtual void visitManageBackpackArtifacts(ManageBackpackArtifacts & pack) {}
+	virtual void visitManageEquippedArtifacts(ManageEquippedArtifacts & pack) {}
 	virtual void visitAssembleArtifacts(AssembleArtifacts & pack) {}
 	virtual void visitAssembleArtifacts(AssembleArtifacts & pack) {}
 	virtual void visitEraseArtifactByClient(EraseArtifactByClient & pack) {}
 	virtual void visitEraseArtifactByClient(EraseArtifactByClient & pack) {}
 	virtual void visitBuyArtifact(BuyArtifact & pack) {}
 	virtual void visitBuyArtifact(BuyArtifact & pack) {}

+ 19 - 0
lib/networkPacks/NetPacksLib.cpp

@@ -383,6 +383,11 @@ void ChangeObjectVisitors::visitTyped(ICPackVisitor & visitor)
 	visitor.visitChangeObjectVisitors(*this);
 	visitor.visitChangeObjectVisitors(*this);
 }
 }
 
 
+void ChangeArtifactsCostume::visitTyped(ICPackVisitor & visitor)
+{
+	visitor.visitChangeArtifactsCostume(*this);
+}
+
 void HeroLevelUp::visitTyped(ICPackVisitor & visitor)
 void HeroLevelUp::visitTyped(ICPackVisitor & visitor)
 {
 {
 	visitor.visitHeroLevelUp(*this);
 	visitor.visitHeroLevelUp(*this);
@@ -613,6 +618,11 @@ void ManageBackpackArtifacts::visitTyped(ICPackVisitor & visitor)
 	visitor.visitManageBackpackArtifacts(*this);
 	visitor.visitManageBackpackArtifacts(*this);
 }
 }
 
 
+void ManageEquippedArtifacts::visitTyped(ICPackVisitor & visitor)
+{
+	visitor.visitManageEquippedArtifacts(*this);
+}
+
 void AssembleArtifacts::visitTyped(ICPackVisitor & visitor)
 void AssembleArtifacts::visitTyped(ICPackVisitor & visitor)
 {
 {
 	visitor.visitAssembleArtifacts(*this);
 	visitor.visitAssembleArtifacts(*this);
@@ -1062,6 +1072,15 @@ void ChangeObjectVisitors::applyGs(CGameState * gs) const
 	}
 	}
 }
 }
 
 
+void ChangeArtifactsCostume::applyGs(CGameState * gs) const
+{
+	auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts;
+	if(auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end())
+		costume->second = costumeSet;
+	else
+		allCostumes.emplace(costumeIdx, costumeSet);
+}
+
 void PlayerEndsGame::applyGs(CGameState * gs) const
 void PlayerEndsGame::applyGs(CGameState * gs) const
 {
 {
 	PlayerState *p = gs->getPlayerState(player);
 	PlayerState *p = gs->getPlayerState(player);

+ 24 - 0
lib/networkPacks/PacksForClient.h

@@ -1288,6 +1288,30 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient
 	}
 	}
 };
 };
 
 
+struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient
+{
+	std::map<ArtifactPosition, ArtifactID> costumeSet;
+	size_t costumeIdx;
+	const PlayerColor player;
+
+	void applyGs(CGameState * gs) const;
+	void visitTyped(ICPackVisitor & visitor) override;
+
+	ChangeArtifactsCostume() = default;
+	ChangeArtifactsCostume(const PlayerColor & player, const size_t costumeIdx)
+		: costumeIdx(costumeIdx)
+		, player(player)
+	{
+	}
+
+	template <typename Handler> void serialize(Handler & h)
+	{
+		h & costumeSet;
+		h & costumeIdx;
+		h & player;
+	}
+};
+
 struct DLL_LINKAGE HeroLevelUp : public Query
 struct DLL_LINKAGE HeroLevelUp : public Query
 {
 {
 	PlayerColor player;
 	PlayerColor player;

+ 25 - 0
lib/networkPacks/PacksForServer.h

@@ -429,6 +429,31 @@ struct DLL_LINKAGE ManageBackpackArtifacts : public CPackForServer
 	}
 	}
 };
 };
 
 
+struct DLL_LINKAGE ManageEquippedArtifacts : public CPackForServer
+{
+	ManageEquippedArtifacts() = default;
+	ManageEquippedArtifacts(const ObjectInstanceID & artHolder, const size_t costumeIdx, bool saveCostume = false)
+		: artHolder(artHolder)
+		, costumeIdx(costumeIdx)
+		, saveCostume(saveCostume)
+	{
+	}
+
+	ObjectInstanceID artHolder;
+	size_t costumeIdx;
+	bool saveCostume;
+
+	void visitTyped(ICPackVisitor & visitor) override;
+
+	template <typename Handler> void serialize(Handler & h)
+	{
+		h & static_cast<CPackForServer&>(*this);
+		h & artHolder;
+		h & costumeIdx;
+		h & saveCostume;
+	}
+};
+
 struct DLL_LINKAGE AssembleArtifacts : public CPackForServer
 struct DLL_LINKAGE AssembleArtifacts : public CPackForServer
 {
 {
 	AssembleArtifacts() = default;
 	AssembleArtifacts() = default;

+ 1 - 0
lib/registerTypes/RegisterTypesClientPacks.h

@@ -67,6 +67,7 @@ void registerTypesClientPacks(Serializer &s)
 	s.template registerType<CPackForClient, HeroVisit>();
 	s.template registerType<CPackForClient, HeroVisit>();
 	s.template registerType<CPackForClient, SetCommanderProperty>();
 	s.template registerType<CPackForClient, SetCommanderProperty>();
 	s.template registerType<CPackForClient, ChangeObjectVisitors>();
 	s.template registerType<CPackForClient, ChangeObjectVisitors>();
+	s.template registerType<CPackForClient, ChangeArtifactsCostume>();
 	s.template registerType<CPackForClient, ShowWorldViewEx>();
 	s.template registerType<CPackForClient, ShowWorldViewEx>();
 	s.template registerType<CPackForClient, EntitiesChanged>();
 	s.template registerType<CPackForClient, EntitiesChanged>();
 	s.template registerType<CPackForClient, BattleStart>();
 	s.template registerType<CPackForClient, BattleStart>();

+ 2 - 1
lib/registerTypes/RegisterTypesServerPacks.h

@@ -49,7 +49,8 @@ void registerTypesServerPacks(Serializer &s)
 	s.template registerType<CPackForServer, BulkSmartSplitStack>();
 	s.template registerType<CPackForServer, BulkSmartSplitStack>();
 	s.template registerType<CPackForServer, BulkMoveArmy>();
 	s.template registerType<CPackForServer, BulkMoveArmy>();
 	s.template registerType<CPackForServer, BulkExchangeArtifacts>();
 	s.template registerType<CPackForServer, BulkExchangeArtifacts>();
-	s.template registerType < CPackForServer, ManageBackpackArtifacts>();
+	s.template registerType<CPackForServer, ManageBackpackArtifacts>();
+	s.template registerType<CPackForServer, ManageEquippedArtifacts>();
 	s.template registerType<CPackForServer, EraseArtifactByClient>();
 	s.template registerType<CPackForServer, EraseArtifactByClient>();
 	s.template registerType<CPackForServer, GamePause>();
 	s.template registerType<CPackForServer, GamePause>();
 }
 }

+ 18 - 0
server/CGameHandler.cpp

@@ -2892,6 +2892,24 @@ bool CGameHandler::scrollBackpackArtifacts(const PlayerColor & player, const Obj
 	return true;
 	return true;
 }
 }
 
 
+bool CGameHandler::saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx)
+{
+	auto artSet = getArtSet(heroID);
+	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);
+	for(const auto & slot : ArtifactUtils::constituentWornSlots())
+	{
+		if(const auto & slotInfo = artSet->getSlot(slot))
+			if(!slotInfo->locked)
+				costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId());
+	}
+
+	sendAndApply(&costume);
+	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

@@ -130,6 +130,7 @@ public:
 	bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override;
 	bool moveArtifact(const PlayerColor & player, const ArtifactLocation & src, const ArtifactLocation & dst) override;
 	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 eraseArtifactByClient(const ArtifactLocation & al);
 	bool eraseArtifactByClient(const ArtifactLocation & al);
 	void synchronizeArtifactHandlerLists();
 	void synchronizeArtifactHandlerLists();
 
 

+ 8 - 0
server/NetPacksServer.cpp

@@ -179,6 +179,14 @@ void ApplyGhNetPackVisitor::visitManageBackpackArtifacts(ManageBackpackArtifacts
 	}
 	}
 }
 }
 
 
+void ApplyGhNetPackVisitor::visitManageEquippedArtifacts(ManageEquippedArtifacts & pack)
+{
+	gh.throwIfWrongOwner(&pack, pack.artHolder);
+	if(pack.saveCostume)
+		gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx);
+	result = true;
+}
+
 void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack)
 void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack)
 {
 {
 	gh.throwIfWrongOwner(&pack, pack.heroID);
 	gh.throwIfWrongOwner(&pack, pack.heroID);

+ 1 - 0
server/ServerNetPackVisitors.h

@@ -47,6 +47,7 @@ public:
 	void visitExchangeArtifacts(ExchangeArtifacts & pack) override;
 	void visitExchangeArtifacts(ExchangeArtifacts & pack) override;
 	void visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) override;
 	void visitBulkExchangeArtifacts(BulkExchangeArtifacts & pack) override;
 	void visitManageBackpackArtifacts(ManageBackpackArtifacts & pack) override;
 	void visitManageBackpackArtifacts(ManageBackpackArtifacts & pack) override;
+	void visitManageEquippedArtifacts(ManageEquippedArtifacts & pack) override;
 	void visitAssembleArtifacts(AssembleArtifacts & pack) override;
 	void visitAssembleArtifacts(AssembleArtifacts & pack) override;
 	void visitEraseArtifactByClient(EraseArtifactByClient & pack) override;
 	void visitEraseArtifactByClient(EraseArtifactByClient & pack) override;
 	void visitBuyArtifact(BuyArtifact & pack) override;
 	void visitBuyArtifact(BuyArtifact & pack) override;