TradePanels.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * TradePanels.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 "TradePanels.h"
  12. #include "../../gui/CGuiHandler.h"
  13. #include "../../render/Canvas.h"
  14. #include "../../widgets/TextControls.h"
  15. #include "../../windows/InfoWindows.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. CTradeableItem::CTradeableItem(const Rect & area, EType Type, int32_t ID, int32_t serial)
  22. : SelectableSlot(area, Point(1, 1))
  23. , type(EType(-1)) // set to invalid, will be corrected in setType
  24. , id(ID)
  25. , serial(serial)
  26. {
  27. OBJECT_CONSTRUCTION;
  28. addUsedEvents(LCLICK);
  29. addUsedEvents(HOVER);
  30. addUsedEvents(SHOW_POPUP);
  31. subtitle = std::make_shared<CLabel>(0, 0, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE);
  32. setType(Type);
  33. this->pos.w = area.w;
  34. this->pos.h = area.h;
  35. }
  36. void CTradeableItem::setType(EType newType)
  37. {
  38. if(type != newType)
  39. {
  40. OBJECT_CONSTRUCTION;
  41. type = newType;
  42. if(getIndex() < 0)
  43. {
  44. image = std::make_shared<CAnimImage>(getFilename(), 0);
  45. image->disable();
  46. }
  47. else
  48. {
  49. image = std::make_shared<CAnimImage>(getFilename(), getIndex());
  50. }
  51. switch(type)
  52. {
  53. case EType::RESOURCE:
  54. subtitle->moveTo(pos.topLeft() + Point(35, 55));
  55. image->moveTo(pos.topLeft() + Point(19, 8));
  56. break;
  57. case EType::CREATURE:
  58. subtitle->moveTo(pos.topLeft() + Point(30, 77));
  59. break;
  60. case EType::PLAYER:
  61. subtitle->moveTo(pos.topLeft() + Point(31, 76));
  62. break;
  63. case EType::ARTIFACT:
  64. subtitle->moveTo(pos.topLeft() + Point(21, 55));
  65. break;
  66. case EType::ARTIFACT_TYPE:
  67. subtitle->moveTo(pos.topLeft() + Point(35, 57));
  68. image->moveTo(pos.topLeft() + Point(13, 0));
  69. break;
  70. }
  71. }
  72. }
  73. void CTradeableItem::setID(int32_t newID)
  74. {
  75. if(id != newID)
  76. {
  77. id = newID;
  78. if(image)
  79. {
  80. const auto index = getIndex();
  81. if(index < 0)
  82. image->disable();
  83. else
  84. {
  85. image->enable();
  86. image->setFrame(index);
  87. }
  88. }
  89. }
  90. }
  91. void CTradeableItem::clear()
  92. {
  93. setID(-1);
  94. image->setFrame(0);
  95. image->disable();
  96. subtitle->clear();
  97. }
  98. AnimationPath CTradeableItem::getFilename()
  99. {
  100. switch(type)
  101. {
  102. case EType::RESOURCE:
  103. return AnimationPath::builtin("RESOURCE");
  104. case EType::PLAYER:
  105. return AnimationPath::builtin("CREST58");
  106. case EType::ARTIFACT_TYPE:
  107. case EType::ARTIFACT:
  108. return AnimationPath::builtin("artifact");
  109. case EType::CREATURE:
  110. return AnimationPath::builtin("TWCRPORT");
  111. default:
  112. return {};
  113. }
  114. }
  115. int CTradeableItem::getIndex()
  116. {
  117. if(id < 0)
  118. return -1;
  119. switch(type)
  120. {
  121. case EType::RESOURCE:
  122. case EType::PLAYER:
  123. return id;
  124. case EType::ARTIFACT_TYPE:
  125. case EType::ARTIFACT:
  126. return CGI->artifacts()->getByIndex(id)->getIconIndex();
  127. case EType::CREATURE:
  128. return CGI->creatures()->getByIndex(id)->getIconIndex();
  129. default:
  130. return -1;
  131. }
  132. }
  133. void CTradeableItem::clickPressed(const Point & cursorPosition)
  134. {
  135. if(clickPressedCallback)
  136. clickPressedCallback(shared_from_this());
  137. }
  138. void CTradeableItem::hover(bool on)
  139. {
  140. if(!on || id == -1)
  141. {
  142. GH.statusbar()->clear();
  143. return;
  144. }
  145. switch(type)
  146. {
  147. case EType::CREATURE:
  148. GH.statusbar()->write(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->objects[id]->getNamePluralTranslated()));
  149. break;
  150. case EType::ARTIFACT_TYPE:
  151. case EType::ARTIFACT:
  152. if(id < 0)
  153. GH.statusbar()->write(CGI->generaltexth->zelp[582].first);
  154. else
  155. GH.statusbar()->write(CGI->artifacts()->getByIndex(id)->getNameTranslated());
  156. break;
  157. case EType::RESOURCE:
  158. GH.statusbar()->write(CGI->generaltexth->restypes[id]);
  159. break;
  160. case EType::PLAYER:
  161. GH.statusbar()->write(CGI->generaltexth->capColors[id]);
  162. break;
  163. }
  164. }
  165. void CTradeableItem::showPopupWindow(const Point & cursorPosition)
  166. {
  167. switch(type)
  168. {
  169. case EType::CREATURE:
  170. break;
  171. case EType::ARTIFACT_TYPE:
  172. case EType::ARTIFACT:
  173. if (id >= 0)
  174. CRClickPopup::createAndPush(CGI->artifacts()->getByIndex(id)->getDescriptionTranslated());
  175. break;
  176. }
  177. }
  178. void TradePanelBase::update()
  179. {
  180. if(deleteSlotsCheck)
  181. slots.erase(std::remove_if(slots.begin(), slots.end(), deleteSlotsCheck), slots.end());
  182. if(updateSlotsCallback)
  183. updateSlotsCallback();
  184. }
  185. void TradePanelBase::deselect()
  186. {
  187. for(const auto & slot : slots)
  188. slot->selectSlot(false);
  189. }
  190. void TradePanelBase::clearSubtitles()
  191. {
  192. for(const auto & slot : slots)
  193. slot->subtitle->clear();
  194. }
  195. void TradePanelBase::updateOffer(CTradeableItem & slot, int cost, int qty)
  196. {
  197. std::string subtitle = std::to_string(qty);
  198. if(cost != 1)
  199. {
  200. subtitle.append("/");
  201. subtitle.append(std::to_string(cost));
  202. }
  203. slot.subtitle->setText(subtitle);
  204. }
  205. void TradePanelBase::setShowcaseSubtitle(const std::string & text)
  206. {
  207. showcaseSlot->subtitle->setText(text);
  208. }
  209. int32_t TradePanelBase::getHighlightedItemId() const
  210. {
  211. if(highlightedSlot)
  212. return highlightedSlot->id;
  213. else
  214. return -1;
  215. }
  216. void TradePanelBase::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot)
  217. {
  218. assert(vstd::contains(slots, newSlot));
  219. if(newSlot == highlightedSlot)
  220. return;
  221. if(highlightedSlot)
  222. highlightedSlot->selectSlot(false);
  223. highlightedSlot = newSlot;
  224. newSlot->selectSlot(true);
  225. }
  226. bool TradePanelBase::isHighlighted() const
  227. {
  228. return highlightedSlot != nullptr;
  229. }
  230. ResourcesPanel::ResourcesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  231. const UpdateSlotsFunctor & updateSubtitles)
  232. {
  233. assert(resourcesForTrade.size() == slotsPos.size());
  234. OBJECT_CONSTRUCTION;
  235. for(const auto & res : resourcesForTrade)
  236. {
  237. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[res.num], slotDimension), EType::RESOURCE, res.num, res.num));
  238. slot->clickPressedCallback = clickPressedCallback;
  239. slot->setSelectionWidth(selectionWidth);
  240. }
  241. updateSlotsCallback = updateSubtitles;
  242. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::RESOURCE, 0, 0);
  243. }
  244. ArtifactsPanel::ArtifactsPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  245. const UpdateSlotsFunctor & updateSubtitles, const std::vector<TradeItemBuy> & arts)
  246. {
  247. assert(slotsForTrade == slotsPos.size());
  248. assert(slotsForTrade == arts.size());
  249. OBJECT_CONSTRUCTION;
  250. for(auto slotIdx = 0; slotIdx < slotsForTrade; slotIdx++)
  251. {
  252. auto artType = arts[slotIdx].getNum();
  253. if(artType != ArtifactID::NONE)
  254. {
  255. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotIdx], slotDimension),
  256. EType::ARTIFACT_TYPE, artType, slotIdx));
  257. slot->clickPressedCallback = clickPressedCallback;
  258. slot->setSelectionWidth(selectionWidth);
  259. }
  260. }
  261. updateSlotsCallback = updateSubtitles;
  262. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
  263. showcaseSlot->subtitle->moveBy(Point(0, 1));
  264. }
  265. PlayersPanel::PlayersPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
  266. {
  267. assert(PlayerColor::PLAYER_LIMIT_I <= slotsPos.size() + 1);
  268. OBJECT_CONSTRUCTION;
  269. std::vector<PlayerColor> players;
  270. for(auto player = PlayerColor(0); player < PlayerColor::PLAYER_LIMIT_I; player++)
  271. {
  272. if(player != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(player) == EPlayerStatus::INGAME)
  273. players.emplace_back(player);
  274. }
  275. slots.resize(players.size());
  276. int slotNum = 0;
  277. for(auto & slot : slots)
  278. {
  279. slot = std::make_shared<CTradeableItem>(Rect(slotsPos[slotNum], slotDimension), EType::PLAYER, players[slotNum].num, slotNum);
  280. slot->clickPressedCallback = clickPressedCallback;
  281. slot->setSelectionWidth(selectionWidth);
  282. slot->subtitle->setText(CGI->generaltexth->capColors[players[slotNum].num]);
  283. slotNum++;
  284. }
  285. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::PLAYER, 0, 0);
  286. }
  287. CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback, const slotsData & initialSlots)
  288. {
  289. assert(initialSlots.size() <= GameConstants::ARMY_SIZE);
  290. assert(slotsPos.size() <= GameConstants::ARMY_SIZE);
  291. OBJECT_CONSTRUCTION;
  292. for(const auto & [creatureId, slotId, creaturesNum] : initialSlots)
  293. {
  294. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[slotId.num], slotDimension),
  295. EType::CREATURE, creaturesNum == 0 ? -1 : creatureId.num, slotId));
  296. slot->clickPressedCallback = clickPressedCallback;
  297. if(creaturesNum != 0)
  298. slot->subtitle->setText(std::to_string(creaturesNum));
  299. slot->setSelectionWidth(selectionWidth);
  300. }
  301. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
  302. }
  303. CreaturesPanel::CreaturesPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback,
  304. const std::vector<std::shared_ptr<CTradeableItem>> & srcSlots, bool emptySlots)
  305. {
  306. assert(slots.size() <= GameConstants::ARMY_SIZE);
  307. OBJECT_CONSTRUCTION;
  308. for(const auto & srcSlot : srcSlots)
  309. {
  310. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(slotsPos[srcSlot->serial], srcSlot->pos.dimensions()),
  311. EType::CREATURE, emptySlots ? -1 : srcSlot->id, srcSlot->serial));
  312. slot->clickPressedCallback = clickPressedCallback;
  313. slot->subtitle->setText(emptySlots ? "" : srcSlot->subtitle->getText());
  314. slot->setSelectionWidth(selectionWidth);
  315. }
  316. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::CREATURE, 0, 0);
  317. }
  318. ArtifactsAltarPanel::ArtifactsAltarPanel(const CTradeableItem::ClickPressedFunctor & clickPressedCallback)
  319. {
  320. OBJECT_CONSTRUCTION;
  321. int slotNum = 0;
  322. for(auto & altarSlotPos : slotsPos)
  323. {
  324. auto slot = slots.emplace_back(std::make_shared<CTradeableItem>(Rect(altarSlotPos, Point(44, 44)), EType::ARTIFACT, -1, slotNum));
  325. slot->clickPressedCallback = clickPressedCallback;
  326. slot->subtitle->clear();
  327. slot->subtitle->moveBy(Point(0, -1));
  328. slotNum++;
  329. }
  330. showcaseSlot = std::make_shared<CTradeableItem>(Rect(selectedPos, slotDimension), EType::ARTIFACT_TYPE, 0, 0);
  331. showcaseSlot->subtitle->moveBy(Point(0, 3));
  332. }