CArtifactSet.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. /*
  2. * CArtifactSet.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "CArtifactSet.h"
  12. #include "CArtifact.h"
  13. #include "ArtifactUtils.h"
  14. #include "../../constants/StringConstants.h"
  15. #include "../../gameState/CGameState.h"
  16. #include "../../mapping/CMap.h"
  17. #include "../../serializer/JsonSerializeFormat.h"
  18. VCMI_LIB_NAMESPACE_BEGIN
  19. const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
  20. {
  21. if(const ArtSlotInfo * si = getSlot(pos))
  22. {
  23. if(si->getArt() && (!excludeLocked || !si->locked))
  24. return si->getArt();
  25. }
  26. return nullptr;
  27. }
  28. ArtifactInstanceID CArtifactSet::getArtID(const ArtifactPosition & pos, bool excludeLocked) const
  29. {
  30. if(const ArtSlotInfo * si = getSlot(pos))
  31. {
  32. if(si->getArt() && (!excludeLocked || !si->locked))
  33. return si->getArt()->getId();
  34. }
  35. return {};
  36. }
  37. ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const
  38. {
  39. for(const auto & [slot, slotInfo] : artifactsWorn)
  40. {
  41. if(slotInfo.getArt()->getTypeId() == aid && (allowLocked || !slotInfo.locked))
  42. return slot;
  43. }
  44. if(!onlyWorn)
  45. {
  46. size_t backpackPositionIdx = ArtifactPosition::BACKPACK_START;
  47. for(const auto & artInfo : artifactsInBackpack)
  48. {
  49. const auto art = artInfo.getArt();
  50. if(art && art->getType()->getId() == aid)
  51. return ArtifactPosition(backpackPositionIdx);
  52. backpackPositionIdx++;
  53. }
  54. }
  55. return ArtifactPosition::PRE_FIRST;
  56. }
  57. bool CArtifactSet::hasScroll(const SpellID & spellID, bool onlyWorn) const
  58. {
  59. return getScrollPos(spellID, onlyWorn) != ArtifactPosition::PRE_FIRST;
  60. }
  61. ArtifactPosition CArtifactSet::getScrollPos(const SpellID & spellID, bool onlyWorn) const
  62. {
  63. for (const auto & slot : artifactsWorn)
  64. if (slot.second.getArt() && slot.second.getArt()->isScroll() && slot.second.getArt()->getScrollSpellID() == spellID)
  65. return slot.first;
  66. if (!onlyWorn)
  67. {
  68. size_t backpackPositionIdx = ArtifactPosition::BACKPACK_START;
  69. for (const auto & slot : artifactsInBackpack)
  70. {
  71. if (slot.getArt() && slot.getArt()->isScroll() && slot.getArt()->getScrollSpellID() == spellID)
  72. return ArtifactPosition(backpackPositionIdx);
  73. backpackPositionIdx++;
  74. }
  75. }
  76. return ArtifactPosition::PRE_FIRST;
  77. }
  78. const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const
  79. {
  80. for(const auto & i : artifactsWorn)
  81. if(i.second.getArt()->getId() == artInstId)
  82. return i.second.getArt();
  83. for(const auto & i : artifactsInBackpack)
  84. if(i.getArt()->getId() == artInstId)
  85. return i.getArt();
  86. return nullptr;
  87. }
  88. ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance * artInst) const
  89. {
  90. if(artInst)
  91. {
  92. for(const auto & slot : artInst->getType()->getPossibleSlots().at(bearerType()))
  93. if(getArt(slot) == artInst)
  94. return slot;
  95. ArtifactPosition backpackSlot = ArtifactPosition::BACKPACK_START;
  96. for(auto & slotInfo : artifactsInBackpack)
  97. {
  98. if(slotInfo.getArt() == artInst)
  99. return backpackSlot;
  100. backpackSlot = ArtifactPosition(backpackSlot + 1);
  101. }
  102. }
  103. return ArtifactPosition::PRE_FIRST;
  104. }
  105. bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchCombinedParts) const
  106. {
  107. if(searchCombinedParts && getCombinedArtWithPart(aid))
  108. return true;
  109. if(getArtPos(aid, onlyWorn, searchCombinedParts) != ArtifactPosition::PRE_FIRST)
  110. return true;
  111. return false;
  112. }
  113. CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art)
  114. {
  115. ArtPlacementMap resArtPlacement;
  116. const auto putToSlot = [this](const ArtifactPosition & targetSlot, const CArtifactInstance * targetArt, bool locked)
  117. {
  118. ArtSlotInfo newSlot(targetArt, locked);
  119. if(targetSlot == ArtifactPosition::TRANSITION_POS)
  120. {
  121. artifactsTransitionPos = newSlot;
  122. }
  123. else if(ArtifactUtils::isSlotEquipment(targetSlot))
  124. {
  125. artifactsWorn.insert_or_assign(targetSlot, newSlot);
  126. }
  127. else
  128. {
  129. auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START;
  130. artifactsInBackpack.insert(position, newSlot);
  131. }
  132. };
  133. putToSlot(slot, art, false);
  134. if(art->getType()->isCombined() && ArtifactUtils::isSlotEquipment(slot))
  135. {
  136. const CArtifactInstance * mainPart = nullptr;
  137. for(const auto & part : art->getPartsInfo())
  138. if(vstd::contains(part.getArtifact()->getType()->getPossibleSlots().at(bearerType()), slot)
  139. && (part.slot == ArtifactPosition::PRE_FIRST))
  140. {
  141. mainPart = part.getArtifact();
  142. break;
  143. }
  144. for(const auto & part : art->getPartsInfo())
  145. {
  146. if(part.getArtifact() != mainPart)
  147. {
  148. auto partSlot = part.slot;
  149. if(!part.getArtifact()->getType()->canBePutAt(this, partSlot))
  150. partSlot = ArtifactUtils::getArtAnyPosition(this, part.getArtifact()->getTypeId());
  151. assert(ArtifactUtils::isSlotEquipment(partSlot));
  152. putToSlot(partSlot, part.getArtifact(), true);
  153. resArtPlacement.emplace(part.getArtifact(), partSlot);
  154. }
  155. else
  156. {
  157. resArtPlacement.emplace(part.getArtifact(), part.slot);
  158. }
  159. }
  160. }
  161. return resArtPlacement;
  162. }
  163. CArtifactSet::CArtifactSet(IGameInfoCallback * cb)
  164. :artifactsTransitionPos(cb)
  165. {}
  166. void CArtifactSet::removeArtifact(const ArtifactPosition & slot)
  167. {
  168. const auto eraseArtSlot = [this](const ArtifactPosition & slotForErase)
  169. {
  170. if(slotForErase == ArtifactPosition::TRANSITION_POS)
  171. {
  172. artifactsTransitionPos.artifactID = {};
  173. }
  174. else if(ArtifactUtils::isSlotBackpack(slotForErase))
  175. {
  176. auto backpackSlot = ArtifactPosition(slotForErase - ArtifactPosition::BACKPACK_START);
  177. assert(artifactsInBackpack.begin() + backpackSlot < artifactsInBackpack.end());
  178. artifactsInBackpack.erase(artifactsInBackpack.begin() + backpackSlot);
  179. }
  180. else
  181. {
  182. artifactsWorn.erase(slotForErase);
  183. }
  184. };
  185. if(const auto art = getArt(slot, false))
  186. {
  187. if(art->isCombined())
  188. {
  189. for(const auto & part : art->getPartsInfo())
  190. {
  191. if(part.slot != ArtifactPosition::PRE_FIRST)
  192. {
  193. assert(getArt(part.slot, false));
  194. assert(getArt(part.slot, false) == part.getArtifact());
  195. }
  196. eraseArtSlot(part.slot);
  197. }
  198. }
  199. eraseArtSlot(slot);
  200. }
  201. }
  202. const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID & partId) const
  203. {
  204. for(const auto & slot : artifactsWorn)
  205. {
  206. auto art = slot.second.getArt();
  207. if(art->isCombined())
  208. {
  209. for(auto & ci : art->getPartsInfo())
  210. {
  211. if(ci.getArtifact()->getTypeId() == partId)
  212. return art;
  213. }
  214. }
  215. }
  216. for(const auto & slot : artifactsInBackpack)
  217. {
  218. auto art = slot.getArt();
  219. if(art->isCombined())
  220. {
  221. for(auto & ci : art->getPartsInfo())
  222. {
  223. if(ci.getArtifact()->getTypeId() == partId)
  224. return art;
  225. }
  226. }
  227. }
  228. return nullptr;
  229. }
  230. const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
  231. {
  232. if(pos == ArtifactPosition::TRANSITION_POS)
  233. return &artifactsTransitionPos;
  234. if(vstd::contains(artifactsWorn, pos))
  235. return &artifactsWorn.at(pos);
  236. if(ArtifactUtils::isSlotBackpack(pos))
  237. {
  238. auto backpackPos = pos - ArtifactPosition::BACKPACK_START;
  239. if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
  240. return nullptr;
  241. else
  242. return &artifactsInBackpack[backpackPos];
  243. }
  244. return nullptr;
  245. }
  246. void CArtifactSet::lockSlot(const ArtifactPosition & pos)
  247. {
  248. if(pos == ArtifactPosition::TRANSITION_POS)
  249. artifactsTransitionPos.locked = true;
  250. else if(ArtifactUtils::isSlotEquipment(pos))
  251. artifactsWorn.at(pos).locked = true;
  252. else
  253. {
  254. assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START);
  255. (artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true;
  256. }
  257. }
  258. bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const
  259. {
  260. if(bearerType() == ArtBearer::ALTAR)
  261. return artifactsInBackpack.size() < GameConstants::ALTAR_ARTIFACTS_SLOTS;
  262. if(const ArtSlotInfo *s = getSlot(pos))
  263. return (onlyLockCheck || !s->getID().hasValue()) && !s->locked;
  264. return true; //no slot means not used
  265. }
  266. void CArtifactSet::artDeserializationFix(CGameState & gs, CBonusSystemNode *node)
  267. {
  268. for(auto & elem : artifactsWorn)
  269. if(elem.second.artifactID.hasValue() && !elem.second.locked)
  270. node->attachToSource(*gs.getArtInstance(elem.second.artifactID));
  271. }
  272. void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
  273. {
  274. //todo: creature and commander artifacts
  275. if(handler.saving && artifactsInBackpack.empty() && artifactsWorn.empty())
  276. return;
  277. if(!handler.saving)
  278. {
  279. artifactsInBackpack.clear();
  280. artifactsWorn.clear();
  281. }
  282. auto s = handler.enterStruct(fieldName);
  283. switch(bearerType())
  284. {
  285. case ArtBearer::HERO:
  286. serializeJsonHero(handler, map);
  287. break;
  288. case ArtBearer::CREATURE:
  289. serializeJsonCreature(handler);
  290. break;
  291. case ArtBearer::COMMANDER:
  292. serializeJsonCommander(handler);
  293. break;
  294. default:
  295. assert(false);
  296. break;
  297. }
  298. }
  299. void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
  300. {
  301. for(const auto & slot : ArtifactUtils::allWornSlots())
  302. {
  303. serializeJsonSlot(handler, slot, map);
  304. }
  305. std::vector<ArtifactID> backpackTemp;
  306. if(handler.saving)
  307. {
  308. backpackTemp.reserve(artifactsInBackpack.size());
  309. for(const ArtSlotInfo & info : artifactsInBackpack)
  310. backpackTemp.push_back(info.getArt()->getTypeId());
  311. }
  312. handler.serializeIdArray(NArtifactPosition::backpack, backpackTemp);
  313. if(!handler.saving)
  314. {
  315. for(const ArtifactID & artifactID : backpackTemp)
  316. {
  317. auto * artifact = map->createArtifact(artifactID);
  318. auto slot = ArtifactPosition::BACKPACK_START + artifactsInBackpack.size();
  319. if(artifact->getType()->canBePutAt(this, slot))
  320. {
  321. auto artsMap = putArtifact(slot, artifact);
  322. artifact->addPlacementMap(artsMap);
  323. }
  324. }
  325. }
  326. }
  327. void CArtifactSet::serializeJsonCreature(JsonSerializeFormat & handler)
  328. {
  329. logGlobal->error("CArtifactSet::serializeJsonCreature not implemented");
  330. }
  331. void CArtifactSet::serializeJsonCommander(JsonSerializeFormat & handler)
  332. {
  333. logGlobal->error("CArtifactSet::serializeJsonCommander not implemented");
  334. }
  335. void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map)
  336. {
  337. ArtifactID artifactID;
  338. if(handler.saving)
  339. {
  340. const ArtSlotInfo * info = getSlot(slot);
  341. if(info != nullptr && !info->locked)
  342. {
  343. artifactID = info->getArt()->getTypeId();
  344. handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
  345. }
  346. }
  347. else
  348. {
  349. handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
  350. if(artifactID != ArtifactID::NONE)
  351. {
  352. auto * artifact = map->createArtifact(artifactID.toEnum());
  353. if(artifact->getType()->canBePutAt(this, slot))
  354. {
  355. auto artsMap = putArtifact(slot, artifact);
  356. artifact->addPlacementMap(artsMap);
  357. }
  358. else
  359. {
  360. logGlobal->debug("Artifact can't be put at the specified location."); //TODO add more debugging information
  361. }
  362. }
  363. }
  364. }
  365. VCMI_LIB_NAMESPACE_END