Bonus.cpp 7.7 KB

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