CAltarCreatures.cpp 7.8 KB

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