Bonus.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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 "BonusParameters.h"
  13. #include "Limiters.h"
  14. #include "Updaters.h"
  15. #include "Propagators.h"
  16. #include "../CBonusTypeHandler.h"
  17. #include "../CCreatureHandler.h"
  18. #include "../CSkillHandler.h"
  19. #include "../TerrainHandler.h"
  20. #include "../GameLibrary.h"
  21. #include "../callback/IGameInfoCallback.h"
  22. #include "../mapObjects/CGObjectInstance.h"
  23. #include "../mapObjectConstructors/CObjectClassesHandler.h"
  24. #include "../battle/BattleInfo.h"
  25. #include "../constants/StringConstants.h"
  26. #include "../entities/hero/CHero.h"
  27. #include "../modding/ModUtility.h"
  28. #include "../spells/CSpellHandler.h"
  29. #include "../texts/CGeneralTextHandler.h"
  30. VCMI_LIB_NAMESPACE_BEGIN
  31. std::string Bonus::Description(const IGameInfoCallback * cb, std::optional<si32> customValue) const
  32. {
  33. MetaString descriptionHelper = description;
  34. auto valueToShow = customValue.value_or(val);
  35. if(descriptionHelper.empty())
  36. {
  37. // no custom description - try to generate one based on bonus source
  38. switch(source)
  39. {
  40. case BonusSource::ARTIFACT:
  41. descriptionHelper.appendName(sid.as<ArtifactID>());
  42. break;
  43. case BonusSource::SPELL_EFFECT:
  44. descriptionHelper.appendName(sid.as<SpellID>());
  45. break;
  46. case BonusSource::CREATURE_ABILITY:
  47. descriptionHelper.appendNamePlural(sid.as<CreatureID>());
  48. break;
  49. case BonusSource::SECONDARY_SKILL:
  50. descriptionHelper.appendTextID(sid.as<SecondarySkill>().toEntity(LIBRARY)->getNameTextID());
  51. break;
  52. case BonusSource::HERO_SPECIAL:
  53. descriptionHelper.appendTextID(sid.as<HeroTypeID>().toEntity(LIBRARY)->getNameTextID());
  54. break;
  55. case BonusSource::OBJECT_INSTANCE:
  56. const auto * object = cb->getObj(sid.as<ObjectInstanceID>());
  57. if (object)
  58. descriptionHelper.appendTextID(LIBRARY->objtypeh->getObjectName(object->ID, object->subID));
  59. }
  60. }
  61. if(descriptionHelper.empty())
  62. {
  63. // still no description - try to generate one based on duration
  64. if ((duration & BonusDuration::ONE_BATTLE) != 0)
  65. {
  66. if (val > 0)
  67. descriptionHelper.appendTextID("core.arraytxt.110"); //+%d Temporary until next battle"
  68. else
  69. descriptionHelper.appendTextID("core.arraytxt.109"); //-%d Temporary until next battle"
  70. // erase sign - already present in description string
  71. valueToShow = std::abs(valueToShow);
  72. }
  73. }
  74. if(descriptionHelper.empty())
  75. {
  76. // still no description - generate placeholder one
  77. descriptionHelper.appendRawString("Unknown");
  78. }
  79. if(valueToShow != 0)
  80. {
  81. descriptionHelper.replacePositiveNumber(valueToShow);
  82. // there is one known string that uses '%s' placeholder for bonus value:
  83. // "core.arraytxt.69" : "\nFountain of Fortune Visited %s",
  84. // So also add string replacement to handle this case
  85. descriptionHelper.replaceRawString(std::to_string(valueToShow));
  86. if(type == BonusType::CREATURE_GROWTH_PERCENT)
  87. descriptionHelper.appendRawString(" +" + std::to_string(valueToShow));
  88. }
  89. return descriptionHelper.toString();
  90. }
  91. JsonNode Bonus::toJsonNode() const
  92. {
  93. JsonNode root;
  94. // only add values that might reasonably be found in config files
  95. root["type"].String() = LIBRARY->bth->bonusToString(type);
  96. if(subtype != BonusSubtypeID())
  97. root["subtype"].String() = subtype.toString();
  98. if(parameters)
  99. root["addInfo"] = parameters->toJsonNode();
  100. if(source != BonusSource::OTHER)
  101. root["sourceType"].String() = vstd::findKey(bonusSourceMap, source);
  102. if(targetSourceType != BonusSource::OTHER)
  103. root["targetSourceType"].String() = vstd::findKey(bonusSourceMap, targetSourceType);
  104. if(sid != BonusSourceID())
  105. root["sourceID"].String() = sid.toString();
  106. if(val != 0)
  107. root["val"].Integer() = val;
  108. if(valType != BonusValueType::ADDITIVE_VALUE)
  109. root["valueType"].String() = vstd::findKey(bonusValueMap, valType);
  110. if(!stacking.empty())
  111. root["stacking"].String() = stacking;
  112. if(!description.empty())
  113. root["description"].String() = description.toString();
  114. if(effectRange != BonusLimitEffect::NO_LIMIT)
  115. root["effectRange"].String() = vstd::findKey(bonusLimitEffect, effectRange);
  116. if(duration != BonusDuration::PERMANENT)
  117. root["duration"] = BonusDuration::toJson(duration);
  118. if(turnsRemain)
  119. root["turns"].Integer() = turnsRemain;
  120. if(limiter)
  121. root["limiters"] = limiter->toJsonNode();
  122. if(updater)
  123. root["updater"] = updater->toJsonNode();
  124. if(propagator)
  125. root["propagator"].String() = vstd::findKey(bonusPropagatorMap, propagator);
  126. if(hidden)
  127. root["hidden"].Bool() = hidden;
  128. return root;
  129. }
  130. void Bonus::convertAddInfo(const std::vector<int> & oldAddInfo)
  131. {
  132. if (oldAddInfo.size() > 1)
  133. parameters = std::make_shared<BonusParameters>(oldAddInfo);
  134. if (oldAddInfo.size() == 1 && oldAddInfo[0] != -1)
  135. {
  136. if (type == BonusType::SPECIAL_UPGRADE || type == BonusType::TRANSMUTATION)
  137. parameters = std::make_shared<BonusParameters>(CreatureID(oldAddInfo[0]));
  138. else if (type == BonusType::DEATH_STARE)
  139. parameters = std::make_shared<BonusParameters>(SpellID(oldAddInfo[0]));
  140. else
  141. parameters = std::make_shared<BonusParameters>(oldAddInfo[0]);
  142. }
  143. }
  144. Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID)
  145. : Bonus(Duration, Type, Src, Val, ID, BonusSubtypeID())
  146. {}
  147. Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype):
  148. duration(Duration),
  149. type(Type),
  150. subtype(Subtype),
  151. source(Src),
  152. val(Val),
  153. sid(ID)
  154. {
  155. targetSourceType = BonusSource::OTHER;
  156. }
  157. Bonus::Bonus(BonusDuration::Type Duration, BonusType Type, BonusSource Src, si32 Val, BonusSourceID ID, BonusSubtypeID Subtype, BonusValueType ValType):
  158. duration(Duration),
  159. type(Type),
  160. subtype(Subtype),
  161. source(Src),
  162. val(Val),
  163. sid(ID),
  164. valType(ValType)
  165. {
  166. turnsRemain = 0;
  167. effectRange = BonusLimitEffect::NO_LIMIT;
  168. targetSourceType = BonusSource::OTHER;
  169. }
  170. Bonus::Bonus(const Bonus & inst, const BonusSourceID & sourceId)
  171. : Bonus(inst)
  172. {
  173. sid = sourceId;
  174. }
  175. std::shared_ptr<Bonus> Bonus::addPropagator(const TPropagatorPtr & Propagator)
  176. {
  177. propagator = Propagator;
  178. return this->shared_from_this();
  179. }
  180. DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
  181. {
  182. out << "\tType: " << LIBRARY->bth->bonusToString(bonus.type) << " \t";
  183. #define printField(field) out << "\t" #field ": " << (int)bonus.field << "\n"
  184. printField(val);
  185. out << "\tSubtype: " << bonus.subtype.toString() << "\n";
  186. printField(duration);
  187. printField(source);
  188. out << "\tSource ID: " << bonus.sid.toString() << "\n";
  189. if(bonus.parameters)
  190. out << "\taddInfo: " << bonus.parameters->toString() << "\n";
  191. printField(turnsRemain);
  192. printField(valType);
  193. if(!bonus.stacking.empty())
  194. out << "\tstacking: \"" << bonus.stacking << "\"\n";
  195. printField(effectRange);
  196. #undef printField
  197. if(bonus.limiter)
  198. out << "\tLimiter: " << bonus.limiter->toString() << "\n";
  199. if(bonus.updater)
  200. out << "\tUpdater: " << bonus.updater->toString() << "\n";
  201. return out;
  202. }
  203. std::shared_ptr<Bonus> Bonus::addLimiter(const TLimiterPtr & Limiter)
  204. {
  205. if (limiter)
  206. {
  207. auto newLimiterList = std::make_shared<AllOfLimiter>();
  208. auto oldLimiterList = std::dynamic_pointer_cast<const AllOfLimiter>(limiter);
  209. if(oldLimiterList)
  210. newLimiterList->limiters = oldLimiterList->limiters;
  211. newLimiterList->add(Limiter);
  212. limiter = newLimiterList;
  213. }
  214. else
  215. {
  216. limiter = Limiter;
  217. }
  218. return this->shared_from_this();
  219. }
  220. // Updaters
  221. static TUpdaterPtr appendToUpdaters(const TUpdaterPtr & current, const TUpdaterPtr & added)
  222. {
  223. if (!current)
  224. return added;
  225. auto newList = std::make_shared<CompositeUpdater>();
  226. auto oldList = std::dynamic_pointer_cast<const CompositeUpdater>(current);
  227. if(oldList)
  228. newList->updaters = oldList->updaters;
  229. newList->updaters.push_back(added);
  230. return newList;
  231. }
  232. std::shared_ptr<Bonus> Bonus::addUpdater(const TUpdaterPtr & newUpdater)
  233. {
  234. updater = appendToUpdaters(updater, newUpdater);
  235. return this->shared_from_this();
  236. }
  237. std::shared_ptr<Bonus> Bonus::addPropagationUpdater(const TUpdaterPtr & newUpdater)
  238. {
  239. propagationUpdater = appendToUpdaters(propagationUpdater, newUpdater);
  240. return this->shared_from_this();
  241. }
  242. VCMI_LIB_NAMESPACE_END