CArtHandler.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  1. #include "StdInc.h"
  2. #include "CArtHandler.h"
  3. #include "Filesystem/CResourceLoader.h"
  4. #include "CGeneralTextHandler.h"
  5. #include <boost/random/linear_congruential.hpp>
  6. #include "VCMI_Lib.h"
  7. #include "CModHandler.h"
  8. #include "CSpellHandler.h"
  9. #include "CObjectHandler.h"
  10. #include "NetPacks.h"
  11. #include "JsonNode.h"
  12. using namespace boost::assign;
  13. /*
  14. * CArtHandler.cpp, part of VCMI engine
  15. *
  16. * Authors: listed in file AUTHORS in main folder
  17. *
  18. * License: GNU General Public License v2.0 or later
  19. * Full text of license available in license.txt file, in main folder
  20. *
  21. */
  22. extern boost::rand48 ran;
  23. const std::string & CArtifact::Name() const
  24. {
  25. return name;
  26. }
  27. const std::string & CArtifact::Description() const
  28. {
  29. return description;
  30. }
  31. const std::string & CArtifact::EventText() const
  32. {
  33. return eventText;
  34. }
  35. bool CArtifact::isBig () const
  36. {
  37. return VLC->arth->isBigArtifact(id);
  38. }
  39. // /**
  40. // * Checks whether the artifact fits at a given slot.
  41. // * @param artifWorn A hero's set of worn artifacts.
  42. // */
  43. // bool CArtifact::fitsAt (const std::map<ui16, const CArtifact*> &artifWorn, ui16 slotID) const
  44. // {
  45. // if (!vstd::contains(possibleSlots, slotID))
  46. // return false;
  47. //
  48. // // Can't put an artifact in a locked slot.
  49. // std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.find(slotID);
  50. // if (it != artifWorn.end() && it->second->id == 145)
  51. // return false;
  52. //
  53. // // Check if a combination artifact fits.
  54. // // TODO: Might want a more general algorithm?
  55. // // Assumes that misc & rings fits only in their slots, and others in only one slot and no duplicates.
  56. // if (constituents != NULL)
  57. // {
  58. // std::map<ui16, const CArtifact*> tempArtifWorn = artifWorn;
  59. // const ui16 ringSlots[] = {6, 7};
  60. // const ui16 miscSlots[] = {9, 10, 11, 12, 18};
  61. // int rings = 0;
  62. // int misc = 0;
  63. //
  64. // VLC->arth->unequipArtifact(tempArtifWorn, slotID);
  65. //
  66. // BOOST_FOREACH(ui32 constituentID, *constituents)
  67. // {
  68. // const CArtifact& constituent = *VLC->arth->artifacts[constituentID];
  69. // const int slot = constituent.possibleSlots[0];
  70. //
  71. // if (slot == 6 || slot == 7)
  72. // rings++;
  73. // else if ((slot >= 9 && slot <= 12) || slot == 18)
  74. // misc++;
  75. // else if (tempArtifWorn.find(slot) != tempArtifWorn.end())
  76. // return false;
  77. // }
  78. //
  79. // // Ensure enough ring slots are free
  80. // for (int i = 0; i < sizeof(ringSlots)/sizeof(*ringSlots); i++)
  81. // {
  82. // if (tempArtifWorn.find(ringSlots[i]) == tempArtifWorn.end() || ringSlots[i] == slotID)
  83. // rings--;
  84. // }
  85. // if (rings > 0)
  86. // return false;
  87. //
  88. // // Ensure enough misc slots are free.
  89. // for (int i = 0; i < sizeof(miscSlots)/sizeof(*miscSlots); i++)
  90. // {
  91. // if (tempArtifWorn.find(miscSlots[i]) == tempArtifWorn.end() || miscSlots[i] == slotID)
  92. // misc--;
  93. // }
  94. // if (misc > 0)
  95. // return false;
  96. // }
  97. //
  98. // return true;
  99. // }
  100. // bool CArtifact::canBeAssembledTo (const std::map<ui16, const CArtifact*> &artifWorn, ui32 artifactID) const
  101. // {
  102. // if (constituentOf == NULL || !vstd::contains(*constituentOf, artifactID))
  103. // return false;
  104. //
  105. // const CArtifact &artifact = *VLC->arth->artifacts[artifactID];
  106. // assert(artifact.constituents);
  107. //
  108. // BOOST_FOREACH(ui32 constituentID, *artifact.constituents)
  109. // {
  110. // bool found = false;
  111. // for (std::map<ui16, const CArtifact*>::const_iterator it = artifWorn.begin(); it != artifWorn.end(); ++it)
  112. // {
  113. // if (it->second->id == constituentID)
  114. // {
  115. // found = true;
  116. // break;
  117. // }
  118. // }
  119. // if (!found)
  120. // return false;
  121. // }
  122. //
  123. // return true;
  124. // }
  125. CArtifact::CArtifact()
  126. {
  127. setNodeType(ARTIFACT);
  128. }
  129. CArtifact::~CArtifact()
  130. {
  131. }
  132. int CArtifact::getArtClassSerial() const
  133. {
  134. if(id == 1)
  135. return 4;
  136. switch(aClass)
  137. {
  138. case ART_TREASURE:
  139. return 0;
  140. case ART_MINOR:
  141. return 1;
  142. case ART_MAJOR:
  143. return 2;
  144. case ART_RELIC:
  145. return 3;
  146. case ART_SPECIAL:
  147. return 5;
  148. }
  149. return -1;
  150. }
  151. std::string CArtifact::nodeName() const
  152. {
  153. return "Artifact: " + Name();
  154. }
  155. // void CArtifact::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
  156. // {
  157. // //combined artifact carries bonuses from its parts
  158. // if(constituents)
  159. // {
  160. // BOOST_FOREACH(ui32 id, *constituents)
  161. // out.insert(VLC->arth->artifacts[id]);
  162. // }
  163. // }
  164. // void CScroll::Init()
  165. // {
  166. // // addNewBonus (Bonus (Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT, 1, id, spellid, Bonus::INDEPENDENT_MAX));
  167. // // //boost::algorithm::replace_first(description, "[spell name]", VLC->spellh->spells[spellid].name);
  168. // }
  169. void CArtifact::setName (std::string desc)
  170. {
  171. name = desc;
  172. }
  173. void CArtifact::setDescription (std::string desc)
  174. {
  175. description = desc;
  176. }
  177. void CArtifact::setEventText (std::string desc)
  178. {
  179. eventText = desc;
  180. }
  181. void CGrowingArtifact::levelUpArtifact (CArtifactInstance * art)
  182. {
  183. Bonus b;
  184. b.type = Bonus::LEVEL_COUNTER;
  185. b.val = 1;
  186. b.duration = Bonus::COMMANDER_KILLED;
  187. art->accumulateBonus (b);
  188. BOOST_FOREACH (auto bonus, bonusesPerLevel)
  189. {
  190. if (art->valOfBonuses(Bonus::LEVEL_COUNTER) % bonus.first == 0) //every n levels
  191. {
  192. art->accumulateBonus (bonus.second);
  193. }
  194. }
  195. BOOST_FOREACH (auto bonus, thresholdBonuses)
  196. {
  197. if (art->valOfBonuses(Bonus::LEVEL_COUNTER) == bonus.first) //every n levels
  198. {
  199. art->addNewBonus (&bonus.second);
  200. }
  201. }
  202. }
  203. CArtHandler::CArtHandler()
  204. {
  205. VLC->arth = this;
  206. // War machines are the default big artifacts.
  207. for (ui32 i = 3; i <= 6; i++)
  208. bigArtifacts.insert(i);
  209. }
  210. CArtHandler::~CArtHandler()
  211. {
  212. for (std::vector< ConstTransitivePtr<CArtifact> >::iterator it = artifacts.begin(); it != artifacts.end(); ++it)
  213. {
  214. delete (*it)->constituents;
  215. delete (*it)->constituentOf;
  216. }
  217. }
  218. void CArtHandler::loadArtifacts(bool onlyTxt)
  219. {
  220. std::vector<ui16> slots;
  221. slots += 17, 16, 15, 14, 13, 18, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0;
  222. growingArtifacts += 146, 147, 148, 150, 151, 152, 153;
  223. static std::map<char, CArtifact::EartClass> classes =
  224. map_list_of('S',CArtifact::ART_SPECIAL)('T',CArtifact::ART_TREASURE)('N',CArtifact::ART_MINOR)('J',CArtifact::ART_MAJOR)('R',CArtifact::ART_RELIC);
  225. CLegacyConfigParser parser("DATA/ARTRAITS.TXT");
  226. CLegacyConfigParser events("DATA/ARTEVENT.TXT");
  227. parser.endLine(); // header
  228. parser.endLine();
  229. std::map<ui32,ui8>::iterator itr;
  230. for (int i=0; i<GameConstants::ARTIFACTS_QUANTITY; i++)
  231. {
  232. CArtifact *art;
  233. if (vstd::contains (growingArtifacts, i))
  234. {
  235. art = new CGrowingArtifact();
  236. }
  237. else
  238. {
  239. art = new CArtifact();
  240. }
  241. CArtifact &nart = *art;
  242. nart.id=i;
  243. nart.setName (parser.readString());
  244. nart.setEventText (events.readString());
  245. events.endLine();
  246. nart.price= parser.readNumber();
  247. nart.possibleSlots[ArtBearer::HERO]; //we want to generate map entry even if it will be empty
  248. nart.possibleSlots[ArtBearer::CREATURE]; //we want to generate map entry even if it will be empty
  249. nart.possibleSlots[ArtBearer::COMMANDER];
  250. for(int j=0;j<slots.size();j++)
  251. {
  252. if(parser.readString() == "x")
  253. nart.possibleSlots[ArtBearer::HERO].push_back(slots[j]);
  254. }
  255. nart.aClass = classes[parser.readString()[0]];
  256. //load description and remove quotation marks
  257. nart.setDescription (parser.readString());
  258. parser.endLine();
  259. if(onlyTxt)
  260. continue;
  261. // Fill in information about combined artifacts. Should perhaps be moved to a config file?
  262. nart.constituentOf = NULL;
  263. switch (nart.id)
  264. {
  265. case 129: // Angelic Alliance
  266. nart.constituents = new std::vector<ui32>();
  267. *nart.constituents += 31, 32, 33, 34, 35, 36;
  268. break;
  269. case 130: // Cloak of the Undead King
  270. nart.constituents = new std::vector<ui32>();
  271. *nart.constituents += 54, 55, 56;
  272. break;
  273. case 131: // Elixir of Life
  274. nart.constituents = new std::vector<ui32>();
  275. *nart.constituents += 94, 95, 96;
  276. break;
  277. case 132: // Armor of the Damned
  278. nart.constituents = new std::vector<ui32>();
  279. *nart.constituents += 8, 14, 20, 26;
  280. break;
  281. case 133: // Statue of Legion
  282. nart.constituents = new std::vector<ui32>();
  283. *nart.constituents += 118, 119, 120, 121, 122;
  284. break;
  285. case 134: // Power of the Dragon Father
  286. nart.constituents = new std::vector<ui32>();
  287. *nart.constituents += 37, 38, 39, 40, 41, 42, 43, 44, 45;
  288. break;
  289. case 135: // Titan's Thunder
  290. nart.constituents = new std::vector<ui32>();
  291. *nart.constituents += 12, 18, 24, 30;
  292. break;
  293. case 136: // Admiral's Hat
  294. nart.constituents = new std::vector<ui32>();
  295. *nart.constituents += 71, 123;
  296. break;
  297. case 137: // Bow of the Sharpshooter
  298. nart.constituents = new std::vector<ui32>();
  299. *nart.constituents += 60, 61, 62;
  300. break;
  301. case 138: // Wizards' Well
  302. nart.constituents = new std::vector<ui32>();
  303. *nart.constituents += 73, 74, 75;
  304. break;
  305. case 139: // Ring of the Magi
  306. nart.constituents = new std::vector<ui32>();
  307. *nart.constituents += 76, 77, 78;
  308. break;
  309. case 140: // Cornucopia
  310. nart.constituents = new std::vector<ui32>();
  311. *nart.constituents += 109, 110, 111, 113;
  312. break;
  313. // TODO: WoG combinationals
  314. default:
  315. nart.constituents = NULL;
  316. break;
  317. }
  318. artifacts.push_back(&nart);
  319. }
  320. if (VLC->modh->modules.COMMANDERS)
  321. { //TODO: move all artifacts config to separate json file
  322. const JsonNode config(ResourceID("config/commanders.json"));
  323. BOOST_FOREACH(const JsonNode &artifact, config["artifacts"].Vector())
  324. {
  325. auto ga = dynamic_cast <CGrowingArtifact *>(artifacts[artifact["id"].Float()].get());
  326. BOOST_FOREACH (auto b, artifact["bonusesPerLevel"].Vector())
  327. {
  328. ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
  329. }
  330. BOOST_FOREACH (auto b, artifact["thresholdBonuses"].Vector())
  331. {
  332. ga->thresholdBonuses.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
  333. }
  334. }
  335. }
  336. sortArts();
  337. if(onlyTxt)
  338. return;
  339. addBonuses();
  340. // Populate reverse mappings of combinational artifacts.
  341. BOOST_FOREACH(CArtifact *artifact, artifacts)
  342. {
  343. if (artifact->constituents != NULL)
  344. {
  345. BOOST_FOREACH(ui32 constituentID, *artifact->constituents)
  346. {
  347. if (artifacts[constituentID]->constituentOf == NULL)
  348. artifacts[constituentID]->constituentOf = new std::vector<ui32>();
  349. artifacts[constituentID]->constituentOf->push_back(artifact->id);
  350. }
  351. }
  352. }
  353. }
  354. int CArtHandler::convertMachineID(int id, bool creToArt )
  355. {
  356. int dif = 142;
  357. if(creToArt)
  358. {
  359. switch (id)
  360. {
  361. case 147:
  362. dif--;
  363. break;
  364. case 148:
  365. dif++;
  366. break;
  367. }
  368. dif = -dif;
  369. }
  370. else
  371. {
  372. switch (id)
  373. {
  374. case 6:
  375. dif--;
  376. break;
  377. case 5:
  378. dif++;
  379. break;
  380. }
  381. }
  382. return id + dif;
  383. }
  384. void CArtHandler::sortArts()
  385. {
  386. //for (int i=0; i<allowedArtifacts.size(); ++i) //do 144, bo nie chcemy bzdurek
  387. //{
  388. // switch (allowedArtifacts[i]->aClass)
  389. // {
  390. // case CArtifact::ART_TREASURE:
  391. // treasures.push_back(allowedArtifacts[i]);
  392. // break;
  393. // case CArtifact::ART_MINOR:
  394. // minors.push_back(allowedArtifacts[i]);
  395. // break;
  396. // case CArtifact::ART_MAJOR:
  397. // majors.push_back(allowedArtifacts[i]);
  398. // break;
  399. // case CArtifact::ART_RELIC:
  400. // relics.push_back(allowedArtifacts[i]);
  401. // break;
  402. // }
  403. //}
  404. }
  405. void CArtHandler::erasePickedArt( TArtifactInstanceID id )
  406. {
  407. std::vector<CArtifact*>* ptr;
  408. CArtifact *art = artifacts[id];
  409. switch (art->aClass)
  410. {
  411. case CArtifact::ART_TREASURE:
  412. ptr = &treasures;
  413. break;
  414. case CArtifact::ART_MINOR:
  415. ptr = &minors;
  416. break;
  417. case CArtifact::ART_MAJOR:
  418. ptr = &majors;
  419. break;
  420. case CArtifact::ART_RELIC:
  421. ptr = &relics;
  422. break;
  423. default: //special artifacts should not be erased
  424. return;
  425. }
  426. ptr->erase (std::find(ptr->begin(), ptr->end(), art)); //remove the artifact from available list
  427. }
  428. ui16 CArtHandler::getRandomArt(int flags)
  429. {
  430. std::vector<ConstTransitivePtr<CArtifact> > out;
  431. getAllowed(out, flags);
  432. ui16 id = out[ran() % out.size()]->id;
  433. erasePickedArt (id);
  434. return id;
  435. }
  436. ui16 CArtHandler::getArtSync (ui32 rand, int flags)
  437. {
  438. std::vector<ConstTransitivePtr<CArtifact> > out;
  439. getAllowed(out, flags);
  440. CArtifact *art = out[rand % out.size()];
  441. return art->id;
  442. }
  443. void CArtHandler::getAllowed(std::vector<ConstTransitivePtr<CArtifact> > &out, int flags)
  444. {
  445. if (flags & CArtifact::ART_TREASURE)
  446. getAllowedArts (out, &treasures, CArtifact::ART_TREASURE);
  447. if (flags & CArtifact::ART_MINOR)
  448. getAllowedArts (out, &minors, CArtifact::ART_MINOR);
  449. if (flags & CArtifact::ART_MAJOR)
  450. getAllowedArts (out, &majors, CArtifact::ART_MAJOR);
  451. if (flags & CArtifact::ART_RELIC)
  452. getAllowedArts (out, &relics, CArtifact::ART_RELIC);
  453. if (!out.size()) //no artifact of specified rarity, we need to take another one
  454. {
  455. getAllowedArts (out, &treasures, CArtifact::ART_TREASURE);
  456. getAllowedArts (out, &minors, CArtifact::ART_MINOR);
  457. getAllowedArts (out, &majors, CArtifact::ART_MAJOR);
  458. getAllowedArts (out, &relics, CArtifact::ART_RELIC);
  459. }
  460. if (!out.size()) //no arts are available at all
  461. {
  462. out.resize (64);
  463. std::fill_n (out.begin(), 64, artifacts[2]); //Give Grail - this can't be banned (hopefully)
  464. }
  465. }
  466. void CArtHandler::getAllowedArts(std::vector<ConstTransitivePtr<CArtifact> > &out, std::vector<CArtifact*> *arts, int flag)
  467. {
  468. if (arts->empty()) //restock available arts
  469. {
  470. for (int i = 0; i < allowedArtifacts.size(); ++i)
  471. {
  472. if (allowedArtifacts[i]->aClass == flag)
  473. arts->push_back(allowedArtifacts[i]);
  474. }
  475. }
  476. for (int i = 0; i < arts->size(); ++i)
  477. {
  478. CArtifact *art = (*arts)[i];
  479. out.push_back(art);
  480. }
  481. }
  482. Bonus *createBonus(Bonus::BonusType type, int val, int subtype, int valType, shared_ptr<ILimiter> limiter = shared_ptr<ILimiter>(), int additionalInfo = 0)
  483. {
  484. Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
  485. added->additionalInfo = additionalInfo;
  486. added->valType = valType;
  487. added->limiter = limiter;
  488. return added;
  489. }
  490. Bonus *createBonus(Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator = shared_ptr<IPropagator>(), int additionalInfo = 0)
  491. {
  492. Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,-1,subtype);
  493. added->additionalInfo = additionalInfo;
  494. added->valType = Bonus::BASE_NUMBER;
  495. added->propagator = propagator;
  496. return added;
  497. }
  498. void CArtHandler::giveArtBonus( TArtifactID aid, Bonus::BonusType type, int val, int subtype, int valType, shared_ptr<ILimiter> limiter, int additionalInfo)
  499. {
  500. giveArtBonus(aid, createBonus(type, val, subtype, valType, limiter, additionalInfo));
  501. }
  502. void CArtHandler::giveArtBonus(TArtifactID aid, Bonus::BonusType type, int val, int subtype, shared_ptr<IPropagator> propagator /*= NULL*/, int additionalInfo)
  503. {
  504. giveArtBonus(aid, createBonus(type, val, subtype, propagator, additionalInfo));
  505. }
  506. void CArtHandler::giveArtBonus(TArtifactID aid, Bonus *bonus)
  507. {
  508. bonus->sid = aid;
  509. if(bonus->subtype == Bonus::MORALE || bonus->type == Bonus::LUCK)
  510. bonus->description = artifacts[aid]->Name() + (bonus->val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(bonus->val);
  511. else
  512. bonus->description = artifacts[aid]->Name();
  513. artifacts[aid]->addNewBonus(bonus);
  514. }
  515. void CArtHandler::makeItCreatureArt (TArtifactInstanceID aid, bool onlyCreature /*=true*/)
  516. {
  517. CArtifact *a = artifacts[aid];
  518. if (onlyCreature)
  519. {
  520. a->possibleSlots[ArtBearer::HERO].clear();
  521. a->possibleSlots[ArtBearer::COMMANDER].clear();
  522. }
  523. a->possibleSlots[ArtBearer::CREATURE].push_back(ArtifactPosition::CREATURE_SLOT);
  524. }
  525. void CArtHandler::makeItCommanderArt( TArtifactInstanceID aid, bool onlyCommander /*= true*/ )
  526. {
  527. CArtifact *a = artifacts[aid];
  528. if (onlyCommander)
  529. {
  530. a->possibleSlots[ArtBearer::HERO].clear();
  531. a->possibleSlots[ArtBearer::CREATURE].clear();
  532. }
  533. for (int i = ArtifactPosition::COMMANDER1; i <= ArtifactPosition::COMMANDER6; ++i)
  534. a->possibleSlots[ArtBearer::COMMANDER].push_back(i);
  535. }
  536. void CArtHandler::addBonuses()
  537. {
  538. const JsonNode config(ResourceID("config/artifacts.json"));
  539. BOOST_FOREACH(const JsonNode &artifact, config["artifacts"].Vector())
  540. {
  541. auto ga = artifacts[artifact["id"].Float()].get();
  542. BOOST_FOREACH (auto b, artifact["bonuses"].Vector())
  543. {
  544. auto bonus = JsonUtils::parseBonus (b);
  545. //common properties
  546. bonus->source = Bonus::ARTIFACT;
  547. bonus->sid = ga->id;
  548. bonus->duration = Bonus::PERMANENT;
  549. bonus->description = ga->Name();
  550. ga->addNewBonus (bonus);
  551. }
  552. if(artifact["type"].String() == "Creature")
  553. makeItCreatureArt(ga->id);
  554. else if(artifact["type"].String() == "Commander")
  555. makeItCommanderArt(ga->id);
  556. }
  557. }
  558. void CArtHandler::clear()
  559. {
  560. BOOST_FOREACH(CArtifact *art, artifacts)
  561. delete art;
  562. artifacts.clear();
  563. clearHlpLists();
  564. }
  565. void CArtHandler::clearHlpLists()
  566. {
  567. treasures.clear();
  568. minors.clear();
  569. majors.clear();
  570. relics.clear();
  571. }
  572. void CArtHandler::initAllowedArtifactsList(const std::vector<ui8> &allowed)
  573. {
  574. allowedArtifacts.clear();
  575. clearHlpLists();
  576. for (int i=0; i<144; ++i) //yes, 144
  577. {
  578. if (allowed[i])
  579. allowedArtifacts.push_back(artifacts[i]);
  580. }
  581. if (VLC->modh->modules.COMMANDERS) //allow all commander artifacts for testing
  582. {
  583. for (int i = 146; i <= 155; ++i)
  584. {
  585. allowedArtifacts.push_back(artifacts[i]);
  586. }
  587. }
  588. }
  589. CArtifactInstance::CArtifactInstance()
  590. {
  591. init();
  592. }
  593. CArtifactInstance::CArtifactInstance( CArtifact *Art)
  594. {
  595. init();
  596. setType(Art);
  597. }
  598. // CArtifactInstance::CArtifactInstance(int aid)
  599. // {
  600. // init();
  601. // setType(VLC->arth->artifacts[aid]);
  602. // }
  603. void CArtifactInstance::setType( CArtifact *Art )
  604. {
  605. artType = Art;
  606. attachTo(Art);
  607. }
  608. std::string CArtifactInstance::nodeName() const
  609. {
  610. return "Artifact instance of " + (artType ? artType->Name() : std::string("uninitialized")) + " type";
  611. }
  612. CArtifactInstance * CArtifactInstance::createScroll( const CSpell *s)
  613. {
  614. CArtifactInstance *ret = new CArtifactInstance(VLC->arth->artifacts[1]);
  615. Bonus *b = new Bonus(Bonus::PERMANENT, Bonus::SPELL, Bonus::ARTIFACT_INSTANCE, -1, 1, s->id);
  616. ret->addNewBonus(b);
  617. return ret;
  618. }
  619. void CArtifactInstance::init()
  620. {
  621. id = -1;
  622. setNodeType(ARTIFACT_INSTANCE);
  623. }
  624. int CArtifactInstance::firstAvailableSlot(const CArtifactSet *h) const
  625. {
  626. BOOST_FOREACH(ui16 slot, artType->possibleSlots[h->bearerType()])
  627. {
  628. if(canBePutAt(h, slot)) //if(artType->fitsAt(h->artifWorn, slot))
  629. {
  630. //we've found a free suitable slot.
  631. return slot;
  632. }
  633. }
  634. //if haven't find proper slot, use backpack
  635. return firstBackpackSlot(h);
  636. }
  637. int CArtifactInstance::firstBackpackSlot(const CArtifactSet *h) const
  638. {
  639. if(!artType->isBig()) //discard big artifact
  640. return GameConstants::BACKPACK_START + h->artifactsInBackpack.size();
  641. return -1;
  642. }
  643. bool CArtifactInstance::canBePutAt(const ArtifactLocation al, bool assumeDestRemoved /*= false*/) const
  644. {
  645. return canBePutAt(al.getHolderArtSet(), al.slot, assumeDestRemoved);
  646. }
  647. bool CArtifactInstance::canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved /*= false*/) const
  648. {
  649. if(slot >= GameConstants::BACKPACK_START)
  650. {
  651. if(artType->isBig())
  652. return false;
  653. //TODO backpack limit
  654. return true;
  655. }
  656. auto possibleSlots = artType->possibleSlots.find(artSet->bearerType());
  657. if(possibleSlots == artType->possibleSlots.end())
  658. {
  659. tlog3 << "Warning: arrtifact " << artType->Name() << " doesn't have defined allowed slots for bearer of type "
  660. << artSet->bearerType() << std::endl;
  661. return false;
  662. }
  663. if(!vstd::contains(possibleSlots->second, slot))
  664. return false;
  665. return artSet->isPositionFree(slot, assumeDestRemoved);
  666. }
  667. void CArtifactInstance::putAt(ArtifactLocation al)
  668. {
  669. assert(canBePutAt(al));
  670. al.getHolderArtSet()->setNewArtSlot(al.slot, this, false);
  671. if(al.slot < GameConstants::BACKPACK_START)
  672. al.getHolderNode()->attachTo(this);
  673. }
  674. void CArtifactInstance::removeFrom(ArtifactLocation al)
  675. {
  676. assert(al.getHolderArtSet()->getArt(al.slot) == this);
  677. al.getHolderArtSet()->eraseArtSlot(al.slot);
  678. if(al.slot < GameConstants::BACKPACK_START)
  679. al.getHolderNode()->detachFrom(this);
  680. //TODO delete me?
  681. }
  682. bool CArtifactInstance::canBeDisassembled() const
  683. {
  684. return artType->constituents && artType->constituentOf->size();
  685. }
  686. std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet *h) const
  687. {
  688. std::vector<const CArtifact *> ret;
  689. if(!artType->constituentOf //not a part of combined artifact
  690. || artType->constituents) //combined artifact already: no combining of combined artifacts... for now.
  691. return ret;
  692. BOOST_FOREACH(ui32 possibleCombinedArt, *artType->constituentOf)
  693. {
  694. const CArtifact * const artifact = VLC->arth->artifacts[possibleCombinedArt];
  695. assert(artifact->constituents);
  696. bool possible = true;
  697. BOOST_FOREACH(ui32 constituentID, *artifact->constituents) //check if all constituents are available
  698. {
  699. if(!h->hasArt(constituentID, true)) //constituent must be equipped
  700. {
  701. possible = false;
  702. break;
  703. }
  704. }
  705. if(possible)
  706. ret.push_back(artifact);
  707. }
  708. return ret;
  709. }
  710. void CArtifactInstance::move(ArtifactLocation src, ArtifactLocation dst)
  711. {
  712. removeFrom(src);
  713. putAt(dst);
  714. }
  715. CArtifactInstance * CArtifactInstance::createNewArtifactInstance(CArtifact *Art)
  716. {
  717. if(!Art->constituents)
  718. {
  719. auto ret = new CArtifactInstance(Art);
  720. if (dynamic_cast<CGrowingArtifact *>(Art))
  721. {
  722. Bonus * bonus = new Bonus;
  723. bonus->type = Bonus::LEVEL_COUNTER;
  724. bonus->val = 0;
  725. ret->addNewBonus (bonus);
  726. }
  727. return ret;
  728. }
  729. else
  730. {
  731. CCombinedArtifactInstance * ret = new CCombinedArtifactInstance(Art);
  732. ret->createConstituents();
  733. return ret;
  734. }
  735. }
  736. CArtifactInstance * CArtifactInstance::createNewArtifactInstance(int aid)
  737. {
  738. return createNewArtifactInstance(VLC->arth->artifacts[aid]);
  739. }
  740. void CArtifactInstance::deserializationFix()
  741. {
  742. setType(artType);
  743. }
  744. int CArtifactInstance::getGivenSpellID() const
  745. {
  746. const Bonus * b = getBonusLocalFirst(Selector::type(Bonus::SPELL));
  747. if(!b)
  748. {
  749. tlog3 << "Warning: " << nodeName() << " doesn't bear any spell!\n";
  750. return -1;
  751. }
  752. return b->subtype;
  753. }
  754. bool CArtifactInstance::isPart(const CArtifactInstance *supposedPart) const
  755. {
  756. return supposedPart == this;
  757. }
  758. bool CCombinedArtifactInstance::canBePutAt(const CArtifactSet *artSet, int slot, bool assumeDestRemoved /*= false*/) const
  759. {
  760. bool canMainArtifactBePlaced = CArtifactInstance::canBePutAt(artSet, slot, assumeDestRemoved);
  761. if(!canMainArtifactBePlaced)
  762. return false; //no is no...
  763. if(slot >= GameConstants::BACKPACK_START)
  764. return true; //we can always remove combined art to the backapck
  765. assert(artType->constituents);
  766. std::vector<ConstituentInfo> constituentsToBePlaced = constituentsInfo; //we'll remove constituents from that list, as we find a suitable slot for them
  767. //it may be that we picked a combined artifact in hero screen (though technically it's still there) to move it
  768. //so we remove from the list all constituents that are already present on dst hero in the form of locks
  769. BOOST_FOREACH(const ConstituentInfo &constituent, constituentsInfo)
  770. {
  771. if(constituent.art == artSet->getArt(constituent.slot, false)) //no need to worry about locked constituent
  772. constituentsToBePlaced -= constituent;
  773. }
  774. //we iterate over all active slots and check if constituents fits them
  775. for (int i = 0; i < GameConstants::BACKPACK_START; i++)
  776. {
  777. for(std::vector<ConstituentInfo>::iterator art = constituentsToBePlaced.begin(); art != constituentsToBePlaced.end(); art++)
  778. {
  779. if(art->art->canBePutAt(artSet, i, i == slot)) // i == al.slot because we can remove already worn artifact only from that slot that is our main destination
  780. {
  781. constituentsToBePlaced.erase(art);
  782. break;
  783. }
  784. }
  785. }
  786. return constituentsToBePlaced.empty();
  787. }
  788. bool CCombinedArtifactInstance::canBeDisassembled() const
  789. {
  790. return true;
  791. }
  792. CCombinedArtifactInstance::CCombinedArtifactInstance(CArtifact *Art)
  793. : CArtifactInstance(Art) //TODO: seems unued, but need to be written
  794. {
  795. }
  796. CCombinedArtifactInstance::CCombinedArtifactInstance()
  797. {
  798. }
  799. void CCombinedArtifactInstance::createConstituents()
  800. {
  801. assert(artType);
  802. assert(artType->constituents);
  803. BOOST_FOREACH(ui32 a, *artType->constituents)
  804. {
  805. addAsConstituent(CArtifactInstance::createNewArtifactInstance(a), -1);
  806. }
  807. }
  808. void CCombinedArtifactInstance::addAsConstituent(CArtifactInstance *art, int slot)
  809. {
  810. assert(vstd::contains(*artType->constituents, art->artType->id));
  811. assert(art->getParentNodes().size() == 1 && art->getParentNodes().front() == art->artType);
  812. constituentsInfo.push_back(ConstituentInfo(art, slot));
  813. attachTo(art);
  814. }
  815. void CCombinedArtifactInstance::putAt(ArtifactLocation al)
  816. {
  817. if(al.slot >= GameConstants::BACKPACK_START)
  818. {
  819. CArtifactInstance::putAt(al);
  820. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  821. ci.slot = -1;
  822. }
  823. else
  824. {
  825. CArtifactInstance *mainConstituent = figureMainConstituent(al); //it'll be replaced with combined artifact, not a lock
  826. CArtifactInstance::putAt(al); //puts combined art (this)
  827. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  828. {
  829. if(ci.art != mainConstituent)
  830. {
  831. const ArtifactLocation suggestedPos(al.artHolder, ci.slot);
  832. const bool inActiveSlot = vstd::isbetween(ci.slot, 0, GameConstants::BACKPACK_START);
  833. const bool suggestedPosValid = ci.art->canBePutAt(suggestedPos);
  834. int pos = -1;
  835. if(inActiveSlot && suggestedPosValid) //there is a valid suggestion where to place lock
  836. pos = ci.slot;
  837. else
  838. ci.slot = pos = ci.art->firstAvailableSlot(al.getHolderArtSet());
  839. assert(pos < GameConstants::BACKPACK_START);
  840. al.getHolderArtSet()->setNewArtSlot(pos, ci.art, true); //sets as lock
  841. }
  842. else
  843. {
  844. ci.slot = -1;
  845. }
  846. }
  847. }
  848. }
  849. void CCombinedArtifactInstance::removeFrom(ArtifactLocation al)
  850. {
  851. if(al.slot >= GameConstants::BACKPACK_START)
  852. {
  853. CArtifactInstance::removeFrom(al);
  854. }
  855. else
  856. {
  857. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  858. {
  859. if(ci.slot >= 0)
  860. {
  861. al.getHolderArtSet()->eraseArtSlot(ci.slot);
  862. ci.slot = -1;
  863. }
  864. else
  865. {
  866. //main constituent
  867. CArtifactInstance::removeFrom(al);
  868. }
  869. }
  870. }
  871. }
  872. CArtifactInstance * CCombinedArtifactInstance::figureMainConstituent(const ArtifactLocation al)
  873. {
  874. CArtifactInstance *mainConstituent = NULL; //it'll be replaced with combined artifact, not a lock
  875. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  876. if(ci.slot == al.slot)
  877. mainConstituent = ci.art;
  878. if(!mainConstituent)
  879. {
  880. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  881. {
  882. if(vstd::contains(ci.art->artType->possibleSlots[al.getHolderArtSet()->bearerType()], al.slot))
  883. {
  884. mainConstituent = ci.art;
  885. }
  886. }
  887. }
  888. return mainConstituent;
  889. }
  890. void CCombinedArtifactInstance::deserializationFix()
  891. {
  892. BOOST_FOREACH(ConstituentInfo &ci, constituentsInfo)
  893. attachTo(ci.art);
  894. }
  895. bool CCombinedArtifactInstance::isPart(const CArtifactInstance *supposedPart) const
  896. {
  897. bool me = CArtifactInstance::isPart(supposedPart);
  898. if(me)
  899. return true;
  900. //check for constituents
  901. BOOST_FOREACH(const ConstituentInfo &constituent, constituentsInfo)
  902. if(constituent.art == supposedPart)
  903. return true;
  904. return false;
  905. }
  906. CCombinedArtifactInstance::ConstituentInfo::ConstituentInfo(CArtifactInstance *Art /*= NULL*/, ui16 Slot /*= -1*/)
  907. {
  908. art = Art;
  909. slot = Slot;
  910. }
  911. bool CCombinedArtifactInstance::ConstituentInfo::operator==(const ConstituentInfo &rhs) const
  912. {
  913. return art == rhs.art && slot == rhs.slot;
  914. }
  915. const CArtifactInstance* CArtifactSet::getArt(ui16 pos, bool excludeLocked /*= true*/) const
  916. {
  917. if(const ArtSlotInfo *si = getSlot(pos))
  918. {
  919. if(si->artifact && (!excludeLocked || !si->locked))
  920. return si->artifact;
  921. }
  922. return NULL;
  923. }
  924. CArtifactInstance* CArtifactSet::getArt(ui16 pos, bool excludeLocked /*= true*/)
  925. {
  926. return const_cast<CArtifactInstance*>((const_cast<const CArtifactSet*>(this))->getArt(pos, excludeLocked));
  927. }
  928. si32 CArtifactSet::getArtPos(int aid, bool onlyWorn /*= true*/) const
  929. {
  930. for(std::map<ui16, ArtSlotInfo>::const_iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
  931. if(i->second.artifact->artType->id == aid)
  932. return i->first;
  933. if(onlyWorn)
  934. return -1;
  935. for(int i = 0; i < artifactsInBackpack.size(); i++)
  936. if(artifactsInBackpack[i].artifact->artType->id == aid)
  937. return GameConstants::BACKPACK_START + i;
  938. return -1;
  939. }
  940. si32 CArtifactSet::getArtPos(const CArtifactInstance *art) const
  941. {
  942. for(std::map<ui16, ArtSlotInfo>::const_iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
  943. if(i->second.artifact == art)
  944. return i->first;
  945. for(int i = 0; i < artifactsInBackpack.size(); i++)
  946. if(artifactsInBackpack[i].artifact == art)
  947. return GameConstants::BACKPACK_START + i;
  948. return -1;
  949. }
  950. const CArtifactInstance * CArtifactSet::getArtByInstanceId( TArtifactInstanceID artInstId ) const
  951. {
  952. for(std::map<ui16, ArtSlotInfo>::const_iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
  953. if(i->second.artifact->id == artInstId)
  954. return i->second.artifact;
  955. for(int i = 0; i < artifactsInBackpack.size(); i++)
  956. if(artifactsInBackpack[i].artifact->id == artInstId)
  957. return artifactsInBackpack[i].artifact;
  958. return NULL;
  959. }
  960. bool CArtifactSet::hasArt(ui32 aid, bool onlyWorn /*= false*/) const
  961. {
  962. return getArtPos(aid, onlyWorn) != -1;
  963. }
  964. const ArtSlotInfo * CArtifactSet::getSlot(ui16 pos) const
  965. {
  966. if(vstd::contains(artifactsWorn, pos))
  967. return &artifactsWorn[pos];
  968. if(pos >= ArtifactPosition::AFTER_LAST )
  969. {
  970. int backpackPos = (int)pos - GameConstants::BACKPACK_START;
  971. if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
  972. return NULL;
  973. else
  974. return &artifactsInBackpack[backpackPos];
  975. }
  976. return NULL;
  977. }
  978. bool CArtifactSet::isPositionFree(ui16 pos, bool onlyLockCheck /*= false*/) const
  979. {
  980. if(const ArtSlotInfo *s = getSlot(pos))
  981. return (onlyLockCheck || !s->artifact) && !s->locked;
  982. return true; //no slot means not used
  983. }
  984. si32 CArtifactSet::getArtTypeId(ui16 pos) const
  985. {
  986. const CArtifactInstance * const a = getArt(pos);
  987. if(!a)
  988. {
  989. tlog2 << (dynamic_cast<const CGHeroInstance*>(this))->name << " has no artifact at " << pos << " (getArtTypeId)\n";
  990. return -1;
  991. }
  992. return a->artType->id;
  993. }
  994. CArtifactSet::~CArtifactSet()
  995. {
  996. }
  997. ArtSlotInfo & CArtifactSet::retreiveNewArtSlot(ui16 slot)
  998. {
  999. assert(!vstd::contains(artifactsWorn, slot));
  1000. ArtSlotInfo &ret = slot < GameConstants::BACKPACK_START
  1001. ? artifactsWorn[slot]
  1002. : *artifactsInBackpack.insert(artifactsInBackpack.begin() + (slot - GameConstants::BACKPACK_START), ArtSlotInfo());
  1003. return ret;
  1004. }
  1005. void CArtifactSet::setNewArtSlot(ui16 slot, CArtifactInstance *art, bool locked)
  1006. {
  1007. ArtSlotInfo &asi = retreiveNewArtSlot(slot);
  1008. asi.artifact = art;
  1009. asi.locked = locked;
  1010. }
  1011. void CArtifactSet::eraseArtSlot(ui16 slot)
  1012. {
  1013. if(slot < GameConstants::BACKPACK_START)
  1014. {
  1015. artifactsWorn.erase(slot);
  1016. }
  1017. else
  1018. {
  1019. slot -= GameConstants::BACKPACK_START;
  1020. artifactsInBackpack.erase(artifactsInBackpack.begin() + slot);
  1021. }
  1022. }
  1023. void CArtifactSet::artDeserializationFix(CBonusSystemNode *node)
  1024. {
  1025. for(bmap<ui16, ArtSlotInfo>::iterator i = artifactsWorn.begin(); i != artifactsWorn.end(); i++)
  1026. if(i->second.artifact && !i->second.locked)
  1027. node->attachTo(i->second.artifact);
  1028. }