From 6c828d1be9e45a1cf14253a0018e8cf9fc534a9b Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 19 Nov 2023 02:05:10 +0200 Subject: [PATCH 1/9] Resources trade panel --- client/widgets/CTradeBase.cpp | 46 ++++++++++---- client/widgets/CTradeBase.h | 103 ++++++++++++++++++++------------ client/windows/CTradeWindow.cpp | 97 +++++++++++++++++++++--------- 3 files changed, 167 insertions(+), 79 deletions(-) diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index e1e7aacde..b195d6990 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -20,7 +20,7 @@ #include "../../lib/CGeneralTextHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" -CTradeBase::CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial) +CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial) : CIntObject(LCLICK | HOVER | SHOW_POPUP, pos) , type(EType(-1)) // set to invalid, will be corrected in setType , id(ID) @@ -38,7 +38,7 @@ CTradeBase::CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool L } } -void CTradeBase::CTradeableItem::setType(EType newType) +void CTradeableItem::setType(EType newType) { if(type != newType) { @@ -57,7 +57,7 @@ void CTradeBase::CTradeableItem::setType(EType newType) } } -void CTradeBase::CTradeableItem::setID(int newID) +void CTradeableItem::setID(int newID) { if(id != newID) { @@ -76,7 +76,7 @@ void CTradeBase::CTradeableItem::setID(int newID) } } -AnimationPath CTradeBase::CTradeableItem::getFilename() +AnimationPath CTradeableItem::getFilename() { switch(type) { @@ -95,7 +95,7 @@ AnimationPath CTradeBase::CTradeableItem::getFilename() } } -int CTradeBase::CTradeableItem::getIndex() +int CTradeableItem::getIndex() { if(id < 0) return -1; @@ -116,7 +116,7 @@ int CTradeBase::CTradeableItem::getIndex() } } -void CTradeBase::CTradeableItem::showAll(Canvas & to) +void CTradeableItem::showAll(Canvas & to) { Point posToBitmap; Point posToSubCenter; @@ -154,13 +154,13 @@ void CTradeBase::CTradeableItem::showAll(Canvas & to) to.drawText(pos.topLeft() + posToSubCenter, FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, subtitle); } -void CTradeBase::CTradeableItem::clickPressed(const Point& cursorPosition) +void CTradeableItem::clickPressed(const Point & cursorPosition) { if(clickPressedCallback) clickPressedCallback(shared_from_this()); } -void CTradeBase::CTradeableItem::showAllAt(const Point& dstPos, const std::string& customSub, Canvas& to) +void CTradeableItem::showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to) { Rect oldPos = pos; std::string oldSub = subtitle; @@ -175,7 +175,7 @@ void CTradeBase::CTradeableItem::showAllAt(const Point& dstPos, const std::strin subtitle = oldSub; } -void CTradeBase::CTradeableItem::hover(bool on) +void CTradeableItem::hover(bool on) { if(!on) { @@ -198,7 +198,7 @@ void CTradeBase::CTradeableItem::hover(bool on) } } -void CTradeBase::CTradeableItem::showPopupWindow(const Point& cursorPosition) +void CTradeableItem::showPopupWindow(const Point & cursorPosition) { switch(type) { @@ -214,7 +214,7 @@ void CTradeBase::CTradeableItem::showPopupWindow(const Point& cursorPosition) } } -std::string CTradeBase::CTradeableItem::getName(int number) const +std::string CTradeableItem::getName(int number) const { switch(type) { @@ -235,7 +235,7 @@ std::string CTradeBase::CTradeableItem::getName(int number) const return ""; } -const CArtifactInstance* CTradeBase::CTradeableItem::getArtInstance() const +const CArtifactInstance * CTradeableItem::getArtInstance() const { switch(type) { @@ -247,7 +247,7 @@ const CArtifactInstance* CTradeBase::CTradeableItem::getArtInstance() const } } -void CTradeBase::CTradeableItem::setArtInstance(const CArtifactInstance * art) +void CTradeableItem::setArtInstance(const CArtifactInstance * art) { assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE); hlp = art; @@ -257,6 +257,26 @@ void CTradeBase::CTradeableItem::setArtInstance(const CArtifactInstance * art) setID(-1); } +SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updatePanelFunctor updateSubtitles) + : updateSubtitles(updateSubtitles) +{ + assert(resourcesForTrade.size() == slotsPos.size()); + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + for(const auto & res : resourcesForTrade) + { + slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); + slots.back()->clickPressedCallback = clickPressedCallback; + slots.back()->pos.w = 69; slots.back()->pos.h = 66; + } +} + +void SResourcesPanel::updateSlots() +{ + if(updateSubtitles) + updateSubtitles(); +} + CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) : market(market) , hero(hero) diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index 75079fe0f..79e3313a5 100644 --- a/client/widgets/CTradeBase.h +++ b/client/widgets/CTradeBase.h @@ -23,52 +23,79 @@ VCMI_LIB_NAMESPACE_END class CButton; class CTextBox; +enum EType +{ + RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE +}; + +class CTradeableItem : public CIntObject, public std::enable_shared_from_this +{ + std::shared_ptr image; + AnimationPath getFilename(); + int getIndex(); +public: + using ClickPressedFunctor = std::function)>; + + const CArtifactInstance * hlp; //holds ptr to artifact instance id type artifact + EType type; + int id; + const int serial; + const bool left; + std::string subtitle; //empty if default + ClickPressedFunctor clickPressedCallback; + + void setType(EType newType); + void setID(int newID); + + const CArtifactInstance * getArtInstance() const; + void setArtInstance(const CArtifactInstance * art); + + CFunctionList callback; + bool downSelection; + + void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); + + void showPopupWindow(const Point & cursorPosition) override; + void hover(bool on) override; + void showAll(Canvas & to) override; + void clickPressed(const Point & cursorPosition) override; + std::string getName(int number = -1) const; + CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); +}; + +struct SResourcesPanel : public CIntObject +{ + using updatePanelFunctor = std::function; + + const std::vector resourcesForTrade = + { + GameResID::WOOD, GameResID::MERCURY, GameResID::ORE, + GameResID::SULFUR, GameResID::CRYSTAL, GameResID::GEMS, + GameResID::GOLD + }; + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 79), Point(83, 79), Point(166, 79), + Point(83, 158) + }; + std::vector> slots; + std::function updateSubtitles; + + SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updatePanelFunctor updateSubtitles); + void updateSlots(); +}; + class CTradeBase { public: - enum EType - { - RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE - }; - - class CTradeableItem : public CIntObject, public std::enable_shared_from_this - { - std::shared_ptr image; - AnimationPath getFilename(); - int getIndex(); - public: - const CArtifactInstance * hlp; //holds ptr to artifact instance id type artifact - EType type; - int id; - const int serial; - const bool left; - std::string subtitle; //empty if default - std::function altarSlot)> clickPressedCallback; - - void setType(EType newType); - void setID(int newID); - - const CArtifactInstance* getArtInstance() const; - void setArtInstance(const CArtifactInstance * art); - - CFunctionList callback; - bool downSelection; - - void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); - - void showPopupWindow(const Point & cursorPosition) override; - void hover(bool on) override; - void showAll(Canvas & to) override; - void clickPressed(const Point & cursorPosition) override; - std::string getName(int number = -1) const; - CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); - }; - const IMarket * market; const CGHeroInstance * hero; //all indexes: 1 = left, 0 = right std::array>, 2> items; + std::shared_ptr resoursesPanelPlayer; + std::shared_ptr resoursesPanelMarket; //highlighted items (nullptr if no highlight) std::shared_ptr hLeft; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index c27ec0775..77a7af5bc 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -84,6 +84,66 @@ void CTradeWindow::initItems(bool Left) } else { + if(Left && itemsType[1] == RESOURCE) + { + resoursesPanelPlayer = std::make_shared( + [this](std::shared_ptr marketSlot) -> void + { + if(hLeft != marketSlot) + hLeft = marketSlot; + else + return; + selectionChanged(true); + }, + [this]() -> void + { + for(auto & slot : resoursesPanelPlayer->slots) + slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(slot->serial))); + }); + resoursesPanelPlayer->moveBy(Point(39, 182)); + resoursesPanelPlayer->updateSlots(); + return; + } + if(!Left && itemsType[0] == RESOURCE) + { + resoursesPanelMarket = std::make_shared( + [this](std::shared_ptr marketSlot) -> void + { + if(hRight != marketSlot) + hRight = marketSlot; + else + return; + selectionChanged(false); + initSubs(false); + }, + [this]() -> void + { + for(auto & slot : resoursesPanelMarket->slots) + { + if(hLeft) //artifact, creature + { + int h1, h2; //hlp variables for getting offer + market->getOffer(hLeft->id, slot->id, h1, h2, mode); + if(slot->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources + { + std::ostringstream oss; + oss << h2; + if(h1 != 1) + oss << "/" << h1; + slot->subtitle = oss.str(); + } + else + slot->subtitle = CGI->generaltexth->allTexts[164]; // n/a + } + else + slot->subtitle = ""; + } + }); + resoursesPanelMarket->moveBy(Point(327, 182)); + return; + } + + std::vector *ids = getItemsIds(Left); std::vector pos; int amount = -1; @@ -185,14 +245,6 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ switch(type) { - case RESOURCE: - dx = 82; - dy = 79; - x = 39; - y = 180; - h = 68; - w = 70; - break; case PLAYER: dx = 83; dy = 118; @@ -244,6 +296,15 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ void CTradeWindow::initSubs(bool Left) { + if(itemsType[Left] == RESOURCE) + { + if(Left) + resoursesPanelPlayer->updateSlots(); + else + resoursesPanelMarket->updateSlots(); + return; + } + for(auto item : items[Left]) { if(Left) @@ -253,9 +314,6 @@ void CTradeWindow::initSubs(bool Left) case CREATURE: item->subtitle = std::to_string(hero->getStackCount(SlotID(item->serial))); break; - case RESOURCE: - item->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(item->serial))); - break; } } else //right side @@ -264,23 +322,6 @@ void CTradeWindow::initSubs(bool Left) { item->subtitle = CGI->generaltexth->capColors[item->id]; } - else if(hLeft)//artifact, creature - { - int h1, h2; //hlp variables for getting offer - market->getOffer(hLeft->id, item->id, h1, h2, mode); - if(item->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources - { - std::ostringstream oss; - oss << h2; - if(h1!=1) - oss << "/" << h1; - item->subtitle = oss.str(); - } - else - item->subtitle = CGI->generaltexth->allTexts[164]; // n/a - } - else - item->subtitle = ""; } } } From b246e24811c251e3698381365f5a545926217942 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 19 Nov 2023 19:49:59 +0200 Subject: [PATCH 2/9] reworking slot selection --- client/widgets/CArtifactHolder.cpp | 27 ++---------- client/widgets/CArtifactHolder.h | 6 +-- client/widgets/CArtifactsOfHeroMarket.cpp | 5 +++ client/widgets/CTradeBase.cpp | 8 ++++ client/widgets/CTradeBase.h | 4 +- client/widgets/MiscWidgets.cpp | 52 +++++++++++++++++++++-- client/widgets/MiscWidgets.h | 19 ++++++++- client/windows/CTradeWindow.cpp | 29 +++++++------ 8 files changed, 103 insertions(+), 47 deletions(-) diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index 544b6adff..14a90796d 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -75,13 +75,11 @@ void CArtPlace::setInternals(const CArtifactInstance * artInst) text = artInst->getDescription(); } -CArtPlace::CArtPlace(Point position, const CArtifactInstance * art) - : ourArt(art) +CArtPlace::CArtPlace(Point position, const CArtifactInstance * art) + : SelectableSlot(Rect(position, Point(44, 44)), Point(1, 1)) + , ourArt(art) , locked(false) { - pos += position; - pos.w = pos.h = 44; - OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); imageIndex = 0; @@ -92,9 +90,6 @@ CArtPlace::CArtPlace(Point position, const CArtifactInstance * art) image = std::make_shared(AnimationPath::builtin("artifact"), imageIndex); image->disable(); - - selection = std::make_shared(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION, 0, -1, -1); - selection->visible = false; } const CArtifactInstance * CArtPlace::getArt() @@ -170,16 +165,6 @@ bool CArtPlace::isLocked() const return locked; } -void CArtPlace::selectSlot(bool on) -{ - selection->visible = on; -} - -bool CArtPlace::isSelected() const -{ - return selection->visible; -} - void CArtPlace::clickPressed(const Point & cursorPosition) { if(clickPressedCallback) @@ -201,12 +186,6 @@ void CArtPlace::gesture(bool on, const Point & initialPosition, const Point & fi gestureCallback(*this, initialPosition); } -void CArtPlace::showAll(Canvas & to) -{ - CIntObject::showAll(to); - selection->showAll(to); -} - void CArtPlace::setArtifact(const CArtifactInstance * art) { setInternals(art); diff --git a/client/widgets/CArtifactHolder.h b/client/widgets/CArtifactHolder.h index fafc50e50..03baf60c4 100644 --- a/client/widgets/CArtifactHolder.h +++ b/client/widgets/CArtifactHolder.h @@ -29,7 +29,7 @@ public: virtual void artifactAssembled(const ArtifactLocation & artLoc)=0; }; -class CArtPlace : public LRClickableAreaWTextComp +class CArtPlace : public LRClickableAreaWTextComp, public SelectableSlot { public: using ClickFunctor = std::function; @@ -40,9 +40,6 @@ public: const CArtifactInstance * getArt(); void lockSlot(bool on); bool isLocked() const; - void selectSlot(bool on); - bool isSelected() const; - void showAll(Canvas & to) override; void setArtifact(const CArtifactInstance * art); void setClickPressedCallback(ClickFunctor callback); void setShowPopupCallback(ClickFunctor callback); @@ -55,7 +52,6 @@ protected: std::shared_ptr image; const CArtifactInstance * ourArt; int imageIndex; - std::shared_ptr selection; bool locked; ClickFunctor clickPressedCallback; ClickFunctor showPopupCallback; diff --git a/client/widgets/CArtifactsOfHeroMarket.cpp b/client/widgets/CArtifactsOfHeroMarket.cpp index 0f71aca12..90ddcde46 100644 --- a/client/widgets/CArtifactsOfHeroMarket.cpp +++ b/client/widgets/CArtifactsOfHeroMarket.cpp @@ -19,6 +19,11 @@ CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position) std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2), position, std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1)); + + for(auto slot : artWorn) + slot.second->selection->lineWidth = 2; + for(auto slot : backpack) + slot->selection->lineWidth = 2; }; void CArtifactsOfHeroMarket::scrollBackpack(int offset) diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index b195d6990..5bf473d44 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -9,6 +9,7 @@ */ #include "StdInc.h" #include "CTradeBase.h" +#include "MiscWidgets.h" #include "../gui/CGuiHandler.h" #include "../render/Canvas.h" @@ -268,6 +269,7 @@ SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPresse slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); slots.back()->clickPressedCallback = clickPressedCallback; slots.back()->pos.w = 69; slots.back()->pos.h = 66; + slots.back()->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions())); } } @@ -277,6 +279,12 @@ void SResourcesPanel::updateSlots() updateSubtitles(); } +void SResourcesPanel::deselect() +{ + for(auto & slot : slots) + slot->selection->selectSlot(false); +} + CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) : market(market) , hero(hero) diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index 79e3313a5..91237732e 100644 --- a/client/widgets/CTradeBase.h +++ b/client/widgets/CTradeBase.h @@ -17,6 +17,7 @@ VCMI_LIB_NAMESPACE_BEGIN class IMarket; class CGHeroInstance; +class SelectableSlot; VCMI_LIB_NAMESPACE_END @@ -50,7 +51,7 @@ public: const CArtifactInstance * getArtInstance() const; void setArtInstance(const CArtifactInstance * art); - CFunctionList callback; + std::unique_ptr selection; bool downSelection; void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); @@ -84,6 +85,7 @@ struct SResourcesPanel : public CIntObject SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updatePanelFunctor updateSubtitles); void updateSlots(); + void deselect(); }; class CTradeBase diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index c985e35e6..391304bd1 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -662,22 +662,37 @@ void CCreaturePic::setAmount(int newAmount) } TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color) : - color(color), colorLine(ColorRGBA()), drawLine(false) + color(color), colorLine(ColorRGBA()), drawLine(false), lineWidth(0) { pos = position + pos.topLeft(); } -TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine) : - color(color), colorLine(colorLine), drawLine(true) +TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine, int width) : + color(color), colorLine(colorLine), drawLine(true), lineWidth(width) { pos = position + pos.topLeft(); } +void TransparentFilledRectangle::setDrawBorder(bool on) +{ + drawLine = on; +} + +bool TransparentFilledRectangle::getDrawBorder() +{ + return drawLine; +} + +void TransparentFilledRectangle::setBorderWidth(int width) +{ + lineWidth = width; +} + void TransparentFilledRectangle::showAll(Canvas & to) { to.drawColorBlended(pos, color); if(drawLine) - to.drawBorder(pos, colorLine); + to.drawBorder(pos, colorLine, lineWidth); } SimpleLine::SimpleLine(Point pos1, Point pos2, ColorRGBA color) : @@ -688,3 +703,32 @@ void SimpleLine::showAll(Canvas & to) { to.drawLine(pos1 + pos.topLeft(), pos2 + pos.topLeft(), color, color); } + +SelectableSlot::SelectableSlot(Rect area, Point oversize, const int width) +{ + pos += area.topLeft(); + pos.w = area.w; pos.h = area.h; + selection = std::make_unique( + Rect(area.topLeft() - oversize, area.dimensions() + oversize * 2), Colors::TRANSPARENCY, Colors::YELLOW, width); + selectSlot(false); +} + +SelectableSlot::SelectableSlot(Rect area, Point oversize) + : SelectableSlot(area, oversize, 1) +{ +} + +SelectableSlot::SelectableSlot(Rect area, const int width) + : SelectableSlot(area, Point(), width) +{ +} + +void SelectableSlot::selectSlot(bool on) +{ + selection->setDrawBorder(on); +} + +bool SelectableSlot::isSelected() const +{ + return selection->getDrawBorder(); +} diff --git a/client/widgets/MiscWidgets.h b/client/widgets/MiscWidgets.h index 59a1004dd..11172a4c5 100644 --- a/client/widgets/MiscWidgets.h +++ b/client/widgets/MiscWidgets.h @@ -252,9 +252,14 @@ class TransparentFilledRectangle : public CIntObject ColorRGBA color; ColorRGBA colorLine; bool drawLine; + int lineWidth; + public: TransparentFilledRectangle(Rect position, ColorRGBA color); - TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine); + TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine, int width = 1); + void setDrawBorder(bool on); + bool getDrawBorder(); + void setBorderWidth(int width); void showAll(Canvas & to) override; }; @@ -267,3 +272,15 @@ public: SimpleLine(Point pos1, Point pos2, ColorRGBA color); void showAll(Canvas & to) override; }; + +class SelectableSlot : virtual public CIntObject +{ +public: + std::unique_ptr selection; + + SelectableSlot(Rect area, Point oversize, const int width); + SelectableSlot(Rect area, Point oversize); + SelectableSlot(Rect area, const int width = 1); + void selectSlot(bool on); + bool isSelected() const; +}; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 77a7af5bc..d6f3d4ec9 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -90,10 +90,13 @@ void CTradeWindow::initItems(bool Left) [this](std::shared_ptr marketSlot) -> void { if(hLeft != marketSlot) + { + if(hLeft) + hLeft->selection->selectSlot(false); hLeft = marketSlot; - else - return; - selectionChanged(true); + hLeft->selection->selectSlot(true); + selectionChanged(true); + } }, [this]() -> void { @@ -110,11 +113,14 @@ void CTradeWindow::initItems(bool Left) [this](std::shared_ptr marketSlot) -> void { if(hRight != marketSlot) + { + if(hRight) + hRight->selection->selectSlot(false); hRight = marketSlot; - else - return; - selectionChanged(false); - initSubs(false); + hRight->selection->selectSlot(true); + selectionChanged(false); + initSubs(false); + } }, [this]() -> void { @@ -330,11 +336,6 @@ void CTradeWindow::showAll(Canvas & to) { CWindowObject::showAll(to); - if(hRight) - to.drawBorder(Rect::createAround(hRight->pos, 1), Colors::BRIGHT_YELLOW, 2); - if(hLeft && hLeft->type != ARTIFACT_INSTANCE) - to.drawBorder(Rect::createAround(hLeft->pos, 1), Colors::BRIGHT_YELLOW, 2); - if(readyToTrade) { if(hLeft) @@ -589,6 +590,10 @@ void CMarketplaceWindow::makeDeal() madeTransaction = true; hLeft = nullptr; hRight = nullptr; + if(resoursesPanelPlayer) + resoursesPanelPlayer->deselect(); + if(resoursesPanelMarket) + resoursesPanelMarket->deselect(); selectionChanged(true); } From f043c417a1599d3e9d8980f4c74802bb27096f02 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 20 Nov 2023 00:37:43 +0200 Subject: [PATCH 3/9] Artifacts trade panel --- client/widgets/CTradeBase.cpp | 50 ++++++++++++++--- client/widgets/CTradeBase.h | 42 ++++++++++---- client/windows/CTradeWindow.cpp | 98 +++++++++++++++++---------------- 3 files changed, 125 insertions(+), 65 deletions(-) diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index 5bf473d44..99b225073 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -258,8 +258,32 @@ void CTradeableItem::setArtInstance(const CArtifactInstance * art) setID(-1); } -SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updatePanelFunctor updateSubtitles) - : updateSubtitles(updateSubtitles) +void STradePanel::updateSlots() +{ + if(updateSlotsCallback) + updateSlotsCallback(); +} + +void STradePanel::deselect() +{ + for(auto & slot : slots) + slot->selection->selectSlot(false); +} + +void STradePanel::clearSubtitles() +{ + for(auto & slot : slots) + slot->subtitle.clear(); +} + +void STradePanel::updateOffer(int slotIdx, int cost, int qty) +{ + slots[slotIdx]->subtitle = std::to_string(qty); + if(cost != 1) + slots[slotIdx]->subtitle += "/" + std::to_string(cost); +} + +SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles) { assert(resourcesForTrade.size() == slotsPos.size()); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); @@ -271,18 +295,26 @@ SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPresse slots.back()->pos.w = 69; slots.back()->pos.h = 66; slots.back()->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions())); } + updateSlotsCallback = updateSubtitles; } -void SResourcesPanel::updateSlots() +SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles, + std::vector & arts) { - if(updateSubtitles) - updateSubtitles(); -} + assert(artifactsForTrade == slotsPos.size()); + assert(artifactsForTrade == arts.size()); + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); -void SResourcesPanel::deselect() -{ + slots.resize(artifactsForTrade); + int slotNum = 0; for(auto & slot : slots) - slot->selection->selectSlot(false); + { + slot = std::make_shared(slotsPos[slotNum], EType::ARTIFACT_TYPE, arts[slotNum].getNum(), false, slotNum); + slot->clickPressedCallback = clickPressedCallback; + slot->pos.w = slot->pos.h = 44; + slot->selection = std::make_unique(Rect(slotsPos[slotNum++], slot->pos.dimensions())); + } + updateSlotsCallback = updateSubtitles; } CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index 91237732e..4a7374126 100644 --- a/client/widgets/CTradeBase.h +++ b/client/widgets/CTradeBase.h @@ -11,7 +11,8 @@ #include "Images.h" -#include "../../lib/FunctionList.h" +#include "../lib/FunctionList.h" +#include "../lib/networkPacks/TradeItem.h" VCMI_LIB_NAMESPACE_BEGIN @@ -64,10 +65,22 @@ public: CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); }; -struct SResourcesPanel : public CIntObject +struct STradePanel : public CIntObject { - using updatePanelFunctor = std::function; + using updateSlotsFunctor = std::function; + std::vector> slots; + std::function updateSlotsCallback; + std::shared_ptr selected; + + virtual void updateSlots(); + virtual void deselect(); + virtual void clearSubtitles(); + void updateOffer(int slotIdx, int, int); +}; + +struct SResourcesPanel : public STradePanel +{ const std::vector resourcesForTrade = { GameResID::WOOD, GameResID::MERCURY, GameResID::ORE, @@ -80,12 +93,22 @@ struct SResourcesPanel : public CIntObject Point(0, 79), Point(83, 79), Point(166, 79), Point(83, 158) }; - std::vector> slots; - std::function updateSubtitles; - SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updatePanelFunctor updateSubtitles); - void updateSlots(); - void deselect(); + SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles); +}; + +struct SArtifactsPanel : public STradePanel +{ + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 79), Point(83, 79), Point(166, 79), + Point(83, 158) + }; + const size_t artifactsForTrade = 7; + + SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles, + std::vector & arts); }; class CTradeBase @@ -96,8 +119,7 @@ public: //all indexes: 1 = left, 0 = right std::array>, 2> items; - std::shared_ptr resoursesPanelPlayer; - std::shared_ptr resoursesPanelMarket; + std::vector> tradePanels; //highlighted items (nullptr if no highlight) std::shared_ptr hLeft; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index d6f3d4ec9..4b927b495 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -86,7 +86,7 @@ void CTradeWindow::initItems(bool Left) { if(Left && itemsType[1] == RESOURCE) { - resoursesPanelPlayer = std::make_shared( + tradePanels.emplace_back(std::make_shared( [this](std::shared_ptr marketSlot) -> void { if(hLeft != marketSlot) @@ -97,19 +97,19 @@ void CTradeWindow::initItems(bool Left) hLeft->selection->selectSlot(true); selectionChanged(true); } - }, + }, [this]() -> void { - for(auto & slot : resoursesPanelPlayer->slots) + for(auto & slot : tradePanels[1]->slots) slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(slot->serial))); - }); - resoursesPanelPlayer->moveBy(Point(39, 182)); - resoursesPanelPlayer->updateSlots(); + })); + tradePanels.back()->moveBy(Point(39, 182)); + tradePanels.back()->updateSlots(); return; } if(!Left && itemsType[0] == RESOURCE) { - resoursesPanelMarket = std::make_shared( + tradePanels.emplace_back(std::make_shared( [this](std::shared_ptr marketSlot) -> void { if(hRight != marketSlot) @@ -124,31 +124,53 @@ void CTradeWindow::initItems(bool Left) }, [this]() -> void { - for(auto & slot : resoursesPanelMarket->slots) - { - if(hLeft) //artifact, creature + if(hLeft) + for(auto & slot : tradePanels[0]->slots) { int h1, h2; //hlp variables for getting offer - market->getOffer(hLeft->id, slot->id, h1, h2, mode); - if(slot->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources - { - std::ostringstream oss; - oss << h2; - if(h1 != 1) - oss << "/" << h1; - slot->subtitle = oss.str(); - } + market->getOffer(hLeft->id, slot->id, h1, h2, EMarketMode::RESOURCE_RESOURCE); + + if(slot->id != hLeft->id) + tradePanels[0]->updateOffer(slot->serial, h1, h2); else slot->subtitle = CGI->generaltexth->allTexts[164]; // n/a } - else - slot->subtitle = ""; - } - }); - resoursesPanelMarket->moveBy(Point(327, 182)); + else + tradePanels[0]->clearSubtitles(); + })); + tradePanels.back()->moveBy(Point(327, 182)); + return; + } + if(!Left && itemsType[0] == ARTIFACT_TYPE) + { + tradePanels.emplace_back(std::make_shared( + [this](std::shared_ptr marketSlot) -> void + { + if(hRight != marketSlot) + { + if(hRight) + hRight->selection->selectSlot(false); + hRight = marketSlot; + hRight->selection->selectSlot(true); + selectionChanged(false); + initSubs(false); + } + }, + [this]() -> void + { + if(hLeft) + for(auto & slot : tradePanels[0]->slots) + { + int h1, h2; //hlp variables for getting offer + market->getOffer(hLeft->id, slot->id, h1, h2, EMarketMode::RESOURCE_ARTIFACT); + tradePanels[0]->updateOffer(slot->serial, h1, h2); + } + else + tradePanels[0]->clearSubtitles(); + }, market->availableItemsIds(mode))); + tradePanels.back()->moveBy(Point(340, 182)); return; } - std::vector *ids = getItemsIds(Left); std::vector pos; @@ -229,12 +251,6 @@ std::vector *CTradeWindow::getItemsIds(bool Left) if(PlayerColor(i) != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(PlayerColor(i)) == EPlayerStatus::INGAME) ids->push_back(i); break; - - case ARTIFACT_TYPE: - ids = new std::vector; - for (auto const & item : market->availableItemsIds(mode)) - ids->push_back(item.getNum()); - break; } } @@ -269,14 +285,6 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ dy = 98; assert(Left); break; - case ARTIFACT_TYPE://45,123 - x = 340 - 289; - y = 180; - w = 44; - h = 44; - dx = 83; - dy = 79; - break; } int leftToRightOffset = 289; @@ -302,12 +310,12 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ void CTradeWindow::initSubs(bool Left) { - if(itemsType[Left] == RESOURCE) + if(itemsType[Left] == RESOURCE || itemsType[Left] == ARTIFACT_TYPE) { if(Left) - resoursesPanelPlayer->updateSlots(); + tradePanels[1]->updateSlots(); else - resoursesPanelMarket->updateSlots(); + tradePanels[0]->updateSlots(); return; } @@ -590,10 +598,8 @@ void CMarketplaceWindow::makeDeal() madeTransaction = true; hLeft = nullptr; hRight = nullptr; - if(resoursesPanelPlayer) - resoursesPanelPlayer->deselect(); - if(resoursesPanelMarket) - resoursesPanelMarket->deselect(); + for(auto & panel : tradePanels) + panel->deselect(); selectionChanged(true); } From 791ee78cc4acf7190760e9e72e449c62891d5950 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:01:53 +0200 Subject: [PATCH 4/9] players trade panel --- client/widgets/CTradeBase.cpp | 42 ++++++-- client/widgets/CTradeBase.h | 14 ++- client/windows/CTradeWindow.cpp | 178 +++++++++++++------------------- 3 files changed, 122 insertions(+), 112 deletions(-) diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index 99b225073..46283ac44 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -17,6 +17,9 @@ #include "../windows/InfoWindows.h" #include "../CGameInfo.h" +#include "../CPlayerInterface.h" + +#include "../../CCallback.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" @@ -126,23 +129,24 @@ void CTradeableItem::showAll(Canvas & to) { case RESOURCE: posToBitmap = Point(19, 9); - posToSubCenter = Point(36, 59); + posToSubCenter = Point(35, 57); break; case CREATURE_PLACEHOLDER: case CREATURE: posToSubCenter = Point(29, 77); break; case PLAYER: - posToSubCenter = Point(31, 76); + posToSubCenter = Point(31, 77); break; case ARTIFACT_PLACEHOLDER: case ARTIFACT_INSTANCE: - posToSubCenter = Point(19, 54); + posToSubCenter = Point(22, 51); if (downSelection) posToSubCenter.y += 8; break; case ARTIFACT_TYPE: - posToSubCenter = Point(19, 58); + posToSubCenter = Point(35, 57); + posToBitmap = Point(13, 0); break; } @@ -293,7 +297,8 @@ SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPresse slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); slots.back()->clickPressedCallback = clickPressedCallback; slots.back()->pos.w = 69; slots.back()->pos.h = 66; - slots.back()->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions())); + slots.back()->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions()), + Point(1, 1), selectionWidth); } updateSlotsCallback = updateSubtitles; } @@ -311,12 +316,35 @@ SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPresse { slot = std::make_shared(slotsPos[slotNum], EType::ARTIFACT_TYPE, arts[slotNum].getNum(), false, slotNum); slot->clickPressedCallback = clickPressedCallback; - slot->pos.w = slot->pos.h = 44; - slot->selection = std::make_unique(Rect(slotsPos[slotNum++], slot->pos.dimensions())); + slot->pos.w = 69; slot->pos.h = 66; + slot->selection = std::make_unique(Rect(slotsPos[slotNum++], slot->pos.dimensions()), Point(1, 1), selectionWidth); } updateSlotsCallback = updateSubtitles; } +SPlayersPanel::SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback) +{ + assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size()); + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + std::vector players; + for(auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT_I; player++) + { + if(player != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(player) == EPlayerStatus::INGAME) + players.emplace_back(player); + } + + slots.resize(players.size()); + int slotNum = 0; + for(auto & slot : slots) + { + slot = std::make_shared(slotsPos[slotNum], EType::PLAYER, players[slotNum].num, false, slotNum); + slot->clickPressedCallback = clickPressedCallback; + slot->selection = std::make_unique(Rect(slotsPos[slotNum], slot->pos.dimensions()), Point(1, 1), selectionWidth); + slot->subtitle = CGI->generaltexth->capColors[players[slotNum++].num]; + } +} + CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) : market(market) , hero(hero) diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index 4a7374126..79f690307 100644 --- a/client/widgets/CTradeBase.h +++ b/client/widgets/CTradeBase.h @@ -72,6 +72,7 @@ struct STradePanel : public CIntObject std::vector> slots; std::function updateSlotsCallback; std::shared_ptr selected; + const int selectionWidth = 2; virtual void updateSlots(); virtual void deselect(); @@ -111,6 +112,17 @@ struct SArtifactsPanel : public STradePanel std::vector & arts); }; +struct SPlayersPanel : public STradePanel +{ + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 118), Point(83, 118), Point(166, 118), + Point(83, 236) + }; + SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback); +}; + class CTradeBase { public: @@ -119,7 +131,7 @@ public: //all indexes: 1 = left, 0 = right std::array>, 2> items; - std::vector> tradePanels; + std::shared_ptr leftTradePanel, rightTradePanel; //highlighted items (nullptr if no highlight) std::shared_ptr hLeft; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 4b927b495..bb5e4034b 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -84,91 +84,75 @@ void CTradeWindow::initItems(bool Left) } else { - if(Left && itemsType[1] == RESOURCE) + auto updRightSub = [this](EMarketMode mode) -> void { - tradePanels.emplace_back(std::make_shared( - [this](std::shared_ptr marketSlot) -> void + if(hLeft) + for(auto & slot : rightTradePanel->slots) { - if(hLeft != marketSlot) - { - if(hLeft) - hLeft->selection->selectSlot(false); - hLeft = marketSlot; - hLeft->selection->selectSlot(true); - selectionChanged(true); - } - }, - [this]() -> void - { - for(auto & slot : tradePanels[1]->slots) - slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(slot->serial))); - })); - tradePanels.back()->moveBy(Point(39, 182)); - tradePanels.back()->updateSlots(); - return; - } - if(!Left && itemsType[0] == RESOURCE) - { - tradePanels.emplace_back(std::make_shared( - [this](std::shared_ptr marketSlot) -> void - { - if(hRight != marketSlot) - { - if(hRight) - hRight->selection->selectSlot(false); - hRight = marketSlot; - hRight->selection->selectSlot(true); - selectionChanged(false); - initSubs(false); - } - }, - [this]() -> void - { - if(hLeft) - for(auto & slot : tradePanels[0]->slots) - { - int h1, h2; //hlp variables for getting offer - market->getOffer(hLeft->id, slot->id, h1, h2, EMarketMode::RESOURCE_RESOURCE); + int h1, h2; //hlp variables for getting offer + market->getOffer(hLeft->id, slot->id, h1, h2, mode); - if(slot->id != hLeft->id) - tradePanels[0]->updateOffer(slot->serial, h1, h2); - else - slot->subtitle = CGI->generaltexth->allTexts[164]; // n/a - } - else - tradePanels[0]->clearSubtitles(); - })); - tradePanels.back()->moveBy(Point(327, 182)); - return; - } - if(!Left && itemsType[0] == ARTIFACT_TYPE) + rightTradePanel->updateOffer(slot->serial, h1, h2); + } + else + rightTradePanel->clearSubtitles(); + }; + + auto clickPressedTradePanel = [this](std::shared_ptr newSlot, bool left) { - tradePanels.emplace_back(std::make_shared( - [this](std::shared_ptr marketSlot) -> void - { - if(hRight != marketSlot) - { - if(hRight) - hRight->selection->selectSlot(false); - hRight = marketSlot; - hRight->selection->selectSlot(true); - selectionChanged(false); - initSubs(false); - } - }, + auto * selectedSlot = &hRight; + if(left) + selectedSlot = &hLeft; + + if(*selectedSlot) + (*selectedSlot)->selection->selectSlot(false); + *selectedSlot = newSlot; + newSlot->selection->selectSlot(true); + selectionChanged(left); + }; + + if(Left && (mode == EMarketMode::RESOURCE_RESOURCE || mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER)) + { + leftTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, true), [this]() -> void { + for(auto & slot : leftTradePanel->slots) + slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(slot->serial))); + }); + leftTradePanel->moveBy(Point(39, 182)); + leftTradePanel->updateSlots(); + return; + } + if(!Left && mode == EMarketMode::RESOURCE_RESOURCE) + { + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), + [this, updRightSub]() -> void + { + updRightSub(EMarketMode::RESOURCE_RESOURCE); if(hLeft) - for(auto & slot : tradePanels[0]->slots) - { - int h1, h2; //hlp variables for getting offer - market->getOffer(hLeft->id, slot->id, h1, h2, EMarketMode::RESOURCE_ARTIFACT); - tradePanels[0]->updateOffer(slot->serial, h1, h2); - } - else - tradePanels[0]->clearSubtitles(); - }, market->availableItemsIds(mode))); - tradePanels.back()->moveBy(Point(340, 182)); + rightTradePanel->slots[hLeft->serial]->subtitle = CGI->generaltexth->allTexts[164]; // n/a + }); + rightTradePanel->moveBy(Point(327, 181)); + return; + } + if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE || mode == EMarketMode::CREATURE_RESOURCE)) + { + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), + std::bind(updRightSub, EMarketMode::ARTIFACT_RESOURCE)); + rightTradePanel->moveBy(Point(327, 181)); + return; + } + if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT) + { + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), + std::bind(updRightSub, EMarketMode::RESOURCE_ARTIFACT), market->availableItemsIds(mode)); + rightTradePanel->moveBy(Point(327, 181)); + return; + } + if(!Left && mode == EMarketMode::RESOURCE_PLAYER) + { + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false)); + rightTradePanel->moveBy(Point(333, 83)); return; } @@ -267,15 +251,6 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ switch(type) { - case PLAYER: - dx = 83; - dy = 118; - h = 64; - w = 58; - x = 44; - y = 83; - assert(!Left); - break; case CREATURE://45,123 x = 45; y = 123; @@ -313,9 +288,9 @@ void CTradeWindow::initSubs(bool Left) if(itemsType[Left] == RESOURCE || itemsType[Left] == ARTIFACT_TYPE) { if(Left) - tradePanels[1]->updateSlots(); + leftTradePanel->updateSlots(); else - tradePanels[0]->updateSlots(); + rightTradePanel->updateSlots(); return; } @@ -330,13 +305,6 @@ void CTradeWindow::initSubs(bool Left) break; } } - else //right side - { - if(itemsType[0] == PLAYER) - { - item->subtitle = CGI->generaltexth->capColors[item->id]; - } - } } } @@ -598,8 +566,10 @@ void CMarketplaceWindow::makeDeal() madeTransaction = true; hLeft = nullptr; hRight = nullptr; - for(auto & panel : tradePanels) - panel->deselect(); + if(leftTradePanel) + leftTradePanel->deselect(); + assert(rightTradePanel); + rightTradePanel->deselect(); selectionChanged(true); } @@ -760,11 +730,11 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const switch(itemsType[1]) { case RESOURCE: - return Point(122, 446); + return Point(122, 448); case CREATURE: return Point(128, 450); case ARTIFACT_INSTANCE: - return Point(134, 466); + return Point(134, 469); } } else @@ -772,12 +742,12 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const switch(itemsType[0]) { case RESOURCE: - if(mode == EMarketMode::ARTIFACT_RESOURCE) - return Point(410, 469); + if(mode == EMarketMode::ARTIFACT_RESOURCE) + return Point(410, 471); else - return Point(410, 446); + return Point(410, 448); case ARTIFACT_TYPE: - return Point(425, 447); + return Point(411, 449); case PLAYER: return Point(417, 451); } From 50a5c72d1b7162d0136339db792131d4395ef796 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 3 Dec 2023 17:08:30 +0200 Subject: [PATCH 5/9] Creatures trade panel --- client/widgets/CAltar.cpp | 88 +++++++------- client/widgets/CAltar.h | 18 +-- client/widgets/CTradeBase.cpp | 69 +++++++---- client/widgets/CTradeBase.h | 28 ++++- client/windows/CAltarWindow.cpp | 4 +- client/windows/CTradeWindow.cpp | 199 +++++--------------------------- client/windows/CTradeWindow.h | 2 - 7 files changed, 154 insertions(+), 254 deletions(-) diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp index a21766618..175857144 100644 --- a/client/widgets/CAltar.cpp +++ b/client/widgets/CAltar.cpp @@ -44,6 +44,10 @@ CAltar::CAltar(const IMarket * market, const CGHeroInstance * hero) void CAltar::deselect() { + if(hLeft) + hLeft->selection->selectSlot(false); + if(hRight) + hRight->selection->selectSlot(false); hLeft = hRight = nullptr; deal->block(true); } @@ -251,35 +255,36 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltar::sacrificeAll, this)); // Creating slots for hero creatures - for(int slotIdx = 0; slotIdx < GameConstants::ARMY_SIZE; slotIdx++) + SCreaturesPanel::slotsData slots; + for(auto slotId = SlotID(0); slotId.num < GameConstants::ARMY_SIZE; slotId++) { - CreatureID creatureId = CreatureID::NONE; - if(const auto & creature = hero->getCreature(SlotID(slotIdx))) - creatureId = creature->getId(); - else - continue; - - auto heroSlot = std::make_shared(posSlotsHero[slotIdx], EType::CREATURE, creatureId.num, true, slotIdx); - heroSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void - { - onSlotClickPressed(altarSlot, items[0], hLeft, hRight); - }; - heroSlot->subtitle = std::to_string(hero->getStackCount(SlotID(slotIdx))); - items[1].emplace_back(heroSlot); + if(const auto & creature = hero->getCreature(slotId)) + slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId))); } + leftTradePanel = std::make_shared([this](std::shared_ptr altarSlot) -> void + { + onSlotClickPressed(altarSlot, rightTradePanel, hLeft, hRight); + }, slots); + 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))); + }; // Creating slots for creatures on altar - assert(items[1].size() <= posSlotsAltar.size()); - for(const auto & heroSlot : items[1]) - { - auto altarSlot = std::make_shared(posSlotsAltar[heroSlot->serial], EType::CREATURE_PLACEHOLDER, heroSlot->id, false, heroSlot->serial); - altarSlot->pos.w = heroSlot->pos.w; altarSlot->pos.h = heroSlot->pos.h; - altarSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void - { - onSlotClickPressed(altarSlot, items[1], hRight, hLeft); - }; - items[0].emplace_back(altarSlot); - } + for(auto & slot : slots) + std::get<2>(slot) = 0; + rightTradePanel = std::make_shared([this](std::shared_ptr altarSlot) -> void + { + onSlotClickPressed(altarSlot, leftTradePanel, hRight, hLeft); + }, slots); + rightTradePanel->moveBy(Point(334, 110)); + + leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = [this](std::shared_ptr & slot) -> bool + { + return this->hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false; + }; readExpValues(); calcExpAltarForHero(); @@ -289,7 +294,7 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * void CAltarCreatures::readExpValues() { int dump; - for(auto heroSlot : items[1]) + for(auto heroSlot : leftTradePanel->slots) { if(heroSlot->id >= 0) market->getOffer(heroSlot->id, 0, dump, expPerUnit[heroSlot->serial], EMarketMode::CREATURE_EXP); @@ -340,14 +345,13 @@ void CAltarCreatures::updateSubtitlesForSelected() rSubtitle->setText(""); } -void CAltarCreatures::updateGarrison() +void CAltarCreatures::updateSlots() { - std::set> empty; - getEmptySlots(empty); - removeItems(empty); + rightTradePanel->deleteSlots(); + leftTradePanel->deleteSlots(); + assert(leftTradePanel->slots.size() == rightTradePanel->slots.size()); readExpValues(); - for(auto & heroSlot : items[1]) - heroSlot->subtitle = std::to_string(hero->getStackCount(SlotID(heroSlot->serial))); + leftTradePanel->updateSlots(); } void CAltarCreatures::deselect() @@ -392,17 +396,17 @@ void CAltarCreatures::makeDeal() for(int & units : unitsOnAltar) units = 0; - for(auto heroSlot : items[0]) + for(auto heroSlot : rightTradePanel->slots) { heroSlot->setType(CREATURE_PLACEHOLDER); - heroSlot->subtitle = ""; + heroSlot->subtitle.clear(); } } void CAltarCreatures::sacrificeAll() { std::optional lastSlot; - for(auto heroSlot : items[1]) + for(auto heroSlot : leftTradePanel->slots) { auto stackCount = hero->getStackCount(SlotID(heroSlot->serial)); if(stackCount > unitsOnAltar[heroSlot->serial]) @@ -417,7 +421,7 @@ void CAltarCreatures::sacrificeAll() if(hRight) unitsSlider->scrollTo(unitsOnAltar[hRight->serial]); - for(auto altarSlot : items[0]) + for(auto altarSlot : rightTradePanel->slots) updateAltarSlot(altarSlot); updateSubtitlesForSelected(); @@ -443,18 +447,21 @@ void CAltarCreatures::onUnitsSliderMoved(int newVal) updateSubtitlesForSelected(); } -void CAltarCreatures::onSlotClickPressed(std::shared_ptr altarSlot, - std::vector> & oppositeSlots, +void CAltarCreatures::onSlotClickPressed(std::shared_ptr altarSlot, std::shared_ptr & oppositePanel, std::shared_ptr & hCurSide, std::shared_ptr & hOppSide) { std::shared_ptr oppositeSlot; - for(const auto & slot : oppositeSlots) + for(const auto & slot : oppositePanel->slots) if(slot->serial == altarSlot->serial) { oppositeSlot = slot; break; } + if(hCurSide) + hCurSide->selection->selectSlot(false); + if(hOppSide) + hOppSide->selection->selectSlot(false); if(hCurSide != altarSlot && oppositeSlot) { hCurSide = altarSlot; @@ -463,4 +470,7 @@ void CAltarCreatures::onSlotClickPressed(std::shared_ptr altarSl updateSubtitlesForSelected(); redraw(); } + hCurSide->selection->selectSlot(true); + hOppSide->selection->selectSlot(true); + redraw(); } diff --git a/client/widgets/CAltar.h b/client/widgets/CAltar.h index 685afa731..e0d39ca94 100644 --- a/client/widgets/CAltar.h +++ b/client/widgets/CAltar.h @@ -66,7 +66,7 @@ class CAltarCreatures : public CAltar { public: CAltarCreatures(const IMarket * market, const CGHeroInstance * hero); - void updateGarrison(); + void updateSlots(); void deselect() override; TExpType calcExpAltarForHero() override; void makeDeal() override; @@ -80,24 +80,10 @@ private: std::vector expPerUnit; std::shared_ptr lSubtitle, rSubtitle; - const std::vector posSlotsAltar = - { - Point(334, 110), Point(417, 110), Point(500, 110), - Point(334, 208), Point(417, 208), Point(500, 208), - Point(417, 306) - }; - const std::vector posSlotsHero = - { - Point(45, 110), Point(128, 110), Point(211, 110), - Point(45, 208), Point(128, 208), Point(211, 208), - Point(128, 306) - }; - void readExpValues(); void updateControls(); void updateSubtitlesForSelected(); void onUnitsSliderMoved(int newVal); - void onSlotClickPressed(std::shared_ptr altarSlot, - std::vector> & oppositeSlots, + void onSlotClickPressed(std::shared_ptr altarSlot, std::shared_ptr & oppositePanel, std::shared_ptr & hCurSide, std::shared_ptr & hOppSide); }; diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index 46283ac44..18ba7e939 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -280,44 +280,51 @@ void STradePanel::clearSubtitles() slot->subtitle.clear(); } -void STradePanel::updateOffer(int slotIdx, int cost, int qty) +void STradePanel::updateOffer(CTradeableItem & slot, int cost, int qty) { - slots[slotIdx]->subtitle = std::to_string(qty); + slot.subtitle = std::to_string(qty); if(cost != 1) - slots[slotIdx]->subtitle += "/" + std::to_string(cost); + slot.subtitle += "/" + std::to_string(cost); } -SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles) +void STradePanel::deleteSlots() +{ + if(deleteSlotsCheck) + slots.erase(std::remove_if(slots.begin(), slots.end(), deleteSlotsCheck), slots.end()); +} + +SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles) { assert(resourcesForTrade.size() == slotsPos.size()); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); for(const auto & res : resourcesForTrade) { - slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); - slots.back()->clickPressedCallback = clickPressedCallback; - slots.back()->pos.w = 69; slots.back()->pos.h = 66; - slots.back()->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions()), - Point(1, 1), selectionWidth); + auto slot = slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); + slot->clickPressedCallback = clickPressedCallback; + slot->pos.w = 69; slots.back()->pos.h = 66; + slot->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions()), Point(1, 1), selectionWidth); } updateSlotsCallback = updateSubtitles; } -SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles, +SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, std::vector & arts) { - assert(artifactsForTrade == slotsPos.size()); - assert(artifactsForTrade == arts.size()); + assert(slotsForTrade == slotsPos.size()); + assert(slotsForTrade == arts.size()); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); - slots.resize(artifactsForTrade); - int slotNum = 0; - for(auto & slot : slots) + for(auto slotIdx = 0; slotIdx < slotsForTrade; slotIdx++) { - slot = std::make_shared(slotsPos[slotNum], EType::ARTIFACT_TYPE, arts[slotNum].getNum(), false, slotNum); - slot->clickPressedCallback = clickPressedCallback; - slot->pos.w = 69; slot->pos.h = 66; - slot->selection = std::make_unique(Rect(slotsPos[slotNum++], slot->pos.dimensions()), Point(1, 1), selectionWidth); + auto artType = arts[slotIdx].getNum(); + if(artType != ArtifactID::NONE) + { + auto slot = slots.emplace_back(std::make_shared(slotsPos[slotIdx], EType::ARTIFACT_TYPE, artType, false, slotIdx)); + slot->clickPressedCallback = clickPressedCallback; + slot->pos.w = 69; slot->pos.h = 66; + slot->selection = std::make_unique(Rect(slotsPos[slotIdx], slot->pos.dimensions()), Point(1, 1), selectionWidth); + } } updateSlotsCallback = updateSubtitles; } @@ -345,6 +352,26 @@ SPlayersPanel::SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCal } } +SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, slotsData & initialSlots) +{ + assert(initialSlots.size() <= GameConstants::ARMY_SIZE); + assert(slotsPos.size() <= GameConstants::ARMY_SIZE); + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + for(const auto & slotData : initialSlots) + { + auto slotId = std::get<1>(slotData); + auto creaturesNum = std::get<2>(slotData); + auto slot = slots.emplace_back(std::make_shared(slotsPos[slotId.num], + creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, std::get<0>(slotData).num, true, slotId)); + 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(Rect(slotsPos[slotId.num], slots.back()->pos.dimensions()), Point(1, 1), selectionWidth); + } +} + CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) : market(market) , hero(hero) @@ -359,7 +386,7 @@ void CTradeBase::removeItems(const std::set> & t void CTradeBase::removeItem(std::shared_ptr item) { - items[item->left] -= item; + rightTradePanel->slots.erase(std::remove(rightTradePanel->slots.begin(), rightTradePanel->slots.end(), item)); if(hRight == item) hRight.reset(); @@ -367,7 +394,7 @@ void CTradeBase::removeItem(std::shared_ptr item) void CTradeBase::getEmptySlots(std::set> & toRemove) { - for(auto item : items[1]) + for(auto item : leftTradePanel->slots) if(!hero->getStackCount(SlotID(item->serial))) toRemove.insert(item); } diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index 79f690307..f913da55c 100644 --- a/client/widgets/CTradeBase.h +++ b/client/widgets/CTradeBase.h @@ -67,17 +67,20 @@ public: struct STradePanel : public CIntObject { - using updateSlotsFunctor = std::function; + using UpdateSlotsFunctor = std::function; + using DeleteSlotsCheck = std::function & slot)>; std::vector> slots; - std::function updateSlotsCallback; + UpdateSlotsFunctor updateSlotsCallback; + DeleteSlotsCheck deleteSlotsCheck; std::shared_ptr selected; const int selectionWidth = 2; virtual void updateSlots(); virtual void deselect(); virtual void clearSubtitles(); - void updateOffer(int slotIdx, int, int); + void updateOffer(CTradeableItem & slot, int, int); + void deleteSlots(); }; struct SResourcesPanel : public STradePanel @@ -95,7 +98,7 @@ struct SResourcesPanel : public STradePanel Point(83, 158) }; - SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles); + SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles); }; struct SArtifactsPanel : public STradePanel @@ -106,9 +109,9 @@ struct SArtifactsPanel : public STradePanel Point(0, 79), Point(83, 79), Point(166, 79), Point(83, 158) }; - const size_t artifactsForTrade = 7; + const size_t slotsForTrade = 7; - SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, updateSlotsFunctor updateSubtitles, + SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, std::vector & arts); }; @@ -123,6 +126,19 @@ struct SPlayersPanel : public STradePanel SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback); }; +struct SCreaturesPanel : public STradePanel +{ + using slotsData = std::vector>; + + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 98), Point(83, 98), Point(166, 98), + Point(83, 196) + }; + SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, slotsData & initialSlots); +}; + class CTradeBase { public: diff --git a/client/windows/CAltarWindow.cpp b/client/windows/CAltarWindow.cpp index a6a312b22..003e3ef59 100644 --- a/client/windows/CAltarWindow.cpp +++ b/client/windows/CAltarWindow.cpp @@ -48,7 +48,7 @@ void CAltarWindow::updateExpToLevel() void CAltarWindow::updateGarrisons() { if(auto altarCreatures = std::static_pointer_cast(altar)) - altarCreatures->updateGarrison(); + altarCreatures->updateSlots(); } bool CAltarWindow::holdsGarrison(const CArmedInstance * army) @@ -130,12 +130,10 @@ void CAltarWindow::showAll(Canvas & to) if(altar->hRight) { - to.drawBorder(Rect::createAround(altar->hRight->pos, 1), Colors::BRIGHT_YELLOW, 2); altar->hRight->showAllAt(altar->pos.topLeft() + Point(396, 423), "", to); } if(altar->hLeft) { - to.drawBorder(Rect::createAround(altar->hLeft->pos, 1), Colors::BRIGHT_YELLOW, 2); altar->hLeft->showAllAt(altar->pos.topLeft() + Point(150, 423), "", to); } } diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index bb5e4034b..a0674bd0b 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -92,7 +92,7 @@ void CTradeWindow::initItems(bool Left) int h1, h2; //hlp variables for getting offer market->getOffer(hLeft->id, slot->id, h1, h2, mode); - rightTradePanel->updateOffer(slot->serial, h1, h2); + rightTradePanel->updateOffer(*slot, h1, h2); } else rightTradePanel->clearSubtitles(); @@ -111,7 +111,22 @@ void CTradeWindow::initItems(bool Left) selectionChanged(left); }; - if(Left && (mode == EMarketMode::RESOURCE_RESOURCE || mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER)) + if(Left && mode == EMarketMode::CREATURE_RESOURCE) + { + 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(std::bind(clickPressedTradePanel, _1, true), slots); + leftTradePanel->moveBy(Point(45, 123)); + leftTradePanel->deleteSlotsCheck = [this](std::shared_ptr & slot) -> bool + { + return this->hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false; + }; + } + else if(Left && (mode == EMarketMode::RESOURCE_RESOURCE || mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER)) { leftTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, true), [this]() -> void @@ -121,9 +136,8 @@ void CTradeWindow::initItems(bool Left) }); leftTradePanel->moveBy(Point(39, 182)); leftTradePanel->updateSlots(); - return; } - if(!Left && mode == EMarketMode::RESOURCE_RESOURCE) + else if(!Left && mode == EMarketMode::RESOURCE_RESOURCE) { rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), [this, updRightSub]() -> void @@ -133,153 +147,28 @@ void CTradeWindow::initItems(bool Left) rightTradePanel->slots[hLeft->serial]->subtitle = CGI->generaltexth->allTexts[164]; // n/a }); rightTradePanel->moveBy(Point(327, 181)); - return; } - if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE || mode == EMarketMode::CREATURE_RESOURCE)) + else if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE || mode == EMarketMode::CREATURE_RESOURCE)) { rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), std::bind(updRightSub, EMarketMode::ARTIFACT_RESOURCE)); rightTradePanel->moveBy(Point(327, 181)); - return; } - if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT) + else if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT) { rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), std::bind(updRightSub, EMarketMode::RESOURCE_ARTIFACT), market->availableItemsIds(mode)); rightTradePanel->moveBy(Point(327, 181)); - return; + rightTradePanel->deleteSlotsCheck = [this](std::shared_ptr & slot) -> bool + { + return vstd::contains(market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT), ArtifactID(slot->id)) ? false : true; + }; } - if(!Left && mode == EMarketMode::RESOURCE_PLAYER) + else if(!Left && mode == EMarketMode::RESOURCE_PLAYER) { rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false)); rightTradePanel->moveBy(Point(333, 83)); - return; } - - std::vector *ids = getItemsIds(Left); - std::vector pos; - int amount = -1; - - getPositionsFor(pos, Left, itemsType[Left]); - - if(Left || !ids) - amount = 7; - else - amount = static_cast(ids->size()); - - if(ids) - vstd::amin(amount, ids->size()); - - for(int j=0; jsize()>j) ? (*ids)[j] : j; - if(id < 0 && mode != EMarketMode::ARTIFACT_EXP) //when sacrificing artifacts we need to prepare empty slots - continue; - - auto item = std::make_shared(pos[j].topLeft(), itemsType[Left], id, Left, j); - item->pos = pos[j] + this->pos.topLeft(); - if(mode != EMarketMode::ARTIFACT_EXP) - item->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void - { - if(altarSlot->left) - { - if(hLeft != altarSlot) - hLeft = altarSlot; - else - return; - } - else - { - if(hRight != altarSlot) - hRight = altarSlot; - else - return; - } - selectionChanged(altarSlot->left); - }; - - items[Left].push_back(item); - } - vstd::clear_pointer(ids); - initSubs(Left); - } -} - -std::vector *CTradeWindow::getItemsIds(bool Left) -{ - std::vector *ids = nullptr; - - if(Left) - { - switch(itemsType[1]) - { - case CREATURE: - ids = new std::vector; - for(int i = 0; i < 7; i++) - { - if(const CCreature *c = hero->getCreature(SlotID(i))) - ids->push_back(c->getId()); - else - ids->push_back(-1); - } - break; - } - } - else - { - switch(itemsType[0]) - { - case PLAYER: - ids = new std::vector; - for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++) - if(PlayerColor(i) != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(PlayerColor(i)) == EPlayerStatus::INGAME) - ids->push_back(i); - break; - } - } - - return ids; -} - -void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType type) const -{ - //seven boxes: - // X X X - // X X X - // X - int h = 0, w = 0, x = 0, y = 0, dx = 0, dy = 0; - - switch(type) - { - case CREATURE://45,123 - x = 45; - y = 123; - w = 58; - h = 64; - dx = 83; - dy = 98; - assert(Left); - break; - } - int leftToRightOffset = 289; - - const std::vector tmp = - { - Rect(Point(x + 0 * dx, y + 0 * dx), Point(w, h) ), - Rect(Point(x + 1 * dx, y + 0 * dx), Point(w, h) ), - Rect(Point(x + 2 * dx, y + 0 * dx), Point(w, h) ), - Rect(Point(x + 0 * dx, y + 1 * dy), Point(w, h) ), - Rect(Point(x + 1 * dx, y + 1 * dy), Point(w, h) ), - Rect(Point(x + 2 * dx, y + 1 * dy), Point(w, h) ), - Rect(Point(x + 1 * dx, y + 2 * dy), Point(w, h) ) - }; - - vstd::concatenate(poss, tmp); - - if(!Left) - { - for(Rect &r : poss) - r.x += leftToRightOffset; } } @@ -287,25 +176,12 @@ void CTradeWindow::initSubs(bool Left) { if(itemsType[Left] == RESOURCE || itemsType[Left] == ARTIFACT_TYPE) { - if(Left) + if(Left) leftTradePanel->updateSlots(); else rightTradePanel->updateSlots(); return; } - - for(auto item : items[Left]) - { - if(Left) - { - switch(itemsType[1]) - { - case CREATURE: - item->subtitle = std::to_string(hero->getStackCount(SlotID(item->serial))); - break; - } - } - } } void CTradeWindow::showAll(Canvas & to) @@ -660,10 +536,8 @@ void CMarketplaceWindow::updateGarrison() if(mode != EMarketMode::CREATURE_RESOURCE) return; - std::set> toRemove; - getEmptySlots(toRemove); - removeItems(toRemove); - initSubs(true); + leftTradePanel->deleteSlots(); + leftTradePanel->updateSlots(); } void CMarketplaceWindow::artifactsChanged(bool Left) @@ -671,17 +545,8 @@ void CMarketplaceWindow::artifactsChanged(bool Left) assert(!Left); if(mode != EMarketMode::RESOURCE_ARTIFACT) return; - - std::vector available = market->availableItemsIds(mode); - std::set> toRemove; - for(auto item : items[0]) - if(!vstd::contains(available, ArtifactID(item->id))) - toRemove.insert(item); - - removeItems(toRemove); - - // clear set to erase final instance of shared_ptr - we want to redraw screen only after it has been deleted - toRemove.clear(); + + rightTradePanel->deleteSlots(); redraw(); } @@ -742,8 +607,8 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const switch(itemsType[0]) { case RESOURCE: - if(mode == EMarketMode::ARTIFACT_RESOURCE) - return Point(410, 471); + if(mode == EMarketMode::ARTIFACT_RESOURCE) + return Point(410, 471); else return Point(410, 448); case ARTIFACT_TYPE: diff --git a/client/windows/CTradeWindow.h b/client/windows/CTradeWindow.h index 85698c295..bfbb6bb46 100644 --- a/client/windows/CTradeWindow.h +++ b/client/windows/CTradeWindow.h @@ -36,8 +36,6 @@ public: void initSubs(bool Left); void initTypes(); void initItems(bool Left); - std::vector *getItemsIds(bool Left); //nullptr if default - void getPositionsFor(std::vector &poss, bool Left, EType type) const; void setMode(EMarketMode Mode); //mode setter void artifactSelected(CArtPlace * slot); //used when selling artifacts -> called when user clicked on artifact slot From d0ca63d2c921c7253202f17def499c4db07e22ac Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 4 Dec 2023 19:16:26 +0200 Subject: [PATCH 6/9] subclasses for market composition --- client/widgets/CAltar.cpp | 129 +++++++++++--------------------- client/widgets/CAltar.h | 26 +------ client/widgets/CTradeBase.cpp | 84 ++++++++++++++++++++- client/widgets/CTradeBase.h | 28 +++++++ client/windows/CAltarWindow.h | 2 +- client/windows/CTradeWindow.cpp | 9 +-- 6 files changed, 158 insertions(+), 120 deletions(-) diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp index 175857144..b5a8161cd 100644 --- a/client/widgets/CAltar.cpp +++ b/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(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(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); - deal = std::make_shared(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"), CGI->generaltexth->zelp[585], std::bind(&CAltar::makeDeal, this)); - expToLevel = std::make_shared(75, 477, FONT_SMALL, ETextAlignment::CENTER); - expForHero = std::make_shared(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(Point(280, 442)); sacrificeAllButton = std::make_shared(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(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"), @@ -235,7 +210,7 @@ void CAltarArtifacts::onSlotClickPressed(std::shared_ptr 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(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); rSubtitle = std::make_shared(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); - unitsSlider = std::make_shared(Point(231, 481), 137, std::bind(&CAltarCreatures::onUnitsSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL); - maxUnits = std::make_shared(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, unitsSlider)); + offerSlider = std::make_shared(Point(231, 481), 137, std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL); + maxUnits = std::make_shared(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( - 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([this](std::shared_ptr 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([this](std::shared_ptr 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 & 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 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 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 altarSlot, std::shared_ptr & oppositePanel, - std::shared_ptr & hCurSide, std::shared_ptr & hOppSide) +void CAltarCreatures::onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSide) { - std::shared_ptr 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 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(); } diff --git a/client/widgets/CAltar.h b/client/widgets/CAltar.h index e0d39ca94..53dceaf2d 100644 --- a/client/widgets/CAltar.h +++ b/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 expToLevel; - std::shared_ptr expForHero; - std::shared_ptr 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 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 maxUnits; - std::shared_ptr unitsSlider; std::vector unitsOnAltar; std::vector expPerUnit; std::shared_ptr lSubtitle, rSubtitle; @@ -83,7 +66,6 @@ private: void readExpValues(); void updateControls(); void updateSubtitlesForSelected(); - void onUnitsSliderMoved(int newVal); - void onSlotClickPressed(std::shared_ptr altarSlot, std::shared_ptr & oppositePanel, - std::shared_ptr & hCurSide, std::shared_ptr & hOppSide); + void onOfferSliderMoved(int newVal); + void onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSide) override; }; diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index 18ba7e939..1402e96f1 100644 --- a/client/widgets/CTradeBase.cpp +++ b/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(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(Rect(slotsPos[slotId.num], slot->pos.dimensions()), Point(1, 1), selectionWidth); + } +} + +SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, + std::vector> & 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(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(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(Point(), AnimationPath::builtin("ALTSACR.DEF"), + CGI->generaltexth->zelp[585], std::bind(&CTradeBase::makeDeal, this)); } void CTradeBase::removeItems(const std::set> & toRemove) @@ -398,3 +418,63 @@ void CTradeBase::getEmptySlots(std::set> & 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 & newSlot, std::shared_ptr & 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(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(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); + deal->moveBy(dealButtonPos); + expToLevel = std::make_shared(75, 477, FONT_SMALL, ETextAlignment::CENTER); + expForHero = std::make_shared(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([this](std::shared_ptr altarSlot) -> void + { + onSlotClickPressed(altarSlot, hLeft); + }, slots); +} + +bool CCreaturesSelling::slotDeletingCheck(std::shared_ptr & 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))); +} diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h index f913da55c..a063a493d 100644 --- a/client/widgets/CTradeBase.h +++ b/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> & stsSlots, bool emptySlots = true); }; class CTradeBase @@ -153,15 +156,40 @@ public: std::shared_ptr hLeft; std::shared_ptr hRight; std::shared_ptr deal; + std::shared_ptr offerSlider; CTradeBase(const IMarket * market, const CGHeroInstance * hero); void removeItems(const std::set> & toRemove); void removeItem(std::shared_ptr item); void getEmptySlots(std::set> & toRemove); virtual void makeDeal() = 0; + virtual void deselect(); + virtual void onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSlot); protected: std::vector> labels; std::vector> buttons; std::vector> texts; }; + +// Market subclasses +class CExpAltar : virtual public CTradeBase, virtual public CIntObject +{ +public: + std::shared_ptr expToLevel; + std::shared_ptr expForHero; + std::shared_ptr 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 & slot); + void updateSubtitle(); +}; diff --git a/client/windows/CAltarWindow.h b/client/windows/CAltarWindow.h index 83ddea490..02873228a 100644 --- a/client/windows/CAltarWindow.h +++ b/client/windows/CAltarWindow.h @@ -28,7 +28,7 @@ public: private: const CGHeroInstance * hero; - std::shared_ptr altar; + std::shared_ptr altar; std::shared_ptr changeModeButton; std::shared_ptr quitButton; std::function windowClosedCallback; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index a0674bd0b..ee5558ddd 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -100,14 +100,7 @@ void CTradeWindow::initItems(bool Left) auto clickPressedTradePanel = [this](std::shared_ptr 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); }; From fdf60b215128976f1c0d987691667285bf2b06b4 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 4 Dec 2023 23:21:49 +0200 Subject: [PATCH 7/9] moved to widgets/markets --- client/CMakeLists.txt | 12 +- client/widgets/CAltar.cpp | 431 ------------------ client/widgets/CArtifactsOfHeroMarket.cpp | 8 +- client/widgets/CTradeBase.h | 195 -------- client/widgets/markets/CAltarArtifacts.cpp | 213 +++++++++ .../{CAltar.h => markets/CAltarArtifacts.h} | 34 +- client/widgets/markets/CAltarCreatures.cpp | 247 ++++++++++ client/widgets/markets/CAltarCreatures.h | 37 ++ client/widgets/markets/CTradeBase.cpp | 111 +++++ client/widgets/markets/CTradeBase.h | 74 +++ .../TradePanels.cpp} | 240 ++++------ client/widgets/markets/TradePanels.h | 140 ++++++ client/windows/CAltarWindow.h | 5 +- client/windows/CTradeWindow.cpp | 96 ++-- client/windows/CTradeWindow.h | 2 +- 15 files changed, 972 insertions(+), 873 deletions(-) delete mode 100644 client/widgets/CAltar.cpp delete mode 100644 client/widgets/CTradeBase.h create mode 100644 client/widgets/markets/CAltarArtifacts.cpp rename client/widgets/{CAltar.h => markets/CAltarArtifacts.h} (57%) create mode 100644 client/widgets/markets/CAltarCreatures.cpp create mode 100644 client/widgets/markets/CAltarCreatures.h create mode 100644 client/widgets/markets/CTradeBase.cpp create mode 100644 client/widgets/markets/CTradeBase.h rename client/widgets/{CTradeBase.cpp => markets/TradePanels.cpp} (58%) create mode 100644 client/widgets/markets/TradePanels.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index bbc580c0c..20697bc2b 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -96,14 +96,12 @@ set(client_SRCS renderSDL/SDL_Extensions.cpp widgets/Buttons.cpp - widgets/CAltar.cpp widgets/CArtifactHolder.cpp widgets/CComponent.cpp widgets/CExchangeController.cpp widgets/CGarrisonInt.cpp widgets/CreatureCostBox.cpp widgets/ComboBox.cpp - widgets/CTradeBase.cpp widgets/Images.cpp widgets/MiscWidgets.cpp widgets/ObjectLists.cpp @@ -118,6 +116,10 @@ set(client_SRCS widgets/CArtifactsOfHeroBackpack.cpp widgets/CWindowWithArtifacts.cpp widgets/RadialMenu.cpp + widgets/markets/CAltarArtifacts.cpp + widgets/markets/CAltarCreatures.cpp + widgets/markets/CTradeBase.cpp + widgets/markets/TradePanels.cpp windows/CAltarWindow.cpp windows/CCastleInterface.cpp @@ -269,14 +271,12 @@ set(client_HEADERS renderSDL/SDL_PixelAccess.h widgets/Buttons.h - widgets/CAltar.h widgets/CArtifactHolder.h widgets/CComponent.h widgets/CExchangeController.h widgets/CGarrisonInt.h widgets/CreatureCostBox.h widgets/ComboBox.h - widgets/CTradeBase.h widgets/Images.h widgets/MiscWidgets.h widgets/ObjectLists.h @@ -291,6 +291,10 @@ set(client_HEADERS widgets/CArtifactsOfHeroBackpack.h widgets/CWindowWithArtifacts.h widgets/RadialMenu.h + widgets/markets/CAltarArtifacts.h + widgets/markets/CAltarCreatures.h + widgets/markets/CTradeBase.h + widgets/markets/TradePanels.h windows/CAltarWindow.h windows/CCastleInterface.h diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp deleted file mode 100644 index b5a8161cd..000000000 --- a/client/widgets/CAltar.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* - * CAltarWindow.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 "CAltar.h" - -#include "../gui/CGuiHandler.h" -#include "../gui/CursorHandler.h" -#include "../widgets/Buttons.h" -#include "../widgets/Slider.h" -#include "../widgets/TextControls.h" - -#include "../CGameInfo.h" -#include "../CPlayerInterface.h" - -#include "../../CCallback.h" - -#include "../../lib/networkPacks/ArtifactLocation.h" -#include "../../lib/CGeneralTextHandler.h" -#include "../../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/mapObjects/CGMarket.h" - -CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero) - : CTradeBase(market, hero) -{ - OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); - - labels.emplace_back(std::make_shared(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477])); - labels.emplace_back(std::make_shared(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478])); - selectedCost = std::make_shared(302, 500, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); - selectedArt = std::make_shared(Point(280, 442)); - - sacrificeAllButton = std::make_shared(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"), - CGI->generaltexth->zelp[571], std::bind(&CExpAltar::sacrificeAll, this)); - sacrificeAllButton->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty()); - - sacrificeBackpackButton = std::make_shared(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"), - CGI->generaltexth->zelp[570], std::bind(&CAltarArtifacts::sacrificeBackpack, this)); - sacrificeBackpackButton->block(hero->artifactsInBackpack.empty()); - - arts = std::make_shared(Point(-365, -11)); - arts->setHero(hero); - - int slotNum = 0; - for(auto & altarSlotPos : posSlotsAltar) - { - auto altarSlot = std::make_shared(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum++); - altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1); - altarSlot->subtitle = ""; - items.front().emplace_back(altarSlot); - } - - calcExpAltarForHero(); - deselect(); -}; - -TExpType CAltarArtifacts::calcExpAltarForHero() -{ - auto artifactsOfHero = std::dynamic_pointer_cast(arts); - TExpType expOnAltar(0); - for(const auto art : artifactsOfHero->artifactsOnAltar) - { - int dmp, expOfArt; - market->getOffer(art->artType->getId(), 0, dmp, expOfArt, EMarketMode::ARTIFACT_EXP); - expOnAltar += expOfArt; - } - auto resultExp = hero->calculateXp(expOnAltar); - expForHero->setText(std::to_string(resultExp)); - return resultExp; -} - -void CAltarArtifacts::makeDeal() -{ - std::vector positions; - for(const auto art : arts->artifactsOnAltar) - { - positions.push_back(hero->getSlotByInstance(art)); - } - std::sort(positions.begin(), positions.end()); - std::reverse(positions.begin(), positions.end()); - - LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector(), std::vector(), hero); - arts->artifactsOnAltar.clear(); - - for(auto item : items[0]) - { - item->setID(-1); - item->subtitle = ""; - } - deal->block(true); - calcExpAltarForHero(); -} - -void CAltarArtifacts::sacrificeAll() -{ - std::vector> artsForMove; - for(const auto & slotInfo : arts->getHero()->artifactsWorn) - { - if(!slotInfo.second.locked && slotInfo.second.artifact->artType->isTradable()) - artsForMove.push_back(slotInfo.second.artifact); - } - for(auto artInst : artsForMove) - moveArtToAltar(nullptr, artInst); - arts->updateWornSlots(); - sacrificeBackpack(); -} - -void CAltarArtifacts::sacrificeBackpack() -{ - while(!arts->visibleArtSet.artifactsInBackpack.empty()) - { - if(!putArtOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact)) - break; - }; - calcExpAltarForHero(); -} - -void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art) -{ - if(art) - { - selectedArt->setArtifact(art); - int dmp, exp; - market->getOffer(art->getTypeId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP); - selectedCost->setText(std::to_string(hero->calculateXp(exp))); - } - else - { - selectedArt->setArtifact(nullptr); - selectedCost->setText(""); - } -} - -void CAltarArtifacts::moveArtToAltar(std::shared_ptr altarSlot, const CArtifactInstance * art) -{ - if(putArtOnAltar(altarSlot, art)) - { - CCS->curh->dragAndDropCursor(nullptr); - arts->unmarkSlots(); - } -} - -std::shared_ptr CAltarArtifacts::getAOHset() const -{ - return arts; -} - -bool CAltarArtifacts::putArtOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art) -{ - if(!art->artType->isTradable()) - { - logGlobal->warn("Cannot put special artifact on altar!"); - return false; - } - - if(!altarSlot || altarSlot->id != -1) - { - int slotIndex = -1; - while(items[0][++slotIndex]->id >= 0 && slotIndex + 1 < items[0].size()); - slotIndex = items[0][slotIndex]->id == -1 ? slotIndex : -1; - if(slotIndex < 0) - { - logGlobal->warn("No free slots on altar!"); - return false; - } - altarSlot = items[0][slotIndex]; - } - - int dmp, exp; - market->getOffer(art->artType->getId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP); - exp = static_cast(hero->calculateXp(exp)); - - arts->artifactsOnAltar.insert(art); - altarSlot->setArtInstance(art); - altarSlot->subtitle = std::to_string(exp); - - deal->block(false); - return true; -}; - -void CAltarArtifacts::onSlotClickPressed(std::shared_ptr altarSlot) -{ - const auto pickedArtInst = arts->getPickedArtifact(); - if(pickedArtInst) - { - arts->pickedArtMoveToAltar(ArtifactPosition::TRANSITION_POS); - moveArtToAltar(altarSlot, pickedArtInst); - } - else if(const CArtifactInstance * art = altarSlot->getArtInstance()) - { - const auto hero = arts->getHero(); - const auto slot = hero->getSlotByInstance(art); - assert(slot != ArtifactPosition::PRE_FIRST); - LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero->id, slot), - ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS)); - arts->pickedArtFromSlot = slot; - arts->artifactsOnAltar.erase(art); - altarSlot->setID(-1); - altarSlot->subtitle.clear(); - deal->block(!arts->artifactsOnAltar.size()); - } - calcExpAltarForHero(); -} - -CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero) - : CTradeBase(market, hero) -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); - - labels.emplace_back(std::make_shared(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, - boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated()))); - labels.emplace_back(std::make_shared(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479])); - texts.emplace_back(std::make_unique(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); - lSubtitle = std::make_shared(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); - rSubtitle = std::make_shared(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); - - offerSlider = std::make_shared(Point(231, 481), 137, std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL); - maxUnits = std::make_shared(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( - Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CExpAltar::sacrificeAll, this)); - - // Hero creatures panel - assert(leftTradePanel); - leftTradePanel->moveBy(Point(45, 110)); - leftTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this); - - // Altar creatures panel - rightTradePanel = std::make_shared([this](std::shared_ptr altarSlot) -> void - { - onSlotClickPressed(altarSlot, hRight); - }, leftTradePanel->slots); - rightTradePanel->moveBy(Point(334, 110)); - - leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1); - readExpValues(); - calcExpAltarForHero(); - deselect(); -}; - -void CAltarCreatures::readExpValues() -{ - int dump; - for(auto heroSlot : leftTradePanel->slots) - { - if(heroSlot->id >= 0) - market->getOffer(heroSlot->id, 0, dump, expPerUnit[heroSlot->serial], EMarketMode::CREATURE_EXP); - } -} - -void CAltarCreatures::updateControls() -{ - int sliderAmount = 0; - if(hLeft) - { - std::optional lastSlot; - for(auto slot = SlotID(0); slot.num < GameConstants::ARMY_SIZE; slot++) - { - if(hero->getStackCount(slot) > unitsOnAltar[slot.num]) - { - if(lastSlot.has_value()) - { - lastSlot = std::nullopt; - break; - } - else - { - lastSlot = slot; - } - } - } - sliderAmount = hero->getStackCount(SlotID(hLeft->serial)); - if(lastSlot.has_value() && lastSlot.value() == SlotID(hLeft->serial)) - sliderAmount--; - } - offerSlider->setAmount(sliderAmount); - offerSlider->block(!offerSlider->getAmount()); - if(hLeft) - offerSlider->scrollTo(unitsOnAltar[hLeft->serial]); - maxUnits->block(offerSlider->getAmount() == 0); -} - -void CAltarCreatures::updateSubtitlesForSelected() -{ - if(hLeft) - lSubtitle->setText(std::to_string(offerSlider->getValue())); - else - lSubtitle->setText(""); - if(hRight) - rSubtitle->setText(hRight->subtitle); - else - rSubtitle->setText(""); -} - -void CAltarCreatures::updateSlots() -{ - rightTradePanel->deleteSlots(); - leftTradePanel->deleteSlots(); - assert(leftTradePanel->slots.size() == rightTradePanel->slots.size()); - readExpValues(); - leftTradePanel->updateSlots(); -} - -void CAltarCreatures::deselect() -{ - CTradeBase::deselect(); - offerSlider->block(true); - maxUnits->block(true); - updateSubtitlesForSelected(); -} - -TExpType CAltarCreatures::calcExpAltarForHero() -{ - TExpType expOnAltar(0); - auto oneUnitExp = expPerUnit.begin(); - for(const auto units : unitsOnAltar) - expOnAltar += *oneUnitExp++ * units; - auto resultExp = hero->calculateXp(expOnAltar); - expForHero->setText(std::to_string(resultExp)); - return resultExp; -} - -void CAltarCreatures::makeDeal() -{ - deselect(); - offerSlider->scrollTo(0); - expForHero->setText(std::to_string(0)); - - std::vector ids; - std::vector toSacrifice; - - for(int i = 0; i < unitsOnAltar.size(); i++) - { - if(unitsOnAltar[i]) - { - ids.push_back(SlotID(i)); - toSacrifice.push_back(unitsOnAltar[i]); - } - } - - LOCPLINT->cb->trade(market, EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero); - - for(int & units : unitsOnAltar) - units = 0; - - for(auto heroSlot : rightTradePanel->slots) - { - heroSlot->setType(CREATURE_PLACEHOLDER); - heroSlot->subtitle.clear(); - } -} - -void CAltarCreatures::sacrificeAll() -{ - std::optional lastSlot; - for(auto heroSlot : leftTradePanel->slots) - { - auto stackCount = hero->getStackCount(SlotID(heroSlot->serial)); - if(stackCount > unitsOnAltar[heroSlot->serial]) - { - if(!lastSlot.has_value()) - lastSlot = SlotID(heroSlot->serial); - unitsOnAltar[heroSlot->serial] = stackCount; - } - } - assert(lastSlot.has_value()); - unitsOnAltar[lastSlot.value().num]--; - - if(hRight) - offerSlider->scrollTo(unitsOnAltar[hRight->serial]); - for(auto altarSlot : rightTradePanel->slots) - updateAltarSlot(altarSlot); - updateSubtitlesForSelected(); - - deal->block(calcExpAltarForHero() == 0); -} - -void CAltarCreatures::updateAltarSlot(std::shared_ptr slot) -{ - auto units = unitsOnAltar[slot->serial]; - slot->setType(units > 0 ? CREATURE : CREATURE_PLACEHOLDER); - slot->subtitle = units > 0 ? - boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : ""; -} - -void CAltarCreatures::onOfferSliderMoved(int newVal) -{ - if(hLeft) - unitsOnAltar[hLeft->serial] = newVal; - if(hRight) - updateAltarSlot(hRight); - deal->block(calcExpAltarForHero() == 0); - updateControls(); - updateSubtitlesForSelected(); -} - -void CAltarCreatures::onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSide) -{ - if(hCurSide == newSlot) - return; - - auto * oppositeSlot = &hLeft; - auto oppositePanel = leftTradePanel; - CTradeBase::onSlotClickPressed(newSlot, hCurSide); - if(hCurSide == hLeft) - { - oppositeSlot = &hRight; - oppositePanel = rightTradePanel; - } - std::shared_ptr oppositeNewSlot; - for(const auto & slot : oppositePanel->slots) - if(slot->serial == newSlot->serial) - { - oppositeNewSlot = slot; - break; - } - assert(oppositeNewSlot); - CTradeBase::onSlotClickPressed(oppositeNewSlot, *oppositeSlot); - updateControls(); - updateSubtitlesForSelected(); - redraw(); -} diff --git a/client/widgets/CArtifactsOfHeroMarket.cpp b/client/widgets/CArtifactsOfHeroMarket.cpp index 90ddcde46..fadc632cd 100644 --- a/client/widgets/CArtifactsOfHeroMarket.cpp +++ b/client/widgets/CArtifactsOfHeroMarket.cpp @@ -20,10 +20,10 @@ CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position) position, std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1)); - for(auto slot : artWorn) - slot.second->selection->lineWidth = 2; - for(auto slot : backpack) - slot->selection->lineWidth = 2; + for(const auto & [slot, artPlace] : artWorn) + artPlace->selection->setBorderWidth(2); + for(auto artPlace : backpack) + artPlace->selection->setBorderWidth(2); }; void CArtifactsOfHeroMarket::scrollBackpack(int offset) diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h deleted file mode 100644 index a063a493d..000000000 --- a/client/widgets/CTradeBase.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * CTradeBase.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 "Images.h" - -#include "../lib/FunctionList.h" -#include "../lib/networkPacks/TradeItem.h" - -VCMI_LIB_NAMESPACE_BEGIN - -class IMarket; -class CGHeroInstance; -class SelectableSlot; - -VCMI_LIB_NAMESPACE_END - -class CButton; -class CTextBox; -class CSlider; - -enum EType -{ - RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE -}; - -class CTradeableItem : public CIntObject, public std::enable_shared_from_this -{ - std::shared_ptr image; - AnimationPath getFilename(); - int getIndex(); -public: - using ClickPressedFunctor = std::function)>; - - const CArtifactInstance * hlp; //holds ptr to artifact instance id type artifact - EType type; - int id; - const int serial; - const bool left; - std::string subtitle; //empty if default - ClickPressedFunctor clickPressedCallback; - - void setType(EType newType); - void setID(int newID); - - const CArtifactInstance * getArtInstance() const; - void setArtInstance(const CArtifactInstance * art); - - std::unique_ptr selection; - bool downSelection; - - void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); - - void showPopupWindow(const Point & cursorPosition) override; - void hover(bool on) override; - void showAll(Canvas & to) override; - void clickPressed(const Point & cursorPosition) override; - std::string getName(int number = -1) const; - CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); -}; - -struct STradePanel : public CIntObject -{ - using UpdateSlotsFunctor = std::function; - using DeleteSlotsCheck = std::function & slot)>; - - std::vector> slots; - UpdateSlotsFunctor updateSlotsCallback; - DeleteSlotsCheck deleteSlotsCheck; - std::shared_ptr selected; - const int selectionWidth = 2; - - virtual void updateSlots(); - virtual void deselect(); - virtual void clearSubtitles(); - void updateOffer(CTradeableItem & slot, int, int); - void deleteSlots(); -}; - -struct SResourcesPanel : public STradePanel -{ - const std::vector resourcesForTrade = - { - GameResID::WOOD, GameResID::MERCURY, GameResID::ORE, - GameResID::SULFUR, GameResID::CRYSTAL, GameResID::GEMS, - GameResID::GOLD - }; - const std::vector slotsPos = - { - Point(0, 0), Point(83, 0), Point(166, 0), - Point(0, 79), Point(83, 79), Point(166, 79), - Point(83, 158) - }; - - SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles); -}; - -struct SArtifactsPanel : public STradePanel -{ - const std::vector slotsPos = - { - Point(0, 0), Point(83, 0), Point(166, 0), - Point(0, 79), Point(83, 79), Point(166, 79), - Point(83, 158) - }; - const size_t slotsForTrade = 7; - - SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, - std::vector & arts); -}; - -struct SPlayersPanel : public STradePanel -{ - const std::vector slotsPos = - { - Point(0, 0), Point(83, 0), Point(166, 0), - Point(0, 118), Point(83, 118), Point(166, 118), - Point(83, 236) - }; - SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback); -}; - -struct SCreaturesPanel : public STradePanel -{ - using slotsData = std::vector>; - - const std::vector slotsPos = - { - Point(0, 0), Point(83, 0), Point(166, 0), - Point(0, 98), Point(83, 98), Point(166, 98), - Point(83, 196) - }; - SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, slotsData & initialSlots); - SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, - std::vector> & stsSlots, bool emptySlots = true); -}; - -class CTradeBase -{ -public: - const IMarket * market; - const CGHeroInstance * hero; - - //all indexes: 1 = left, 0 = right - std::array>, 2> items; - std::shared_ptr leftTradePanel, rightTradePanel; - - //highlighted items (nullptr if no highlight) - std::shared_ptr hLeft; - std::shared_ptr hRight; - std::shared_ptr deal; - std::shared_ptr offerSlider; - - CTradeBase(const IMarket * market, const CGHeroInstance * hero); - void removeItems(const std::set> & toRemove); - void removeItem(std::shared_ptr item); - void getEmptySlots(std::set> & toRemove); - virtual void makeDeal() = 0; - virtual void deselect(); - virtual void onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSlot); - -protected: - std::vector> labels; - std::vector> buttons; - std::vector> texts; -}; - -// Market subclasses -class CExpAltar : virtual public CTradeBase, virtual public CIntObject -{ -public: - std::shared_ptr expToLevel; - std::shared_ptr expForHero; - std::shared_ptr 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 & slot); - void updateSubtitle(); -}; diff --git a/client/widgets/markets/CAltarArtifacts.cpp b/client/widgets/markets/CAltarArtifacts.cpp new file mode 100644 index 000000000..b59d08e2f --- /dev/null +++ b/client/widgets/markets/CAltarArtifacts.cpp @@ -0,0 +1,213 @@ +/* + * CAltarArtifacts.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 "CAltarArtifacts.h" + +#include "../../gui/CGuiHandler.h" +#include "../../gui/CursorHandler.h" +#include "../../widgets/Buttons.h" +#include "../../widgets/TextControls.h" + +#include "../../CGameInfo.h" +#include "../../CPlayerInterface.h" + +#include "../../../CCallback.h" + +#include "../../../lib/networkPacks/ArtifactLocation.h" +#include "../../../lib/CGeneralTextHandler.h" +#include "../../../lib/mapObjects/CGHeroInstance.h" +#include "../../../lib/mapObjects/CGMarket.h" + +CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero) + : CTradeBase(market, hero) +{ + OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + + labels.emplace_back(std::make_shared(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477])); + labels.emplace_back(std::make_shared(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478])); + selectedCost = std::make_shared(302, 500, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); + selectedArt = std::make_shared(Point(280, 442)); + + sacrificeAllButton = std::make_shared(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"), + CGI->generaltexth->zelp[571], std::bind(&CExperienceAltar::sacrificeAll, this)); + sacrificeAllButton->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty()); + + sacrificeBackpackButton = std::make_shared(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"), + CGI->generaltexth->zelp[570], std::bind(&CAltarArtifacts::sacrificeBackpack, this)); + sacrificeBackpackButton->block(hero->artifactsInBackpack.empty()); + + arts = std::make_shared(Point(-365, -11)); + arts->setHero(hero); + + int slotNum = 0; + for(auto & altarSlotPos : posSlotsAltar) + { + auto altarSlot = std::make_shared(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum); + altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1, hRight); + altarSlot->subtitle.clear(); + items.front().emplace_back(altarSlot); + slotNum++; + } + + expForHero->setText(std::to_string(0)); + CTradeBase::deselect(); +}; + +TExpType CAltarArtifacts::calcExpAltarForHero() +{ + auto artifactsOfHero = std::dynamic_pointer_cast(arts); + TExpType expOnAltar(0); + for(const auto art : artifactsOfHero->artifactsOnAltar) + { + int dmp = 0; + int expOfArt = 0; + market->getOffer(art->getTypeId(), 0, dmp, expOfArt, EMarketMode::ARTIFACT_EXP); + expOnAltar += expOfArt; + } + auto resultExp = hero->calculateXp(expOnAltar); + expForHero->setText(std::to_string(resultExp)); + return resultExp; +} + +void CAltarArtifacts::makeDeal() +{ + std::vector positions; + for(const auto art : arts->artifactsOnAltar) + { + positions.push_back(hero->getSlotByInstance(art)); + } + std::sort(positions.begin(), positions.end()); + std::reverse(positions.begin(), positions.end()); + + LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector(), std::vector(), hero); + arts->artifactsOnAltar.clear(); + + for(auto item : items[0]) + { + item->setID(-1); + item->subtitle.clear(); + } + deal->block(true); + calcExpAltarForHero(); +} + +void CAltarArtifacts::sacrificeAll() +{ + std::vector> artsForMove; + for(const auto & [slot, slotInfo] : arts->getHero()->artifactsWorn) + { + if(!slotInfo.locked && slotInfo.artifact->artType->isTradable()) + artsForMove.emplace_back(slotInfo.artifact); + } + for(auto artInst : artsForMove) + moveArtToAltar(nullptr, artInst); + arts->updateWornSlots(); + sacrificeBackpack(); +} + +void CAltarArtifacts::sacrificeBackpack() +{ + while(!arts->visibleArtSet.artifactsInBackpack.empty()) + { + if(!putArtOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact)) + break; + }; + calcExpAltarForHero(); +} + +void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art) +{ + if(art) + { + selectedArt->setArtifact(art); + int dmp = 0; + int exp = 0; + market->getOffer(art->getTypeId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP); + selectedCost->setText(std::to_string(hero->calculateXp(exp))); + } + else + { + selectedArt->setArtifact(nullptr); + selectedCost->setText(""); + } +} + +void CAltarArtifacts::moveArtToAltar(std::shared_ptr altarSlot, const CArtifactInstance * art) +{ + if(putArtOnAltar(altarSlot, art)) + { + CCS->curh->dragAndDropCursor(nullptr); + arts->unmarkSlots(); + } +} + +std::shared_ptr CAltarArtifacts::getAOHset() const +{ + return arts; +} + +bool CAltarArtifacts::putArtOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art) +{ + if(!art->artType->isTradable()) + { + logGlobal->warn("Cannot put special artifact on altar!"); + return false; + } + + if(!altarSlot || altarSlot->id != -1) + { + int slotIndex = -1; + while(items[0][++slotIndex]->id >= 0 && slotIndex + 1 < items[0].size()); + slotIndex = items[0][slotIndex]->id == -1 ? slotIndex : -1; + if(slotIndex < 0) + { + logGlobal->warn("No free slots on altar!"); + return false; + } + altarSlot = items[0][slotIndex]; + } + + int dmp = 0; + int exp = 0; + market->getOffer(art->artType->getId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP); + exp = static_cast(hero->calculateXp(exp)); + + arts->artifactsOnAltar.insert(art); + altarSlot->setArtInstance(art); + altarSlot->subtitle = std::to_string(exp); + + deal->block(false); + return true; +}; + +void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & hCurSlot) +{ + const auto pickedArtInst = arts->getPickedArtifact(); + if(pickedArtInst) + { + arts->pickedArtMoveToAltar(ArtifactPosition::TRANSITION_POS); + moveArtToAltar(newSlot, pickedArtInst); + } + else if(const CArtifactInstance * art = newSlot->getArtInstance()) + { + const auto hero = arts->getHero(); + const auto slot = hero->getSlotByInstance(art); + assert(slot != ArtifactPosition::PRE_FIRST); + LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero->id, slot), + ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS)); + arts->pickedArtFromSlot = slot; + arts->artifactsOnAltar.erase(art); + newSlot->setID(-1); + newSlot->subtitle.clear(); + deal->block(!arts->artifactsOnAltar.size()); + } + calcExpAltarForHero(); +} diff --git a/client/widgets/CAltar.h b/client/widgets/markets/CAltarArtifacts.h similarity index 57% rename from client/widgets/CAltar.h rename to client/widgets/markets/CAltarArtifacts.h index 53dceaf2d..67a99bb85 100644 --- a/client/widgets/CAltar.h +++ b/client/widgets/markets/CAltarArtifacts.h @@ -1,5 +1,5 @@ /* - * CAltar.h, part of VCMI engine + * CAltarArtifacts.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * @@ -9,10 +9,10 @@ */ #pragma once -#include "../widgets/CArtifactsOfHeroAltar.h" -#include "../widgets/CTradeBase.h" +#include "../CArtifactsOfHeroAltar.h" +#include "CTradeBase.h" -class CAltarArtifacts : public CExpAltar +class CAltarArtifacts : public CExperienceAltar { public: CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero); @@ -43,29 +43,5 @@ private: }; bool putArtOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art); - void onSlotClickPressed(std::shared_ptr altarSlot); -}; - -class CAltarCreatures : public CExpAltar, public CCreaturesSelling -{ -public: - CAltarCreatures(const IMarket * market, const CGHeroInstance * hero); - void updateSlots(); - void deselect() override; - TExpType calcExpAltarForHero() override; - void makeDeal() override; - void sacrificeAll() override; - void updateAltarSlot(std::shared_ptr slot); - -private: - std::shared_ptr maxUnits; - std::vector unitsOnAltar; - std::vector expPerUnit; - std::shared_ptr lSubtitle, rSubtitle; - - void readExpValues(); - void updateControls(); - void updateSubtitlesForSelected(); - void onOfferSliderMoved(int newVal); - void onSlotClickPressed(std::shared_ptr & newSlot, std::shared_ptr & hCurSide) override; + void onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & hCurSlot) override; }; diff --git a/client/widgets/markets/CAltarCreatures.cpp b/client/widgets/markets/CAltarCreatures.cpp new file mode 100644 index 000000000..84b5f05f8 --- /dev/null +++ b/client/widgets/markets/CAltarCreatures.cpp @@ -0,0 +1,247 @@ +/* + * CAltarCreatures.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 "CAltarCreatures.h" + +#include "../../gui/CGuiHandler.h" +#include "../../widgets/Buttons.h" +#include "../../widgets/Slider.h" +#include "../../widgets/TextControls.h" + +#include "../../CGameInfo.h" +#include "../../CPlayerInterface.h" + +#include "../../../CCallback.h" + +#include "../../../lib/CGeneralTextHandler.h" +#include "../../../lib/mapObjects/CGHeroInstance.h" +#include "../../../lib/mapObjects/CGMarket.h" + +CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero) + : CTradeBase(market, hero) +{ + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + labels.emplace_back(std::make_shared(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, + boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated()))); + labels.emplace_back(std::make_shared(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479])); + texts.emplace_back(std::make_unique(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); + lSubtitle = std::make_shared(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); + rSubtitle = std::make_shared(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); + + offerSlider = std::make_shared(Point(231, 481), 137, std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL); + maxUnits = std::make_shared(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( + Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CExperienceAltar::sacrificeAll, this)); + + // Hero creatures panel + assert(leftTradePanel); + leftTradePanel->moveBy(Point(45, 110)); + leftTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this); + + // Altar creatures panel + rightTradePanel = std::make_shared([this](const std::shared_ptr & altarSlot) + { + CAltarCreatures::onSlotClickPressed(altarSlot, hRight); + }, leftTradePanel->slots); + rightTradePanel->moveBy(Point(334, 110)); + + leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1); + readExpValues(); + expForHero->setText(std::to_string(0)); + CAltarCreatures::deselect(); +}; + +void CAltarCreatures::readExpValues() +{ + int dump; + for(auto heroSlot : leftTradePanel->slots) + { + if(heroSlot->id >= 0) + market->getOffer(heroSlot->id, 0, dump, expPerUnit[heroSlot->serial], EMarketMode::CREATURE_EXP); + } +} + +void CAltarCreatures::updateControls() +{ + int sliderAmount = 0; + if(hLeft) + { + std::optional lastSlot; + for(auto slot = SlotID(0); slot.num < GameConstants::ARMY_SIZE; slot++) + { + if(hero->getStackCount(slot) > unitsOnAltar[slot.num]) + { + if(lastSlot.has_value()) + { + lastSlot = std::nullopt; + break; + } + else + { + lastSlot = slot; + } + } + } + sliderAmount = hero->getStackCount(SlotID(hLeft->serial)); + if(lastSlot.has_value() && lastSlot.value() == SlotID(hLeft->serial)) + sliderAmount--; + } + offerSlider->setAmount(sliderAmount); + offerSlider->block(!offerSlider->getAmount()); + if(hLeft) + offerSlider->scrollTo(unitsOnAltar[hLeft->serial]); + maxUnits->block(offerSlider->getAmount() == 0); +} + +void CAltarCreatures::updateSubtitlesForSelected() +{ + if(hLeft) + lSubtitle->setText(std::to_string(offerSlider->getValue())); + else + lSubtitle->setText(""); + if(hRight) + rSubtitle->setText(hRight->subtitle); + else + rSubtitle->setText(""); +} + +void CAltarCreatures::updateSlots() +{ + rightTradePanel->deleteSlots(); + leftTradePanel->deleteSlots(); + assert(leftTradePanel->slots.size() == rightTradePanel->slots.size()); + readExpValues(); + leftTradePanel->updateSlots(); +} + +void CAltarCreatures::deselect() +{ + CTradeBase::deselect(); + offerSlider->block(true); + maxUnits->block(true); + updateSubtitlesForSelected(); +} + +TExpType CAltarCreatures::calcExpAltarForHero() +{ + TExpType expOnAltar(0); + auto oneUnitExp = expPerUnit.begin(); + for(const auto units : unitsOnAltar) + expOnAltar += *oneUnitExp++ * units; + auto resultExp = hero->calculateXp(expOnAltar); + expForHero->setText(std::to_string(resultExp)); + return resultExp; +} + +void CAltarCreatures::makeDeal() +{ + deselect(); + offerSlider->scrollTo(0); + expForHero->setText(std::to_string(0)); + + std::vector ids; + std::vector toSacrifice; + + for(int i = 0; i < unitsOnAltar.size(); i++) + { + if(unitsOnAltar[i]) + { + ids.push_back(SlotID(i)); + toSacrifice.push_back(unitsOnAltar[i]); + } + } + + LOCPLINT->cb->trade(market, EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero); + + for(int & units : unitsOnAltar) + units = 0; + + for(auto heroSlot : rightTradePanel->slots) + { + heroSlot->setType(EType::CREATURE_PLACEHOLDER); + heroSlot->subtitle.clear(); + } +} + +void CAltarCreatures::sacrificeAll() +{ + std::optional lastSlot; + for(auto heroSlot : leftTradePanel->slots) + { + auto stackCount = hero->getStackCount(SlotID(heroSlot->serial)); + if(stackCount > unitsOnAltar[heroSlot->serial]) + { + if(!lastSlot.has_value()) + lastSlot = SlotID(heroSlot->serial); + unitsOnAltar[heroSlot->serial] = stackCount; + } + } + assert(lastSlot.has_value()); + unitsOnAltar[lastSlot.value().num]--; + + if(hRight) + offerSlider->scrollTo(unitsOnAltar[hRight->serial]); + for(auto altarSlot : rightTradePanel->slots) + updateAltarSlot(altarSlot); + updateSubtitlesForSelected(); + + deal->block(calcExpAltarForHero() == 0); +} + +void CAltarCreatures::updateAltarSlot(std::shared_ptr slot) +{ + auto units = unitsOnAltar[slot->serial]; + slot->setType(units > 0 ? EType::CREATURE : EType::CREATURE_PLACEHOLDER); + slot->subtitle = units > 0 ? + boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : ""; +} + +void CAltarCreatures::onOfferSliderMoved(int newVal) +{ + if(hLeft) + unitsOnAltar[hLeft->serial] = newVal; + if(hRight) + updateAltarSlot(hRight); + deal->block(calcExpAltarForHero() == 0); + updateControls(); + updateSubtitlesForSelected(); +} + +void CAltarCreatures::onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & hCurSide) +{ + if(hCurSide == newSlot) + return; + + auto * oppositeSlot = &hLeft; + auto oppositePanel = leftTradePanel; + CTradeBase::onSlotClickPressed(newSlot, hCurSide); + if(hCurSide == hLeft) + { + oppositeSlot = &hRight; + oppositePanel = rightTradePanel; + } + std::shared_ptr oppositeNewSlot; + for(const auto & slot : oppositePanel->slots) + if(slot->serial == newSlot->serial) + { + oppositeNewSlot = slot; + break; + } + assert(oppositeNewSlot); + CTradeBase::onSlotClickPressed(oppositeNewSlot, *oppositeSlot); + updateControls(); + updateSubtitlesForSelected(); + redraw(); +} diff --git a/client/widgets/markets/CAltarCreatures.h b/client/widgets/markets/CAltarCreatures.h new file mode 100644 index 000000000..24ede7fa5 --- /dev/null +++ b/client/widgets/markets/CAltarCreatures.h @@ -0,0 +1,37 @@ +/* + * CAltarCreatures.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 "CTradeBase.h" + +class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling +{ +public: + CAltarCreatures(const IMarket * market, const CGHeroInstance * hero); + void updateSlots(); + void deselect() override; + TExpType calcExpAltarForHero() override; + void makeDeal() override; + void sacrificeAll() override; + void updateAltarSlot(std::shared_ptr slot); + +private: + std::shared_ptr maxUnits; + std::vector unitsOnAltar; + std::vector expPerUnit; + std::shared_ptr lSubtitle; + std::shared_ptr rSubtitle; + + void readExpValues(); + void updateControls(); + void updateSubtitlesForSelected(); + void onOfferSliderMoved(int newVal); + void onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & hCurSide) override; +}; diff --git a/client/widgets/markets/CTradeBase.cpp b/client/widgets/markets/CTradeBase.cpp new file mode 100644 index 000000000..226799f3c --- /dev/null +++ b/client/widgets/markets/CTradeBase.cpp @@ -0,0 +1,111 @@ +/* + * CTradeBase.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 "CTradeBase.h" + +#include "../MiscWidgets.h" + +#include "../../gui/CGuiHandler.h" +#include "../../widgets/Buttons.h" +#include "../../widgets/TextControls.h" + +#include "../../CGameInfo.h" + +#include "../../../lib/CGeneralTextHandler.h" +#include "../../../lib/mapObjects/CGHeroInstance.h" + +CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) + : market(market) + , hero(hero) +{ + deal = std::make_shared(Point(), AnimationPath::builtin("ALTSACR.DEF"), + CGI->generaltexth->zelp[585], std::bind(&CTradeBase::makeDeal, this)); +} + +void CTradeBase::removeItems(const std::set> & toRemove) +{ + for(auto item : toRemove) + removeItem(item); +} + +void CTradeBase::removeItem(std::shared_ptr item) +{ + rightTradePanel->slots.erase(std::remove(rightTradePanel->slots.begin(), rightTradePanel->slots.end(), item)); + + if(hRight == item) + hRight.reset(); +} + +void CTradeBase::getEmptySlots(std::set> & toRemove) +{ + for(auto item : leftTradePanel->slots) + 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(const std::shared_ptr & newSlot, std::shared_ptr & hCurSlot) +{ + if(newSlot == hCurSlot) + return; + + if(hCurSlot) + hCurSlot->selection->selectSlot(false); + hCurSlot = newSlot; + newSlot->selection->selectSlot(true); +} + +CExperienceAltar::CExperienceAltar() +{ + OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + + // Experience needed to reach next level + texts.emplace_back(std::make_shared(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(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); + deal->moveBy(dealButtonPos); + expToLevel = std::make_shared(75, 477, FONT_SMALL, ETextAlignment::CENTER); + expForHero = std::make_shared(75, 545, FONT_SMALL, ETextAlignment::CENTER); +} + +CCreaturesSelling::CCreaturesSelling() +{ + assert(hero); + CreaturesPanel::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([this](const std::shared_ptr & altarSlot) + { + CTradeBase::onSlotClickPressed(altarSlot, hLeft); + }, slots); +} + +bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr & 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))); +} diff --git a/client/widgets/markets/CTradeBase.h b/client/widgets/markets/CTradeBase.h new file mode 100644 index 000000000..1586ba16f --- /dev/null +++ b/client/widgets/markets/CTradeBase.h @@ -0,0 +1,74 @@ +/* + * CTradeBase.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 "TradePanels.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class IMarket; +class CGHeroInstance; + +VCMI_LIB_NAMESPACE_END + +class CButton; +class CSlider; + +class CTradeBase +{ +public: + const IMarket * market; + const CGHeroInstance * hero; + + //all indexes: 1 = left, 0 = right + std::array>, 2> items; + std::shared_ptr leftTradePanel; + std::shared_ptr rightTradePanel; + + //highlighted items (nullptr if no highlight) + std::shared_ptr hLeft; + std::shared_ptr hRight; + std::shared_ptr deal; + std::shared_ptr offerSlider; + + std::vector> labels; + std::vector> buttons; + std::vector> texts; + + CTradeBase(const IMarket * market, const CGHeroInstance * hero); + void removeItems(const std::set> & toRemove); + void removeItem(std::shared_ptr item); + void getEmptySlots(std::set> & toRemove); + virtual void makeDeal() = 0; + virtual void deselect(); + virtual void onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & hCurSlot); +}; + +// Market subclasses +class CExperienceAltar : virtual public CTradeBase, virtual public CIntObject +{ +public: + std::shared_ptr expToLevel; + std::shared_ptr expForHero; + std::shared_ptr sacrificeAllButton; + const Point dealButtonPos = Point(269, 520); + + CExperienceAltar(); + virtual void sacrificeAll() = 0; + virtual TExpType calcExpAltarForHero() = 0; +}; + +class CCreaturesSelling : virtual public CTradeBase, virtual public CIntObject +{ +public: + CCreaturesSelling(); + bool slotDeletingCheck(const std::shared_ptr & slot); + void updateSubtitle(); +}; diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/markets/TradePanels.cpp similarity index 58% rename from client/widgets/CTradeBase.cpp rename to client/widgets/markets/TradePanels.cpp index 1402e96f1..b2ac2b9f9 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/markets/TradePanels.cpp @@ -1,5 +1,5 @@ /* - * CTradeBase.cpp, part of VCMI engine + * TradePanels.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * @@ -8,33 +8,34 @@ * */ #include "StdInc.h" -#include "CTradeBase.h" -#include "MiscWidgets.h" +#include "TradePanels.h" -#include "../gui/CGuiHandler.h" -#include "../render/Canvas.h" -#include "../widgets/Buttons.h" -#include "../widgets/TextControls.h" -#include "../windows/InfoWindows.h" +#include "../MiscWidgets.h" -#include "../CGameInfo.h" -#include "../CPlayerInterface.h" +#include "../../gui/CGuiHandler.h" +#include "../../render/Canvas.h" +#include "../../widgets/TextControls.h" +#include "../../windows/InfoWindows.h" -#include "../../CCallback.h" +#include "../../CGameInfo.h" +#include "../../CPlayerInterface.h" -#include "../../lib/CGeneralTextHandler.h" -#include "../../lib/mapObjects/CGHeroInstance.h" +#include "../../../CCallback.h" + +#include "../../../lib/CGeneralTextHandler.h" +#include "../../../lib/mapObjects/CGHeroInstance.h" CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial) : CIntObject(LCLICK | HOVER | SHOW_POPUP, pos) + , hlp(nullptr) , type(EType(-1)) // set to invalid, will be corrected in setType , id(ID) , serial(Serial) , left(Left) + , downSelection(false) { OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); - downSelection = false; - hlp = nullptr; + setType(Type); if(image) { @@ -85,15 +86,15 @@ AnimationPath CTradeableItem::getFilename() { switch(type) { - case RESOURCE: + case EType::RESOURCE: return AnimationPath::builtin("RESOURCE"); - case PLAYER: + case EType::PLAYER: return AnimationPath::builtin("CREST58"); - case ARTIFACT_TYPE: - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_TYPE: + case EType::ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_INSTANCE: return AnimationPath::builtin("artifact"); - case CREATURE: + case EType::CREATURE: return AnimationPath::builtin("TWCRPORT"); default: return {}; @@ -107,14 +108,14 @@ int CTradeableItem::getIndex() switch(type) { - case RESOURCE: - case PLAYER: + case EType::RESOURCE: + case EType::PLAYER: return id; - case ARTIFACT_TYPE: - case ARTIFACT_INSTANCE: - case ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_TYPE: + case EType::ARTIFACT_INSTANCE: + case EType::ARTIFACT_PLACEHOLDER: return CGI->artifacts()->getByIndex(id)->getIconIndex(); - case CREATURE: + case EType::CREATURE: return CGI->creatures()->getByIndex(id)->getIconIndex(); default: return -1; @@ -126,26 +127,26 @@ void CTradeableItem::showAll(Canvas & to) Point posToBitmap; Point posToSubCenter; - switch (type) + switch(type) { - case RESOURCE: + case EType::RESOURCE: posToBitmap = Point(19, 9); posToSubCenter = Point(35, 57); break; - case CREATURE_PLACEHOLDER: - case CREATURE: + case EType::CREATURE_PLACEHOLDER: + case EType::CREATURE: posToSubCenter = Point(29, 77); break; - case PLAYER: + case EType::PLAYER: posToSubCenter = Point(31, 77); break; - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_INSTANCE: posToSubCenter = Point(22, 51); if (downSelection) posToSubCenter.y += 8; break; - case ARTIFACT_TYPE: + case EType::ARTIFACT_TYPE: posToSubCenter = Point(35, 57); posToBitmap = Point(13, 0); break; @@ -191,11 +192,11 @@ void CTradeableItem::hover(bool on) switch(type) { - case CREATURE: - case CREATURE_PLACEHOLDER: + case EType::CREATURE: + case EType::CREATURE_PLACEHOLDER: GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated())); break; - case ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_PLACEHOLDER: if(id < 0) GH.statusbar()->write(CGI->generaltexth->zelp[582].first); else @@ -208,11 +209,11 @@ void CTradeableItem::showPopupWindow(const Point & cursorPosition) { switch(type) { - case CREATURE: - case CREATURE_PLACEHOLDER: + case EType::CREATURE: + case EType::CREATURE_PLACEHOLDER: break; - case ARTIFACT_TYPE: - case ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_TYPE: + case EType::ARTIFACT_PLACEHOLDER: //TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription. if (id >= 0) CRClickPopup::createAndPush(CGI->artifacts()->getByIndex(id)->getDescriptionTranslated()); @@ -224,17 +225,17 @@ std::string CTradeableItem::getName(int number) const { switch(type) { - case PLAYER: + case EType::PLAYER: return CGI->generaltexth->capColors[id]; - case RESOURCE: + case EType::RESOURCE: return CGI->generaltexth->restypes[id]; - case CREATURE: + case EType::CREATURE: if (number == 1) return CGI->creh->objects[id]->getNameSingularTranslated(); else return CGI->creh->objects[id]->getNamePluralTranslated(); - case ARTIFACT_TYPE: - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_TYPE: + case EType::ARTIFACT_INSTANCE: return CGI->artifacts()->getByIndex(id)->getNameTranslated(); } logGlobal->error("Invalid trade item type: %d", (int)type); @@ -245,8 +246,8 @@ const CArtifactInstance * CTradeableItem::getArtInstance() const { switch(type) { - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_PLACEHOLDER: + case EType::ARTIFACT_INSTANCE: return hlp; default: return nullptr; @@ -255,46 +256,49 @@ const CArtifactInstance * CTradeableItem::getArtInstance() const void CTradeableItem::setArtInstance(const CArtifactInstance * art) { - assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE); + assert(type == EType::ARTIFACT_PLACEHOLDER || type == EType::ARTIFACT_INSTANCE); hlp = art; if(art) - setID(art->artType->getId()); + setID(art->getTypeId()); else setID(-1); } -void STradePanel::updateSlots() +void TradePanelBase::updateSlots() { if(updateSlotsCallback) updateSlotsCallback(); } -void STradePanel::deselect() +void TradePanelBase::deselect() { - for(auto & slot : slots) + for(const auto & slot : slots) slot->selection->selectSlot(false); } -void STradePanel::clearSubtitles() +void TradePanelBase::clearSubtitles() { - for(auto & slot : slots) + for(const auto & slot : slots) slot->subtitle.clear(); } -void STradePanel::updateOffer(CTradeableItem & slot, int cost, int qty) +void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty) { slot.subtitle = std::to_string(qty); if(cost != 1) - slot.subtitle += "/" + std::to_string(cost); + { + slot.subtitle.append("/"); + slot.subtitle.append(std::to_string(cost)); + } } -void STradePanel::deleteSlots() +void TradePanelBase::deleteSlots() { if(deleteSlotsCheck) slots.erase(std::remove_if(slots.begin(), slots.end(), deleteSlotsCheck), slots.end()); } -SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles) +ResourcesPanel::ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles) { assert(resourcesForTrade.size() == slotsPos.size()); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); @@ -309,8 +313,8 @@ SResourcesPanel::SResourcesPanel(CTradeableItem::ClickPressedFunctor clickPresse updateSlotsCallback = updateSubtitles; } -SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, - std::vector & arts) +ArtifactsPanel::ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, + const std::vector & arts) { assert(slotsForTrade == slotsPos.size()); assert(slotsForTrade == arts.size()); @@ -330,9 +334,9 @@ SArtifactsPanel::SArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPresse updateSlotsCallback = updateSubtitles; } -SPlayersPanel::SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback) +PlayersPanel::PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback) { - assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size()); + assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size() + 1); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); std::vector players; @@ -349,37 +353,36 @@ SPlayersPanel::SPlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCal slot = std::make_shared(slotsPos[slotNum], EType::PLAYER, players[slotNum].num, false, slotNum); slot->clickPressedCallback = clickPressedCallback; slot->selection = std::make_unique(Rect(slotsPos[slotNum], slot->pos.dimensions()), Point(1, 1), selectionWidth); - slot->subtitle = CGI->generaltexth->capColors[players[slotNum++].num]; + slot->subtitle = CGI->generaltexth->capColors[players[slotNum].num]; + slotNum++; } } -SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, slotsData & initialSlots) +CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots) { assert(initialSlots.size() <= GameConstants::ARMY_SIZE); assert(slotsPos.size() <= GameConstants::ARMY_SIZE); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); - for(const auto & slotData : initialSlots) + for(const auto & [creatureId, slotId, creaturesNum] : initialSlots) { - auto slotId = std::get<1>(slotData); - auto creaturesNum = std::get<2>(slotData); auto slot = slots.emplace_back(std::make_shared(slotsPos[slotId.num], - creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, std::get<0>(slotData).num, true, slotId)); + creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, true, slotId)); slot->clickPressedCallback = clickPressedCallback; if(creaturesNum != 0) - slot->subtitle = std::to_string(std::get<2>(slotData)); + slot->subtitle = std::to_string(creaturesNum); slot->pos.w = 58; slot->pos.h = 64; slot->selection = std::make_unique(Rect(slotsPos[slotId.num], slot->pos.dimensions()), Point(1, 1), selectionWidth); } } -SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, - std::vector> & stsSlots, bool emptySlots) +CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, + const std::vector> & srcSlots, bool emptySlots) { assert(slots.size() <= GameConstants::ARMY_SIZE); OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); - for(const auto & srcSlot : stsSlots) + for(const auto & srcSlot : srcSlots) { auto slot = slots.emplace_back(std::make_shared(slotsPos[srcSlot->serial], emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, true, srcSlot->serial)); @@ -389,92 +392,3 @@ SCreaturesPanel::SCreaturesPanel(CTradeableItem::ClickPressedFunctor clickPresse slot->selection = std::make_unique(Rect(slotsPos[slot->serial], slot->pos.dimensions()), Point(1, 1), selectionWidth); } } - -CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) - : market(market) - , hero(hero) -{ - deal = std::make_shared(Point(), AnimationPath::builtin("ALTSACR.DEF"), - CGI->generaltexth->zelp[585], std::bind(&CTradeBase::makeDeal, this)); -} - -void CTradeBase::removeItems(const std::set> & toRemove) -{ - for(auto item : toRemove) - removeItem(item); -} - -void CTradeBase::removeItem(std::shared_ptr item) -{ - rightTradePanel->slots.erase(std::remove(rightTradePanel->slots.begin(), rightTradePanel->slots.end(), item)); - - if(hRight == item) - hRight.reset(); -} - -void CTradeBase::getEmptySlots(std::set> & toRemove) -{ - for(auto item : leftTradePanel->slots) - 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 & newSlot, std::shared_ptr & 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(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(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); - deal->moveBy(dealButtonPos); - expToLevel = std::make_shared(75, 477, FONT_SMALL, ETextAlignment::CENTER); - expForHero = std::make_shared(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([this](std::shared_ptr altarSlot) -> void - { - onSlotClickPressed(altarSlot, hLeft); - }, slots); -} - -bool CCreaturesSelling::slotDeletingCheck(std::shared_ptr & 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))); -} diff --git a/client/widgets/markets/TradePanels.h b/client/widgets/markets/TradePanels.h new file mode 100644 index 000000000..20a028ed4 --- /dev/null +++ b/client/widgets/markets/TradePanels.h @@ -0,0 +1,140 @@ +/* + * TradePanels.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 "../Images.h" + +#include "../../../lib/networkPacks/TradeItem.h" + +class CTextBox; +class SelectableSlot; + +enum class EType +{ + RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE +}; + +class CTradeableItem : public CIntObject, public std::enable_shared_from_this +{ +public: + std::shared_ptr image; + AnimationPath getFilename(); + int getIndex(); + using ClickPressedFunctor = std::function&)>; + + const CArtifactInstance * hlp; //holds ptr to artifact instance id type artifact + EType type; + int id; + const int serial; + const bool left; + std::string subtitle; + ClickPressedFunctor clickPressedCallback; + + void setType(EType newType); + void setID(int newID); + + const CArtifactInstance * getArtInstance() const; + void setArtInstance(const CArtifactInstance * art); + + std::unique_ptr selection; + bool downSelection; + + void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); + + void showPopupWindow(const Point & cursorPosition) override; + void hover(bool on) override; + void showAll(Canvas & to) override; + void clickPressed(const Point & cursorPosition) override; + std::string getName(int number = -1) const; + CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); +}; + +class TradePanelBase : public CIntObject +{ +public: + using UpdateSlotsFunctor = std::function; + using DeleteSlotsCheck = std::function&)>; + + std::vector> slots; + UpdateSlotsFunctor updateSlotsCallback; + DeleteSlotsCheck deleteSlotsCheck; + std::shared_ptr selected; + const int selectionWidth = 2; + + virtual void updateSlots(); + virtual void deselect(); + virtual void clearSubtitles(); + void updateOffer(CTradeableItem & slot, int, int); + void deleteSlots(); +}; + +class ResourcesPanel : public TradePanelBase +{ + const std::vector resourcesForTrade = + { + GameResID::WOOD, GameResID::MERCURY, GameResID::ORE, + GameResID::SULFUR, GameResID::CRYSTAL, GameResID::GEMS, + GameResID::GOLD + }; + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 79), Point(83, 79), Point(166, 79), + Point(83, 158) + }; + +public: + ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles); +}; + +class ArtifactsPanel : public TradePanelBase +{ + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 79), Point(83, 79), Point(166, 79), + Point(83, 158) + }; + const size_t slotsForTrade = 7; + +public: + ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, + const std::vector & arts); +}; + +class PlayersPanel : public TradePanelBase +{ + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 118), Point(83, 118), Point(166, 118), + Point(83, 236) + }; + +public: + explicit PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback); +}; + +class CreaturesPanel : public TradePanelBase +{ + const std::vector slotsPos = + { + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 98), Point(83, 98), Point(166, 98), + Point(83, 196) + }; + +public: + using slotsData = std::vector>; + + CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots); + CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, + const std::vector> & srcSlots, bool emptySlots = true); +}; diff --git a/client/windows/CAltarWindow.h b/client/windows/CAltarWindow.h index 02873228a..3084ebf35 100644 --- a/client/windows/CAltarWindow.h +++ b/client/windows/CAltarWindow.h @@ -9,7 +9,8 @@ */ #pragma once -#include "../widgets/CAltar.h" +#include "../widgets/markets/CAltarArtifacts.h" +#include "../widgets/markets/CAltarCreatures.h" #include "../widgets/CWindowWithArtifacts.h" #include "CWindowObject.h" @@ -28,7 +29,7 @@ public: private: const CGHeroInstance * hero; - std::shared_ptr altar; + std::shared_ptr altar; std::shared_ptr changeModeButton; std::shared_ptr quitButton; std::function windowClosedCallback; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index ee5558ddd..e5ff7ab63 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -47,24 +47,24 @@ void CTradeWindow::initTypes() switch(mode) { case EMarketMode::RESOURCE_RESOURCE: - itemsType[1] = RESOURCE; - itemsType[0] = RESOURCE; + itemsType[1] = EType::RESOURCE; + itemsType[0] = EType::RESOURCE; break; case EMarketMode::RESOURCE_PLAYER: - itemsType[1] = RESOURCE; - itemsType[0] = PLAYER; + itemsType[1] = EType::RESOURCE; + itemsType[0] = EType::PLAYER; break; case EMarketMode::CREATURE_RESOURCE: - itemsType[1] = CREATURE; - itemsType[0] = RESOURCE; + itemsType[1] = EType::CREATURE; + itemsType[0] = EType::RESOURCE; break; case EMarketMode::RESOURCE_ARTIFACT: - itemsType[1] = RESOURCE; - itemsType[0] = ARTIFACT_TYPE; + itemsType[1] = EType::RESOURCE; + itemsType[0] = EType::ARTIFACT_TYPE; break; case EMarketMode::ARTIFACT_RESOURCE: - itemsType[1] = ARTIFACT_INSTANCE; - itemsType[0] = RESOURCE; + itemsType[1] = EType::ARTIFACT_INSTANCE; + itemsType[0] = EType::RESOURCE; break; } } @@ -73,7 +73,7 @@ void CTradeWindow::initItems(bool Left) { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - if(Left && (itemsType[1] == ARTIFACT_TYPE || itemsType[1] == ARTIFACT_INSTANCE)) + if(Left && (itemsType[1] == EType::ARTIFACT_TYPE || itemsType[1] == EType::ARTIFACT_INSTANCE)) { if(mode == EMarketMode::ARTIFACT_RESOURCE) { @@ -84,13 +84,13 @@ void CTradeWindow::initItems(bool Left) } else { - auto updRightSub = [this](EMarketMode mode) -> void + auto updRightSub = [this](EMarketMode marketMode) { if(hLeft) - for(auto & slot : rightTradePanel->slots) + for(const auto & slot : rightTradePanel->slots) { int h1, h2; //hlp variables for getting offer - market->getOffer(hLeft->id, slot->id, h1, h2, mode); + market->getOffer(hLeft->id, slot->id, h1, h2, marketMode); rightTradePanel->updateOffer(*slot, h1, h2); } @@ -98,7 +98,7 @@ void CTradeWindow::initItems(bool Left) rightTradePanel->clearSubtitles(); }; - auto clickPressedTradePanel = [this](std::shared_ptr newSlot, bool left) + auto clickPressedTradePanel = [this](const std::shared_ptr & newSlot, bool left) { CTradeBase::onSlotClickPressed(newSlot, left ? hLeft : hRight); selectionChanged(left); @@ -106,25 +106,29 @@ void CTradeWindow::initItems(bool Left) if(Left && mode == EMarketMode::CREATURE_RESOURCE) { - SCreaturesPanel::slotsData slots; + CreaturesPanel::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(std::bind(clickPressedTradePanel, _1, true), slots); + leftTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, true), slots); leftTradePanel->moveBy(Point(45, 123)); - leftTradePanel->deleteSlotsCheck = [this](std::shared_ptr & slot) -> bool + leftTradePanel->deleteSlotsCheck = [this](const std::shared_ptr & slot) { return this->hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false; }; } else if(Left && (mode == EMarketMode::RESOURCE_RESOURCE || mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER)) { - leftTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, true), - [this]() -> void + leftTradePanel = std::make_shared( + [clickPressedTradePanel](const std::shared_ptr & newSlot) { - for(auto & slot : leftTradePanel->slots) + clickPressedTradePanel(newSlot, true); + }, + [this]() + { + for(const auto & slot : leftTradePanel->slots) slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast(slot->serial))); }); leftTradePanel->moveBy(Point(39, 182)); @@ -132,8 +136,12 @@ void CTradeWindow::initItems(bool Left) } else if(!Left && mode == EMarketMode::RESOURCE_RESOURCE) { - rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), - [this, updRightSub]() -> void + rightTradePanel = std::make_shared( + [clickPressedTradePanel](const std::shared_ptr & newSlot) + { + clickPressedTradePanel(newSlot, false); + }, + [this, updRightSub]() { updRightSub(EMarketMode::RESOURCE_RESOURCE); if(hLeft) @@ -143,23 +151,23 @@ void CTradeWindow::initItems(bool Left) } else if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE || mode == EMarketMode::CREATURE_RESOURCE)) { - rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), std::bind(updRightSub, EMarketMode::ARTIFACT_RESOURCE)); rightTradePanel->moveBy(Point(327, 181)); } else if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT) { - rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false), std::bind(updRightSub, EMarketMode::RESOURCE_ARTIFACT), market->availableItemsIds(mode)); rightTradePanel->moveBy(Point(327, 181)); - rightTradePanel->deleteSlotsCheck = [this](std::shared_ptr & slot) -> bool + rightTradePanel->deleteSlotsCheck = [this](const std::shared_ptr & slot) { return vstd::contains(market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT), ArtifactID(slot->id)) ? false : true; }; } else if(!Left && mode == EMarketMode::RESOURCE_PLAYER) { - rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false)); + rightTradePanel = std::make_shared(std::bind(clickPressedTradePanel, _1, false)); rightTradePanel->moveBy(Point(333, 83)); } } @@ -167,7 +175,7 @@ void CTradeWindow::initItems(bool Left) void CTradeWindow::initSubs(bool Left) { - if(itemsType[Left] == RESOURCE || itemsType[Left] == ARTIFACT_TYPE) + if(itemsType[Left] == EType::RESOURCE || itemsType[Left] == EType::ARTIFACT_TYPE) { if(Left) leftTradePanel->updateSlots(); @@ -464,9 +472,9 @@ void CMarketplaceWindow::selectionChanged(bool side) if(slider) { int newAmount = -1; - if(itemsType[1] == RESOURCE) + if(itemsType[1] == EType::RESOURCE) newAmount = LOCPLINT->cb->getResourceAmount(static_cast(soldItemId)); - else if(itemsType[1] == CREATURE) + else if(itemsType[1] == EType::CREATURE) newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1 && hero->needsLastStack()); else assert(0); @@ -476,7 +484,7 @@ void CMarketplaceWindow::selectionChanged(bool side) max->block(false); deal->block(false); } - else if(itemsType[1] == RESOURCE) //buying -> check if we can afford transaction + else if(itemsType[1] == EType::RESOURCE) //buying -> check if we can afford transaction { deal->block(LOCPLINT->cb->getResourceAmount(static_cast(soldItemId)) < r1); } @@ -494,7 +502,7 @@ void CMarketplaceWindow::selectionChanged(bool side) deal->block(true); } - if(side && itemsType[0] != PLAYER) //items[1] selection changed, recalculate offers + if(side && itemsType[0] != EType::PLAYER) //items[1] selection changed, recalculate offers initSubs(false); updateTraderText(); @@ -549,8 +557,8 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const { switch(itemsType[1]) { - case RESOURCE: - case CREATURE: + case EType::RESOURCE: + case EType::CREATURE: { int val = slider ? slider->getValue() * r1 @@ -558,7 +566,7 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const return std::to_string(val); } - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_INSTANCE: return ((deal->isBlocked()) ? "0" : "1"); } } @@ -566,14 +574,14 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const { switch(itemsType[0]) { - case RESOURCE: + case EType::RESOURCE: if(slider) return std::to_string( slider->getValue() * r2 ); else return std::to_string(r2); - case ARTIFACT_TYPE: + case EType::ARTIFACT_TYPE: return ((deal->isBlocked()) ? "0" : "1"); - case PLAYER: + case EType::PLAYER: return (hRight ? CGI->generaltexth->capColors[hRight->id] : ""); } } @@ -587,11 +595,11 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const { switch(itemsType[1]) { - case RESOURCE: + case EType::RESOURCE: return Point(122, 448); - case CREATURE: + case EType::CREATURE: return Point(128, 450); - case ARTIFACT_INSTANCE: + case EType::ARTIFACT_INSTANCE: return Point(134, 469); } } @@ -599,14 +607,14 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const { switch(itemsType[0]) { - case RESOURCE: + case EType::RESOURCE: if(mode == EMarketMode::ARTIFACT_RESOURCE) return Point(410, 471); else return Point(410, 448); - case ARTIFACT_TYPE: + case EType::ARTIFACT_TYPE: return Point(411, 449); - case PLAYER: + case EType::PLAYER: return Point(417, 451); } } diff --git a/client/windows/CTradeWindow.h b/client/windows/CTradeWindow.h index bfbb6bb46..68195144d 100644 --- a/client/windows/CTradeWindow.h +++ b/client/windows/CTradeWindow.h @@ -9,7 +9,7 @@ */ #pragma once -#include "../widgets/CTradeBase.h" +#include "../widgets/markets/CTradeBase.h" #include "../widgets/CWindowWithArtifacts.h" #include "CWindowObject.h" From b840cf3650bc246961dc34d4e8ad736944889df6 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Wed, 10 Jan 2024 18:01:34 +0200 Subject: [PATCH 8/9] suggested changes --- client/widgets/CArtifactHolder.h | 2 +- client/widgets/CArtifactsOfHeroMarket.cpp | 4 +- client/widgets/MiscWidgets.cpp | 8 +++- client/widgets/MiscWidgets.h | 5 ++- client/widgets/markets/CAltarArtifacts.cpp | 4 +- client/widgets/markets/CAltarCreatures.cpp | 2 + client/widgets/markets/CTradeBase.cpp | 11 ++--- client/widgets/markets/TradePanels.cpp | 52 +++++++++++----------- client/widgets/markets/TradePanels.h | 15 ++++--- client/windows/CTradeWindow.cpp | 2 +- 10 files changed, 55 insertions(+), 50 deletions(-) diff --git a/client/widgets/CArtifactHolder.h b/client/widgets/CArtifactHolder.h index 03baf60c4..c39cbdca7 100644 --- a/client/widgets/CArtifactHolder.h +++ b/client/widgets/CArtifactHolder.h @@ -29,7 +29,7 @@ public: virtual void artifactAssembled(const ArtifactLocation & artLoc)=0; }; -class CArtPlace : public LRClickableAreaWTextComp, public SelectableSlot +class CArtPlace : public SelectableSlot { public: using ClickFunctor = std::function; diff --git a/client/widgets/CArtifactsOfHeroMarket.cpp b/client/widgets/CArtifactsOfHeroMarket.cpp index fadc632cd..52e9828ed 100644 --- a/client/widgets/CArtifactsOfHeroMarket.cpp +++ b/client/widgets/CArtifactsOfHeroMarket.cpp @@ -21,9 +21,9 @@ CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position) std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1)); for(const auto & [slot, artPlace] : artWorn) - artPlace->selection->setBorderWidth(2); + artPlace->setSelectionWidth(2); for(auto artPlace : backpack) - artPlace->selection->setBorderWidth(2); + artPlace->setSelectionWidth(2); }; void CArtifactsOfHeroMarket::scrollBackpack(int offset) diff --git a/client/widgets/MiscWidgets.cpp b/client/widgets/MiscWidgets.cpp index 391304bd1..d70f24c31 100644 --- a/client/widgets/MiscWidgets.cpp +++ b/client/widgets/MiscWidgets.cpp @@ -705,9 +705,8 @@ void SimpleLine::showAll(Canvas & to) } SelectableSlot::SelectableSlot(Rect area, Point oversize, const int width) + : LRClickableAreaWTextComp(area) { - pos += area.topLeft(); - pos.w = area.w; pos.h = area.h; selection = std::make_unique( Rect(area.topLeft() - oversize, area.dimensions() + oversize * 2), Colors::TRANSPARENCY, Colors::YELLOW, width); selectSlot(false); @@ -732,3 +731,8 @@ bool SelectableSlot::isSelected() const { return selection->getDrawBorder(); } + +void SelectableSlot::setSelectionWidth(int width) +{ + selection->setBorderWidth(width); +} diff --git a/client/widgets/MiscWidgets.h b/client/widgets/MiscWidgets.h index 11172a4c5..534fd0d29 100644 --- a/client/widgets/MiscWidgets.h +++ b/client/widgets/MiscWidgets.h @@ -273,14 +273,15 @@ public: void showAll(Canvas & to) override; }; -class SelectableSlot : virtual public CIntObject +class SelectableSlot : public LRClickableAreaWTextComp { -public: std::unique_ptr selection; +public: SelectableSlot(Rect area, Point oversize, const int width); SelectableSlot(Rect area, Point oversize); SelectableSlot(Rect area, const int width = 1); void selectSlot(bool on); bool isSelected() const; + void setSelectionWidth(int width); }; diff --git a/client/widgets/markets/CAltarArtifacts.cpp b/client/widgets/markets/CAltarArtifacts.cpp index b59d08e2f..70ba7aa36 100644 --- a/client/widgets/markets/CAltarArtifacts.cpp +++ b/client/widgets/markets/CAltarArtifacts.cpp @@ -31,6 +31,8 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * { OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + deal = std::make_shared(dealButtonPos, AnimationPath::builtin("ALTSACR.DEF"), + CGI->generaltexth->zelp[585], [this]() {CAltarArtifacts::makeDeal(); }); labels.emplace_back(std::make_shared(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477])); labels.emplace_back(std::make_shared(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478])); selectedCost = std::make_shared(302, 500, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); @@ -50,7 +52,7 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * int slotNum = 0; for(auto & altarSlotPos : posSlotsAltar) { - auto altarSlot = std::make_shared(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum); + auto altarSlot = std::make_shared(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum); altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1, hRight); altarSlot->subtitle.clear(); items.front().emplace_back(altarSlot); diff --git a/client/widgets/markets/CAltarCreatures.cpp b/client/widgets/markets/CAltarCreatures.cpp index 84b5f05f8..908ce602e 100644 --- a/client/widgets/markets/CAltarCreatures.cpp +++ b/client/widgets/markets/CAltarCreatures.cpp @@ -30,6 +30,8 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + deal = std::make_shared(dealButtonPos, AnimationPath::builtin("ALTSACR.DEF"), + CGI->generaltexth->zelp[584], [this]() {CAltarCreatures::makeDeal();}); labels.emplace_back(std::make_shared(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated()))); labels.emplace_back(std::make_shared(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479])); diff --git a/client/widgets/markets/CTradeBase.cpp b/client/widgets/markets/CTradeBase.cpp index 226799f3c..2dacc01e2 100644 --- a/client/widgets/markets/CTradeBase.cpp +++ b/client/widgets/markets/CTradeBase.cpp @@ -25,8 +25,6 @@ CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) : market(market) , hero(hero) { - deal = std::make_shared(Point(), AnimationPath::builtin("ALTSACR.DEF"), - CGI->generaltexth->zelp[585], std::bind(&CTradeBase::makeDeal, this)); } void CTradeBase::removeItems(const std::set> & toRemove) @@ -53,9 +51,9 @@ void CTradeBase::getEmptySlots(std::set> & toRem void CTradeBase::deselect() { if(hLeft) - hLeft->selection->selectSlot(false); + hLeft->selectSlot(false); if(hRight) - hRight->selection->selectSlot(false); + hRight->selectSlot(false); hLeft = hRight = nullptr; deal->block(true); } @@ -66,9 +64,9 @@ void CTradeBase::onSlotClickPressed(const std::shared_ptr & newS return; if(hCurSlot) - hCurSlot->selection->selectSlot(false); + hCurSlot->selectSlot(false); hCurSlot = newSlot; - newSlot->selection->selectSlot(true); + newSlot->selectSlot(true); } CExperienceAltar::CExperienceAltar() @@ -79,7 +77,6 @@ CExperienceAltar::CExperienceAltar() texts.emplace_back(std::make_shared(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(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); - deal->moveBy(dealButtonPos); expToLevel = std::make_shared(75, 477, FONT_SMALL, ETextAlignment::CENTER); expForHero = std::make_shared(75, 545, FONT_SMALL, ETextAlignment::CENTER); } diff --git a/client/widgets/markets/TradePanels.cpp b/client/widgets/markets/TradePanels.cpp index b2ac2b9f9..16a48eb2f 100644 --- a/client/widgets/markets/TradePanels.cpp +++ b/client/widgets/markets/TradePanels.cpp @@ -10,8 +10,6 @@ #include "StdInc.h" #include "TradePanels.h" -#include "../MiscWidgets.h" - #include "../../gui/CGuiHandler.h" #include "../../render/Canvas.h" #include "../../widgets/TextControls.h" @@ -25,9 +23,9 @@ #include "../../../lib/CGeneralTextHandler.h" #include "../../../lib/mapObjects/CGHeroInstance.h" -CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial) - : CIntObject(LCLICK | HOVER | SHOW_POPUP, pos) - , hlp(nullptr) +CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, bool Left, int Serial) + : SelectableSlot(area, Point(1, 1)) + , artInstance(nullptr) , type(EType(-1)) // set to invalid, will be corrected in setType , id(ID) , serial(Serial) @@ -35,13 +33,15 @@ CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Ser , downSelection(false) { OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + + addUsedEvents(LCLICK); + addUsedEvents(HOVER); + addUsedEvents(SHOW_POPUP); setType(Type); - if(image) - { - this->pos.w = image->pos.w; - this->pos.h = image->pos.h; - } + + this->pos.w = area.w; + this->pos.h = area.h; } void CTradeableItem::setType(EType newType) @@ -248,7 +248,7 @@ const CArtifactInstance * CTradeableItem::getArtInstance() const { case EType::ARTIFACT_PLACEHOLDER: case EType::ARTIFACT_INSTANCE: - return hlp; + return artInstance; default: return nullptr; } @@ -257,7 +257,7 @@ const CArtifactInstance * CTradeableItem::getArtInstance() const void CTradeableItem::setArtInstance(const CArtifactInstance * art) { assert(type == EType::ARTIFACT_PLACEHOLDER || type == EType::ARTIFACT_INSTANCE); - hlp = art; + artInstance = art; if(art) setID(art->getTypeId()); else @@ -273,7 +273,7 @@ void TradePanelBase::updateSlots() void TradePanelBase::deselect() { for(const auto & slot : slots) - slot->selection->selectSlot(false); + slot->selectSlot(false); } void TradePanelBase::clearSubtitles() @@ -305,10 +305,10 @@ ResourcesPanel::ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedC for(const auto & res : resourcesForTrade) { - auto slot = slots.emplace_back(std::make_shared(slotsPos[res.num], EType::RESOURCE, res.num, true, res.num)); + auto slot = slots.emplace_back(std::make_shared(Rect(slotsPos[res.num], slotDimension), + EType::RESOURCE, res.num, true, res.num)); slot->clickPressedCallback = clickPressedCallback; - slot->pos.w = 69; slots.back()->pos.h = 66; - slot->selection = std::make_unique(Rect(slotsPos[res.num], slots.back()->pos.dimensions()), Point(1, 1), selectionWidth); + slot->setSelectionWidth(selectionWidth); } updateSlotsCallback = updateSubtitles; } @@ -325,10 +325,10 @@ ArtifactsPanel::ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedC auto artType = arts[slotIdx].getNum(); if(artType != ArtifactID::NONE) { - auto slot = slots.emplace_back(std::make_shared(slotsPos[slotIdx], EType::ARTIFACT_TYPE, artType, false, slotIdx)); + auto slot = slots.emplace_back(std::make_shared(Rect(slotsPos[slotIdx], slotDimension), + EType::ARTIFACT_TYPE, artType, false, slotIdx)); slot->clickPressedCallback = clickPressedCallback; - slot->pos.w = 69; slot->pos.h = 66; - slot->selection = std::make_unique(Rect(slotsPos[slotIdx], slot->pos.dimensions()), Point(1, 1), selectionWidth); + slot->setSelectionWidth(selectionWidth); } } updateSlotsCallback = updateSubtitles; @@ -350,9 +350,9 @@ PlayersPanel::PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallb int slotNum = 0; for(auto & slot : slots) { - slot = std::make_shared(slotsPos[slotNum], EType::PLAYER, players[slotNum].num, false, slotNum); + slot = std::make_shared(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, false, slotNum); slot->clickPressedCallback = clickPressedCallback; - slot->selection = std::make_unique(Rect(slotsPos[slotNum], slot->pos.dimensions()), Point(1, 1), selectionWidth); + slot->setSelectionWidth(selectionWidth); slot->subtitle = CGI->generaltexth->capColors[players[slotNum].num]; slotNum++; } @@ -366,13 +366,12 @@ CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedC for(const auto & [creatureId, slotId, creaturesNum] : initialSlots) { - auto slot = slots.emplace_back(std::make_shared(slotsPos[slotId.num], + auto slot = slots.emplace_back(std::make_shared(Rect(slotsPos[slotId.num], slotDimension), creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, true, slotId)); slot->clickPressedCallback = clickPressedCallback; if(creaturesNum != 0) slot->subtitle = std::to_string(creaturesNum); - slot->pos.w = 58; slot->pos.h = 64; - slot->selection = std::make_unique(Rect(slotsPos[slotId.num], slot->pos.dimensions()), Point(1, 1), selectionWidth); + slot->setSelectionWidth(selectionWidth); } } @@ -384,11 +383,10 @@ CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedC for(const auto & srcSlot : srcSlots) { - auto slot = slots.emplace_back(std::make_shared(slotsPos[srcSlot->serial], + auto slot = slots.emplace_back(std::make_shared(Rect(slotsPos[srcSlot->serial], srcSlot->pos.dimensions()), 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(Rect(slotsPos[slot->serial], slot->pos.dimensions()), Point(1, 1), selectionWidth); + slot->setSelectionWidth(selectionWidth); } } diff --git a/client/widgets/markets/TradePanels.h b/client/widgets/markets/TradePanels.h index 20a028ed4..23bc1b336 100644 --- a/client/widgets/markets/TradePanels.h +++ b/client/widgets/markets/TradePanels.h @@ -9,19 +9,17 @@ */ #pragma once +#include "../MiscWidgets.h" #include "../Images.h" #include "../../../lib/networkPacks/TradeItem.h" -class CTextBox; -class SelectableSlot; - enum class EType { RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE }; -class CTradeableItem : public CIntObject, public std::enable_shared_from_this +class CTradeableItem : public SelectableSlot, public std::enable_shared_from_this { public: std::shared_ptr image; @@ -29,7 +27,7 @@ public: int getIndex(); using ClickPressedFunctor = std::function&)>; - const CArtifactInstance * hlp; //holds ptr to artifact instance id type artifact + const CArtifactInstance * artInstance; //holds ptr to artifact instance id type artifact EType type; int id; const int serial; @@ -43,7 +41,6 @@ public: const CArtifactInstance * getArtInstance() const; void setArtInstance(const CArtifactInstance * art); - std::unique_ptr selection; bool downSelection; void showAllAt(const Point & dstPos, const std::string & customSub, Canvas & to); @@ -53,7 +50,7 @@ public: void showAll(Canvas & to) override; void clickPressed(const Point & cursorPosition) override; std::string getName(int number = -1) const; - CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial); + CTradeableItem(const Rect & area, EType Type, int ID, bool Left, int Serial); }; class TradePanelBase : public CIntObject @@ -89,6 +86,7 @@ class ResourcesPanel : public TradePanelBase Point(0, 79), Point(83, 79), Point(166, 79), Point(83, 158) }; + const Point slotDimension = Point(69, 66); public: ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles); @@ -103,6 +101,7 @@ class ArtifactsPanel : public TradePanelBase Point(83, 158) }; const size_t slotsForTrade = 7; + const Point slotDimension = Point(69, 66); public: ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles, @@ -117,6 +116,7 @@ class PlayersPanel : public TradePanelBase Point(0, 118), Point(83, 118), Point(166, 118), Point(83, 236) }; + const Point slotDimension = Point(58, 64); public: explicit PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback); @@ -130,6 +130,7 @@ class CreaturesPanel : public TradePanelBase Point(0, 98), Point(83, 98), Point(166, 98), Point(83, 196) }; + const Point slotDimension = Point(58, 64); public: using slotsData = std::vector>; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index e5ff7ab63..6243ed634 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -77,7 +77,7 @@ void CTradeWindow::initItems(bool Left) { if(mode == EMarketMode::ARTIFACT_RESOURCE) { - auto item = std::make_shared(Point(137, 469), itemsType[Left], -1, 1, 0); + auto item = std::make_shared(Rect(Point(137, 469), Point()), itemsType[Left], -1, 1, 0); item->recActions &= ~(UPDATE | SHOWALL); items[Left].push_back(item); } From 4df7de36c11c8d7779e06029e89b5839831d0816 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:52:12 +0200 Subject: [PATCH 9/9] fixed regression --- client/widgets/markets/CAltarCreatures.cpp | 2 ++ client/widgets/markets/CTradeBase.cpp | 5 +---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/client/widgets/markets/CAltarCreatures.cpp b/client/widgets/markets/CAltarCreatures.cpp index 908ce602e..66161e2f7 100644 --- a/client/widgets/markets/CAltarCreatures.cpp +++ b/client/widgets/markets/CAltarCreatures.cpp @@ -51,6 +51,8 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * assert(leftTradePanel); leftTradePanel->moveBy(Point(45, 110)); leftTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this); + for(const auto & slot : leftTradePanel->slots) + slot->clickPressedCallback = [this](const std::shared_ptr & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, hLeft);}; // Altar creatures panel rightTradePanel = std::make_shared([this](const std::shared_ptr & altarSlot) diff --git a/client/widgets/markets/CTradeBase.cpp b/client/widgets/markets/CTradeBase.cpp index 2dacc01e2..62f792862 100644 --- a/client/widgets/markets/CTradeBase.cpp +++ b/client/widgets/markets/CTradeBase.cpp @@ -90,10 +90,7 @@ CCreaturesSelling::CCreaturesSelling() if(const auto & creature = hero->getCreature(slotId)) slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId))); } - leftTradePanel = std::make_shared([this](const std::shared_ptr & altarSlot) - { - CTradeBase::onSlotClickPressed(altarSlot, hLeft); - }, slots); + leftTradePanel = std::make_shared(nullptr, slots); } bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr & slot)