Browse Source

subclasses for market composition

SoundSSGood 1 year ago
parent
commit
d0ca63d2c9

+ 42 - 87
client/widgets/CAltar.cpp

@@ -11,7 +11,6 @@
 #include "StdInc.h"
 #include "CAltar.h"
 
-#include "../widgets/CAltar.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/CursorHandler.h"
 #include "../widgets/Buttons.h"
@@ -28,32 +27,8 @@
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/mapObjects/CGMarket.h"
 
-CAltar::CAltar(const IMarket * market, const CGHeroInstance * hero)
-	: CTradeBase(market, hero)
-{
-	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
-
-	// Experience needed to reach next level
-	texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
-	// Total experience on the Altar
-	texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
-	deal = std::make_shared<CButton>(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"), CGI->generaltexth->zelp[585], std::bind(&CAltar::makeDeal, this));
-	expToLevel = std::make_shared<CLabel>(75, 477, FONT_SMALL, ETextAlignment::CENTER);
-	expForHero = std::make_shared<CLabel>(75, 545, FONT_SMALL, ETextAlignment::CENTER);
-}
-
-void CAltar::deselect()
-{
-	if(hLeft)
-		hLeft->selection->selectSlot(false);
-	if(hRight)
-		hRight->selection->selectSlot(false);
-	hLeft = hRight = nullptr;
-	deal->block(true);
-}
-
 CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero)
-	: CAltar(market, hero)
+	: CTradeBase(market, hero)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
 
@@ -63,7 +38,7 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 	selectedArt = std::make_shared<CArtPlace>(Point(280, 442));
 
 	sacrificeAllButton = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"),
-		CGI->generaltexth->zelp[571], std::bind(&CAltar::sacrificeAll, this));
+		CGI->generaltexth->zelp[571], std::bind(&CExpAltar::sacrificeAll, this));
 	sacrificeAllButton->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
 
 	sacrificeBackpackButton = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"),
@@ -235,7 +210,7 @@ void CAltarArtifacts::onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSl
 }
 
 CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero)
-	: CAltar(market, hero)
+	: CTradeBase(market, hero)
 {
 	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
 
@@ -246,46 +221,27 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance *
 	lSubtitle = std::make_shared<CLabel>(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 	rSubtitle = std::make_shared<CLabel>(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
 
-	unitsSlider = std::make_shared<CSlider>(Point(231, 481), 137, std::bind(&CAltarCreatures::onUnitsSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
-	maxUnits = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, unitsSlider));
+	offerSlider = std::make_shared<CSlider>(Point(231, 481), 137, std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
+	maxUnits = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, offerSlider));
 
 	unitsOnAltar.resize(GameConstants::ARMY_SIZE, 0);
 	expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
 	sacrificeAllButton = std::make_shared<CButton>(
-		Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltar::sacrificeAll, this));
+		Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CExpAltar::sacrificeAll, this));
 
-	// Creating slots for hero creatures
-	SCreaturesPanel::slotsData slots;
-	for(auto slotId = SlotID(0); slotId.num < GameConstants::ARMY_SIZE; slotId++)
-	{
-		if(const auto & creature = hero->getCreature(slotId))
-			slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId)));
-	}
-	leftTradePanel = std::make_shared<SCreaturesPanel>([this](std::shared_ptr<CTradeableItem> altarSlot) -> void
-		{
-			onSlotClickPressed(altarSlot, rightTradePanel, hLeft, hRight);
-		}, slots);
+	// Hero creatures panel
+	assert(leftTradePanel);
 	leftTradePanel->moveBy(Point(45, 110));
-	leftTradePanel->updateSlotsCallback = [this]() -> void
-		{
-			for(auto & heroSlot : leftTradePanel->slots)
-				heroSlot->subtitle = std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)));
-		};
+	leftTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this);
 
-	// Creating slots for creatures on altar
-	for(auto & slot : slots)
-		std::get<2>(slot) = 0;
+	// Altar creatures panel
 	rightTradePanel = std::make_shared<SCreaturesPanel>([this](std::shared_ptr<CTradeableItem> altarSlot) -> void
 		{
-			onSlotClickPressed(altarSlot, leftTradePanel, hRight, hLeft);
-		}, slots);
+			onSlotClickPressed(altarSlot, hRight);
+		}, leftTradePanel->slots);
 	rightTradePanel->moveBy(Point(334, 110));
 
-	leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = [this](std::shared_ptr<CTradeableItem> & slot) -> bool
-		{
-			return this->hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
-		};
-
+	leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1);
 	readExpValues();
 	calcExpAltarForHero();
 	deselect();
@@ -326,17 +282,17 @@ void CAltarCreatures::updateControls()
 		if(lastSlot.has_value() && lastSlot.value() == SlotID(hLeft->serial))
 			sliderAmount--;
 	}
-	unitsSlider->setAmount(sliderAmount);
-	unitsSlider->block(!unitsSlider->getAmount());
+	offerSlider->setAmount(sliderAmount);
+	offerSlider->block(!offerSlider->getAmount());
 	if(hLeft)
-		unitsSlider->scrollTo(unitsOnAltar[hLeft->serial]);
-	maxUnits->block(unitsSlider->getAmount() == 0);
+		offerSlider->scrollTo(unitsOnAltar[hLeft->serial]);
+	maxUnits->block(offerSlider->getAmount() == 0);
 }
 
 void CAltarCreatures::updateSubtitlesForSelected()
 {
 	if(hLeft)
-		lSubtitle->setText(std::to_string(unitsSlider->getValue()));
+		lSubtitle->setText(std::to_string(offerSlider->getValue()));
 	else
 		lSubtitle->setText("");
 	if(hRight)
@@ -356,8 +312,8 @@ void CAltarCreatures::updateSlots()
 
 void CAltarCreatures::deselect()
 {
-	CAltar::deselect();
-	unitsSlider->block(true);
+	CTradeBase::deselect();
+	offerSlider->block(true);
 	maxUnits->block(true);
 	updateSubtitlesForSelected();
 }
@@ -376,7 +332,7 @@ TExpType CAltarCreatures::calcExpAltarForHero()
 void CAltarCreatures::makeDeal()
 {
 	deselect();
-	unitsSlider->scrollTo(0);
+	offerSlider->scrollTo(0);
 	expForHero->setText(std::to_string(0));
 
 	std::vector<TradeItemSell> ids;
@@ -420,7 +376,7 @@ void CAltarCreatures::sacrificeAll()
 	unitsOnAltar[lastSlot.value().num]--;
 
 	if(hRight)
-		unitsSlider->scrollTo(unitsOnAltar[hRight->serial]);
+		offerSlider->scrollTo(unitsOnAltar[hRight->serial]);
 	for(auto altarSlot : rightTradePanel->slots)
 		updateAltarSlot(altarSlot);
 	updateSubtitlesForSelected();
@@ -436,7 +392,7 @@ void CAltarCreatures::updateAltarSlot(std::shared_ptr<CTradeableItem> slot)
 		boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "";
 }
 
-void CAltarCreatures::onUnitsSliderMoved(int newVal)
+void CAltarCreatures::onOfferSliderMoved(int newVal)
 {
 	if(hLeft)
 		unitsOnAltar[hLeft->serial] = newVal;
@@ -447,30 +403,29 @@ void CAltarCreatures::onUnitsSliderMoved(int newVal)
 	updateSubtitlesForSelected();
 }
 
-void CAltarCreatures::onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSlot, std::shared_ptr<STradePanel> & oppositePanel,
-	std::shared_ptr<CTradeableItem> & hCurSide, std::shared_ptr<CTradeableItem> & hOppSide)
+void CAltarCreatures::onSlotClickPressed(std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSide)
 {
-	std::shared_ptr<CTradeableItem> oppositeSlot;
+	if(hCurSide == newSlot)
+		return;
+
+	auto * oppositeSlot = &hLeft;
+	auto oppositePanel = leftTradePanel;
+	CTradeBase::onSlotClickPressed(newSlot, hCurSide);
+	if(hCurSide == hLeft)
+	{
+		oppositeSlot = &hRight;
+		oppositePanel = rightTradePanel;
+	}
+	std::shared_ptr<CTradeableItem> oppositeNewSlot;
 	for(const auto & slot : oppositePanel->slots)
-		if(slot->serial == altarSlot->serial)
+		if(slot->serial == newSlot->serial)
 		{
-			oppositeSlot = slot;
+			oppositeNewSlot = slot;
 			break;
 		}
-
-	if(hCurSide)
-		hCurSide->selection->selectSlot(false);
-	if(hOppSide)
-		hOppSide->selection->selectSlot(false);
-	if(hCurSide != altarSlot && oppositeSlot)
-	{
-		hCurSide = altarSlot;
-		hOppSide = oppositeSlot;
-		updateControls();
-		updateSubtitlesForSelected();
-		redraw();
-	}
-	hCurSide->selection->selectSlot(true);
-	hOppSide->selection->selectSlot(true);
+	assert(oppositeNewSlot);
+	CTradeBase::onSlotClickPressed(oppositeNewSlot, *oppositeSlot);
+	updateControls();
+	updateSubtitlesForSelected();
 	redraw();
 }

+ 4 - 22
client/widgets/CAltar.h

@@ -12,23 +12,7 @@
 #include "../widgets/CArtifactsOfHeroAltar.h"
 #include "../widgets/CTradeBase.h"
 
-class CSlider;
-
-class CAltar : public CTradeBase, public CIntObject
-{
-public:
-	std::shared_ptr<CLabel> expToLevel;
-	std::shared_ptr<CLabel> expForHero;
-	std::shared_ptr<CButton> sacrificeAllButton;
-
-	CAltar(const IMarket * market, const CGHeroInstance * hero);
-	virtual ~CAltar() = default;
-	virtual void sacrificeAll() = 0;
-	virtual void deselect();
-	virtual TExpType calcExpAltarForHero() = 0;
-};
-
-class CAltarArtifacts : public CAltar
+class CAltarArtifacts : public CExpAltar
 {
 public:
 	CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero);
@@ -62,7 +46,7 @@ private:
 	void onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSlot);
 };
 
-class CAltarCreatures : public CAltar
+class CAltarCreatures : public CExpAltar, public CCreaturesSelling
 {
 public:
 	CAltarCreatures(const IMarket * market, const CGHeroInstance * hero);
@@ -75,7 +59,6 @@ public:
 
 private:
 	std::shared_ptr<CButton> maxUnits;
-	std::shared_ptr<CSlider> unitsSlider;
 	std::vector<int> unitsOnAltar;
 	std::vector<int> expPerUnit;
 	std::shared_ptr<CLabel> lSubtitle, rSubtitle;
@@ -83,7 +66,6 @@ private:
 	void readExpValues();
 	void updateControls();
 	void updateSubtitlesForSelected();
-	void onUnitsSliderMoved(int newVal);
-	void onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSlot, std::shared_ptr<STradePanel> & oppositePanel,
-		std::shared_ptr<CTradeableItem> & hCurSide, std::shared_ptr<CTradeableItem> & hOppSide);
+	void onOfferSliderMoved(int newVal);
+	void onSlotClickPressed(std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSide) override;
 };

+ 82 - 2
client/widgets/CTradeBase.cpp

@@ -13,6 +13,7 @@
 
 #include "../gui/CGuiHandler.h"
 #include "../render/Canvas.h"
+#include "../widgets/Buttons.h"
 #include "../widgets/TextControls.h"
 #include "../windows/InfoWindows.h"
 
@@ -367,8 +368,25 @@ SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPresse
 		slot->clickPressedCallback = clickPressedCallback;
 		if(creaturesNum != 0)
 			slot->subtitle = std::to_string(std::get<2>(slotData));
-		slot->pos.w = 58; slots.back()->pos.h = 64;
-		slot->selection = std::make_unique<SelectableSlot>(Rect(slotsPos[slotId.num], slots.back()->pos.dimensions()), Point(1, 1), selectionWidth);
+		slot->pos.w = 58; slot->pos.h = 64;
+		slot->selection = std::make_unique<SelectableSlot>(Rect(slotsPos[slotId.num], slot->pos.dimensions()), Point(1, 1), selectionWidth);
+	}
+}
+
+SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
+	std::vector<std::shared_ptr<CTradeableItem>> & stsSlots, bool emptySlots)
+{
+	assert(slots.size() <= GameConstants::ARMY_SIZE);
+	OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
+
+	for(const auto & srcSlot : stsSlots)
+	{
+		auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(slotsPos[srcSlot->serial],
+			emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, true, srcSlot->serial));
+		slot->clickPressedCallback = clickPressedCallback;
+		slot->subtitle = emptySlots ? "" : srcSlot->subtitle;
+		slot->pos.w = srcSlot->pos.w; slot->pos.h = srcSlot->pos.h;
+		slot->selection = std::make_unique<SelectableSlot>(Rect(slotsPos[slot->serial], slot->pos.dimensions()), Point(1, 1), selectionWidth);
 	}
 }
 
@@ -376,6 +394,8 @@ CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero)
 	: market(market)
 	, hero(hero)
 {
+	deal = std::make_shared<CButton>(Point(), AnimationPath::builtin("ALTSACR.DEF"),
+		CGI->generaltexth->zelp[585], std::bind(&CTradeBase::makeDeal, this));
 }
 
 void CTradeBase::removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove)
@@ -398,3 +418,63 @@ void CTradeBase::getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRem
 		if(!hero->getStackCount(SlotID(item->serial)))
 			toRemove.insert(item);
 }
+
+void CTradeBase::deselect()
+{
+	if(hLeft)
+		hLeft->selection->selectSlot(false);
+	if(hRight)
+		hRight->selection->selectSlot(false);
+	hLeft = hRight = nullptr;
+	deal->block(true);
+}
+
+void CTradeBase::onSlotClickPressed(std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
+{
+	if(newSlot == hCurSlot)
+		return;
+
+	if(hCurSlot)
+		hCurSlot->selection->selectSlot(false);
+	hCurSlot = newSlot;
+	newSlot->selection->selectSlot(true);
+}
+
+CExpAltar::CExpAltar()
+{
+	OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
+
+	// Experience needed to reach next level
+	texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
+	// Total experience on the Altar
+	texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
+	deal->moveBy(dealButtonPos);
+	expToLevel = std::make_shared<CLabel>(75, 477, FONT_SMALL, ETextAlignment::CENTER);
+	expForHero = std::make_shared<CLabel>(75, 545, FONT_SMALL, ETextAlignment::CENTER);
+}
+
+CCreaturesSelling::CCreaturesSelling()
+{
+	assert(hero);
+	SCreaturesPanel::slotsData slots;
+	for(auto slotId = SlotID(0); slotId.num < GameConstants::ARMY_SIZE; slotId++)
+	{
+		if(const auto & creature = hero->getCreature(slotId))
+			slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId)));
+	}
+	leftTradePanel = std::make_shared<SCreaturesPanel>([this](std::shared_ptr<CTradeableItem> altarSlot) -> void
+		{
+			onSlotClickPressed(altarSlot, hLeft);
+		}, slots);
+}
+
+bool CCreaturesSelling::slotDeletingCheck(std::shared_ptr<CTradeableItem> & slot)
+{
+	return hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
+}
+
+void CCreaturesSelling::updateSubtitle()
+{
+	for(auto & heroSlot : leftTradePanel->slots)
+		heroSlot->subtitle = std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)));
+}

+ 28 - 0
client/widgets/CTradeBase.h

@@ -24,6 +24,7 @@ VCMI_LIB_NAMESPACE_END
 
 class CButton;
 class CTextBox;
+class CSlider;
 
 enum EType
 {
@@ -137,6 +138,8 @@ struct SCreaturesPanel : public STradePanel
 		Point(83, 196)
 	};
 	SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, slotsData & initialSlots);
+	SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
+		std::vector<std::shared_ptr<CTradeableItem>> & stsSlots, bool emptySlots = true);
 };
 
 class CTradeBase
@@ -153,15 +156,40 @@ public:
 	std::shared_ptr<CTradeableItem> hLeft;
 	std::shared_ptr<CTradeableItem> hRight;
 	std::shared_ptr<CButton> deal;
+	std::shared_ptr<CSlider> offerSlider;
 
 	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);
 	virtual void makeDeal() = 0;
+	virtual void deselect();
+	virtual void onSlotClickPressed(std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
 
 protected:
 	std::vector<std::shared_ptr<CLabel>> labels;
 	std::vector<std::shared_ptr<CButton>> buttons;
 	std::vector<std::shared_ptr<CTextBox>> texts;
 };
+
+// Market subclasses
+class CExpAltar : virtual public CTradeBase, virtual public CIntObject
+{
+public:
+	std::shared_ptr<CLabel> expToLevel;
+	std::shared_ptr<CLabel> expForHero;
+	std::shared_ptr<CButton> sacrificeAllButton;
+	const Point dealButtonPos = Point(269, 520);
+
+	CExpAltar();
+	virtual void sacrificeAll() = 0;
+	virtual TExpType calcExpAltarForHero() = 0;
+};
+
+class CCreaturesSelling : virtual public CTradeBase, virtual public CIntObject
+{
+public:
+	CCreaturesSelling();
+	bool slotDeletingCheck(std::shared_ptr<CTradeableItem> & slot);
+	void updateSubtitle();
+};

+ 1 - 1
client/windows/CAltarWindow.h

@@ -28,7 +28,7 @@ public:
 
 private:
 	const CGHeroInstance * hero;
-	std::shared_ptr<CAltar> altar;
+	std::shared_ptr<CExpAltar> altar;
 	std::shared_ptr<CButton> changeModeButton;
 	std::shared_ptr<CButton> quitButton;
 	std::function<void()> windowClosedCallback;

+ 1 - 8
client/windows/CTradeWindow.cpp

@@ -100,14 +100,7 @@ void CTradeWindow::initItems(bool Left)
 
 		auto clickPressedTradePanel = [this](std::shared_ptr<CTradeableItem> newSlot, bool left)
 		{
-			auto * selectedSlot = &hRight;
-			if(left)
-				selectedSlot = &hLeft;
-
-			if(*selectedSlot)
-				(*selectedSlot)->selection->selectSlot(false);
-			*selectedSlot = newSlot;
-			newSlot->selection->selectSlot(true);
+			CTradeBase::onSlotClickPressed(newSlot, left ? hLeft : hRight);
 			selectionChanged(left);
 		};