|  |  |  | @@ -141,6 +141,8 @@ public: | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	//bool adventureCast(const SpellCastContext & context) const override;  | 
		
	
		
			
				|  |  |  |  | 	void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const override; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; | 
		
	
		
			
				|  |  |  |  | protected: | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	virtual void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const; | 
		
	
	
		
			
				
					
					|  |  |  | @@ -173,6 +175,14 @@ protected: | 
		
	
		
			
				|  |  |  |  | 	void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;	 | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | class CureMechanics: public DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
		
			
				|  |  |  |  | 	CureMechanics(CSpell * s): DefaultSpellMechanics(s){};	 | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override;	 | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | class DeathStareMechnics: public DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
	
		
			
				
					
					|  |  |  | @@ -185,9 +195,20 @@ class DispellHelpfulMechanics: public DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
		
			
				|  |  |  |  | 	DispellHelpfulMechanics(CSpell * s): DefaultSpellMechanics(s){}; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;	 | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | class DispellMechanics: public DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
		
			
				|  |  |  |  | 	DispellMechanics(CSpell * s): DefaultSpellMechanics(s){}; | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	void afterCast(BattleInfo * battle, const BattleSpellCast * packet) const override;	 | 
		
	
		
			
				|  |  |  |  | }; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | class HypnotizeMechanics: public DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | public: | 
		
	
	
		
			
				
					
					|  |  |  | @@ -270,33 +291,39 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s) | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	switch (s->id) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 	case SpellID::CLONE: | 
		
	
		
			
				|  |  |  |  | 		return new CloneMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::DISPEL_HELPFUL_SPELLS: | 
		
	
		
			
				|  |  |  |  | 		return new DispellHelpfulMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SACRIFICE: | 
		
	
		
			
				|  |  |  |  | 		return new SacrificeMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::ACID_BREATH_DAMAGE: | 
		
	
		
			
				|  |  |  |  | 		return new AcidBreathDamageMechnics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::CHAIN_LIGHTNING: | 
		
	
		
			
				|  |  |  |  | 		return new ChainLightningMechanics(s);		 | 
		
	
		
			
				|  |  |  |  | 	case SpellID::CLONE: | 
		
	
		
			
				|  |  |  |  | 		return new CloneMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::CURE: | 
		
	
		
			
				|  |  |  |  | 		return new CureMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::DEATH_STARE: | 
		
	
		
			
				|  |  |  |  | 		return new DeathStareMechnics(s);			 | 
		
	
		
			
				|  |  |  |  | 	case SpellID::DISPEL: | 
		
	
		
			
				|  |  |  |  | 		return new DispellMechanics(s);	 | 
		
	
		
			
				|  |  |  |  | 	case SpellID::DISPEL_HELPFUL_SPELLS: | 
		
	
		
			
				|  |  |  |  | 		return new DispellHelpfulMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::FIRE_WALL: | 
		
	
		
			
				|  |  |  |  | 	case SpellID::FORCE_FIELD: | 
		
	
		
			
				|  |  |  |  | 		return new WallMechanics(s);		 | 
		
	
		
			
				|  |  |  |  | 	case SpellID::HYPNOTIZE: | 
		
	
		
			
				|  |  |  |  | 		return new HypnotizeMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::LAND_MINE: | 
		
	
		
			
				|  |  |  |  | 	case SpellID::QUICKSAND: | 
		
	
		
			
				|  |  |  |  | 		return new ObstacleMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::TELEPORT: | 
		
	
		
			
				|  |  |  |  | 		return new TeleportMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::REMOVE_OBSTACLE: | 
		
	
		
			
				|  |  |  |  | 		return new RemoveObstacleMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SACRIFICE: | 
		
	
		
			
				|  |  |  |  | 		return new SacrificeMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SUMMON_FIRE_ELEMENTAL: | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SUMMON_EARTH_ELEMENTAL: | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SUMMON_WATER_ELEMENTAL: | 
		
	
		
			
				|  |  |  |  | 	case SpellID::SUMMON_AIR_ELEMENTAL: | 
		
	
		
			
				|  |  |  |  | 		return new SummonMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::REMOVE_OBSTACLE: | 
		
	
		
			
				|  |  |  |  | 		return new RemoveObstacleMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::DEATH_STARE: | 
		
	
		
			
				|  |  |  |  | 		return new DeathStareMechnics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::ACID_BREATH_DAMAGE: | 
		
	
		
			
				|  |  |  |  | 		return new AcidBreathDamageMechnics(s); | 
		
	
		
			
				|  |  |  |  | 	case SpellID::TELEPORT: | 
		
	
		
			
				|  |  |  |  | 		return new TeleportMechanics(s); | 
		
	
		
			
				|  |  |  |  | 	default:		 | 
		
	
		
			
				|  |  |  |  | 		if(s->isRisingSpell()) | 
		
	
		
			
				|  |  |  |  | 			return new SpecialRisingSpellMechanics(s); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -307,11 +334,28 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s) | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///DefaultSpellMechanics | 
		
	
		
			
				|  |  |  |  | void DefaultSpellMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	//TODO: may be move all from BattleSpellCast::applyGs here  | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	//handle countering spells | 
		
	
		
			
				|  |  |  |  | 	for(auto stackID : packet->affectedCres) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if(vstd::contains(packet->resisted, stackID)) | 
		
	
		
			
				|  |  |  |  | 			continue; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		CStack * s = battle->getStack(stackID); | 
		
	
		
			
				|  |  |  |  | 		s->popBonuses([&](const Bonus * b) -> bool | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			//check for each bonus if it should be removed | 
		
	
		
			
				|  |  |  |  | 			const bool isSpellEffect = Selector::sourceType(Bonus::SPELL_EFFECT)(b); | 
		
	
		
			
				|  |  |  |  | 			const int spellID = isSpellEffect ? b->sid : -1; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 			return isSpellEffect && vstd::contains(owner->counteredSpells, spellID); | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  | 	}	 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | //bool DefaultSpellMechanics::adventureCast(const SpellCastContext& context) const | 
		
	
		
			
				|  |  |  |  | //{ | 
		
	
		
			
				|  |  |  |  | //	return false; //there is no general algorithm for casting adventure spells | 
		
	
		
			
				|  |  |  |  | //} | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -893,6 +937,33 @@ ESpellCastProblem::ESpellCastProblem CloneMechanics::isImmuneByStack(const CGHer | 
		
	
		
			
				|  |  |  |  | 	return DefaultSpellMechanics::isImmuneByStack(caster, obj);	 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///CureMechanics | 
		
	
		
			
				|  |  |  |  | void CureMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	DefaultSpellMechanics::afterCast(battle, packet); | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	for(auto stackID : packet->affectedCres) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if(vstd::contains(packet->resisted, stackID)) | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			logGlobal->errorStream() << "Resistance to positive spell CURE"; | 
		
	
		
			
				|  |  |  |  | 			continue; | 
		
	
		
			
				|  |  |  |  | 		}			 | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		CStack *s = battle->getStack(stackID); | 
		
	
		
			
				|  |  |  |  | 		s->popBonuses([&](const Bonus *b) -> bool | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			if(b->source == Bonus::SPELL_EFFECT) | 
		
	
		
			
				|  |  |  |  | 			{ | 
		
	
		
			
				|  |  |  |  | 				CSpell * sp = SpellID(b->sid).toSpell(); | 
		
	
		
			
				|  |  |  |  | 				return sp->isNegative(); | 
		
	
		
			
				|  |  |  |  | 			} | 
		
	
		
			
				|  |  |  |  | 			return false; //not a spell effect | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  | 	}		 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///DeathStareMechnics | 
		
	
		
			
				|  |  |  |  | void DeathStareMechnics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
	
		
			
				
					
					|  |  |  | @@ -915,6 +986,24 @@ void DeathStareMechnics::applyBattleEffects(const SpellCastEnvironment * env, Ba | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///DispellHelpfulMechanics | 
		
	
		
			
				|  |  |  |  | void DispellHelpfulMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	DefaultSpellMechanics::afterCast(battle, packet); | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	for(auto stackID : packet->affectedCres) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if(vstd::contains(packet->resisted, stackID)) | 
		
	
		
			
				|  |  |  |  | 			continue; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		CStack *s = battle->getStack(stackID); | 
		
	
		
			
				|  |  |  |  | 		s->popBonuses([&](const Bonus *b) -> bool | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			return Selector::positiveSpellEffects(b); | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  | 	}	 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(const CGHeroInstance * caster,  const CStack * obj) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	TBonusListPtr spellBon = obj->getSpellBonuses(); | 
		
	
	
		
			
				
					
					|  |  |  | @@ -936,6 +1025,25 @@ ESpellCastProblem::ESpellCastProblem DispellHelpfulMechanics::isImmuneByStack(co | 
		
	
		
			
				|  |  |  |  | 	return DefaultSpellMechanics::isImmuneByStack(caster,obj);	 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///DispellMechanics | 
		
	
		
			
				|  |  |  |  | void DispellMechanics::afterCast(BattleInfo * battle, const BattleSpellCast * packet) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
		
			
				|  |  |  |  | 	DefaultSpellMechanics::afterCast(battle, packet); | 
		
	
		
			
				|  |  |  |  | 	 | 
		
	
		
			
				|  |  |  |  | 	for(auto stackID : packet->affectedCres) | 
		
	
		
			
				|  |  |  |  | 	{ | 
		
	
		
			
				|  |  |  |  | 		if(vstd::contains(packet->resisted, stackID)) | 
		
	
		
			
				|  |  |  |  | 			continue; | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | 		CStack *s = battle->getStack(stackID); | 
		
	
		
			
				|  |  |  |  | 		s->popBonuses([&](const Bonus *b) -> bool | 
		
	
		
			
				|  |  |  |  | 		{ | 
		
	
		
			
				|  |  |  |  | 			return Selector::sourceType(Bonus::SPELL_EFFECT)(b); | 
		
	
		
			
				|  |  |  |  | 		}); | 
		
	
		
			
				|  |  |  |  | 	}	 | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  |  | 
		
	
		
			
				|  |  |  |  | ///HypnotizeMechanics | 
		
	
		
			
				|  |  |  |  | ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const | 
		
	
		
			
				|  |  |  |  | { | 
		
	
	
		
			
				
					
					|  |  |  |   |