Browse Source

Altar artifacts widget refactoring

SoundSSGood 1 year ago
parent
commit
ae8d70748b

+ 87 - 59
client/widgets/markets/CAltarArtifacts.cpp

@@ -26,7 +26,7 @@
 #include "../../../lib/mapObjects/CGMarket.h"
 
 CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CAltarArtifacts::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -37,10 +37,8 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 
 	deal = std::make_shared<CButton>(dealButtonPos, AnimationPath::builtin("ALTSACR.DEF"),
 		CGI->generaltexth->zelp[585], [this]() {CAltarArtifacts::makeDeal(); });
-	labels.emplace_back(std::make_shared<CLabel>(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]));
-	labels.emplace_back(std::make_shared<CLabel>(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
-	selectedSubtitle = std::make_shared<CLabel>(302, 501, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
-	selectedArt = std::make_shared<CArtPlace>(Point(280, 442));
+	labels.emplace_back(std::make_shared<CLabel>(450, 32, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]));
+	labels.emplace_back(std::make_shared<CLabel>(302, 424, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
 
 	sacrificeAllButton = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"),
 		CGI->generaltexth->zelp[571], std::bind(&CExperienceAltar::sacrificeAll, this));
@@ -54,47 +52,49 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 	heroArts = std::make_shared<CArtifactsOfHeroAltar>(Point(-365, -11));
 	heroArts->setHero(hero);
 
-	int slotNum = 0;
-	for(auto & altarSlotPos : posSlotsAltar)
-	{
-		auto altarSlot = std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, slotNum);
-		altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1, hRight);
-		altarSlot->subtitle->clear();
-		items.front().emplace_back(altarSlot);
-		slotNum++;
-	}
+	// Altar
+	offerTradePanel = std::make_shared<ArtifactsAltarPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
+		{
+			CAltarArtifacts::onSlotClickPressed(altarSlot, hRight);
+		});
+	offerTradePanel->updateSlotsCallback = std::bind(&CAltarArtifacts::updateAltarSlots, this);
+	offerTradePanel->moveTo(pos.topLeft() + Point(315, 52));
 
-	expForHero->setText(std::to_string(0));
-	CTradeBase::deselect();
+	CTradeBase::updateSelected();
+	CAltarArtifacts::deselect();
 };
 
 TExpType CAltarArtifacts::calcExpAltarForHero()
 {
 	TExpType expOnAltar(0);
 	for(const auto & tradeSlot : tradeSlotsMap)
-		expOnAltar += calcExpCost(tradeSlot.first);
+		expOnAltar += calcExpCost(tradeSlot.second->getTypeId());
 	expForHero->setText(std::to_string(expOnAltar));
 	return expOnAltar;
 }
 
+void CAltarArtifacts::deselect()
+{
+	CTradeBase::deselect();
+	expForHero->setText(std::to_string(0));
+	tradeSlotsMap.clear();
+	// The event for removing artifacts from the altar will not be triggered. Therefore, we clean the altar immediately.
+	for(auto & slot : offerTradePanel->slots)
+	{
+		slot->setID(-1);
+		slot->subtitle->clear();
+	}
+}
+
 void CAltarArtifacts::makeDeal()
 {
 	std::vector<TradeItemSell> positions;
-	for(const auto & [artInst, altarSlot] : tradeSlotsMap)
+	for(const auto & [altarSlot, artInst] : tradeSlotsMap)
 	{
 		positions.push_back(artInst->getId());
 	}
 	LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
-
-	tradeSlotsMap.clear();
-	// The event for removing artifacts from the altar will not be triggered. Therefore, we clean the altar immediately.
-	for(auto item : items[0])
-	{
-		item->setID(-1);
-		item->subtitle->clear();
-	}
-	calcExpAltarForHero();
-	deal->block(tradeSlotsMap.empty());
+	deselect();
 }
 
 void CAltarArtifacts::sacrificeAll()
@@ -107,10 +107,20 @@ void CAltarArtifacts::sacrificeBackpack()
 	LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, altarId, false, false, true);
 }
 
-void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art)
+void CAltarArtifacts::setSelectedArtifact(std::optional<ArtifactID> id)
 {
-	selectedArt->setArtifact(art);
-	selectedSubtitle->setText(art == nullptr ? "" : std::to_string(calcExpCost(art)));
+	if(id.has_value())
+	{
+		hRight = offerTradePanel->selectedSlot;
+		hRight->setID(id.value().num);
+		offerQty = calcExpCost(id.value());
+	}
+	else
+	{
+		hRight.reset();
+		offerQty = 0;
+	}
+	updateSelected();
 }
 
 std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
@@ -123,47 +133,54 @@ ObjectInstanceID CAltarArtifacts::getObjId() const
 	return altarId;
 }
 
-void CAltarArtifacts::updateSlots()
+void CAltarArtifacts::updateAltarSlots()
 {
 	assert(altarArtifacts->artifactsInBackpack.size() <= GameConstants::ALTAR_ARTIFACTS_SLOTS);
 	assert(tradeSlotsMap.size() <= GameConstants::ALTAR_ARTIFACTS_SLOTS);
 	
-	auto slotsToAdd = tradeSlotsMap;
-	for(auto & altarSlot : items[0])
+	auto tradeSlotsMapNewArts = tradeSlotsMap;
+	for(auto & altarSlot : offerTradePanel->slots)
 		if(altarSlot->id != -1)
 		{
-			if(tradeSlotsMap.find(altarSlot->getArtInstance()) == tradeSlotsMap.end())
+			if(tradeSlotsMap.find(altarSlot) == tradeSlotsMap.end())
 			{
 				altarSlot->setID(-1);
 				altarSlot->subtitle->clear();
 			}
 			else
 			{
-				slotsToAdd.erase(altarSlot->getArtInstance());
+				tradeSlotsMapNewArts.erase(altarSlot);
 			}
 		}
 
-	for(auto & tradeSlot : slotsToAdd)
+	for(auto & tradeSlot : tradeSlotsMapNewArts)
 	{
-		assert(tradeSlot.second->id == -1);
-		assert(altarArtifacts->getSlotByInstance(tradeSlot.first) != ArtifactPosition::PRE_FIRST);
-		tradeSlot.second->setArtInstance(tradeSlot.first);
-		tradeSlot.second->subtitle->setText(std::to_string(calcExpCost(tradeSlot.first)));
+		assert(tradeSlot.first->id == -1);
+		assert(altarArtifacts->getSlotByInstance(tradeSlot.second) != ArtifactPosition::PRE_FIRST);
+		tradeSlot.first->setID(tradeSlot.second->getTypeId());
+		tradeSlot.first->subtitle->setText(std::to_string(calcExpCost(tradeSlot.second->getTypeId())));
 	}
-	for(auto & slotInfo : altarArtifacts->artifactsInBackpack)
+
+	auto newArtsFromBulkMove = altarArtifacts->artifactsInBackpack;
+	for(const auto & [altarSlot, art] : tradeSlotsMap)
 	{
-		if(tradeSlotsMap.find(slotInfo.artifact) == tradeSlotsMap.end())
-		{
-			for(auto & altarSlot : items[0])
-				if(altarSlot->id == -1)
-				{
-					altarSlot->setArtInstance(slotInfo.artifact);
-					altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.artifact)));
-					tradeSlotsMap.try_emplace(slotInfo.artifact, altarSlot);
-					break;
-				}
-		}
+		newArtsFromBulkMove.erase(std::remove_if(newArtsFromBulkMove.begin(), newArtsFromBulkMove.end(), [art = art](auto & slotInfo)
+			{
+				return slotInfo.artifact == art;
+			}));
+	}
+	for(const auto & slotInfo : newArtsFromBulkMove)
+	{
+		for(auto & altarSlot : offerTradePanel->slots)
+			if(altarSlot->id == -1)
+			{
+				altarSlot->setID(slotInfo.artifact->getTypeId());
+				altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.artifact->getTypeId())));
+				tradeSlotsMap.try_emplace(altarSlot, slotInfo.artifact);
+				break;
+			}
 	}
+
 	calcExpAltarForHero();
 	deal->block(tradeSlotsMap.empty());
 }
@@ -176,6 +193,16 @@ void CAltarArtifacts::putBackArtifacts()
 		LOCPLINT->cb->bulkMoveArtifacts(altarId, heroArts->getHero()->id, false, true, true);
 }
 
+CTradeBase::SelectionParams CAltarArtifacts::getSelectionParams() const
+{
+	if(hRight)
+		return std::make_tuple(
+			std::nullopt,
+			SelectionParamOneSide {std::to_string(offerQty), GameResID(hRight->id)}
+	);
+	return std::make_tuple(std::nullopt, std::nullopt);
+}
+
 void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
 {
 	assert(altarSlot);
@@ -187,7 +214,7 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 			if(pickedArtInst->artType->isTradable())
 			{
 				if(altarSlot->id == -1)
-					tradeSlotsMap.try_emplace(pickedArtInst, altarSlot);
+					tradeSlotsMap.try_emplace(altarSlot, pickedArtInst);
 				deal->block(false);
 
 				LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->getHero()->id, ArtifactPosition::TRANSITION_POS),
@@ -200,19 +227,20 @@ void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> &
 			}
 		}
 	}
-	else if(const CArtifactInstance * art = altarSlot->getArtInstance())
+	else if(altarSlot->id != -1)
 	{
-		const auto slot = altarArtifacts->getSlotByInstance(art);
+		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));
-		tradeSlotsMap.erase(art);
+		tradeSlotsMap.erase(altarSlot);
 	}
 }
 
-TExpType CAltarArtifacts::calcExpCost(const CArtifactInstance * art)
+TExpType CAltarArtifacts::calcExpCost(ArtifactID id)
 {
 	int bidQty = 0;
 	int expOfArt = 0;
-	market->getOffer(art->getTypeId(), 0, bidQty, expOfArt, EMarketMode::ARTIFACT_EXP);
+	market->getOffer(id, 0, bidQty, expOfArt, EMarketMode::ARTIFACT_EXP);
 	return hero->calculateXp(expOfArt);
 }

+ 6 - 18
client/widgets/markets/CAltarArtifacts.h

@@ -17,36 +17,24 @@ class CAltarArtifacts : public CExperienceAltar
 public:
 	CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero);
 	TExpType calcExpAltarForHero() override;
+	void deselect() override;
 	void makeDeal() override;
 	void sacrificeAll() override;
 	void sacrificeBackpack();
-	void setSelectedArtifact(const CArtifactInstance * art);
+	void setSelectedArtifact(std::optional<ArtifactID> id);
 	std::shared_ptr<CArtifactsOfHeroAltar> getAOHset() const;
 	ObjectInstanceID getObjId() const;
-	void updateSlots() override;
 	void putBackArtifacts();
 
 private:
 	ObjectInstanceID altarId;
 	const CArtifactSet * altarArtifacts;
-	std::shared_ptr<CArtPlace> selectedArt;
-	std::shared_ptr<CLabel> selectedSubtitle;
 	std::shared_ptr<CButton> sacrificeBackpackButton;
 	std::shared_ptr<CArtifactsOfHeroAltar> heroArts;
-	std::map<const CArtifactInstance*, std::shared_ptr<CTradeableItem>> tradeSlotsMap;
-
-	const std::vector<Point> posSlotsAltar =
-	{
-		Point(317, 53), Point(371, 53), Point(425, 53),
-		Point(479, 53), Point(533, 53), Point(317, 123),
-		Point(371, 123), Point(425, 123), Point(479, 123),
-		Point(533, 123), Point(317, 193), Point(371, 193),
-		Point(425, 193), Point(479, 193), Point(533, 193),
-		Point(317, 263), Point(371, 263), Point(425, 263),
-		Point(479, 263), Point(533, 263), Point(398, 333),
-		Point(452, 333)
-	};
+	std::map<std::shared_ptr<CTradeableItem>, const CArtifactInstance*> tradeSlotsMap;
 
+	void updateAltarSlots();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
-	TExpType calcExpCost(const CArtifactInstance * art);
+	TExpType calcExpCost(ArtifactID id);
 };

+ 2 - 3
client/widgets/markets/CAltarCreatures.cpp

@@ -26,8 +26,7 @@
 #include "../../../lib/mapObjects/CGMarket.h"
 
 CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
-	, CMarketMisc([this](){return CAltarCreatures::getSelectionParams();})
+	: CTradeBase(market, hero, [this](){return CAltarCreatures::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -166,7 +165,7 @@ void CAltarCreatures::makeDeal()
 	}
 }
 
-CMarketMisc::SelectionParams CAltarCreatures::getSelectionParams()
+CTradeBase::SelectionParams CAltarCreatures::getSelectionParams() const
 {
 	std::optional<SelectionParamOneSide> bidSelected = std::nullopt;
 	std::optional<SelectionParamOneSide> offerSelected = std::nullopt;

+ 2 - 2
client/widgets/markets/CAltarCreatures.h

@@ -11,7 +11,7 @@
 
 #include "CTradeBase.h"
 
-class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling, public CMarketMisc
+class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling
 {
 public:
 	CAltarCreatures(const IMarket * market, const CGHeroInstance * hero);
@@ -25,7 +25,7 @@ private:
 	std::vector<int> unitsOnAltar;
 	std::vector<int> expPerUnit;
 
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void updateAltarSlot(const std::shared_ptr<CTradeableItem> & slot);
 	void readExpValues();
 	void updateControls();

+ 3 - 4
client/widgets/markets/CArtifactsBuying.cpp

@@ -26,9 +26,8 @@
 #include "../../../lib/mapObjects/CGTownInstance.h"
 
 CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CArtifactsBuying::getSelectionParams();})
 	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CArtifactsBuying::onSlotClickPressed(heroSlot, hLeft);})
-	, CMarketMisc([this](){return CArtifactsBuying::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -59,7 +58,7 @@ CArtifactsBuying::CArtifactsBuying(const IMarket * market, const CGHeroInstance
 	offerTradePanel->moveTo(pos.topLeft() + Point(328, 182));
 
 	CTradeBase::updateSlots();
-	CMarketMisc::deselect();
+	CTradeBase::deselect();
 }
 
 void CArtifactsBuying::makeDeal()
@@ -68,7 +67,7 @@ void CArtifactsBuying::makeDeal()
 	deselect();
 }
 
-CMarketMisc::SelectionParams CArtifactsBuying::getSelectionParams()
+CTradeBase::SelectionParams CArtifactsBuying::getSelectionParams() const
 {
 	if(hLeft && hRight)
 		return std::make_tuple(

+ 2 - 2
client/widgets/markets/CArtifactsBuying.h

@@ -11,13 +11,13 @@
 
 #include "CTradeBase.h"
 
-class CArtifactsBuying : public CResourcesSelling, public CMarketMisc
+class CArtifactsBuying : public CResourcesSelling
 {
 public:
 	CArtifactsBuying(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
 
 private:
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void CArtifactsBuying::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 };

+ 4 - 5
client/widgets/markets/CArtifactsSelling.cpp

@@ -23,11 +23,10 @@
 #include "../../../lib/mapObjects/CGMarket.h"
 
 CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CArtifactsSelling::getSelectionParams();})
 	, CResourcesBuying(
 		[this](const std::shared_ptr<CTradeableItem> & resSlot){CArtifactsSelling::onSlotClickPressed(resSlot, hRight);},
 		[this](){CTradeBase::updateSubtitles(EMarketMode::ARTIFACT_RESOURCE);})
-	, CMarketMisc([this](){return CArtifactsSelling::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -61,7 +60,7 @@ CArtifactsSelling::CArtifactsSelling(const IMarket * market, const CGHeroInstanc
 	offerTradePanel->selectedSlot->moveTo(pos.topLeft() + Point(409, 473));
 	
 	CArtifactsSelling::updateSelected();
-	CMarketMisc::deselect();
+	CTradeBase::deselect();
 }
 
 void CArtifactsSelling::makeDeal()
@@ -71,7 +70,7 @@ void CArtifactsSelling::makeDeal()
 
 void CArtifactsSelling::updateSelected()
 {
-	CMarketMisc::updateSelected();
+	CTradeBase::updateSelected();
 
 	if(hLeft && hRight)
 	{
@@ -92,7 +91,7 @@ std::shared_ptr<CArtifactsOfHeroMarket> CArtifactsSelling::getAOHset() const
 	return heroArts;
 }
 
-CMarketMisc::SelectionParams CArtifactsSelling::getSelectionParams()
+CTradeBase::SelectionParams CArtifactsSelling::getSelectionParams() const
 {
 	if(hLeft && hRight)
 		return std::make_tuple(

+ 3 - 3
client/widgets/markets/CArtifactsSelling.h

@@ -12,12 +12,12 @@
 #include "../CArtifactsOfHeroMarket.h"
 #include "CTradeBase.h"
 
-class CArtifactsSelling : public CResourcesBuying, public CMarketMisc
+class CArtifactsSelling : public CResourcesBuying
 {
 public:
 	CArtifactsSelling(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
-	void updateSelected();
+	void updateSelected() override;
 	std::shared_ptr<CArtifactsOfHeroMarket> getAOHset() const;
 
 private:
@@ -25,6 +25,6 @@ private:
 	std::shared_ptr<CLabel> bidSelectedSubtitle;
 	std::shared_ptr<CTradeableItem> bidSelectedSlot;
 
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
 };

+ 3 - 4
client/widgets/markets/CFreelancerGuild.cpp

@@ -27,11 +27,10 @@
 #include "../../../lib/mapObjects/CGTownInstance.h"
 
 CFreelancerGuild::CFreelancerGuild(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CFreelancerGuild::getSelectionParams();})
 	, CResourcesBuying(
 		[this](const std::shared_ptr<CTradeableItem> & heroSlot){CFreelancerGuild::onSlotClickPressed(heroSlot, hLeft);},
 		[this](){CTradeBase::updateSubtitles(EMarketMode::CREATURE_RESOURCE);})
-	, CMarketMisc([this](){return CFreelancerGuild::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -71,7 +70,7 @@ CFreelancerGuild::CFreelancerGuild(const IMarket * market, const CGHeroInstance
 			};
 		});
 
-	CMarketMisc::deselect();
+	CTradeBase::deselect();
 }
 
 void CFreelancerGuild::makeDeal()
@@ -83,7 +82,7 @@ void CFreelancerGuild::makeDeal()
 	}
 }
 
-CMarketMisc::SelectionParams CFreelancerGuild::getSelectionParams()
+CTradeBase::SelectionParams CFreelancerGuild::getSelectionParams() const
 {
 	if(hLeft && hRight)
 		return std::make_tuple(

+ 2 - 2
client/widgets/markets/CFreelancerGuild.h

@@ -11,14 +11,14 @@
 
 #include "CTradeBase.h"
 
-class CFreelancerGuild : public CCreaturesSelling , public CResourcesBuying, public CMarketMisc
+class CFreelancerGuild : public CCreaturesSelling , public CResourcesBuying
 {
 public:
 	CFreelancerGuild(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
 
 private:
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void onOfferSliderMoved(int newVal);
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
 };

+ 3 - 4
client/widgets/markets/CMarketResources.cpp

@@ -25,12 +25,11 @@
 #include "../../../lib/mapObjects/CGMarket.h"
 
 CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CMarketResources::getSelectionParams();})
 	, CResourcesBuying(
 		[this](const std::shared_ptr<CTradeableItem> & resSlot){CMarketResources::onSlotClickPressed(resSlot, hRight);},
 		[this](){CMarketResources::updateSubtitles();})
 	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CMarketResources::onSlotClickPressed(heroSlot, hLeft);})
-	, CMarketMisc([this](){return CMarketResources::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -59,7 +58,7 @@ CMarketResources::CMarketResources(const IMarket * market, const CGHeroInstance
 		});
 
 	CTradeBase::updateSlots();
-	CMarketMisc::deselect();
+	CTradeBase::deselect();
 }
 
 void CMarketResources::makeDeal()
@@ -71,7 +70,7 @@ void CMarketResources::makeDeal()
 	}
 }
 
-CMarketMisc::SelectionParams CMarketResources::getSelectionParams()
+CTradeBase::SelectionParams CMarketResources::getSelectionParams() const
 {
 	if(hLeft && hRight && hLeft->id != hRight->id)
 		return std::make_tuple(

+ 2 - 2
client/widgets/markets/CMarketResources.h

@@ -11,14 +11,14 @@
 
 #include "CTradeBase.h"
 
-class CMarketResources : public CResourcesSelling, public CResourcesBuying, public CMarketMisc
+class CMarketResources : public CResourcesSelling, public CResourcesBuying
 {
 public:
 	CMarketResources(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
 
 private:
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void onOfferSliderMoved(int newVal);
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 	void updateSubtitles();

+ 34 - 64
client/widgets/markets/CTradeBase.cpp

@@ -27,33 +27,13 @@
 #include "../../../lib/mapObjects/CGHeroInstance.h"
 #include "../../../lib/mapObjects/CGMarket.h"
 
-CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero)
+CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero, const SelectionParamsFunctor & getParamsCallback)
 	: market(market)
 	, hero(hero)
+	, selectionParamsCallback(getParamsCallback)
 {
 }
 
-void CTradeBase::removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove)
-{
-	for(auto item : toRemove)
-		removeItem(item);
-}
-
-void CTradeBase::removeItem(std::shared_ptr<CTradeableItem> item)
-{
-	offerTradePanel->slots.erase(std::remove(offerTradePanel->slots.begin(), offerTradePanel->slots.end(), item));
-
-	if(hRight == item)
-		hRight.reset();
-}
-
-void CTradeBase::getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove)
-{
-	for(auto item : bidTradePanel->slots)
-		if(!hero->getStackCount(SlotID(item->serial)))
-			toRemove.insert(item);
-}
-
 void CTradeBase::deselect()
 {
 	if(hLeft)
@@ -69,6 +49,9 @@ void CTradeBase::deselect()
 		offerSlider->scrollTo(0);
 		offerSlider->block(true);
 	}
+	bidQty = 0;
+	offerQty = 0;
+	updateSelected();
 }
 
 void CTradeBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
@@ -104,6 +87,31 @@ void CTradeBase::updateSubtitles(EMarketMode marketMode)
 		offerTradePanel->clearSubtitles();
 };
 
+void CTradeBase::updateSelected()
+{
+	const auto updateSelectedBody = [](std::shared_ptr<TradePanelBase> & tradePanel, const std::optional<const SelectionParamOneSide> & params)
+	{
+		std::optional<size_t> lImageIndex = std::nullopt;
+		if(params.has_value())
+		{
+			tradePanel->setSelectedSubtitleText(params.value().text);
+			lImageIndex = params.value().imageIndex;
+		}
+		else
+		{
+			tradePanel->clearSelectedSubtitleText();
+		}
+		tradePanel->setSelectedFrameIndex(lImageIndex);
+	};
+
+	assert(selectionParamsCallback);
+	const auto params = selectionParamsCallback();
+	if(bidTradePanel)
+		updateSelectedBody(bidTradePanel, std::get<0>(params));
+	if(offerTradePanel)
+		updateSelectedBody(offerTradePanel, std::get<1>(params));
+}
+
 CExperienceAltar::CExperienceAltar()
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
@@ -128,7 +136,7 @@ CCreaturesSelling::CCreaturesSelling()
 			slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId)));
 	}
 	bidTradePanel = std::make_shared<CreaturesPanel>(nullptr, slots);
-	bidTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this);
+	bidTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitles, this);
 }
 
 bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot)
@@ -136,7 +144,7 @@ bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem>
 	return hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
 }
 
-void CCreaturesSelling::updateSubtitle()
+void CCreaturesSelling::updateSubtitles()
 {
 	for(auto & heroSlot : bidTradePanel->slots)
 		heroSlot->subtitle->setText(std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial))));
@@ -156,50 +164,12 @@ CResourcesSelling::CResourcesSelling(const CTradeableItem::ClickPressedFunctor &
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
-	bidTradePanel = std::make_shared<ResourcesPanel>(clickPressedCallback, std::bind(&CResourcesSelling::updateSubtitle, this));
+	bidTradePanel = std::make_shared<ResourcesPanel>(clickPressedCallback, std::bind(&CResourcesSelling::updateSubtitles, this));
 	labels.emplace_back(std::make_shared<CLabel>(156, 148, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]));
 }
 
-void CResourcesSelling::updateSubtitle()
+void CResourcesSelling::updateSubtitles()
 {
 	for(const auto & slot : bidTradePanel->slots)
 		slot->subtitle->setText(std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial))));
 }
-
-CMarketMisc::CMarketMisc(const SelectionParamsFunctor & callback)
-	: selectionParamsCallback(callback)
-{
-}
-
-void CMarketMisc::deselect()
-{
-	CTradeBase::deselect();
-	bidQty = 0;
-	offerQty = 0;
-	updateSelected();
-}
-
-void CMarketMisc::updateSelected()
-{
-	const auto updateSelectedBody = [](std::shared_ptr<TradePanelBase> & tradePanel, const std::optional<const SelectionParamOneSide> & params)
-	{
-		std::optional<size_t> lImageIndex = std::nullopt;
-		if(params.has_value())
-		{
-			tradePanel->setSelectedSubtitleText(params.value().text);
-			lImageIndex = params.value().imageIndex;
-		}
-		else
-		{
-			tradePanel->clearSelectedSubtitleText();
-		}
-		tradePanel->setSelectedFrameIndex(lImageIndex);
-	};
-
-	assert(selectionParamsCallback);
-	const auto params = selectionParamsCallback();
-	if(bidTradePanel)
-		updateSelectedBody(bidTradePanel, std::get<0>(params));
-	if(offerTradePanel)
-		updateSelectedBody(offerTradePanel, std::get<1>(params));
-}

+ 20 - 32
client/widgets/markets/CTradeBase.h

@@ -24,33 +24,42 @@ class CSlider;
 class CTradeBase : public CIntObject
 {
 public:
+	struct SelectionParamOneSide
+	{
+		std::string text;
+		int imageIndex;
+	};
+	using SelectionParams = std::tuple<std::optional<const SelectionParamOneSide>, std::optional<const SelectionParamOneSide>>;
+	using SelectionParamsFunctor = std::function<const SelectionParams()>;
+
 	const IMarket * market;
 	const CGHeroInstance * hero;
 
-	//all indexes: 1 = left, 0 = right
-	std::array<std::vector<std::shared_ptr<CTradeableItem>>, 2> items;
 	std::shared_ptr<TradePanelBase> bidTradePanel;
 	std::shared_ptr<TradePanelBase> offerTradePanel;
 
-	//highlighted items (nullptr if no highlight)
+	// Highlighted trade slots (nullptr if no highlight)
 	std::shared_ptr<CTradeableItem> hLeft;
 	std::shared_ptr<CTradeableItem> hRight;
 	std::shared_ptr<CButton> deal;
 	std::shared_ptr<CSlider> offerSlider;
 	std::shared_ptr<CButton> maxAmount;
-
 	std::vector<std::shared_ptr<CLabel>> labels;
 	std::vector<std::shared_ptr<CTextBox>> texts;
+	SelectionParamsFunctor selectionParamsCallback;
+	int bidQty;
+	int offerQty;
 
-	CTradeBase(const IMarket * market, const CGHeroInstance * hero);
-	void removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove);
-	void removeItem(std::shared_ptr<CTradeableItem> item);
-	void getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove);
+	CTradeBase(const IMarket * market, const CGHeroInstance * hero, const SelectionParamsFunctor & getParamsCallback);
 	virtual void makeDeal() = 0;
 	virtual void deselect();
-	virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 	virtual void updateSlots();
+
+protected:
+	virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 	virtual void updateSubtitles(EMarketMode marketMode);
+	virtual void updateSelected();
+	virtual CTradeBase::SelectionParams getSelectionParams() const = 0;
 };
 
 // Market subclasses
@@ -72,7 +81,7 @@ class CCreaturesSelling : virtual public CTradeBase
 public:
 	CCreaturesSelling();
 	bool slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot);
-	void updateSubtitle();
+	void updateSubtitles();
 };
 
 class CResourcesBuying : virtual public CTradeBase
@@ -86,26 +95,5 @@ class CResourcesSelling : virtual public CTradeBase
 {
 public:
 	CResourcesSelling(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
-	void updateSubtitle();
-};
-
-class CMarketMisc : virtual public CTradeBase
-{
-public:
-	struct SelectionParamOneSide
-	{ 
-		std::string text; 
-		int imageIndex; 
-	};
-	using SelectionParams = std::tuple<std::optional<const SelectionParamOneSide>, std::optional<const SelectionParamOneSide>>;
-	using SelectionParamsFunctor = std::function<const SelectionParams()>;
-
-	CMarketMisc(const SelectionParamsFunctor & callback);
-	void deselect() override;
-	void updateSelected();
-
-protected:
-	int bidQty;
-	int offerQty;
-	SelectionParamsFunctor selectionParamsCallback;
+	void updateSubtitles();
 };

+ 2 - 3
client/widgets/markets/CTransferResources.cpp

@@ -24,9 +24,8 @@
 #include "../../../lib/CGeneralTextHandler.h"
 
 CTransferResources::CTransferResources(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
+	: CTradeBase(market, hero, [this](){return CTransferResources::getSelectionParams();})
 	, CResourcesSelling([this](const std::shared_ptr<CTradeableItem> & heroSlot){CTransferResources::onSlotClickPressed(heroSlot, hLeft);})
-	, CMarketMisc([this](){return CTransferResources::getSelectionParams();})
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -65,7 +64,7 @@ void CTransferResources::makeDeal()
 	}
 }
 
-CMarketMisc::SelectionParams CTransferResources::getSelectionParams()
+CTradeBase::SelectionParams CTransferResources::getSelectionParams() const
 {
 	if(hLeft && hRight)
 		return std::make_tuple(

+ 2 - 2
client/widgets/markets/CTransferResources.h

@@ -11,14 +11,14 @@
 
 #include "CTradeBase.h"
 
-class CTransferResources : public CResourcesSelling, public CMarketMisc
+class CTransferResources : public CResourcesSelling
 {
 public:
 	CTransferResources(const IMarket * market, const CGHeroInstance * hero);
 	void makeDeal() override;
 
 private:
-	CMarketMisc::SelectionParams getSelectionParams();
+	CTradeBase::SelectionParams getSelectionParams() const override;
 	void onOfferSliderMoved(int newVal);
 	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 };

+ 17 - 23
client/widgets/markets/TradePanels.cpp

@@ -25,7 +25,6 @@
 
 CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, int Serial)
 	: SelectableSlot(area, Point(1, 2))
-	, artInstance(nullptr)
 	, type(EType(-1)) // set to invalid, will be corrected in setType
 	, id(ID)
 	, serial(Serial)
@@ -75,6 +74,7 @@ void CTradeableItem::setType(EType newType)
 			break;
 		case EType::ARTIFACT_PLACEHOLDER:
 		case EType::ARTIFACT_INSTANCE:
+			subtitle->moveTo(pos.topLeft() + Point(22, 55));
 			break;
 		case EType::ARTIFACT_TYPE:
 			subtitle->moveTo(pos.topLeft() + Point(35, 57));
@@ -195,28 +195,6 @@ void CTradeableItem::showPopupWindow(const Point & cursorPosition)
 	}
 }
 
-const CArtifactInstance* CTradeableItem::getArtInstance() const
-{
-	switch(type)
-	{
-	case EType::ARTIFACT_PLACEHOLDER:
-	case EType::ARTIFACT_INSTANCE:
-		return artInstance;
-	default:
-		return nullptr;
-	}
-}
-
-void CTradeableItem::setArtInstance(const CArtifactInstance * art)
-{
-	assert(type == EType::ARTIFACT_PLACEHOLDER || type == EType::ARTIFACT_INSTANCE);
-	artInstance = art;
-	if(art)
-		setID(art->getTypeId());
-	else
-		setID(-1);
-}
-
 void TradePanelBase::updateSlots()
 {
 	if(deleteSlotsCheck)
@@ -370,3 +348,19 @@ CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & click
 	}
 	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
 }
+
+ArtifactsAltarPanel::ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
+{
+	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
+
+	int slotNum = 0;
+	for(auto & altarSlotPos : slotsPos)
+	{
+		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, slotNum));
+		slot->clickPressedCallback = clickPressedCallback;
+		slot->subtitle->clear();
+		slotNum++;
+	}
+	selectedSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
+	selectedSlot->subtitle->moveBy(Point(0, 3));
+}

+ 20 - 4
client/widgets/markets/TradePanels.h

@@ -27,7 +27,6 @@ public:
 	int getIndex();
 	using ClickPressedFunctor = std::function<void(const std::shared_ptr<CTradeableItem>&)>;
 
-	const CArtifactInstance * artInstance; //holds ptr to artifact instance id type artifact
 	EType type;
 	int id;
 	const int serial;
@@ -37,9 +36,6 @@ public:
 	void setType(EType newType);
 	void setID(int newID);
 
-	const CArtifactInstance * getArtInstance() const;
-	void setArtInstance(const CArtifactInstance * art);
-
 	void showPopupWindow(const Point & cursorPosition) override;
 	void hover(bool on) override;
 	void clickPressed(const Point & cursorPosition) override;
@@ -139,3 +135,23 @@ public:
 	CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
 		const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots = true);
 };
+
+class ArtifactsAltarPanel : public TradePanelBase
+{
+	const std::vector<Point> slotsPos =
+	{
+		Point(0, 0), Point(54, 0), Point(108, 0),
+		Point(162, 0), Point(216, 0), Point(0, 70),
+		Point(54, 70), Point(108, 70), Point(162, 70),
+		Point(216, 70), Point(0, 140), Point(54, 140),
+		Point(108, 140), Point(162, 140), Point(216, 140),
+		Point(0, 210), Point(54, 210), Point(108, 210),
+		Point(162, 210), Point(216, 210), Point(81, 280),
+		Point(135, 280)
+	};
+	const Point slotDimension = Point(69, 66);
+	const Point selectedPos = Point(-48, 389);
+
+public:
+	ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback);
+};

+ 2 - 2
client/windows/CAltarWindow.cpp

@@ -47,9 +47,9 @@ void CAltarWindow::artifactMoved(const ArtifactLocation & srcLoc, const Artifact
 			altarArtifacts->updateSlots();
 
 		if(const auto pickedArt = getPickedArtifact())
-			altarArtifacts->setSelectedArtifact(pickedArt);
+			altarArtifacts->setSelectedArtifact(pickedArt->getTypeId());
 		else
-			altarArtifacts->setSelectedArtifact(nullptr);
+			altarArtifacts->setSelectedArtifact(std::nullopt);
 	}
 	CWindowWithArtifacts::artifactMoved(srcLoc, destLoc, withRedraw);
 }