diff --git a/client/render/AssetGenerator.cpp b/client/render/AssetGenerator.cpp index 30c59e5cb..7eddde407 100644 --- a/client/render/AssetGenerator.cpp +++ b/client/render/AssetGenerator.cpp @@ -57,6 +57,22 @@ void AssetGenerator::initialize() imageFiles[ImagePath::builtin(name)] = [this, color](){ return createResBarElement(std::max(PlayerColor(0), color));}; } + for (PlayerColor color(-1); color < PlayerColor::PLAYER_LIMIT; ++color) + { + for(int amount : { 8, 9 }) + { + auto addResWindow = [this, amount, color](std::string baseName, CreateResourceWindowType type){ + std::string name = baseName + "-R" + std::to_string(amount) + (color == -1 ? "" : "-" + color.toString()); + imageFiles[ImagePath::builtin(name)] = [this, color, amount, type](){ return createResourceWindow(type, amount, std::max(PlayerColor(0), color)); }; + }; + addResWindow("TPMRKABS", CreateResourceWindowType::ARTIFACTS_BUYING); + addResWindow("TPMRKASS", CreateResourceWindowType::ARTIFACTS_SELLING); + addResWindow("TPMRKRES", CreateResourceWindowType::MARKET_RESOURCES); + addResWindow("TPMRKCRS", CreateResourceWindowType::FREELANCERS_GUILD); + addResWindow("TPMRKPTS", CreateResourceWindowType::TRANSFER_RESOURCES); + } + } + imageFiles[ImagePath::builtin("stackWindow/info-panel-0.png")] = [this](){ return createCreatureInfoPanel(2);}; imageFiles[ImagePath::builtin("stackWindow/info-panel-1.png")] = [this](){ return createCreatureInfoPanel(3);}; imageFiles[ImagePath::builtin("stackWindow/info-panel-2.png")] = [this](){ return createCreatureInfoPanel(4);}; @@ -669,6 +685,65 @@ AssetGenerator::CanvasPtr AssetGenerator::createCreatureInfoPanel(int boxesAmoun return image; } +AssetGenerator::CanvasPtr AssetGenerator::createResourceWindow(CreateResourceWindowType type, int count, PlayerColor color) const +{ + assert(count >= 8 && count <= 9); + + const std::map files = { + { ARTIFACTS_BUYING, ImagePath::builtin("TPMRKABS") }, + { ARTIFACTS_SELLING, ImagePath::builtin("TPMRKASS") }, + { MARKET_RESOURCES, ImagePath::builtin("TPMRKRES") }, + { FREELANCERS_GUILD, ImagePath::builtin("TPMRKCRS") }, + { TRANSFER_RESOURCES, ImagePath::builtin("TPMRKPTS") } + }; + + auto file = files.at(type); + auto locator = ImageLocator(file, EImageBlitMode::COLORKEY); + std::shared_ptr baseImg = ENGINE->renderHandler().loadImage(locator); + baseImg->playerColored(color); + + auto image = ENGINE->renderHandler().createImage(baseImg->dimensions(), CanvasScalingPolicy::IGNORE); + Canvas canvas = image->getCanvas(); + canvas.draw(baseImg, Point(0, 0)); + + auto drawBox = [&canvas, &baseImg](bool left, bool one){ + if(left) + { + canvas.draw(baseImg, Point(38, 339), Rect(121, 339, 71, 69)); + if(!one) + canvas.draw(baseImg, Point(204, 339), Rect(121, 339, 71, 69)); + } + else + { + canvas.draw(baseImg, Point(325, 339), Rect(408, 339, 71, 69)); + if(!one) + canvas.draw(baseImg, Point(491, 339), Rect(408, 339, 71, 69)); + } + }; + + switch (type) + { + case ARTIFACTS_BUYING: + drawBox(true, count == 8); + break; + case ARTIFACTS_SELLING: + drawBox(false, count == 8); + break; + case MARKET_RESOURCES: + drawBox(true, count == 8); + drawBox(false, count == 8); + break; + case FREELANCERS_GUILD: + drawBox(false, count == 8); + break; + case TRANSFER_RESOURCES: + drawBox(true, count == 8); + break; + } + + return image; +} + AssetGenerator::CanvasPtr AssetGenerator::createCreatureInfoPanelElement(CreatureInfoPanelElement element) const { std::map size { diff --git a/client/render/AssetGenerator.h b/client/render/AssetGenerator.h index 54e955253..d0a95cc9a 100644 --- a/client/render/AssetGenerator.h +++ b/client/render/AssetGenerator.h @@ -60,6 +60,8 @@ private: CanvasPtr createPaletteShiftedImage(const AnimationPath & source, const std::vector & animation, int frameIndex, int paletteShiftCounter) const; CanvasPtr createAdventureMapButtonClear(const PlayerColor & player, bool small) const; CanvasPtr createCreatureInfoPanel(int boxesAmount) const; + enum CreateResourceWindowType{ ARTIFACTS_BUYING, ARTIFACTS_SELLING, MARKET_RESOURCES, FREELANCERS_GUILD, TRANSFER_RESOURCES }; + CanvasPtr createResourceWindow(CreateResourceWindowType type, int count, PlayerColor color) const; enum CreatureInfoPanelElement{ BONUS_EFFECTS, SPELL_EFFECTS, BUTTON_PANEL, COMMANDER_BACKGROUND, COMMANDER_ABILITIES }; CanvasPtr createCreatureInfoPanelElement(CreatureInfoPanelElement element) const; CanvasPtr createQuestWindow() const; diff --git a/client/widgets/markets/CMarketBase.cpp b/client/widgets/markets/CMarketBase.cpp index f318ed566..afe95f0e0 100644 --- a/client/widgets/markets/CMarketBase.cpp +++ b/client/widgets/markets/CMarketBase.cpp @@ -46,7 +46,8 @@ void CMarketBase::deselect() offerTradePanel->highlightedSlot->selectSlot(false); offerTradePanel->highlightedSlot.reset(); } - deal->block(true); + if(deal) + deal->block(true); bidQty = 0; offerQty = 0; updateShowcases(); @@ -54,7 +55,12 @@ void CMarketBase::deselect() void CMarketBase::onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & curPanel) { - assert(newSlot); + if(!newSlot) + { + deselect(); + return; + } + assert(curPanel); if(newSlot == curPanel->highlightedSlot) return; @@ -81,13 +87,14 @@ void CMarketBase::updateSubtitlesForBid(EMarketMode marketMode, int bidId) } else { - for(const auto & slot : offerTradePanel->slots) - { - int slotBidQty = 0; - int slotOfferQty = 0; - market->getOffer(bidId, slot->id, slotBidQty, slotOfferQty, marketMode); - offerTradePanel->updateOffer(*slot, slotBidQty, slotOfferQty); - } + if(offerTradePanel) + for(const auto & slot : offerTradePanel->slots) + { + int slotBidQty = 0; + int slotOfferQty = 0; + market->getOffer(bidId, slot->id, slotBidQty, slotOfferQty, marketMode); + offerTradePanel->updateOffer(*slot, slotBidQty, slotOfferQty); + } } }; @@ -120,6 +127,11 @@ void CMarketBase::highlightingChanged() updateShowcases(); } +CMarketBase::MarketShowcasesParams CMarketBase::getShowcasesParams() const +{ + return {}; +} + CExperienceAltar::CExperienceAltar() { OBJECT_CONSTRUCTION; @@ -164,8 +176,9 @@ bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr void CCreaturesSelling::updateSubtitles() const { - for(const auto & heroSlot : bidTradePanel->slots) - heroSlot->subtitle->setText(std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)))); + if(bidTradePanel) + for(const auto & heroSlot : bidTradePanel->slots) + heroSlot->subtitle->setText(std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)))); } CResourcesBuying::CResourcesBuying(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, @@ -188,8 +201,9 @@ CResourcesSelling::CResourcesSelling(const CTradeableItem::ClickPressedFunctor & void CResourcesSelling::updateSubtitles() const { - for(const auto & slot : bidTradePanel->slots) - slot->subtitle->setText(std::to_string(GAME->interface()->cb->getResourceAmount(static_cast(slot->serial)))); + if(bidTradePanel) + for(const auto & slot : bidTradePanel->slots) + slot->subtitle->setText(std::to_string(GAME->interface()->cb->getResourceAmount(static_cast(slot->serial)))); } CMarketSlider::CMarketSlider(const CSlider::SliderMovingFunctor & movingCallback) @@ -197,6 +211,7 @@ CMarketSlider::CMarketSlider(const CSlider::SliderMovingFunctor & movingCallback OBJECT_CONSTRUCTION; offerSlider = std::make_shared(Point(230, 489), 137, movingCallback, 0, 0, 0, Orientation::HORIZONTAL); + offerSlider->setScrollBounds(Rect(-215, -50, 575, 120)); maxAmount = std::make_shared(Point(228, 520), AnimationPath::builtin("IRCBTNS.DEF"), LIBRARY->generaltexth->zelp[596], [this]() { diff --git a/client/widgets/markets/CMarketBase.h b/client/widgets/markets/CMarketBase.h index 0b581b354..3abd16dab 100644 --- a/client/widgets/markets/CMarketBase.h +++ b/client/widgets/markets/CMarketBase.h @@ -58,7 +58,7 @@ protected: virtual void onSlotClickPressed(const std::shared_ptr & newSlot, std::shared_ptr & curPanel); virtual void updateSubtitlesForBid(EMarketMode marketMode, int bidId); virtual void updateShowcases(); - virtual MarketShowcasesParams getShowcasesParams() const = 0; + virtual MarketShowcasesParams getShowcasesParams() const; virtual void highlightingChanged(); }; diff --git a/client/widgets/markets/CMarketResources.cpp b/client/widgets/markets/CMarketResources.cpp index e82fb6ca1..f5660b063 100644 --- a/client/widgets/markets/CMarketResources.cpp +++ b/client/widgets/markets/CMarketResources.cpp @@ -98,8 +98,10 @@ void CMarketResources::highlightingChanged() void CMarketResources::updateSubtitles() { CMarketBase::updateSubtitlesForBid(EMarketMode::RESOURCE_RESOURCE, bidTradePanel->getHighlightedItemId()); - if(bidTradePanel->highlightedSlot) - offerTradePanel->slots[bidTradePanel->highlightedSlot->serial]->subtitle->setText(LIBRARY->generaltexth->allTexts[164]); // n/a + if(bidTradePanel && bidTradePanel->highlightedSlot) + for(auto & slot : offerTradePanel->slots) + if(slot->id == bidTradePanel->highlightedSlot->id) + slot->subtitle->setText(LIBRARY->generaltexth->allTexts[164]); // n/a } std::string CMarketResources::getTraderText() diff --git a/client/widgets/markets/TradePanels.cpp b/client/widgets/markets/TradePanels.cpp index bb6a35212..eeb87b80d 100644 --- a/client/widgets/markets/TradePanels.cpp +++ b/client/widgets/markets/TradePanels.cpp @@ -13,6 +13,7 @@ #include "../../GameEngine.h" #include "../../GameInstance.h" #include "../../render/Canvas.h" +#include "../../widgets/Slider.h" #include "../../widgets/TextControls.h" #include "../../windows/InfoWindows.h" @@ -262,20 +263,50 @@ bool TradePanelBase::isHighlighted() const ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const UpdateSlotsFunctor & updateSubtitles) + : clickPressedCallback(std::move(clickPressedCallback)) { - assert(resourcesForTrade.size() == slotsPos.size()); OBJECT_CONSTRUCTION; - for(const auto & res : resourcesForTrade) + resourcesForTrade = LIBRARY->resourceTypeHandler->getAllObjects(); + + int lines = vstd::divideAndCeil(resourcesForTrade.size(), 3); + if(lines > 3) { - auto slot = slots.emplace_back(std::make_shared(Rect(slotsPos[res.num], slotDimension), EType::RESOURCE, res.num, res.num)); - slot->clickPressedCallback = clickPressedCallback; - slot->setSelectionWidth(selectionWidth); + slider = std::make_shared(Point(240, 0), 224, [this](int to){ updateSlots(to); setRedrawParent(true); redraw(); }, 3, lines, 0, Orientation::VERTICAL, CSlider::BROWN); + slider->setPanningStep(72); + slider->setScrollBounds(Rect(-240, 0, 240, 224)); } - updateSlotsCallback = updateSubtitles; + + updateSlotsCallback = std::move(updateSubtitles); + + updateSlots(0); showcaseSlot = std::make_shared(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0); } +void ResourcesPanel::updateSlots(int line) +{ + OBJECT_CONSTRUCTION; + + clickPressedCallback(nullptr); + + int offset = line * 3; + slots.clear(); + for (int i = 0; i < std::min(static_cast(resourcesForTrade.size() - offset), 9); i++) + { + const auto& res = resourcesForTrade[i + offset]; + auto slotPos = slotsPos[i]; + if(resourcesForTrade.size() == 7 && i == 6) // for 7 ressources place gold in the middle + slotPos = slotsPos[i + 1]; + + auto slotPtr = std::make_shared(Rect(slotPos, slotDimension), EType::RESOURCE, res.num, res.num); + slotPtr->clickPressedCallback = clickPressedCallback; + slotPtr->setSelectionWidth(selectionWidth); + slots.push_back(slotPtr); + } + + updateSlotsCallback(); +} + ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const UpdateSlotsFunctor & updateSubtitles, const std::vector & arts) { diff --git a/client/widgets/markets/TradePanels.h b/client/widgets/markets/TradePanels.h index 3e2610106..007f88d3f 100644 --- a/client/widgets/markets/TradePanels.h +++ b/client/widgets/markets/TradePanels.h @@ -14,6 +14,8 @@ #include "../../../lib/networkPacks/TradeItem.h" +class CSlider; + enum class EType { RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, ARTIFACT @@ -68,21 +70,21 @@ public: 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) + Point(0, 0), Point(83, 0), Point(166, 0), + Point(0, 79), Point(83, 79), Point(166, 79), + Point(0, 158), Point(83, 158), Point(166, 158) }; const Point slotDimension = Point(69, 66); const Point selectedPos = Point(83, 267); + CTradeableItem::ClickPressedFunctor clickPressedCallback; + + std::vector resourcesForTrade; + std::shared_ptr slider; + + void updateSlots(int line); public: ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const UpdateSlotsFunctor & updateSubtitles); }; diff --git a/client/windows/CMarketWindow.cpp b/client/windows/CMarketWindow.cpp index 95b567905..cf4b7264d 100644 --- a/client/windows/CMarketWindow.cpp +++ b/client/windows/CMarketWindow.cpp @@ -30,6 +30,7 @@ #include "../../lib/GameLibrary.h" #include "../../lib/callback/CCallback.h" #include "../../lib/entities/building/CBuilding.h" +#include "../../lib/entities/ResourceTypeHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGMarket.h" #include "../../lib/mapObjects/CGTownInstance.h" @@ -200,11 +201,23 @@ std::string CMarketWindow::getMarketTitle(const ObjectInstanceID marketId, const return GAME->interface()->cb->getObj(marketId)->getObjectName(); } +ImagePath CMarketWindow::getImagePathBasedOnResources(std::string name) +{ + int res = LIBRARY->resourceTypeHandler->getAllObjects().size(); + if(res == 8) + name += "-R8"; + else if(res > 8) + name += "-R9"; + return ImagePath::builtin(name); +} + void CMarketWindow::createArtifactsBuying(const IMarket * market, const CGHeroInstance * hero) { OBJECT_CONSTRUCTION; - background = createBg(ImagePath::builtin("TPMRKABS.bmp"), PLAYER_COLORED); + auto image = getImagePathBasedOnResources("TPMRKABS"); + + background = createBg(image, PLAYER_COLORED); marketWidget = std::make_shared(market, hero, getMarketTitle(market->getObjInstanceID(), EMarketMode::RESOURCE_ARTIFACT)); initWidgetInternals(EMarketMode::RESOURCE_ARTIFACT, LIBRARY->generaltexth->zelp[600]); } @@ -213,7 +226,9 @@ void CMarketWindow::createArtifactsSelling(const IMarket * market, const CGHeroI { OBJECT_CONSTRUCTION; - background = createBg(ImagePath::builtin("TPMRKASS.bmp"), PLAYER_COLORED); + auto image = getImagePathBasedOnResources("TPMRKASS"); + + background = createBg(image, PLAYER_COLORED); // Create image that copies part of background containing slot MISC_1 into position of slot MISC_5 artSlotBack = std::make_shared(background->getSurface(), Rect(20, 187, 47, 47), 0, 0); artSlotBack->moveTo(pos.topLeft() + Point(18, 339)); @@ -229,7 +244,9 @@ void CMarketWindow::createMarketResources(const IMarket * market, const CGHeroIn { OBJECT_CONSTRUCTION; - background = createBg(ImagePath::builtin("TPMRKRES.bmp"), PLAYER_COLORED); + auto image = getImagePathBasedOnResources("TPMRKRES"); + + background = createBg(image, PLAYER_COLORED); marketWidget = std::make_shared(market, hero); initWidgetInternals(EMarketMode::RESOURCE_RESOURCE, LIBRARY->generaltexth->zelp[600]); } @@ -238,7 +255,9 @@ void CMarketWindow::createFreelancersGuild(const IMarket * market, const CGHeroI { OBJECT_CONSTRUCTION; - background = createBg(ImagePath::builtin("TPMRKCRS.bmp"), PLAYER_COLORED); + auto image = getImagePathBasedOnResources("TPMRKCRS"); + + background = createBg(image, PLAYER_COLORED); marketWidget = std::make_shared(market, hero); initWidgetInternals(EMarketMode::CREATURE_RESOURCE, LIBRARY->generaltexth->zelp[600]); } @@ -247,7 +266,9 @@ void CMarketWindow::createTransferResources(const IMarket * market, const CGHero { OBJECT_CONSTRUCTION; - background = createBg(ImagePath::builtin("TPMRKPTS.bmp"), PLAYER_COLORED); + auto image = getImagePathBasedOnResources("TPMRKPTS"); + + background = createBg(image, PLAYER_COLORED); marketWidget = std::make_shared(market, hero); initWidgetInternals(EMarketMode::RESOURCE_PLAYER, LIBRARY->generaltexth->zelp[600]); } diff --git a/client/windows/CMarketWindow.h b/client/windows/CMarketWindow.h index f2874918e..6707aacdd 100644 --- a/client/windows/CMarketWindow.h +++ b/client/windows/CMarketWindow.h @@ -38,6 +38,8 @@ private: void createAltarArtifacts(const IMarket * market, const CGHeroInstance * hero); void createAltarCreatures(const IMarket * market, const CGHeroInstance * hero); + ImagePath getImagePathBasedOnResources(std::string name); + const int buttonHeightWithMargin = 32 + 3; std::vector> changeModeButtons; std::shared_ptr quitButton;