Jelajahi Sumber

initial files

SoundSSGood 2 tahun lalu
induk
melakukan
9427de6344

+ 4 - 0
client/CMakeLists.txt

@@ -105,6 +105,7 @@ set(client_SRCS
 	widgets/CArtifactsOfHeroKingdom.cpp
 	widgets/CArtifactsOfHeroAltar.cpp
 	widgets/CArtifactsOfHeroMarket.cpp
+	widgets/CArtifactsOfHeroBackpack.cpp
 	widgets/CWindowWithArtifacts.cpp
 
 	windows/CCastleInterface.cpp
@@ -121,6 +122,7 @@ set(client_SRCS
 	windows/GUIClasses.cpp
 	windows/InfoWindows.cpp
 	windows/QuickRecruitmentWindow.cpp
+	windows/CHeroBackpackWindow.cpp
 	windows/settings/GeneralOptionsTab.cpp
 	windows/settings/OtherOptionsTab.cpp
 	windows/settings/SettingsMainWindow.cpp
@@ -258,6 +260,7 @@ set(client_HEADERS
 	widgets/CArtifactsOfHeroKingdom.h
 	widgets/CArtifactsOfHeroAltar.h
 	widgets/CArtifactsOfHeroMarket.h
+	widgets/CArtifactsOfHeroBackpack.h
 	widgets/CWindowWithArtifacts.h
 
 	windows/CCastleInterface.h
@@ -274,6 +277,7 @@ set(client_HEADERS
 	windows/GUIClasses.h
 	windows/InfoWindows.h
 	windows/QuickRecruitmentWindow.h
+	windows/CHeroBackpackWindow.h
 	windows/settings/GeneralOptionsTab.h
 	windows/settings/OtherOptionsTab.h
 	windows/settings/SettingsMainWindow.h

+ 1 - 0
client/gui/Shortcut.h

@@ -154,6 +154,7 @@ enum class EShortcut
 	HERO_LOOSE_FORMATION,
 	HERO_TIGHT_FORMATION,
 	HERO_TOGGLE_TACTICS, // b
+	HERO_BACKPACK,
 
 	// Spellbook screen
 	SPELLBOOK_TAB_ADVENTURE,

+ 5 - 0
client/widgets/CArtifactsOfHeroAltar.cpp

@@ -28,6 +28,11 @@ CArtifactsOfHeroAltar::CArtifactsOfHeroAltar(const Point & position)
 	pickedArtFromSlot = ArtifactPosition::PRE_FIRST;
 };
 
+CArtifactsOfHeroAltar::~CArtifactsOfHeroAltar()
+{
+	putBackPickedArtifact();
+}
+
 void CArtifactsOfHeroAltar::setHero(const CGHeroInstance * hero)
 {
 	if(hero)

+ 1 - 0
client/widgets/CArtifactsOfHeroAltar.h

@@ -21,6 +21,7 @@ public:
 	CArtifactFittingSet visibleArtSet;
 
 	CArtifactsOfHeroAltar(const Point & position);
+	~CArtifactsOfHeroAltar();
 	void setHero(const CGHeroInstance * hero) override;
 	void updateWornSlots() override;
 	void updateBackpackSlots() override;

+ 71 - 0
client/widgets/CArtifactsOfHeroBackpack.cpp

@@ -0,0 +1,71 @@
+/*
+ * CArtifactsOfHeroBackpack.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "CArtifactsOfHeroBackpack.h"
+
+#include "../gui/CGuiHandler.h"
+#include "../gui/Shortcut.h"
+
+#include "Buttons.h"
+#include "GameSettings.h"
+#include "IHandlerBase.h"
+
+#include "../CPlayerInterface.h"
+
+#include "../../CCallback.h"
+
+CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(const Point & position, DestroyHandler destroyThisCallback)
+{
+	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
+	pos += position;
+
+	const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
+	auto visibleCapasityMax = HERO_BACKPACK_WINDOW_SLOT_LINES * HERO_BACKPACK_WINDOW_SLOT_COLUMNS;
+	if(backpackCap >= 0)
+		visibleCapasityMax = visibleCapasityMax > backpackCap ? backpackCap : visibleCapasityMax;
+
+	backpack.resize(visibleCapasityMax);
+	size_t artPlaceIdx = 0;
+	for(auto & artPlace : backpack)
+	{
+		artPlace = std::make_shared<CHeroArtPlace>(
+			Point(46 * (artPlaceIdx % HERO_BACKPACK_WINDOW_SLOT_COLUMNS), 46 * (artPlaceIdx / HERO_BACKPACK_WINDOW_SLOT_COLUMNS)));
+		artPlace->setArtifact(nullptr);
+		artPlace->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1);
+		artPlace->rightClickCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1);
+		artPlaceIdx++;
+	}
+	if(backpackCap < 0 || visibleCapasityMax < backpackCap)
+	{
+		auto scrollHandler = std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1);
+		leftBackpackRoll = std::make_shared<CButton>(Point(-20, 0), "hsbtns3.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT);
+		rightBackpackRoll = std::make_shared<CButton>(Point(368, 318), "hsbtns5.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT);
+		leftBackpackRoll->block(true);
+		rightBackpackRoll->block(true);
+	}
+	this->destroyThisCallback = destroyThisCallback;
+}
+
+void CArtifactsOfHeroBackpack::swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc)
+{
+	LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
+}
+
+void CArtifactsOfHeroBackpack::pickUpArtifact(CHeroArtPlace & artPlace)
+{
+	LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero, artPlace.slot),
+		ArtifactLocation(curHero, ArtifactPosition::TRANSITION_POS));
+}
+
+void CArtifactsOfHeroBackpack::destroyThis()
+{
+	if(destroyThisCallback)
+		destroyThisCallback();
+}

+ 35 - 0
client/widgets/CArtifactsOfHeroBackpack.h

@@ -0,0 +1,35 @@
+/*
+ * CArtifactsOfHeroBackpack.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "CArtifactsOfHeroBase.h"
+
+VCMI_LIB_NAMESPACE_BEGIN
+
+struct ArtifactLocation;
+
+VCMI_LIB_NAMESPACE_END
+
+class CArtifactsOfHeroBackpack : public CArtifactsOfHeroBase
+{
+public:
+	using DestroyHandler = std::function<void()>;
+
+	CArtifactsOfHeroBackpack(const Point & position, DestroyHandler destroyThisCallback);
+	void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
+	void pickUpArtifact(CHeroArtPlace & artPlace);
+	void destroyThis();
+	
+private:
+	DestroyHandler destroyThisCallback;
+
+	const size_t HERO_BACKPACK_WINDOW_SLOT_COLUMNS = 8;
+	const size_t HERO_BACKPACK_WINDOW_SLOT_LINES = 8;
+};

+ 14 - 5
client/widgets/CArtifactsOfHeroBase.cpp

@@ -11,7 +11,6 @@
 #include "CArtifactsOfHeroBase.h"
 
 #include "../gui/CGuiHandler.h"
-#include "../gui/CursorHandler.h"
 #include "../gui/Shortcut.h"
 
 #include "Buttons.h"
@@ -26,11 +25,12 @@
 
 CArtifactsOfHeroBase::CArtifactsOfHeroBase()
 	: backpackPos(0),
-	curHero(nullptr)
+	curHero(nullptr),
+	putBackPickedArtCallback(nullptr)
 {
 }
 
-CArtifactsOfHeroBase::~CArtifactsOfHeroBase()
+void CArtifactsOfHeroBase::putBackPickedArtifact()
 {
 	// Artifact located in artifactsTransitionPos should be returned
 	if(getPickedArtifact())
@@ -45,6 +45,13 @@ CArtifactsOfHeroBase::~CArtifactsOfHeroBase()
 			LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero, ArtifactPosition::TRANSITION_POS), ArtifactLocation(curHero, slot));
 		}
 	}
+	if(putBackPickedArtCallback)
+		putBackPickedArtCallback();
+}
+
+void CArtifactsOfHeroBase::setPutBackPickedArtifactCallback(PutBackPickedArtCallback callback)
+{
+	putBackPickedArtCallback = callback;
 }
 
 void CArtifactsOfHeroBase::init(
@@ -159,8 +166,10 @@ void CArtifactsOfHeroBase::scrollBackpackForArtSet(int offset, const CArtifactSe
 	}
 
 	// Blocking scrolling if there is not enough artifacts to scroll
-	leftBackpackRoll->block(!scrollingPossible);
-	rightBackpackRoll->block(!scrollingPossible);
+	if(leftBackpackRoll)
+		leftBackpackRoll->block(!scrollingPossible);
+	if(rightBackpackRoll)
+		rightBackpackRoll->block(!scrollingPossible);
 }
 
 void CArtifactsOfHeroBase::safeRedraw()

+ 4 - 1
client/widgets/CArtifactsOfHeroBase.h

@@ -20,12 +20,14 @@ protected:
 public:
 	using ArtPlaceMap = std::map<ArtifactPosition, ArtPlacePtr>;
 	using ClickHandler = std::function<void(CArtifactsOfHeroBase&, CHeroArtPlace&)>;
+	using PutBackPickedArtCallback = std::function<void()>;
 
 	ClickHandler leftClickCallback;
 	ClickHandler rightClickCallback;
 	
 	CArtifactsOfHeroBase();
-	virtual ~CArtifactsOfHeroBase();
+	virtual void putBackPickedArtifact();
+	virtual void setPutBackPickedArtifactCallback(PutBackPickedArtCallback callback);
 	virtual void leftClickArtPlace(CHeroArtPlace & artPlace);
 	virtual void rightClickArtPlace(CHeroArtPlace & artPlace);
 	virtual void setHero(const CGHeroInstance * hero);
@@ -47,6 +49,7 @@ protected:
 	std::shared_ptr<CButton> leftBackpackRoll;
 	std::shared_ptr<CButton> rightBackpackRoll;
 	int backpackPos; // Position to display artifacts in heroes backpack
+	PutBackPickedArtCallback putBackPickedArtCallback;
 
 	const std::vector<Point> slotPos =
 	{

+ 5 - 0
client/widgets/CArtifactsOfHeroKingdom.cpp

@@ -41,6 +41,11 @@ CArtifactsOfHeroKingdom::CArtifactsOfHeroKingdom(ArtPlaceMap ArtWorn, std::vecto
 	rightBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, +1));
 }
 
+CArtifactsOfHeroKingdom::~CArtifactsOfHeroKingdom()
+{
+	putBackPickedArtifact();
+}
+
 void CArtifactsOfHeroKingdom::swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc)
 {
 	LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);

+ 1 - 0
client/widgets/CArtifactsOfHeroKingdom.h

@@ -22,6 +22,7 @@ class CArtifactsOfHeroKingdom : public CArtifactsOfHeroBase
 public:
 	CArtifactsOfHeroKingdom(ArtPlaceMap ArtWorn, std::vector<ArtPlacePtr> Backpack,
 		std::shared_ptr<CButton> leftScroll, std::shared_ptr<CButton> rightScroll);
+	~CArtifactsOfHeroKingdom();
 	void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
 	void pickUpArtifact(CHeroArtPlace & artPlace);
 };

+ 5 - 0
client/widgets/CArtifactsOfHeroMain.cpp

@@ -23,6 +23,11 @@ CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
 }
 
+CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
+{
+	putBackPickedArtifact();
+}
+
 void CArtifactsOfHeroMain::swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc)
 {
 	LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);

+ 1 - 0
client/widgets/CArtifactsOfHeroMain.h

@@ -21,6 +21,7 @@ class CArtifactsOfHeroMain : public CArtifactsOfHeroBase
 {
 public:
 	CArtifactsOfHeroMain(const Point & position);
+	~CArtifactsOfHeroMain();
 	void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
 	void pickUpArtifact(CHeroArtPlace & artPlace);
 };

+ 50 - 30
client/widgets/CWindowWithArtifacts.cpp

@@ -26,19 +26,20 @@
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 
-CWindowWithArtifacts::~CWindowWithArtifacts()
-{
-	CCS->curh->dragAndDropCursor(nullptr);
-}
-
 void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr artSet)
 {
+	CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackHandler = []() -> void
+	{
+		CCS->curh->dragAndDropCursor(nullptr);
+	};
+
 	artSets.emplace_back(artSet);
-	std::visit([this](auto artSetWeak)
+	std::visit([this, artPutBackHandler](auto artSetWeak)
 		{
 			auto artSet = artSetWeak.lock();
 			artSet->leftClickCallback = std::bind(&CWindowWithArtifacts::leftClickArtPlaceHero, this, _1, _2);
 			artSet->rightClickCallback = std::bind(&CWindowWithArtifacts::rightClickArtPlaceHero, this, _1, _2);
+			artSet->setPutBackPickedArtifactCallback(artPutBackHandler);
 		}, artSet);
 }
 
@@ -90,35 +91,37 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
 		{
 			const auto artSetPtr = artSetWeak.lock();
 
-			// Hero(Main, Exchange) window, Kingdom window, Altar window left click handler
+			// Hero(Main, Exchange) window, Kingdom window, Altar window, Backpack window left click handler
 			if constexpr(
 				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>> || 
 				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>> ||
-				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroAltar>>)
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroAltar>> ||
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroBackpack>>)
 			{
 				const auto pickedArtInst = getPickedArtifact();
 				const auto heroPickedArt = getHeroPickedArtifact();
 				const auto hero = artSetPtr->getHero();
+				auto isTransferAllowed = false;
+				std::string msg;
 
 				if(pickedArtInst)
 				{
 					auto srcLoc = ArtifactLocation(heroPickedArt, ArtifactPosition::TRANSITION_POS);
 					auto dstLoc = ArtifactLocation(hero, artPlace.slot);
-					auto isTransferAllowed = false;
 
 					if(ArtifactUtils::isSlotBackpack(artPlace.slot))
 					{
 						if(pickedArtInst->artType->isBig())
 						{
 							// War machines cannot go to backpack
-							LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArtInst->artType->getNameTranslated()));
+							msg = boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArtInst->artType->getNameTranslated());
 						}
 						else
 						{
 							if(ArtifactUtils::isBackpackFreeSlots(heroPickedArt))
 								isTransferAllowed = true;
 							else
-								LOCPLINT->showInfoDialog(CGI->generaltexth->translate("core.genrltxt.152"));
+								msg = CGI->generaltexth->translate("core.genrltxt.152");
 						}
 					}
 					// Check if artifact transfer is possible
@@ -137,7 +140,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
 				else
 				{
 					if(artPlace.getArt())
-					{			
+					{
 						if(artSetPtr->getHero()->tempOwner == LOCPLINT->playerID)
 						{
 							if(checkSpecialArts(hero, artPlace))
@@ -148,12 +151,23 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
 							for(const auto artSlot : ArtifactUtils::unmovableSlots())
 								if(artPlace.slot == artSlot)
 								{
-									LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
+									msg = CGI->generaltexth->allTexts[21];
 									break;
 								}
 						}
 					}
 				}
+
+				if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroBackpack>>)
+				{
+					if(!isTransferAllowed)
+						artSetPtr->destroyThis();
+				}
+				else
+				{
+					if(!msg.empty())
+						LOCPLINT->showInfoDialog(msg);
+				}
 			}
 			// Market window left click handler
 			else if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMarket>>)
@@ -189,10 +203,11 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
 		{
 			const auto artSetPtr = artSetWeak.lock();
 
-			// Hero(Main, Exchange) window, Kingdom window right click handler
+			// Hero (Main, Exchange) window, Kingdom window, Backpack window right click handler
 			if constexpr(
 				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>> ||
-				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>>)
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>> ||
+				std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroBackpack>>)
 			{
 				if(artPlace.getArt())
 				{
@@ -244,19 +259,19 @@ void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const
 		if(artSetPtr)
 		{
 			const auto hero = artSetPtr->getHero();
-			if(artSetPtr->isActive())
+			if(pickedArtInst)
 			{
-				if(pickedArtInst)
+				if(artSetPtr->isActive())
 				{
 					CCS->curh->dragAndDropCursor("artifact", pickedArtInst->artType->getIconIndex());
 					if(srcLoc.isHolder(hero) || !std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>>)
 						artSetPtr->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID);
 				}
-				else
-				{
-					artSetPtr->unmarkSlots();
-					CCS->curh->dragAndDropCursor(nullptr);
-				}
+			}
+			else
+			{
+				artSetPtr->unmarkSlots();
+				CCS->curh->dragAndDropCursor(nullptr);
 			}
 			if(withRedraw)
 			{
@@ -321,19 +336,21 @@ void CWindowWithArtifacts::updateSlots(const ArtifactPosition & slot)
 std::optional<std::tuple<const CGHeroInstance*, const CArtifactInstance*>> CWindowWithArtifacts::getState()
 {
 	const CArtifactInstance * artInst = nullptr;
-	const CGHeroInstance * hero = nullptr;
-	size_t pickedCnt = 0;
+	std::map<const CGHeroInstance*, size_t> pickedCnt;
 
-	auto getHeroArtBody = [&hero, &artInst, &pickedCnt](auto artSetWeak) -> void
+	auto getHeroArtBody = [&artInst, &pickedCnt](auto artSetWeak) -> void
 	{
 		auto artSetPtr = artSetWeak.lock();
 		if(artSetPtr)
 		{
 			if(const auto art = artSetPtr->getPickedArtifact())
 			{
-				artInst = art;
-				hero = artSetPtr->getHero();
-				pickedCnt += hero->artifactsTransitionPos.size();
+				const auto hero = artSetPtr->getHero();
+				if(pickedCnt.count(hero) == 0)
+				{
+					pickedCnt.insert({ hero, hero->artifactsTransitionPos.size() });
+					artInst = art;
+				}
 			}
 		}
 	};
@@ -343,10 +360,13 @@ std::optional<std::tuple<const CGHeroInstance*, const CArtifactInstance*>> CWind
 	// 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(pickedCnt > 1)
+	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(hero, artInst);
+		return std::make_tuple(pickedCnt.begin()->first, artInst);
 }
 
 std::optional<CWindowWithArtifacts::CArtifactsOfHeroPtr> CWindowWithArtifacts::findAOHbyRef(CArtifactsOfHeroBase & artsInst)

+ 3 - 2
client/widgets/CWindowWithArtifacts.h

@@ -14,6 +14,7 @@
 #include "CArtifactsOfHeroKingdom.h"
 #include "CArtifactsOfHeroAltar.h"
 #include "CArtifactsOfHeroMarket.h"
+#include "CArtifactsOfHeroBackpack.h"
 
 class CWindowWithArtifacts : public CArtifactHolder
 {
@@ -22,9 +23,9 @@ public:
 		std::weak_ptr<CArtifactsOfHeroMarket>,
 		std::weak_ptr<CArtifactsOfHeroAltar>,
 		std::weak_ptr<CArtifactsOfHeroKingdom>,
-		std::weak_ptr<CArtifactsOfHeroMain>>;
+		std::weak_ptr<CArtifactsOfHeroMain>,
+		std::weak_ptr<CArtifactsOfHeroBackpack>>;
 
-	virtual ~CWindowWithArtifacts();
 	void addSet(CArtifactsOfHeroPtr artSet);
 	const CGHeroInstance * getHeroPickedArtifact();
 	const CArtifactInstance * getPickedArtifact();

+ 23 - 0
client/windows/CHeroBackpackWindow.cpp

@@ -0,0 +1,23 @@
+/*
+ * CHeroBackpackWindow.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#include "StdInc.h"
+#include "CHeroBackpackWindow.h"
+
+#include "../gui/CGuiHandler.h"
+
+CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
+	: CWindowObject(PLAYER_COLORED)
+{
+	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
+	
+	arts = std::make_shared<CArtifactsOfHeroBackpack>(Point(-100, -170), std::bind(&CHeroBackpackWindow::close, this));
+	arts->setHero(hero);
+	addSet(arts);
+}

+ 22 - 0
client/windows/CHeroBackpackWindow.h

@@ -0,0 +1,22 @@
+/*
+ * CHeroBackpackWindow.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../widgets/CWindowWithArtifacts.h"
+#include "CWindowObject.h"
+
+class CHeroBackpackWindow : public CWindowObject, public CWindowWithArtifacts
+{
+public:
+	CHeroBackpackWindow(const CGHeroInstance * hero);
+	
+private:
+	std::shared_ptr<CArtifactsOfHeroBackpack> arts;
+};

+ 8 - 0
client/windows/CHeroWindow.cpp

@@ -11,6 +11,7 @@
 #include "CHeroWindow.h"
 
 #include "CCreatureWindow.h"
+#include "CHeroBackpackWindow.h"
 #include "CKingdomInterface.h"
 #include "GUIClasses.h"
 
@@ -136,6 +137,8 @@ CHeroWindow::CHeroWindow(const CGHeroInstance * hero)
 	questlogLabel = std::make_shared<CTextBox>(CGI->generaltexth->jktexts[9], Rect(510, 430, 65, 35), 0, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE);
 	questlogButton = std::make_shared<CButton>(Point(314, 429), "hsbtns4.def", CButton::tooltip(heroscrn[0]), [=](){ LOCPLINT->showQuestLog(); }, EShortcut::ADVENTURE_QUEST_LOG);
 
+	backpackButton = std::make_shared<CButton>(Point(380, 429), "hsbtns2.def", CButton::tooltip(""), [=]() { createBackpackWindow(); }, EShortcut::HERO_BACKPACK);
+
 	formations = std::make_shared<CToggleGroup>(0);
 	formations->addToggle(0, std::make_shared<CToggleButton>(Point(481, 483), "hsbtns6.def", std::make_pair(heroscrn[23], heroscrn[29]), 0, EShortcut::HERO_TIGHT_FORMATION));
 	formations->addToggle(1, std::make_shared<CToggleButton>(Point(481, 519), "hsbtns7.def", std::make_pair(heroscrn[24], heroscrn[30]), 0, EShortcut::HERO_LOOSE_FORMATION));
@@ -357,6 +360,11 @@ void CHeroWindow::dismissCurrent()
 	LOCPLINT->showYesNoDialog(CGI->generaltexth->allTexts[22], ony, nullptr);
 }
 
+void CHeroWindow::createBackpackWindow()
+{
+	GH.windows().createAndPushWindow<CHeroBackpackWindow>(curHero);
+}
+
 void CHeroWindow::commanderWindow()
 {
 	const auto pickedArtInst = getPickedArtifact();

+ 2 - 0
client/windows/CHeroWindow.h

@@ -105,6 +105,7 @@ class CHeroWindow : public CStatusbarWindow, public CGarrisonHolder, public CWin
 	std::shared_ptr<CTextBox> questlogLabel;
 	std::shared_ptr<CButton> questlogButton;
 	std::shared_ptr<CButton> commanderButton;
+	std::shared_ptr<CButton> backpackButton;
 
 	std::shared_ptr<CToggleButton> tacticsButton;
 	std::shared_ptr<CToggleGroup> formations;
@@ -125,6 +126,7 @@ public:
 	void commanderWindow();
 	void switchHero(); //changes displayed hero
 	void updateGarrisons() override;
+	void createBackpackWindow();
 
 	//friends
 	friend void CHeroArtPlace::clickPressed(const Point & cursorPosition);

+ 2 - 4
client/windows/CTradeWindow.cpp

@@ -370,7 +370,6 @@ void CTradeWindow::initItems(bool Left)
 
 	if(Left && (itemsType[1] == ARTIFACT_TYPE || itemsType[1] == ARTIFACT_INSTANCE))
 	{
-		int xOffset = 0, yOffset = 0;
 		if(mode == EMarketMode::ARTIFACT_RESOURCE)
 		{
 			auto item = std::make_shared<CTradeableItem>(Point(137, 469), itemsType[Left], -1, 1, 0);
@@ -1428,10 +1427,9 @@ int CAltarWindow::firstFreeSlot()
 
 void CAltarWindow::SacrificeBackpack()
 {
-	auto artsAltar = std::dynamic_pointer_cast<CArtifactsOfHeroAltar>(arts);
-	while(!artsAltar->visibleArtSet.artifactsInBackpack.empty())
+	while(!arts->visibleArtSet.artifactsInBackpack.empty())
 	{
-		if(!putOnAltar(nullptr, artsAltar->visibleArtSet.artifactsInBackpack[0].artifact))
+		if(!putOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact))
 			break;
 	};
 	calcTotalExp();