CQuestLog.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /*
  2. * CQuestLog.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 "CQuestLog.h"
  12. #include "CAdvmapInterface.h"
  13. #include "../CBitmapHandler.h"
  14. #include "../CGameInfo.h"
  15. #include "../CPlayerInterface.h"
  16. #include "../Graphics.h"
  17. #include "../gui/CGuiHandler.h"
  18. #include "../gui/SDL_Extensions.h"
  19. #include "../widgets/CComponent.h"
  20. #include "../../CCallback.h"
  21. #include "../../lib/CArtHandler.h"
  22. #include "../../lib/CConfigHandler.h"
  23. #include "../../lib/CGameState.h"
  24. #include "../../lib/CGeneralTextHandler.h"
  25. #include "../../lib/NetPacksBase.h"
  26. #include "../../lib/mapObjects/CQuest.h"
  27. struct QuestInfo;
  28. class CAdvmapInterface;
  29. void CQuestLabel::clickLeft(tribool down, bool previousState)
  30. {
  31. if(down)
  32. callback();
  33. }
  34. void CQuestLabel::showAll(SDL_Surface * to)
  35. {
  36. if(active)
  37. CMultiLineLabel::showAll(to);
  38. }
  39. CQuestIcon::CQuestIcon(const std::string & defname, int index, int x, int y)
  40. : CAnimImage(defname, index, 0, x, y)
  41. {
  42. addUsedEvents(LCLICK);
  43. }
  44. void CQuestIcon::clickLeft(tribool down, bool previousState)
  45. {
  46. if(down)
  47. callback();
  48. }
  49. void CQuestIcon::showAll(SDL_Surface * to)
  50. {
  51. CSDL_Ext::CClipRectGuard guard(to, parent->pos);
  52. CAnimImage::showAll(to);
  53. }
  54. CQuestMinimap::CQuestMinimap(const Rect & position)
  55. : CMinimap(position), currentQuest(nullptr)
  56. {
  57. }
  58. void CQuestMinimap::addQuestMarks(const QuestInfo * q)
  59. {
  60. OBJ_CONSTRUCTION_CAPTURING_ALL;
  61. icons.clear();
  62. int3 tile;
  63. if(q->obj)
  64. tile = q->obj->pos;
  65. else
  66. tile = q->tile;
  67. int x, y;
  68. minimap->tileToPixels(tile, x, y);
  69. if(level != tile.z)
  70. setLevel(tile.z);
  71. auto pic = std::make_shared<CQuestIcon>("VwSymbol.def", 3, x, y);
  72. pic->moveBy(Point(-pic->pos.w / 2, -pic->pos.h / 2));
  73. pic->callback = std::bind(&CQuestMinimap::iconClicked, this);
  74. icons.push_back(pic);
  75. }
  76. void CQuestMinimap::update()
  77. {
  78. CMinimap::update();
  79. if(currentQuest)
  80. addQuestMarks(currentQuest);
  81. }
  82. void CQuestMinimap::iconClicked()
  83. {
  84. if(currentQuest->obj)
  85. adventureInt->centerOn(currentQuest->obj->pos);
  86. //moveAdvMapSelection();
  87. }
  88. void CQuestMinimap::showAll(SDL_Surface * to)
  89. {
  90. CIntObject::showAll(to); // blitting IntObject directly to hide radar
  91. for(auto pic : icons)
  92. pic->showAll(to);
  93. }
  94. CQuestLog::CQuestLog(const std::vector<QuestInfo> & Quests)
  95. : CWindowObject(PLAYER_COLORED | BORDERED, "questDialog"), questIndex(0), currentQuest(nullptr), componentsBox(nullptr), hideComplete(false), quests(Quests), slider(nullptr)
  96. {
  97. OBJ_CONSTRUCTION_CAPTURING_ALL;
  98. init();
  99. }
  100. void CQuestLog::init()
  101. {
  102. const JsonNode & texts = CGI->generaltexth->localizedTexts["questLog"];
  103. minimap = new CQuestMinimap(Rect(12, 12, 169, 169));
  104. // TextBox have it's own 4 pixel padding from top at least for English. To achieve 10px from both left and top only add 6px margin
  105. description = new CTextBox("", Rect(205, 18, 385, DESCRIPTION_HEIGHT_MAX), CSlider::BROWN, FONT_MEDIUM, TOPLEFT, Colors::WHITE);
  106. ok = new CButton(Point(539, 398), "IOKAY.DEF", CGI->generaltexth->zelp[445], std::bind(&CQuestLog::close, this), SDLK_RETURN);
  107. // Both button and lable are shifted to -2px by x and y to not make them actually look like they're on same line with quests list and ok button
  108. hideCompleteButton = new CToggleButton(Point(10, 396), "sysopchk.def", CButton::tooltip(texts["hideComplete"]), std::bind(&CQuestLog::toggleComplete, this, _1));
  109. hideCompleteLabel = new CLabel(46, 398, FONT_MEDIUM, TOPLEFT, Colors::WHITE, texts["hideComplete"]["label"].String());
  110. slider = new CSlider(Point(166, 195), 191, std::bind(&CQuestLog::sliderMoved, this, _1), QUEST_COUNT, 0, false, CSlider::BROWN);
  111. recreateLabelList();
  112. recreateQuestList(0);
  113. }
  114. void CQuestLog::recreateLabelList()
  115. {
  116. if(labels.size())
  117. labels.clear();
  118. bool completeMissing = true;
  119. int currentLabel = 0;
  120. for(int i = 0; i < quests.size(); ++i)
  121. {
  122. // Quests with MISSION_NONE type don't have text for them and can't be displayed
  123. if(quests[i].quest->missionType == CQuest::MISSION_NONE)
  124. continue;
  125. if(quests[i].quest->progress == CQuest::COMPLETE)
  126. {
  127. completeMissing = false;
  128. if(hideComplete)
  129. continue;
  130. }
  131. MetaString text;
  132. quests[i].quest->getRolloverText(text, false);
  133. if(quests[i].obj)
  134. {
  135. if(auto seersHut = dynamic_cast<const CGSeerHut *>(quests[i].obj))
  136. {
  137. MetaString toSeer;
  138. toSeer << VLC->generaltexth->allTexts[347];
  139. toSeer.addReplacement(seersHut->seerName);
  140. text.addReplacement(toSeer.toString());
  141. }
  142. else
  143. text.addReplacement(quests[i].obj->getObjectName()); //get name of the object
  144. }
  145. auto label = std::make_shared<CQuestLabel>(Rect(13, 195, 149, 31), FONT_SMALL, TOPLEFT, Colors::WHITE, text.toString());
  146. label->disable();
  147. label->callback = std::bind(&CQuestLog::selectQuest, this, i, currentLabel);
  148. labels.push_back(label);
  149. // Select latest active quest
  150. if(quests[i].quest->progress != CQuest::COMPLETE)
  151. selectQuest(i, currentLabel);
  152. currentLabel = labels.size();
  153. }
  154. if(completeMissing) // We can't use block(completeMissing) because if false button state reset to NORMAL
  155. hideCompleteButton->block(true);
  156. slider->setAmount(currentLabel);
  157. if(currentLabel > QUEST_COUNT)
  158. {
  159. slider->block(false);
  160. slider->moveToMax();
  161. }
  162. else
  163. {
  164. slider->block(true);
  165. slider->moveToMin();
  166. }
  167. }
  168. void CQuestLog::showAll(SDL_Surface * to)
  169. {
  170. CWindowObject::showAll(to);
  171. if(labels.size() && labels[questIndex]->active)
  172. {
  173. Rect rect = Rect::around(labels[questIndex]->pos);
  174. rect.x -= 2; // Adjustment needed as we want selection box on top of border in graphics
  175. rect.w += 2;
  176. CSDL_Ext::drawBorder(to, rect, int3(Colors::METALLIC_GOLD.r, Colors::METALLIC_GOLD.g, Colors::METALLIC_GOLD.b));
  177. }
  178. }
  179. void CQuestLog::recreateQuestList(int newpos)
  180. {
  181. for(int i = 0; i < labels.size(); ++i)
  182. {
  183. labels[i]->pos = Rect(pos.x + 14, pos.y + 195 + (i - newpos) * 32, 151, 31);
  184. if(i >= newpos && i < newpos + QUEST_COUNT)
  185. labels[i]->enable();
  186. else
  187. labels[i]->disable();
  188. }
  189. minimap->update();
  190. }
  191. void CQuestLog::selectQuest(int which, int labelId)
  192. {
  193. questIndex = labelId;
  194. currentQuest = &quests[which];
  195. minimap->currentQuest = currentQuest;
  196. MetaString text;
  197. std::vector<Component> components;
  198. currentQuest->quest->getVisitText(text, components, currentQuest->quest->isCustomFirst, true);
  199. if(description->slider)
  200. description->slider->moveToMin(); // scroll text to start position
  201. description->setText(text.toString()); //TODO: use special log entry text
  202. vstd::clear_pointer(componentsBox);
  203. int componentsSize = components.size();
  204. int descriptionHeight = DESCRIPTION_HEIGHT_MAX;
  205. if(componentsSize)
  206. {
  207. descriptionHeight -= 15;
  208. CComponent::ESize imageSize = CComponent::large;
  209. switch(currentQuest->quest->missionType)
  210. {
  211. case CQuest::MISSION_ARMY:
  212. {
  213. if(componentsSize > 4)
  214. descriptionHeight -= 195;
  215. else
  216. descriptionHeight -= 100;
  217. break;
  218. }
  219. case CQuest::MISSION_ART:
  220. {
  221. if(componentsSize > 4)
  222. descriptionHeight -= 190;
  223. else
  224. descriptionHeight -= 90;
  225. break;
  226. }
  227. case CQuest::MISSION_PRIMARY_STAT:
  228. case CQuest::MISSION_RESOURCES:
  229. {
  230. if(componentsSize > 4)
  231. {
  232. imageSize = CComponent::small; // Only small icons can be used for resources as 4+ icons take too much space
  233. descriptionHeight -= 140;
  234. }
  235. else
  236. descriptionHeight -= 125;
  237. break;
  238. }
  239. default:
  240. descriptionHeight -= 115;
  241. break;
  242. }
  243. OBJ_CONSTRUCTION_CAPTURING_ALL;
  244. std::vector<CComponent *> comps;
  245. for(auto & component : components)
  246. comps.push_back(new CComponent(component, imageSize));
  247. componentsBox = new CComponentBox(comps, Rect(202, 20 + descriptionHeight + 15, 391, DESCRIPTION_HEIGHT_MAX - (20 + descriptionHeight)));
  248. }
  249. description->resize(Point(385, descriptionHeight));
  250. minimap->update();
  251. redraw();
  252. }
  253. void CQuestLog::sliderMoved(int newpos)
  254. {
  255. recreateQuestList(newpos); //move components
  256. redraw();
  257. }
  258. void CQuestLog::toggleComplete(bool on)
  259. {
  260. OBJ_CONSTRUCTION_CAPTURING_ALL;
  261. hideComplete = on;
  262. recreateLabelList();
  263. recreateQuestList(0);
  264. redraw();
  265. }