1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Merge pull request #3258 from SoundSSGood/trade-panels

Market rework
This commit is contained in:
Ivan Savenko
2024-01-12 21:53:13 +02:00
committed by GitHub
22 changed files with 1478 additions and 1223 deletions

View File

@@ -96,14 +96,12 @@ set(client_SRCS
renderSDL/SDL_Extensions.cpp
widgets/Buttons.cpp
widgets/CAltar.cpp
widgets/CArtifactHolder.cpp
widgets/CComponent.cpp
widgets/CExchangeController.cpp
widgets/CGarrisonInt.cpp
widgets/CreatureCostBox.cpp
widgets/ComboBox.cpp
widgets/CTradeBase.cpp
widgets/Images.cpp
widgets/MiscWidgets.cpp
widgets/ObjectLists.cpp
@@ -118,6 +116,10 @@ set(client_SRCS
widgets/CArtifactsOfHeroBackpack.cpp
widgets/CWindowWithArtifacts.cpp
widgets/RadialMenu.cpp
widgets/markets/CAltarArtifacts.cpp
widgets/markets/CAltarCreatures.cpp
widgets/markets/CTradeBase.cpp
widgets/markets/TradePanels.cpp
windows/CAltarWindow.cpp
windows/CCastleInterface.cpp
@@ -269,14 +271,12 @@ set(client_HEADERS
renderSDL/SDL_PixelAccess.h
widgets/Buttons.h
widgets/CAltar.h
widgets/CArtifactHolder.h
widgets/CComponent.h
widgets/CExchangeController.h
widgets/CGarrisonInt.h
widgets/CreatureCostBox.h
widgets/ComboBox.h
widgets/CTradeBase.h
widgets/Images.h
widgets/MiscWidgets.h
widgets/ObjectLists.h
@@ -291,6 +291,10 @@ set(client_HEADERS
widgets/CArtifactsOfHeroBackpack.h
widgets/CWindowWithArtifacts.h
widgets/RadialMenu.h
widgets/markets/CAltarArtifacts.h
widgets/markets/CAltarCreatures.h
widgets/markets/CTradeBase.h
widgets/markets/TradePanels.h
windows/CAltarWindow.h
windows/CCastleInterface.h

View File

@@ -1,466 +0,0 @@
/*
* CAltarWindow.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CAltar.h"
#include "../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<CTextBox>(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
// Total experience on the Altar
texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
deal = std::make_shared<CButton>(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"), CGI->generaltexth->zelp[585], std::bind(&CAltar::makeDeal, this));
expToLevel = std::make_shared<CLabel>(75, 477, FONT_SMALL, ETextAlignment::CENTER);
expForHero = std::make_shared<CLabel>(75, 545, FONT_SMALL, ETextAlignment::CENTER);
}
void CAltar::deselect()
{
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<CLabel>(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]));
labels.emplace_back(std::make_shared<CLabel>(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
selectedCost = std::make_shared<CLabel>(302, 500, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
selectedArt = std::make_shared<CArtPlace>(Point(280, 442));
sacrificeAllButton = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"),
CGI->generaltexth->zelp[571], std::bind(&CAltar::sacrificeAll, this));
sacrificeAllButton->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
sacrificeBackpackButton = std::make_shared<CButton>(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<CArtifactsOfHeroAltar>(Point(-365, -11));
arts->setHero(hero);
int slotNum = 0;
for(auto & altarSlotPos : posSlotsAltar)
{
auto altarSlot = std::make_shared<CTradeableItem>(altarSlotPos, EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum++);
altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1);
altarSlot->subtitle = "";
items.front().emplace_back(altarSlot);
}
calcExpAltarForHero();
deselect();
};
TExpType CAltarArtifacts::calcExpAltarForHero()
{
auto artifactsOfHero = std::dynamic_pointer_cast<CArtifactsOfHeroAltar>(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<TradeItemSell> positions;
for(const auto art : arts->artifactsOnAltar)
{
positions.push_back(hero->getSlotByInstance(art));
}
std::sort(positions.begin(), positions.end());
std::reverse(positions.begin(), positions.end());
LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
arts->artifactsOnAltar.clear();
for(auto item : items[0])
{
item->setID(-1);
item->subtitle = "";
}
deal->block(true);
calcExpAltarForHero();
}
void CAltarArtifacts::sacrificeAll()
{
std::vector<ConstTransitivePtr<CArtifactInstance>> 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<CTradeableItem> altarSlot, const CArtifactInstance * art)
{
if(putArtOnAltar(altarSlot, art))
{
CCS->curh->dragAndDropCursor(nullptr);
arts->unmarkSlots();
}
}
std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
{
return arts;
}
bool CAltarArtifacts::putArtOnAltar(std::shared_ptr<CTradeableItem> 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<int>(hero->calculateXp(exp));
arts->artifactsOnAltar.insert(art);
altarSlot->setArtInstance(art);
altarSlot->subtitle = std::to_string(exp);
deal->block(false);
return true;
};
void CAltarArtifacts::onSlotClickPressed(std::shared_ptr<CTradeableItem> 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)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
labels.emplace_back(std::make_shared<CLabel>(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW,
boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated())));
labels.emplace_back(std::make_shared<CLabel>(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479]));
texts.emplace_back(std::make_unique<CTextBox>(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
lSubtitle = std::make_shared<CLabel>(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
rSubtitle = std::make_shared<CLabel>(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
unitsSlider = std::make_shared<CSlider>(Point(231, 481), 137, std::bind(&CAltarCreatures::onUnitsSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
maxUnits = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, unitsSlider));
unitsOnAltar.resize(GameConstants::ARMY_SIZE, 0);
expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
sacrificeAllButton = std::make_shared<CButton>(
Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CAltar::sacrificeAll, this));
// Creating slots for hero creatures
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<CTradeableItem>(posSlotsHero[slotIdx], EType::CREATURE, creatureId.num, true, slotIdx);
heroSlot->clickPressedCallback = [this](std::shared_ptr<CTradeableItem> altarSlot) -> void
{
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<CTradeableItem>(posSlotsAltar[heroSlot->serial], EType::CREATURE_PLACEHOLDER, heroSlot->id, false, heroSlot->serial);
altarSlot->pos.w = heroSlot->pos.w; altarSlot->pos.h = heroSlot->pos.h;
altarSlot->clickPressedCallback = [this](std::shared_ptr<CTradeableItem> altarSlot) -> void
{
onSlotClickPressed(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<SlotID> 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<std::shared_ptr<CTradeableItem>> 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<TradeItemSell> ids;
std::vector<ui32> toSacrifice;
for(int i = 0; i < unitsOnAltar.size(); i++)
{
if(unitsOnAltar[i])
{
ids.push_back(SlotID(i));
toSacrifice.push_back(unitsOnAltar[i]);
}
}
LOCPLINT->cb->trade(market, EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero);
for(int & units : unitsOnAltar)
units = 0;
for(auto heroSlot : items[0])
{
heroSlot->setType(CREATURE_PLACEHOLDER);
heroSlot->subtitle = "";
}
}
void CAltarCreatures::sacrificeAll()
{
std::optional<SlotID> 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<CTradeableItem> slot)
{
auto units = unitsOnAltar[slot->serial];
slot->setType(units > 0 ? CREATURE : CREATURE_PLACEHOLDER);
slot->subtitle = units > 0 ?
boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "";
}
void CAltarCreatures::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<CTradeableItem> altarSlot,
std::vector<std::shared_ptr<CTradeableItem>> & oppositeSlots,
std::shared_ptr<CTradeableItem> & hCurSide, std::shared_ptr<CTradeableItem> & hOppSide)
{
std::shared_ptr<CTradeableItem> 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();
}
}

View File

@@ -1,103 +0,0 @@
/*
* 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<CLabel> expToLevel;
std::shared_ptr<CLabel> expForHero;
std::shared_ptr<CButton> sacrificeAllButton;
CAltar(const IMarket * market, const CGHeroInstance * hero);
virtual ~CAltar() = default;
virtual void sacrificeAll() = 0;
virtual void deselect();
virtual TExpType calcExpAltarForHero() = 0;
};
class CAltarArtifacts : public CAltar
{
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<CTradeableItem>, const CArtifactInstance * art);
std::shared_ptr<CArtifactsOfHeroAltar> getAOHset() const;
private:
std::shared_ptr<CArtPlace> selectedArt;
std::shared_ptr<CLabel> selectedCost;
std::shared_ptr<CButton> sacrificeBackpackButton;
std::shared_ptr<CArtifactsOfHeroAltar> arts;
const std::vector<Point> 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<CTradeableItem> altarSlot, const CArtifactInstance * art);
void onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSlot);
};
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<CTradeableItem> slot);
private:
std::shared_ptr<CButton> maxUnits;
std::shared_ptr<CSlider> unitsSlider;
std::vector<int> unitsOnAltar;
std::vector<int> expPerUnit;
std::shared_ptr<CLabel> lSubtitle, rSubtitle;
const std::vector<Point> 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<Point> posSlotsHero =
{
Point(45, 110), Point(128, 110), Point(211, 110),
Point(45, 208), Point(128, 208), Point(211, 208),
Point(128, 306)
};
void readExpValues();
void updateControls();
void updateSubtitlesForSelected();
void onUnitsSliderMoved(int newVal);
void onSlotClickPressed(std::shared_ptr<CTradeableItem> altarSlot,
std::vector<std::shared_ptr<CTradeableItem>> & oppositeSlots,
std::shared_ptr<CTradeableItem> & hCurSide, std::shared_ptr<CTradeableItem> & hOppSide);
};

View File

@@ -75,13 +75,11 @@ void CArtPlace::setInternals(const CArtifactInstance * artInst)
text = artInst->getDescription();
}
CArtPlace::CArtPlace(Point position, const CArtifactInstance * art)
: ourArt(art)
CArtPlace::CArtPlace(Point position, const CArtifactInstance * art)
: SelectableSlot(Rect(position, Point(44, 44)), Point(1, 1))
, ourArt(art)
, locked(false)
{
pos += position;
pos.w = pos.h = 44;
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
imageIndex = 0;
@@ -92,9 +90,6 @@ CArtPlace::CArtPlace(Point position, const CArtifactInstance * art)
image = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), imageIndex);
image->disable();
selection = std::make_shared<CAnimImage>(AnimationPath::builtin("artifact"), ArtifactID::ART_SELECTION, 0, -1, -1);
selection->visible = false;
}
const CArtifactInstance * CArtPlace::getArt()
@@ -170,16 +165,6 @@ bool CArtPlace::isLocked() const
return locked;
}
void CArtPlace::selectSlot(bool on)
{
selection->visible = on;
}
bool CArtPlace::isSelected() const
{
return selection->visible;
}
void CArtPlace::clickPressed(const Point & cursorPosition)
{
if(clickPressedCallback)
@@ -201,12 +186,6 @@ void CArtPlace::gesture(bool on, const Point & initialPosition, const Point & fi
gestureCallback(*this, initialPosition);
}
void CArtPlace::showAll(Canvas & to)
{
CIntObject::showAll(to);
selection->showAll(to);
}
void CArtPlace::setArtifact(const CArtifactInstance * art)
{
setInternals(art);

View File

@@ -29,7 +29,7 @@ public:
virtual void artifactAssembled(const ArtifactLocation & artLoc)=0;
};
class CArtPlace : public LRClickableAreaWTextComp
class CArtPlace : public SelectableSlot
{
public:
using ClickFunctor = std::function<void(CArtPlace&, const Point&)>;
@@ -40,9 +40,6 @@ public:
const CArtifactInstance * getArt();
void lockSlot(bool on);
bool isLocked() const;
void selectSlot(bool on);
bool isSelected() const;
void showAll(Canvas & to) override;
void setArtifact(const CArtifactInstance * art);
void setClickPressedCallback(ClickFunctor callback);
void setShowPopupCallback(ClickFunctor callback);
@@ -55,7 +52,6 @@ protected:
std::shared_ptr<CAnimImage> image;
const CArtifactInstance * ourArt;
int imageIndex;
std::shared_ptr<CAnimImage> selection;
bool locked;
ClickFunctor clickPressedCallback;
ClickFunctor showPopupCallback;

View File

@@ -19,6 +19,11 @@ CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position)
std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
position,
std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1));
for(const auto & [slot, artPlace] : artWorn)
artPlace->setSelectionWidth(2);
for(auto artPlace : backpack)
artPlace->setSelectionWidth(2);
};
void CArtifactsOfHeroMarket::scrollBackpack(int offset)

View File

@@ -1,285 +0,0 @@
/*
* 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);
if(image)
{
this->pos.w = image->pos.w;
this->pos.h = image->pos.h;
}
}
void CTradeBase::CTradeableItem::setType(EType newType)
{
if(type != newType)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
type = newType;
if(getIndex() < 0)
{
image = std::make_shared<CAnimImage>(getFilename(), 0);
image->disable();
}
else
{
image = std::make_shared<CAnimImage>(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, 77);
break;
case PLAYER:
posToSubCenter = Point(31, 76);
break;
case ARTIFACT_PLACEHOLDER:
case ARTIFACT_INSTANCE:
posToSubCenter = Point(19, 54);
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<std::shared_ptr<CTradeableItem>> & toRemove)
{
for(auto item : toRemove)
removeItem(item);
}
void CTradeBase::removeItem(std::shared_ptr<CTradeableItem> item)
{
items[item->left] -= item;
if(hRight == item)
hRight.reset();
}
void CTradeBase::getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove)
{
for(auto item : items[1])
if(!hero->getStackCount(SlotID(item->serial)))
toRemove.insert(item);
}

View File

@@ -1,88 +0,0 @@
/*
* CTradeBase.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "Images.h"
#include "../../lib/FunctionList.h"
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<CTradeableItem>
{
std::shared_ptr<CAnimImage> 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<void(std::shared_ptr<CTradeableItem> altarSlot)> clickPressedCallback;
void setType(EType newType);
void setID(int newID);
const CArtifactInstance* getArtInstance() const;
void setArtInstance(const CArtifactInstance * art);
CFunctionList<void()> 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<std::vector<std::shared_ptr<CTradeableItem>>, 2> items;
//highlighted items (nullptr if no highlight)
std::shared_ptr<CTradeableItem> hLeft;
std::shared_ptr<CTradeableItem> hRight;
std::shared_ptr<CButton> deal;
CTradeBase(const IMarket * market, const CGHeroInstance * hero);
void removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove);
void removeItem(std::shared_ptr<CTradeableItem> item);
void getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove);
virtual void makeDeal() = 0;
protected:
std::vector<std::shared_ptr<CLabel>> labels;
std::vector<std::shared_ptr<CButton>> buttons;
std::vector<std::shared_ptr<CTextBox>> texts;
};

View File

@@ -662,22 +662,37 @@ void CCreaturePic::setAmount(int newAmount)
}
TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color) :
color(color), colorLine(ColorRGBA()), drawLine(false)
color(color), colorLine(ColorRGBA()), drawLine(false), lineWidth(0)
{
pos = position + pos.topLeft();
}
TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine) :
color(color), colorLine(colorLine), drawLine(true)
TransparentFilledRectangle::TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine, int width) :
color(color), colorLine(colorLine), drawLine(true), lineWidth(width)
{
pos = position + pos.topLeft();
}
void TransparentFilledRectangle::setDrawBorder(bool on)
{
drawLine = on;
}
bool TransparentFilledRectangle::getDrawBorder()
{
return drawLine;
}
void TransparentFilledRectangle::setBorderWidth(int width)
{
lineWidth = width;
}
void TransparentFilledRectangle::showAll(Canvas & to)
{
to.drawColorBlended(pos, color);
if(drawLine)
to.drawBorder(pos, colorLine);
to.drawBorder(pos, colorLine, lineWidth);
}
SimpleLine::SimpleLine(Point pos1, Point pos2, ColorRGBA color) :
@@ -688,3 +703,36 @@ void SimpleLine::showAll(Canvas & to)
{
to.drawLine(pos1 + pos.topLeft(), pos2 + pos.topLeft(), color, color);
}
SelectableSlot::SelectableSlot(Rect area, Point oversize, const int width)
: LRClickableAreaWTextComp(area)
{
selection = std::make_unique<TransparentFilledRectangle>(
Rect(area.topLeft() - oversize, area.dimensions() + oversize * 2), Colors::TRANSPARENCY, Colors::YELLOW, width);
selectSlot(false);
}
SelectableSlot::SelectableSlot(Rect area, Point oversize)
: SelectableSlot(area, oversize, 1)
{
}
SelectableSlot::SelectableSlot(Rect area, const int width)
: SelectableSlot(area, Point(), width)
{
}
void SelectableSlot::selectSlot(bool on)
{
selection->setDrawBorder(on);
}
bool SelectableSlot::isSelected() const
{
return selection->getDrawBorder();
}
void SelectableSlot::setSelectionWidth(int width)
{
selection->setBorderWidth(width);
}

View File

@@ -252,9 +252,14 @@ class TransparentFilledRectangle : public CIntObject
ColorRGBA color;
ColorRGBA colorLine;
bool drawLine;
int lineWidth;
public:
TransparentFilledRectangle(Rect position, ColorRGBA color);
TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine);
TransparentFilledRectangle(Rect position, ColorRGBA color, ColorRGBA colorLine, int width = 1);
void setDrawBorder(bool on);
bool getDrawBorder();
void setBorderWidth(int width);
void showAll(Canvas & to) override;
};
@@ -267,3 +272,16 @@ public:
SimpleLine(Point pos1, Point pos2, ColorRGBA color);
void showAll(Canvas & to) override;
};
class SelectableSlot : public LRClickableAreaWTextComp
{
std::unique_ptr<TransparentFilledRectangle> selection;
public:
SelectableSlot(Rect area, Point oversize, const int width);
SelectableSlot(Rect area, Point oversize);
SelectableSlot(Rect area, const int width = 1);
void selectSlot(bool on);
bool isSelected() const;
void setSelectionWidth(int width);
};

View File

@@ -0,0 +1,215 @@
/*
* CAltarArtifacts.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CAltarArtifacts.h"
#include "../../gui/CGuiHandler.h"
#include "../../gui/CursorHandler.h"
#include "../../widgets/Buttons.h"
#include "../../widgets/TextControls.h"
#include "../../CGameInfo.h"
#include "../../CPlayerInterface.h"
#include "../../../CCallback.h"
#include "../../../lib/networkPacks/ArtifactLocation.h"
#include "../../../lib/CGeneralTextHandler.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
#include "../../../lib/mapObjects/CGMarket.h"
CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero)
: CTradeBase(market, hero)
{
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
deal = std::make_shared<CButton>(dealButtonPos, AnimationPath::builtin("ALTSACR.DEF"),
CGI->generaltexth->zelp[585], [this]() {CAltarArtifacts::makeDeal(); });
labels.emplace_back(std::make_shared<CLabel>(450, 34, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]));
labels.emplace_back(std::make_shared<CLabel>(302, 423, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
selectedCost = std::make_shared<CLabel>(302, 500, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
selectedArt = std::make_shared<CArtPlace>(Point(280, 442));
sacrificeAllButton = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"),
CGI->generaltexth->zelp[571], std::bind(&CExperienceAltar::sacrificeAll, this));
sacrificeAllButton->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
sacrificeBackpackButton = std::make_shared<CButton>(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<CArtifactsOfHeroAltar>(Point(-365, -11));
arts->setHero(hero);
int slotNum = 0;
for(auto & altarSlotPos : posSlotsAltar)
{
auto altarSlot = std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT_PLACEHOLDER, -1, false, slotNum);
altarSlot->clickPressedCallback = std::bind(&CAltarArtifacts::onSlotClickPressed, this, _1, hRight);
altarSlot->subtitle.clear();
items.front().emplace_back(altarSlot);
slotNum++;
}
expForHero->setText(std::to_string(0));
CTradeBase::deselect();
};
TExpType CAltarArtifacts::calcExpAltarForHero()
{
auto artifactsOfHero = std::dynamic_pointer_cast<CArtifactsOfHeroAltar>(arts);
TExpType expOnAltar(0);
for(const auto art : artifactsOfHero->artifactsOnAltar)
{
int dmp = 0;
int expOfArt = 0;
market->getOffer(art->getTypeId(), 0, dmp, expOfArt, EMarketMode::ARTIFACT_EXP);
expOnAltar += expOfArt;
}
auto resultExp = hero->calculateXp(expOnAltar);
expForHero->setText(std::to_string(resultExp));
return resultExp;
}
void CAltarArtifacts::makeDeal()
{
std::vector<TradeItemSell> positions;
for(const auto art : arts->artifactsOnAltar)
{
positions.push_back(hero->getSlotByInstance(art));
}
std::sort(positions.begin(), positions.end());
std::reverse(positions.begin(), positions.end());
LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
arts->artifactsOnAltar.clear();
for(auto item : items[0])
{
item->setID(-1);
item->subtitle.clear();
}
deal->block(true);
calcExpAltarForHero();
}
void CAltarArtifacts::sacrificeAll()
{
std::vector<ConstTransitivePtr<CArtifactInstance>> artsForMove;
for(const auto & [slot, slotInfo] : arts->getHero()->artifactsWorn)
{
if(!slotInfo.locked && slotInfo.artifact->artType->isTradable())
artsForMove.emplace_back(slotInfo.artifact);
}
for(auto artInst : artsForMove)
moveArtToAltar(nullptr, artInst);
arts->updateWornSlots();
sacrificeBackpack();
}
void CAltarArtifacts::sacrificeBackpack()
{
while(!arts->visibleArtSet.artifactsInBackpack.empty())
{
if(!putArtOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact))
break;
};
calcExpAltarForHero();
}
void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art)
{
if(art)
{
selectedArt->setArtifact(art);
int dmp = 0;
int exp = 0;
market->getOffer(art->getTypeId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP);
selectedCost->setText(std::to_string(hero->calculateXp(exp)));
}
else
{
selectedArt->setArtifact(nullptr);
selectedCost->setText("");
}
}
void CAltarArtifacts::moveArtToAltar(std::shared_ptr<CTradeableItem> altarSlot, const CArtifactInstance * art)
{
if(putArtOnAltar(altarSlot, art))
{
CCS->curh->dragAndDropCursor(nullptr);
arts->unmarkSlots();
}
}
std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
{
return arts;
}
bool CAltarArtifacts::putArtOnAltar(std::shared_ptr<CTradeableItem> altarSlot, const CArtifactInstance * art)
{
if(!art->artType->isTradable())
{
logGlobal->warn("Cannot put special artifact on altar!");
return false;
}
if(!altarSlot || altarSlot->id != -1)
{
int slotIndex = -1;
while(items[0][++slotIndex]->id >= 0 && slotIndex + 1 < items[0].size());
slotIndex = items[0][slotIndex]->id == -1 ? slotIndex : -1;
if(slotIndex < 0)
{
logGlobal->warn("No free slots on altar!");
return false;
}
altarSlot = items[0][slotIndex];
}
int dmp = 0;
int exp = 0;
market->getOffer(art->artType->getId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP);
exp = static_cast<int>(hero->calculateXp(exp));
arts->artifactsOnAltar.insert(art);
altarSlot->setArtInstance(art);
altarSlot->subtitle = std::to_string(exp);
deal->block(false);
return true;
};
void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
{
const auto pickedArtInst = arts->getPickedArtifact();
if(pickedArtInst)
{
arts->pickedArtMoveToAltar(ArtifactPosition::TRANSITION_POS);
moveArtToAltar(newSlot, pickedArtInst);
}
else if(const CArtifactInstance * art = newSlot->getArtInstance())
{
const auto hero = arts->getHero();
const auto slot = hero->getSlotByInstance(art);
assert(slot != ArtifactPosition::PRE_FIRST);
LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero->id, slot),
ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS));
arts->pickedArtFromSlot = slot;
arts->artifactsOnAltar.erase(art);
newSlot->setID(-1);
newSlot->subtitle.clear();
deal->block(!arts->artifactsOnAltar.size());
}
calcExpAltarForHero();
}

View File

@@ -0,0 +1,47 @@
/*
* CAltarArtifacts.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 "../CArtifactsOfHeroAltar.h"
#include "CTradeBase.h"
class CAltarArtifacts : public CExperienceAltar
{
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<CTradeableItem>, const CArtifactInstance * art);
std::shared_ptr<CArtifactsOfHeroAltar> getAOHset() const;
private:
std::shared_ptr<CArtPlace> selectedArt;
std::shared_ptr<CLabel> selectedCost;
std::shared_ptr<CButton> sacrificeBackpackButton;
std::shared_ptr<CArtifactsOfHeroAltar> arts;
const std::vector<Point> 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<CTradeableItem> altarSlot, const CArtifactInstance * art);
void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
};

View File

@@ -0,0 +1,251 @@
/*
* CAltarCreatures.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CAltarCreatures.h"
#include "../../gui/CGuiHandler.h"
#include "../../widgets/Buttons.h"
#include "../../widgets/Slider.h"
#include "../../widgets/TextControls.h"
#include "../../CGameInfo.h"
#include "../../CPlayerInterface.h"
#include "../../../CCallback.h"
#include "../../../lib/CGeneralTextHandler.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
#include "../../../lib/mapObjects/CGMarket.h"
CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero)
: CTradeBase(market, hero)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
deal = std::make_shared<CButton>(dealButtonPos, AnimationPath::builtin("ALTSACR.DEF"),
CGI->generaltexth->zelp[584], [this]() {CAltarCreatures::makeDeal();});
labels.emplace_back(std::make_shared<CLabel>(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW,
boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->getNameTranslated())));
labels.emplace_back(std::make_shared<CLabel>(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479]));
texts.emplace_back(std::make_unique<CTextBox>(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
lSubtitle = std::make_shared<CLabel>(180, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
rSubtitle = std::make_shared<CLabel>(426, 503, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
offerSlider = std::make_shared<CSlider>(Point(231, 481), 137, std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1), 0, 0, 0, Orientation::HORIZONTAL);
maxUnits = std::make_shared<CButton>(Point(147, 520), AnimationPath::builtin("IRCBTNS.DEF"), CGI->generaltexth->zelp[578], std::bind(&CSlider::scrollToMax, offerSlider));
unitsOnAltar.resize(GameConstants::ARMY_SIZE, 0);
expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
sacrificeAllButton = std::make_shared<CButton>(
Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), CGI->generaltexth->zelp[579], std::bind(&CExperienceAltar::sacrificeAll, this));
// Hero creatures panel
assert(leftTradePanel);
leftTradePanel->moveBy(Point(45, 110));
leftTradePanel->updateSlotsCallback = std::bind(&CCreaturesSelling::updateSubtitle, this);
for(const auto & slot : leftTradePanel->slots)
slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, hLeft);};
// Altar creatures panel
rightTradePanel = std::make_shared<CreaturesPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
{
CAltarCreatures::onSlotClickPressed(altarSlot, hRight);
}, leftTradePanel->slots);
rightTradePanel->moveBy(Point(334, 110));
leftTradePanel->deleteSlotsCheck = rightTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1);
readExpValues();
expForHero->setText(std::to_string(0));
CAltarCreatures::deselect();
};
void CAltarCreatures::readExpValues()
{
int dump;
for(auto heroSlot : leftTradePanel->slots)
{
if(heroSlot->id >= 0)
market->getOffer(heroSlot->id, 0, dump, expPerUnit[heroSlot->serial], EMarketMode::CREATURE_EXP);
}
}
void CAltarCreatures::updateControls()
{
int sliderAmount = 0;
if(hLeft)
{
std::optional<SlotID> lastSlot;
for(auto slot = SlotID(0); slot.num < GameConstants::ARMY_SIZE; slot++)
{
if(hero->getStackCount(slot) > unitsOnAltar[slot.num])
{
if(lastSlot.has_value())
{
lastSlot = std::nullopt;
break;
}
else
{
lastSlot = slot;
}
}
}
sliderAmount = hero->getStackCount(SlotID(hLeft->serial));
if(lastSlot.has_value() && lastSlot.value() == SlotID(hLeft->serial))
sliderAmount--;
}
offerSlider->setAmount(sliderAmount);
offerSlider->block(!offerSlider->getAmount());
if(hLeft)
offerSlider->scrollTo(unitsOnAltar[hLeft->serial]);
maxUnits->block(offerSlider->getAmount() == 0);
}
void CAltarCreatures::updateSubtitlesForSelected()
{
if(hLeft)
lSubtitle->setText(std::to_string(offerSlider->getValue()));
else
lSubtitle->setText("");
if(hRight)
rSubtitle->setText(hRight->subtitle);
else
rSubtitle->setText("");
}
void CAltarCreatures::updateSlots()
{
rightTradePanel->deleteSlots();
leftTradePanel->deleteSlots();
assert(leftTradePanel->slots.size() == rightTradePanel->slots.size());
readExpValues();
leftTradePanel->updateSlots();
}
void CAltarCreatures::deselect()
{
CTradeBase::deselect();
offerSlider->block(true);
maxUnits->block(true);
updateSubtitlesForSelected();
}
TExpType CAltarCreatures::calcExpAltarForHero()
{
TExpType expOnAltar(0);
auto oneUnitExp = expPerUnit.begin();
for(const auto units : unitsOnAltar)
expOnAltar += *oneUnitExp++ * units;
auto resultExp = hero->calculateXp(expOnAltar);
expForHero->setText(std::to_string(resultExp));
return resultExp;
}
void CAltarCreatures::makeDeal()
{
deselect();
offerSlider->scrollTo(0);
expForHero->setText(std::to_string(0));
std::vector<TradeItemSell> ids;
std::vector<ui32> toSacrifice;
for(int i = 0; i < unitsOnAltar.size(); i++)
{
if(unitsOnAltar[i])
{
ids.push_back(SlotID(i));
toSacrifice.push_back(unitsOnAltar[i]);
}
}
LOCPLINT->cb->trade(market, EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero);
for(int & units : unitsOnAltar)
units = 0;
for(auto heroSlot : rightTradePanel->slots)
{
heroSlot->setType(EType::CREATURE_PLACEHOLDER);
heroSlot->subtitle.clear();
}
}
void CAltarCreatures::sacrificeAll()
{
std::optional<SlotID> lastSlot;
for(auto heroSlot : leftTradePanel->slots)
{
auto stackCount = hero->getStackCount(SlotID(heroSlot->serial));
if(stackCount > unitsOnAltar[heroSlot->serial])
{
if(!lastSlot.has_value())
lastSlot = SlotID(heroSlot->serial);
unitsOnAltar[heroSlot->serial] = stackCount;
}
}
assert(lastSlot.has_value());
unitsOnAltar[lastSlot.value().num]--;
if(hRight)
offerSlider->scrollTo(unitsOnAltar[hRight->serial]);
for(auto altarSlot : rightTradePanel->slots)
updateAltarSlot(altarSlot);
updateSubtitlesForSelected();
deal->block(calcExpAltarForHero() == 0);
}
void CAltarCreatures::updateAltarSlot(std::shared_ptr<CTradeableItem> slot)
{
auto units = unitsOnAltar[slot->serial];
slot->setType(units > 0 ? EType::CREATURE : EType::CREATURE_PLACEHOLDER);
slot->subtitle = units > 0 ?
boost::str(boost::format(CGI->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "";
}
void CAltarCreatures::onOfferSliderMoved(int newVal)
{
if(hLeft)
unitsOnAltar[hLeft->serial] = newVal;
if(hRight)
updateAltarSlot(hRight);
deal->block(calcExpAltarForHero() == 0);
updateControls();
updateSubtitlesForSelected();
}
void CAltarCreatures::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSide)
{
if(hCurSide == newSlot)
return;
auto * oppositeSlot = &hLeft;
auto oppositePanel = leftTradePanel;
CTradeBase::onSlotClickPressed(newSlot, hCurSide);
if(hCurSide == hLeft)
{
oppositeSlot = &hRight;
oppositePanel = rightTradePanel;
}
std::shared_ptr<CTradeableItem> oppositeNewSlot;
for(const auto & slot : oppositePanel->slots)
if(slot->serial == newSlot->serial)
{
oppositeNewSlot = slot;
break;
}
assert(oppositeNewSlot);
CTradeBase::onSlotClickPressed(oppositeNewSlot, *oppositeSlot);
updateControls();
updateSubtitlesForSelected();
redraw();
}

View File

@@ -0,0 +1,37 @@
/*
* CAltarCreatures.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "CTradeBase.h"
class CAltarCreatures : public CExperienceAltar, public CCreaturesSelling
{
public:
CAltarCreatures(const IMarket * market, const CGHeroInstance * hero);
void updateSlots();
void deselect() override;
TExpType calcExpAltarForHero() override;
void makeDeal() override;
void sacrificeAll() override;
void updateAltarSlot(std::shared_ptr<CTradeableItem> slot);
private:
std::shared_ptr<CButton> maxUnits;
std::vector<int> unitsOnAltar;
std::vector<int> expPerUnit;
std::shared_ptr<CLabel> lSubtitle;
std::shared_ptr<CLabel> rSubtitle;
void readExpValues();
void updateControls();
void updateSubtitlesForSelected();
void onOfferSliderMoved(int newVal);
void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSide) override;
};

View File

@@ -0,0 +1,105 @@
/*
* CTradeBase.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CTradeBase.h"
#include "../MiscWidgets.h"
#include "../../gui/CGuiHandler.h"
#include "../../widgets/Buttons.h"
#include "../../widgets/TextControls.h"
#include "../../CGameInfo.h"
#include "../../../lib/CGeneralTextHandler.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
CTradeBase::CTradeBase(const IMarket * market, const CGHeroInstance * hero)
: market(market)
, hero(hero)
{
}
void CTradeBase::removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove)
{
for(auto item : toRemove)
removeItem(item);
}
void CTradeBase::removeItem(std::shared_ptr<CTradeableItem> item)
{
rightTradePanel->slots.erase(std::remove(rightTradePanel->slots.begin(), rightTradePanel->slots.end(), item));
if(hRight == item)
hRight.reset();
}
void CTradeBase::getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove)
{
for(auto item : leftTradePanel->slots)
if(!hero->getStackCount(SlotID(item->serial)))
toRemove.insert(item);
}
void CTradeBase::deselect()
{
if(hLeft)
hLeft->selectSlot(false);
if(hRight)
hRight->selectSlot(false);
hLeft = hRight = nullptr;
deal->block(true);
}
void CTradeBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
{
if(newSlot == hCurSlot)
return;
if(hCurSlot)
hCurSlot->selectSlot(false);
hCurSlot = newSlot;
newSlot->selectSlot(true);
}
CExperienceAltar::CExperienceAltar()
{
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
// Experience needed to reach next level
texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
// Total experience on the Altar
texts.emplace_back(std::make_shared<CTextBox>(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
expToLevel = std::make_shared<CLabel>(75, 477, FONT_SMALL, ETextAlignment::CENTER);
expForHero = std::make_shared<CLabel>(75, 545, FONT_SMALL, ETextAlignment::CENTER);
}
CCreaturesSelling::CCreaturesSelling()
{
assert(hero);
CreaturesPanel::slotsData slots;
for(auto slotId = SlotID(0); slotId.num < GameConstants::ARMY_SIZE; slotId++)
{
if(const auto & creature = hero->getCreature(slotId))
slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId)));
}
leftTradePanel = std::make_shared<CreaturesPanel>(nullptr, slots);
}
bool CCreaturesSelling::slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot)
{
return hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
}
void CCreaturesSelling::updateSubtitle()
{
for(auto & heroSlot : leftTradePanel->slots)
heroSlot->subtitle = std::to_string(this->hero->getStackCount(SlotID(heroSlot->serial)));
}

View File

@@ -0,0 +1,74 @@
/*
* CTradeBase.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "TradePanels.h"
VCMI_LIB_NAMESPACE_BEGIN
class IMarket;
class CGHeroInstance;
VCMI_LIB_NAMESPACE_END
class CButton;
class CSlider;
class CTradeBase
{
public:
const IMarket * market;
const CGHeroInstance * hero;
//all indexes: 1 = left, 0 = right
std::array<std::vector<std::shared_ptr<CTradeableItem>>, 2> items;
std::shared_ptr<TradePanelBase> leftTradePanel;
std::shared_ptr<TradePanelBase> rightTradePanel;
//highlighted items (nullptr if no highlight)
std::shared_ptr<CTradeableItem> hLeft;
std::shared_ptr<CTradeableItem> hRight;
std::shared_ptr<CButton> deal;
std::shared_ptr<CSlider> offerSlider;
std::vector<std::shared_ptr<CLabel>> labels;
std::vector<std::shared_ptr<CButton>> buttons;
std::vector<std::shared_ptr<CTextBox>> texts;
CTradeBase(const IMarket * market, const CGHeroInstance * hero);
void removeItems(const std::set<std::shared_ptr<CTradeableItem>> & toRemove);
void removeItem(std::shared_ptr<CTradeableItem> item);
void getEmptySlots(std::set<std::shared_ptr<CTradeableItem>> & toRemove);
virtual void makeDeal() = 0;
virtual void deselect();
virtual void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot);
};
// Market subclasses
class CExperienceAltar : virtual public CTradeBase, virtual public CIntObject
{
public:
std::shared_ptr<CLabel> expToLevel;
std::shared_ptr<CLabel> expForHero;
std::shared_ptr<CButton> sacrificeAllButton;
const Point dealButtonPos = Point(269, 520);
CExperienceAltar();
virtual void sacrificeAll() = 0;
virtual TExpType calcExpAltarForHero() = 0;
};
class CCreaturesSelling : virtual public CTradeBase, virtual public CIntObject
{
public:
CCreaturesSelling();
bool slotDeletingCheck(const std::shared_ptr<CTradeableItem> & slot);
void updateSubtitle();
};

View File

@@ -0,0 +1,392 @@
/*
* TradePanels.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 "TradePanels.h"
#include "../../gui/CGuiHandler.h"
#include "../../render/Canvas.h"
#include "../../widgets/TextControls.h"
#include "../../windows/InfoWindows.h"
#include "../../CGameInfo.h"
#include "../../CPlayerInterface.h"
#include "../../../CCallback.h"
#include "../../../lib/CGeneralTextHandler.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
CTradeableItem::CTradeableItem(const Rect & area, EType Type, int ID, bool Left, int Serial)
: SelectableSlot(area, Point(1, 1))
, artInstance(nullptr)
, type(EType(-1)) // set to invalid, will be corrected in setType
, id(ID)
, serial(Serial)
, left(Left)
, downSelection(false)
{
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
addUsedEvents(LCLICK);
addUsedEvents(HOVER);
addUsedEvents(SHOW_POPUP);
setType(Type);
this->pos.w = area.w;
this->pos.h = area.h;
}
void CTradeableItem::setType(EType newType)
{
if(type != newType)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
type = newType;
if(getIndex() < 0)
{
image = std::make_shared<CAnimImage>(getFilename(), 0);
image->disable();
}
else
{
image = std::make_shared<CAnimImage>(getFilename(), getIndex());
}
}
}
void 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 CTradeableItem::getFilename()
{
switch(type)
{
case EType::RESOURCE:
return AnimationPath::builtin("RESOURCE");
case EType::PLAYER:
return AnimationPath::builtin("CREST58");
case EType::ARTIFACT_TYPE:
case EType::ARTIFACT_PLACEHOLDER:
case EType::ARTIFACT_INSTANCE:
return AnimationPath::builtin("artifact");
case EType::CREATURE:
return AnimationPath::builtin("TWCRPORT");
default:
return {};
}
}
int CTradeableItem::getIndex()
{
if(id < 0)
return -1;
switch(type)
{
case EType::RESOURCE:
case EType::PLAYER:
return id;
case EType::ARTIFACT_TYPE:
case EType::ARTIFACT_INSTANCE:
case EType::ARTIFACT_PLACEHOLDER:
return CGI->artifacts()->getByIndex(id)->getIconIndex();
case EType::CREATURE:
return CGI->creatures()->getByIndex(id)->getIconIndex();
default:
return -1;
}
}
void CTradeableItem::showAll(Canvas & to)
{
Point posToBitmap;
Point posToSubCenter;
switch(type)
{
case EType::RESOURCE:
posToBitmap = Point(19, 9);
posToSubCenter = Point(35, 57);
break;
case EType::CREATURE_PLACEHOLDER:
case EType::CREATURE:
posToSubCenter = Point(29, 77);
break;
case EType::PLAYER:
posToSubCenter = Point(31, 77);
break;
case EType::ARTIFACT_PLACEHOLDER:
case EType::ARTIFACT_INSTANCE:
posToSubCenter = Point(22, 51);
if (downSelection)
posToSubCenter.y += 8;
break;
case EType::ARTIFACT_TYPE:
posToSubCenter = Point(35, 57);
posToBitmap = Point(13, 0);
break;
}
if(image)
{
image->moveTo(pos.topLeft() + posToBitmap);
CIntObject::showAll(to);
}
to.drawText(pos.topLeft() + posToSubCenter, FONT_SMALL, Colors::WHITE, ETextAlignment::CENTER, subtitle);
}
void CTradeableItem::clickPressed(const Point & cursorPosition)
{
if(clickPressedCallback)
clickPressedCallback(shared_from_this());
}
void 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 CTradeableItem::hover(bool on)
{
if(!on)
{
GH.statusbar()->clear();
return;
}
switch(type)
{
case EType::CREATURE:
case EType::CREATURE_PLACEHOLDER:
GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated()));
break;
case EType::ARTIFACT_PLACEHOLDER:
if(id < 0)
GH.statusbar()->write(CGI->generaltexth->zelp[582].first);
else
GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated());
break;
}
}
void CTradeableItem::showPopupWindow(const Point & cursorPosition)
{
switch(type)
{
case EType::CREATURE:
case EType::CREATURE_PLACEHOLDER:
break;
case EType::ARTIFACT_TYPE:
case EType::ARTIFACT_PLACEHOLDER:
//TODO: it's would be better for market to contain actual CArtifactInstance and not just ids of certain artifact type so we can use getEffectiveDescription.
if (id >= 0)
CRClickPopup::createAndPush(CGI->artifacts()->getByIndex(id)->getDescriptionTranslated());
break;
}
}
std::string CTradeableItem::getName(int number) const
{
switch(type)
{
case EType::PLAYER:
return CGI->generaltexth->capColors[id];
case EType::RESOURCE:
return CGI->generaltexth->restypes[id];
case EType::CREATURE:
if (number == 1)
return CGI->creh->objects[id]->getNameSingularTranslated();
else
return CGI->creh->objects[id]->getNamePluralTranslated();
case EType::ARTIFACT_TYPE:
case EType::ARTIFACT_INSTANCE:
return CGI->artifacts()->getByIndex(id)->getNameTranslated();
}
logGlobal->error("Invalid trade item type: %d", (int)type);
return "";
}
const CArtifactInstance * CTradeableItem::getArtInstance() const
{
switch(type)
{
case EType::ARTIFACT_PLACEHOLDER:
case EType::ARTIFACT_INSTANCE:
return artInstance;
default:
return nullptr;
}
}
void CTradeableItem::setArtInstance(const CArtifactInstance * art)
{
assert(type == EType::ARTIFACT_PLACEHOLDER || type == EType::ARTIFACT_INSTANCE);
artInstance = art;
if(art)
setID(art->getTypeId());
else
setID(-1);
}
void TradePanelBase::updateSlots()
{
if(updateSlotsCallback)
updateSlotsCallback();
}
void TradePanelBase::deselect()
{
for(const auto & slot : slots)
slot->selectSlot(false);
}
void TradePanelBase::clearSubtitles()
{
for(const auto & slot : slots)
slot->subtitle.clear();
}
void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty)
{
slot.subtitle = std::to_string(qty);
if(cost != 1)
{
slot.subtitle.append("/");
slot.subtitle.append(std::to_string(cost));
}
}
void TradePanelBase::deleteSlots()
{
if(deleteSlotsCheck)
slots.erase(std::remove_if(slots.begin(), slots.end(), deleteSlotsCheck), slots.end());
}
ResourcesPanel::ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles)
{
assert(resourcesForTrade.size() == slotsPos.size());
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
for(const auto & res : resourcesForTrade)
{
auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[res.num], slotDimension),
EType::RESOURCE, res.num, true, res.num));
slot->clickPressedCallback = clickPressedCallback;
slot->setSelectionWidth(selectionWidth);
}
updateSlotsCallback = updateSubtitles;
}
ArtifactsPanel::ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles,
const std::vector<TradeItemBuy> & arts)
{
assert(slotsForTrade == slotsPos.size());
assert(slotsForTrade == arts.size());
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
for(auto slotIdx = 0; slotIdx < slotsForTrade; slotIdx++)
{
auto artType = arts[slotIdx].getNum();
if(artType != ArtifactID::NONE)
{
auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotIdx], slotDimension),
EType::ARTIFACT_TYPE, artType, false, slotIdx));
slot->clickPressedCallback = clickPressedCallback;
slot->setSelectionWidth(selectionWidth);
}
}
updateSlotsCallback = updateSubtitles;
}
PlayersPanel::PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback)
{
assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size() + 1);
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
std::vector<PlayerColor> players;
for(auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT_I; player++)
{
if(player != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(player) == EPlayerStatus::INGAME)
players.emplace_back(player);
}
slots.resize(players.size());
int slotNum = 0;
for(auto & slot : slots)
{
slot = std::make_shared<CTradeableItem>(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, false, slotNum);
slot->clickPressedCallback = clickPressedCallback;
slot->setSelectionWidth(selectionWidth);
slot->subtitle = CGI->generaltexth->capColors[players[slotNum].num];
slotNum++;
}
}
CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots)
{
assert(initialSlots.size() <= GameConstants::ARMY_SIZE);
assert(slotsPos.size() <= GameConstants::ARMY_SIZE);
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
for(const auto & [creatureId, slotId, creaturesNum] : initialSlots)
{
auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotId.num], slotDimension),
creaturesNum == 0 ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, creatureId.num, true, slotId));
slot->clickPressedCallback = clickPressedCallback;
if(creaturesNum != 0)
slot->subtitle = std::to_string(creaturesNum);
slot->setSelectionWidth(selectionWidth);
}
}
CreaturesPanel::CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots)
{
assert(slots.size() <= GameConstants::ARMY_SIZE);
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
for(const auto & srcSlot : srcSlots)
{
auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[srcSlot->serial], srcSlot->pos.dimensions()),
emptySlots ? EType::CREATURE_PLACEHOLDER : EType::CREATURE, srcSlot->id, true, srcSlot->serial));
slot->clickPressedCallback = clickPressedCallback;
slot->subtitle = emptySlots ? "" : srcSlot->subtitle;
slot->setSelectionWidth(selectionWidth);
}
}

View File

@@ -0,0 +1,141 @@
/*
* TradePanels.h, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#pragma once
#include "../MiscWidgets.h"
#include "../Images.h"
#include "../../../lib/networkPacks/TradeItem.h"
enum class EType
{
RESOURCE, PLAYER, ARTIFACT_TYPE, CREATURE, CREATURE_PLACEHOLDER, ARTIFACT_PLACEHOLDER, ARTIFACT_INSTANCE
};
class CTradeableItem : public SelectableSlot, public std::enable_shared_from_this<CTradeableItem>
{
public:
std::shared_ptr<CAnimImage> image;
AnimationPath getFilename();
int getIndex();
using ClickPressedFunctor = std::function<void(const std::shared_ptr<CTradeableItem>&)>;
const CArtifactInstance * artInstance; //holds ptr to artifact instance id type artifact
EType type;
int id;
const int serial;
const bool left;
std::string subtitle;
ClickPressedFunctor clickPressedCallback;
void setType(EType newType);
void setID(int newID);
const CArtifactInstance * getArtInstance() const;
void setArtInstance(const CArtifactInstance * art);
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(const Rect & area, EType Type, int ID, bool Left, int Serial);
};
class TradePanelBase : public CIntObject
{
public:
using UpdateSlotsFunctor = std::function<void()>;
using DeleteSlotsCheck = std::function<bool(const std::shared_ptr<CTradeableItem>&)>;
std::vector<std::shared_ptr<CTradeableItem>> slots;
UpdateSlotsFunctor updateSlotsCallback;
DeleteSlotsCheck deleteSlotsCheck;
std::shared_ptr<CTradeableItem> selected;
const int selectionWidth = 2;
virtual void updateSlots();
virtual void deselect();
virtual void clearSubtitles();
void updateOffer(CTradeableItem & slot, int, int);
void deleteSlots();
};
class ResourcesPanel : public TradePanelBase
{
const std::vector<GameResID> resourcesForTrade =
{
GameResID::WOOD, GameResID::MERCURY, GameResID::ORE,
GameResID::SULFUR, GameResID::CRYSTAL, GameResID::GEMS,
GameResID::GOLD
};
const std::vector<Point> slotsPos =
{
Point(0, 0), Point(83, 0), Point(166, 0),
Point(0, 79), Point(83, 79), Point(166, 79),
Point(83, 158)
};
const Point slotDimension = Point(69, 66);
public:
ResourcesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles);
};
class ArtifactsPanel : public TradePanelBase
{
const std::vector<Point> slotsPos =
{
Point(0, 0), Point(83, 0), Point(166, 0),
Point(0, 79), Point(83, 79), Point(166, 79),
Point(83, 158)
};
const size_t slotsForTrade = 7;
const Point slotDimension = Point(69, 66);
public:
ArtifactsPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, UpdateSlotsFunctor updateSubtitles,
const std::vector<TradeItemBuy> & arts);
};
class PlayersPanel : public TradePanelBase
{
const std::vector<Point> slotsPos =
{
Point(0, 0), Point(83, 0), Point(166, 0),
Point(0, 118), Point(83, 118), Point(166, 118),
Point(83, 236)
};
const Point slotDimension = Point(58, 64);
public:
explicit PlayersPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback);
};
class CreaturesPanel : public TradePanelBase
{
const std::vector<Point> slotsPos =
{
Point(0, 0), Point(83, 0), Point(166, 0),
Point(0, 98), Point(83, 98), Point(166, 98),
Point(83, 196)
};
const Point slotDimension = Point(58, 64);
public:
using slotsData = std::vector<std::tuple<CreatureID, SlotID, int>>;
CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback, const slotsData & initialSlots);
CreaturesPanel(CTradeableItem::ClickPressedFunctor clickPressedCallback,
const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots = true);
};

View File

@@ -48,7 +48,7 @@ void CAltarWindow::updateExpToLevel()
void CAltarWindow::updateGarrisons()
{
if(auto altarCreatures = std::static_pointer_cast<CAltarCreatures>(altar))
altarCreatures->updateGarrison();
altarCreatures->updateSlots();
}
bool CAltarWindow::holdsGarrison(const CArmedInstance * army)
@@ -130,12 +130,10 @@ void CAltarWindow::showAll(Canvas & to)
if(altar->hRight)
{
to.drawBorder(Rect::createAround(altar->hRight->pos, 1), Colors::BRIGHT_YELLOW, 2);
altar->hRight->showAllAt(altar->pos.topLeft() + Point(396, 423), "", to);
}
if(altar->hLeft)
{
to.drawBorder(Rect::createAround(altar->hLeft->pos, 1), Colors::BRIGHT_YELLOW, 2);
altar->hLeft->showAllAt(altar->pos.topLeft() + Point(150, 423), "", to);
}
}

View File

@@ -9,7 +9,8 @@
*/
#pragma once
#include "../widgets/CAltar.h"
#include "../widgets/markets/CAltarArtifacts.h"
#include "../widgets/markets/CAltarCreatures.h"
#include "../widgets/CWindowWithArtifacts.h"
#include "CWindowObject.h"
@@ -28,7 +29,7 @@ public:
private:
const CGHeroInstance * hero;
std::shared_ptr<CAltar> altar;
std::shared_ptr<CExperienceAltar> altar;
std::shared_ptr<CButton> changeModeButton;
std::shared_ptr<CButton> quitButton;
std::function<void()> windowClosedCallback;

View File

@@ -47,24 +47,24 @@ void CTradeWindow::initTypes()
switch(mode)
{
case EMarketMode::RESOURCE_RESOURCE:
itemsType[1] = RESOURCE;
itemsType[0] = RESOURCE;
itemsType[1] = EType::RESOURCE;
itemsType[0] = EType::RESOURCE;
break;
case EMarketMode::RESOURCE_PLAYER:
itemsType[1] = RESOURCE;
itemsType[0] = PLAYER;
itemsType[1] = EType::RESOURCE;
itemsType[0] = EType::PLAYER;
break;
case EMarketMode::CREATURE_RESOURCE:
itemsType[1] = CREATURE;
itemsType[0] = RESOURCE;
itemsType[1] = EType::CREATURE;
itemsType[0] = EType::RESOURCE;
break;
case EMarketMode::RESOURCE_ARTIFACT:
itemsType[1] = RESOURCE;
itemsType[0] = ARTIFACT_TYPE;
itemsType[1] = EType::RESOURCE;
itemsType[0] = EType::ARTIFACT_TYPE;
break;
case EMarketMode::ARTIFACT_RESOURCE:
itemsType[1] = ARTIFACT_INSTANCE;
itemsType[0] = RESOURCE;
itemsType[1] = EType::ARTIFACT_INSTANCE;
itemsType[0] = EType::RESOURCE;
break;
}
}
@@ -73,215 +73,115 @@ void CTradeWindow::initItems(bool Left)
{
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255-DISPOSE);
if(Left && (itemsType[1] == ARTIFACT_TYPE || itemsType[1] == ARTIFACT_INSTANCE))
if(Left && (itemsType[1] == EType::ARTIFACT_TYPE || itemsType[1] == EType::ARTIFACT_INSTANCE))
{
if(mode == EMarketMode::ARTIFACT_RESOURCE)
{
auto item = std::make_shared<CTradeableItem>(Point(137, 469), itemsType[Left], -1, 1, 0);
auto item = std::make_shared<CTradeableItem>(Rect(Point(137, 469), Point()), itemsType[Left], -1, 1, 0);
item->recActions &= ~(UPDATE | SHOWALL);
items[Left].push_back(item);
}
}
else
{
std::vector<int> *ids = getItemsIds(Left);
std::vector<Rect> pos;
int amount = -1;
getPositionsFor(pos, Left, itemsType[Left]);
if(Left || !ids)
amount = 7;
else
amount = static_cast<int>(ids->size());
if(ids)
vstd::amin(amount, ids->size());
for(int j=0; j<amount; j++)
auto updRightSub = [this](EMarketMode marketMode)
{
int id = (ids && ids->size()>j) ? (*ids)[j] : j;
if(id < 0 && mode != EMarketMode::ARTIFACT_EXP) //when sacrificing artifacts we need to prepare empty slots
continue;
auto item = std::make_shared<CTradeableItem>(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<CTradeableItem> altarSlot) -> void
if(hLeft)
for(const auto & slot : rightTradePanel->slots)
{
if(altarSlot->left)
{
if(hLeft != altarSlot)
hLeft = altarSlot;
else
return;
}
else
{
if(hRight != altarSlot)
hRight = altarSlot;
else
return;
}
selectionChanged(altarSlot->left);
};
int h1, h2; //hlp variables for getting offer
market->getOffer(hLeft->id, slot->id, h1, h2, marketMode);
items[Left].push_back(item);
}
vstd::clear_pointer(ids);
initSubs(Left);
}
}
rightTradePanel->updateOffer(*slot, h1, h2);
}
else
rightTradePanel->clearSubtitles();
};
std::vector<int> *CTradeWindow::getItemsIds(bool Left)
{
std::vector<int> *ids = nullptr;
if(Left)
{
switch(itemsType[1])
auto clickPressedTradePanel = [this](const std::shared_ptr<CTradeableItem> & newSlot, bool left)
{
case CREATURE:
ids = new std::vector<int>;
for(int i = 0; i < 7; i++)
CTradeBase::onSlotClickPressed(newSlot, left ? hLeft : hRight);
selectionChanged(left);
};
if(Left && mode == EMarketMode::CREATURE_RESOURCE)
{
CreaturesPanel::slotsData slots;
for(auto slotId = SlotID(0); slotId.num < GameConstants::ARMY_SIZE; slotId++)
{
if(const CCreature *c = hero->getCreature(SlotID(i)))
ids->push_back(c->getId());
else
ids->push_back(-1);
if(const auto & creature = hero->getCreature(slotId))
slots.emplace_back(std::make_tuple(creature->getId(), slotId, hero->getStackCount(slotId)));
}
break;
leftTradePanel = std::make_shared<CreaturesPanel>(std::bind(clickPressedTradePanel, _1, true), slots);
leftTradePanel->moveBy(Point(45, 123));
leftTradePanel->deleteSlotsCheck = [this](const std::shared_ptr<CTradeableItem> & slot)
{
return this->hero->getStackCount(SlotID(slot->serial)) == 0 ? true : false;
};
}
}
else
{
switch(itemsType[0])
else if(Left && (mode == EMarketMode::RESOURCE_RESOURCE || mode == EMarketMode::RESOURCE_ARTIFACT || mode == EMarketMode::RESOURCE_PLAYER))
{
case PLAYER:
ids = new std::vector<int>;
for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
if(PlayerColor(i) != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(PlayerColor(i)) == EPlayerStatus::INGAME)
ids->push_back(i);
break;
case ARTIFACT_TYPE:
ids = new std::vector<int>;
for (auto const & item : market->availableItemsIds(mode))
ids->push_back(item.getNum());
break;
leftTradePanel = std::make_shared<ResourcesPanel>(
[clickPressedTradePanel](const std::shared_ptr<CTradeableItem> & newSlot)
{
clickPressedTradePanel(newSlot, true);
},
[this]()
{
for(const auto & slot : leftTradePanel->slots)
slot->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(slot->serial)));
});
leftTradePanel->moveBy(Point(39, 182));
leftTradePanel->updateSlots();
}
else if(!Left && mode == EMarketMode::RESOURCE_RESOURCE)
{
rightTradePanel = std::make_shared<ResourcesPanel>(
[clickPressedTradePanel](const std::shared_ptr<CTradeableItem> & newSlot)
{
clickPressedTradePanel(newSlot, false);
},
[this, updRightSub]()
{
updRightSub(EMarketMode::RESOURCE_RESOURCE);
if(hLeft)
rightTradePanel->slots[hLeft->serial]->subtitle = CGI->generaltexth->allTexts[164]; // n/a
});
rightTradePanel->moveBy(Point(327, 181));
}
else if(!Left && (mode == EMarketMode::ARTIFACT_RESOURCE || mode == EMarketMode::CREATURE_RESOURCE))
{
rightTradePanel = std::make_shared<ResourcesPanel>(std::bind(clickPressedTradePanel, _1, false),
std::bind(updRightSub, EMarketMode::ARTIFACT_RESOURCE));
rightTradePanel->moveBy(Point(327, 181));
}
else if(!Left && mode == EMarketMode::RESOURCE_ARTIFACT)
{
rightTradePanel = std::make_shared<ArtifactsPanel>(std::bind(clickPressedTradePanel, _1, false),
std::bind(updRightSub, EMarketMode::RESOURCE_ARTIFACT), market->availableItemsIds(mode));
rightTradePanel->moveBy(Point(327, 181));
rightTradePanel->deleteSlotsCheck = [this](const std::shared_ptr<CTradeableItem> & slot)
{
return vstd::contains(market->availableItemsIds(EMarketMode::RESOURCE_ARTIFACT), ArtifactID(slot->id)) ? false : true;
};
}
else if(!Left && mode == EMarketMode::RESOURCE_PLAYER)
{
rightTradePanel = std::make_shared<PlayersPanel>(std::bind(clickPressedTradePanel, _1, false));
rightTradePanel->moveBy(Point(333, 83));
}
}
return ids;
}
void CTradeWindow::getPositionsFor(std::vector<Rect> &poss, bool Left, EType type) const
{
//seven boxes:
// X X X
// X X X
// X
int h = 0, w = 0, x = 0, y = 0, dx = 0, dy = 0;
switch(type)
{
case 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<Rect> 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;
}
}
void CTradeWindow::initSubs(bool Left)
{
for(auto item : items[Left])
{
if(itemsType[Left] == EType::RESOURCE || itemsType[Left] == EType::ARTIFACT_TYPE)
{
if(Left)
{
switch(itemsType[1])
{
case CREATURE:
item->subtitle = std::to_string(hero->getStackCount(SlotID(item->serial)));
break;
case RESOURCE:
item->subtitle = std::to_string(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(item->serial)));
break;
}
}
else //right side
{
if(itemsType[0] == PLAYER)
{
item->subtitle = CGI->generaltexth->capColors[item->id];
}
else if(hLeft)//artifact, creature
{
int h1, h2; //hlp variables for getting offer
market->getOffer(hLeft->id, item->id, h1, h2, mode);
if(item->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources
{
std::ostringstream oss;
oss << h2;
if(h1!=1)
oss << "/" << h1;
item->subtitle = oss.str();
}
else
item->subtitle = CGI->generaltexth->allTexts[164]; // n/a
}
else
item->subtitle = "";
}
leftTradePanel->updateSlots();
else
rightTradePanel->updateSlots();
return;
}
}
@@ -289,11 +189,6 @@ void CTradeWindow::showAll(Canvas & to)
{
CWindowObject::showAll(to);
if(hRight)
to.drawBorder(Rect::createAround(hRight->pos, 1), Colors::BRIGHT_YELLOW, 2);
if(hLeft && hLeft->type != ARTIFACT_INSTANCE)
to.drawBorder(Rect::createAround(hLeft->pos, 1), Colors::BRIGHT_YELLOW, 2);
if(readyToTrade)
{
if(hLeft)
@@ -548,6 +443,10 @@ void CMarketplaceWindow::makeDeal()
madeTransaction = true;
hLeft = nullptr;
hRight = nullptr;
if(leftTradePanel)
leftTradePanel->deselect();
assert(rightTradePanel);
rightTradePanel->deselect();
selectionChanged(true);
}
@@ -573,9 +472,9 @@ void CMarketplaceWindow::selectionChanged(bool side)
if(slider)
{
int newAmount = -1;
if(itemsType[1] == RESOURCE)
if(itemsType[1] == EType::RESOURCE)
newAmount = LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId));
else if(itemsType[1] == CREATURE)
else if(itemsType[1] == EType::CREATURE)
newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->stacksCount() == 1 && hero->needsLastStack());
else
assert(0);
@@ -585,7 +484,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
max->block(false);
deal->block(false);
}
else if(itemsType[1] == RESOURCE) //buying -> check if we can afford transaction
else if(itemsType[1] == EType::RESOURCE) //buying -> check if we can afford transaction
{
deal->block(LOCPLINT->cb->getResourceAmount(static_cast<EGameResID>(soldItemId)) < r1);
}
@@ -603,7 +502,7 @@ void CMarketplaceWindow::selectionChanged(bool side)
deal->block(true);
}
if(side && itemsType[0] != PLAYER) //items[1] selection changed, recalculate offers
if(side && itemsType[0] != EType::PLAYER) //items[1] selection changed, recalculate offers
initSubs(false);
updateTraderText();
@@ -638,10 +537,8 @@ void CMarketplaceWindow::updateGarrison()
if(mode != EMarketMode::CREATURE_RESOURCE)
return;
std::set<std::shared_ptr<CTradeableItem>> toRemove;
getEmptySlots(toRemove);
removeItems(toRemove);
initSubs(true);
leftTradePanel->deleteSlots();
leftTradePanel->updateSlots();
}
void CMarketplaceWindow::artifactsChanged(bool Left)
@@ -649,17 +546,8 @@ void CMarketplaceWindow::artifactsChanged(bool Left)
assert(!Left);
if(mode != EMarketMode::RESOURCE_ARTIFACT)
return;
std::vector<TradeItemBuy> available = market->availableItemsIds(mode);
std::set<std::shared_ptr<CTradeableItem>> toRemove;
for(auto item : items[0])
if(!vstd::contains(available, ArtifactID(item->id)))
toRemove.insert(item);
removeItems(toRemove);
// clear set to erase final instance of shared_ptr - we want to redraw screen only after it has been deleted
toRemove.clear();
rightTradePanel->deleteSlots();
redraw();
}
@@ -669,8 +557,8 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const
{
switch(itemsType[1])
{
case RESOURCE:
case CREATURE:
case EType::RESOURCE:
case EType::CREATURE:
{
int val = slider
? slider->getValue() * r1
@@ -678,7 +566,7 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const
return std::to_string(val);
}
case ARTIFACT_INSTANCE:
case EType::ARTIFACT_INSTANCE:
return ((deal->isBlocked()) ? "0" : "1");
}
}
@@ -686,14 +574,14 @@ std::string CMarketplaceWindow::updateSlotSubtitle(bool Left) const
{
switch(itemsType[0])
{
case RESOURCE:
case EType::RESOURCE:
if(slider)
return std::to_string( slider->getValue() * r2 );
else
return std::to_string(r2);
case ARTIFACT_TYPE:
case EType::ARTIFACT_TYPE:
return ((deal->isBlocked()) ? "0" : "1");
case PLAYER:
case EType::PLAYER:
return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
}
}
@@ -707,26 +595,26 @@ Point CMarketplaceWindow::selectionOffset(bool Left) const
{
switch(itemsType[1])
{
case RESOURCE:
return Point(122, 446);
case CREATURE:
case EType::RESOURCE:
return Point(122, 448);
case EType::CREATURE:
return Point(128, 450);
case ARTIFACT_INSTANCE:
return Point(134, 466);
case EType::ARTIFACT_INSTANCE:
return Point(134, 469);
}
}
else
{
switch(itemsType[0])
{
case RESOURCE:
case EType::RESOURCE:
if(mode == EMarketMode::ARTIFACT_RESOURCE)
return Point(410, 469);
return Point(410, 471);
else
return Point(410, 446);
case ARTIFACT_TYPE:
return Point(425, 447);
case PLAYER:
return Point(410, 448);
case EType::ARTIFACT_TYPE:
return Point(411, 449);
case EType::PLAYER:
return Point(417, 451);
}
}

View File

@@ -9,7 +9,7 @@
*/
#pragma once
#include "../widgets/CTradeBase.h"
#include "../widgets/markets/CTradeBase.h"
#include "../widgets/CWindowWithArtifacts.h"
#include "CWindowObject.h"
@@ -36,8 +36,6 @@ public:
void initSubs(bool Left);
void initTypes();
void initItems(bool Left);
std::vector<int> *getItemsIds(bool Left); //nullptr if default
void getPositionsFor(std::vector<Rect> &poss, bool Left, EType type) const;
void setMode(EMarketMode Mode); //mode setter
void artifactSelected(CArtPlace * slot); //used when selling artifacts -> called when user clicked on artifact slot