CTradeWindow.cpp 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507
  1. #include "StdInc.h"
  2. #include "CTradeWindow.h"
  3. #include "CGuiHandler.h"
  4. #include "CAnimation.h"
  5. #include "CCursorHandler.h"
  6. #include "../CAdvmapInterface.h"
  7. #include "../CGameInfo.h"
  8. #include "../CPlayerInterface.h"
  9. #include "../../CCallback.h"
  10. #include "../../lib/VCMI_Lib.h"
  11. #include "../../lib/CArtHandler.h"
  12. #include "../../lib/CCreatureHandler.h"
  13. #include "../../lib/CGeneralTextHandler.h"
  14. #include "../../lib/CHeroHandler.h"
  15. #include "../../lib/mapObjects/CGHeroInstance.h"
  16. /*
  17. * CTradeWindow.cpp, part of VCMI engine
  18. *
  19. * Authors: listed in file AUTHORS in main folder
  20. *
  21. * License: GNU General Public License v2.0 or later
  22. * Full text of license available in license.txt file, in main folder
  23. *
  24. */
  25. CTradeWindow::CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial):
  26. CIntObject(LCLICK | HOVER | RCLICK, pos),
  27. type(EType(-1)),// set to invalid, will be corrected in setType
  28. id(ID),
  29. serial(Serial),
  30. left(Left)
  31. {
  32. downSelection = false;
  33. hlp = nullptr;
  34. image = nullptr;
  35. setType(Type);
  36. }
  37. void CTradeWindow::CTradeableItem::setType(EType newType)
  38. {
  39. if (type != newType)
  40. {
  41. OBJ_CONSTRUCTION_CAPTURING_ALL;
  42. type = newType;
  43. delete image;
  44. if (getIndex() < 0)
  45. {
  46. image = new CAnimImage(getFilename(), 0);
  47. image->disable();
  48. }
  49. else
  50. image = new CAnimImage(getFilename(), getIndex());
  51. }
  52. }
  53. void CTradeWindow::CTradeableItem::setID(int newID)
  54. {
  55. if (id != newID)
  56. {
  57. id = newID;
  58. if (image)
  59. {
  60. int index = getIndex();
  61. if (index < 0)
  62. image->disable();
  63. else
  64. {
  65. image->enable();
  66. image->setFrame(index);
  67. }
  68. }
  69. }
  70. }
  71. std::string CTradeWindow::CTradeableItem::getFilename()
  72. {
  73. switch(type)
  74. {
  75. case RESOURCE:
  76. return "RESOURCE";
  77. case PLAYER:
  78. return "CREST58";
  79. case ARTIFACT_TYPE:
  80. case ARTIFACT_PLACEHOLDER:
  81. case ARTIFACT_INSTANCE:
  82. return "artifact";
  83. case CREATURE:
  84. return "TWCRPORT";
  85. default:
  86. return "";
  87. }
  88. }
  89. int CTradeWindow::CTradeableItem::getIndex()
  90. {
  91. if (id < 0)
  92. return -1;
  93. switch(type)
  94. {
  95. case RESOURCE:
  96. case PLAYER:
  97. return id;
  98. case ARTIFACT_TYPE:
  99. case ARTIFACT_INSTANCE:
  100. case ARTIFACT_PLACEHOLDER:
  101. return VLC->arth->artifacts[id]->iconIndex;
  102. case CREATURE:
  103. return VLC->creh->creatures[id]->iconIndex;
  104. default:
  105. return -1;
  106. }
  107. }
  108. void CTradeWindow::CTradeableItem::showAll(SDL_Surface * to)
  109. {
  110. Point posToBitmap;
  111. Point posToSubCenter;
  112. switch(type)
  113. {
  114. case RESOURCE:
  115. posToBitmap = Point(19,9);
  116. posToSubCenter = Point(36, 59);
  117. break;
  118. case CREATURE_PLACEHOLDER:
  119. case CREATURE:
  120. posToSubCenter = Point(29, 76);
  121. if(downSelection)
  122. posToSubCenter.y += 5;
  123. break;
  124. case PLAYER:
  125. posToSubCenter = Point(31, 76);
  126. break;
  127. case ARTIFACT_PLACEHOLDER:
  128. case ARTIFACT_INSTANCE:
  129. posToSubCenter = Point(19, 55);
  130. if(downSelection)
  131. posToSubCenter.y += 8;
  132. break;
  133. case ARTIFACT_TYPE:
  134. posToSubCenter = Point(19, 58);
  135. break;
  136. }
  137. if (image)
  138. {
  139. image->moveTo(pos.topLeft() + posToBitmap);
  140. CIntObject::showAll(to);
  141. }
  142. printAtMiddleLoc(subtitle, posToSubCenter, FONT_SMALL, Colors::WHITE, to);
  143. }
  144. void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
  145. {
  146. CTradeWindow *mw = dynamic_cast<CTradeWindow *>(parent);
  147. assert(mw);
  148. if(down)
  149. {
  150. if(type == ARTIFACT_PLACEHOLDER)
  151. {
  152. CAltarWindow *aw = static_cast<CAltarWindow *>(mw);
  153. if(const CArtifactInstance *movedArt = aw->arts->commonInfo->src.art)
  154. {
  155. aw->moveFromSlotToAltar(aw->arts->commonInfo->src.slotID, this, movedArt);
  156. }
  157. else if(const CArtifactInstance *art = getArtInstance())
  158. {
  159. aw->arts->commonInfo->src.AOH = aw->arts;
  160. aw->arts->commonInfo->src.art = art;
  161. aw->arts->commonInfo->src.slotID = aw->hero->getArtPos(art);
  162. aw->arts->markPossibleSlots(art);
  163. //aw->arts->commonInfo->dst.AOH = aw->arts;
  164. CCS->curh->dragAndDropCursor(new CAnimImage("artifact", art->artType->iconIndex));
  165. aw->arts->artifactsOnAltar.erase(art);
  166. setID(-1);
  167. subtitle = "";
  168. aw->deal->block(!aw->arts->artifactsOnAltar.size());
  169. }
  170. aw->calcTotalExp();
  171. return;
  172. }
  173. if(left)
  174. {
  175. if(mw->hLeft != this)
  176. mw->hLeft = this;
  177. else
  178. return;
  179. }
  180. else
  181. {
  182. if(mw->hRight != this)
  183. mw->hRight = this;
  184. else
  185. return;
  186. }
  187. mw->selectionChanged(left);
  188. }
  189. }
  190. void CTradeWindow::CTradeableItem::showAllAt(const Point &dstPos, const std::string &customSub, SDL_Surface * to)
  191. {
  192. Rect oldPos = pos;
  193. std::string oldSub = subtitle;
  194. downSelection = true;
  195. moveTo(dstPos);
  196. subtitle = customSub;
  197. showAll(to);
  198. downSelection = false;
  199. moveTo(oldPos.topLeft());
  200. subtitle = oldSub;
  201. }
  202. void CTradeWindow::CTradeableItem::hover(bool on)
  203. {
  204. if(!on)
  205. {
  206. GH.statusbar->clear();
  207. return;
  208. }
  209. switch(type)
  210. {
  211. case CREATURE:
  212. case CREATURE_PLACEHOLDER:
  213. GH.statusbar->setText(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl));
  214. break;
  215. case ARTIFACT_PLACEHOLDER:
  216. if(id < 0)
  217. GH.statusbar->setText(CGI->generaltexth->zelp[582].first);
  218. else
  219. GH.statusbar->setText(CGI->arth->artifacts[id]->Name());
  220. break;
  221. }
  222. }
  223. void CTradeWindow::CTradeableItem::clickRight(tribool down, bool previousState)
  224. {
  225. if(down)
  226. {
  227. switch(type)
  228. {
  229. case CREATURE:
  230. case CREATURE_PLACEHOLDER:
  231. //GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl));
  232. break;
  233. case ARTIFACT_TYPE:
  234. case ARTIFACT_PLACEHOLDER:
  235. if(id >= 0)
  236. adventureInt->handleRightClick(CGI->arth->artifacts[id]->Description(), down);
  237. break;
  238. }
  239. }
  240. }
  241. std::string CTradeWindow::CTradeableItem::getName(int number /*= -1*/) const
  242. {
  243. switch(type)
  244. {
  245. case PLAYER:
  246. return CGI->generaltexth->capColors[id];
  247. case RESOURCE:
  248. return CGI->generaltexth->restypes[id];
  249. case CREATURE:
  250. if(number == 1)
  251. return CGI->creh->creatures[id]->nameSing;
  252. else
  253. return CGI->creh->creatures[id]->namePl;
  254. case ARTIFACT_TYPE:
  255. case ARTIFACT_INSTANCE:
  256. return CGI->arth->artifacts[id]->Name();
  257. }
  258. assert(0);
  259. return "";
  260. }
  261. const CArtifactInstance * CTradeWindow::CTradeableItem::getArtInstance() const
  262. {
  263. switch(type)
  264. {
  265. case ARTIFACT_PLACEHOLDER:
  266. case ARTIFACT_INSTANCE:
  267. return (const CArtifactInstance *)hlp;
  268. default:
  269. return nullptr;
  270. }
  271. }
  272. void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art)
  273. {
  274. assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE);
  275. hlp = art;
  276. if(art)
  277. setID(art->artType->id);
  278. else
  279. setID(-1);
  280. }
  281. CTradeWindow::CTradeWindow(std::string bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode::EMarketMode Mode):
  282. CWindowObject(PLAYER_COLORED, bgName),
  283. market(Market),
  284. hero(Hero),
  285. arts(nullptr),
  286. hLeft(nullptr),
  287. hRight(nullptr),
  288. readyToTrade(false)
  289. {
  290. type |= BLOCK_ADV_HOTKEYS;
  291. mode = Mode;
  292. initTypes();
  293. }
  294. void CTradeWindow::initTypes()
  295. {
  296. switch(mode)
  297. {
  298. case EMarketMode::RESOURCE_RESOURCE:
  299. itemsType[1] = RESOURCE;
  300. itemsType[0] = RESOURCE;
  301. break;
  302. case EMarketMode::RESOURCE_PLAYER:
  303. itemsType[1] = RESOURCE;
  304. itemsType[0] = PLAYER;
  305. break;
  306. case EMarketMode::CREATURE_RESOURCE:
  307. itemsType[1] = CREATURE;
  308. itemsType[0] = RESOURCE;
  309. break;
  310. case EMarketMode::RESOURCE_ARTIFACT:
  311. itemsType[1] = RESOURCE;
  312. itemsType[0] = ARTIFACT_TYPE;
  313. break;
  314. case EMarketMode::ARTIFACT_RESOURCE:
  315. itemsType[1] = ARTIFACT_INSTANCE;
  316. itemsType[0] = RESOURCE;
  317. break;
  318. case EMarketMode::CREATURE_EXP:
  319. itemsType[1] = CREATURE;
  320. itemsType[0] = CREATURE_PLACEHOLDER;
  321. break;
  322. case EMarketMode::ARTIFACT_EXP:
  323. itemsType[1] = ARTIFACT_TYPE;
  324. itemsType[0] = ARTIFACT_PLACEHOLDER;
  325. break;
  326. }
  327. }
  328. void CTradeWindow::initItems(bool Left)
  329. {
  330. if(Left && (itemsType[1] == ARTIFACT_TYPE || itemsType[1] == ARTIFACT_INSTANCE))
  331. {
  332. int xOffset = 0, yOffset = 0;
  333. if(mode == EMarketMode::ARTIFACT_RESOURCE)
  334. {
  335. xOffset = -361;
  336. yOffset = +46;
  337. auto hlp = new CTradeableItem(Point(137, 469), itemsType[Left], -1, 1, 0);
  338. hlp->recActions &= ~(UPDATE | SHOWALL);
  339. items[Left].push_back(hlp);
  340. }
  341. else //ARTIFACT_EXP
  342. {
  343. xOffset = -363;
  344. yOffset = -12;
  345. }
  346. BLOCK_CAPTURING;
  347. arts = new CArtifactsOfHero(Point(pos.x+xOffset, pos.y+yOffset));
  348. arts->commonInfo = new CArtifactsOfHero::SCommonPart;
  349. arts->commonInfo->participants.insert(arts);
  350. arts->recActions = 255;
  351. arts->setHero(hero);
  352. arts->allowedAssembling = false;
  353. addChild(arts);
  354. artSets.push_back(arts);
  355. if(mode == EMarketMode::ARTIFACT_RESOURCE)
  356. arts->highlightModeCallback = boost::bind(&CTradeWindow::artifactSelected, this, _1);
  357. return;
  358. }
  359. std::vector<int> *ids = getItemsIds(Left);
  360. std::vector<Rect> pos;
  361. int amount = -1;
  362. getPositionsFor(pos, Left, itemsType[Left]);
  363. if(Left || !ids)
  364. amount = 7;
  365. else
  366. amount = ids->size();
  367. if(ids)
  368. vstd::amin(amount, ids->size());
  369. for(int j=0; j<amount; j++)
  370. {
  371. int id = (ids && ids->size()>j) ? (*ids)[j] : j;
  372. if(id < 0 && mode != EMarketMode::ARTIFACT_EXP) //when sacrificing artifacts we need to prepare empty slots
  373. continue;
  374. auto hlp = new CTradeableItem(pos[j].topLeft(), itemsType[Left], id, Left, j);
  375. hlp->pos = pos[j] + this->pos.topLeft();
  376. items[Left].push_back(hlp);
  377. }
  378. initSubs(Left);
  379. }
  380. std::vector<int> *CTradeWindow::getItemsIds(bool Left)
  381. {
  382. std::vector<int> *ids = nullptr;
  383. if(mode == EMarketMode::ARTIFACT_EXP)
  384. return new std::vector<int>(22, -1);
  385. if(Left)
  386. {
  387. switch(itemsType[1])
  388. {
  389. case CREATURE:
  390. ids = new std::vector<int>;
  391. for(int i = 0; i < 7; i++)
  392. {
  393. if(const CCreature *c = hero->getCreature(SlotID(i)))
  394. ids->push_back(c->idNumber);
  395. else
  396. ids->push_back(-1);
  397. }
  398. break;
  399. }
  400. }
  401. else
  402. {
  403. switch(itemsType[0])
  404. {
  405. case PLAYER:
  406. ids = new std::vector<int>;
  407. for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
  408. if(PlayerColor(i) != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(PlayerColor(i)) == EPlayerStatus::INGAME)
  409. ids->push_back(i);
  410. break;
  411. case ARTIFACT_TYPE:
  412. ids = new std::vector<int>(market->availableItemsIds(mode));
  413. break;
  414. }
  415. }
  416. return ids;
  417. }
  418. void CTradeWindow::getPositionsFor(std::vector<Rect> &poss, bool Left, EType type) const
  419. {
  420. using namespace boost::assign;
  421. if(mode == EMarketMode::ARTIFACT_EXP && !Left)
  422. {
  423. //22 boxes, 5 in row, last row: two boxes centered
  424. int h, w, x, y, dx, dy;
  425. h = w = 44;
  426. x = 317;
  427. y = 53;
  428. dx = 54;
  429. dy = 70;
  430. for (int i = 0; i < 4 ; i++)
  431. for (int j = 0; j < 5 ; j++)
  432. poss += Rect(x + dx*j, y + dy*i, w, h);
  433. poss += Rect(x + dx*1.5, y + dy*4, w, h);
  434. poss += Rect(x + dx*2.5, y + dy*4, w, h);
  435. }
  436. else
  437. {
  438. //seven boxes:
  439. // X X X
  440. // X X X
  441. // X
  442. int h, w, x, y, dx, dy;
  443. int leftToRightOffset;
  444. getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset);
  445. poss += genRect(h, w, x, y), genRect(h, w, x + dx, y), genRect(h, w, x + 2*dx, y),
  446. genRect(h, w, x, y + dy), genRect(h, w, x + dx, y + dy), genRect(h, w, x + 2*dx, y + dy),
  447. genRect(h, w, x + dx, y + 2*dy);
  448. if(!Left)
  449. {
  450. for(Rect &r : poss)
  451. r.x += leftToRightOffset;
  452. }
  453. }
  454. }
  455. void CTradeWindow::initSubs(bool Left)
  456. {
  457. for(CTradeableItem *t : items[Left])
  458. {
  459. if(Left)
  460. {
  461. switch(itemsType[1])
  462. {
  463. case CREATURE:
  464. t->subtitle = boost::lexical_cast<std::string>(hero->getStackCount(SlotID(t->serial)));
  465. break;
  466. case RESOURCE:
  467. t->subtitle = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(t->serial)));
  468. break;
  469. }
  470. }
  471. else //right side
  472. {
  473. if(itemsType[0] == PLAYER)
  474. {
  475. t->subtitle = CGI->generaltexth->capColors[t->id];
  476. }
  477. else if(hLeft)//artifact, creature
  478. {
  479. int h1, h2; //hlp variables for getting offer
  480. market->getOffer(hLeft->id, t->id, h1, h2, mode);
  481. if(t->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources
  482. {
  483. std::ostringstream oss;
  484. oss << h2;
  485. if(h1!=1)
  486. oss << "/" << h1;
  487. t->subtitle = oss.str();
  488. }
  489. else
  490. t->subtitle = CGI->generaltexth->allTexts[164]; // n/a
  491. }
  492. else
  493. t->subtitle = "";
  494. }
  495. }
  496. }
  497. void CTradeWindow::showAll(SDL_Surface * to)
  498. {
  499. CWindowObject::showAll(to);
  500. if(hRight)
  501. CSDL_Ext::drawBorder(to,hRight->pos.x-1,hRight->pos.y-1,hRight->pos.w+2,hRight->pos.h+2,int3(255,231,148));
  502. if(hLeft && hLeft->type != ARTIFACT_INSTANCE)
  503. CSDL_Ext::drawBorder(to,hLeft->pos.x-1,hLeft->pos.y-1,hLeft->pos.w+2,hLeft->pos.h+2,int3(255,231,148));
  504. if(readyToTrade)
  505. {
  506. hLeft->showAllAt(pos.topLeft() + selectionOffset(true), selectionSubtitle(true), to);
  507. hRight->showAllAt(pos.topLeft() + selectionOffset(false), selectionSubtitle(false), to);
  508. }
  509. }
  510. void CTradeWindow::removeItems(const std::set<CTradeableItem *> &toRemove)
  511. {
  512. for(CTradeableItem *t : toRemove)
  513. removeItem(t);
  514. }
  515. void CTradeWindow::removeItem(CTradeableItem * t)
  516. {
  517. items[t->left] -= t;
  518. delete t;
  519. if(hRight == t)
  520. {
  521. hRight = nullptr;
  522. selectionChanged(false);
  523. }
  524. }
  525. void CTradeWindow::getEmptySlots(std::set<CTradeableItem *> &toRemove)
  526. {
  527. for(CTradeableItem *t : items[1])
  528. if(!hero->getStackCount(SlotID(t->serial)))
  529. toRemove.insert(t);
  530. }
  531. void CTradeWindow::setMode(EMarketMode::EMarketMode Mode)
  532. {
  533. const IMarket *m = market;
  534. const CGHeroInstance *h = hero;
  535. CTradeWindow *nwindow = nullptr;
  536. GH.popIntTotally(this);
  537. switch(Mode)
  538. {
  539. case EMarketMode::CREATURE_EXP:
  540. case EMarketMode::ARTIFACT_EXP:
  541. nwindow = new CAltarWindow(m, h, Mode);
  542. break;
  543. default:
  544. nwindow = new CMarketplaceWindow(m, h, Mode);
  545. break;
  546. }
  547. GH.pushInt(nwindow);
  548. }
  549. void CTradeWindow::artifactSelected(CArtPlace *slot)
  550. {
  551. assert(mode == EMarketMode::ARTIFACT_RESOURCE);
  552. items[1][0]->setArtInstance(slot->ourArt);
  553. if(slot->ourArt)
  554. hLeft = items[1][0];
  555. else
  556. hLeft = nullptr;
  557. selectionChanged(true);
  558. }
  559. std::string CMarketplaceWindow::getBackgroundForMode(EMarketMode::EMarketMode mode)
  560. {
  561. switch(mode)
  562. {
  563. case EMarketMode::RESOURCE_RESOURCE:
  564. return "TPMRKRES.bmp";
  565. case EMarketMode::RESOURCE_PLAYER:
  566. return "TPMRKPTS.bmp";
  567. case EMarketMode::CREATURE_RESOURCE:
  568. return "TPMRKCRS.bmp";
  569. case EMarketMode::RESOURCE_ARTIFACT:
  570. return "TPMRKABS.bmp";
  571. case EMarketMode::ARTIFACT_RESOURCE:
  572. return "TPMRKASS.bmp";
  573. }
  574. assert(0);
  575. return "";
  576. }
  577. CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstance *Hero, EMarketMode::EMarketMode Mode)
  578. : CTradeWindow(getBackgroundForMode(Mode), Market, Hero, Mode)
  579. {
  580. OBJ_CONSTRUCTION_CAPTURING_ALL;
  581. madeTransaction = false;
  582. bool sliderNeeded = true;
  583. new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
  584. std::string title;
  585. if (market->o->ID == Obj::TOWN)
  586. {
  587. switch (mode)
  588. {
  589. break; case EMarketMode::CREATURE_RESOURCE:
  590. title = CGI->townh->factions[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->Name();
  591. break; case EMarketMode::RESOURCE_ARTIFACT:
  592. title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
  593. sliderNeeded = false;
  594. break; case EMarketMode::ARTIFACT_RESOURCE:
  595. title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
  596. sliderNeeded = false;
  597. break; default:
  598. title = CGI->generaltexth->allTexts[158];
  599. }
  600. }
  601. else
  602. {
  603. switch (market->o->ID)
  604. {
  605. break; case Obj::BLACK_MARKET: title = CGI->generaltexth->allTexts[349];
  606. break; case Obj::TRADING_POST: title = CGI->generaltexth->allTexts[159];
  607. break; case Obj::TRADING_POST_SNOW: title = CGI->generaltexth->allTexts[159];
  608. break; default: title = market->o->getObjectName();
  609. }
  610. }
  611. new CLabel(300, 27, FONT_BIG, CENTER, Colors::YELLOW, title);
  612. initItems(false);
  613. initItems(true);
  614. ok = new CAdventureMapButton(CGI->generaltexth->zelp[600],boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN);
  615. ok->assignedKeys.insert(SDLK_ESCAPE);
  616. deal = new CAdventureMapButton(CGI->generaltexth->zelp[595],boost::bind(&CMarketplaceWindow::makeDeal,this),307,520,"TPMRKB.DEF");
  617. deal->block(true);
  618. if(sliderNeeded)
  619. {
  620. slider = new CSlider(231,490,137,nullptr,0,0);
  621. slider->moved = boost::bind(&CMarketplaceWindow::sliderMoved,this,_1);
  622. max = new CAdventureMapButton(CGI->generaltexth->zelp[596],boost::bind(&CMarketplaceWindow::setMax,this),229,520,"IRCBTNS.DEF");
  623. max->block(true);
  624. }
  625. else
  626. {
  627. slider = nullptr;
  628. max = nullptr;
  629. deal->moveBy(Point(-30, 0));
  630. }
  631. Rect traderTextRect;
  632. //left side
  633. switch(Mode)
  634. {
  635. case EMarketMode::RESOURCE_RESOURCE:
  636. case EMarketMode::RESOURCE_PLAYER:
  637. case EMarketMode::RESOURCE_ARTIFACT:
  638. new CLabel(154, 148, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]);
  639. break;
  640. case EMarketMode::CREATURE_RESOURCE:
  641. //%s's Creatures
  642. new CLabel(152, 102, FONT_SMALL, CENTER, Colors::WHITE,
  643. boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
  644. break;
  645. case EMarketMode::ARTIFACT_RESOURCE:
  646. //%s's Artifacts
  647. new CLabel(152, 102, FONT_SMALL, CENTER, Colors::WHITE,
  648. boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
  649. break;
  650. }
  651. //right side
  652. switch(Mode)
  653. {
  654. case EMarketMode::RESOURCE_RESOURCE:
  655. case EMarketMode::CREATURE_RESOURCE:
  656. case EMarketMode::RESOURCE_ARTIFACT:
  657. case EMarketMode::ARTIFACT_RESOURCE:
  658. new CLabel(445, 148, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[168]);
  659. traderTextRect = Rect(316, 48, 260, 75);
  660. break;
  661. case EMarketMode::RESOURCE_PLAYER:
  662. new CLabel(445, 55, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[169]);
  663. traderTextRect = Rect(28, 48, 260, 75);
  664. break;
  665. }
  666. traderText = new CTextBox("", traderTextRect, 0, FONT_SMALL, CENTER);
  667. int specialOffset = mode == EMarketMode::ARTIFACT_RESOURCE ? 35 : 0; //in selling artifacts mode we need to move res-res and art-res buttons down
  668. if(printButtonFor(EMarketMode::RESOURCE_PLAYER))
  669. new CAdventureMapButton(CGI->generaltexth->zelp[612],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_PLAYER), 18, 520,"TPMRKBU1.DEF");
  670. if(printButtonFor(EMarketMode::RESOURCE_RESOURCE))
  671. new CAdventureMapButton(CGI->generaltexth->zelp[605],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_RESOURCE), 516, 450 + specialOffset,"TPMRKBU5.DEF");
  672. if(printButtonFor(EMarketMode::CREATURE_RESOURCE))
  673. new CAdventureMapButton(CGI->generaltexth->zelp[599],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::CREATURE_RESOURCE), 516, 485,"TPMRKBU4.DEF"); //was y=450, changed to not overlap res-res in some conditions
  674. if(printButtonFor(EMarketMode::RESOURCE_ARTIFACT))
  675. new CAdventureMapButton(CGI->generaltexth->zelp[598],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_ARTIFACT), 18, 450 + specialOffset,"TPMRKBU2.DEF");
  676. if(printButtonFor(EMarketMode::ARTIFACT_RESOURCE))
  677. new CAdventureMapButton(CGI->generaltexth->zelp[613],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::ARTIFACT_RESOURCE), 18, 485,"TPMRKBU3.DEF"); //was y=450, changed to not overlap res-art in some conditions
  678. updateTraderText();
  679. }
  680. CMarketplaceWindow::~CMarketplaceWindow()
  681. {
  682. hLeft = hRight = nullptr;
  683. for(auto & elem : items[1])
  684. delete elem;
  685. for(auto & elem : items[0])
  686. delete elem;
  687. items[1].clear();
  688. items[0].clear();
  689. }
  690. void CMarketplaceWindow::setMax()
  691. {
  692. slider->moveToMax();
  693. }
  694. void CMarketplaceWindow::makeDeal()
  695. {
  696. int sliderValue = 0;
  697. if(slider)
  698. sliderValue = slider->value;
  699. else
  700. sliderValue = !deal->isBlocked(); //should always be 1
  701. if(!sliderValue)
  702. return;
  703. int leftIdToSend = -1;
  704. switch (mode)
  705. {
  706. case EMarketMode::CREATURE_RESOURCE:
  707. leftIdToSend = hLeft->serial;
  708. break;
  709. case EMarketMode::ARTIFACT_RESOURCE:
  710. leftIdToSend = hLeft->getArtInstance()->id.getNum();
  711. break;
  712. default:
  713. leftIdToSend = hLeft->id;
  714. break;
  715. }
  716. if(slider)
  717. {
  718. LOCPLINT->cb->trade(market->o, mode, leftIdToSend, hRight->id, slider->value*r1, hero);
  719. slider->moveTo(0);
  720. }
  721. else
  722. {
  723. LOCPLINT->cb->trade(market->o, mode, leftIdToSend, hRight->id, r2, hero);
  724. }
  725. madeTransaction = true;
  726. hLeft = nullptr;
  727. hRight = nullptr;
  728. selectionChanged(true);
  729. }
  730. void CMarketplaceWindow::sliderMoved( int to )
  731. {
  732. redraw();
  733. }
  734. void CMarketplaceWindow::selectionChanged(bool side)
  735. {
  736. readyToTrade = hLeft && hRight;
  737. if(mode == EMarketMode::RESOURCE_RESOURCE)
  738. readyToTrade = readyToTrade && (hLeft->id != hRight->id); //for resource trade, two DIFFERENT resources must be selected
  739. if(mode == EMarketMode::ARTIFACT_RESOURCE && !hLeft)
  740. arts->unmarkSlots(false);
  741. if(readyToTrade)
  742. {
  743. int soldItemId = hLeft->id;
  744. market->getOffer(soldItemId, hRight->id, r1, r2, mode);
  745. if(slider)
  746. {
  747. int newAmount = -1;
  748. if(itemsType[1] == RESOURCE)
  749. newAmount = LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId));
  750. else if(itemsType[1] == CREATURE)
  751. newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->Slots().size() == 1 && hero->needsLastStack());
  752. else
  753. assert(0);
  754. slider->setAmount(newAmount / r1);
  755. slider->moveTo(0);
  756. max->block(false);
  757. deal->block(false);
  758. }
  759. else if(itemsType[1] == RESOURCE) //buying -> check if we can afford transaction
  760. {
  761. deal->block(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId)) < r1);
  762. }
  763. else
  764. deal->block(false);
  765. }
  766. else
  767. {
  768. if(slider)
  769. {
  770. max->block(true);
  771. slider->setAmount(0);
  772. slider->moveTo(0);
  773. }
  774. deal->block(true);
  775. }
  776. if(side && itemsType[0] != PLAYER) //items[1] selection changed, recalculate offers
  777. initSubs(false);
  778. updateTraderText();
  779. redraw();
  780. }
  781. bool CMarketplaceWindow::printButtonFor(EMarketMode::EMarketMode M) const
  782. {
  783. return market->allowsTrade(M) && M != mode && (hero || ( M != EMarketMode::CREATURE_RESOURCE && M != EMarketMode::RESOURCE_ARTIFACT && M != EMarketMode::ARTIFACT_RESOURCE ));
  784. }
  785. void CMarketplaceWindow::garrisonChanged()
  786. {
  787. if(mode != EMarketMode::CREATURE_RESOURCE)
  788. return;
  789. std::set<CTradeableItem *> toRemove;
  790. getEmptySlots(toRemove);
  791. removeItems(toRemove);
  792. initSubs(true);
  793. }
  794. void CMarketplaceWindow::artifactsChanged(bool Left)
  795. {
  796. assert(!Left);
  797. if(mode != EMarketMode::RESOURCE_ARTIFACT)
  798. return;
  799. std::vector<int> available = market->availableItemsIds(mode);
  800. std::set<CTradeableItem *> toRemove;
  801. for(CTradeableItem *t : items[0])
  802. if(!vstd::contains(available, t->id))
  803. toRemove.insert(t);
  804. removeItems(toRemove);
  805. redraw();
  806. }
  807. std::string CMarketplaceWindow::selectionSubtitle(bool Left) const
  808. {
  809. if(Left)
  810. {
  811. switch(itemsType[1])
  812. {
  813. case RESOURCE:
  814. case CREATURE:
  815. {
  816. int val = slider
  817. ? slider->value * r1
  818. : (((deal->isBlocked())) ? 0 : r1);
  819. return boost::lexical_cast<std::string>(val);
  820. }
  821. case ARTIFACT_INSTANCE:
  822. return ((deal->isBlocked()) ? "0" : "1");
  823. }
  824. }
  825. else
  826. {
  827. switch(itemsType[0])
  828. {
  829. case RESOURCE:
  830. if(slider)
  831. return boost::lexical_cast<std::string>( slider->value * r2 );
  832. else
  833. return boost::lexical_cast<std::string>(r2);
  834. case ARTIFACT_TYPE:
  835. return ((deal->isBlocked()) ? "0" : "1");
  836. case PLAYER:
  837. return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
  838. }
  839. }
  840. return "???";
  841. }
  842. Point CMarketplaceWindow::selectionOffset(bool Left) const
  843. {
  844. if(Left)
  845. {
  846. switch(itemsType[1])
  847. {
  848. case RESOURCE:
  849. return Point(122, 446);
  850. case CREATURE:
  851. return Point(128, 450);
  852. case ARTIFACT_INSTANCE:
  853. return Point(134, 466);
  854. }
  855. }
  856. else
  857. {
  858. switch(itemsType[0])
  859. {
  860. case RESOURCE:
  861. if(mode == EMarketMode::ARTIFACT_RESOURCE)
  862. return Point(410, 469);
  863. else
  864. return Point(410, 446);
  865. case ARTIFACT_TYPE:
  866. return Point(425, 447);
  867. case PLAYER:
  868. return Point(417, 451);
  869. }
  870. }
  871. assert(0);
  872. return Point(0,0);
  873. }
  874. void CMarketplaceWindow::resourceChanged(int type, int val)
  875. {
  876. initSubs(true);
  877. }
  878. void CMarketplaceWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const
  879. {
  880. switch(type)
  881. {
  882. case RESOURCE:
  883. dx = 82;
  884. dy = 79;
  885. x = 39;
  886. y = 180;
  887. h = 66;
  888. w = 74;
  889. break;
  890. case PLAYER:
  891. dx = 83;
  892. dy = 118;
  893. h = 64;
  894. w = 58;
  895. x = 44;
  896. y = 83;
  897. assert(Right);
  898. break;
  899. case CREATURE://45,123
  900. x = 45;
  901. y = 123;
  902. w = 58;
  903. h = 64;
  904. dx = 83;
  905. dy = 98;
  906. assert(!Right);
  907. break;
  908. case ARTIFACT_TYPE://45,123
  909. x = 340-289;
  910. y = 180;
  911. w = 44;
  912. h = 44;
  913. dx = 83;
  914. dy = 79;
  915. break;
  916. }
  917. leftToRightOffset = 289;
  918. }
  919. void CMarketplaceWindow::updateTraderText()
  920. {
  921. if(readyToTrade)
  922. {
  923. if(mode == EMarketMode::RESOURCE_PLAYER)
  924. {
  925. //I can give %s to the %s player.
  926. traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[165]) % hLeft->getName() % hRight->getName()));
  927. }
  928. else if(mode == EMarketMode::RESOURCE_ARTIFACT)
  929. {
  930. //I can offer you the %s for %d %s of %s.
  931. traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[267]) % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
  932. }
  933. else if(mode == EMarketMode::RESOURCE_RESOURCE)
  934. {
  935. //I can offer you %d %s of %s for %d %s of %s.
  936. traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[157]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
  937. }
  938. else if(mode == EMarketMode::CREATURE_RESOURCE)
  939. {
  940. //I can offer you %d %s of %s for %d %s.
  941. traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[269]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % hLeft->getName(r1)));
  942. }
  943. else if(mode == EMarketMode::ARTIFACT_RESOURCE)
  944. {
  945. //I can offer you %d %s of %s for your %s.
  946. traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[268]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % hLeft->getName(r1)));
  947. }
  948. return;
  949. }
  950. int gnrtxtnr = -1;
  951. if(madeTransaction)
  952. {
  953. if(mode == EMarketMode::RESOURCE_PLAYER)
  954. gnrtxtnr = 166; //Are there any other resources you'd like to give away?
  955. else
  956. gnrtxtnr = 162; //You have received quite a bargain. I expect to make no profit on the deal. Can I interest you in any of my other wares?
  957. }
  958. else
  959. {
  960. if(mode == EMarketMode::RESOURCE_PLAYER)
  961. gnrtxtnr = 167; //If you'd like to give any of your resources to another player, click on the item you wish to give and to whom.
  962. else
  963. gnrtxtnr = 163; //Please inspect our fine wares. If you feel like offering a trade, click on the items you wish to trade with and for.
  964. }
  965. traderText->setText(CGI->generaltexth->allTexts[gnrtxtnr]);
  966. }
  967. CAltarWindow::CAltarWindow(const IMarket *Market, const CGHeroInstance *Hero /*= nullptr*/, EMarketMode::EMarketMode Mode)
  968. :CTradeWindow((Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, Mode)
  969. {
  970. OBJ_CONSTRUCTION_CAPTURING_ALL;
  971. if(Mode == EMarketMode::CREATURE_EXP)
  972. {
  973. //%s's Creatures
  974. new CLabel(155, 30, FONT_SMALL, CENTER, Colors::YELLOW,
  975. boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
  976. //Altar of Sacrifice
  977. new CLabel(450, 30, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479]);
  978. //To sacrifice creatures, move them from your army on to the Altar and click Sacrifice
  979. new CTextBox(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, CENTER, Colors::YELLOW);
  980. slider = new CSlider(231,481,137,nullptr,0,0);
  981. slider->moved = boost::bind(&CAltarWindow::sliderMoved,this,_1);
  982. max = new CAdventureMapButton(CGI->generaltexth->zelp[578],boost::bind(&CSlider::moveToMax, slider),147,520,"IRCBTNS.DEF");
  983. sacrificedUnits.resize(GameConstants::ARMY_SIZE, 0);
  984. sacrificeAll = new CAdventureMapButton(CGI->generaltexth->zelp[579],boost::bind(&CAltarWindow::SacrificeAll,this),393,520,"ALTARMY.DEF");
  985. sacrificeBackpack = nullptr;
  986. initItems(true);
  987. mimicCres();
  988. artIcon = nullptr;
  989. }
  990. else
  991. {
  992. //Sacrifice artifacts for experience
  993. new CLabel(450, 34, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]);
  994. //%s's Creatures
  995. new CLabel(302, 423, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]);
  996. sacrificeAll = new CAdventureMapButton(CGI->generaltexth->zelp[571], boost::bind(&CAltarWindow::SacrificeAll,this),393,520,"ALTFILL.DEF");
  997. sacrificeAll->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
  998. sacrificeBackpack = new CAdventureMapButton(CGI->generaltexth->zelp[570],boost::bind(&CAltarWindow::SacrificeBackpack,this),147,520,"ALTEMBK.DEF");
  999. sacrificeBackpack->block(hero->artifactsInBackpack.empty());
  1000. slider = nullptr;
  1001. max = nullptr;
  1002. initItems(true);
  1003. initItems(false);
  1004. artIcon = new CAnimImage("ARTIFACT", 0, 0, 281, 442);
  1005. artIcon->disable();
  1006. }
  1007. //Experience needed to reach next level
  1008. new CTextBox(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, CENTER, Colors::YELLOW);
  1009. //Total experience on the Altar
  1010. new CTextBox(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, CENTER, Colors::YELLOW);
  1011. new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
  1012. ok = new CAdventureMapButton(CGI->generaltexth->zelp[568],boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN);
  1013. ok->assignedKeys.insert(SDLK_ESCAPE);
  1014. deal = new CAdventureMapButton(CGI->generaltexth->zelp[585],boost::bind(&CAltarWindow::makeDeal,this),269,520,"ALTSACR.DEF");
  1015. if(Hero->getAlignment() != ::EAlignment::EVIL && Mode == EMarketMode::CREATURE_EXP)
  1016. new CAdventureMapButton(CGI->generaltexth->zelp[580], boost::bind(&CTradeWindow::setMode,this, EMarketMode::ARTIFACT_EXP), 516, 421, "ALTART.DEF");
  1017. if(Hero->getAlignment() != ::EAlignment::GOOD && Mode == EMarketMode::ARTIFACT_EXP)
  1018. new CAdventureMapButton(CGI->generaltexth->zelp[572], boost::bind(&CTradeWindow::setMode,this, EMarketMode::CREATURE_EXP), 516, 421, "ALTSACC.DEF");
  1019. expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
  1020. getExpValues();
  1021. expToLevel = new CLabel(73, 475, FONT_SMALL, CENTER);
  1022. expOnAltar = new CLabel(73, 543, FONT_SMALL, CENTER);
  1023. setExpToLevel();
  1024. calcTotalExp();
  1025. blockTrade();
  1026. }
  1027. CAltarWindow::~CAltarWindow()
  1028. {
  1029. }
  1030. void CAltarWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const
  1031. {
  1032. leftToRightOffset = 289;
  1033. x = 45;
  1034. y = 110;
  1035. w = 58;
  1036. h = 64;
  1037. dx = 83;
  1038. dy = 98;
  1039. }
  1040. void CAltarWindow::sliderMoved(int to)
  1041. {
  1042. sacrificedUnits[hLeft->serial] = to;
  1043. updateRight(hRight);
  1044. deal->block(!to);
  1045. calcTotalExp();
  1046. redraw();
  1047. }
  1048. void CAltarWindow::makeDeal()
  1049. {
  1050. if(mode == EMarketMode::CREATURE_EXP)
  1051. {
  1052. blockTrade();
  1053. slider->value = 0;
  1054. std::vector<int> toSacrifice = sacrificedUnits;
  1055. for (int i = 0; i < toSacrifice.size(); i++)
  1056. {
  1057. if(toSacrifice[i])
  1058. LOCPLINT->cb->trade(market->o, mode, i, 0, toSacrifice[i], hero);
  1059. }
  1060. for(int& val : sacrificedUnits)
  1061. val = 0;
  1062. for(CTradeableItem *t : items[0])
  1063. {
  1064. t->setType(CREATURE_PLACEHOLDER);
  1065. t->subtitle = "";
  1066. }
  1067. }
  1068. else
  1069. {
  1070. for(const CArtifactInstance *art : arts->artifactsOnAltar) //sacrifice each artifact on the list
  1071. {
  1072. LOCPLINT->cb->trade(market->o, mode, hero->getArtPos(art), -1, 1, hero);
  1073. }
  1074. arts->artifactsOnAltar.clear();
  1075. for(CTradeableItem *t : items[0])
  1076. {
  1077. t->setID(-1);
  1078. t->subtitle = "";
  1079. }
  1080. arts->commonInfo->reset();
  1081. //arts->scrollBackpack(0);
  1082. deal->block(true);
  1083. }
  1084. calcTotalExp();
  1085. }
  1086. void CAltarWindow::SacrificeAll()
  1087. {
  1088. if(mode == EMarketMode::CREATURE_EXP)
  1089. {
  1090. bool movedAnything = false;
  1091. for(CTradeableItem *t : items[1])
  1092. sacrificedUnits[t->serial] = hero->getStackCount(SlotID(t->serial));
  1093. sacrificedUnits[items[1].front()->serial]--;
  1094. for(CTradeableItem *t : items[0])
  1095. {
  1096. updateRight(t);
  1097. if(t->type == CREATURE)
  1098. movedAnything = true;
  1099. }
  1100. deal->block(!movedAnything);
  1101. calcTotalExp();
  1102. }
  1103. else
  1104. {
  1105. for(auto i = hero->artifactsWorn.cbegin(); i != hero->artifactsWorn.cend(); i++)
  1106. {
  1107. if(i->second.artifact->artType->id != ArtifactID::ART_LOCK) //ignore locks from assembled artifacts
  1108. moveFromSlotToAltar(i->first, nullptr, i->second.artifact);
  1109. }
  1110. SacrificeBackpack();
  1111. }
  1112. redraw();
  1113. }
  1114. void CAltarWindow::selectionChanged(bool side)
  1115. {
  1116. if(mode != EMarketMode::CREATURE_EXP)
  1117. return;
  1118. CTradeableItem *&selected = side ? hLeft : hRight;
  1119. CTradeableItem *&theOther = side ? hRight : hLeft;
  1120. theOther = *std::find_if(items[!side].begin(), items[!side].end(), [&](const CTradeableItem * item)
  1121. {
  1122. return item->serial == selected->serial;
  1123. });
  1124. int stackCount = 0;
  1125. for (int i = 0; i < GameConstants::ARMY_SIZE; i++)
  1126. if(hero->getStackCount(SlotID(i)) > sacrificedUnits[i])
  1127. stackCount++;
  1128. slider->setAmount(hero->getStackCount(SlotID(hLeft->serial)) - (stackCount == 1));
  1129. slider->block(!slider->amount);
  1130. slider->value = sacrificedUnits[hLeft->serial];
  1131. max->block(!slider->amount);
  1132. readyToTrade = true;
  1133. redraw();
  1134. }
  1135. void CAltarWindow::mimicCres()
  1136. {
  1137. std::vector<Rect> positions;
  1138. getPositionsFor(positions, false, CREATURE);
  1139. for(CTradeableItem *t : items[1])
  1140. {
  1141. auto hlp = new CTradeableItem(positions[t->serial].topLeft(), CREATURE_PLACEHOLDER, t->id, false, t->serial);
  1142. hlp->pos = positions[t->serial] + this->pos.topLeft();
  1143. items[0].push_back(hlp);
  1144. }
  1145. }
  1146. Point CAltarWindow::selectionOffset(bool Left) const
  1147. {
  1148. if(Left)
  1149. return Point(150, 421);
  1150. else
  1151. return Point(396, 421);
  1152. }
  1153. std::string CAltarWindow::selectionSubtitle(bool Left) const
  1154. {
  1155. if(Left && slider && hLeft)
  1156. return boost::lexical_cast<std::string>(slider->value);
  1157. else if(!Left && hRight)
  1158. return hRight->subtitle;
  1159. else
  1160. return "";
  1161. }
  1162. void CAltarWindow::artifactsChanged(bool left)
  1163. {
  1164. }
  1165. void CAltarWindow::garrisonChanged()
  1166. {
  1167. if(mode != EMarketMode::CREATURE_EXP)
  1168. return;
  1169. std::set<CTradeableItem *> empty;
  1170. getEmptySlots(empty);
  1171. for(CTradeableItem *t : empty)
  1172. {
  1173. removeItem(*std::find_if(items[0].begin(), items[0].end(), [&](const CTradeableItem * item)
  1174. {
  1175. return item->serial == t->serial;
  1176. }));
  1177. }
  1178. initSubs(true);
  1179. getExpValues();
  1180. }
  1181. void CAltarWindow::getExpValues()
  1182. {
  1183. int dump;
  1184. for(CTradeableItem *t : items[1])
  1185. if(t->id >= 0)
  1186. market->getOffer(t->id, 0, dump, expPerUnit[t->serial], EMarketMode::CREATURE_EXP);
  1187. }
  1188. void CAltarWindow::calcTotalExp()
  1189. {
  1190. int val = 0;
  1191. if(mode == EMarketMode::CREATURE_EXP)
  1192. {
  1193. for (int i = 0; i < sacrificedUnits.size(); i++)
  1194. {
  1195. val += expPerUnit[i] * sacrificedUnits[i];
  1196. }
  1197. }
  1198. else
  1199. {
  1200. for(const CArtifactInstance *art : arts->artifactsOnAltar)
  1201. {
  1202. int dmp, valOfArt;
  1203. market->getOffer(art->artType->id, 0, dmp, valOfArt, mode);
  1204. val += valOfArt; //WAS val += valOfArt * arts->artifactsOnAltar.count(*i);
  1205. }
  1206. }
  1207. val = hero->calculateXp(val);
  1208. expOnAltar->setText(boost::lexical_cast<std::string>(val));
  1209. }
  1210. void CAltarWindow::setExpToLevel()
  1211. {
  1212. expToLevel->setText(boost::lexical_cast<std::string>(CGI->heroh->reqExp(CGI->heroh->level(hero->exp)+1) - hero->exp));
  1213. }
  1214. void CAltarWindow::blockTrade()
  1215. {
  1216. hLeft = hRight = nullptr;
  1217. readyToTrade = false;
  1218. if(slider)
  1219. {
  1220. slider->block(true);
  1221. max->block(true);
  1222. }
  1223. deal->block(true);
  1224. }
  1225. void CAltarWindow::updateRight(CTradeableItem *toUpdate)
  1226. {
  1227. int val = sacrificedUnits[toUpdate->serial];
  1228. toUpdate->setType(val ? CREATURE : CREATURE_PLACEHOLDER);
  1229. toUpdate->subtitle = val ? boost::str(boost::format(CGI->generaltexth->allTexts[122]) % boost::lexical_cast<std::string>(val * expPerUnit[toUpdate->serial])) : ""; //%s exp
  1230. }
  1231. int CAltarWindow::firstFreeSlot()
  1232. {
  1233. int ret = -1;
  1234. while(items[0][++ret]->id >= 0 && ret + 1 < items[0].size());
  1235. return ret < items[0].size() ? ret : -1;
  1236. }
  1237. void CAltarWindow::SacrificeBackpack()
  1238. {
  1239. std::multiset<const CArtifactInstance *> toOmmit = arts->artifactsOnAltar;
  1240. for (auto & elem : hero->artifactsInBackpack)
  1241. {
  1242. if(vstd::contains(toOmmit, elem.artifact))
  1243. {
  1244. toOmmit -= elem.artifact;
  1245. continue;
  1246. }
  1247. putOnAltar(nullptr, elem.artifact);
  1248. }
  1249. arts->scrollBackpack(0);
  1250. calcTotalExp();
  1251. }
  1252. void CAltarWindow::artifactPicked()
  1253. {
  1254. redraw();
  1255. }
  1256. void CAltarWindow::showAll(SDL_Surface * to)
  1257. {
  1258. CTradeWindow::showAll(to);
  1259. if(mode == EMarketMode::ARTIFACT_EXP && arts && arts->commonInfo->src.art)
  1260. {
  1261. artIcon->setFrame(arts->commonInfo->src.art->artType->iconIndex);
  1262. artIcon->showAll(to);
  1263. int dmp, val;
  1264. market->getOffer(arts->commonInfo->src.art->artType->id, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
  1265. printAtMiddleLoc(boost::lexical_cast<std::string>(val), 304, 498, FONT_SMALL, Colors::WHITE, to);
  1266. }
  1267. }
  1268. bool CAltarWindow::putOnAltar(CTradeableItem* altarSlot, const CArtifactInstance *art)
  1269. {
  1270. int artID = art->artType->id;
  1271. if(artID != 1 && artID < 7) //special art
  1272. {
  1273. logGlobal->warnStream() << "Cannot put special artifact on altar!";
  1274. return false;
  1275. }
  1276. if(!altarSlot)
  1277. {
  1278. int slotIndex = firstFreeSlot();
  1279. if(slotIndex < 0)
  1280. {
  1281. logGlobal->warnStream() << "No free slots on altar!";
  1282. return false;
  1283. }
  1284. altarSlot = items[0][slotIndex];
  1285. }
  1286. int dmp, val;
  1287. market->getOffer(artID, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
  1288. arts->artifactsOnAltar.insert(art);
  1289. altarSlot->setArtInstance(art);
  1290. altarSlot->subtitle = boost::lexical_cast<std::string>(val);
  1291. deal->block(false);
  1292. return true;
  1293. }
  1294. void CAltarWindow::moveFromSlotToAltar(ArtifactPosition slotID, CTradeableItem* altarSlot, const CArtifactInstance *art)
  1295. {
  1296. auto freeBackpackSlot = ArtifactPosition(hero->artifactsInBackpack.size() + GameConstants::BACKPACK_START);
  1297. if(arts->commonInfo->src.art)
  1298. {
  1299. arts->commonInfo->dst.slotID = freeBackpackSlot;
  1300. arts->commonInfo->dst.AOH = arts;
  1301. }
  1302. if(putOnAltar(altarSlot, art))
  1303. {
  1304. if(slotID < GameConstants::BACKPACK_START)
  1305. LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero, slotID), ArtifactLocation(hero, freeBackpackSlot));
  1306. else
  1307. {
  1308. arts->commonInfo->src.clear();
  1309. arts->commonInfo->dst.clear();
  1310. CCS->curh->dragAndDropCursor(nullptr);
  1311. arts->unmarkSlots(false);
  1312. }
  1313. }
  1314. }