CKingdomInterface.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. #include "CKingdomInterface.h"
  2. #include <boost/algorithm/string/replace.hpp>
  3. #include <boost/bind.hpp>
  4. #include <boost/lexical_cast.hpp>
  5. #include <boost/foreach.hpp>
  6. #include <boost/format.hpp>
  7. #include "../CCallback.h"
  8. #include "../lib/CCreatureHandler.h" //creatures name for objects list
  9. #include "../lib/CGeneralTextHandler.h"
  10. #include "../lib/CObjectHandler.h" //Hero/Town objects
  11. #include "AdventureMapButton.h"
  12. #include "CAnimation.h" //CAnimImage
  13. #include "CAdvmapInterface.h" //CResDataBar
  14. #include "CCastleInterface.h" //various town-specific classes
  15. #include "CConfigHandler.h"
  16. #include "CGameInfo.h"
  17. #include "CPlayerInterface.h" //LOCPLINT
  18. /*
  19. * CKingdomInterface.cpp, part of VCMI engine
  20. *
  21. * Authors: listed in file AUTHORS in main folder
  22. *
  23. * License: GNU General Public License v2.0 or later
  24. * Full text of license available in license.txt file, in main folder
  25. *
  26. */
  27. extern SDL_Surface *screenBuf;
  28. InfoBox::InfoBox(Point position, InfoPos Pos, InfoSize Size, IInfoBoxData *Data):
  29. size(Size),
  30. infoPos(Pos),
  31. data(Data),
  32. value(NULL),
  33. name(NULL)
  34. {
  35. assert(data);
  36. used = LCLICK | RCLICK;
  37. EFonts font = (size < SIZE_MEDIUM)? FONT_SMALL: FONT_MEDIUM;
  38. OBJ_CONSTRUCTION_CAPTURING_ALL;
  39. pos+=position;
  40. image = new CAnimImage(data->getImageName(size), data->getImageIndex());
  41. pos = image->pos;
  42. if (infoPos == POS_CORNER)
  43. value = new CLabel(pos.w, pos.h, font, BOTTOMRIGHT, zwykly, data->getValueText());
  44. if (infoPos == POS_INSIDE)
  45. value = new CLabel(pos.w/2, pos.h-6, font, CENTER, zwykly, data->getValueText());
  46. if (infoPos == POS_UP_DOWN || infoPos == POS_DOWN)
  47. value = new CLabel(pos.w/2, pos.h+8, font, CENTER, zwykly, data->getValueText());
  48. if (infoPos == POS_UP_DOWN)
  49. name = new CLabel(pos.w/2, -12, font, CENTER, zwykly, data->getNameText());
  50. if (infoPos == POS_RIGHT)
  51. {
  52. name = new CLabel(pos.w+6, 6, font, TOPLEFT, zwykly, data->getNameText());
  53. value = new CLabel(pos.w+6, pos.h-16, font, TOPLEFT, zwykly, data->getValueText());
  54. }
  55. pos = image->pos;
  56. if (name)
  57. pos = pos | name->pos;
  58. if (value)
  59. pos = pos | value->pos;
  60. hover = new HoverableArea;
  61. hover->hoverText = data->getHoverText();
  62. hover->pos = pos;
  63. }
  64. InfoBox::~InfoBox()
  65. {
  66. delete data;
  67. }
  68. void InfoBox::clickRight(tribool down, bool previousState)
  69. {
  70. if (down)
  71. {
  72. SComponent *comp;
  73. std::string text;
  74. data->prepareMessage(text, &comp);
  75. if (comp)
  76. CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
  77. else
  78. adventureInt->handleRightClick(text, down);
  79. }
  80. }
  81. void InfoBox::clickLeft(tribool down, bool previousState)
  82. {
  83. if((!down) && previousState)
  84. {
  85. SComponent *comp;
  86. std::string text;
  87. data->prepareMessage(text, &comp);
  88. std::vector<SComponent*> compVector;
  89. if (comp)
  90. compVector.push_back(comp);
  91. LOCPLINT->showInfoDialog(text, compVector);
  92. }
  93. }
  94. //TODO?
  95. /*
  96. void InfoBox::update()
  97. {
  98. }
  99. */
  100. IInfoBoxData::IInfoBoxData(InfoType Type):
  101. type(Type)
  102. {
  103. }
  104. InfoBoxAbstractHeroData::InfoBoxAbstractHeroData(InfoType Type):
  105. IInfoBoxData(Type)
  106. {
  107. }
  108. std::string InfoBoxAbstractHeroData::getValueText()
  109. {
  110. switch (type)
  111. {
  112. case HERO_MANA:
  113. case HERO_EXPERIENCE:
  114. case HERO_PRIMARY_SKILL:
  115. return boost::lexical_cast<std::string>(getValue());
  116. case HERO_SPECIAL:
  117. {
  118. std::string text = CGI->generaltexth->jktexts[5];
  119. size_t begin = text.find('{');
  120. size_t end = text.find('}', begin);
  121. return text.substr(begin, end-begin);
  122. }
  123. case HERO_SECONDARY_SKILL:
  124. {
  125. si64 value = getValue();
  126. if (value)
  127. return CGI->generaltexth->levels[value];
  128. }
  129. default:
  130. assert(0);
  131. }
  132. return "";
  133. }
  134. std::string InfoBoxAbstractHeroData::getNameText()
  135. {
  136. switch (type)
  137. {
  138. case HERO_PRIMARY_SKILL:
  139. return CGI->generaltexth->primarySkillNames[getSubID()];
  140. case HERO_MANA:
  141. return CGI->generaltexth->allTexts[387];
  142. case HERO_EXPERIENCE:
  143. {
  144. std::string text = CGI->generaltexth->jktexts[6];
  145. size_t begin = text.find('{');
  146. size_t end = text.find('}', begin);
  147. return text.substr(begin, end-begin);
  148. }
  149. case HERO_SPECIAL:
  150. return CGI->generaltexth->hTxts[getSubID()].bonusName;
  151. case HERO_SECONDARY_SKILL:
  152. if (getValue())
  153. return CGI->generaltexth->skillName[getSubID()];
  154. else
  155. return "";
  156. default:
  157. assert(0);
  158. }
  159. return "";
  160. }
  161. std::string InfoBoxAbstractHeroData::getImageName(InfoBox::InfoSize size)
  162. {
  163. //TODO: sizes
  164. switch(size)
  165. {
  166. case InfoBox::SIZE_SMALL:
  167. {
  168. switch(type)
  169. {
  170. case HERO_PRIMARY_SKILL:
  171. case HERO_MANA:
  172. case HERO_EXPERIENCE:
  173. return "PSKIL32";
  174. case HERO_SPECIAL:
  175. return "UN32";
  176. case HERO_SECONDARY_SKILL:
  177. return "SECSK32";
  178. default:
  179. assert(0);
  180. }
  181. }
  182. case InfoBox::SIZE_BIG:
  183. {
  184. switch(type)
  185. {
  186. case HERO_PRIMARY_SKILL:
  187. case HERO_MANA:
  188. case HERO_EXPERIENCE:
  189. return "PSKIL42";
  190. case HERO_SPECIAL:
  191. return "UN44";
  192. case HERO_SECONDARY_SKILL:
  193. return "SECSKILL";
  194. default:
  195. assert(0);
  196. }
  197. }
  198. default:
  199. assert(0);
  200. }
  201. return "";
  202. }
  203. std::string InfoBoxAbstractHeroData::getHoverText()
  204. {
  205. //TODO: any texts here?
  206. return "";
  207. }
  208. size_t InfoBoxAbstractHeroData::getImageIndex()
  209. {
  210. switch (type)
  211. {
  212. case HERO_SPECIAL:
  213. case HERO_PRIMARY_SKILL:
  214. return getSubID();
  215. case HERO_MANA:
  216. return 5;
  217. case HERO_EXPERIENCE:
  218. return 4;
  219. case HERO_SECONDARY_SKILL:
  220. {
  221. si64 value = getValue();
  222. if (value)
  223. return getSubID()*3 + value + 2;
  224. else
  225. return 0;//FIXME: Should be transparent instead of empty
  226. }
  227. default:
  228. assert(0);
  229. return 0;
  230. }
  231. }
  232. bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, SComponent **comp)
  233. {
  234. switch (type)
  235. {
  236. case HERO_SPECIAL:
  237. text = CGI->generaltexth->hTxts[getSubID()].longBonus;
  238. *comp = NULL;
  239. return true;
  240. case HERO_PRIMARY_SKILL:
  241. text = CGI->generaltexth->arraytxt[2+getSubID()];
  242. *comp =new SComponent(SComponent::primskill, getSubID(), getValue());
  243. return true;
  244. case HERO_MANA:
  245. text = CGI->generaltexth->allTexts[149];
  246. *comp = NULL;
  247. return true;
  248. case HERO_EXPERIENCE:
  249. text = CGI->generaltexth->allTexts[241];
  250. *comp = NULL;
  251. return true;
  252. case HERO_SECONDARY_SKILL:
  253. {
  254. si64 value = getValue();
  255. int subID = getSubID();
  256. if (!value)
  257. return false;
  258. text = CGI->generaltexth->skillInfoTexts[subID][value-1];
  259. *comp = new SComponent(SComponent::secskill, subID, value);
  260. return true;
  261. }
  262. default:
  263. assert(0);
  264. return false;
  265. }
  266. }
  267. InfoBoxHeroData::InfoBoxHeroData(InfoType Type, const CGHeroInstance * Hero, int Index):
  268. InfoBoxAbstractHeroData(Type),
  269. hero(Hero),
  270. index(Index)
  271. {
  272. }
  273. int InfoBoxHeroData::getSubID()
  274. {
  275. switch(type)
  276. {
  277. case HERO_PRIMARY_SKILL:
  278. return index;
  279. case HERO_SECONDARY_SKILL:
  280. if (hero->secSkills.size() > index)
  281. return hero->secSkills[index].first;
  282. case HERO_MANA:
  283. case HERO_EXPERIENCE:
  284. case HERO_SPECIAL:
  285. return 0;
  286. default:
  287. assert(0);
  288. return 0;
  289. }
  290. }
  291. si64 InfoBoxHeroData::getValue()
  292. {
  293. switch(type)
  294. {
  295. case HERO_PRIMARY_SKILL:
  296. return hero->getPrimSkillLevel(index);
  297. case HERO_MANA:
  298. return hero->mana;
  299. case HERO_EXPERIENCE:
  300. return hero->exp;
  301. case HERO_SECONDARY_SKILL:
  302. if (hero->secSkills.size() > index)
  303. return hero->secSkills[index].second;
  304. case HERO_SPECIAL:
  305. return 0;
  306. default:
  307. assert(0);
  308. return 0;
  309. }
  310. }
  311. std::string InfoBoxHeroData::getHoverText()
  312. {
  313. switch (type)
  314. {
  315. case HERO_PRIMARY_SKILL:
  316. return boost::str(boost::format(CGI->generaltexth->heroscrn[1]) % CGI->generaltexth->primarySkillNames[index]);
  317. case HERO_MANA:
  318. return CGI->generaltexth->heroscrn[22];
  319. case HERO_EXPERIENCE:
  320. return CGI->generaltexth->heroscrn[9];
  321. case HERO_SPECIAL:
  322. return CGI->generaltexth->heroscrn[27];
  323. case HERO_SECONDARY_SKILL:
  324. {
  325. if (hero->secSkills.size() > index)
  326. {
  327. std::string level = CGI->generaltexth->levels[hero->secSkills[index].second-1];
  328. std::string skill = CGI->generaltexth->skillName[hero->secSkills[index].first];
  329. return boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % level % skill);
  330. }
  331. else
  332. return "";
  333. }
  334. default:
  335. return InfoBoxAbstractHeroData::getHoverText();
  336. }
  337. }
  338. std::string InfoBoxHeroData::getValueText()
  339. {
  340. switch (type)
  341. {
  342. case HERO_MANA:
  343. if (hero)
  344. return boost::lexical_cast<std::string>(hero->mana) + '/' +
  345. boost::lexical_cast<std::string>(hero->manaLimit());
  346. case HERO_EXPERIENCE:
  347. return boost::lexical_cast<std::string>(hero->exp);
  348. default:
  349. return InfoBoxAbstractHeroData::getValueText();
  350. }
  351. }
  352. bool InfoBoxHeroData::prepareMessage(std::string &text, SComponent**comp)
  353. {
  354. switch(type)
  355. {
  356. case HERO_MANA:
  357. text = CGI->generaltexth->allTexts[205];
  358. boost::replace_first(text, "%s", boost::lexical_cast<std::string>(hero->name));
  359. boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->mana));
  360. boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->manaLimit()));
  361. *comp = NULL;
  362. return true;
  363. case HERO_EXPERIENCE:
  364. text = CGI->generaltexth->allTexts[2];
  365. boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->level));
  366. boost::replace_first(text, "%d", boost::lexical_cast<std::string>(CGI->heroh->reqExp(hero->level+1)));
  367. boost::replace_first(text, "%d", boost::lexical_cast<std::string>(hero->exp));
  368. *comp = NULL;
  369. return true;
  370. default:
  371. return InfoBoxAbstractHeroData::prepareMessage(text, comp);
  372. }
  373. }
  374. InfoBoxCustomHeroData::InfoBoxCustomHeroData(InfoType Type, int SubID, si64 Value):
  375. InfoBoxAbstractHeroData(Type),
  376. subID(SubID),
  377. value(Value)
  378. {
  379. }
  380. int InfoBoxCustomHeroData::getSubID()
  381. {
  382. return subID;
  383. }
  384. si64 InfoBoxCustomHeroData::getValue()
  385. {
  386. return value;
  387. }
  388. InfoBoxCustom::InfoBoxCustom(std::string ValueText, std::string NameText, std::string ImageName, size_t ImageIndex, std::string HoverText):
  389. IInfoBoxData(CUSTOM),
  390. valueText(ValueText),
  391. nameText(NameText),
  392. imageName(ImageName),
  393. hoverText(HoverText),
  394. imageIndex(ImageIndex)
  395. {
  396. }
  397. std::string InfoBoxCustom::getHoverText()
  398. {
  399. return hoverText;
  400. }
  401. size_t InfoBoxCustom::getImageIndex()
  402. {
  403. return imageIndex;
  404. }
  405. std::string InfoBoxCustom::getImageName(InfoBox::InfoSize size)
  406. {
  407. return imageName;
  408. }
  409. std::string InfoBoxCustom::getNameText()
  410. {
  411. return nameText;
  412. }
  413. std::string InfoBoxCustom::getValueText()
  414. {
  415. return valueText;
  416. }
  417. bool InfoBoxCustom::prepareMessage(std::string &text, SComponent **comp)
  418. {
  419. return false;
  420. }
  421. CObjectList::CObjectList(IGuiObjectListManager *Manager):
  422. manager(Manager)
  423. {
  424. }
  425. CObjectList::~CObjectList()
  426. {
  427. delete manager;
  428. }
  429. void CObjectList::deleteItem(CIntObject* item)
  430. {
  431. if (!item)
  432. return;
  433. if (active)
  434. item->deactivate();
  435. removeChild(item);
  436. manager->removeObject(item);
  437. }
  438. CIntObject* CObjectList::createItem(size_t index)
  439. {
  440. OBJ_CONSTRUCTION_CAPTURING_ALL;
  441. CIntObject * item = manager->getObject(index);
  442. if (item == NULL)
  443. item = new CIntObject();
  444. item->recActions = defActions;
  445. //May happen if object was created before call to getObject()
  446. if(item->parent != this)
  447. {
  448. if (item->parent)
  449. moveChild(item, item->parent, this);
  450. else
  451. addChild(item);
  452. }
  453. if (item && active)
  454. item->activate();
  455. return item;
  456. }
  457. CTabbedInt::CTabbedInt(IGuiObjectListManager *Manager, Point position, size_t ActiveID):
  458. CObjectList(Manager),
  459. activeTab(NULL),
  460. activeID(ActiveID)
  461. {
  462. pos += position;
  463. reset();
  464. }
  465. void CTabbedInt::setActive(size_t which)
  466. {
  467. if (which != activeID)
  468. {
  469. activeID = which;
  470. reset();
  471. }
  472. }
  473. void CTabbedInt::reset()
  474. {
  475. deleteItem(activeTab);
  476. activeTab = createItem(activeID);
  477. activeTab->moveTo(pos.topLeft());
  478. if (active)
  479. redraw();
  480. }
  481. CIntObject * CTabbedInt::getItem()
  482. {
  483. return activeTab;
  484. }
  485. CListBox::CListBox(IGuiObjectListManager *Manager, Point Pos, Point ItemOffset, size_t VisibleSize,
  486. size_t TotalSize, size_t InitialPos, int Slider, Rect SliderPos):
  487. CObjectList(Manager),
  488. first(InitialPos),
  489. totalSize(TotalSize),
  490. itemOffset(ItemOffset)
  491. {
  492. pos += Pos;
  493. items.resize(VisibleSize, NULL);
  494. if (Slider & 1)
  495. {
  496. OBJ_CONSTRUCTION_CAPTURING_ALL;
  497. slider = new CSlider(SliderPos.x, SliderPos.y, SliderPos.w, boost::bind(&CListBox::moveToPos, this, _1),
  498. VisibleSize, TotalSize, InitialPos, Slider & 2, Slider & 4);
  499. }
  500. reset();
  501. }
  502. // Used to move active items after changing list position
  503. void CListBox::updatePositions()
  504. {
  505. Point itemPos = pos.topLeft();
  506. for (std::list<CIntObject*>::iterator it = items.begin(); it!=items.end(); it++)
  507. {
  508. (*it)->moveTo(itemPos);
  509. itemPos += itemOffset;
  510. }
  511. if (active)
  512. {
  513. redraw();
  514. if (slider)
  515. slider->moveTo(first);
  516. }
  517. }
  518. void CListBox::reset()
  519. {
  520. size_t current = first;
  521. for (std::list<CIntObject*>::iterator it = items.begin(); it!=items.end(); it++)
  522. {
  523. deleteItem(*it);
  524. *it = createItem(current++);
  525. }
  526. updatePositions();
  527. }
  528. void CListBox::moveToPos(size_t which)
  529. {
  530. //Calculate new position
  531. size_t maxPossible;
  532. if (totalSize > items.size())
  533. maxPossible = totalSize - items.size();
  534. else
  535. maxPossible = 0;
  536. size_t newPos = std::min(which, maxPossible);
  537. //If move distance is 1 (most of calls from Slider) - use faster shifts instead of resetting all items
  538. if (first - newPos == 1)
  539. moveToPrev();
  540. else if (newPos - first == 1)
  541. moveToNext();
  542. else if (newPos != first)
  543. {
  544. first = newPos;
  545. reset();
  546. }
  547. }
  548. void CListBox::moveToNext()
  549. {
  550. //Remove front item and insert new one to end
  551. if (first + items.size() < totalSize)
  552. {
  553. first++;
  554. deleteItem(items.front());
  555. items.pop_front();
  556. items.push_back(createItem(first+items.size()));
  557. updatePositions();
  558. }
  559. }
  560. void CListBox::moveToPrev()
  561. {
  562. //Remove last item and insert new one at start
  563. if (first)
  564. {
  565. first--;
  566. deleteItem(items.back());
  567. items.pop_back();
  568. items.push_front(createItem(first));
  569. updatePositions();
  570. }
  571. }
  572. std::list<CIntObject*> CListBox::getItems()
  573. {
  574. return items;
  575. }
  576. struct OwnedObjectInfo
  577. {
  578. int imageID;
  579. unsigned int count;
  580. std::string hoverText;
  581. };
  582. class OwnedObjectsListManager : public IGuiObjectListManager
  583. {
  584. std::vector<OwnedObjectInfo> objects;
  585. public:
  586. virtual CIntObject * getObject(size_t position)
  587. {
  588. if (position < objects.size())
  589. {
  590. OwnedObjectInfo &obj = objects[position];
  591. std::string value = boost::lexical_cast<std::string>(obj.count);
  592. return new InfoBox(Point(), InfoBox::POS_CORNER, InfoBox::SIZE_SMALL,
  593. new InfoBoxCustom(value,"", "FLAGPORT", obj.imageID, obj.hoverText));
  594. }
  595. return NULL;
  596. }
  597. OwnedObjectsListManager(std::vector<OwnedObjectInfo> Objects):
  598. objects(Objects)
  599. {
  600. }
  601. };
  602. class TownHeroListManager : public IGuiObjectListManager
  603. {
  604. public:
  605. CIntObject *currentItem;
  606. CIntObject *getObject(size_t position)
  607. {
  608. size_t size = conf.go()->ac.overviewSize;
  609. switch (position)
  610. {
  611. case 0:
  612. return new CKingdHeroList(size);
  613. case 1:
  614. return new CKingdTownList(size);
  615. default:
  616. return NULL;
  617. }
  618. }
  619. };
  620. CKingdomInterface::CKingdomInterface()
  621. {
  622. OBJ_CONSTRUCTION_CAPTURING_ALL;
  623. background = new CPicture(conf.go()->ac.overviewBg);
  624. background->colorize(LOCPLINT->playerID);
  625. pos = background->center();
  626. unsigned int footerPos = conf.go()->ac.overviewSize * 116;
  627. tabArea = new CTabbedInt(new TownHeroListManager, Point(4,4));
  628. std::vector<const CGObjectInstance * > ownedObjects = LOCPLINT->cb->getMyObjects();
  629. generateObjectsList(ownedObjects);
  630. generateMinesList(ownedObjects);
  631. generateButtons();
  632. statusbar = new CGStatusBar(new CPicture("KSTATBAR", 10,pos.h - 45));
  633. resdatabar= new CResDataBar("KRESBAR", 3, 111+footerPos, 32, 2, 76, 76);
  634. }
  635. void CKingdomInterface::generateObjectsList(const std::vector<const CGObjectInstance * > &ownedObjects)
  636. {
  637. unsigned int footerPos = conf.go()->ac.overviewSize * 116;
  638. size_t dwellSize = (footerPos - 64)/57;
  639. //Map used to determine image number for several objects
  640. std::map<std::pair<int,int>,int> idToImage;
  641. idToImage[std::make_pair( 20, 1)] = 81;//Golem factory
  642. idToImage[std::make_pair( 42, 0)] = 82;//Lighthouse
  643. idToImage[std::make_pair( 33, 0)] = 83;//Garrison
  644. idToImage[std::make_pair(219, 0)] = 83;//Garrison
  645. idToImage[std::make_pair( 33, 1)] = 84;//Anti-magic Garrison
  646. idToImage[std::make_pair(219, 1)] = 84;//Anti-magic Garrison
  647. idToImage[std::make_pair( 53, 7)] = 85;//Abandoned mine
  648. idToImage[std::make_pair( 20, 0)] = 86;//Conflux
  649. idToImage[std::make_pair( 87, 0)] = 87;//Harbor
  650. std::map<int, OwnedObjectInfo> visibleObjects;
  651. BOOST_FOREACH(const CGObjectInstance * object, ownedObjects)
  652. {
  653. //Dwellings
  654. if ( object->ID == 17 )
  655. {
  656. OwnedObjectInfo &info = visibleObjects[object->subID];
  657. if (info.count++ == 0)
  658. {
  659. info.hoverText = CGI->creh->creatures[CGI->objh->cregens[object->subID]]->namePl;
  660. info.imageID = object->subID;
  661. }
  662. }
  663. //Special objects from idToImage map that should be displayed in objects list
  664. std::map<std::pair<int,int>,int>::iterator iter = idToImage.find(std::make_pair(object->ID, object->subID));
  665. if (iter != idToImage.end())
  666. {
  667. OwnedObjectInfo &info = visibleObjects[iter->second];
  668. if (info.count++ == 0)
  669. {
  670. info.hoverText = object->hoverName;
  671. info.imageID = iter->second;
  672. }
  673. }
  674. }
  675. std::vector<OwnedObjectInfo> objectsVector;
  676. objectsVector.reserve(visibleObjects.size());
  677. std::pair<int, OwnedObjectInfo> element;
  678. BOOST_FOREACH(element, visibleObjects)
  679. {
  680. objectsVector.push_back(element.second);
  681. }
  682. dwellingsList = new CListBox(new OwnedObjectsListManager(objectsVector), Point(740,44), Point(0,57), dwellSize, visibleObjects.size());
  683. }
  684. void CKingdomInterface::generateMinesList(const std::vector<const CGObjectInstance * > &ownedObjects)
  685. {
  686. unsigned int footerPos = conf.go()->ac.overviewSize * 116;
  687. std::vector<int> minesCount(RESOURCE_QUANTITY, 0);
  688. int totalIncome=0;
  689. BOOST_FOREACH(const CGObjectInstance * object, ownedObjects)
  690. {
  691. //Mines
  692. if ( object->ID == 53 )
  693. {
  694. const CGMine *mine = dynamic_cast<const CGMine*>(object);
  695. assert(mine);
  696. minesCount[mine->producedResource]++;
  697. if (mine->producedResource == Res::GOLD)
  698. totalIncome += mine->producedQuantity;
  699. }
  700. }
  701. //Heroes can produce gold as well - skill, speciality or arts
  702. std::vector<const CGHeroInstance*> heroes = LOCPLINT->cb->getHeroesInfo(true);
  703. for(size_t i=0; i<heroes.size(); i++)
  704. {
  705. totalIncome += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::SECONDARY_SKILL_PREMY, CGHeroInstance::ESTATES));
  706. totalIncome += heroes[i]->valOfBonuses(Selector::typeSubtype(Bonus::GENERATE_RESOURCE, Res::GOLD));
  707. }
  708. //Add town income of all towns
  709. std::vector<const CGTownInstance*> towns = LOCPLINT->cb->getTownsInfo(true);
  710. for(size_t i=0; i<towns.size(); i++)
  711. {
  712. totalIncome += towns[i]->dailyIncome();
  713. }
  714. for (int i=0; i<7; i++)
  715. {
  716. std::string value = boost::lexical_cast<std::string>(minesCount[i]);
  717. minesBox[i] = new InfoBox(Point(20+i*80, 31+footerPos), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
  718. new InfoBoxCustom(value, "", "OVMINES", i, CGI->generaltexth->mines[i].first));
  719. }
  720. incomeArea = new HoverableArea;
  721. incomeArea->pos = Rect(pos.x+580, pos.y+31+footerPos, 136, 68);
  722. incomeArea->hoverText = CGI->generaltexth->allTexts[255];
  723. incomeAmount = new CLabel(628, footerPos + 70, FONT_SMALL, TOPLEFT, zwykly, boost::lexical_cast<std::string>(totalIncome));
  724. }
  725. void CKingdomInterface::generateButtons()
  726. {
  727. unsigned int footerPos = conf.go()->ac.overviewSize * 116;
  728. //Main control buttons
  729. btnHeroes = new AdventureMapButton (CGI->generaltexth->overview[11], CGI->generaltexth->overview[6],
  730. boost::bind(&CKingdomInterface::activateTab, this, 0),748,28+footerPos,"OVBUTN1.DEF", SDLK_h);
  731. btnHeroes->block(true);
  732. btnTowns = new AdventureMapButton (CGI->generaltexth->overview[12], CGI->generaltexth->overview[7],
  733. boost::bind(&CKingdomInterface::activateTab, this, 1),748,64+footerPos,"OVBUTN6.DEF", SDLK_t);
  734. btnExit = new AdventureMapButton (CGI->generaltexth->allTexts[600],"",
  735. boost::bind(&CGuiHandler::popIntTotally,&GH, this),748,99+footerPos,"OVBUTN1.DEF", SDLK_RETURN);
  736. btnExit->assignedKeys.insert(SDLK_ESCAPE);
  737. btnExit->setOffset(3);
  738. //Object list control buttons
  739. dwellTop = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPos, dwellingsList, 0),
  740. 733, 4, "OVBUTN4.DEF");
  741. dwellBottom = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPos, dwellingsList, -1),
  742. 733, footerPos+2, "OVBUTN4.DEF");
  743. dwellBottom->setOffset(2);
  744. dwellUp = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToPrev, dwellingsList),
  745. 733, 24, "OVBUTN4.DEF");
  746. dwellUp->setOffset(4);
  747. dwellDown = new AdventureMapButton ("", "", boost::bind(&CListBox::moveToNext, dwellingsList),
  748. 733, footerPos-18, "OVBUTN4.DEF");
  749. dwellDown->setOffset(6);
  750. }
  751. void CKingdomInterface::activateTab(size_t which)
  752. {
  753. btnHeroes->block(which == 0);
  754. btnTowns->block(which == 1);
  755. tabArea->setActive(which);
  756. }
  757. void CKingdomInterface::townChanged(const CGTownInstance *town)
  758. {
  759. if (CKingdTownList * townList = dynamic_cast<CKingdTownList*>(tabArea->getItem()))
  760. townList->townChanged(town);
  761. }
  762. void CKingdomInterface::updateGarrisons()
  763. {
  764. if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(tabArea->getItem()))
  765. garrison->updateGarrisons();
  766. }
  767. void CKingdomInterface::artifactAssembled(const ArtifactLocation& artLoc)
  768. {
  769. if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
  770. arts->artifactAssembled(artLoc);
  771. }
  772. void CKingdomInterface::artifactDisassembled(const ArtifactLocation& artLoc)
  773. {
  774. if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
  775. arts->artifactDisassembled(artLoc);
  776. }
  777. void CKingdomInterface::artifactMoved(const ArtifactLocation& artLoc, const ArtifactLocation& destLoc)
  778. {
  779. if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
  780. arts->artifactMoved(artLoc, destLoc);
  781. }
  782. void CKingdomInterface::artifactRemoved(const ArtifactLocation& artLoc)
  783. {
  784. if (CArtifactHolder * arts = dynamic_cast<CArtifactHolder*>(tabArea->getItem()))
  785. arts->artifactRemoved(artLoc);
  786. }
  787. class HeroListManager : public IGuiObjectListManager
  788. {
  789. CWindowWithArtifacts * arts;
  790. CArtifactsOfHero::SCommonPart * artsCommonPart;
  791. public:
  792. HeroListManager(CWindowWithArtifacts * parent);
  793. ~HeroListManager();
  794. CIntObject * getObject(size_t position);
  795. void removeObject(CIntObject *object);
  796. };
  797. HeroListManager::HeroListManager(CWindowWithArtifacts * parent)
  798. {
  799. arts = parent;
  800. artsCommonPart = new CArtifactsOfHero::SCommonPart;
  801. }
  802. HeroListManager::~HeroListManager()
  803. {
  804. delete artsCommonPart;
  805. }
  806. CIntObject * HeroListManager::getObject(size_t position)
  807. {
  808. unsigned int picCount = conf.go()->ac.overviewPics;
  809. size_t heroesCount = LOCPLINT->cb->howManyHeroes(false);
  810. if (position < heroesCount)
  811. {
  812. CHeroItem * hero = new CHeroItem(LOCPLINT->cb->getHeroBySerial(position, false), artsCommonPart);
  813. artsCommonPart->participants.insert(hero->heroArts);
  814. arts->artSets.push_back(hero->heroArts);
  815. return hero;
  816. }
  817. else
  818. {
  819. return new CAnimImage("OVSLOT", (position-2) % picCount );
  820. }
  821. };
  822. void HeroListManager::removeObject(CIntObject *object)
  823. {
  824. if (CHeroItem * hero = dynamic_cast<CHeroItem*>(object))
  825. {
  826. arts->artSets.erase(std::find(arts->artSets.begin(), arts->artSets.end(), hero->heroArts));
  827. artsCommonPart->participants.erase(hero->heroArts);
  828. }
  829. delete object;
  830. }
  831. CKingdHeroList::CKingdHeroList(size_t maxSize)
  832. {
  833. OBJ_CONSTRUCTION_CAPTURING_ALL;
  834. title = new CPicture("OVTITLE",16,0);
  835. title->colorize(LOCPLINT->playerID);
  836. heroLabel = new CLabel(150, 10, FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[0]);
  837. skillsLabel = new CLabel(500, 10, FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[1]);
  838. unsigned int townCount = LOCPLINT->cb->howManyHeroes(false);
  839. unsigned int size = conf.go()->ac.overviewSize*116 + 19;
  840. heroes = new CListBox(new HeroListManager(this), Point(19,21), Point(0,116), maxSize, townCount, 0, 1, Rect(-19, -21, size, size) );
  841. }
  842. void CKingdHeroList::updateGarrisons()
  843. {
  844. std::list<CIntObject*> list = heroes->getItems();
  845. BOOST_FOREACH(CIntObject* object, list)
  846. {
  847. if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(object) )
  848. garrison->updateGarrisons();
  849. }
  850. }
  851. class TownListManager : public IGuiObjectListManager
  852. {
  853. public:
  854. CIntObject * getObject(size_t position)
  855. {
  856. unsigned int picCount = conf.go()->ac.overviewPics;
  857. size_t townsCount = LOCPLINT->cb->howManyTowns();
  858. if (position < townsCount)
  859. return new CTownItem(LOCPLINT->cb->getTownBySerial(position));
  860. else
  861. return new CAnimImage("OVSLOT", (position-2) % picCount );
  862. }
  863. };
  864. CKingdTownList::CKingdTownList(size_t maxSize)
  865. {
  866. OBJ_CONSTRUCTION_CAPTURING_ALL;
  867. title = new CPicture("OVTITLE",16,0);
  868. title->colorize(LOCPLINT->playerID);
  869. townLabel = new CLabel(146,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[3]);
  870. garrHeroLabel = new CLabel(375,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[4]);
  871. visitHeroLabel = new CLabel(608,10,FONT_MEDIUM, CENTER, zwykly, CGI->generaltexth->overview[5]);
  872. unsigned int townCount = LOCPLINT->cb->howManyTowns();
  873. unsigned int size = conf.go()->ac.overviewSize*116 + 19;
  874. towns = new CListBox(new TownListManager, Point(19,21), Point(0,116), maxSize, townCount, 0, 1, Rect(-19, -21, size, size) );
  875. }
  876. void CKingdTownList::townChanged(const CGTownInstance *town)
  877. {
  878. std::list<CIntObject*> list = towns->getItems();
  879. BOOST_FOREACH(CIntObject* object, list)
  880. {
  881. CTownItem * townItem = dynamic_cast<CTownItem*>(object);
  882. if ( townItem && townItem->town == town)
  883. townItem->update();
  884. }
  885. }
  886. void CKingdTownList::updateGarrisons()
  887. {
  888. std::list<CIntObject*> list = towns->getItems();
  889. BOOST_FOREACH(CIntObject* object, list)
  890. {
  891. if (CGarrisonHolder * garrison = dynamic_cast<CGarrisonHolder*>(object) )
  892. garrison->updateGarrisons();
  893. }
  894. }
  895. CTownItem::CTownItem(const CGTownInstance* Town):
  896. town(Town)
  897. {
  898. OBJ_CONSTRUCTION_CAPTURING_ALL;
  899. background = new CAnimImage("OVSLOT", 6);
  900. name = new CLabel(74, 8, FONT_SMALL, TOPLEFT, zwykly, town->name);
  901. income = new CLabel( 190, 60, FONT_SMALL, CENTER, zwykly, boost::lexical_cast<std::string>(town->dailyIncome()));
  902. hall = new CTownInfo( 69, 31, town, true);
  903. fort = new CTownInfo(111, 31, town, false);
  904. garr = new CGarrisonInt(313, 3, 4, Point(232,0), NULL, Point(313,2), town->getUpperArmy(), town->visitingHero, true, true, true);
  905. heroes = new HeroSlots(town, Point(244,6), Point(475,6), garr, false);
  906. size_t iconIndex = town->subID*2;
  907. if (!town->hasFort())
  908. iconIndex += F_NUMBER*2;
  909. if(town->builded >= MAX_BUILDING_PER_TURN)
  910. iconIndex++;
  911. picture = new CAnimImage("ITPT", iconIndex, 0, 5, 6);
  912. townArea = new LRClickableAreaOpenTown;
  913. townArea->pos = Rect(pos.x+5, pos.y+6, 58, 64);
  914. townArea->town = town;
  915. for (size_t i=0; i<town->creatures.size(); i++)
  916. {
  917. growth.push_back(new CCreaInfo(Point(401+37*i, 78), town, i, true, true));
  918. available.push_back(new CCreaInfo(Point(48+37*i, 78), town, i, true, false));
  919. }
  920. }
  921. void CTownItem::updateGarrisons()
  922. {
  923. garr->highlighted = NULL;
  924. garr->setArmy(town->getUpperArmy(), 0);
  925. garr->setArmy(town->visitingHero, 1);
  926. garr->recreateSlots();
  927. }
  928. void CTownItem::update()
  929. {
  930. std::string incomeVal = boost::lexical_cast<std::string>(town->dailyIncome());
  931. if (incomeVal != income->text)
  932. income->setTxt(incomeVal);
  933. heroes->update();
  934. for (size_t i=0; i<town->creatures.size(); i++)
  935. {
  936. growth[i]->update();
  937. available[i]->update();
  938. }
  939. }
  940. class ArtSlotsTab : public CIntObject
  941. {
  942. public:
  943. CAnimImage * background;
  944. std::vector<CArtPlace*> arts;
  945. ArtSlotsTab()
  946. {
  947. OBJ_CONSTRUCTION_CAPTURING_ALL;
  948. background = new CAnimImage("OVSLOT", 4);
  949. pos = background->pos;
  950. for (size_t i=0; i<9; i++)
  951. arts.push_back(new CArtPlace(Point(270+i*48, 65)));
  952. }
  953. };
  954. class BackpackTab : public CIntObject
  955. {
  956. public:
  957. CAnimImage * background;
  958. std::vector<CArtPlace*> arts;
  959. AdventureMapButton *btnLeft;
  960. AdventureMapButton *btnRight;
  961. BackpackTab()
  962. {
  963. OBJ_CONSTRUCTION_CAPTURING_ALL;
  964. background = new CAnimImage("OVSLOT", 5);
  965. pos = background->pos;
  966. btnLeft = new AdventureMapButton(std::string(), std::string(), CFunctionList<void()>(), 269, 66, "HSBTNS3");
  967. btnRight = new AdventureMapButton(std::string(), std::string(), CFunctionList<void()>(), 675, 66, "HSBTNS5");
  968. for (size_t i=0; i<8; i++)
  969. arts.push_back(new CArtPlace(Point(295+i*48, 65)));
  970. }
  971. };
  972. class HeroItemManager : public CIntObject, public IGuiObjectListManager
  973. {
  974. public:
  975. ArtSlotsTab* tab1;
  976. ArtSlotsTab* tab2;
  977. BackpackTab* tab3;
  978. HeroItemManager(const CGHeroInstance* Hero);
  979. CIntObject * getObject(size_t position);
  980. void removeObject(CIntObject * object);
  981. };
  982. HeroItemManager::HeroItemManager(const CGHeroInstance* Hero)
  983. {
  984. OBJ_CONSTRUCTION_CAPTURING_ALL;
  985. recActions = 0;
  986. defActions = DISPOSE | SHARE_POS;
  987. tab1 = new ArtSlotsTab;
  988. tab2 = new ArtSlotsTab;
  989. tab3 = new BackpackTab;
  990. }
  991. CIntObject * HeroItemManager::getObject(size_t position)
  992. {
  993. switch (position)
  994. {
  995. case 0: return tab1;
  996. case 1: return tab2;
  997. case 2: return tab3;
  998. default: assert(0);
  999. return NULL;
  1000. }
  1001. }
  1002. void HeroItemManager::removeObject(CIntObject * object)
  1003. {
  1004. addChild(object, false);
  1005. }
  1006. CHeroItem::CHeroItem(const CGHeroInstance* Hero, CArtifactsOfHero::SCommonPart * artsCommonPart):
  1007. hero(Hero)
  1008. {
  1009. OBJ_CONSTRUCTION_CAPTURING_ALL;
  1010. name = new CLabel(75, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name);
  1011. HeroItemManager *manager = new HeroItemManager(hero);
  1012. std::vector<CArtPlace*> arts;
  1013. arts.insert(arts.end(), manager->tab1->arts.begin(), manager->tab1->arts.end());
  1014. arts.insert(arts.end(), manager->tab2->arts.begin(), manager->tab2->arts.end());
  1015. heroArts = new CArtifactsOfHero(arts, manager->tab3->arts, manager->tab3->btnLeft, manager->tab3->btnRight, false);
  1016. heroArts->commonInfo = artsCommonPart;
  1017. heroArts->setHero(hero);
  1018. artsTabs = new CTabbedInt(manager);
  1019. artButtons = new CHighlightableButtonsGroup(0);
  1020. for (size_t it = 0; it<3; it++)
  1021. {
  1022. std::map<int,std::string> tooltip;
  1023. tooltip[0] = CGI->generaltexth->overview[13+it];
  1024. std::string overlay = CGI->generaltexth->overview[8+it];
  1025. artButtons->addButton(tooltip, overlay, "OVBUTN3",364+it*112, 46, it);
  1026. size_t begin = overlay.find('{');
  1027. size_t end = overlay.find('}', begin);
  1028. overlay = overlay.substr(begin+1, end - begin);
  1029. artButtons->buttons[it]->addTextOverlay(overlay, FONT_SMALL, tytulowy);
  1030. }
  1031. artButtons->onChange += boost::bind(&CTabbedInt::setActive, artsTabs, _1);
  1032. artButtons->onChange += boost::bind(&CHeroItem::onArtChange, this, _1);
  1033. artButtons->select(0,0);
  1034. garr = new CGarrisonInt(6, 78, 4, Point(), NULL, Point(), hero, NULL, true, true);
  1035. portrait = new CAnimImage("PortraitsLarge", hero->subID, 0, 5, 6);
  1036. heroArea = new CHeroArea(5, 6, hero);
  1037. name = new CLabel(73, 7, FONT_SMALL, TOPLEFT, zwykly, hero->name);
  1038. artsText = new CLabel(320, 55, FONT_SMALL, CENTER, zwykly, CGI->generaltexth->overview[2]);
  1039. for (size_t i=0; i<PRIMARY_SKILLS; i++)
  1040. heroInfo.push_back(new InfoBox(Point(78+i*36, 26), InfoBox::POS_DOWN, InfoBox::SIZE_SMALL,
  1041. new InfoBoxHeroData(IInfoBoxData::HERO_PRIMARY_SKILL, hero, i)));
  1042. for (size_t i=0; i<SKILL_PER_HERO; i++)
  1043. heroInfo.push_back(new InfoBox(Point(410+i*36, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL,
  1044. new InfoBoxHeroData(IInfoBoxData::HERO_SECONDARY_SKILL, hero, i)));
  1045. heroInfo.push_back(new InfoBox(Point(375, 5), InfoBox::POS_NONE, InfoBox::SIZE_SMALL,
  1046. new InfoBoxHeroData(IInfoBoxData::HERO_SPECIAL, hero)));
  1047. heroInfo.push_back(new InfoBox(Point(330, 5), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
  1048. new InfoBoxHeroData(IInfoBoxData::HERO_EXPERIENCE, hero)));
  1049. heroInfo.push_back(new InfoBox(Point(280, 5), InfoBox::POS_INSIDE, InfoBox::SIZE_SMALL,
  1050. new InfoBoxHeroData(IInfoBoxData::HERO_MANA, hero)));
  1051. morale = new MoraleLuckBox(true, Rect(225, 53, 30, 22), true);
  1052. luck = new MoraleLuckBox(false, Rect(225, 28, 30, 22), true);
  1053. morale->set(hero);
  1054. luck->set(hero);
  1055. }
  1056. void CHeroItem::onArtChange(int tabIndex)
  1057. {
  1058. //redraw item after background change
  1059. if (active)
  1060. redraw();
  1061. }