MiscWidgets.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. #include "StdInc.h"
  2. #include "MiscWidgets.h"
  3. #include "../gui/CGuiHandler.h"
  4. #include "../gui/CCursorHandler.h"
  5. #include "../CBitmapHandler.h"
  6. #include "../CPlayerInterface.h"
  7. #include "../CMessage.h"
  8. #include "../CGameInfo.h"
  9. #include "../windows/CAdvmapInterface.h"
  10. #include "../windows/CCastleInterface.h"
  11. #include "../../CCallback.h"
  12. #include "../../lib/mapObjects/CGHeroInstance.h"
  13. #include "../../lib/CGeneralTextHandler.h"
  14. #include "../../lib/CModHandler.h"
  15. /*
  16. * MiscWidgets.cpp, part of VCMI engine
  17. *
  18. * Authors: listed in file AUTHORS in main folder
  19. *
  20. * License: GNU General Public License v2.0 or later
  21. * Full text of license available in license.txt file, in main folder
  22. *
  23. */
  24. void CSelWindow::selectionChange(unsigned to)
  25. {
  26. for (unsigned i=0;i<components.size();i++)
  27. {
  28. CSelectableComponent * pom = dynamic_cast<CSelectableComponent*>(components[i]);
  29. if (!pom)
  30. continue;
  31. pom->select(i==to);
  32. }
  33. redraw();
  34. }
  35. CSelWindow::CSelWindow(const std::string &Text, PlayerColor player, int charperline, const std::vector<CSelectableComponent*> &comps, const std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, QueryID askID)
  36. {
  37. OBJ_CONSTRUCTION_CAPTURING_ALL;
  38. ID = askID;
  39. for(int i=0;i<Buttons.size();i++)
  40. {
  41. buttons.push_back(new CAdventureMapButton("","",Buttons[i].second,0,0,Buttons[i].first));
  42. if(!i && askID.getNum() >= 0)
  43. buttons.back()->callback += boost::bind(&CSelWindow::madeChoice,this);
  44. buttons[i]->callback += boost::bind(&CInfoWindow::close,this); //each button will close the window apart from call-defined actions
  45. }
  46. text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
  47. buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
  48. buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
  49. if(buttons.size() > 1 && askID.getNum() >= 0) //cancel button functionality
  50. buttons.back()->callback += boost::bind(&CCallback::selectionMade,LOCPLINT->cb.get(),0,askID);
  51. for(int i=0;i<comps.size();i++)
  52. {
  53. comps[i]->recActions = 255;
  54. addChild(comps[i]);
  55. components.push_back(comps[i]);
  56. comps[i]->onSelect = boost::bind(&CSelWindow::selectionChange,this,i);
  57. if(i<9)
  58. comps[i]->assignedKeys.insert(SDLK_1+i);
  59. }
  60. CMessage::drawIWindow(this, Text, player);
  61. }
  62. void CSelWindow::madeChoice()
  63. {
  64. if(ID.getNum() < 0)
  65. return;
  66. int ret = -1;
  67. for (int i=0;i<components.size();i++)
  68. {
  69. if(dynamic_cast<CSelectableComponent*>(components[i])->selected)
  70. {
  71. ret = i;
  72. }
  73. }
  74. LOCPLINT->cb->selectionMade(ret+1,ID);
  75. }
  76. CInfoWindow::CInfoWindow(std::string Text, PlayerColor player, const TCompsInfo &comps, const TButtonsInfo &Buttons, bool delComps)
  77. {
  78. OBJ_CONSTRUCTION_CAPTURING_ALL;
  79. type |= BLOCK_ADV_HOTKEYS;
  80. ID = QueryID(-1);
  81. for(auto & Button : Buttons)
  82. {
  83. CAdventureMapButton *button = new CAdventureMapButton("","",boost::bind(&CInfoWindow::close,this),0,0,Button.first);
  84. button->borderColor = Colors::METALLIC_GOLD;
  85. button->borderEnabled = true;
  86. button->callback.add(Button.second); //each button will close the window apart from call-defined actions
  87. buttons.push_back(button);
  88. }
  89. text = new CTextBox(Text, Rect(0, 0, 250, 100), 0, FONT_MEDIUM, CENTER, Colors::WHITE);
  90. if(!text->slider)
  91. {
  92. text->resize(text->label->textSize);
  93. }
  94. if(buttons.size())
  95. {
  96. buttons.front()->assignedKeys.insert(SDLK_RETURN); //first button - reacts on enter
  97. buttons.back()->assignedKeys.insert(SDLK_ESCAPE); //last button - reacts on escape
  98. }
  99. for(auto & comp : comps)
  100. {
  101. comp->recActions = 0xff;
  102. addChild(comp);
  103. comp->recActions &= ~(SHOWALL | UPDATE);
  104. components.push_back(comp);
  105. }
  106. setDelComps(delComps);
  107. CMessage::drawIWindow(this,Text,player);
  108. }
  109. CInfoWindow::CInfoWindow()
  110. {
  111. ID = QueryID(-1);
  112. setDelComps(false);
  113. text = nullptr;
  114. }
  115. void CInfoWindow::close()
  116. {
  117. GH.popIntTotally(this);
  118. if(LOCPLINT)
  119. LOCPLINT->showingDialog->setn(false);
  120. }
  121. void CInfoWindow::show(SDL_Surface * to)
  122. {
  123. CIntObject::show(to);
  124. }
  125. CInfoWindow::~CInfoWindow()
  126. {
  127. if(!delComps)
  128. {
  129. for (auto & elem : components)
  130. removeChild(elem);
  131. }
  132. }
  133. void CInfoWindow::showAll(SDL_Surface * to)
  134. {
  135. CSimpleWindow::show(to);
  136. CIntObject::showAll(to);
  137. }
  138. void CInfoWindow::showInfoDialog(const std::string &text, const std::vector<CComponent *> *components, bool DelComps, PlayerColor player)
  139. {
  140. CInfoWindow * window = CInfoWindow::create(text, player, components, DelComps);
  141. GH.pushInt(window);
  142. }
  143. void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<CComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, PlayerColor player)
  144. {
  145. assert(!LOCPLINT || LOCPLINT->showingDialog->get());
  146. std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
  147. pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
  148. pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0));
  149. CInfoWindow * temp = new CInfoWindow(text, player, components ? *components : std::vector<CComponent*>(), pom, DelComps);
  150. for(auto & elem : onYes.funcs)
  151. temp->buttons[0]->callback += elem;
  152. for(auto & elem : onNo.funcs)
  153. temp->buttons[1]->callback += elem;
  154. GH.pushInt(temp);
  155. }
  156. void CInfoWindow::showOkDialog(const std::string & text, const std::vector<CComponent*> *components, const boost::function<void()> & onOk, bool delComps, PlayerColor player)
  157. {
  158. std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
  159. pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
  160. CInfoWindow * temp = new CInfoWindow(text, player, *components, pom, delComps);
  161. temp->buttons[0]->callback += onOk;
  162. GH.pushInt(temp);
  163. }
  164. CInfoWindow * CInfoWindow::create(const std::string &text, PlayerColor playerID /*= 1*/, const std::vector<CComponent*> *components /*= nullptr*/, bool DelComps)
  165. {
  166. std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
  167. pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
  168. CInfoWindow * ret = new CInfoWindow(text, playerID, components ? *components : std::vector<CComponent*>(), pom, DelComps);
  169. return ret;
  170. }
  171. std::string CInfoWindow::genText(std::string title, std::string description)
  172. {
  173. return std::string("{") + title + "}" + "\n\n" + description;
  174. }
  175. void CInfoWindow::setDelComps(bool DelComps)
  176. {
  177. delComps = DelComps;
  178. for(CComponent *comp : components)
  179. {
  180. if(delComps)
  181. comp->recActions |= DISPOSE;
  182. else
  183. comp->recActions &= ~DISPOSE;
  184. }
  185. }
  186. CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, int x, int y, bool Free)
  187. :free(Free),bitmap(Bitmap)
  188. {
  189. init(x, y);
  190. }
  191. CInfoPopup::CInfoPopup(SDL_Surface * Bitmap, const Point &p, EAlignment alignment, bool Free/*=false*/)
  192. : free(Free),bitmap(Bitmap)
  193. {
  194. switch(alignment)
  195. {
  196. case BOTTOMRIGHT:
  197. init(p.x - Bitmap->w, p.y - Bitmap->h);
  198. break;
  199. case CENTER:
  200. init(p.x - Bitmap->w/2, p.y - Bitmap->h/2);
  201. break;
  202. case TOPLEFT:
  203. init(p.x, p.y);
  204. break;
  205. default:
  206. assert(0); //not implemented
  207. }
  208. }
  209. CInfoPopup::CInfoPopup(SDL_Surface *Bitmap, bool Free)
  210. {
  211. CCS->curh->hide();
  212. free=Free;
  213. bitmap=Bitmap;
  214. if(bitmap)
  215. {
  216. pos.x = screen->w/2 - bitmap->w/2;
  217. pos.y = screen->h/2 - bitmap->h/2;
  218. pos.h = bitmap->h;
  219. pos.w = bitmap->w;
  220. }
  221. }
  222. void CInfoPopup::close()
  223. {
  224. if(free)
  225. SDL_FreeSurface(bitmap);
  226. GH.popIntTotally(this);
  227. }
  228. void CInfoPopup::show(SDL_Surface * to)
  229. {
  230. blitAt(bitmap,pos.x,pos.y,to);
  231. }
  232. CInfoPopup::~CInfoPopup()
  233. {
  234. CCS->curh->show();
  235. }
  236. void CInfoPopup::init(int x, int y)
  237. {
  238. CCS->curh->hide();
  239. pos.x = x;
  240. pos.y = y;
  241. pos.h = bitmap->h;
  242. pos.w = bitmap->w;
  243. // Put the window back on screen if necessary
  244. vstd::amax(pos.x, 0);
  245. vstd::amax(pos.y, 0);
  246. vstd::amin(pos.x, screen->w - bitmap->w);
  247. vstd::amin(pos.y, screen->h - bitmap->h);
  248. }
  249. void CRClickPopup::clickRight(tribool down, bool previousState)
  250. {
  251. if(down)
  252. return;
  253. close();
  254. }
  255. void CRClickPopup::close()
  256. {
  257. GH.popIntTotally(this);
  258. }
  259. void CRClickPopup::createAndPush(const std::string &txt, const CInfoWindow::TCompsInfo &comps)
  260. {
  261. PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue
  262. CSimpleWindow * temp = new CInfoWindow(txt, player, comps);
  263. temp->center(Point(GH.current->motion)); //center on mouse
  264. temp->fitToScreen(10);
  265. auto rcpi = new CRClickPopupInt(temp,true);
  266. GH.pushInt(rcpi);
  267. }
  268. void CRClickPopup::createAndPush(const std::string &txt, CComponent * component)
  269. {
  270. CInfoWindow::TCompsInfo intComps;
  271. intComps.push_back(component);
  272. createAndPush(txt, intComps);
  273. }
  274. void CRClickPopup::createAndPush(const CGObjectInstance *obj, const Point &p, EAlignment alignment /*= BOTTOMRIGHT*/)
  275. {
  276. CIntObject *iWin = createInfoWin(p, obj); //try get custom infowindow for this obj
  277. if(iWin)
  278. GH.pushInt(iWin);
  279. else
  280. {
  281. if (adventureInt->curHero())
  282. CRClickPopup::createAndPush(obj->getHoverText(adventureInt->curHero()));
  283. else
  284. CRClickPopup::createAndPush(obj->getHoverText(LOCPLINT->playerID));
  285. }
  286. }
  287. CRClickPopup::CRClickPopup()
  288. {
  289. addUsedEvents(RCLICK);
  290. }
  291. CRClickPopup::~CRClickPopup()
  292. {
  293. }
  294. void CRClickPopupInt::show(SDL_Surface * to)
  295. {
  296. inner->show(to);
  297. }
  298. CRClickPopupInt::CRClickPopupInt( IShowActivatable *our, bool deleteInt )
  299. {
  300. CCS->curh->hide();
  301. inner = our;
  302. delInner = deleteInt;
  303. }
  304. CRClickPopupInt::~CRClickPopupInt()
  305. {
  306. if(delInner)
  307. delete inner;
  308. CCS->curh->show();
  309. }
  310. void CRClickPopupInt::showAll(SDL_Surface * to)
  311. {
  312. inner->showAll(to);
  313. }
  314. Point CInfoBoxPopup::toScreen(Point p)
  315. {
  316. vstd::abetween(p.x, adventureInt->terrain.pos.x + 100, adventureInt->terrain.pos.x + adventureInt->terrain.pos.w - 100);
  317. vstd::abetween(p.y, adventureInt->terrain.pos.y + 100, adventureInt->terrain.pos.y + adventureInt->terrain.pos.h - 100);
  318. return p;
  319. }
  320. CInfoBoxPopup::CInfoBoxPopup(Point position, const CGTownInstance * town):
  321. CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
  322. {
  323. InfoAboutTown iah;
  324. LOCPLINT->cb->getTownInfo(town, iah);
  325. OBJ_CONSTRUCTION_CAPTURING_ALL;
  326. new CTownTooltip(Point(9, 10), iah);
  327. }
  328. CInfoBoxPopup::CInfoBoxPopup(Point position, const CGHeroInstance * hero):
  329. CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "HEROQVBK", toScreen(position))
  330. {
  331. InfoAboutHero iah;
  332. LOCPLINT->cb->getHeroInfo(hero, iah);
  333. OBJ_CONSTRUCTION_CAPTURING_ALL;
  334. new CHeroTooltip(Point(9, 10), iah);
  335. }
  336. CInfoBoxPopup::CInfoBoxPopup(Point position, const CGGarrison * garr):
  337. CWindowObject(RCLICK_POPUP | PLAYER_COLORED, "TOWNQVBK", toScreen(position))
  338. {
  339. InfoAboutTown iah;
  340. LOCPLINT->cb->getTownInfo(garr, iah);
  341. OBJ_CONSTRUCTION_CAPTURING_ALL;
  342. new CArmyTooltip(Point(9, 10), iah);
  343. }
  344. CIntObject * CRClickPopup::createInfoWin(Point position, const CGObjectInstance * specific) //specific=0 => draws info about selected town/hero
  345. {
  346. if(!specific)
  347. specific = adventureInt->selection;
  348. assert(specific);
  349. switch(specific->ID)
  350. {
  351. case Obj::HERO:
  352. return new CInfoBoxPopup(position, dynamic_cast<const CGHeroInstance *>(specific));
  353. case Obj::TOWN:
  354. return new CInfoBoxPopup(position, dynamic_cast<const CGTownInstance *>(specific));
  355. case Obj::GARRISON:
  356. case Obj::GARRISON2:
  357. return new CInfoBoxPopup(position, dynamic_cast<const CGGarrison *>(specific));
  358. default:
  359. return nullptr;
  360. }
  361. }
  362. void LRClickableAreaWTextComp::clickLeft(tribool down, bool previousState)
  363. {
  364. if((!down) && previousState)
  365. {
  366. std::vector<CComponent*> comp(1, createComponent());
  367. LOCPLINT->showInfoDialog(text, comp);
  368. }
  369. }
  370. LRClickableAreaWTextComp::LRClickableAreaWTextComp(const Rect &Pos, int BaseType)
  371. : LRClickableAreaWText(Pos), baseType(BaseType), bonusValue(-1)
  372. {
  373. }
  374. CComponent * LRClickableAreaWTextComp::createComponent() const
  375. {
  376. if(baseType >= 0)
  377. return new CComponent(CComponent::Etype(baseType), type, bonusValue);
  378. else
  379. return nullptr;
  380. }
  381. void LRClickableAreaWTextComp::clickRight(tribool down, bool previousState)
  382. {
  383. if(down)
  384. {
  385. if(CComponent *comp = createComponent())
  386. {
  387. CRClickPopup::createAndPush(text, CInfoWindow::TCompsInfo(1, comp));
  388. return;
  389. }
  390. }
  391. LRClickableAreaWText::clickRight(down, previousState); //only if with-component variant not occurred
  392. }
  393. CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * _hero):hero(_hero)
  394. {
  395. OBJ_CONSTRUCTION_CAPTURING_ALL;
  396. addUsedEvents(LCLICK | RCLICK | HOVER);
  397. pos.x += x; pos.w = 58;
  398. pos.y += y; pos.h = 64;
  399. if (hero)
  400. new CAnimImage("PortraitsLarge", hero->portrait);
  401. }
  402. void CHeroArea::clickLeft(tribool down, bool previousState)
  403. {
  404. if((!down) && previousState && hero)
  405. LOCPLINT->openHeroWindow(hero);
  406. }
  407. void CHeroArea::clickRight(tribool down, bool previousState)
  408. {
  409. if((!down) && previousState && hero)
  410. LOCPLINT->openHeroWindow(hero);
  411. }
  412. void CHeroArea::hover(bool on)
  413. {
  414. if (on && hero)
  415. GH.statusbar->setText(hero->getObjectName());
  416. else
  417. GH.statusbar->clear();
  418. }
  419. void LRClickableAreaOpenTown::clickLeft(tribool down, bool previousState)
  420. {
  421. if((!down) && previousState && town)
  422. {
  423. LOCPLINT->openTownWindow(town);
  424. if ( type == 2 )
  425. LOCPLINT->castleInt->builds->buildingClicked(BuildingID::VILLAGE_HALL);
  426. else if ( type == 3 && town->fortLevel() )
  427. LOCPLINT->castleInt->builds->buildingClicked(BuildingID::FORT);
  428. }
  429. }
  430. void LRClickableAreaOpenTown::clickRight(tribool down, bool previousState)
  431. {
  432. if((!down) && previousState && town)
  433. LOCPLINT->openTownWindow(town);//TODO: popup?
  434. }
  435. LRClickableAreaOpenTown::LRClickableAreaOpenTown()
  436. : LRClickableAreaWTextComp(Rect(0,0,0,0), -1)
  437. {
  438. }
  439. void CMinorResDataBar::show(SDL_Surface * to)
  440. {
  441. }
  442. void CMinorResDataBar::showAll(SDL_Surface * to)
  443. {
  444. blitAt(bg,pos.x,pos.y,to);
  445. for (Res::ERes i=Res::WOOD; i<=Res::GOLD; vstd::advance(i, 1))
  446. {
  447. std::string text = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(i));
  448. graphics->fonts[FONT_SMALL]->renderTextCenter(to, text, Colors::WHITE, Point(pos.x + 50 + 76 * i, pos.y + pos.h/2));
  449. }
  450. std::vector<std::string> temp;
  451. temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::MONTH)));
  452. temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::WEEK)));
  453. temp.push_back(boost::lexical_cast<std::string>(LOCPLINT->cb->getDate(Date::DAY_OF_WEEK)));
  454. std::string datetext = CGI->generaltexth->allTexts[62]+": %s, " + CGI->generaltexth->allTexts[63]
  455. + ": %s, " + CGI->generaltexth->allTexts[64] + ": %s";
  456. graphics->fonts[FONT_SMALL]->renderTextCenter(to, CSDL_Ext::processStr(datetext,temp), Colors::WHITE, Point(pos.x+545+(pos.w-545)/2,pos.y+pos.h/2));
  457. }
  458. CMinorResDataBar::CMinorResDataBar()
  459. {
  460. bg = BitmapHandler::loadBitmap("KRESBAR.bmp");
  461. CSDL_Ext::setDefaultColorKey(bg);
  462. graphics->blueToPlayersAdv(bg,LOCPLINT->playerID);
  463. pos.x = 7;
  464. pos.y = 575;
  465. pos.w = bg->w;
  466. pos.h = bg->h;
  467. }
  468. CMinorResDataBar::~CMinorResDataBar()
  469. {
  470. SDL_FreeSurface(bg);
  471. }
  472. void CArmyTooltip::init(const InfoAboutArmy &army)
  473. {
  474. OBJ_CONSTRUCTION_CAPTURING_ALL;
  475. new CLabel(66, 2, FONT_SMALL, TOPLEFT, Colors::WHITE, army.name);
  476. std::vector<Point> slotsPos;
  477. slotsPos.push_back(Point(36,73));
  478. slotsPos.push_back(Point(72,73));
  479. slotsPos.push_back(Point(108,73));
  480. slotsPos.push_back(Point(18,122));
  481. slotsPos.push_back(Point(54,122));
  482. slotsPos.push_back(Point(90,122));
  483. slotsPos.push_back(Point(126,122));
  484. for(auto & slot : army.army)
  485. {
  486. if(slot.first.getNum() >= GameConstants::ARMY_SIZE)
  487. {
  488. logGlobal->warnStream() << "Warning: " << army.name << " has stack in slot " << slot.first;
  489. continue;
  490. }
  491. new CAnimImage("CPRSMALL", slot.second.type->iconIndex, 0, slotsPos[slot.first.getNum()].x, slotsPos[slot.first.getNum()].y);
  492. std::string subtitle;
  493. if(army.army.isDetailed)
  494. subtitle = boost::lexical_cast<std::string>(slot.second.count);
  495. else
  496. {
  497. //if =0 - we have no information about stack size at all
  498. if (slot.second.count)
  499. subtitle = CGI->generaltexth->arraytxt[171 + 3*(slot.second.count)];
  500. }
  501. new CLabel(slotsPos[slot.first.getNum()].x + 17, slotsPos[slot.first.getNum()].y + 41, FONT_TINY, CENTER, Colors::WHITE, subtitle);
  502. }
  503. }
  504. CArmyTooltip::CArmyTooltip(Point pos, const InfoAboutArmy &army):
  505. CIntObject(0, pos)
  506. {
  507. init(army);
  508. }
  509. CArmyTooltip::CArmyTooltip(Point pos, const CArmedInstance * army):
  510. CIntObject(0, pos)
  511. {
  512. init(InfoAboutArmy(army, true));
  513. }
  514. void CHeroTooltip::init(const InfoAboutHero &hero)
  515. {
  516. OBJ_CONSTRUCTION_CAPTURING_ALL;
  517. new CAnimImage("PortraitsLarge", hero.portrait, 0, 3, 2);
  518. if(hero.details)
  519. {
  520. for (size_t i = 0; i < hero.details->primskills.size(); i++)
  521. new CLabel(75 + 28 * i, 58, FONT_SMALL, CENTER, Colors::WHITE,
  522. boost::lexical_cast<std::string>(hero.details->primskills[i]));
  523. new CLabel(158, 98, FONT_TINY, CENTER, Colors::WHITE,
  524. boost::lexical_cast<std::string>(hero.details->mana));
  525. new CAnimImage("IMRL22", hero.details->morale + 3, 0, 5, 74);
  526. new CAnimImage("ILCK22", hero.details->luck + 3, 0, 5, 91);
  527. }
  528. }
  529. CHeroTooltip::CHeroTooltip(Point pos, const InfoAboutHero &hero):
  530. CArmyTooltip(pos, hero)
  531. {
  532. init(hero);
  533. }
  534. CHeroTooltip::CHeroTooltip(Point pos, const CGHeroInstance * hero):
  535. CArmyTooltip(pos, InfoAboutHero(hero, true))
  536. {
  537. init(InfoAboutHero(hero, true));
  538. }
  539. void CTownTooltip::init(const InfoAboutTown &town)
  540. {
  541. OBJ_CONSTRUCTION_CAPTURING_ALL;
  542. //order of icons in def: fort, citadel, castle, no fort
  543. size_t fortIndex = town.fortLevel ? town.fortLevel - 1 : 3;
  544. new CAnimImage("ITMCLS", fortIndex, 0, 105, 31);
  545. assert(town.tType);
  546. size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
  547. new CAnimImage("itpt", iconIndex, 0, 3, 2);
  548. if(town.details)
  549. {
  550. new CAnimImage("ITMTLS", town.details->hallLevel, 0, 67, 31);
  551. if (town.details->goldIncome)
  552. new CLabel(157, 58, FONT_TINY, CENTER, Colors::WHITE,
  553. boost::lexical_cast<std::string>(town.details->goldIncome));
  554. if(town.details->garrisonedHero) //garrisoned hero icon
  555. new CPicture("TOWNQKGH", 149, 76);
  556. if(town.details->customRes)//silo is built
  557. {
  558. if (town.tType->primaryRes == Res::WOOD_AND_ORE )// wood & ore
  559. {
  560. new CAnimImage("SMALRES", Res::WOOD, 0, 7, 75);
  561. new CAnimImage("SMALRES", Res::ORE , 0, 7, 88);
  562. }
  563. else
  564. new CAnimImage("SMALRES", town.tType->primaryRes, 0, 7, 81);
  565. }
  566. }
  567. }
  568. CTownTooltip::CTownTooltip(Point pos, const InfoAboutTown &town):
  569. CArmyTooltip(pos, town)
  570. {
  571. init(town);
  572. }
  573. CTownTooltip::CTownTooltip(Point pos, const CGTownInstance * town):
  574. CArmyTooltip(pos, InfoAboutTown(town, true))
  575. {
  576. init(InfoAboutTown(town, true));
  577. }
  578. void MoraleLuckBox::set(const IBonusBearer *node)
  579. {
  580. OBJ_CONSTRUCTION_CAPTURING_ALL;
  581. const int textId[] = {62, 88}; //eg %s \n\n\n {Current Luck Modifiers:}
  582. const int noneTxtId = 108; //Russian version uses same text for neutral morale\luck
  583. const int neutralDescr[] = {60, 86}; //eg {Neutral Morale} \n\n Neutral morale means your armies will neither be blessed with extra attacks or freeze in combat.
  584. const int componentType[] = {CComponent::luck, CComponent::morale};
  585. const int hoverTextBase[] = {7, 4};
  586. const Bonus::BonusType bonusType[] = {Bonus::LUCK, Bonus::MORALE};
  587. int (IBonusBearer::*getValue[])() const = {&IBonusBearer::LuckVal, &IBonusBearer::MoraleVal};
  588. int mrlt = -9;
  589. TModDescr mrl;
  590. if (node)
  591. {
  592. node->getModifiersWDescr(mrl, bonusType[morale]);
  593. bonusValue = (node->*getValue[morale])();
  594. }
  595. else
  596. bonusValue = 0;
  597. mrlt = (bonusValue>0)-(bonusValue<0); //signum: -1 - bad luck / morale, 0 - neutral, 1 - good
  598. hoverText = CGI->generaltexth->heroscrn[hoverTextBase[morale] - mrlt];
  599. baseType = componentType[morale];
  600. text = CGI->generaltexth->arraytxt[textId[morale]];
  601. boost::algorithm::replace_first(text,"%s",CGI->generaltexth->arraytxt[neutralDescr[morale]-mrlt]);
  602. if (!mrl.size())
  603. text += CGI->generaltexth->arraytxt[noneTxtId];
  604. else
  605. {
  606. //it's a creature window
  607. if ((morale && node->hasBonusOfType(Bonus::UNDEAD)) ||
  608. node->hasBonusOfType(Bonus::BLOCK_MORALE) || node->hasBonusOfType(Bonus::NON_LIVING))
  609. {
  610. text += CGI->generaltexth->arraytxt[113]; //unaffected by morale
  611. }
  612. else
  613. {
  614. for(auto & elem : mrl)
  615. {
  616. if (elem.first) //no bonuses with value 0
  617. text += "\n" + elem.second;
  618. }
  619. }
  620. }
  621. std::string imageName;
  622. if (small)
  623. imageName = morale ? "IMRL30": "ILCK30";
  624. else
  625. imageName = morale ? "IMRL42" : "ILCK42";
  626. delete image;
  627. image = new CAnimImage(imageName, bonusValue + 3);
  628. image->moveBy(Point(pos.w/2 - image->pos.w/2, pos.h/2 - image->pos.h/2));//center icon
  629. }
  630. MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r, bool Small):
  631. image(nullptr),
  632. morale(Morale),
  633. small(Small)
  634. {
  635. bonusValue = 0;
  636. pos = r + pos;
  637. }
  638. CCreaturePic::CCreaturePic(int x, int y, const CCreature *cre, bool Big, bool Animated)
  639. {
  640. OBJ_CONSTRUCTION_CAPTURING_ALL;
  641. pos.x+=x;
  642. pos.y+=y;
  643. TFaction faction = cre->faction;
  644. assert(CGI->townh->factions.size() > faction);
  645. if(Big)
  646. bg = new CPicture(CGI->townh->factions[faction]->creatureBg130);
  647. else
  648. bg = new CPicture(CGI->townh->factions[faction]->creatureBg120);
  649. bg->needRefresh = true;
  650. anim = new CCreatureAnim(0, 0, cre->animDefName, Rect());
  651. anim->clipRect(cre->isDoubleWide()?170:150, 155, bg->pos.w, bg->pos.h);
  652. anim->startPreview(cre->hasBonusOfType(Bonus::SIEGE_WEAPON));
  653. pos.w = bg->pos.w;
  654. pos.h = bg->pos.h;
  655. }