CWindowWithArtifacts.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. /*
  2. * CWindowWithArtifacts.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 "CWindowWithArtifacts.h"
  12. #include "../gui/CGuiHandler.h"
  13. #include "../gui/CursorHandler.h"
  14. #include "../gui/WindowHandler.h"
  15. #include "../render/IRenderHandler.h"
  16. #include "../render/CAnimation.h"
  17. #include "../render/IImage.h"
  18. #include "../widgets/CComponent.h"
  19. #include "../windows/CSpellWindow.h"
  20. #include "../windows/CHeroBackpackWindow.h"
  21. #include "../CPlayerInterface.h"
  22. #include "../CGameInfo.h"
  23. #include "../../lib/ArtifactUtils.h"
  24. #include "../../lib/CGeneralTextHandler.h"
  25. #include "../../lib/mapObjects/CGHeroInstance.h"
  26. #include "../../lib/networkPacks/ArtifactLocation.h"
  27. #include "../../lib/CConfigHandler.h"
  28. #include "../../CCallback.h"
  29. CWindowWithArtifacts::CWindowWithArtifacts(const std::vector<ArtifactsOfHeroVar> * artSets)
  30. {
  31. if(artSets)
  32. this->artSets.insert(this->artSets.end(), artSets->begin(), artSets->end());
  33. }
  34. void CWindowWithArtifacts::addSet(ArtifactsOfHeroVar newArtSet)
  35. {
  36. artSets.emplace_back(newArtSet);
  37. }
  38. void CWindowWithArtifacts::addSetAndCallbacks(ArtifactsOfHeroVar newArtSet)
  39. {
  40. addSet(newArtSet);
  41. std::visit([this](auto artSet)
  42. {
  43. if constexpr(std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMarket>>)
  44. {
  45. artSet->clickPressedCallback = [artSet](CArtPlace & artPlace, const Point & cursorPosition)
  46. {
  47. artSet->onClickPressedArtPlace(artPlace);
  48. };
  49. }
  50. if constexpr(std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroQuickBackpack>>)
  51. {
  52. artSet->clickPressedCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
  53. {
  54. if(const auto curHero = artSet->getHero())
  55. swapArtifactAndClose(*artSet, artPlace.slot, ArtifactLocation(curHero->id, artSet->getFilterSlot()));
  56. };
  57. }
  58. if constexpr(
  59. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
  60. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
  61. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>> ||
  62. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>)
  63. {
  64. artSet->clickPressedCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
  65. {
  66. if(const auto curHero = artSet->getHero())
  67. clickPressedOnArtPlace(*curHero, artPlace.slot,
  68. !std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>>,
  69. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>>,
  70. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>);
  71. };
  72. }
  73. if constexpr(
  74. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMarket>> ||
  75. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroQuickBackpack>>)
  76. {
  77. artSet->showPopupCallback = [this](CArtPlace & artPlace, const Point & cursorPosition)
  78. {
  79. showArifactInfo(artPlace, cursorPosition);
  80. };
  81. }
  82. if constexpr(
  83. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
  84. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>> ||
  85. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroAltar>> ||
  86. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroBackpack>>)
  87. {
  88. artSet->showPopupCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
  89. {
  90. showArtifactAssembling(*artSet, artPlace, cursorPosition);
  91. };
  92. }
  93. if constexpr(
  94. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroMain>> ||
  95. std::is_same_v<decltype(artSet), std::shared_ptr<CArtifactsOfHeroKingdom>>)
  96. {
  97. artSet->gestureCallback = [this, artSet](CArtPlace & artPlace, const Point & cursorPosition)
  98. {
  99. if(const auto curHero = artSet->getHero())
  100. showQuickBackpackWindow(*curHero, artPlace.slot, cursorPosition);
  101. };
  102. }
  103. }, newArtSet);
  104. }
  105. void CWindowWithArtifacts::addCloseCallback(const CloseCallback & callback)
  106. {
  107. closeCallback = callback;
  108. }
  109. const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact()
  110. {
  111. const CGHeroInstance * hero = nullptr;
  112. for(auto & artSet : artSets)
  113. std::visit([&hero](auto artSetPtr)
  114. {
  115. if(const auto pickedArt = artSetPtr->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
  116. {
  117. hero = artSetPtr->getHero();
  118. return;
  119. }
  120. }, artSet);
  121. return hero;
  122. }
  123. const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact()
  124. {
  125. const CArtifactInstance * art = nullptr;
  126. for(auto & artSet : artSets)
  127. std::visit([&art](auto artSetPtr)
  128. {
  129. if(const auto pickedArt = artSetPtr->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
  130. {
  131. art = pickedArt;
  132. return;
  133. }
  134. }, artSet);
  135. return art;
  136. }
  137. void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance & hero, const ArtifactPosition & slot,
  138. bool allowExchange, bool altarTrading, bool closeWindow)
  139. {
  140. if(!LOCPLINT->makingTurn)
  141. return;
  142. if(const auto heroArtOwner = getHeroPickedArtifact())
  143. {
  144. if(allowExchange || hero.id == heroArtOwner->id)
  145. putPickedArtifact(hero, slot);
  146. }
  147. else if(auto art = hero.getArt(slot))
  148. {
  149. if(hero.getOwner() == LOCPLINT->playerID)
  150. {
  151. if(checkSpecialArts(*art, hero, altarTrading))
  152. onClickPressedCommonArtifact(hero, slot, closeWindow);
  153. }
  154. else
  155. {
  156. for(const auto & artSlot : ArtifactUtils::unmovableSlots())
  157. if(slot == artSlot)
  158. {
  159. LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
  160. break;
  161. }
  162. }
  163. }
  164. }
  165. void CWindowWithArtifacts::swapArtifactAndClose(const CArtifactsOfHeroBase & artsInst, const ArtifactPosition & slot,
  166. const ArtifactLocation & dstLoc) const
  167. {
  168. LOCPLINT->cb->swapArtifacts(ArtifactLocation(artsInst.getHero()->id, slot), dstLoc);
  169. if(closeCallback)
  170. closeCallback();
  171. }
  172. void CWindowWithArtifacts::showArtifactAssembling(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace,
  173. const Point & cursorPosition) const
  174. {
  175. if(artsInst.getArt(artPlace.slot))
  176. {
  177. if(ArtifactUtilsClient::askToDisassemble(artsInst.getHero(), artPlace.slot))
  178. return;
  179. if(ArtifactUtilsClient::askToAssemble(artsInst.getHero(), artPlace.slot))
  180. return;
  181. if(artPlace.text.size())
  182. artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
  183. }
  184. }
  185. void CWindowWithArtifacts::showArifactInfo(CArtPlace & artPlace, const Point & cursorPosition) const
  186. {
  187. if(artPlace.getArt() && artPlace.text.size())
  188. artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
  189. }
  190. void CWindowWithArtifacts::showQuickBackpackWindow(const CGHeroInstance & hero, const ArtifactPosition & slot,
  191. const Point & cursorPosition) const
  192. {
  193. if(!settings["general"]["enableUiEnhancements"].Bool())
  194. return;
  195. GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(&hero, slot);
  196. auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
  197. backpackWindow->moveTo(cursorPosition - Point(1, 1));
  198. backpackWindow->fitToScreen(15);
  199. }
  200. void CWindowWithArtifacts::activate()
  201. {
  202. if(const auto art = getPickedArtifact())
  203. {
  204. markPossibleSlots();
  205. setCursorAnimation(*art);
  206. }
  207. CWindowObject::activate();
  208. }
  209. void CWindowWithArtifacts::deactivate()
  210. {
  211. CCS->curh->dragAndDropCursor(nullptr);
  212. CWindowObject::deactivate();
  213. }
  214. void CWindowWithArtifacts::enableArtifactsCostumeSwitcher() const
  215. {
  216. for(auto & artSet : artSets)
  217. std::visit(
  218. [](auto artSetPtr)
  219. {
  220. if constexpr(std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroMain>>)
  221. artSetPtr->enableArtifactsCostumeSwitcher();
  222. }, artSet);
  223. }
  224. void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc)
  225. {
  226. update();
  227. }
  228. void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc)
  229. {
  230. for(auto & artSet : artSets)
  231. std::visit([this](auto artSetPtr)
  232. {
  233. if(const auto pickedArtInst = getPickedArtifact())
  234. {
  235. markPossibleSlots();
  236. setCursorAnimation(*pickedArtInst);
  237. }
  238. else
  239. {
  240. artSetPtr->unmarkSlots();
  241. CCS->curh->dragAndDropCursor(nullptr);
  242. }
  243. }, artSet);
  244. }
  245. void CWindowWithArtifacts::artifactDisassembled(const ArtifactLocation & artLoc)
  246. {
  247. update();
  248. }
  249. void CWindowWithArtifacts::artifactAssembled(const ArtifactLocation & artLoc)
  250. {
  251. markPossibleSlots();
  252. update();
  253. }
  254. void CWindowWithArtifacts::update()
  255. {
  256. for(auto & artSet : artSets)
  257. std::visit([](auto artSetPtr)
  258. {
  259. artSetPtr->updateWornSlots();
  260. artSetPtr->updateBackpackSlots();
  261. // Make sure the status bar is updated so it does not display old text
  262. if(auto artPlace = artSetPtr->getArtPlace(GH.getCursorPosition()))
  263. artPlace->hover(true);
  264. }, artSet);
  265. }
  266. void CWindowWithArtifacts::markPossibleSlots()
  267. {
  268. if(const auto pickedArtInst = getPickedArtifact())
  269. {
  270. const auto heroArtOwner = getHeroPickedArtifact();
  271. auto artifactAssembledBody = [&pickedArtInst, &heroArtOwner](auto artSetPtr)
  272. {
  273. if(artSetPtr->isActive())
  274. {
  275. const auto hero = artSetPtr->getHero();
  276. if(heroArtOwner == hero || !std::is_same_v<decltype(artSetPtr), std::shared_ptr<CArtifactsOfHeroKingdom>>)
  277. artSetPtr->markPossibleSlots(pickedArtInst, hero->tempOwner == LOCPLINT->playerID);
  278. }
  279. };
  280. for(auto & artSet : artSets)
  281. std::visit(artifactAssembledBody, artSet);
  282. }
  283. }
  284. bool CWindowWithArtifacts::checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance & hero, bool isTrade) const
  285. {
  286. const auto artId = artInst.getTypeId();
  287. if(artId == ArtifactID::SPELLBOOK)
  288. {
  289. GH.windows().createAndPushWindow<CSpellWindow>(&hero, LOCPLINT, LOCPLINT->battleInt.get());
  290. return false;
  291. }
  292. if(artId == ArtifactID::CATAPULT)
  293. {
  294. // The Catapult must be equipped
  295. LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[312],
  296. std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, ArtifactID(ArtifactID::CATAPULT))));
  297. return false;
  298. }
  299. if(isTrade && !artInst.artType->isTradable())
  300. {
  301. LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21],
  302. std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, artId)));
  303. return false;
  304. }
  305. return true;
  306. }
  307. void CWindowWithArtifacts::setCursorAnimation(const CArtifactInstance & artInst)
  308. {
  309. if(artInst.isScroll() && settings["general"]["enableUiEnhancements"].Bool())
  310. {
  311. assert(artInst.getScrollSpellID().num >= 0);
  312. const auto animation = GH.renderHandler().loadAnimation(AnimationPath::builtin("spellscr"));
  313. animation->load(artInst.getScrollSpellID().num);
  314. CCS->curh->dragAndDropCursor(animation->getImage(artInst.getScrollSpellID().num)->scaleFast(Point(44, 34)));
  315. }
  316. else
  317. {
  318. CCS->curh->dragAndDropCursor(AnimationPath::builtin("artifact"), artInst.artType->getIconIndex());
  319. }
  320. }
  321. void CWindowWithArtifacts::putPickedArtifact(const CGHeroInstance & curHero, const ArtifactPosition & targetSlot)
  322. {
  323. const auto heroArtOwner = getHeroPickedArtifact();
  324. const auto pickedArt = getPickedArtifact();
  325. auto srcLoc = ArtifactLocation(heroArtOwner->id, ArtifactPosition::TRANSITION_POS);
  326. auto dstLoc = ArtifactLocation(curHero.id, targetSlot);
  327. if(ArtifactUtils::isSlotBackpack(dstLoc.slot))
  328. {
  329. if(pickedArt->artType->isBig())
  330. {
  331. // War machines cannot go to backpack
  332. LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArt->artType->getNameTranslated()));
  333. }
  334. else
  335. {
  336. if(ArtifactUtils::isBackpackFreeSlots(heroArtOwner))
  337. LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
  338. else
  339. LOCPLINT->showInfoDialog(CGI->generaltexth->translate("core.genrltxt.152"));
  340. }
  341. }
  342. // Check if artifact transfer is possible
  343. else if(pickedArt->canBePutAt(&curHero, dstLoc.slot, true) && (!curHero.getArt(targetSlot) || curHero.tempOwner == LOCPLINT->playerID))
  344. {
  345. LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
  346. }
  347. }
  348. void CWindowWithArtifacts::onClickPressedCommonArtifact(const CGHeroInstance & curHero, const ArtifactPosition & slot, bool closeWindow)
  349. {
  350. assert(curHero.getArt(slot));
  351. auto srcLoc = ArtifactLocation(curHero.id, slot);
  352. auto dstLoc = ArtifactLocation(curHero.id, ArtifactPosition::TRANSITION_POS);
  353. if(GH.isKeyboardCmdDown())
  354. {
  355. for(auto & anotherSet : artSets)
  356. {
  357. if(std::holds_alternative<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet))
  358. {
  359. const auto anotherHeroEquipment = std::get<std::shared_ptr<CArtifactsOfHeroMain>>(anotherSet);
  360. if(curHero.id != anotherHeroEquipment->getHero()->id)
  361. {
  362. dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
  363. dstLoc.artHolder = anotherHeroEquipment->getHero()->id;
  364. break;
  365. }
  366. }
  367. if(std::holds_alternative<std::shared_ptr<CArtifactsOfHeroAltar>>(anotherSet))
  368. {
  369. const auto heroEquipment = std::get<std::shared_ptr<CArtifactsOfHeroAltar>>(anotherSet);
  370. dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
  371. dstLoc.artHolder = heroEquipment->altarId;
  372. break;
  373. }
  374. }
  375. }
  376. else if(GH.isKeyboardAltDown())
  377. {
  378. const auto artId = curHero.getArt(slot)->getTypeId();
  379. if(ArtifactUtils::isSlotEquipment(slot))
  380. dstLoc.slot = ArtifactUtils::getArtBackpackPosition(&curHero, artId);
  381. else if(ArtifactUtils::isSlotBackpack(slot))
  382. dstLoc.slot = ArtifactUtils::getArtEquippedPosition(&curHero, artId);
  383. }
  384. else if(closeWindow && closeCallback)
  385. {
  386. closeCallback();
  387. }
  388. if(dstLoc.slot != ArtifactPosition::PRE_FIRST)
  389. LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
  390. }