mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-16 10:19:47 +02:00
20d5b33ea6
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.
238 lines
7.9 KiB
C++
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);
|
|
}
|