2
0

CSpellHandler.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * CSpellHandler.h, 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. #pragma once
  11. #include <vcmi/spells/Spell.h>
  12. #include <vcmi/spells/Service.h>
  13. #include <vcmi/spells/Magic.h>
  14. #include "../JsonNode.h"
  15. #include "../IHandlerBase.h"
  16. #include "../ConstTransitivePtr.h"
  17. #include "../int3.h"
  18. #include "../GameConstants.h"
  19. #include "../battle/BattleHex.h"
  20. #include "../HeroBonus.h"
  21. class CSpell;
  22. class IAdventureSpellMechanics;
  23. class CBattleInfoCallback;
  24. class AdventureSpellCastParameters;
  25. class SpellCastEnvironment;
  26. class JsonSerializeFormat;
  27. namespace test
  28. {
  29. class CSpellTest;
  30. }
  31. namespace spells
  32. {
  33. class ISpellMechanicsFactory;
  34. class IBattleCast;
  35. struct SchoolInfo
  36. {
  37. ESpellSchool id; //backlink
  38. Bonus::BonusType damagePremyBonus;
  39. Bonus::BonusType immunityBonus;
  40. std::string jsonName;
  41. SecondarySkill::ESecondarySkill skill;
  42. Bonus::BonusType knoledgeBonus;
  43. };
  44. }
  45. enum class VerticalPosition : ui8{TOP, CENTER, BOTTOM};
  46. class DLL_LINKAGE CSpell : public spells::Spell
  47. {
  48. public:
  49. struct ProjectileInfo
  50. {
  51. ///in radians. Only positive value. Negative angle is handled by vertical flip
  52. double minimumAngle;
  53. ///resource name
  54. std::string resourceName;
  55. template <typename Handler> void serialize(Handler & h, const int version)
  56. {
  57. h & minimumAngle;
  58. h & resourceName;
  59. }
  60. };
  61. struct AnimationItem
  62. {
  63. std::string resourceName;
  64. VerticalPosition verticalPosition;
  65. int pause;
  66. AnimationItem();
  67. template <typename Handler> void serialize(Handler & h, const int version)
  68. {
  69. h & resourceName;
  70. h & verticalPosition;
  71. if(version >= 754)
  72. {
  73. h & pause;
  74. }
  75. else if(!h.saving)
  76. {
  77. pause = 0;
  78. }
  79. }
  80. };
  81. typedef AnimationItem TAnimation;
  82. typedef std::vector<TAnimation> TAnimationQueue;
  83. struct DLL_LINKAGE AnimationInfo
  84. {
  85. AnimationInfo();
  86. ~AnimationInfo();
  87. ///displayed on all affected targets.
  88. TAnimationQueue affect;
  89. ///displayed on caster.
  90. TAnimationQueue cast;
  91. ///displayed on target hex. If spell was cast with no target selection displayed on entire battlefield (f.e. ARMAGEDDON)
  92. TAnimationQueue hit;
  93. ///displayed "between" caster and (first) target. Ignored if spell was cast with no target selection.
  94. ///use selectProjectile to access
  95. std::vector<ProjectileInfo> projectile;
  96. template <typename Handler> void serialize(Handler & h, const int version)
  97. {
  98. h & projectile;
  99. h & hit;
  100. h & cast;
  101. if(version >= 762)
  102. {
  103. h & affect;
  104. }
  105. }
  106. std::string selectProjectile(const double angle) const;
  107. } animationInfo;
  108. public:
  109. struct LevelInfo
  110. {
  111. std::string description; //descriptions of spell for skill level
  112. si32 cost;
  113. si32 power;
  114. si32 AIValue;
  115. bool smartTarget;
  116. bool clearTarget;
  117. bool clearAffected;
  118. std::string range;
  119. //TODO: remove these two when AI will understand special effects
  120. std::vector<std::shared_ptr<Bonus>> effects; //deprecated
  121. std::vector<std::shared_ptr<Bonus>> cumulativeEffects; //deprecated
  122. JsonNode battleEffects;
  123. LevelInfo();
  124. ~LevelInfo();
  125. template <typename Handler> void serialize(Handler & h, const int version)
  126. {
  127. h & description;
  128. h & cost;
  129. h & power;
  130. h & AIValue;
  131. h & smartTarget;
  132. h & range;
  133. if(version >= 773)
  134. {
  135. h & effects;
  136. h & cumulativeEffects;
  137. }
  138. else
  139. {
  140. //all old effects treated as not cumulative, special cases handled by CSpell::serialize
  141. std::vector<Bonus> old;
  142. h & old;
  143. if(!h.saving)
  144. {
  145. effects.clear();
  146. cumulativeEffects.clear();
  147. for(const Bonus & oldBonus : old)
  148. effects.push_back(std::make_shared<Bonus>(oldBonus));
  149. }
  150. }
  151. h & clearTarget;
  152. h & clearAffected;
  153. if(version >= 780)
  154. h & battleEffects;
  155. }
  156. };
  157. /** \brief Low level accessor. Don`t use it if absolutely necessary
  158. *
  159. * \param level. spell school level
  160. * \return Spell level info structure
  161. *
  162. */
  163. const CSpell::LevelInfo & getLevelInfo(const int32_t level) const;
  164. public:
  165. enum ESpellPositiveness
  166. {
  167. NEGATIVE = -1,
  168. NEUTRAL = 0,
  169. POSITIVE = 1
  170. };
  171. struct DLL_LINKAGE TargetInfo
  172. {
  173. spells::AimType type;
  174. bool smart;
  175. bool massive;
  176. bool clearAffected;
  177. bool clearTarget;
  178. TargetInfo(const CSpell * spell, const int32_t level, spells::Mode mode);
  179. };
  180. using BTVector = std::vector<Bonus::BonusType>;
  181. SpellID id;
  182. std::string identifier;
  183. std::string name;
  184. si32 level;
  185. std::map<ESpellSchool, bool> school;
  186. si32 power; //spell's power
  187. std::map<TFaction, si32> probabilities; //% chance to gain for castles
  188. bool combat; //is this spell combat (true) or adventure (false)
  189. bool creatureAbility; //if true, only creatures can use this spell
  190. si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
  191. std::vector<SpellID> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs)
  192. JsonNode targetCondition; //custom condition on what spell can affect
  193. CSpell();
  194. ~CSpell();
  195. int64_t calculateDamage(const spells::Caster * caster) const override;
  196. /**
  197. * Calls cb for each school this spell belongs to
  198. *
  199. * Set stop to true to abort looping
  200. */
  201. void forEachSchool(const std::function<void(const spells::SchoolInfo &, bool &)> & cb) const override;
  202. spells::AimType getTargetType() const;
  203. bool hasEffects() const;
  204. void getEffects(std::vector<Bonus> & lst, const int level, const bool cumulative, const si32 duration, boost::optional<si32 *> maxDuration = boost::none) const;
  205. bool hasBattleEffects() const;
  206. int32_t getCost(const int32_t skillLevel) const override;
  207. si32 getProbability(const TFaction factionId) const;
  208. int32_t getBasePower() const override;
  209. int32_t getLevelPower(const int32_t skillLevel) const override;
  210. int32_t getIndex() const override;
  211. int32_t getIconIndex() const override;
  212. const std::string & getName() const override;
  213. const std::string & getJsonKey() const override;
  214. SpellID getId() const override;
  215. int32_t getLevel() const override;
  216. const std::string & getLevelDescription(const int32_t skillLevel) const override;
  217. boost::logic::tribool getPositiveness() const override;
  218. bool isPositive() const override;
  219. bool isNegative() const override;
  220. bool isNeutral() const override;
  221. bool isDamage() const override;
  222. bool isOffensive() const override;
  223. bool isSpecial() const override;
  224. bool isAdventure() const override;
  225. bool isCombat() const override;
  226. bool isCreatureAbility() const override;
  227. void registerIcons(const IconRegistar & cb) const override;
  228. const std::string & getIconImmune() const; ///< Returns resource name of icon for SPELL_IMMUNITY bonus
  229. const std::string & getIconBook() const;
  230. const std::string & getIconEffect() const;
  231. const std::string & getIconScenarioBonus() const;
  232. const std::string & getIconScroll() const;
  233. const std::string & getCastSound() const override;
  234. void updateFrom(const JsonNode & data);
  235. void serializeJson(JsonSerializeFormat & handler);
  236. template <typename Handler> void serialize(Handler & h, const int version)
  237. {
  238. h & identifier;
  239. h & id;
  240. h & name;
  241. h & level;
  242. h & power;
  243. h & probabilities;
  244. h & attributes;
  245. h & combat;
  246. h & creatureAbility;
  247. h & positiveness;
  248. h & counteredSpells;
  249. h & rising;
  250. h & damage;
  251. h & offensive;
  252. h & targetType;
  253. if(version >= 780)
  254. {
  255. h & targetCondition;
  256. }
  257. else
  258. {
  259. BTVector immunities;
  260. BTVector absoluteImmunities;
  261. BTVector limiters;
  262. BTVector absoluteLimiters;
  263. h & immunities;
  264. h & limiters;
  265. h & absoluteImmunities;
  266. h & absoluteLimiters;
  267. if(!h.saving)
  268. targetCondition = convertTargetCondition(immunities, absoluteImmunities, limiters, absoluteLimiters);
  269. }
  270. h & iconImmune;
  271. h & defaultProbability;
  272. h & special;
  273. h & castSound;
  274. h & iconBook;
  275. h & iconEffect;
  276. h & iconScenarioBonus;
  277. h & iconScroll;
  278. h & levels;
  279. h & school;
  280. h & animationInfo;
  281. //backward compatibility
  282. //can not be added to level structure as level structure does not know spell id
  283. if(!h.saving && version < 773)
  284. {
  285. if(id == SpellID::DISRUPTING_RAY || id == SpellID::ACID_BREATH_DEFENSE)
  286. for(auto & level : levels)
  287. std::swap(level.effects, level.cumulativeEffects);
  288. }
  289. }
  290. friend class CSpellHandler;
  291. friend class Graphics;
  292. friend class test::CSpellTest;
  293. public:
  294. ///internal interface (for callbacks)
  295. ///Checks general but spell-specific problems. Use only during battle.
  296. bool canBeCast(const CBattleInfoCallback * cb, spells::Mode mode, const spells::Caster * caster) const;
  297. bool canBeCast(spells::Problem & problem, const CBattleInfoCallback * cb, spells::Mode mode, const spells::Caster * caster) const;
  298. public:
  299. ///Server logic. Has write access to GameState via packets.
  300. ///May be executed on client side by (future) non-cheat-proof scripts.
  301. bool adventureCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const;
  302. public://internal, for use only by Mechanics classes
  303. ///applies caster`s secondary skills and affectedCreature`s to raw damage
  304. int64_t adjustRawDamage(const spells::Caster * caster, const battle::Unit * affectedCreature, int64_t rawDamage) const;
  305. ///returns raw damage or healed HP
  306. int64_t calculateRawEffectValue(int32_t effectLevel, int32_t basePowerMultiplier, int32_t levelPowerMultiplier) const;
  307. std::unique_ptr<spells::Mechanics> battleMechanics(const spells::IBattleCast * event) const;
  308. private:
  309. void setIsOffensive(const bool val);
  310. void setIsRising(const bool val);
  311. JsonNode convertTargetCondition(const BTVector & immunity, const BTVector & absImmunity, const BTVector & limit, const BTVector & absLimit) const;
  312. //call this after load or deserialization. cant be done in constructor.
  313. void setupMechanics();
  314. private:
  315. si32 defaultProbability;
  316. bool rising;
  317. bool damage;
  318. bool offensive;
  319. bool special;
  320. std::string attributes; //reference only attributes //todo: remove or include in configuration format, currently unused
  321. spells::AimType targetType;
  322. ///graphics related stuff
  323. std::string iconImmune;
  324. std::string iconBook;
  325. std::string iconEffect;
  326. std::string iconScenarioBonus;
  327. std::string iconScroll;
  328. ///sound related stuff
  329. std::string castSound;
  330. std::vector<LevelInfo> levels;
  331. std::unique_ptr<spells::ISpellMechanicsFactory> mechanics;//(!) do not serialize
  332. std::unique_ptr<IAdventureSpellMechanics> adventureMechanics;//(!) do not serialize
  333. };
  334. bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos); //for spells like Dimension Door
  335. class DLL_LINKAGE CSpellHandler: public CHandlerBase<SpellID, spells::Spell, CSpell, spells::Service>
  336. {
  337. public:
  338. CSpellHandler();
  339. virtual ~CSpellHandler();
  340. ///IHandler base
  341. std::vector<JsonNode> loadLegacyData(size_t dataSize) override;
  342. void afterLoadFinalization() override;
  343. void beforeValidate(JsonNode & object) override;
  344. /**
  345. * Gets a list of default allowed spells. OH3 spells are all allowed by default.
  346. *
  347. */
  348. std::vector<bool> getDefaultAllowed() const override;
  349. template <typename Handler> void serialize(Handler & h, const int version)
  350. {
  351. h & objects;
  352. if(!h.saving && version < 780)
  353. {
  354. update780();
  355. }
  356. if(!h.saving)
  357. {
  358. afterLoadFinalization();
  359. }
  360. }
  361. protected:
  362. const std::vector<std::string> & getTypeNames() const override;
  363. CSpell * loadFromJson(const std::string & scope, const JsonNode & json, const std::string & identifier, size_t index) override;
  364. private:
  365. void update780();
  366. };