CAltarCreatures.cpp 8.1 KB

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