CArtifactsOfHeroBase.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * CArtifactsOfHeroBase.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 "CArtifactsOfHeroBase.h"
  12. #include "../gui/CGuiHandler.h"
  13. #include "../gui/CursorHandler.h"
  14. #include "../gui/Shortcut.h"
  15. #include "Buttons.h"
  16. #include "../CPlayerInterface.h"
  17. #include "../CGameInfo.h"
  18. #include "../../CCallback.h"
  19. #include "../../lib/ArtifactUtils.h"
  20. #include "../../lib/mapObjects/CGHeroInstance.h"
  21. CArtifactsOfHeroBase::CArtifactsOfHeroBase()
  22. : backpackPos(0),
  23. curHero(nullptr)
  24. {
  25. }
  26. CArtifactsOfHeroBase::~CArtifactsOfHeroBase()
  27. {
  28. // TODO: cursor handling is CWindowWithArtifacts level. Should be moved when trading, kingdom and hero window are reworked
  29. // This will interfere with the implementation of a separate backpack window
  30. CCS->curh->dragAndDropCursor(nullptr);
  31. // Artifact located in artifactsTransitionPos should be returned
  32. if(getPickedArtifact())
  33. {
  34. auto slot = ArtifactUtils::getArtAnyPosition(curHero, curHero->artifactsTransitionPos.begin()->artifact->getTypeId());
  35. if(slot == ArtifactPosition::PRE_FIRST)
  36. {
  37. LOCPLINT->cb->eraseArtifactByClient(ArtifactLocation(curHero, ArtifactPosition::TRANSITION_POS));
  38. }
  39. else
  40. {
  41. LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero, ArtifactPosition::TRANSITION_POS), ArtifactLocation(curHero, slot));
  42. }
  43. }
  44. }
  45. void CArtifactsOfHeroBase::init(
  46. CHeroArtPlace::ClickHandler lClickCallback,
  47. CHeroArtPlace::ClickHandler rClickCallback,
  48. const Point & position,
  49. BpackScrollHandler scrollHandler)
  50. {
  51. // CArtifactsOfHeroBase::init may be transform to CArtifactsOfHeroBase::CArtifactsOfHeroBase if OBJECT_CONSTRUCTION_CAPTURING is removed
  52. OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
  53. pos += position;
  54. for(int g = 0; g < GameConstants::BACKPACK_START; g++)
  55. {
  56. artWorn[ArtifactPosition(g)] = std::make_shared<CHeroArtPlace>(slotPos[g]);
  57. }
  58. backpack.clear();
  59. for(int s = 0; s < 5; s++)
  60. {
  61. auto artPlace = std::make_shared<CHeroArtPlace>(Point(403 + 46 * s, 365));
  62. backpack.push_back(artPlace);
  63. }
  64. for(auto artPlace : artWorn)
  65. {
  66. artPlace.second->slot = artPlace.first;
  67. artPlace.second->setArtifact(nullptr);
  68. artPlace.second->leftClickCallback = lClickCallback;
  69. artPlace.second->rightClickCallback = rClickCallback;
  70. }
  71. for(auto artPlace : backpack)
  72. {
  73. artPlace->setArtifact(nullptr);
  74. artPlace->leftClickCallback = lClickCallback;
  75. artPlace->rightClickCallback = rClickCallback;
  76. }
  77. leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), "hsbtns3.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(-1); }, EShortcut::MOVE_LEFT);
  78. rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), "hsbtns5.def", CButton::tooltip(), [scrollHandler]() { scrollHandler(+1); }, EShortcut::MOVE_RIGHT);
  79. leftBackpackRoll->block(true);
  80. rightBackpackRoll->block(true);
  81. }
  82. void CArtifactsOfHeroBase::leftClickArtPlace(CHeroArtPlace & artPlace)
  83. {
  84. if(leftClickCallback)
  85. leftClickCallback(*this, artPlace);
  86. }
  87. void CArtifactsOfHeroBase::rightClickArtPlace(CHeroArtPlace & artPlace)
  88. {
  89. if(rightClickCallback)
  90. rightClickCallback(*this, artPlace);
  91. }
  92. void CArtifactsOfHeroBase::setHero(const CGHeroInstance * hero)
  93. {
  94. curHero = hero;
  95. if(curHero->artifactsInBackpack.size() > 0)
  96. backpackPos %= curHero->artifactsInBackpack.size();
  97. else
  98. backpackPos = 0;
  99. for(auto slot : artWorn)
  100. {
  101. setSlotData(slot.second, slot.first, *curHero);
  102. }
  103. scrollBackpackForArtSet(0, *curHero);
  104. }
  105. const CGHeroInstance * CArtifactsOfHeroBase::getHero() const
  106. {
  107. return curHero;
  108. }
  109. void CArtifactsOfHeroBase::scrollBackpack(int offset)
  110. {
  111. scrollBackpackForArtSet(offset, *curHero);
  112. safeRedraw();
  113. }
  114. void CArtifactsOfHeroBase::scrollBackpackForArtSet(int offset, const CArtifactSet & artSet)
  115. {
  116. // offset==-1 => to left; offset==1 => to right
  117. using slotInc = std::function<ArtifactPosition(ArtifactPosition&)>;
  118. auto artsInBackpack = static_cast<int>(artSet.artifactsInBackpack.size());
  119. auto scrollingPossible = artsInBackpack > backpack.size();
  120. slotInc inc_straight = [](ArtifactPosition & slot) -> ArtifactPosition
  121. {
  122. return slot + 1;
  123. };
  124. slotInc inc_ring = [artsInBackpack](ArtifactPosition & slot) -> ArtifactPosition
  125. {
  126. return ArtifactPosition(GameConstants::BACKPACK_START + (slot - GameConstants::BACKPACK_START + 1) % artsInBackpack);
  127. };
  128. slotInc inc;
  129. if(scrollingPossible)
  130. inc = inc_ring;
  131. else
  132. inc = inc_straight;
  133. backpackPos += offset;
  134. if(backpackPos < 0)
  135. backpackPos += artsInBackpack;
  136. if(artsInBackpack)
  137. backpackPos %= artsInBackpack;
  138. auto slot = ArtifactPosition(GameConstants::BACKPACK_START + backpackPos);
  139. for(auto artPlace : backpack)
  140. {
  141. setSlotData(artPlace, slot, artSet);
  142. slot = inc(slot);
  143. }
  144. // Blocking scrolling if there is not enough artifacts to scroll
  145. leftBackpackRoll->block(!scrollingPossible);
  146. rightBackpackRoll->block(!scrollingPossible);
  147. }
  148. void CArtifactsOfHeroBase::safeRedraw()
  149. {
  150. if(isActive())
  151. {
  152. if(parent)
  153. parent->redraw();
  154. else
  155. redraw();
  156. }
  157. }
  158. void CArtifactsOfHeroBase::markPossibleSlots(const CArtifactInstance * art, bool assumeDestRemoved)
  159. {
  160. for(auto artPlace : artWorn)
  161. artPlace.second->selectSlot(art->artType->canBePutAt(curHero, artPlace.second->slot, assumeDestRemoved));
  162. }
  163. void CArtifactsOfHeroBase::unmarkSlots()
  164. {
  165. for(auto & artPlace : artWorn)
  166. artPlace.second->selectSlot(false);
  167. for(auto & artPlace : backpack)
  168. artPlace->selectSlot(false);
  169. }
  170. CArtifactsOfHeroBase::ArtPlacePtr CArtifactsOfHeroBase::getArtPlace(const ArtifactPosition & slot)
  171. {
  172. if(ArtifactUtils::isSlotEquipment(slot))
  173. {
  174. if(artWorn.find(slot) == artWorn.end())
  175. {
  176. logGlobal->error("CArtifactsOfHero::getArtPlace: invalid slot %d", slot);
  177. return nullptr;
  178. }
  179. return artWorn[slot];
  180. }
  181. if(ArtifactUtils::isSlotBackpack(slot))
  182. {
  183. for(ArtPlacePtr artPlace : backpack)
  184. if(artPlace->slot == slot)
  185. return artPlace;
  186. return nullptr;
  187. }
  188. else
  189. {
  190. return nullptr;
  191. }
  192. }
  193. void CArtifactsOfHeroBase::updateWornSlots()
  194. {
  195. for(auto place : artWorn)
  196. updateSlot(place.first);
  197. }
  198. void CArtifactsOfHeroBase::updateBackpackSlots()
  199. {
  200. if(curHero->artifactsInBackpack.size() <= backpack.size() && backpackPos != 0)
  201. backpackPos = 0;
  202. scrollBackpackForArtSet(0, *curHero);
  203. }
  204. void CArtifactsOfHeroBase::updateSlot(const ArtifactPosition & slot)
  205. {
  206. setSlotData(getArtPlace(slot), slot, *curHero);
  207. }
  208. const CArtifactInstance * CArtifactsOfHeroBase::getPickedArtifact()
  209. {
  210. // Returns only the picked up artifact. Not just highlighted like in the trading window.
  211. if(!curHero || curHero->artifactsTransitionPos.empty())
  212. return nullptr;
  213. else
  214. return curHero->getArt(ArtifactPosition::TRANSITION_POS);
  215. }
  216. void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot, const CArtifactSet & artSet)
  217. {
  218. // Spurious call from artifactMoved in attempt to update hidden backpack slot
  219. if(!artPlace && ArtifactUtils::isSlotBackpack(slot))
  220. {
  221. return;
  222. }
  223. artPlace->slot = slot;
  224. if(auto slotInfo = artSet.getSlot(slot))
  225. {
  226. artPlace->lockSlot(slotInfo->locked);
  227. artPlace->setArtifact(slotInfo->artifact);
  228. if(!slotInfo->artifact->isCombined())
  229. {
  230. // If the artifact is part of at least one combined artifact, add additional information
  231. std::map<const CArtifact*, int> arts;
  232. for(const auto combinedArt : slotInfo->artifact->artType->getPartOf())
  233. {
  234. arts.insert(std::pair(combinedArt, 0));
  235. for(const auto part : combinedArt->getConstituents())
  236. if(artSet.hasArt(part->getId(), true))
  237. arts.at(combinedArt)++;
  238. }
  239. artPlace->addCombinedArtInfo(arts);
  240. }
  241. }
  242. else
  243. {
  244. artPlace->setArtifact(nullptr);
  245. }
  246. }