1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-16 10:19:47 +02:00
vcmi/client/widgets/markets/CAltarArtifacts.cpp
Ivan Savenko 20d5b33ea6 Remove marketModes as member
marketModes are now generated in runtime and are not a member of
IMarket. Was not a bad change, but towns load buildings before town type
is randomized, leading to case where market modes are not actually known
when building is added to town (like random towns with market built)

Since altar requires CArtifactSet for work, IMarket will now always
contain it, but it will only be accessible if market supports altar
mode.
2024-08-27 14:07:00 +00:00

238 lines
7.9 KiB
C++

/*
* 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/Shortcut.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/texts/CGeneralTextHandler.h"
#include "../../../lib/mapObjects/CGHeroInstance.h"
#include "../../../lib/mapObjects/IMarket.h"
CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance * hero)
: CMarketBase(market, hero)
{
OBJECT_CONSTRUCTION;
assert(market->getArtifactsStorage());
altarArtifactsStorage = market->getArtifactsStorage();
deal = std::make_shared<CButton>(Point(269, 520), AnimationPath::builtin("ALTSACR.DEF"),
CGI->generaltexth->zelp[585], [this]() {CAltarArtifacts::makeDeal(); }, EShortcut::MARKET_DEAL);
labels.emplace_back(std::make_shared<CLabel>(450, 32, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]));
labels.emplace_back(std::make_shared<CLabel>(302, 424, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]));
sacrificeAllButton = std::make_shared<CButton>(Point(393, 520), AnimationPath::builtin("ALTFILL.DEF"),
CGI->generaltexth->zelp[571], std::bind(&CExperienceAltar::sacrificeAll, this), EShortcut::MARKET_SACRIFICE_ALL);
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), EShortcut::MARKET_SACRIFICE_BACKPACK);
sacrificeBackpackButton->block(hero->artifactsInBackpack.empty());
// Hero's artifacts
heroArts = std::make_shared<CArtifactsOfHeroAltar>(Point(-365, -11));
heroArts->setHero(hero);
heroArts->altarId = market->getObjInstanceID();
// Altar
offerTradePanel = std::make_shared<ArtifactsAltarPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
{
CAltarArtifacts::onSlotClickPressed(altarSlot, offerTradePanel);
});
offerTradePanel->updateSlotsCallback = std::bind(&CAltarArtifacts::updateAltarSlots, this);
offerTradePanel->moveTo(pos.topLeft() + Point(315, 52));
CMarketBase::updateShowcases();
CAltarArtifacts::deselect();
};
TExpType CAltarArtifacts::calcExpAltarForHero()
{
TExpType expOnAltar(0);
for(const auto & tradeSlot : tradeSlotsMap)
expOnAltar += calcExpCost(tradeSlot.second->getTypeId());
expForHero->setText(std::to_string(expOnAltar));
return expOnAltar;
}
void CAltarArtifacts::deselect()
{
CMarketBase::deselect();
CExperienceAltar::deselect();
tradeSlotsMap.clear();
// The event for removing artifacts from the altar will not be triggered. Therefore, we clean the altar immediately.
for(const auto & slot : offerTradePanel->slots)
slot->clear();
offerTradePanel->showcaseSlot->clear();
}
void CAltarArtifacts::update()
{
CMarketBase::update();
CExperienceAltar::update();
if(const auto art = hero->getArt(ArtifactPosition::TRANSITION_POS))
offerQty = calcExpCost(art->getTypeId());
else
offerQty = 0;
updateShowcases();
redraw();
}
void CAltarArtifacts::makeDeal()
{
std::vector<TradeItemSell> positions;
for(const auto & [altarSlot, artInst] : tradeSlotsMap)
{
positions.push_back(artInst->getId());
}
LOCPLINT->cb->trade(market->getObjInstanceID(), EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
deselect();
}
void CAltarArtifacts::sacrificeAll()
{
LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, true, true);
}
void CAltarArtifacts::sacrificeBackpack()
{
LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, heroArts->altarId, false, false, true);
}
std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
{
return heroArts;
}
void CAltarArtifacts::updateAltarSlots()
{
assert(altarArtifactsStorage->artifactsInBackpack.size() <= GameConstants::ALTAR_ARTIFACTS_SLOTS);
assert(tradeSlotsMap.size() <= GameConstants::ALTAR_ARTIFACTS_SLOTS);
auto tradeSlotsMapNewArts = tradeSlotsMap;
for(const auto & altarSlot : offerTradePanel->slots)
if(altarSlot->id != -1)
{
if(tradeSlotsMap.find(altarSlot) == tradeSlotsMap.end())
{
altarSlot->setID(-1);
altarSlot->subtitle->clear();
}
else
{
tradeSlotsMapNewArts.erase(altarSlot);
}
}
for(auto & tradeSlot : tradeSlotsMapNewArts)
{
assert(tradeSlot.first->id == -1);
assert(altarArtifactsStorage->getArtPos(tradeSlot.second) != ArtifactPosition::PRE_FIRST);
tradeSlot.first->setID(tradeSlot.second->getTypeId().num);
tradeSlot.first->subtitle->setText(std::to_string(calcExpCost(tradeSlot.second->getTypeId())));
}
auto newArtsFromBulkMove = altarArtifactsStorage->artifactsInBackpack;
for(const auto & [altarSlot, art] : tradeSlotsMap)
{
newArtsFromBulkMove.erase(std::remove_if(newArtsFromBulkMove.begin(), newArtsFromBulkMove.end(), [artForRemove = art](auto & slotInfo)
{
return slotInfo.artifact == artForRemove;
}));
}
for(const auto & slotInfo : newArtsFromBulkMove)
{
for(const auto & altarSlot : offerTradePanel->slots)
if(altarSlot->id == -1)
{
altarSlot->setID(slotInfo.artifact->getTypeId().num);
altarSlot->subtitle->setText(std::to_string(calcExpCost(slotInfo.artifact->getTypeId())));
tradeSlotsMap.try_emplace(altarSlot, slotInfo.artifact);
break;
}
}
calcExpAltarForHero();
deal->block(tradeSlotsMap.empty() || !LOCPLINT->makingTurn);
}
void CAltarArtifacts::putBackArtifacts()
{
// TODO: If the backpack capacity limit is enabled, artifacts may remain on the altar.
// Perhaps should be erased in CGameHandler::objectVisitEnded if id of visited object will be available
if(!altarArtifactsStorage->artifactsInBackpack.empty())
LOCPLINT->cb->bulkMoveArtifacts(heroArts->altarId, heroArts->getHero()->id, false, true, true);
}
CMarketBase::MarketShowcasesParams CAltarArtifacts::getShowcasesParams() const
{
if(const auto art = hero->getArt(ArtifactPosition::TRANSITION_POS))
return MarketShowcasesParams
{
std::nullopt,
ShowcaseParams {std::to_string(offerQty), CGI->artifacts()->getByIndex(art->getTypeId())->getIconIndex()}
};
return MarketShowcasesParams {std::nullopt, std::nullopt};
}
void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<TradePanelBase> & curPanel)
{
assert(altarSlot);
if(const auto pickedArtInst = heroArts->getPickedArtifact())
{
if(pickedArtInst->canBePutAt(altarArtifactsStorage))
{
if(pickedArtInst->artType->isTradable())
{
if(altarSlot->id == -1)
tradeSlotsMap.try_emplace(altarSlot, pickedArtInst);
deal->block(!LOCPLINT->makingTurn);
LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->getHero()->id, ArtifactPosition::TRANSITION_POS),
ArtifactLocation(heroArts->altarId, ArtifactPosition::ALTAR));
}
else
{
logGlobal->warn("Cannot put special artifact on altar!");
return;
}
}
}
else if(altarSlot->id != -1)
{
assert(tradeSlotsMap.at(altarSlot));
const auto slot = altarArtifactsStorage->getArtPos(tradeSlotsMap.at(altarSlot));
assert(slot != ArtifactPosition::PRE_FIRST);
LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->altarId, slot),
ArtifactLocation(hero->id, GH.isKeyboardCtrlDown() ? ArtifactPosition::FIRST_AVAILABLE : ArtifactPosition::TRANSITION_POS));
tradeSlotsMap.erase(altarSlot);
}
}
TExpType CAltarArtifacts::calcExpCost(ArtifactID id) const
{
int bidQty = 0;
int expOfArt = 0;
market->getOffer(id, 0, bidQty, expOfArt, EMarketMode::ARTIFACT_EXP);
return hero->calculateXp(expOfArt);
}