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] 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"