CArtifactSet.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  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(IGameCallback * 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 : artifactsInBackpack)
  205. {
  206. auto art = slot.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. return nullptr;
  217. }
  218. const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
  219. {
  220. if(pos == ArtifactPosition::TRANSITION_POS)
  221. return &artifactsTransitionPos;
  222. if(vstd::contains(artifactsWorn, pos))
  223. return &artifactsWorn.at(pos);
  224. if(ArtifactUtils::isSlotBackpack(pos))
  225. {
  226. auto backpackPos = pos - ArtifactPosition::BACKPACK_START;
  227. if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
  228. return nullptr;
  229. else
  230. return &artifactsInBackpack[backpackPos];
  231. }
  232. return nullptr;
  233. }
  234. void CArtifactSet::lockSlot(const ArtifactPosition & pos)
  235. {
  236. if(pos == ArtifactPosition::TRANSITION_POS)
  237. artifactsTransitionPos.locked = true;
  238. else if(ArtifactUtils::isSlotEquipment(pos))
  239. artifactsWorn.at(pos).locked = true;
  240. else
  241. {
  242. assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START);
  243. (artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true;
  244. }
  245. }
  246. bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const
  247. {
  248. if(bearerType() == ArtBearer::ALTAR)
  249. return artifactsInBackpack.size() < GameConstants::ALTAR_ARTIFACTS_SLOTS;
  250. if(const ArtSlotInfo *s = getSlot(pos))
  251. return (onlyLockCheck || !s->getID().hasValue()) && !s->locked;
  252. return true; //no slot means not used
  253. }
  254. void CArtifactSet::artDeserializationFix(CGameState & gs, CBonusSystemNode *node)
  255. {
  256. for(auto & elem : artifactsWorn)
  257. if(elem.second.artifactID.hasValue() && !elem.second.locked)
  258. node->attachToSource(*gs.getArtInstance(elem.second.artifactID));
  259. }
  260. void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
  261. {
  262. //todo: creature and commander artifacts
  263. if(handler.saving && artifactsInBackpack.empty() && artifactsWorn.empty())
  264. return;
  265. if(!handler.saving)
  266. {
  267. artifactsInBackpack.clear();
  268. artifactsWorn.clear();
  269. }
  270. auto s = handler.enterStruct(fieldName);
  271. switch(bearerType())
  272. {
  273. case ArtBearer::HERO:
  274. serializeJsonHero(handler, map);
  275. break;
  276. case ArtBearer::CREATURE:
  277. serializeJsonCreature(handler);
  278. break;
  279. case ArtBearer::COMMANDER:
  280. serializeJsonCommander(handler);
  281. break;
  282. default:
  283. assert(false);
  284. break;
  285. }
  286. }
  287. void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
  288. {
  289. for(const auto & slot : ArtifactUtils::allWornSlots())
  290. {
  291. serializeJsonSlot(handler, slot, map);
  292. }
  293. std::vector<ArtifactID> backpackTemp;
  294. if(handler.saving)
  295. {
  296. backpackTemp.reserve(artifactsInBackpack.size());
  297. for(const ArtSlotInfo & info : artifactsInBackpack)
  298. backpackTemp.push_back(info.getArt()->getTypeId());
  299. }
  300. handler.serializeIdArray(NArtifactPosition::backpack, backpackTemp);
  301. if(!handler.saving)
  302. {
  303. for(const ArtifactID & artifactID : backpackTemp)
  304. {
  305. auto * artifact = map->createArtifact(artifactID);
  306. auto slot = ArtifactPosition::BACKPACK_START + artifactsInBackpack.size();
  307. if(artifact->getType()->canBePutAt(this, slot))
  308. {
  309. auto artsMap = putArtifact(slot, artifact);
  310. artifact->addPlacementMap(artsMap);
  311. }
  312. }
  313. }
  314. }
  315. void CArtifactSet::serializeJsonCreature(JsonSerializeFormat & handler)
  316. {
  317. logGlobal->error("CArtifactSet::serializeJsonCreature not implemented");
  318. }
  319. void CArtifactSet::serializeJsonCommander(JsonSerializeFormat & handler)
  320. {
  321. logGlobal->error("CArtifactSet::serializeJsonCommander not implemented");
  322. }
  323. void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map)
  324. {
  325. ArtifactID artifactID;
  326. if(handler.saving)
  327. {
  328. const ArtSlotInfo * info = getSlot(slot);
  329. if(info != nullptr && !info->locked)
  330. {
  331. artifactID = info->getArt()->getTypeId();
  332. handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
  333. }
  334. }
  335. else
  336. {
  337. handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
  338. if(artifactID != ArtifactID::NONE)
  339. {
  340. auto * artifact = map->createArtifact(artifactID.toEnum());
  341. if(artifact->getType()->canBePutAt(this, slot))
  342. {
  343. auto artsMap = putArtifact(slot, artifact);
  344. artifact->addPlacementMap(artsMap);
  345. }
  346. else
  347. {
  348. logGlobal->debug("Artifact can't be put at the specified location."); //TODO add more debugging information
  349. }
  350. }
  351. }
  352. }
  353. VCMI_LIB_NAMESPACE_END