ArtifactUtils.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /*
  2. * ArtifactUtils.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 "ArtifactUtils.h"
  11. #include "CArtHandler.h"
  12. #include "IGameSettings.h"
  13. #include "spells/CSpellHandler.h"
  14. #include "mapObjects/CGHeroInstance.h"
  15. VCMI_LIB_NAMESPACE_BEGIN
  16. DLL_LINKAGE bool ArtifactUtils::checkIfSlotValid(const CArtifactSet & artSet, const ArtifactPosition & slot)
  17. {
  18. if(artSet.bearerType() == ArtBearer::HERO)
  19. {
  20. if(isSlotEquipment(slot) || isSlotBackpack(slot) || slot == ArtifactPosition::TRANSITION_POS)
  21. return true;
  22. }
  23. else if(artSet.bearerType() == ArtBearer::ALTAR)
  24. {
  25. if(isSlotBackpack(slot))
  26. return true;
  27. }
  28. else if(artSet.bearerType() == ArtBearer::COMMANDER)
  29. {
  30. if(vstd::contains(commanderSlots(), slot))
  31. return true;
  32. }
  33. else if(artSet.bearerType() == ArtBearer::CREATURE)
  34. {
  35. if(slot == ArtifactPosition::CREATURE_SLOT)
  36. return true;
  37. }
  38. return false;
  39. }
  40. DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtAnyPosition(const CArtifactSet * target, const ArtifactID & aid)
  41. {
  42. if(auto targetSlot = getArtEquippedPosition(target, aid); targetSlot != ArtifactPosition::PRE_FIRST)
  43. return targetSlot;
  44. return getArtBackpackPosition(target, aid);
  45. }
  46. DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtEquippedPosition(const CArtifactSet * target, const ArtifactID & aid)
  47. {
  48. const auto * art = aid.toArtifact();
  49. for(const auto & slot : art->getPossibleSlots().at(target->bearerType()))
  50. {
  51. if(art->canBePutAt(target, slot))
  52. return slot;
  53. }
  54. return ArtifactPosition::PRE_FIRST;
  55. }
  56. DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid)
  57. {
  58. const auto * art = aid.toArtifact();
  59. if(target->bearerType() == ArtBearer::HERO)
  60. if(art->canBePutAt(target, ArtifactPosition::BACKPACK_START))
  61. {
  62. return ArtifactPosition::BACKPACK_START;
  63. }
  64. return ArtifactPosition::PRE_FIRST;
  65. }
  66. DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::unmovableSlots()
  67. {
  68. static const std::vector<ArtifactPosition> positions =
  69. {
  70. ArtifactPosition::SPELLBOOK,
  71. ArtifactPosition::MACH4
  72. };
  73. return positions;
  74. }
  75. DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commonWornSlots()
  76. {
  77. static const std::vector<ArtifactPosition> positions =
  78. {
  79. ArtifactPosition::HEAD,
  80. ArtifactPosition::SHOULDERS,
  81. ArtifactPosition::NECK,
  82. ArtifactPosition::RIGHT_HAND,
  83. ArtifactPosition::LEFT_HAND,
  84. ArtifactPosition::TORSO,
  85. ArtifactPosition::RIGHT_RING,
  86. ArtifactPosition::LEFT_RING,
  87. ArtifactPosition::FEET,
  88. ArtifactPosition::MISC1,
  89. ArtifactPosition::MISC2,
  90. ArtifactPosition::MISC3,
  91. ArtifactPosition::MISC4,
  92. ArtifactPosition::MISC5,
  93. };
  94. return positions;
  95. }
  96. DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::allWornSlots()
  97. {
  98. static const std::vector<ArtifactPosition> positions =
  99. {
  100. ArtifactPosition::HEAD,
  101. ArtifactPosition::SHOULDERS,
  102. ArtifactPosition::NECK,
  103. ArtifactPosition::RIGHT_HAND,
  104. ArtifactPosition::LEFT_HAND,
  105. ArtifactPosition::TORSO,
  106. ArtifactPosition::RIGHT_RING,
  107. ArtifactPosition::LEFT_RING,
  108. ArtifactPosition::FEET,
  109. ArtifactPosition::MISC1,
  110. ArtifactPosition::MISC2,
  111. ArtifactPosition::MISC3,
  112. ArtifactPosition::MISC4,
  113. ArtifactPosition::MISC5,
  114. ArtifactPosition::MACH1,
  115. ArtifactPosition::MACH2,
  116. ArtifactPosition::MACH3,
  117. ArtifactPosition::MACH4,
  118. ArtifactPosition::SPELLBOOK
  119. };
  120. return positions;
  121. }
  122. DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commanderSlots()
  123. {
  124. static const std::vector<ArtifactPosition> positions =
  125. {
  126. ArtifactPosition::COMMANDER1,
  127. ArtifactPosition::COMMANDER2,
  128. ArtifactPosition::COMMANDER3,
  129. ArtifactPosition::COMMANDER4,
  130. ArtifactPosition::COMMANDER5,
  131. ArtifactPosition::COMMANDER6
  132. };
  133. return positions;
  134. }
  135. DLL_LINKAGE bool ArtifactUtils::isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
  136. {
  137. return slot.second.artifact
  138. && !slot.second.locked
  139. && !vstd::contains(unmovableSlots(), slot.first);
  140. }
  141. DLL_LINKAGE bool ArtifactUtils::checkSpellbookIsNeeded(const CGHeroInstance * heroPtr, const ArtifactID & artID, const ArtifactPosition & slot)
  142. {
  143. // TODO what'll happen if Titan's thunder is equipped by pickin git up or the start of game?
  144. // Titan's Thunder creates new spellbook on equip
  145. if(artID == ArtifactID::TITANS_THUNDER && slot == ArtifactPosition::RIGHT_HAND)
  146. {
  147. if(heroPtr && !heroPtr->hasSpellbook())
  148. {
  149. return true;
  150. }
  151. }
  152. return false;
  153. }
  154. DLL_LINKAGE bool ArtifactUtils::isSlotBackpack(const ArtifactPosition & slot)
  155. {
  156. return slot >= ArtifactPosition::BACKPACK_START;
  157. }
  158. DLL_LINKAGE bool ArtifactUtils::isSlotEquipment(const ArtifactPosition & slot)
  159. {
  160. return slot < ArtifactPosition::BACKPACK_START && slot >= ArtifactPosition(0);
  161. }
  162. DLL_LINKAGE bool ArtifactUtils::isBackpackFreeSlots(const CArtifactSet * target, const size_t reqSlots)
  163. {
  164. if(target->bearerType() == ArtBearer::HERO)
  165. {
  166. const auto backpackCap = VLC->engineSettings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
  167. if(backpackCap < 0)
  168. return true;
  169. else
  170. return target->artifactsInBackpack.size() + reqSlots <= backpackCap;
  171. }
  172. else
  173. return false;
  174. }
  175. DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities(
  176. const CArtifactSet * artSet, const ArtifactID & aid, const bool onlyEquiped)
  177. {
  178. std::vector<const CArtifact*> arts;
  179. const auto * art = aid.toArtifact();
  180. if(art->isCombined())
  181. return arts;
  182. for(const auto artifact : art->getPartOf())
  183. {
  184. assert(artifact->isCombined());
  185. bool possible = true;
  186. for(const auto constituent : artifact->getConstituents()) //check if all constituents are available
  187. {
  188. if(!artSet->hasArt(constituent->getId(), onlyEquiped, false))
  189. {
  190. possible = false;
  191. break;
  192. }
  193. }
  194. if(possible)
  195. arts.push_back(artifact);
  196. }
  197. return arts;
  198. }
  199. DLL_LINKAGE CArtifactInstance * ArtifactUtils::createScroll(const SpellID & spellId)
  200. {
  201. return ArtifactUtils::createArtifact(ArtifactID::SPELL_SCROLL, spellId);
  202. }
  203. DLL_LINKAGE CArtifactInstance * ArtifactUtils::createArtifact(const ArtifactID & artId, const SpellID & spellId)
  204. {
  205. const std::function<CArtifactInstance*(const CArtifact*)> createArtInst =
  206. [&createArtInst, &spellId](const CArtifact * art) -> CArtifactInstance*
  207. {
  208. assert(art);
  209. auto * artInst = new CArtifactInstance(art);
  210. if(art->isCombined())
  211. {
  212. for(const auto & part : art->getConstituents())
  213. artInst->addPart(createArtInst(part), ArtifactPosition::PRE_FIRST);
  214. }
  215. if(art->isGrowing())
  216. {
  217. auto bonus = std::make_shared<Bonus>();
  218. bonus->type = BonusType::LEVEL_COUNTER;
  219. bonus->val = 0;
  220. artInst->addNewBonus(bonus);
  221. }
  222. if(art->isScroll())
  223. {
  224. artInst->addNewBonus(std::make_shared<Bonus>(BonusDuration::PERMANENT, BonusType::SPELL,
  225. BonusSource::ARTIFACT_INSTANCE, -1, BonusSourceID(ArtifactID(ArtifactID::SPELL_SCROLL)), BonusSubtypeID(spellId)));
  226. }
  227. return artInst;
  228. };
  229. if(artId.getNum() >= 0)
  230. {
  231. return createArtInst(artId.toArtifact());
  232. }
  233. else
  234. {
  235. return new CArtifactInstance(); // random, empty
  236. }
  237. }
  238. DLL_LINKAGE void ArtifactUtils::insertScrrollSpellName(std::string & description, const SpellID & sid)
  239. {
  240. // We expect scroll description to be like this: This scroll contains the [spell name] spell which is added
  241. // into spell book for as long as hero carries the scroll. So we want to replace text in [...] with a spell name.
  242. // However other language versions don't have name placeholder at all, so we have to be careful
  243. auto nameStart = description.find_first_of('[');
  244. auto nameEnd = description.find_first_of(']', nameStart);
  245. if(nameStart != std::string::npos && nameEnd != std::string::npos)
  246. {
  247. if(sid.getNum() >= 0)
  248. description = description.replace(nameStart, nameEnd - nameStart + 1, sid.toEntity(VLC->spells())->getNameTranslated());
  249. else
  250. description = description.erase(nameStart, nameEnd - nameStart + 2); // erase "[spell name] " - including space
  251. }
  252. }
  253. VCMI_LIB_NAMESPACE_END