From fbe3e0fe1234002b2dee859119605896a245b862 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sat, 4 Nov 2023 22:15:03 +0200 Subject: [PATCH 1/5] CArtPlace preparation --- client/widgets/CArtifactHolder.cpp | 102 +++++++--------------- client/widgets/CArtifactHolder.h | 39 +++------ client/widgets/CArtifactsOfHeroBase.h | 2 + client/widgets/CArtifactsOfHeroMarket.cpp | 2 +- 4 files changed, 49 insertions(+), 96 deletions(-) diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index c4440aaef..3a9bfc10f 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -75,12 +75,26 @@ 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) + : ourArt(art) + , locked(false) { - image = nullptr; pos += position; pos.w = pos.h = 44; + + OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + + imageIndex = 0; + if(locked) + imageIndex = ArtifactID::ART_LOCK; + else if(ourArt) + imageIndex = ourArt->artType->getIconIndex(); + + image = std::make_shared(AnimationPath::builtin("artifact"), imageIndex); + image->disable(); + + selection = std::make_shared(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION); + selection->visible = false; } const CArtifactInstance * CArtPlace::getArt() @@ -88,26 +102,12 @@ const CArtifactInstance * CArtPlace::getArt() return ourArt; } -CCommanderArtPlace::CCommanderArtPlace(Point position, const CGHeroInstance * commanderOwner, ArtifactPosition artSlot, const CArtifactInstance * Art) - : CArtPlace(position, Art), +CCommanderArtPlace::CCommanderArtPlace(Point position, const CGHeroInstance * commanderOwner, ArtifactPosition artSlot, const CArtifactInstance * art) + : CArtPlace(position, art), commanderOwner(commanderOwner), commanderSlotID(artSlot.num) { - createImage(); - setArtifact(Art); -} - -void CCommanderArtPlace::createImage() -{ - OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); - - imageIndex = 0; - if(ourArt) - imageIndex = ourArt->artType->getIconIndex(); - - image = std::make_shared(AnimationPath::builtin("artifact"), imageIndex); - if(!ourArt) - image->disable(); + setArtifact(art); } void CCommanderArtPlace::returnArtToHeroCallback() @@ -145,20 +145,12 @@ void CCommanderArtPlace::showPopupWindow(const Point & cursorPosition) CArtPlace::showPopupWindow(cursorPosition); } -void CCommanderArtPlace::setArtifact(const CArtifactInstance * art) +CHeroArtPlace::CHeroArtPlace(Point position, const CArtifactInstance * art) + : CArtPlace(position, art) { - setInternals(art); } -CHeroArtPlace::CHeroArtPlace(Point position, const CArtifactInstance * Art) - : CArtPlace(position, Art), - locked(false), - marked(false) -{ - createImage(); -} - -void CHeroArtPlace::lockSlot(bool on) +void CArtPlace::lockSlot(bool on) { if(locked == on) return; @@ -173,26 +165,19 @@ void CHeroArtPlace::lockSlot(bool on) image->setFrame(0); } -bool CHeroArtPlace::isLocked() +bool CArtPlace::isLocked() const { return locked; } -void CHeroArtPlace::selectSlot(bool on) +void CArtPlace::selectSlot(bool on) { - if(marked == on) - return; - - marked = on; - if(on) - selection->enable(); - else - selection->disable(); + selection->visible = on; } -bool CHeroArtPlace::isMarked() const +bool CArtPlace::isSelected() const { - return marked; + return selection->visible; } void CHeroArtPlace::clickPressed(const Point & cursorPosition) @@ -207,18 +192,13 @@ void CHeroArtPlace::showPopupWindow(const Point & cursorPosition) showPopupCallback(*this); } -void CHeroArtPlace::showAll(Canvas & to) +void CArtPlace::showAll(Canvas & to) { - if(ourArt) - { - CIntObject::showAll(to); - } - - if(marked && isActive()) - to.drawBorder(pos, Colors::BRIGHT_YELLOW); + CIntObject::showAll(to); + selection->showAll(to); } -void CHeroArtPlace::setArtifact(const CArtifactInstance * art) +void CArtPlace::setArtifact(const CArtifactInstance * art) { setInternals(art); if(art) @@ -253,24 +233,6 @@ void CHeroArtPlace::addCombinedArtInfo(std::map & arts) } } -void CHeroArtPlace::createImage() -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - si32 imageIndex = 0; - - if(locked) - imageIndex = ArtifactID::ART_LOCK; - else if(ourArt) - imageIndex = ourArt->artType->getIconIndex(); - - image = std::make_shared(AnimationPath::builtin("artifact"), imageIndex); - image->disable(); - - selection = std::make_shared(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION); - selection->disable(); -} - bool ArtifactUtilsClient::askToAssemble(const CGHeroInstance * hero, const ArtifactPosition & slot) { assert(hero); diff --git a/client/widgets/CArtifactHolder.h b/client/widgets/CArtifactHolder.h index 5f8648a3f..43bc4e729 100644 --- a/client/widgets/CArtifactHolder.h +++ b/client/widgets/CArtifactHolder.h @@ -19,7 +19,6 @@ class CArtifactSet; VCMI_LIB_NAMESPACE_END class CAnimImage; -class CButton; class CArtifactHolder { @@ -32,19 +31,24 @@ public: class CArtPlace : public LRClickableAreaWTextComp { +public: + CArtPlace(Point position, const CArtifactInstance * art = nullptr); + 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); + protected: std::shared_ptr image; const CArtifactInstance * ourArt; int imageIndex; + std::shared_ptr selection; + bool locked; void setInternals(const CArtifactInstance * artInst); - virtual void createImage()=0; - -public: - CArtPlace(Point position, const CArtifactInstance * Art = nullptr); - const CArtifactInstance * getArt(); - - virtual void setArtifact(const CArtifactInstance * art)=0; }; class CCommanderArtPlace : public CArtPlace @@ -53,14 +57,12 @@ protected: const CGHeroInstance * commanderOwner; ArtifactPosition commanderSlotID; - void createImage() override; void returnArtToHeroCallback(); public: - CCommanderArtPlace(Point position, const CGHeroInstance * commanderOwner, ArtifactPosition artSlot, const CArtifactInstance * Art = nullptr); + CCommanderArtPlace(Point position, const CGHeroInstance * commanderOwner, ArtifactPosition artSlot, const CArtifactInstance * art = nullptr); void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; - void setArtifact(const CArtifactInstance * art) override; }; class CHeroArtPlace: public CArtPlace @@ -72,23 +74,10 @@ public: ClickFunctor leftClickCallback; ClickFunctor showPopupCallback; - CHeroArtPlace(Point position, const CArtifactInstance * Art = nullptr); - void lockSlot(bool on); - bool isLocked(); - void selectSlot(bool on); - bool isMarked() const; + CHeroArtPlace(Point position, const CArtifactInstance * art = nullptr); void clickPressed(const Point & cursorPosition) override; void showPopupWindow(const Point & cursorPosition) override; - void showAll(Canvas & to) override; - void setArtifact(const CArtifactInstance * art) override; void addCombinedArtInfo(std::map & arts); - -protected: - std::shared_ptr selection; - bool locked; - bool marked; - - void createImage() override; }; namespace ArtifactUtilsClient diff --git a/client/widgets/CArtifactsOfHeroBase.h b/client/widgets/CArtifactsOfHeroBase.h index aeacc10fa..2fe10de74 100644 --- a/client/widgets/CArtifactsOfHeroBase.h +++ b/client/widgets/CArtifactsOfHeroBase.h @@ -11,6 +11,8 @@ #include "CArtifactHolder.h" +class CButton; + class CArtifactsOfHeroBase : public CIntObject { protected: diff --git a/client/widgets/CArtifactsOfHeroMarket.cpp b/client/widgets/CArtifactsOfHeroMarket.cpp index 1f01775b3..94d04f512 100644 --- a/client/widgets/CArtifactsOfHeroMarket.cpp +++ b/client/widgets/CArtifactsOfHeroMarket.cpp @@ -30,7 +30,7 @@ void CArtifactsOfHeroMarket::scrollBackpack(int offset) { for(auto & artPlace : backpack) { - if(artPlace->isMarked()) + if(artPlace->isSelected()) { selectArtCallback(artPlace.get()); break; From 9f9317a8a0334dd6c24dde7b36f25303ddb9122b Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 5 Nov 2023 00:53:37 +0200 Subject: [PATCH 2/5] CTradeBase initial commit --- client/CMakeLists.txt | 2 + client/widgets/CTradeBase.cpp | 280 ++++++++++++++++++++++++++ client/widgets/CTradeBase.h | 88 +++++++++ client/windows/CTradeWindow.cpp | 335 ++------------------------------ client/windows/CTradeWindow.h | 66 +------ 5 files changed, 395 insertions(+), 376 deletions(-) create mode 100644 client/widgets/CTradeBase.cpp create mode 100644 client/widgets/CTradeBase.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 2912d02cf..caaedd72e 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -99,6 +99,7 @@ set(client_SRCS widgets/CGarrisonInt.cpp widgets/CreatureCostBox.cpp widgets/ComboBox.cpp + widgets/CTradeBase.cpp widgets/Images.cpp widgets/MiscWidgets.cpp widgets/ObjectLists.cpp @@ -265,6 +266,7 @@ set(client_HEADERS widgets/CGarrisonInt.h widgets/CreatureCostBox.h widgets/ComboBox.h + widgets/CTradeBase.h widgets/Images.h widgets/MiscWidgets.h widgets/ObjectLists.h diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp new file mode 100644 index 000000000..2d9ea755f --- /dev/null +++ b/client/widgets/CTradeBase.cpp @@ -0,0 +1,280 @@ +/* + * 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 "../gui/CGuiHandler.h" +#include "../render/Canvas.h" +#include "../widgets/TextControls.h" +#include "../windows/InfoWindows.h" + +#include "../CGameInfo.h" + +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/mapObjects/CGHeroInstance.h" + +CTradeBase::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) + , serial(Serial) + , left(Left) +{ + OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE); + downSelection = false; + hlp = nullptr; + setType(Type); +} + +void CTradeBase::CTradeableItem::setType(EType newType) +{ + if(type != newType) + { + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + type = newType; + + if(getIndex() < 0) + { + image = std::make_shared(getFilename(), 0); + image->disable(); + } + else + { + image = std::make_shared(getFilename(), getIndex()); + } + } +} + +void CTradeBase::CTradeableItem::setID(int newID) +{ + if(id != newID) + { + id = newID; + if(image) + { + int index = getIndex(); + if(index < 0) + image->disable(); + else + { + image->enable(); + image->setFrame(index); + } + } + } +} + +AnimationPath CTradeBase::CTradeableItem::getFilename() +{ + switch(type) + { + case RESOURCE: + return AnimationPath::builtin("RESOURCE"); + case PLAYER: + return AnimationPath::builtin("CREST58"); + case ARTIFACT_TYPE: + case ARTIFACT_PLACEHOLDER: + case ARTIFACT_INSTANCE: + return AnimationPath::builtin("artifact"); + case CREATURE: + return AnimationPath::builtin("TWCRPORT"); + default: + return {}; + } +} + +int CTradeBase::CTradeableItem::getIndex() +{ + if(id < 0) + return -1; + + switch(type) + { + case RESOURCE: + case PLAYER: + return id; + case ARTIFACT_TYPE: + case ARTIFACT_INSTANCE: + case ARTIFACT_PLACEHOLDER: + return CGI->artifacts()->getByIndex(id)->getIconIndex(); + case CREATURE: + return CGI->creatures()->getByIndex(id)->getIconIndex(); + default: + return -1; + } +} + +void CTradeBase::CTradeableItem::showAll(Canvas & to) +{ + Point posToBitmap; + Point posToSubCenter; + + switch (type) + { + case RESOURCE: + posToBitmap = Point(19, 9); + posToSubCenter = Point(36, 59); + break; + case CREATURE_PLACEHOLDER: + case CREATURE: + posToSubCenter = Point(29, 76); + break; + case PLAYER: + posToSubCenter = Point(31, 76); + break; + case ARTIFACT_PLACEHOLDER: + case ARTIFACT_INSTANCE: + posToSubCenter = Point(19, 55); + if (downSelection) + posToSubCenter.y += 8; + break; + case ARTIFACT_TYPE: + posToSubCenter = Point(19, 58); + break; + } + + if(image) + { + image->moveTo(pos.topLeft() + posToBitmap); + CIntObject::showAll(to); + } + + to.drawText(pos.topLeft() + posToSubCenter, FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, subtitle); +} + +void CTradeBase::CTradeableItem::clickPressed(const Point& cursorPosition) +{ + if(clickPressedCallback) + clickPressedCallback(shared_from_this()); +} + +void CTradeBase::CTradeableItem::showAllAt(const Point& dstPos, const std::string& customSub, Canvas& to) +{ + Rect oldPos = pos; + std::string oldSub = subtitle; + downSelection = true; + + moveTo(dstPos); + subtitle = customSub; + showAll(to); + + downSelection = false; + moveTo(oldPos.topLeft()); + subtitle = oldSub; +} + +void CTradeBase::CTradeableItem::hover(bool on) +{ + if(!on) + { + GH.statusbar()->clear(); + return; + } + + switch(type) + { + case CREATURE: + case CREATURE_PLACEHOLDER: + GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated())); + break; + case ARTIFACT_PLACEHOLDER: + if(id < 0) + GH.statusbar()->write(CGI->generaltexth->zelp[582].first); + else + GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated()); + break; + } +} + +void CTradeBase::CTradeableItem::showPopupWindow(const Point& cursorPosition) +{ + switch(type) + { + case CREATURE: + case CREATURE_PLACEHOLDER: + break; + case ARTIFACT_TYPE: + case 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()); + break; + } +} + +std::string CTradeBase::CTradeableItem::getName(int number) const +{ + switch(type) + { + case PLAYER: + return CGI->generaltexth->capColors[id]; + case RESOURCE: + return CGI->generaltexth->restypes[id]; + case CREATURE: + if (number == 1) + return CGI->creh->objects[id]->getNameSingularTranslated(); + else + return CGI->creh->objects[id]->getNamePluralTranslated(); + case ARTIFACT_TYPE: + case ARTIFACT_INSTANCE: + return CGI->artifacts()->getByIndex(id)->getNameTranslated(); + } + logGlobal->error("Invalid trade item type: %d", (int)type); + return ""; +} + +const CArtifactInstance* CTradeBase::CTradeableItem::getArtInstance() const +{ + switch(type) + { + case ARTIFACT_PLACEHOLDER: + case ARTIFACT_INSTANCE: + return hlp; + default: + return nullptr; + } +} + +void CTradeBase::CTradeableItem::setArtInstance(const CArtifactInstance * art) +{ + assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE); + hlp = art; + if(art) + setID(art->artType->getId()); + else + setID(-1); +} + +CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero) + : market(market) + , hero(hero) +{ +} + +void CTradeBase::removeItems(const std::set> & toRemove) +{ + for(auto item : toRemove) + removeItem(item); +} + +void CTradeBase::removeItem(std::shared_ptr item) +{ + items[item->left] -= item; + + if(hRight == item) + hRight.reset(); +} + +void CTradeBase::getEmptySlots(std::set> & toRemove) +{ + for(auto item : items[1]) + if(!hero->getStackCount(SlotID(item->serial))) + toRemove.insert(item); +} diff --git a/client/widgets/CTradeBase.h b/client/widgets/CTradeBase.h new file mode 100644 index 000000000..75079fe0f --- /dev/null +++ b/client/widgets/CTradeBase.h @@ -0,0 +1,88 @@ +/* + * 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" + +VCMI_LIB_NAMESPACE_BEGIN + +class IMarket; +class CGHeroInstance; + +VCMI_LIB_NAMESPACE_END + +class CButton; +class CTextBox; + +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; + + //highlighted items (nullptr if no highlight) + std::shared_ptr hLeft; + std::shared_ptr hRight; + std::shared_ptr deal; + + 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; + +protected: + std::vector> labels; + std::vector> buttons; + std::vector> texts; +}; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 2d9da6c4c..f852824a0 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -12,317 +12,28 @@ #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" -#include "../widgets/Images.h" #include "../render/Canvas.h" -#include "../gui/TextAlignment.h" #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" #include "../widgets/Buttons.h" #include "../widgets/Slider.h" #include "../widgets/TextControls.h" -#include "../windows/InfoWindows.h" #include "../CGameInfo.h" #include "../CPlayerInterface.h" #include "../../CCallback.h" -#include "../../lib/VCMI_Lib.h" -#include "../../lib/CArtHandler.h" -#include "../../lib/CCreatureHandler.h" #include "../../lib/CGeneralTextHandler.h" #include "../../lib/CHeroHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGMarket.h" -#include "../../lib/networkPacks/ArtifactLocation.h" - -CTradeWindow::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), - serial(Serial), - left(Left) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - downSelection = false; - hlp = nullptr; - setType(Type); -} - -void CTradeWindow::CTradeableItem::setType(EType newType) -{ - if(type != newType) - { - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - type = newType; - - if(getIndex() < 0) - { - image = std::make_shared(getFilename(), 0); - image->disable(); - } - else - { - image = std::make_shared(getFilename(), getIndex()); - } - } -} - -void CTradeWindow::CTradeableItem::setID(int newID) -{ - if (id != newID) - { - id = newID; - if (image) - { - int index = getIndex(); - if (index < 0) - image->disable(); - else - { - image->enable(); - image->setFrame(index); - } - } - } -} - -AnimationPath CTradeWindow::CTradeableItem::getFilename() -{ - switch(type) - { - case RESOURCE: - return AnimationPath::builtin("RESOURCE"); - case PLAYER: - return AnimationPath::builtin("CREST58"); - case ARTIFACT_TYPE: - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: - return AnimationPath::builtin("artifact"); - case CREATURE: - return AnimationPath::builtin("TWCRPORT"); - default: - return {}; - } -} - -int CTradeWindow::CTradeableItem::getIndex() -{ - if (id < 0) - return -1; - - switch(type) - { - case RESOURCE: - case PLAYER: - return id; - case ARTIFACT_TYPE: - case ARTIFACT_INSTANCE: - case ARTIFACT_PLACEHOLDER: - return CGI->artifacts()->getByIndex(id)->getIconIndex(); - case CREATURE: - return CGI->creatures()->getByIndex(id)->getIconIndex(); - default: - return -1; - } -} - -void CTradeWindow::CTradeableItem::showAll(Canvas & to) -{ - CTradeWindow *mw = dynamic_cast(parent); - assert(mw); - - Point posToBitmap; - Point posToSubCenter; - - switch(type) - { - case RESOURCE: - posToBitmap = Point(19,9); - posToSubCenter = Point(36, 59); - break; - case CREATURE_PLACEHOLDER: - case CREATURE: - posToSubCenter = Point(29, 76); - // Positing of unit count is different in Altar of Sacrifice and Freelancer's Guild - if(mw->mode == EMarketMode::CREATURE_EXP && downSelection) - posToSubCenter.y += 5; - break; - case PLAYER: - posToSubCenter = Point(31, 76); - break; - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: - posToSubCenter = Point(19, 55); - if(downSelection) - posToSubCenter.y += 8; - break; - case ARTIFACT_TYPE: - posToSubCenter = Point(19, 58); - break; - } - - if (image) - { - image->moveTo(pos.topLeft() + posToBitmap); - CIntObject::showAll(to); - } - - to.drawText(pos.topLeft() + posToSubCenter, FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, subtitle); -} - -void CTradeWindow::CTradeableItem::clickPressed(const Point & cursorPosition) -{ - CTradeWindow *mw = dynamic_cast(parent); - assert(mw); - if(type == ARTIFACT_PLACEHOLDER) - { - CAltarWindow *aw = static_cast(mw); - const auto pickedArtInst = aw->getPickedArtifact(); - - if(pickedArtInst) - { - aw->arts->pickedArtMoveToAltar(ArtifactPosition::TRANSITION_POS); - aw->moveArtToAltar(this->shared_from_this(), pickedArtInst); - } - else if(const CArtifactInstance *art = getArtInstance()) - { - const auto hero = aw->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)); - aw->arts->pickedArtFromSlot = slot; - aw->arts->artifactsOnAltar.erase(art); - setID(-1); - subtitle.clear(); - aw->deal->block(!aw->arts->artifactsOnAltar.size()); - } - - aw->calcTotalExp(); - return; - } - if(left) - { - if(mw->hLeft != this->shared_from_this()) - mw->hLeft = this->shared_from_this(); - else - return; - } - else - { - if(mw->hRight != this->shared_from_this()) - mw->hRight = this->shared_from_this(); - else - return; - } - mw->selectionChanged(left); -} - -void CTradeWindow::CTradeableItem::showAllAt(const Point &dstPos, const std::string &customSub, Canvas & to) -{ - Rect oldPos = pos; - std::string oldSub = subtitle; - downSelection = true; - - moveTo(dstPos); - subtitle = customSub; - showAll(to); - - downSelection = false; - moveTo(oldPos.topLeft()); - subtitle = oldSub; -} - -void CTradeWindow::CTradeableItem::hover(bool on) -{ - if(!on) - { - GH.statusbar()->clear(); - return; - } - - switch(type) - { - case CREATURE: - case CREATURE_PLACEHOLDER: - GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated())); - break; - case ARTIFACT_PLACEHOLDER: - if(id < 0) - GH.statusbar()->write(CGI->generaltexth->zelp[582].first); - else - GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated()); - break; - } -} - -void CTradeWindow::CTradeableItem::showPopupWindow(const Point & cursorPosition) -{ - switch(type) - { - case CREATURE: - case CREATURE_PLACEHOLDER: - //GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->namePl)); - break; - case ARTIFACT_TYPE: - case 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()); - break; - } -} - -std::string CTradeWindow::CTradeableItem::getName(int number) const -{ - switch(type) - { - case PLAYER: - return CGI->generaltexth->capColors[id]; - case RESOURCE: - return CGI->generaltexth->restypes[id]; - case CREATURE: - if(number == 1) - return CGI->creh->objects[id]->getNameSingularTranslated(); - else - return CGI->creh->objects[id]->getNamePluralTranslated(); - case ARTIFACT_TYPE: - case ARTIFACT_INSTANCE: - return CGI->artifacts()->getByIndex(id)->getNameTranslated(); - } - logGlobal->error("Invalid trade item type: %d", (int)type); - return ""; -} - -const CArtifactInstance * CTradeWindow::CTradeableItem::getArtInstance() const -{ - switch(type) - { - case ARTIFACT_PLACEHOLDER: - case ARTIFACT_INSTANCE: - return hlp; - default: - return nullptr; - } -} - -void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art) -{ - assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE); - hlp = art; - if(art) - setID(art->artType->getId()); - else - setID(-1); -} CTradeWindow::CTradeWindow(const ImagePath & bgName, const IMarket *Market, const CGHeroInstance *Hero, const std::function & onWindowClosed, EMarketMode Mode): + CTradeBase(Market, Hero), CWindowObject(PLAYER_COLORED, bgName), - market(Market), onWindowClosed(onWindowClosed), - hero(Hero), readyToTrade(false) { OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); @@ -403,6 +114,26 @@ void CTradeWindow::initItems(bool Left) 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); @@ -571,30 +302,6 @@ void CTradeWindow::close() CWindowObject::close(); } -void CTradeWindow::removeItems(const std::set> & toRemove) -{ - for(auto item : toRemove) - removeItem(item); -} - -void CTradeWindow::removeItem(std::shared_ptr item) -{ - items[item->left] -= item; - - if(hRight == item) - { - hRight.reset(); - selectionChanged(false); - } -} - -void CTradeWindow::getEmptySlots(std::set> & toRemove) -{ - for(auto item : items[1]) - if(!hero->getStackCount(SlotID(item->serial))) - toRemove.insert(item); -} - void CTradeWindow::setMode(EMarketMode Mode) { const IMarket *m = market; diff --git a/client/windows/CTradeWindow.h b/client/windows/CTradeWindow.h index 45a8cfee5..704d8aaef 100644 --- a/client/windows/CTradeWindow.h +++ b/client/windows/CTradeWindow.h @@ -9,76 +9,21 @@ */ #pragma once +#include "../widgets/CTradeBase.h" #include "../widgets/CWindowWithArtifacts.h" #include "CWindowObject.h" -#include "../../lib/FunctionList.h" - -VCMI_LIB_NAMESPACE_BEGIN - -class IMarket; - -VCMI_LIB_NAMESPACE_END class CSlider; -class CTextBox; -class CPicture; class CGStatusBar; -class CTradeWindow : public CWindowObject, public CWindowWithArtifacts //base for markets and altar of sacrifice +class CTradeWindow : public CTradeBase, public CWindowObject, public CWindowWithArtifacts //base for markets and altar of sacrifice { 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 - - 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; - - //highlighted items (nullptr if no highlight) - std::shared_ptr hLeft; - std::shared_ptr hRight; EType itemsType[2]; EMarketMode mode; std::shared_ptr ok; std::shared_ptr max; - std::shared_ptr deal; std::shared_ptr slider; //for choosing amount to be exchanged bool readyToTrade; @@ -93,9 +38,6 @@ public: void initItems(bool Left); std::vector *getItemsIds(bool Left); //nullptr if default void getPositionsFor(std::vector &poss, bool Left, EType type) const; - void removeItems(const std::set> & toRemove); - void removeItem(std::shared_ptr item); - void getEmptySlots(std::set> & toRemove); void setMode(EMarketMode Mode); //mode setter void artifactSelected(CHeroArtPlace *slot); //used when selling artifacts -> called when user clicked on artifact slot @@ -130,7 +72,7 @@ public: void setMax(); void sliderMoved(int to); - void makeDeal(); + void makeDeal() override; void selectionChanged(bool side) override; //true == left CMarketplaceWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function & onWindowClosed, EMarketMode Mode); ~CMarketplaceWindow(); @@ -171,7 +113,7 @@ public: void putOnAltar(int backpackIndex); bool putOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art); - void makeDeal(); + void makeDeal() override; void showAll(Canvas & to) override; void blockTrade(); From 75ebd954af814e501f18a115c71d4c9b1effc97b Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Sun, 5 Nov 2023 02:01:23 +0200 Subject: [PATCH 3/5] Creatures altar & Artifacts altar --- client/CMakeLists.txt | 4 + client/CPlayerInterface.cpp | 9 +- client/widgets/CAltar.cpp | 457 +++++++++++++++++++++++++++ client/widgets/CAltar.h | 98 ++++++ client/widgets/CTradeBase.cpp | 9 +- client/windows/CAltarWindow.cpp | 136 ++++++++ client/windows/CAltarWindow.h | 38 +++ client/windows/CTradeWindow.cpp | 529 ++------------------------------ client/windows/CTradeWindow.h | 57 +--- client/windows/CWindowObject.h | 3 +- 10 files changed, 777 insertions(+), 563 deletions(-) create mode 100644 client/widgets/CAltar.cpp create mode 100644 client/widgets/CAltar.h create mode 100644 client/windows/CAltarWindow.cpp create mode 100644 client/windows/CAltarWindow.h diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index caaedd72e..6257722a2 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -93,6 +93,7 @@ set(client_SRCS renderSDL/SDL_Extensions.cpp widgets/Buttons.cpp + widgets/CAltar.cpp widgets/CArtifactHolder.cpp widgets/CComponent.cpp widgets/CExchangeController.cpp @@ -115,6 +116,7 @@ set(client_SRCS widgets/CWindowWithArtifacts.cpp widgets/RadialMenu.cpp + windows/CAltarWindow.cpp windows/CCastleInterface.cpp windows/CCreatureWindow.cpp windows/CHeroOverview.cpp @@ -260,6 +262,7 @@ set(client_HEADERS renderSDL/SDL_PixelAccess.h widgets/Buttons.h + widgets/CAltar.h widgets/CArtifactHolder.h widgets/CComponent.h widgets/CExchangeController.h @@ -282,6 +285,7 @@ set(client_HEADERS widgets/CWindowWithArtifacts.h widgets/RadialMenu.h + windows/CAltarWindow.h windows/CCastleInterface.h windows/CCreatureWindow.h windows/CHeroOverview.h diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 409b0f30e..2ee8b1caf 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -48,6 +48,7 @@ #include "widgets/CComponent.h" #include "widgets/CGarrisonInt.h" +#include "windows/CAltarWindow.h" #include "windows/CCastleInterface.h" #include "windows/CCreatureWindow.h" #include "windows/CHeroWindow.h" @@ -421,7 +422,7 @@ void CPlayerInterface::heroPrimarySkillChanged(const CGHeroInstance * hero, Prim if (which == PrimarySkill::EXPERIENCE) { for (auto ctw : GH.windows().findWindows()) - ctw->setExpToLevel(); + ctw->updateExpToLevel(); } else adventureInt->onHeroChanged(hero); @@ -558,10 +559,10 @@ void CPlayerInterface::garrisonsChanged(std::vector ob for (auto cgh : GH.windows().findWindows()) cgh->updateGarrisons(); - for (auto cmw : GH.windows().findWindows()) + for (auto cmw : GH.windows().findWindows()) { - if (vstd::contains(objs, cmw->hero)) - cmw->garrisonChanged(); + if(vstd::contains(objs, cmw->getHero())) + cmw->updateGarrison(); } GH.windows().totalRedraw(); diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp new file mode 100644 index 000000000..60f27c7a4 --- /dev/null +++ b/client/widgets/CAltar.cpp @@ -0,0 +1,457 @@ +/* + * 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 "../widgets/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" + +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() +{ + hLeft = hRight = nullptr; + deal->block(true); +} + +CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero) + : CAltar(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(&CAltar::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, -10)); + arts->setHero(hero); + + int slotNum = 0; + for(auto & altarSlotPos : posSlotsAltar) + { + auto altarSlot = std::make_shared(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum++); + altarSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void + { + 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(); + }; + 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::greater<>()); + + LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, {}, {}, 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; +}; + +CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero) + : CAltar(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); + + unitsSlider = std::make_shared(Point(231, 481), 137, [this](int newVal) -> void + { + if(hLeft) + unitsOnAltar[hLeft->serial] = newVal; + if(hRight) + updateAltarSlot(hRight); + deal->block(calcExpAltarForHero() == 0); + updateControls(); + updateSubtitlesForSelected(); + }, 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)); + + 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)); + + auto clickPressed = [this](std::shared_ptr altarSlot, std::vector> & oppositeSlots, + std::shared_ptr & hCurSide, std::shared_ptr & hOppSide) -> void + { + std::shared_ptr oppositeSlot; + for(const auto & slot : oppositeSlots) + if(slot->serial == altarSlot->serial) + { + oppositeSlot = slot; + break; + } + + if(hCurSide != altarSlot && oppositeSlot) + { + hCurSide = altarSlot; + hOppSide = oppositeSlot; + updateControls(); + updateSubtitlesForSelected(); + redraw(); + } + }; + + for(int slotIdx = 0; slotIdx < GameConstants::ARMY_SIZE; slotIdx++) + { + 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, clickPressed](std::shared_ptr altarSlot) -> void + { + clickPressed(altarSlot, items[0], hLeft, hRight); + }; + heroSlot->subtitle = std::to_string(hero->getStackCount(SlotID(slotIdx))); + items[1].emplace_back(heroSlot); + } + 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, clickPressed](std::shared_ptr altarSlot) -> void + { + clickPressed(altarSlot, items[1], hRight, hLeft); + }; + items[0].emplace_back(altarSlot); + } + + readExpValues(); + calcExpAltarForHero(); + deselect(); +}; + +void CAltarCreatures::readExpValues() +{ + int dump; + for(auto heroSlot : items[1]) + { + 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--; + } + unitsSlider->setAmount(sliderAmount); + unitsSlider->block(!unitsSlider->getAmount()); + if(hLeft) + unitsSlider->scrollTo(unitsOnAltar[hLeft->serial]); + maxUnits->block(unitsSlider->getAmount() == 0); +} + +void CAltarCreatures::updateSubtitlesForSelected() +{ + if(hLeft) + lSubtitle->setText(std::to_string(unitsSlider->getValue())); + else + lSubtitle->setText(""); + if(hRight) + rSubtitle->setText(hRight->subtitle); + else + rSubtitle->setText(""); +} + +void CAltarCreatures::updateGarrison() +{ + std::set> empty; + getEmptySlots(empty); + removeItems(empty); + readExpValues(); + for(auto & heroSlot : items[1]) + heroSlot->subtitle = std::to_string(hero->getStackCount(SlotID(heroSlot->serial))); +} + +void CAltarCreatures::deselect() +{ + CAltar::deselect(); + unitsSlider->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(); + unitsSlider->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(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 : items[0]) + { + heroSlot->setType(CREATURE_PLACEHOLDER); + heroSlot->subtitle = ""; + } +} + +void CAltarCreatures::sacrificeAll() +{ + std::optional lastSlot; + for(auto heroSlot : items[1]) + { + 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) + unitsSlider->scrollTo(unitsOnAltar[hRight->serial]); + for(auto altarSlot : items[0]) + 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]))) : ""; +} \ No newline at end of file diff --git a/client/widgets/CAltar.h b/client/widgets/CAltar.h new file mode 100644 index 000000000..c6afe24b8 --- /dev/null +++ b/client/widgets/CAltar.h @@ -0,0 +1,98 @@ +/* + * CAltar.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 "../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 +{ +public: + CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero); + TExpType calcExpAltarForHero() override; + void makeDeal() override; + void sacrificeAll() override; + void sacrificeBackpack(); + void setSelectedArtifact(const CArtifactInstance * art); + void moveArtToAltar(std::shared_ptr, const CArtifactInstance * art); + std::shared_ptr getAOHset() const; + +private: + std::shared_ptr selectedArt; + std::shared_ptr selectedCost; + std::shared_ptr sacrificeBackpackButton; + std::shared_ptr arts; + + const std::vector posSlotsAltar = + { + Point(317, 53), Point(371, 53), Point(425, 53), + Point(479, 53), Point(533, 53), Point(317, 123), + Point(371, 123), Point(425, 123), Point(479, 123), + Point(533, 123), Point(317, 193), Point(371, 193), + Point(425, 193), Point(479, 193), Point(533, 193), + Point(317, 263), Point(371, 263), Point(425, 263), + Point(479, 263), Point(533, 263), Point(398, 333), + Point(452, 333) + }; + + bool putArtOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art); +}; + +class CAltarCreatures : public CAltar +{ +public: + CAltarCreatures(const IMarket * market, const CGHeroInstance * hero); + void updateGarrison(); + void deselect() override; + TExpType calcExpAltarForHero() override; + void makeDeal() override; + void sacrificeAll() override; + void updateAltarSlot(std::shared_ptr slot); + +private: + std::shared_ptr maxUnits; + std::shared_ptr unitsSlider; + std::vector unitsOnAltar; + 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(); +}; diff --git a/client/widgets/CTradeBase.cpp b/client/widgets/CTradeBase.cpp index 2d9ea755f..e1e7aacde 100644 --- a/client/widgets/CTradeBase.cpp +++ b/client/widgets/CTradeBase.cpp @@ -31,6 +31,11 @@ CTradeBase::CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool L downSelection = false; hlp = nullptr; setType(Type); + if(image) + { + this->pos.w = image->pos.w; + this->pos.h = image->pos.h; + } } void CTradeBase::CTradeableItem::setType(EType newType) @@ -124,14 +129,14 @@ void CTradeBase::CTradeableItem::showAll(Canvas & to) break; case CREATURE_PLACEHOLDER: case CREATURE: - posToSubCenter = Point(29, 76); + posToSubCenter = Point(29, 77); break; case PLAYER: posToSubCenter = Point(31, 76); break; case ARTIFACT_PLACEHOLDER: case ARTIFACT_INSTANCE: - posToSubCenter = Point(19, 55); + posToSubCenter = Point(19, 54); if (downSelection) posToSubCenter.y += 8; break; diff --git a/client/windows/CAltarWindow.cpp b/client/windows/CAltarWindow.cpp new file mode 100644 index 000000000..faabbb5ca --- /dev/null +++ b/client/windows/CAltarWindow.cpp @@ -0,0 +1,136 @@ +/* + * 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 "CAltarWindow.h" + +#include "../gui/CGuiHandler.h" +#include "../render/Canvas.h" +#include "../gui/Shortcut.h" +#include "../widgets/Buttons.h" +#include "../widgets/TextControls.h" + +#include "../CGameInfo.h" + +#include "../../lib/CGeneralTextHandler.h" +#include "../../lib/CHeroHandler.h" +#include "../../lib/mapObjects/CGHeroInstance.h" + +CAltarWindow::CAltarWindow(const IMarket * market, const CGHeroInstance * hero, const std::function & onWindowClosed, EMarketMode mode) + : CWindowObject(PLAYER_COLORED, ImagePath::builtin(mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp")) + , hero(hero) + , windowClosedCallback(onWindowClosed) +{ + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + if(mode == EMarketMode::ARTIFACT_EXP) + createAltarArtifacts(market, hero); + else if (mode == EMarketMode::CREATURE_EXP) + createAltarCreatures(market, hero); + else + close(); + updateExpToLevel(); + statusBar = CGStatusBar::create(std::make_shared(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26)); +} + +void CAltarWindow::updateExpToLevel() +{ + altar->expToLevel->setText(std::to_string(CGI->heroh->reqExp(CGI->heroh->level(altar->hero->exp) + 1) - altar->hero->exp)); +} + +void CAltarWindow::updateGarrison() +{ + if(auto altarCreatures = std::static_pointer_cast(altar)) + altarCreatures->updateGarrison(); +} + +const CGHeroInstance * CAltarWindow::getHero() const +{ + return hero; +} + +void CAltarWindow::close() +{ + if(windowClosedCallback) + windowClosedCallback(); + + CWindowObject::close(); +} + +void CAltarWindow::createAltarArtifacts(const IMarket * market, const CGHeroInstance * hero) +{ + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + background = createBg(ImagePath::builtin("ALTRART2.bmp"), PLAYER_COLORED); + + auto altarArtifacts = std::make_shared(market, hero); + altar = altarArtifacts; + artSets.clear(); + addSetAndCallbacks(altarArtifacts->getAOHset()); + + changeModeButton = std::make_shared(Point(516, 421), AnimationPath::builtin("ALTSACC.DEF"), + CGI->generaltexth->zelp[572], std::bind(&CAltarWindow::createAltarCreatures, this, market, hero)); + if(altar->hero->getAlignment() == EAlignment::GOOD) + changeModeButton->block(true); + quitButton = std::make_shared(Point(516, 520), AnimationPath::builtin("IOK6432.DEF"), + CGI->generaltexth->zelp[568], std::bind(&CAltarWindow::close, this), EShortcut::GLOBAL_RETURN); + altar->setRedrawParent(true); + redraw(); +} + +void CAltarWindow::createAltarCreatures(const IMarket * market, const CGHeroInstance * hero) +{ + OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + + background = createBg(ImagePath::builtin("ALTARMON.bmp"), PLAYER_COLORED); + + altar = std::make_shared(market, hero); + + changeModeButton = std::make_shared(Point(516, 421), AnimationPath::builtin("ALTART.DEF"), + CGI->generaltexth->zelp[580], std::bind(&CAltarWindow::createAltarArtifacts, this, market, hero)); + if(altar->hero->getAlignment() == EAlignment::EVIL) + changeModeButton->block(true); + quitButton = std::make_shared(Point(516, 520), AnimationPath::builtin("IOK6432.DEF"), + CGI->generaltexth->zelp[568], std::bind(&CAltarWindow::close, this), EShortcut::GLOBAL_RETURN); + altar->setRedrawParent(true); + redraw(); +} + +void CAltarWindow::artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw) +{ + if(!getState().has_value()) + return; + + if(auto altarArtifacts = std::static_pointer_cast(altar)) + { + if(const auto pickedArt = getPickedArtifact()) + altarArtifacts->setSelectedArtifact(pickedArt); + else + altarArtifacts->setSelectedArtifact(nullptr); + } + CWindowWithArtifacts::artifactMoved(srcLoc, destLoc, withRedraw); +} + +void CAltarWindow::showAll(Canvas & to) +{ + // This func is temporary workaround for compliance with CTradeWindow + CWindowObject::showAll(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/CAltarWindow.h b/client/windows/CAltarWindow.h new file mode 100644 index 000000000..9d1ffe2a5 --- /dev/null +++ b/client/windows/CAltarWindow.h @@ -0,0 +1,38 @@ +/* + * CAltarWindow.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 "../widgets/CAltar.h" +#include "../widgets/CWindowWithArtifacts.h" +#include "CWindowObject.h" + +class CAltarWindow : public CWindowObject, public CWindowWithArtifacts +{ +public: + CAltarWindow(const IMarket * market, const CGHeroInstance * hero, const std::function & onWindowClosed, EMarketMode mode); + void updateExpToLevel(); + void updateGarrison(); + const CGHeroInstance * getHero() const; + void close() override; + + void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw) override; + void showAll(Canvas & to) override; + +private: + const CGHeroInstance * hero; + std::shared_ptr altar; + std::shared_ptr changeModeButton; + std::shared_ptr quitButton; + std::function windowClosedCallback; + std::shared_ptr statusBar; + + void createAltarArtifacts(const IMarket * market, const CGHeroInstance * hero); + void createAltarCreatures(const IMarket * market, const CGHeroInstance * hero); +}; diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index f852824a0..04b1c59cf 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -66,14 +66,6 @@ void CTradeWindow::initTypes() itemsType[1] = ARTIFACT_INSTANCE; itemsType[0] = RESOURCE; break; - case EMarketMode::CREATURE_EXP: - itemsType[1] = CREATURE; - itemsType[0] = CREATURE_PLACEHOLDER; - break; - case EMarketMode::ARTIFACT_EXP: - itemsType[1] = ARTIFACT_TYPE; - itemsType[0] = ARTIFACT_PLACEHOLDER; - break; } } @@ -145,26 +137,7 @@ std::vector *CTradeWindow::getItemsIds(bool Left) { std::vector *ids = nullptr; - if(mode == EMarketMode::ARTIFACT_EXP) - return new std::vector(22, -1); - - 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 + if(!Left) { switch(itemsType[0]) { @@ -186,50 +159,31 @@ std::vector *CTradeWindow::getItemsIds(bool Left) void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType type) const { - if(mode == EMarketMode::ARTIFACT_EXP && !Left) + //seven boxes: + // X X X + // X X X + // X + int h, w, x, y, dx, dy; + int leftToRightOffset; + getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset); + + const std::vector tmp = { - //22 boxes, 5 in row, last row: two boxes centered - int h, w, x, y, dx, dy; - h = w = 44; - x = 317; - y = 53; - dx = 54; - dy = 70; - for (int i = 0; i < 4 ; i++) - for (int j = 0; j < 5 ; j++) - poss.push_back(Rect(x + dx*j, y + dy*i, w, h)); + 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) ) + }; - poss.push_back(Rect((int)(x + dx * 1.5), (y + dy * 4), w, h)); - poss.push_back(Rect((int)(x + dx * 2.5), (y + dy * 4), w, h)); - } - else + vstd::concatenate(poss, tmp); + + if(!Left) { - //seven boxes: - // X X X - // X X X - // X - int h, w, x, y, dx, dy; - int leftToRightOffset; - getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset); - - 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; - } + for(Rect &r : poss) + r.x += leftToRightOffset; } } @@ -288,9 +242,9 @@ void CTradeWindow::showAll(Canvas & to) if(readyToTrade) { if(hLeft) - hLeft->showAllAt(pos.topLeft() + selectionOffset(true), selectionSubtitle(true), to); + hLeft->showAllAt(pos.topLeft() + selectionOffset(true), updateSlotSubtitle(true), to); if(hRight) - hRight->showAllAt(pos.topLeft() + selectionOffset(false), selectionSubtitle(false), to); + hRight->showAllAt(pos.topLeft() + selectionOffset(false), updateSlotSubtitle(false), to); } } @@ -315,7 +269,6 @@ void CTradeWindow::setMode(EMarketMode Mode) { case EMarketMode::CREATURE_EXP: case EMarketMode::ARTIFACT_EXP: - GH.windows().createAndPushWindow(m, h, functor, Mode); break; default: GH.windows().createAndPushWindow(m, h, functor, Mode); @@ -612,7 +565,7 @@ bool CMarketplaceWindow::printButtonFor(EMarketMode M) const } } -void CMarketplaceWindow::garrisonChanged() +void CMarketplaceWindow::updateGarrison() { if(mode != EMarketMode::CREATURE_RESOURCE) return; @@ -642,7 +595,7 @@ void CMarketplaceWindow::artifactsChanged(bool Left) redraw(); } -std::string CMarketplaceWindow::selectionSubtitle(bool Left) const +std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const { if(Left) { @@ -811,431 +764,3 @@ void CMarketplaceWindow::updateTraderText() } traderText->setText(CGI->generaltexth->allTexts[gnrtxtnr]); } - -CAltarWindow::CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function & onWindowClosed, EMarketMode Mode) - : CTradeWindow(ImagePath::builtin(Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, onWindowClosed, Mode) -{ - OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); - - if(Mode == EMarketMode::CREATURE_EXP) - { - //%s's Creatures - labels.push_back(std::make_shared(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, - boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated()))); - - //Altar of Sacrifice - labels.push_back(std::make_shared(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479])); - - //To sacrifice creatures, move them from your army on to the Altar and click Sacrifice - new CTextBox(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW); - - slider = std::make_shared(Point(231, 481), 137, std::bind(&CAltarWindow::sliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL); - max = std::make_shared(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, slider)); - - sacrificedUnits.resize(GameConstants::ARMY_SIZE, 0); - sacrificeAll = std::make_shared(Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltarWindow::SacrificeAll,this)); - - initItems(true); - mimicCres(); - } - else - { - //Sacrifice artifacts for experience - labels.push_back(std::make_shared(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477])); - //%s's Creatures - labels.push_back(std::make_shared(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478])); - - sacrificeAll = std::make_shared(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"), CGI->generaltexth->zelp[571], std::bind(&CAltarWindow::SacrificeAll,this)); - sacrificeAll->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty()); - sacrificeBackpack = std::make_shared(Point(147, 520), AnimationPath::builtin("ALTEMBK.DEF"), CGI->generaltexth->zelp[570], std::bind(&CAltarWindow::SacrificeBackpack,this)); - sacrificeBackpack->block(hero->artifactsInBackpack.empty()); - - arts = std::make_shared(Point(-365, -12)); - arts->setHero(hero); - addSetAndCallbacks(arts); - - initItems(true); - initItems(false); - artIcon = std::make_shared(AnimationPath::builtin("ARTIFACT"), 0, 0, 281, 442); - artIcon->disable(); - } - - //Experience needed to reach next level - texts.push_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.push_back(std::make_shared(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW)); - - statusBar = CGStatusBar::create(std::make_shared(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26)); - - ok = std::make_shared(Point(516, 520), AnimationPath::builtin("IOK6432.DEF"), CGI->generaltexth->zelp[568], [&](){ close();}, EShortcut::GLOBAL_RETURN); - - deal = std::make_shared(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"), CGI->generaltexth->zelp[585], std::bind(&CAltarWindow::makeDeal,this)); - - if(Mode == EMarketMode::CREATURE_EXP) - { - auto changeMode = std::make_shared(Point(516, 421), AnimationPath::builtin("ALTART.DEF"), CGI->generaltexth->zelp[580], std::bind(&CTradeWindow::setMode,this, EMarketMode::ARTIFACT_EXP)); - if(Hero->getAlignment() == ::EAlignment::EVIL) - changeMode->block(true); - buttons.push_back(changeMode); - } - else if(Mode == EMarketMode::ARTIFACT_EXP) - { - auto changeMode = std::make_shared(Point(516, 421), AnimationPath::builtin("ALTSACC.DEF"), CGI->generaltexth->zelp[572], std::bind(&CTradeWindow::setMode,this, EMarketMode::CREATURE_EXP)); - if(Hero->getAlignment() == ::EAlignment::GOOD) - changeMode->block(true); - buttons.push_back(changeMode); - } - - expPerUnit.resize(GameConstants::ARMY_SIZE, 0); - getExpValues(); - - expToLevel = std::make_shared(73, 475, FONT_SMALL, ETextAlignment::CENTER); - expOnAltar = std::make_shared(73, 543, FONT_SMALL, ETextAlignment::CENTER); - - setExpToLevel(); - calcTotalExp(); - blockTrade(); -} - -CAltarWindow::~CAltarWindow() = default; - -void CAltarWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const -{ - leftToRightOffset = 289; - x = 45; - y = 110; - w = 58; - h = 64; - dx = 83; - dy = 98; -} - -void CAltarWindow::sliderMoved(int to) -{ - if(hLeft) - sacrificedUnits[hLeft->serial] = to; - if(hRight) - updateRight(hRight); - - deal->block(!to); - calcTotalExp(); - redraw(); -} - -void CAltarWindow::makeDeal() -{ - if(mode == EMarketMode::CREATURE_EXP) - { - blockTrade(); - slider->scrollTo(0); - - std::vector ids; - std::vector toSacrifice; - - for(int i = 0; i < sacrificedUnits.size(); i++) - { - if(sacrificedUnits[i]) - { - ids.push_back(i); - toSacrifice.push_back(sacrificedUnits[i]); - } - } - - LOCPLINT->cb->trade(market, mode, ids, {}, toSacrifice, hero); - - for(int& val : sacrificedUnits) - val = 0; - - for(auto item : items[0]) - { - item->setType(CREATURE_PLACEHOLDER); - item->subtitle = ""; - } - } - else - { - std::vector positions; - for(const CArtifactInstance * art : arts->artifactsOnAltar) - { - positions.push_back(hero->getSlotByInstance(art)); - } - std::sort(positions.begin(), positions.end(), std::greater<>()); - - LOCPLINT->cb->trade(market, mode, positions, {}, {}, hero); - arts->artifactsOnAltar.clear(); - - for(auto item : items[0]) - { - item->setID(-1); - item->subtitle = ""; - } - - //arts->scrollBackpack(0); - deal->block(true); - } - - calcTotalExp(); -} - -void CAltarWindow::SacrificeAll() -{ - if(mode == EMarketMode::CREATURE_EXP) - { - bool movedAnything = false; - for(auto item : items[1]) - sacrificedUnits[item->serial] = hero->getStackCount(SlotID(item->serial)); - - sacrificedUnits[items[1].front()->serial]--; - - for(auto item : items[0]) - { - updateRight(item); - if(item->type == CREATURE) - movedAnything = true; - } - - deal->block(!movedAnything); - calcTotalExp(); - } - else - { - std::vector> artsForMove; - for(const auto& slotInfo : arts->visibleArtSet.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(); - } - redraw(); -} - -void CAltarWindow::selectionChanged(bool side) -{ - if(mode != EMarketMode::CREATURE_EXP) - return; - - int stackCount = 0; - for (int i = 0; i < GameConstants::ARMY_SIZE; i++) - if(hero->getStackCount(SlotID(i)) > sacrificedUnits[i]) - stackCount++; - - slider->setAmount(hero->getStackCount(SlotID(hLeft->serial)) - (stackCount == 1)); - slider->block(!slider->getAmount()); - slider->scrollTo(sacrificedUnits[hLeft->serial]); - max->block(!slider->getAmount()); - selectOppositeItem(side); - readyToTrade = true; - redraw(); -} - -void CAltarWindow::selectOppositeItem(bool side) -{ - bool oppositeSide = !side; - int pos = vstd::find_pos(items[side], side ? hLeft : hRight); - int oppositePos = vstd::find_pos(items[oppositeSide], oppositeSide ? hLeft : hRight); - - if(pos >= 0 && pos != oppositePos) - { - if(oppositeSide) - hLeft = items[oppositeSide][pos]; - else - hRight = items[oppositeSide][pos]; - - selectionChanged(oppositeSide); - } -} - -void CAltarWindow::mimicCres() -{ - OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE); - std::vector positions; - getPositionsFor(positions, false, CREATURE); - - for(auto item : items[1]) - { - auto hlp = std::make_shared(positions[item->serial].topLeft(), CREATURE_PLACEHOLDER, item->id, false, item->serial); - hlp->pos = positions[item->serial] + this->pos.topLeft(); - items[0].push_back(hlp); - } -} - -Point CAltarWindow::selectionOffset(bool Left) const -{ - if(Left) - return Point(150, 421); - else - return Point(396, 421); -} - -std::string CAltarWindow::selectionSubtitle(bool Left) const -{ - if(Left && slider && hLeft) - return std::to_string(slider->getValue()); - else if(!Left && hRight) - return hRight->subtitle; - else - return ""; -} - -void CAltarWindow::artifactsChanged(bool left) -{ - -} - -void CAltarWindow::garrisonChanged() -{ - if(mode != EMarketMode::CREATURE_EXP) - return; - - std::set> empty; - getEmptySlots(empty); - - removeItems(empty); - - initSubs(true); - getExpValues(); -} - -void CAltarWindow::getExpValues() -{ - int dump; - for(auto item : items[1]) - { - if(item->id >= 0) - market->getOffer(item->id, 0, dump, expPerUnit[item->serial], EMarketMode::CREATURE_EXP); - } -} - -void CAltarWindow::calcTotalExp() -{ - int val = 0; - if(mode == EMarketMode::CREATURE_EXP) - { - for (int i = 0; i < sacrificedUnits.size(); i++) - { - val += expPerUnit[i] * sacrificedUnits[i]; - } - } - else - { - auto artifactsOfHero = std::dynamic_pointer_cast(arts); - for(const CArtifactInstance * art : artifactsOfHero->artifactsOnAltar) - { - int dmp, valOfArt; - market->getOffer(art->artType->getId(), 0, dmp, valOfArt, mode); - val += valOfArt; //WAS val += valOfArt * arts->artifactsOnAltar.count(*i); - } - } - val = static_cast(hero->calculateXp(val)); - expOnAltar->setText(std::to_string(val)); -} - -void CAltarWindow::setExpToLevel() -{ - expToLevel->setText(std::to_string(CGI->heroh->reqExp(CGI->heroh->level(hero->exp)+1) - hero->exp)); -} - -void CAltarWindow::blockTrade() -{ - hLeft = hRight = nullptr; - readyToTrade = false; - if(slider) - { - slider->block(true); - max->block(true); - } - deal->block(true); -} - -void CAltarWindow::updateRight(std::shared_ptr toUpdate) -{ - int val = sacrificedUnits[toUpdate->serial]; - toUpdate->setType(val ? CREATURE : CREATURE_PLACEHOLDER); - toUpdate->subtitle = val ? boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(val * expPerUnit[toUpdate->serial]))) : ""; //%s exp -} - -int CAltarWindow::firstFreeSlot() -{ - int ret = -1; - while(items[0][++ret]->id >= 0 && ret + 1 < items[0].size()); - return items[0][ret]->id == -1 ? ret : -1; -} - -void CAltarWindow::SacrificeBackpack() -{ - while(!arts->visibleArtSet.artifactsInBackpack.empty()) - { - if(!putOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact)) - break; - }; - calcTotalExp(); -} - -void CAltarWindow::artifactPicked() -{ - redraw(); -} - -void CAltarWindow::showAll(Canvas & to) -{ - CTradeWindow::showAll(to); - if(mode == EMarketMode::ARTIFACT_EXP && arts) - { - if(auto pickedArt = arts->getPickedArtifact()) - { - artIcon->setFrame(pickedArt->artType->getIconIndex()); - artIcon->showAll(to); - - int dmp, val; - market->getOffer(pickedArt->getTypeId(), 0, dmp, val, EMarketMode::ARTIFACT_EXP); - val = static_cast(hero->calculateXp(val)); - - to.drawText(Point(304, 498), FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, std::to_string(val)); - } - } -} - -bool CAltarWindow::putOnAltar(std::shared_ptr altarSlot, const CArtifactInstance *art) -{ - if(!art->artType->isTradable()) //special art - { - logGlobal->warn("Cannot put special artifact on altar!"); - return false; - } - - if(!altarSlot || altarSlot->id != -1) - { - int slotIndex = firstFreeSlot(); - if(slotIndex < 0) - { - logGlobal->warn("No free slots on altar!"); - return false; - } - altarSlot = items[0][slotIndex]; - } - - int dmp, val; - market->getOffer(art->artType->getId(), 0, dmp, val, EMarketMode::ARTIFACT_EXP); - val = static_cast(hero->calculateXp(val)); - - arts->artifactsOnAltar.insert(art); - arts->deleteFromVisible(art); - altarSlot->setArtInstance(art); - altarSlot->subtitle = std::to_string(val); - - deal->block(false); - return true; -} - -void CAltarWindow::moveArtToAltar(std::shared_ptr altarSlot, const CArtifactInstance *art) -{ - if(putOnAltar(altarSlot, art)) - { - CCS->curh->dragAndDropCursor(nullptr); - arts->unmarkSlots(); - } -} diff --git a/client/windows/CTradeWindow.h b/client/windows/CTradeWindow.h index 704d8aaef..9c0763d68 100644 --- a/client/windows/CTradeWindow.h +++ b/client/windows/CTradeWindow.h @@ -45,16 +45,13 @@ public: virtual void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const = 0; virtual void selectionChanged(bool side) = 0; //true == left virtual Point selectionOffset(bool Left) const = 0; - virtual std::string selectionSubtitle(bool Left) const = 0; - virtual void garrisonChanged() = 0; + virtual std::string updateSlotSubtitle(bool Left) const = 0; + virtual void updateGarrison() = 0; virtual void artifactsChanged(bool left) = 0; protected: std::function onWindowClosed; std::shared_ptr statusBar; - std::vector> labels; std::vector> images; - std::vector> buttons; - std::vector> texts; }; class CMarketplaceWindow : public CTradeWindow @@ -78,58 +75,12 @@ public: ~CMarketplaceWindow(); Point selectionOffset(bool Left) const override; - std::string selectionSubtitle(bool Left) const override; + std::string updateSlotSubtitle(bool Left) const override; - void garrisonChanged() override; //removes creatures with count 0 from the list (apparently whole stack has been sold) + void updateGarrison() override; //removes creatures with count 0 from the list (apparently whole stack has been sold) void artifactsChanged(bool left) override; void resourceChanged(); void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const override; void updateTraderText(); }; - -class CAltarWindow : public CTradeWindow -{ - std::shared_ptr artIcon; -public: - std::vector sacrificedUnits; //[slot_nr] -> how many creatures from that slot will be sacrificed - std::vector expPerUnit; - - std::shared_ptr sacrificeAll; - std::shared_ptr sacrificeBackpack; - std::shared_ptr expToLevel; - std::shared_ptr expOnAltar; - std::shared_ptr arts; - - CAltarWindow(const IMarket * Market, const CGHeroInstance * Hero, const std::function & onWindowClosed, EMarketMode Mode); - ~CAltarWindow(); - - void getExpValues(); - - void selectionChanged(bool side) override; //true == left - void selectOppositeItem(bool side); - void SacrificeAll(); - void SacrificeBackpack(); - - void putOnAltar(int backpackIndex); - bool putOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art); - void makeDeal() override; - void showAll(Canvas & to) override; - - void blockTrade(); - void sliderMoved(int to); - void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const override; - void mimicCres(); - - Point selectionOffset(bool Left) const override; - std::string selectionSubtitle(bool Left) const override; - void garrisonChanged() override; - void artifactsChanged(bool left) override; - void calcTotalExp(); - void setExpToLevel(); - void updateRight(std::shared_ptr toUpdate); - - void artifactPicked(); - int firstFreeSlot(); - void moveArtToAltar(std::shared_ptr, const CArtifactInstance * art); -}; diff --git a/client/windows/CWindowObject.h b/client/windows/CWindowObject.h index 4746f52c8..52111aee6 100644 --- a/client/windows/CWindowObject.h +++ b/client/windows/CWindowObject.h @@ -16,8 +16,6 @@ class CGStatusBar; class CWindowObject : public WindowBase { - std::shared_ptr createBg(const ImagePath & imageName, bool playerColored); - std::vector> shadowParts; void setShadow(bool on); @@ -32,6 +30,7 @@ protected: //To display border void updateShadow(); void setBackground(const ImagePath & filename); + std::shared_ptr createBg(const ImagePath & imageName, bool playerColored); public: enum EOptions { From 539b2e596de2be13ba2853d05c68f5eb2cdd9e76 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 6 Nov 2023 14:13:10 +0200 Subject: [PATCH 4/5] adjusting the placement of artifact slots --- client/widgets/CAltar.cpp | 2 +- client/widgets/CArtifactHolder.cpp | 2 +- client/widgets/CArtifactsOfHeroAltar.cpp | 7 +++++++ client/widgets/CArtifactsOfHeroBase.h | 12 ++++++------ client/windows/GUIClasses.cpp | 4 ++-- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp index 60f27c7a4..338297456 100644 --- a/client/widgets/CAltar.cpp +++ b/client/widgets/CAltar.cpp @@ -66,7 +66,7 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * CGI->generaltexth->zelp[570], std::bind(&CAltarArtifacts::sacrificeBackpack, this)); sacrificeBackpackButton->block(hero->artifactsInBackpack.empty()); - arts = std::make_shared(Point(-365, -10)); + arts = std::make_shared(Point(-365, -11)); arts->setHero(hero); int slotNum = 0; diff --git a/client/widgets/CArtifactHolder.cpp b/client/widgets/CArtifactHolder.cpp index 3a9bfc10f..334cd9f6e 100644 --- a/client/widgets/CArtifactHolder.cpp +++ b/client/widgets/CArtifactHolder.cpp @@ -93,7 +93,7 @@ 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); + selection = std::make_shared(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION, 0, -1, -1); selection->visible = false; } diff --git a/client/widgets/CArtifactsOfHeroAltar.cpp b/client/widgets/CArtifactsOfHeroAltar.cpp index 5c33ee05c..a104974a2 100644 --- a/client/widgets/CArtifactsOfHeroAltar.cpp +++ b/client/widgets/CArtifactsOfHeroAltar.cpp @@ -10,6 +10,7 @@ #include "StdInc.h" #include "CArtifactsOfHeroAltar.h" +#include "Buttons.h" #include "../CPlayerInterface.h" #include "../../CCallback.h" @@ -27,6 +28,12 @@ CArtifactsOfHeroAltar::CArtifactsOfHeroAltar(const Point & position) position, std::bind(&CArtifactsOfHeroAltar::scrollBackpack, this, _1)); pickedArtFromSlot = ArtifactPosition::PRE_FIRST; + + // The backpack is in the altar window above and to the right + for(auto & slot : backpack) + slot->moveBy(Point(2, -1)); + leftBackpackRoll->moveBy(Point(2, -1)); + rightBackpackRoll->moveBy(Point(2, -1)); }; CArtifactsOfHeroAltar::~CArtifactsOfHeroAltar() diff --git a/client/widgets/CArtifactsOfHeroBase.h b/client/widgets/CArtifactsOfHeroBase.h index 2fe10de74..a85b8ebff 100644 --- a/client/widgets/CArtifactsOfHeroBase.h +++ b/client/widgets/CArtifactsOfHeroBase.h @@ -54,13 +54,13 @@ protected: const std::vector slotPos = { - Point(509,30), Point(567,240), Point(509,80), //0-2 - Point(383,68), Point(564,183), Point(509,130), //3-5 - Point(431,68), Point(610,183), Point(515,295), //6-8 - Point(383,143), Point(399,194), Point(415,245), //9-11 - Point(431,296), Point(564,30), Point(610,30), //12-14 + Point(509,30), Point(568,242), Point(509,80), //0-2 + Point(383,69), Point(562,184), Point(509,131), //3-5 + Point(431,69), Point(610,184), Point(515,295), //6-8 + Point(383,143), Point(399,193), Point(415,244), //9-11 + Point(431,295), Point(564,30), Point(610,30), //12-14 Point(610,76), Point(610,122), Point(610,310), //15-17 - Point(381,296) //18 + Point(381,295) //18 }; virtual void init(CHeroArtPlace::ClickFunctor lClickCallback, CHeroArtPlace::ClickFunctor showPopupCallback, diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 34824e619..0d0a1e710 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -677,9 +677,9 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, manaValues[leftRight] = std::make_shared(155 + 490 * leftRight, qeLayout ? 66 : 71, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE); } - artifs[0] = std::make_shared(Point(-334, 150)); + artifs[0] = std::make_shared(Point(-334, 151)); artifs[0]->setHero(heroInst[0]); - artifs[1] = std::make_shared(Point(98, 150)); + artifs[1] = std::make_shared(Point(98, 151)); artifs[1]->setHero(heroInst[1]); addSetAndCallbacks(artifs[0]); From 41ee52d9d4340b28d548608710b7f1327a0b6a62 Mon Sep 17 00:00:00 2001 From: SoundSSGood <87084363+SoundSSGood@users.noreply.github.com> Date: Mon, 6 Nov 2023 15:21:40 +0200 Subject: [PATCH 5/5] fix build & suggested changed --- client/widgets/CAltar.cpp | 126 +++++++++++++++++--------------- client/widgets/CAltar.h | 5 ++ client/windows/CAltarWindow.cpp | 6 +- client/windows/CTradeWindow.cpp | 86 ++++++++++------------ client/windows/CTradeWindow.h | 4 - 5 files changed, 115 insertions(+), 112 deletions(-) diff --git a/client/widgets/CAltar.cpp b/client/widgets/CAltar.cpp index 338297456..ba76f47d3 100644 --- a/client/widgets/CAltar.cpp +++ b/client/widgets/CAltar.cpp @@ -73,29 +73,7 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * for(auto & altarSlotPos : posSlotsAltar) { auto altarSlot = std::make_shared(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum++); - altarSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void - { - 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(); - }; + altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1); altarSlot->subtitle = ""; items.front().emplace_back(altarSlot); } @@ -227,6 +205,30 @@ bool CAltarArtifacts::putArtOnAltar(std::shared_ptr altarSlot, c 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) : CAltar(market, hero) { @@ -239,16 +241,7 @@ 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, [this](int newVal) -> void - { - if(hLeft) - unitsOnAltar[hLeft->serial] = newVal; - if(hRight) - updateAltarSlot(hRight); - deal->block(calcExpAltarForHero() == 0); - updateControls(); - updateSubtitlesForSelected(); - }, 0, 0, 0, Orientation::HORIZONTAL); + 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)); unitsOnAltar.resize(GameConstants::ARMY_SIZE, 0); @@ -256,27 +249,7 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * sacrificeAllButton = std::make_shared( Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltar::sacrificeAll, this)); - auto clickPressed = [this](std::shared_ptr altarSlot, std::vector> & oppositeSlots, - std::shared_ptr & hCurSide, std::shared_ptr & hOppSide) -> void - { - std::shared_ptr oppositeSlot; - for(const auto & slot : oppositeSlots) - if(slot->serial == altarSlot->serial) - { - oppositeSlot = slot; - break; - } - - if(hCurSide != altarSlot && oppositeSlot) - { - hCurSide = altarSlot; - hOppSide = oppositeSlot; - updateControls(); - updateSubtitlesForSelected(); - redraw(); - } - }; - + // Creating slots for hero creatures for(int slotIdx = 0; slotIdx < GameConstants::ARMY_SIZE; slotIdx++) { CreatureID creatureId = CreatureID::NONE; @@ -286,21 +259,23 @@ CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * continue; auto heroSlot = std::make_shared(posSlotsHero[slotIdx], EType::CREATURE, creatureId.num, true, slotIdx); - heroSlot->clickPressedCallback = [this, clickPressed](std::shared_ptr altarSlot) -> void + heroSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void { - clickPressed(altarSlot, items[0], hLeft, hRight); + onSlotClickPressed(altarSlot, items[0], hLeft, hRight); }; heroSlot->subtitle = std::to_string(hero->getStackCount(SlotID(slotIdx))); items[1].emplace_back(heroSlot); } + + // 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, clickPressed](std::shared_ptr altarSlot) -> void + altarSlot->clickPressedCallback = [this](std::shared_ptr altarSlot) -> void { - clickPressed(altarSlot, items[1], hRight, hLeft); + onSlotClickPressed(altarSlot, items[1], hRight, hLeft); }; items[0].emplace_back(altarSlot); } @@ -454,4 +429,37 @@ void CAltarCreatures::updateAltarSlot(std::shared_ptr slot) 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]))) : ""; -} \ No newline at end of file +} + +void CAltarCreatures::onUnitsSliderMoved(int newVal) +{ + if(hLeft) + unitsOnAltar[hLeft->serial] = newVal; + if(hRight) + updateAltarSlot(hRight); + deal->block(calcExpAltarForHero() == 0); + updateControls(); + updateSubtitlesForSelected(); +} + +void CAltarCreatures::onSlotClickPressed(std::shared_ptr altarSlot, + std::vector> & oppositeSlots, + std::shared_ptr & hCurSide, std::shared_ptr & hOppSide) +{ + std::shared_ptr oppositeSlot; + for(const auto & slot : oppositeSlots) + if(slot->serial == altarSlot->serial) + { + oppositeSlot = slot; + break; + } + + if(hCurSide != altarSlot && oppositeSlot) + { + hCurSide = altarSlot; + hOppSide = oppositeSlot; + updateControls(); + updateSubtitlesForSelected(); + redraw(); + } +} diff --git a/client/widgets/CAltar.h b/client/widgets/CAltar.h index c6afe24b8..685afa731 100644 --- a/client/widgets/CAltar.h +++ b/client/widgets/CAltar.h @@ -59,6 +59,7 @@ private: }; bool putArtOnAltar(std::shared_ptr altarSlot, const CArtifactInstance * art); + void onSlotClickPressed(std::shared_ptr altarSlot); }; class CAltarCreatures : public CAltar @@ -95,4 +96,8 @@ private: void readExpValues(); void updateControls(); void updateSubtitlesForSelected(); + void onUnitsSliderMoved(int newVal); + void onSlotClickPressed(std::shared_ptr altarSlot, + std::vector> & oppositeSlots, + std::shared_ptr & hCurSide, std::shared_ptr & hOppSide); }; diff --git a/client/windows/CAltarWindow.cpp b/client/windows/CAltarWindow.cpp index faabbb5ca..249abcde2 100644 --- a/client/windows/CAltarWindow.cpp +++ b/client/windows/CAltarWindow.cpp @@ -30,12 +30,12 @@ CAltarWindow::CAltarWindow(const IMarket * market, const CGHeroInstance * hero, { OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE); + assert(mode == EMarketMode::ARTIFACT_EXP || mode == EMarketMode::CREATURE_EXP); if(mode == EMarketMode::ARTIFACT_EXP) createAltarArtifacts(market, hero); - else if (mode == EMarketMode::CREATURE_EXP) + else if(mode == EMarketMode::CREATURE_EXP) createAltarCreatures(market, hero); - else - close(); + updateExpToLevel(); statusBar = CGStatusBar::create(std::make_shared(background->getSurface(), Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26)); } diff --git a/client/windows/CTradeWindow.cpp b/client/windows/CTradeWindow.cpp index 04b1c59cf..5cb261793 100644 --- a/client/windows/CTradeWindow.cpp +++ b/client/windows/CTradeWindow.cpp @@ -163,9 +163,46 @@ void CTradeWindow::getPositionsFor(std::vector &poss, bool Left, EType typ // X X X // X X X // X - int h, w, x, y, dx, dy; - int leftToRightOffset; - getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset); + int h = 0, w = 0, x = 0, y = 0, dx = 0, dy = 0; + + switch(type) + { + case RESOURCE: + dx = 82; + dy = 79; + x = 39; + y = 180; + h = 68; + w = 70; + break; + 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; + w = 58; + h = 64; + dx = 83; + 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; const std::vector tmp = { @@ -672,49 +709,6 @@ void CMarketplaceWindow::resourceChanged() initSubs(true); } -void CMarketplaceWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const -{ - switch(type) - { - case RESOURCE: - dx = 82; - dy = 79; - x = 39; - y = 180; - h = 68; - w = 70; - break; - case PLAYER: - dx = 83; - dy = 118; - h = 64; - w = 58; - x = 44; - y = 83; - assert(Right); - break; - case CREATURE://45,123 - x = 45; - y = 123; - w = 58; - h = 64; - dx = 83; - dy = 98; - assert(!Right); - break; - case ARTIFACT_TYPE://45,123 - x = 340-289; - y = 180; - w = 44; - h = 44; - dx = 83; - dy = 79; - break; - } - - leftToRightOffset = 289; -} - void CMarketplaceWindow::updateTraderText() { if(readyToTrade) diff --git a/client/windows/CTradeWindow.h b/client/windows/CTradeWindow.h index 9c0763d68..04ea7529c 100644 --- a/client/windows/CTradeWindow.h +++ b/client/windows/CTradeWindow.h @@ -41,8 +41,6 @@ public: void setMode(EMarketMode Mode); //mode setter void artifactSelected(CHeroArtPlace *slot); //used when selling artifacts -> called when user clicked on artifact slot - - virtual void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const = 0; virtual void selectionChanged(bool side) = 0; //true == left virtual Point selectionOffset(bool Left) const = 0; virtual std::string updateSlotSubtitle(bool Left) const = 0; @@ -80,7 +78,5 @@ public: void updateGarrison() override; //removes creatures with count 0 from the list (apparently whole stack has been sold) void artifactsChanged(bool left) override; void resourceChanged(); - - void getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const override; void updateTraderText(); };