CArtifactSet.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const
  58. {
  59. for(const auto & i : artifactsWorn)
  60. if(i.second.getArt()->getId() == artInstId)
  61. return i.second.getArt();
  62. for(const auto & i : artifactsInBackpack)
  63. if(i.getArt()->getId() == artInstId)
  64. return i.getArt();
  65. return nullptr;
  66. }
  67. ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance * artInst) const
  68. {
  69. if(artInst)
  70. {
  71. for(const auto & slot : artInst->getType()->getPossibleSlots().at(bearerType()))
  72. if(getArt(slot) == artInst)
  73. return slot;
  74. ArtifactPosition backpackSlot = ArtifactPosition::BACKPACK_START;
  75. for(auto & slotInfo : artifactsInBackpack)
  76. {
  77. if(slotInfo.getArt() == artInst)
  78. return backpackSlot;
  79. backpackSlot = ArtifactPosition(backpackSlot + 1);
  80. }
  81. }
  82. return ArtifactPosition::PRE_FIRST;
  83. }
  84. bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchCombinedParts) const
  85. {
  86. if(searchCombinedParts && getCombinedArtWithPart(aid))
  87. return true;
  88. if(getArtPos(aid, onlyWorn, searchCombinedParts) != ArtifactPosition::PRE_FIRST)
  89. return true;
  90. return false;
  91. }
  92. CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art)
  93. {
  94. ArtPlacementMap resArtPlacement;
  95. const auto putToSlot = [this](const ArtifactPosition & targetSlot, const CArtifactInstance * targetArt, bool locked)
  96. {
  97. ArtSlotInfo newSlot(targetArt, locked);
  98. if(targetSlot == ArtifactPosition::TRANSITION_POS)
  99. {
  100. artifactsTransitionPos = newSlot;
  101. }
  102. else if(ArtifactUtils::isSlotEquipment(targetSlot))
  103. {
  104. artifactsWorn.insert_or_assign(targetSlot, newSlot);
  105. }
  106. else
  107. {
  108. auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START;
  109. artifactsInBackpack.insert(position, newSlot);
  110. }
  111. };
  112. putToSlot(slot, art, false);
  113. if(art->getType()->isCombined() && ArtifactUtils::isSlotEquipment(slot))
  114. {
  115. const CArtifactInstance * mainPart = nullptr;
  116. for(const auto & part : art->getPartsInfo())
  117. if(vstd::contains(part.getArtifact()->getType()->getPossibleSlots().at(bearerType()), slot)
  118. && (part.slot == ArtifactPosition::PRE_FIRST))
  119. {
  120. mainPart = part.getArtifact();
  121. break;
  122. }
  123. for(const auto & part : art->getPartsInfo())
  124. {
  125. if(part.getArtifact() != mainPart)
  126. {
  127. auto partSlot = part.slot;
  128. if(!part.getArtifact()->getType()->canBePutAt(this, partSlot))
  129. partSlot = ArtifactUtils::getArtAnyPosition(this, part.getArtifact()->getTypeId());
  130. assert(ArtifactUtils::isSlotEquipment(partSlot));
  131. putToSlot(partSlot, part.getArtifact(), true);
  132. resArtPlacement.emplace(part.getArtifact(), partSlot);
  133. }
  134. else
  135. {
  136. resArtPlacement.emplace(part.getArtifact(), part.slot);
  137. }
  138. }
  139. }
  140. return resArtPlacement;
  141. }
  142. CArtifactSet::CArtifactSet(IGameCallback * cb)
  143. :artifactsTransitionPos(cb)
  144. {}
  145. void CArtifactSet::removeArtifact(const ArtifactPosition & slot)
  146. {
  147. const auto eraseArtSlot = [this](const ArtifactPosition & slotForErase)
  148. {
  149. if(slotForErase == ArtifactPosition::TRANSITION_POS)
  150. {
  151. artifactsTransitionPos.artifactID = {};
  152. }
  153. else if(ArtifactUtils::isSlotBackpack(slotForErase))
  154. {
  155. auto backpackSlot = ArtifactPosition(slotForErase - ArtifactPosition::BACKPACK_START);
  156. assert(artifactsInBackpack.begin() + backpackSlot < artifactsInBackpack.end());
  157. artifactsInBackpack.erase(artifactsInBackpack.begin() + backpackSlot);
  158. }
  159. else
  160. {
  161. artifactsWorn.erase(slotForErase);
  162. }
  163. };
  164. if(const auto art = getArt(slot, false))
  165. {
  166. if(art->isCombined())
  167. {
  168. for(const auto & part : art->getPartsInfo())
  169. {
  170. if(part.slot != ArtifactPosition::PRE_FIRST)
  171. {
  172. assert(getArt(part.slot, false));
  173. assert(getArt(part.slot, false) == part.getArtifact());
  174. }
  175. eraseArtSlot(part.slot);
  176. }
  177. }
  178. eraseArtSlot(slot);
  179. }
  180. }
  181. const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID & partId) const
  182. {
  183. for(const auto & slot : artifactsInBackpack)
  184. {
  185. auto art = slot.getArt();
  186. if(art->isCombined())
  187. {
  188. for(auto & ci : art->getPartsInfo())
  189. {
  190. if(ci.getArtifact()->getTypeId() == partId)
  191. return art;
  192. }
  193. }
  194. }
  195. return nullptr;
  196. }
  197. const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
  198. {
  199. if(pos == ArtifactPosition::TRANSITION_POS)
  200. return &artifactsTransitionPos;
  201. if(vstd::contains(artifactsWorn, pos))
  202. return &artifactsWorn.at(pos);
  203. if(ArtifactUtils::isSlotBackpack(pos))
  204. {
  205. auto backpackPos = pos - ArtifactPosition::BACKPACK_START;
  206. if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
  207. return nullptr;
  208. else
  209. return &artifactsInBackpack[backpackPos];
  210. }
  211. return nullptr;
  212. }
  213. void CArtifactSet::lockSlot(const ArtifactPosition & pos)
  214. {
  215. if(pos == ArtifactPosition::TRANSITION_POS)
  216. artifactsTransitionPos.locked = true;
  217. else if(ArtifactUtils::isSlotEquipment(pos))
  218. artifactsWorn.at(pos).locked = true;
  219. else
  220. {
  221. assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START);
  222. (artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true;
  223. }
  224. }
  225. bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const
  226. {
  227. if(bearerType() == ArtBearer::ALTAR)
  228. return artifactsInBackpack.size() < GameConstants::ALTAR_ARTIFACTS_SLOTS;
  229. if(const ArtSlotInfo *s = getSlot(pos))
  230. return (onlyLockCheck || !s->getArt()) && !s->locked;
  231. return true; //no slot means not used
  232. }
  233. void CArtifactSet::artDeserializationFix(CGameState & gs, CBonusSystemNode *node)
  234. {
  235. for(auto & elem : artifactsWorn)
  236. if(elem.second.artifactID.hasValue() && !elem.second.locked)
  237. node->attachToSource(*gs.getArtInstance(elem.second.artifactID));
  238. }
  239. void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
  240. {
  241. //todo: creature and commander artifacts
  242. if(handler.saving && artifactsInBackpack.empty() && artifactsWorn.empty())
  243. return;
  244. if(!handler.saving)
  245. {
  246. artifactsInBackpack.clear();
  247. artifactsWorn.clear();
  248. }
  249. auto s = handler.enterStruct(fieldName);
  250. switch(bearerType())
  251. {
  252. case ArtBearer::HERO:
  253. serializeJsonHero(handler, map);
  254. break;
  255. case ArtBearer::CREATURE:
  256. serializeJsonCreature(handler);
  257. break;
  258. case ArtBearer::COMMANDER:
  259. serializeJsonCommander(handler);
  260. break;
  261. default:
  262. assert(false);
  263. break;
  264. }
  265. }
  266. void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
  267. {
  268. for(const auto & slot : ArtifactUtils::allWornSlots())
  269. {
  270. serializeJsonSlot(handler, slot, map);
  271. }
  272. std::vector<ArtifactID> backpackTemp;
  273. if(handler.saving)
  274. {
  275. backpackTemp.reserve(artifactsInBackpack.size());
  276. for(const ArtSlotInfo & info : artifactsInBackpack)
  277. backpackTemp.push_back(info.getArt()->getTypeId());
  278. }
  279. handler.serializeIdArray(NArtifactPosition::backpack, backpackTemp);
  280. if(!handler.saving)
  281. {
  282. for(const ArtifactID & artifactID : backpackTemp)
  283. {
  284. auto * artifact = map->createArtifact(artifactID);
  285. auto slot = ArtifactPosition::BACKPACK_START + artifactsInBackpack.size();
  286. if(artifact->getType()->canBePutAt(this, slot))
  287. {
  288. auto artsMap = putArtifact(slot, artifact);
  289. artifact->addPlacementMap(artsMap);
  290. }
  291. }
  292. }
  293. }
  294. void CArtifactSet::serializeJsonCreature(JsonSerializeFormat & handler)
  295. {
  296. logGlobal->error("CArtifactSet::serializeJsonCreature not implemented");
  297. }
  298. void CArtifactSet::serializeJsonCommander(JsonSerializeFormat & handler)
  299. {
  300. logGlobal->error("CArtifactSet::serializeJsonCommander not implemented");
  301. }
  302. void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map)
  303. {
  304. ArtifactID artifactID;
  305. if(handler.saving)
  306. {
  307. const ArtSlotInfo * info = getSlot(slot);
  308. if(info != nullptr && !info->locked)
  309. {
  310. artifactID = info->getArt()->getTypeId();
  311. handler.serializeId(NArtifactPosition::namesHero[slot.num], artifactID, ArtifactID::NONE);
  312. }
  313. }
  314. else
  315. {
  316. handler.serializeId(NArtifactPosition::namesHero[slot.num], artifactID, ArtifactID::NONE);
  317. if(artifactID != ArtifactID::NONE)
  318. {
  319. auto * artifact = map->createArtifact(artifactID.toEnum());
  320. if(artifact->getType()->canBePutAt(this, slot))
  321. {
  322. auto artsMap = putArtifact(slot, artifact);
  323. artifact->addPlacementMap(artsMap);
  324. }
  325. else
  326. {
  327. logGlobal->debug("Artifact can't be put at the specified location."); //TODO add more debugging information
  328. }
  329. }
  330. }
  331. }
  332. VCMI_LIB_NAMESPACE_END