CAltarCreatures.cpp 8.6 KB

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