Bonus.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * Bonus.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 "Bonus.h"
  12. #include "CBonusSystemNode.h"
  13. #include "Limiters.h"
  14. #include "Updaters.h"
  15. #include "Propagators.h"
  16. #include "../VCMI_Lib.h"
  17. #include "../spells/CSpellHandler.h"
  18. #include "../CCreatureHandler.h"
  19. #include "../CCreatureSet.h"
  20. #include "../CHeroHandler.h"
  21. #include "../CTownHandler.h"
  22. #include "../CGeneralTextHandler.h"
  23. #include "../CSkillHandler.h"
  24. #include "../CArtHandler.h"
  25. #include "../TerrainHandler.h"
  26. #include "../StringConstants.h"
  27. #include "../battle/BattleInfo.h"
  28. #include "../modding/ModUtility.h"
  29. VCMI_LIB_NAMESPACE_BEGIN
  30. //This constructor should be placed here to avoid side effects
  31. CAddInfo::CAddInfo() = default;
  32. CAddInfo::CAddInfo(si32 value)
  33. {
  34. if(value != CAddInfo::NONE)
  35. push_back(value);
  36. }
  37. bool CAddInfo::operator==(si32 value) const
  38. {
  39. switch(size())
  40. {
  41. case 0:
  42. return value == CAddInfo::NONE;
  43. case 1:
  44. return operator[](0) == value;
  45. default:
  46. return false;
  47. }
  48. }
  49. bool CAddInfo::operator!=(si32 value) const
  50. {
  51. return !operator==(value);
  52. }
  53. si32 & CAddInfo::operator[](size_type pos)
  54. {
  55. if(pos >= size())
  56. resize(pos + 1, CAddInfo::NONE);
  57. return vector::operator[](pos);
  58. }
  59. si32 CAddInfo::operator[](size_type pos) const
  60. {
  61. return pos < size() ? vector::operator[](pos) : CAddInfo::NONE;
  62. }
  63. std::string CAddInfo::toString() const
  64. {
  65. return toJsonNode().toJson(true);
  66. }
  67. JsonNode CAddInfo::toJsonNode() const
  68. {
  69. if(size() < 2)
  70. {
  71. return JsonUtils::intNode(operator[](0));
  72. }
  73. else
  74. {
  75. JsonNode node(JsonNode::JsonType::DATA_VECTOR);
  76. for(si32 value : *this)
  77. node.Vector().push_back(JsonUtils::intNode(value));
  78. return node;
  79. }
  80. }
  81. std::string Bonus::Description(std::optional<si32> customValue) const
  82. {
  83. std::ostringstream str;
  84. if(description.empty())
  85. {
  86. if(stacking.empty() || stacking == "ALWAYS")
  87. {
  88. switch(source)
  89. {
  90. case BonusSource::ARTIFACT:
  91. str << ArtifactID(sid).toArtifact(VLC->artifacts())->getNameTranslated();
  92. break;
  93. case BonusSource::SPELL_EFFECT:
  94. str << SpellID(sid).toSpell(VLC->spells())->getNameTranslated();
  95. break;
  96. case BonusSource::CREATURE_ABILITY:
  97. str << CreatureID(sid).toCreature(VLC->creatures())->getNamePluralTranslated();
  98. break;
  99. case BonusSource::SECONDARY_SKILL:
  100. str << VLC->skills()->getByIndex(sid)->getNameTranslated();
  101. break;
  102. case BonusSource::HERO_SPECIAL:
  103. str << VLC->heroTypes()->getByIndex(sid)->getNameTranslated();
  104. break;
  105. default:
  106. //todo: handle all possible sources
  107. str << "Unknown";
  108. break;
  109. }
  110. }
  111. else
  112. str << stacking;
  113. }
  114. else
  115. {
  116. str << description;
  117. }
  118. if(auto value = customValue.value_or(val))
  119. str << " " << std::showpos << value;
  120. return str.str();
  121. }
  122. static JsonNode subtypeToJson(BonusType type, int subtype)
  123. {
  124. switch(type)
  125. {
  126. case BonusType::PRIMARY_SKILL:
  127. return JsonUtils::stringNode("primSkill." + NPrimarySkill::names[subtype]);
  128. case BonusType::SPECIAL_SPELL_LEV:
  129. case BonusType::SPECIFIC_SPELL_DAMAGE:
  130. case BonusType::SPELL:
  131. case BonusType::SPECIAL_PECULIAR_ENCHANT:
  132. case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
  133. case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
  134. return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "spell", SpellID::encode(subtype)));
  135. case BonusType::IMPROVED_NECROMANCY:
  136. case BonusType::SPECIAL_UPGRADE:
  137. return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(subtype)));
  138. case BonusType::GENERATE_RESOURCE:
  139. return JsonUtils::stringNode("resource." + GameConstants::RESOURCE_NAMES[subtype]);
  140. default:
  141. return JsonUtils::intNode(subtype);
  142. }
  143. }
  144. static JsonNode additionalInfoToJson(BonusType type, CAddInfo addInfo)
  145. {
  146. switch(type)
  147. {
  148. case BonusType::SPECIAL_UPGRADE:
  149. return JsonUtils::stringNode(ModUtility::makeFullIdentifier("", "creature", CreatureID::encode(addInfo[0])));
  150. default:
  151. return addInfo.toJsonNode();
  152. }
  153. }
  154. JsonNode Bonus::toJsonNode() const
  155. {
  156. JsonNode root(JsonNode::JsonType::DATA_STRUCT);
  157. // only add values that might reasonably be found in config files
  158. root["type"].String() = vstd::findKey(bonusNameMap, type);
  159. if(subtype != -1)
  160. root["subtype"] = subtypeToJson(type, subtype);
  161. if(additionalInfo != CAddInfo::NONE)
  162. root["addInfo"] = additionalInfoToJson(type, additionalInfo);
  163. if(turnsRemain != 0)
  164. root["turns"].Integer() = turnsRemain;
  165. if(source != BonusSource::OTHER)
  166. root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
  167. if(targetSourceType != BonusSource::OTHER)
  168. root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
  169. if(sid != 0)
  170. root["sourceID"].Integer() = sid;
  171. if(val != 0)
  172. root["val"].Integer() = val;
  173. if(valType != BonusValueType::ADDITIVE_VALUE)
  174. root["valueType"].String() = vstd::findKey(bonusValueMap, valType);
  175. if(!stacking.empty())
  176. root["stacking"].String() = stacking;
  177. if(!description.empty())
  178. root["description"].String() = description;
  179. if(effectRange != BonusLimitEffect::NO_LIMIT)
  180. root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
  181. if(duration != BonusDuration::PERMANENT)
  182. root["duration"] = BonusDuration::toJson(duration);
  183. if(turnsRemain)
  184. root["turns"].Integer() = turnsRemain;
  185. if(limiter)
  186. root["limiters"] = limiter->toJsonNode();
  187. if(updater)
  188. root["updater"] = updater->toJsonNode();
  189. if(propagator)
  190. root["propagator"].String() = vstd::findKey(bonusPropagatorMap, propagator);
  191. return root;
  192. }
  193. Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype):
  194. duration(Duration),
  195. type(Type),
  196. subtype(Subtype),
  197. source(Src),
  198. val(Val),
  199. sid(ID),
  200. description(std::move(Desc))
  201. {
  202. boost::algorithm::trim(description);
  203. targetSourceType = BonusSource::OTHER;
  204. }
  205. Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype, BonusValueType ValType):
  206. duration(Duration),
  207. type(Type),
  208. subtype(Subtype),
  209. source(Src),
  210. val(Val),
  211. sid(ID),
  212. valType(ValType)
  213. {
  214. turnsRemain = 0;
  215. effectRange = BonusLimitEffect::NO_LIMIT;
  216. targetSourceType = BonusSource::OTHER;
  217. }
  218. std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
  219. {
  220. propagator = Propagator;
  221. return this->shared_from_this();
  222. }
  223. DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
  224. {
  225. for(const auto & i : bonusNameMap)
  226. if(i.second == bonus.type)
  227. out << "\tType: " << i.first << " \t";
  228. #define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
  229. printField(val);
  230. printField(subtype);
  231. printField(duration.to_ulong());
  232. printField(source);
  233. printField(sid);
  234. if(bonus.additionalInfo != CAddInfo::NONE)
  235. out << "\taddInfo: " << bonus.additionalInfo.toString() << "\n";
  236. printField(turnsRemain);
  237. printField(valType);
  238. if(!bonus.stacking.empty())
  239. out << "\tstacking: \"" << bonus.stacking << "\"\n";
  240. printField(effectRange);
  241. #undef printField
  242. if(bonus.limiter)
  243. out << "\tLimiter: " << bonus.limiter->toString() << "\n";
  244. if(bonus.updater)
  245. out << "\tUpdater: " << bonus.updater->toString() << "\n";
  246. return out;
  247. }
  248. std::shared_ptr<Bonus> Bonus::addLimiter(const TLimiterPtr & Limiter)
  249. {
  250. if (limiter)
  251. {
  252. //If we already have limiter list, retrieve it
  253. auto limiterList = std::dynamic_pointer_cast<AllOfLimiter>(limiter);
  254. if(!limiterList)
  255. {
  256. //Create a new limiter list with old limiter and the new one will be pushed later
  257. limiterList = std::make_shared<AllOfLimiter>();
  258. limiterList->add(limiter);
  259. limiter = limiterList;
  260. }
  261. limiterList->add(Limiter);
  262. }
  263. else
  264. {
  265. limiter = Limiter;
  266. }
  267. return this->shared_from_this();
  268. }
  269. // Updaters
  270. std::shared_ptr<Bonus> Bonus::addUpdater(const TUpdaterPtr & Updater)
  271. {
  272. updater = Updater;
  273. return this->shared_from_this();
  274. }
  275. VCMI_LIB_NAMESPACE_END