CAltarCreatures.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /*
  2. * CAltarCreatures.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CAltarCreatures.h"
  12. #include "../../GameEngine.h"
  13. #include "../../GameInstance.h"
  14. #include "../../gui/Shortcut.h"
  15. #include "../../widgets/Buttons.h"
  16. #include "../../widgets/TextControls.h"
  17. #include "../../CPlayerInterface.h"
  18. #include "../../../lib/GameLibrary.h"
  19. #include "../../../lib/callback/CCallback.h"
  20. #include "../../../lib/texts/CGeneralTextHandler.h"
  21. #include "../../../lib/mapObjects/CGHeroInstance.h"
  22. #include "../../../lib/mapObjects/IMarket.h"
  23. CAltarCreatures::CAltarCreatures(const IMarket * market, const CGHeroInstance * hero)
  24. : CMarketBase(market, hero)
  25. , CMarketSlider(std::bind(&CAltarCreatures::onOfferSliderMoved, this, _1))
  26. , CMarketTraderText(Point(28, 31), FONT_MEDIUM, Colors::YELLOW)
  27. {
  28. OBJECT_CONSTRUCTION;
  29. deal = std::make_shared<CButton>(dealButtonPosWithSlider, AnimationPath::builtin("ALTSACR.DEF"),
  30. LIBRARY->generaltexth->zelp[584], [this]() {CAltarCreatures::makeDeal();}, EShortcut::MARKET_DEAL);
  31. labels.emplace_back(std::make_shared<CLabel>(155, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW,
  32. boost::str(boost::format(LIBRARY->generaltexth->allTexts[272]) % hero->getNameTranslated())));
  33. labels.emplace_back(std::make_shared<CLabel>(450, 30, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW, LIBRARY->generaltexth->allTexts[479]));
  34. texts.emplace_back(std::make_unique<CTextBox>(LIBRARY->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, ETextAlignment::CENTER, Colors::YELLOW));
  35. offerSlider->moveTo(pos.topLeft() + Point(231, 481));
  36. maxAmount->setHelp(LIBRARY->generaltexth->zelp[578]);
  37. unitsOnAltar.resize(GameConstants::ARMY_SIZE, 0);
  38. expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
  39. sacrificeAllButton = std::make_shared<CButton>(
  40. Point(393, 520), AnimationPath::builtin("ALTARMY.DEF"), LIBRARY->generaltexth->zelp[579], std::bind(&CExperienceAltar::sacrificeAll, this), EShortcut::MARKET_SACRIFICE_ALL);
  41. // Hero creatures panel
  42. assert(bidTradePanel);
  43. bidTradePanel->moveTo(pos.topLeft() + Point(45, 110));
  44. bidTradePanel->showcaseSlot->moveTo(pos.topLeft() + Point(149, 422));
  45. bidTradePanel->showcaseSlot->subtitle->moveBy(Point(0, 3));
  46. for(const auto & slot : bidTradePanel->slots)
  47. slot->clickPressedCallback = [this](const std::shared_ptr<CTradeableItem> & heroSlot) {CAltarCreatures::onSlotClickPressed(heroSlot, bidTradePanel);};
  48. // Altar creatures panel
  49. offerTradePanel = std::make_shared<CreaturesPanel>([this](const std::shared_ptr<CTradeableItem> & altarSlot)
  50. {
  51. CAltarCreatures::onSlotClickPressed(altarSlot, offerTradePanel);
  52. }, bidTradePanel->slots);
  53. offerTradePanel->moveTo(pos.topLeft() + Point(334, 110));
  54. offerTradePanel->showcaseSlot->moveTo(pos.topLeft() + Point(395, 422));
  55. offerTradePanel->showcaseSlot->subtitle->moveBy(Point(0, 3));
  56. offerTradePanel->updateSlotsCallback = [this]()
  57. {
  58. for(const auto & altarSlot : offerTradePanel->slots)
  59. updateAltarSlot(altarSlot);
  60. };
  61. bidTradePanel->deleteSlotsCheck = offerTradePanel->deleteSlotsCheck = std::bind(&CCreaturesSelling::slotDeletingCheck, this, _1);
  62. readExpValues();
  63. CAltarCreatures::deselect();
  64. };
  65. void CAltarCreatures::readExpValues()
  66. {
  67. int bidQty = 0;
  68. for(const auto & heroSlot : bidTradePanel->slots)
  69. {
  70. if(heroSlot->id >= 0)
  71. market->getOffer(heroSlot->id, 0, bidQty, expPerUnit[heroSlot->serial], EMarketMode::CREATURE_EXP);
  72. }
  73. }
  74. void CAltarCreatures::highlightingChanged()
  75. {
  76. int sliderAmount = 0;
  77. if(bidTradePanel->isHighlighted())
  78. {
  79. std::optional<SlotID> lastSlot;
  80. for(auto slot = SlotID(0); slot.num < GameConstants::ARMY_SIZE; slot++)
  81. {
  82. if(hero->getStackCount(slot) > unitsOnAltar[slot.num])
  83. {
  84. if(lastSlot.has_value())
  85. {
  86. lastSlot = std::nullopt;
  87. break;
  88. }
  89. else
  90. {
  91. lastSlot = slot;
  92. }
  93. }
  94. }
  95. sliderAmount = hero->getStackCount(SlotID(bidTradePanel->highlightedSlot->serial));
  96. if(lastSlot.has_value() && lastSlot.value() == SlotID(bidTradePanel->highlightedSlot->serial))
  97. sliderAmount--;
  98. }
  99. offerSlider->setAmount(sliderAmount);
  100. offerSlider->block(!offerSlider->getAmount());
  101. if(bidTradePanel->isHighlighted())
  102. offerSlider->scrollTo(unitsOnAltar[bidTradePanel->highlightedSlot->serial]);
  103. maxAmount->block(offerSlider->getAmount() == 0);
  104. updateShowcases();
  105. CMarketTraderText::highlightingChanged();
  106. }
  107. void CAltarCreatures::update()
  108. {
  109. CMarketBase::update();
  110. CExperienceAltar::update();
  111. assert(bidTradePanel->slots.size() == offerTradePanel->slots.size());
  112. }
  113. void CAltarCreatures::deselect()
  114. {
  115. CMarketBase::deselect();
  116. CExperienceAltar::deselect();
  117. CMarketSlider::deselect();
  118. CMarketTraderText::deselect();
  119. }
  120. TExpType CAltarCreatures::calcExpAltarForHero()
  121. {
  122. TExpType expOnAltar(0);
  123. auto oneUnitExp = expPerUnit.begin();
  124. for(const auto units : unitsOnAltar)
  125. expOnAltar += *oneUnitExp++ * units;
  126. auto resultExp = hero->calculateXp(expOnAltar);
  127. expForHero->setText(std::to_string(resultExp));
  128. return resultExp;
  129. }
  130. void CAltarCreatures::makeDeal()
  131. {
  132. std::vector<TradeItemSell> ids;
  133. std::vector<ui32> toSacrifice;
  134. for(int i = 0; i < unitsOnAltar.size(); i++)
  135. {
  136. if(unitsOnAltar[i])
  137. {
  138. ids.push_back(SlotID(i));
  139. toSacrifice.push_back(unitsOnAltar[i]);
  140. }
  141. }
  142. GAME->interface()->cb->trade(market->getObjInstanceID(), EMarketMode::CREATURE_EXP, ids, {}, toSacrifice, hero);
  143. for(int & units : unitsOnAltar)
  144. units = 0;
  145. for(const auto & heroSlot : offerTradePanel->slots)
  146. {
  147. heroSlot->setID(CreatureID::NONE);
  148. heroSlot->subtitle->clear();
  149. }
  150. deselect();
  151. }
  152. CMarketBase::MarketShowcasesParams CAltarCreatures::getShowcasesParams() const
  153. {
  154. std::optional<ShowcaseParams> bidSelected = std::nullopt;
  155. std::optional<ShowcaseParams> offerSelected = std::nullopt;
  156. if(bidTradePanel->isHighlighted())
  157. bidSelected = ShowcaseParams {std::to_string(offerSlider->getValue()), LIBRARY->creatures()->getByIndex(bidTradePanel->getHighlightedItemId())->getIconIndex()};
  158. if(offerTradePanel->isHighlighted() && offerSlider->getValue() > 0)
  159. offerSelected = ShowcaseParams {offerTradePanel->highlightedSlot->subtitle->getText(), LIBRARY->creatures()->getByIndex(offerTradePanel->getHighlightedItemId())->getIconIndex()};
  160. return MarketShowcasesParams {bidSelected, offerSelected};
  161. }
  162. void CAltarCreatures::sacrificeAll()
  163. {
  164. std::optional<SlotID> lastSlot;
  165. for(const auto & heroSlot : bidTradePanel->slots)
  166. {
  167. auto stackCount = hero->getStackCount(SlotID(heroSlot->serial));
  168. if(stackCount > unitsOnAltar[heroSlot->serial])
  169. {
  170. if(!lastSlot.has_value())
  171. lastSlot = SlotID(heroSlot->serial);
  172. unitsOnAltar[heroSlot->serial] = stackCount;
  173. }
  174. }
  175. if(hero->needsLastStack())
  176. {
  177. assert(lastSlot.has_value());
  178. unitsOnAltar[lastSlot.value().num]--;
  179. }
  180. if(offerTradePanel->isHighlighted())
  181. offerSlider->scrollTo(unitsOnAltar[offerTradePanel->highlightedSlot->serial]);
  182. offerTradePanel->update();
  183. updateShowcases();
  184. deal->block(calcExpAltarForHero() == 0 || !GAME->interface()->makingTurn);
  185. }
  186. void CAltarCreatures::updateAltarSlot(const std::shared_ptr<CTradeableItem> & slot)
  187. {
  188. auto units = unitsOnAltar[slot->serial];
  189. const auto [oppositeSlot, oppositePanel] = getOpposite(slot);
  190. slot->setID(units > 0 ? oppositeSlot->id : CreatureID::NONE);
  191. slot->subtitle->setText(units > 0 ?
  192. boost::str(boost::format(LIBRARY->generaltexth->allTexts[122]) % std::to_string(hero->calculateXp(units * expPerUnit[slot->serial]))) : "");
  193. }
  194. void CAltarCreatures::onOfferSliderMoved(int newVal)
  195. {
  196. if(bidTradePanel->isHighlighted())
  197. unitsOnAltar[bidTradePanel->highlightedSlot->serial] = newVal;
  198. if(offerTradePanel->isHighlighted())
  199. updateAltarSlot(offerTradePanel->highlightedSlot);
  200. deal->block(calcExpAltarForHero() == 0 || !GAME->interface()->makingTurn);
  201. highlightingChanged();
  202. redraw();
  203. }
  204. void CAltarCreatures::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<TradePanelBase> & curPanel)
  205. {
  206. assert(newSlot);
  207. assert(curPanel);
  208. if(newSlot == curPanel->highlightedSlot)
  209. return;
  210. curPanel->onSlotClickPressed(newSlot);
  211. auto [oppositeSlot, oppositePanel] = getOpposite(newSlot);
  212. oppositePanel->onSlotClickPressed(oppositeSlot);
  213. highlightingChanged();
  214. redraw();
  215. }
  216. std::string CAltarCreatures::getTraderText()
  217. {
  218. if(bidTradePanel->isHighlighted() && offerTradePanel->isHighlighted())
  219. {
  220. MetaString message = MetaString::createFromTextID("core.genrltxt.484");
  221. message.replaceNamePlural(CreatureID(bidTradePanel->getHighlightedItemId()));
  222. return message.toString();
  223. }
  224. else
  225. {
  226. return "";
  227. }
  228. }
  229. std::tuple<const std::shared_ptr<CTradeableItem>, std::shared_ptr<TradePanelBase>> CAltarCreatures::getOpposite(
  230. const std::shared_ptr<CTradeableItem> & curSlot)
  231. {
  232. assert(curSlot);
  233. auto oppositePanel = bidTradePanel;
  234. if(vstd::contains(bidTradePanel->slots, curSlot))
  235. oppositePanel = offerTradePanel;
  236. std::shared_ptr<CTradeableItem> oppositeSlot;
  237. for(const auto & slot : oppositePanel->slots)
  238. if (slot->serial == curSlot->serial)
  239. {
  240. oppositeSlot = slot;
  241. break;
  242. }
  243. return std::make_tuple(oppositeSlot, oppositePanel);
  244. }