2011-12-14 00:23:17 +03:00
# pragma once
2009-04-16 14:14:13 +03:00
2014-03-07 16:21:09 +03:00
# include "IHandlerBase.h"
2010-12-19 16:39:56 +02:00
# include "../lib/ConstTransitivePtr.h"
2011-12-14 00:23:17 +03:00
# include "int3.h"
# include "GameConstants.h"
2014-11-13 03:53:25 +02:00
# include "BattleHex.h"
2013-01-15 17:20:48 +03:00
# include "HeroBonus.h"
2009-05-14 07:49:04 +03:00
2014-03-07 16:21:09 +03:00
2009-04-15 17:03:31 +03:00
/*
* CSpellHandler . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
2009-04-16 14:14:13 +03:00
*/
2014-11-12 05:59:53 +02:00
class CSpell ;
2014-11-13 03:53:25 +02:00
class ISpellMechanics ;
class CLegacyConfigParser ;
2014-11-12 05:59:53 +02:00
class CGHeroInstance ;
class CStack ;
2014-11-13 03:53:25 +02:00
class CBattleInfoCallback ;
2014-11-25 15:16:49 +02:00
class BattleInfo ;
2014-11-13 03:53:25 +02:00
2014-11-12 10:36:34 +02:00
struct CPackForClient ;
2014-11-25 18:43:34 +02:00
struct BattleSpellCast ;
2014-11-25 22:59:21 +02:00
2014-11-25 13:19:13 +02:00
class CRandomGenerator ;
2014-11-12 10:36:34 +02:00
2014-11-12 10:03:55 +02:00
struct SpellSchoolInfo
{
ESpellSchool id ; //backlink
Bonus : : BonusType damagePremyBonus ;
Bonus : : BonusType immunityBonus ;
2014-11-13 16:24:30 +02:00
std : : string jsonName ;
2014-11-13 16:57:35 +02:00
SecondarySkill : : ESecondarySkill skill ;
Bonus : : BonusType knoledgeBonus ;
2014-11-12 10:03:55 +02:00
} ;
2014-11-12 10:36:34 +02:00
///callback to be provided by server
class DLL_LINKAGE SpellCastEnvironment
{
public :
2014-11-25 21:00:04 +02:00
virtual ~ SpellCastEnvironment ( ) { } ;
2014-11-25 16:35:20 +02:00
virtual void sendAndApply ( CPackForClient * info ) const = 0 ;
2014-11-25 13:19:13 +02:00
2014-11-25 16:35:20 +02:00
virtual CRandomGenerator & getRandomGenerator ( ) const = 0 ;
virtual void complain ( const std : : string & problem ) const = 0 ;
2014-11-12 10:36:34 +02:00
} ;
///helper struct
2014-11-25 13:19:13 +02:00
struct DLL_LINKAGE BattleSpellCastParameters
2014-11-12 10:36:34 +02:00
{
public :
2014-11-27 18:09:59 +02:00
BattleSpellCastParameters ( const BattleInfo * cb ) ;
2014-11-13 03:53:25 +02:00
int spellLvl ;
2014-11-25 13:19:13 +02:00
BattleHex destination ;
2014-11-13 03:53:25 +02:00
ui8 casterSide ;
PlayerColor casterColor ;
2014-11-23 13:10:29 +02:00
const CGHeroInstance * caster ;
const CGHeroInstance * secHero ;
2014-11-13 03:53:25 +02:00
int usedSpellPower ;
ECastingMode : : ECastingMode mode ;
2014-11-25 13:19:13 +02:00
const CStack * casterStack ;
2014-11-26 21:25:13 +02:00
const CStack * selectedStack ;
const BattleInfo * cb ;
2014-11-12 05:59:53 +02:00
} ;
2012-05-18 23:50:16 +03:00
2014-11-27 15:51:16 +02:00
enum class VerticalPosition : ui8 { TOP , CENTER , BOTTOM } ;
2014-11-13 03:53:25 +02:00
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CSpell
2009-04-16 14:14:13 +03:00
{
2014-11-26 21:25:13 +02:00
public :
struct ProjectileInfo
{
///in radians. Only positive value. Negative angle is handled by vertical flip
double minimumAngle ;
///resource name
2014-11-27 15:51:16 +02:00
std : : string resourceName ;
2014-11-26 21:25:13 +02:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2014-11-27 15:51:16 +02:00
h & minimumAngle & resourceName ;
2014-11-26 21:25:13 +02:00
}
} ;
2014-11-27 15:51:16 +02:00
struct AnimationItem
{
std : : string resourceName ;
VerticalPosition verticalPosition ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & resourceName & verticalPosition ;
}
} ;
typedef AnimationItem TAnimation ;
2014-11-26 21:25:13 +02:00
typedef std : : vector < TAnimation > TAnimationQueue ;
2014-11-26 23:27:38 +02:00
struct DLL_LINKAGE AnimationInfo
2014-11-26 21:25:13 +02:00
{
AnimationInfo ( ) ;
~ AnimationInfo ( ) ;
///displayed on all affected targets.
TAnimationQueue affect ;
///displayed on caster.
TAnimationQueue cast ;
///displayed on target hex. If spell was casted with no target selection displayed on entire battlefield (f.e. ARMAGEDDON)
TAnimationQueue hit ;
///displayed "between" caster and (first) target. Ignored if spell was casted with no target selection.
///use selectProjectile to access
std : : vector < ProjectileInfo > projectile ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & projectile & hit & cast ;
}
std : : string selectProjectile ( const double angle ) const ;
} animationInfo ;
2014-03-07 16:21:09 +03:00
public :
2014-05-01 01:48:33 +03:00
struct LevelInfo
{
std : : string description ; //descriptions of spell for skill level
2014-11-25 11:26:32 +02:00
si32 cost ;
si32 power ;
si32 AIValue ;
2014-05-01 01:48:33 +03:00
bool smartTarget ;
2014-11-13 12:37:42 +02:00
bool clearTarget ;
bool clearAffected ;
2014-05-01 01:48:33 +03:00
std : : string range ;
std : : vector < Bonus > effects ;
LevelInfo ( ) ;
~ LevelInfo ( ) ;
template < typename Handler > void serialize ( Handler & h , const int version )
{
h & description & cost & power & AIValue & smartTarget & range & effects ;
2014-11-13 12:37:42 +02:00
h & clearTarget & clearAffected ;
2014-05-01 01:48:33 +03:00
}
} ;
/** \brief Low level accessor. Don`t use it if absolutely necessary
*
* \ param level . spell school level
* \ return Spell level info structure
*
*/
const CSpell : : LevelInfo & getLevelInfo ( const int level ) const ;
2009-04-16 14:14:13 +03:00
public :
2014-11-13 12:37:42 +02:00
enum ETargetType { NO_TARGET , CREATURE , OBSTACLE , LOCATION } ;
2012-02-17 00:19:07 +03:00
enum ESpellPositiveness { NEGATIVE = - 1 , NEUTRAL = 0 , POSITIVE = 1 } ;
2014-03-17 16:11:10 +03:00
struct TargetInfo
{
2014-05-01 01:48:33 +03:00
ETargetType type ;
bool smart ;
bool massive ;
2014-05-18 12:20:36 +03:00
bool onlyAlive ;
2014-11-13 03:53:25 +02:00
///no immunity on primary target (mostly spell-like attack)
bool alwaysHitDirectly ;
2014-11-13 05:29:41 +02:00
2014-11-13 14:00:45 +02:00
bool clearTarget ;
bool clearAffected ;
2014-11-13 05:29:41 +02:00
TargetInfo ( const CSpell * spell , const int level ) ;
TargetInfo ( const CSpell * spell , const int level , ECastingMode : : ECastingMode mode ) ;
private :
void init ( const CSpell * spell , const int level ) ;
2014-03-17 16:11:10 +03:00
} ;
2013-02-11 02:24:57 +03:00
SpellID id ;
2014-03-07 16:21:09 +03:00
std : : string identifier ; //???
2009-04-16 14:14:13 +03:00
std : : string name ;
2014-03-17 16:11:10 +03:00
2009-04-16 14:14:13 +03:00
si32 level ;
2014-11-12 10:03:55 +02:00
bool earth ; //deprecated
bool water ; //deprecated
bool fire ; //deprecated
bool air ; //deprecated
std : : map < ESpellSchool , bool > school ; //todo: use this instead of separate boolean fields
2009-04-16 14:14:13 +03:00
si32 power ; //spell's power
2014-03-07 16:21:09 +03:00
2012-12-18 13:32:11 +03:00
std : : map < TFaction , si32 > probabilities ; //% chance to gain for castles
2013-02-13 22:35:43 +03:00
2009-04-16 14:14:13 +03:00
bool combatSpell ; //is this spell combat (true) or adventure (false)
bool creatureAbility ; //if true, only creatures can use this spell
si8 positiveness ; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
2014-03-17 16:11:10 +03:00
2013-02-11 02:24:57 +03:00
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)
2012-09-14 02:41:03 +03:00
2013-01-15 17:20:48 +03:00
CSpell ( ) ;
2013-04-21 19:38:31 +03:00
~ CSpell ( ) ;
2014-11-13 16:57:35 +02:00
bool isCastableBy ( const IBonusBearer * caster , bool hasSpellBook , const std : : set < SpellID > & spellBook ) const ;
2014-11-29 03:25:51 +02:00
2013-01-15 17:20:48 +03:00
2013-06-26 14:18:27 +03:00
std : : vector < BattleHex > rangeInHexes ( BattleHex centralHex , ui8 schoolLvl , ui8 side , bool * outDroppedHexes = nullptr ) const ; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
2014-03-17 16:11:10 +03:00
ETargetType getTargetType ( ) const ; //deprecated
2014-11-13 03:53:25 +02:00
CSpell : : TargetInfo getTargetInfo ( const int level ) const ;
2014-11-13 05:29:41 +02:00
2009-04-16 14:14:13 +03:00
2014-03-09 02:18:51 +03:00
bool isCombatSpell ( ) const ;
bool isAdventureSpell ( ) const ;
bool isCreatureAbility ( ) const ;
2013-02-02 20:20:31 +03:00
2014-03-09 02:18:51 +03:00
bool isPositive ( ) const ;
bool isNegative ( ) const ;
2014-05-17 13:36:49 +03:00
bool isNeutral ( ) const ;
2013-02-02 20:20:31 +03:00
2014-03-09 02:18:51 +03:00
bool isDamageSpell ( ) const ;
2014-11-12 07:34:43 +02:00
bool isHealingSpell ( ) const ;
bool isRisingSpell ( ) const ;
2014-03-09 02:18:51 +03:00
bool isOffensiveSpell ( ) const ;
2013-02-02 20:20:31 +03:00
2014-03-09 02:18:51 +03:00
bool isSpecialSpell ( ) const ;
2014-03-07 19:10:20 +03:00
2014-03-09 02:18:51 +03:00
bool hasEffects ( ) const ;
2013-01-16 14:19:04 +03:00
void getEffects ( std : : vector < Bonus > & lst , const int level ) const ;
2014-11-12 06:41:12 +02:00
2014-11-29 03:25:51 +02:00
///checks for creature immunity / anything that prevent casting *at given hex* - doesn't take into account general problems such as not having spellbook or mana points etc.
ESpellCastProblem : : ESpellCastProblem isImmuneAt ( const CBattleInfoCallback * cb , const CGHeroInstance * caster , ECastingMode : : ECastingMode mode , BattleHex destination ) const ;
2014-11-12 06:41:12 +02:00
//internal, for use only by Mechanics classes
2014-11-12 04:50:51 +02:00
ESpellCastProblem : : ESpellCastProblem isImmuneBy ( const IBonusBearer * obj ) const ;
2014-11-12 05:59:53 +02:00
2014-11-29 03:25:51 +02:00
//checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
2014-11-13 03:53:25 +02:00
ESpellCastProblem : : ESpellCastProblem isImmuneByStack ( const CGHeroInstance * caster , const CStack * obj ) const ;
2014-11-12 07:02:27 +02:00
2014-11-12 08:52:11 +02:00
//internal, for use only by Mechanics classes. applying secondary skills
2014-11-12 07:02:27 +02:00
ui32 calculateBonus ( ui32 baseDamage , const CGHeroInstance * caster , const CStack * affectedCreature ) const ;
2014-11-12 07:34:43 +02:00
2014-11-13 07:13:06 +02:00
///calculate spell damage on stack taking caster`s secondary skills and affectedCreature`s bonuses into account
2014-11-12 08:52:11 +02:00
ui32 calculateDamage ( const CGHeroInstance * caster , const CStack * affectedCreature , int spellSchoolLevel , int usedSpellPower ) const ;
2014-11-12 07:34:43 +02:00
///calculate healed HP for all spells casted by hero
ui32 calculateHealedHP ( const CGHeroInstance * caster , const CStack * stack , const CStack * sacrificedStack = nullptr ) const ;
2014-11-12 08:52:11 +02:00
2014-11-13 03:53:25 +02:00
///selects from allStacks actually affected stacks
std : : set < const CStack * > getAffectedStacks ( const CBattleInfoCallback * cb , ECastingMode : : ECastingMode mode , PlayerColor casterColor , int spellLvl , BattleHex destination , const CGHeroInstance * caster = nullptr ) const ;
2012-02-17 00:19:07 +03:00
2014-03-09 02:18:51 +03:00
si32 getCost ( const int skillLevel ) const ;
2014-03-07 16:21:09 +03:00
2014-05-01 01:48:33 +03:00
/**
* Returns spell level power , base power ignored
*/
2014-03-09 02:18:51 +03:00
si32 getPower ( const int skillLevel ) const ;
2014-03-07 16:21:09 +03:00
2014-05-01 01:48:33 +03:00
// /**
2014-03-07 16:21:09 +03:00
// * Returns spell power, taking base power into account
// */
2014-03-09 02:18:51 +03:00
// si32 calculatePower(const int skillLevel) const;
2014-03-07 16:21:09 +03:00
2014-03-09 02:18:51 +03:00
si32 getProbability ( const TFaction factionId ) const ;
2014-03-07 16:21:09 +03:00
2014-11-24 18:14:10 +02:00
/**
* Calls cb for each school this spell belongs to
*
* Set stop to true to abort looping
*/
void forEachSchool ( const std : : function < void ( const SpellSchoolInfo & , bool & ) > & cb ) const ;
2013-02-13 22:35:43 +03:00
/**
2014-05-01 01:48:33 +03:00
* Returns resource name of icon for SPELL_IMMUNITY bonus
*/
2014-03-09 02:18:51 +03:00
const std : : string & getIconImmune ( ) const ;
2014-03-17 16:11:10 +03:00
2014-03-10 19:00:58 +03:00
const std : : string & getCastSound ( ) const ;
2013-02-13 22:35:43 +03:00
2009-04-16 14:14:13 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2014-11-13 15:57:49 +02:00
h & identifier & id & name & level & power
2014-11-28 00:03:25 +02:00
& probabilities & attributes & combatSpell & creatureAbility & positiveness & counteredSpells ;
2013-02-13 22:35:43 +03:00
h & isRising & isDamage & isOffensive ;
h & targetType ;
2014-05-18 16:55:26 +03:00
h & immunities & limiters & absoluteImmunities & absoluteLimiters ;
2013-02-13 22:35:43 +03:00
h & iconImmune ;
2014-05-18 16:55:26 +03:00
h & defaultProbability ;
2014-05-01 01:48:33 +03:00
h & isSpecial ;
h & castSound & iconBook & iconEffect & iconScenarioBonus & iconScroll ;
2014-11-26 21:25:13 +02:00
h & levels ;
h & school ;
h & animationInfo ;
2014-03-17 16:11:10 +03:00
2014-11-12 05:59:53 +02:00
if ( ! h . saving )
2014-11-12 10:03:55 +02:00
setup ( ) ;
2009-04-16 14:14:13 +03:00
}
2013-01-15 17:20:48 +03:00
friend class CSpellHandler ;
2014-03-10 19:00:58 +03:00
friend class Graphics ;
2014-11-26 21:25:13 +02:00
public :
///Server logic. Has write access to GameState via packets.
///May be executed on client side by (future) non-cheat-proof scripts.
//void adventureCast() const;
void battleCast ( const SpellCastEnvironment * env , BattleSpellCastParameters & parameters ) const ;
2014-11-25 22:59:21 +02:00
public :
2014-11-26 21:25:13 +02:00
///Client-server logic. Has direct write access to GameState.
///Shall be called (only) when applying packets on BOTH SIDES
///implementation of BattleSpellCast applying
2014-11-25 22:59:21 +02:00
void afterCast ( BattleInfo * battle , const BattleSpellCast * packet ) const ;
2013-01-15 17:20:48 +03:00
private :
2014-05-01 01:48:33 +03:00
void setIsOffensive ( const bool val ) ;
void setIsRising ( const bool val ) ;
2014-11-12 05:59:53 +02:00
//call this after load or deserialization. cant be done in constructor.
2014-11-12 10:03:55 +02:00
void setup ( ) ;
2014-11-12 05:59:53 +02:00
void setupMechanics ( ) ;
2014-03-07 16:21:09 +03:00
private :
2014-05-01 01:48:33 +03:00
si32 defaultProbability ;
2013-02-13 22:35:43 +03:00
2013-01-16 14:19:04 +03:00
bool isRising ;
bool isDamage ;
bool isOffensive ;
2014-03-07 19:10:20 +03:00
bool isSpecial ;
2013-01-15 17:20:48 +03:00
2014-03-07 16:21:09 +03:00
std : : string attributes ; //reference only attributes //todo: remove or include in configuration format, currently unused
2013-02-13 22:35:43 +03:00
ETargetType targetType ;
std : : vector < Bonus : : BonusType > immunities ; //any of these grants immunity
2014-03-23 15:59:03 +03:00
std : : vector < Bonus : : BonusType > absoluteImmunities ; //any of these grants immunity, can't be negated
2013-02-13 22:35:43 +03:00
std : : vector < Bonus : : BonusType > limiters ; //all of them are required to be affected
2014-05-18 16:55:26 +03:00
std : : vector < Bonus : : BonusType > absoluteLimiters ; //all of them are required to be affected, can't be negated
2013-02-02 20:20:31 +03:00
2013-02-13 22:35:43 +03:00
///graphics related stuff
2013-01-15 17:20:48 +03:00
2013-02-13 22:35:43 +03:00
std : : string iconImmune ;
2014-03-17 16:11:10 +03:00
2014-03-10 19:00:58 +03:00
std : : string iconBook ;
std : : string iconEffect ;
2014-03-17 16:11:10 +03:00
std : : string iconScenarioBonus ;
2014-03-10 19:00:58 +03:00
std : : string iconScroll ;
///sound related stuff
std : : string castSound ;
2014-03-17 16:11:10 +03:00
std : : vector < LevelInfo > levels ;
2014-11-12 05:59:53 +02:00
2014-11-12 10:36:34 +02:00
ISpellMechanics * mechanics ; //(!) do not serialize
2009-04-16 14:14:13 +03:00
} ;
2011-12-14 00:23:17 +03:00
bool DLL_LINKAGE isInScreenRange ( const int3 & center , const int3 & pos ) ; //for spells like Dimension Door
2010-03-21 00:17:19 +02:00
2014-03-07 16:21:09 +03:00
class DLL_LINKAGE CSpellHandler : public CHandlerBase < SpellID , CSpell >
2009-04-16 14:14:13 +03:00
{
public :
2009-09-25 06:21:56 +03:00
CSpellHandler ( ) ;
2014-03-07 16:21:09 +03:00
virtual ~ CSpellHandler ( ) ;
2014-05-01 01:48:33 +03:00
///IHandler base
std : : vector < JsonNode > loadLegacyData ( size_t dataSize ) override ;
void afterLoadFinalization ( ) override ;
2014-05-18 17:47:18 +03:00
void beforeValidate ( JsonNode & object ) override ;
2013-01-15 17:20:48 +03:00
2013-01-06 22:30:12 +03:00
/**
* Gets a list of default allowed spells . OH3 spells are all allowed by default .
*
* @ return a list of allowed spells , the index is the spell id and the value either 0 for not allowed or 1 for allowed
*/
2014-03-07 16:21:09 +03:00
std : : vector < bool > getDefaultAllowed ( ) const override ;
2014-03-08 22:02:47 +03:00
const std : : string getTypeName ( ) const override ;
2013-01-06 22:30:12 +03:00
2009-04-16 14:14:13 +03:00
template < typename Handler > void serialize ( Handler & h , const int version )
{
2014-03-07 16:21:09 +03:00
h & objects ;
2009-04-16 14:14:13 +03:00
}
2014-11-25 22:59:21 +02:00
2014-03-07 16:21:09 +03:00
protected :
2014-05-01 01:48:33 +03:00
CSpell * loadFromJson ( const JsonNode & json ) override ;
2009-04-16 14:14:13 +03:00
} ;