context: /*
   * DAWN OF LIGHT - The first free open source DAoC server emulator
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
   * of the License, or (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
   *
   */
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  using System.Text;
  using DOL.AI.Brain;
  using DOL.Database;
  using DOL.Events;
  using DOL.GS.Effects;
  using DOL.GS.PacketHandler;
  using DOL.GS.ServerProperties;
  using DOL.GS.RealmAbilities;
  using DOL.GS.SkillHandler;
  using DOL.GS.Utils;
  using DOL.Language;
  
  using log4net;
  
  namespace DOL.GS.Spells
  {
  	/// <summary>
  	/// Default class for spell handler
  	/// should be used as a base class for spell handler
  	/// </summary>
  	public class SpellHandler : ISpellHandler
  	{
  		private static readonly ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  
  		/// <summary>
  		/// Maximum number of sub-spells to get delve info for.
  		/// </summary>
  		protected static readonly byte MAX_DELVE_RECURSION = 5;
  
  		protected DelayedCastTimer m_castTimer;
  		/// <summary>
  		/// The spell that we want to handle
  		/// </summary>
  		protected Spell m_spell;
  		/// <summary>
  		/// The spell line the spell belongs to
  		/// </summary>
  		protected SpellLine m_spellLine;
  		/// <summary>
  		/// The caster of the spell
  		/// </summary>
  		protected GameLiving m_caster;
  		/// <summary>
  		/// The target for this spell
  		/// </summary>
  		protected GameLiving m_spellTarget = null;
  		/// <summary>
  		/// Has the spell been interrupted
  		/// </summary>
  		protected bool m_interrupted = false;
  		/// <summary>
  		/// Delayedcast Stage
  		/// </summary>
  		public int Stage
  		{
  			get { return m_stage; }
  			set { m_stage = value; }
  		}
  		protected int m_stage = 0;
  		/// <summary>
  		/// Use to store Time when the delayedcast started
  		/// </summary>
  		protected long m_started = 0;
  		/// <summary>
  		/// Shall we start the reuse timer
  		/// </summary>
  		protected bool m_startReuseTimer = true;
  
  		public bool StartReuseTimer
  		{
  			get { return m_startReuseTimer; }
  		}
  
  		/// <summary>
  		/// Can this spell be queued with other spells?
  		/// </summary>
  		public virtual bool CanQueue
  		{
  			get { return true; }
  		}
  
  		/// <summary>
  		/// Does this spell break stealth on start of cast?
  		/// </summary>
  		public virtual bool UnstealthCasterOnStart
  		{
  			get { return true; }
  		}
  
  		/// <summary>
  		/// Does this spell break stealth on Finish of cast?
  		/// </summary>
  		public virtual bool UnstealthCasterOnFinish
  		{
  			get { return true; }
  		}
  
  		protected InventoryItem m_spellItem = null;
  
  		/// <summary>
  		/// Ability that casts a spell
  		/// </summary>
  		protected ISpellCastingAbilityHandler m_ability = null;
  
  		/// <summary>
  		/// Stores the current delve info depth
  		/// </summary>
  		private byte m_delveInfoDepth;
  
  		/// <summary>
  		/// AttackData result for this spell, if any
  		/// </summary>
  		protected AttackData m_lastAttackData = null;
  		/// <summary>
  		/// AttackData result for this spell, if any
  		/// </summary>
  		public AttackData LastAttackData
  		{
  			get { return m_lastAttackData; }
  		}
  
  		/// <summary>
  		/// The property key for the interrupt timeout
  		/// </summary>
  		public const string INTERRUPT_TIMEOUT_PROPERTY = "CAST_INTERRUPT_TIMEOUT";
  		/// <summary>
  		/// The property key for focus spells
  		/// </summary>
  		protected const string FOCUS_SPELL = "FOCUSING_A_SPELL";
  
  		protected bool m_ignoreDamageCap = false;
  
  		/// <summary>
  		/// Does this spell ignore any damage cap?
  		/// </summary>
  		public bool IgnoreDamageCap
  		{
  			get { return m_ignoreDamageCap; }
  			set { m_ignoreDamageCap = value; }
  		}
  
  		protected bool m_useMinVariance = false;
  
  		/// <summary>
  		/// Should this spell use the minimum variance for the type?
  		/// Followup style effects, for example, always use the minimum variance
  		/// </summary>
  		public bool UseMinVariance
  		{
  			get { return m_useMinVariance; }
  			set { m_useMinVariance = value; }
  		}
  
  		/// <summary>
  		/// Can this SpellHandler Coexist with other Overwritable Spell Effect
  		/// </summary>
  		public virtual bool AllowCoexisting
  		{
  			get { return Spell.AllowCoexisting; }
  		}
  
  
  		/// <summary>
  		/// The CastingCompleteEvent
  		/// </summary>
  		public event CastingCompleteCallback CastingCompleteEvent;
  		//public event SpellEndsCallback SpellEndsEvent;
  
  		/// <summary>
  		/// spell handler constructor
  		/// <param name="caster">living that is casting that spell</param>
  		/// <param name="spell">the spell to cast</param>
  		/// <param name="spellLine">the spell line that spell belongs to</param>
  		/// </summary>
  		public SpellHandler(GameLiving caster, Spell spell, SpellLine spellLine)
  		{
  			m_caster = caster;
  			m_spell = spell;
  			m_spellLine = spellLine;
  		}
  
  		/// <summary>
  		/// Returns the string representation of the SpellHandler
  		/// </summary>
  		/// <returns></returns>
  		public override string ToString()
  		{
  			return new StringBuilder(128)
  				.Append("Caster=").Append(Caster == null ? "(null)" : Caster.Name)
  				.Append(", IsCasting=").Append(IsCasting)
  				.Append(", m_interrupted=").Append(m_interrupted)
  				.Append("\nSpell: ").Append(Spell == null ? "(null)" : Spell.ToString())
  				.Append("\nSpellLine: ").Append(SpellLine == null ? "(null)" : SpellLine.ToString())
  				.ToString();
  		}
  
  		#region Pulsing Spells
  
  		/// <summary>
  		/// When spell pulses
  		/// </summary>
  		public virtual void OnSpellPulse(PulsingSpellEffect effect)
  		{
  			if (Caster.IsMoving && Spell.IsFocus)
  			{
  				MessageToCaster("Your spell was cancelled.", eChatType.CT_SpellExpires);
  				effect.Cancel(false);
  				return;
  			}
  			if (Caster.IsAlive == false)
  			{
  				effect.Cancel(false);
  				return;
  			}
  			if (Caster.ObjectState != GameObject.eObjectState.Active)
  				return;
  			if (Caster.IsStunned || Caster.IsMezzed)
  				return;
  
  			// no instrument anymore = stop the song
  			if (m_spell.InstrumentRequirement != 0 && !CheckInstrument())
  			{
  				MessageToCaster("You stop playing your song.", eChatType.CT_Spell);
  				effect.Cancel(false);
  				return;
  			}
  
  			if (Caster.Mana >= Spell.PulsePower)
  			{
  				Caster.Mana -= Spell.PulsePower;
  				if (Spell.InstrumentRequirement != 0 || !HasPositiveEffect)
  				{
  					SendEffectAnimation(Caster, 0, true, 1); // pulsing auras or songs
  				}
  
  				StartSpell(m_spellTarget);
  			}
  			else
  			{
  				if (Spell.IsFocus)
  				{
  					FocusSpellAction(null, Caster, null);
  				}
  				MessageToCaster("You do not have enough mana and your spell was cancelled.", eChatType.CT_SpellExpires);
  				effect.Cancel(false);
  			}
  		}
  
  		/// <summary>
  		/// Checks if caster holds the right instrument for this spell
  		/// </summary>
  		/// <returns>true if right instrument</returns>
  		protected bool CheckInstrument()
  		{
  			InventoryItem instrument = Caster.AttackWeapon;
  			// From patch 1.97:  Flutes, Lutes, and Drums will now be able to play any song type, and will no longer be limited to specific songs.
  			if (instrument == null || instrument.Object_Type != (int)eObjectType.Instrument) // || (instrument.DPS_AF != 4 && instrument.DPS_AF != m_spell.InstrumentRequirement))
  			{
  				return false;
  			}
  			return true;
  		}
  
  		/// <summary>
  		/// Cancels first pulsing spell of type
  		/// </summary>
  		/// <param name="living">owner of pulsing spell</param>
  		/// <param name="spellType">type of spell to cancel</param>
  		/// <returns>true if any spells were canceled</returns>
  		public virtual bool CancelPulsingSpell(GameLiving living, string spellType)
  		{
  			lock (living.ConcentrationEffects)
  			{
  				for (int i = 0; i < living.ConcentrationEffects.Count; i++)
  				{
  					PulsingSpellEffect effect = living.ConcentrationEffects[i] as PulsingSpellEffect;
  					if (effect == null)
  						continue;
  					if (effect.SpellHandler.Spell.SpellType == spellType)
  					{
  						effect.Cancel(false);
  						return true;
  					}
  				}
  			}
  			return false;
  		}
  
  		/// <summary>
  		/// Cancels all pulsing spells
  		/// </summary>
  		/// <param name="living"></param>
  		public static void CancelAllPulsingSpells(GameLiving living)
  		{
  			List<IConcentrationEffect> pulsingSpells = new List<IConcentrationEffect>();
  
  			GamePlayer player = living as GamePlayer;
  
  			lock (living.ConcentrationEffects)
  			{
  				for (int i = 0; i < living.ConcentrationEffects.Count; i++)
  				{
  					PulsingSpellEffect effect = living.ConcentrationEffects[i] as PulsingSpellEffect;
  					if (effect == null)
  						continue;
  
  					if (player != null && player.CharacterClass.MaxPulsingSpells > 1)
  						pulsingSpells.Add(effect);
  					else
  						effect.Cancel(false);
  				}
  			}
  
  			// Non-concentration spells are grouped at the end of GameLiving.ConcentrationEffects.
  			// The first one is added at the very end; successive additions are inserted just before the last element
  			// which results in the following ordering:
  			// Assume pulsing spells A, B, C, and D were added in that order; X, Y, and Z represent other spells
  			// ConcentrationEffects = { X, Y, Z, ..., B, C, D, A }
  			// If there are only ever 2 or less pulsing spells active, then the oldest one will always be at the end.
  			// However, if an update or modification allows more than 2 to be active, the goofy ordering of the spells
  			// will prevent us from knowing which spell is the oldest and should be canceled - we can go ahead and simply
  			// cancel the last spell in the list (which will result in inconsistent behavior) or change the code that adds
  			// spells to ConcentrationEffects so that it enforces predictable ordering.
  			if (pulsingSpells.Count > 1)
  			{
  				pulsingSpells[pulsingSpells.Count - 1].Cancel(false);
  			}
  		}
  
  		#endregion
  
  		/// <summary>
  		/// Sets the target of the spell to the caster for beneficial effects when not selecting a valid target
  		///		ie. You're in the middle of a fight with a mob and want to heal yourself.  Rather than having to switch
  		///		targets to yourself to healm and then back to the target, you can just heal yourself
  		/// </summary>
  		/// <param name="target">The current target of the spell, changed to the player if appropriate</param>
  		protected virtual void AutoSelectCaster(ref GameLiving target)
  		{
  			GameNPC npc = target as GameNPC;
  			if (Spell.Target.ToUpper() == "REALM" && Caster is GamePlayer &&
  				(npc == null || npc.Realm != Caster.Realm || (npc.Flags & GameNPC.eFlags.PEACE) != 0))
  				target = Caster;
  		}
  
  		/// <summary>
  		/// Cast a spell by using an item
  		/// </summary>
  		/// <param name="item"></param>
  		/// <returns></returns>
  		public virtual bool CastSpell(InventoryItem item)
  		{
  			m_spellItem = item;
  			return CastSpell(Caster.TargetObject as GameLiving);
  		}
  
  		/// <summary>
  		/// Cast a spell by using an Item
  		/// </summary>
  		/// <param name="targetObject"></param>
  		/// <param name="item"></param>
  		/// <returns></returns>
  		public virtual bool CastSpell(GameLiving targetObject, InventoryItem item)
  		{
  			m_spellItem = item;
  			return CastSpell(targetObject);
  		}
  
  		/// <summary>
  		/// called whenever the player clicks on a spell icon
  		/// or a GameLiving wants to cast a spell
  		/// </summary>
  		public virtual bool CastSpell()
  		{
  			return CastSpell(Caster.TargetObject as GameLiving);
  		}
  
  		public virtual bool CastSpell(GameLiving targetObject)
  		{
  			bool success = true;
  
  			if (Properties.AUTOSELECT_CASTER)
  				AutoSelectCaster(ref targetObject);
  
  			m_spellTarget = targetObject;
  
  			Caster.Notify(GameLivingEvent.CastStarting, m_caster, new CastingEventArgs(this));
  
  			//[Stryve]: Do not break stealth if spell can be cast without breaking stealth.
  			if (Caster is GamePlayer && UnstealthCasterOnStart)
  				((GamePlayer)Caster).Stealth(false);
  
  			if (Caster.IsEngaging)
  			{
  				EngageEffect effect = Caster.EffectList.GetOfType<EngageEffect>();
  
  				if (effect != null)
  					effect.Cancel(false);
  			}
  
  			m_interrupted = false;
  
  			if (Spell.Target.ToLower() == "pet")
  			{
  				// Pet is the target, check if the caster is the pet.
  
  				if (Caster is GameNPC && (Caster as GameNPC).Brain is IControlledBrain)
  					m_spellTarget = Caster;
  
  				if (Caster is GamePlayer && Caster.ControlledBrain != null && Caster.ControlledBrain.Body != null)
  				{
  					if (m_spellTarget == null || !Caster.IsControlledNPC(m_spellTarget as GameNPC))
  					{
  						m_spellTarget = Caster.ControlledBrain.Body;
  					}
  				}
  			}
  			else if (Spell.Target.ToLower() == "controlled")
  			{
  				// Can only be issued by the owner of a pet and the target
  				// is always the pet then.
  
  				if (Caster is GamePlayer && Caster.ControlledBrain != null)
  					m_spellTarget = Caster.ControlledBrain.Body;
  				else
  					m_spellTarget = null;
  			}
  
  			if (Spell.Pulse != 0 && !Spell.IsFocus && CancelPulsingSpell(Caster, Spell.SpellType))
  			{
  				if (Spell.InstrumentRequirement == 0)
  					MessageToCaster("You cancel your effect.", eChatType.CT_Spell);
  				else
  					MessageToCaster("You stop playing your song.", eChatType.CT_Spell);
  			}
  			else if (GameServer.ServerRules.IsAllowedToCastSpell(Caster, m_spellTarget, Spell, m_spellLine))
  			{
  				if (CheckBeginCast(m_spellTarget))
  				{
  					if (m_caster is GamePlayer && (m_caster as GamePlayer).IsOnHorse && !HasPositiveEffect)
  					{
  						(m_caster as GamePlayer).IsOnHorse = false;
  					}
  
  					if (!Spell.IsInstantCast)
  					{
  						StartCastTimer(m_spellTarget);
  
  						if ((Caster is GamePlayer && (Caster as GamePlayer).IsStrafing) || Caster.IsMoving)
  							CasterMoves();
  					}
  					else
  					{
  						if (Caster.ControlledBrain == null || Caster.ControlledBrain.Body == null || !(Caster.ControlledBrain.Body is NecromancerPet))
  						{
  							SendCastAnimation(0);
  						}
  
  						FinishSpellCast(m_spellTarget);
  					}
  				}
  				else
  				{
  					success = false;
  				}
  			}
  
  			// This is critical to restore the casters state and allow them to cast another spell
  			if (!IsCasting)
  				OnAfterSpellCastSequence();
  
  			return success;
  		}
  
  
  		public virtual void StartCastTimer( GameLiving target )
  		{
  			m_interrupted = false;
  			SendSpellMessages();
  
  			int time = CalculateCastingTime();
  
  			int step1 = time / 3;
  			int step3 = step1;
  
  			step1 = step1.Clamp( 1, ServerProperties.Properties.SPELL_INTERRUPT_MAXSTAGELENGTH );
  			step3 = step3.Clamp( 1, ServerProperties.Properties.SPELL_INTERRUPT_MAXSTAGELENGTH );
  
  			int step2 = time - step1 - step3;
  			byte step2_substeps = 0;
  			if( step2 > ServerProperties.Properties.SPELL_INTERRUPT_MAX_INTERMEDIATE_STAGELENGTH )
  			{
  				step2_substeps = (byte) ( ( step2 / ServerProperties.Properties.SPELL_INTERRUPT_MAX_INTERMEDIATE_STAGELENGTH ) + 1 );
  				step2 /= step2_substeps;
  			}
  			if( step2 < 1 )
  				step2 = 1;
  
  			if( Caster is GamePlayer && ServerProperties.Properties.ENABLE_DEBUG )
  			{
  				( Caster as GamePlayer ).Out.SendMessage( $"[DEBUG] spell time = {time}, step1 = {step1}, step2 = {step2}, step3 = {step3}", eChatType.CT_System, eChatLoc.CL_SystemWindow );
  			}
  
  			m_castTimer = new DelayedCastTimer( Caster, this, target, step2, step3, step2_substeps );
  			m_castTimer.Start( step1 );
  			m_started = Caster.CurrentRegion.Time;
  			SendCastAnimation();
  
  			if( m_caster.IsMoving || m_caster.IsStrafing )
  			{
  				CasterMoves();
  			}
  		}
  
  		/// <summary>
  		/// Is called when the caster moves
  		/// </summary>
  		public virtual void CasterMoves()
  		{
  			if (Spell.InstrumentRequirement != 0)
  				return;
  
  			if (Spell.MoveCast)
  				return;
  
  			InterruptCasting();
  			if (Caster is GamePlayer)
  				(Caster as GamePlayer).Out.SendMessage(LanguageMgr.GetTranslation((Caster as GamePlayer).Client, "SpellHandler.CasterMove"), eChatType.CT_Important, eChatLoc.CL_SystemWindow);
  		}
  
  		/// <summary>
  		/// This sends the spell messages to the player/target.
  		///</summary>
  		public virtual void SendSpellMessages()
  		{
  			if (Spell.InstrumentRequirement == 0)
  				MessageToCaster("You begin casting a " + Spell.Name + " spell!", eChatType.CT_Spell);
  			else
  				MessageToCaster("You begin playing " + Spell.Name + "!", eChatType.CT_Spell);
  		}
  
  		/// <summary>
  		/// casting sequence has a chance for interrupt through attack from enemy
  		/// the final decision and the interrupt is done here
  		/// TODO: con level dependend
  		/// </summary>
  		/// <param name="attacker">attacker that interrupts the cast sequence</param>
  		/// <returns>true if casting was interrupted</returns>
  		public virtual bool CasterIsAttacked(GameLiving attacker)
  		{
  			//[StephenxPimentel] Check if the necro has MoC effect before interrupting.
  			if (Caster is NecromancerPet)
  			{
  				if ((Caster as NecromancerPet).Owner.EffectList.GetOfType<MasteryofConcentrationEffect>() != null)
  				{
  					return false;
  				}
  			}
  			if (Spell.Uninterruptible)
  				return false;
  			if (Caster.EffectList.CountOfType(typeof(QuickCastEffect), typeof(MasteryofConcentrationEffect), typeof(FacilitatePainworkingEffect)) > 0)
  				return false;
  			if (IsCasting && Stage < 2)
  			{
  				if (Caster.ChanceSpellInterrupt(attacker))
  				{
  					Caster.LastInterruptMessage = attacker.GetName(0, true) + " attacks you and your spell is interrupted!";
  					MessageToLiving(Caster, Caster.LastInterruptMessage, eChatType.CT_SpellResisted);
  					InterruptCasting(); // always interrupt at the moment
  					return true;
  				}
  			}
  			return false;
  		}
  
  		#region begin & end cast check
  
  		public virtual bool CheckBeginCast(GameLiving selectedTarget)
  		{
  			return CheckBeginCast(selectedTarget, false);
  		}
  
  		/// <summary>
  		/// All checks before any casting begins
  		/// </summary>
  		/// <param name="selectedTarget"></param>
  		/// <returns></returns>
  		public virtual bool CheckBeginCast(GameLiving selectedTarget, bool quiet)
  		{
  			if (m_caster.ObjectState != GameLiving.eObjectState.Active)
  			{
  				return false;
  			}
  
  			if (!m_caster.IsAlive)
  			{
  				if (!quiet) MessageToCaster("You are dead and can't cast!", eChatType.CT_System);
  				return false;
  			}
  
  
  			if (m_caster is GamePlayer)
  			{
  				long nextSpellAvailTime = m_caster.TempProperties.getProperty<long>(GamePlayer.NEXT_SPELL_AVAIL_TIME_BECAUSE_USE_POTION);
  
  				if (nextSpellAvailTime > m_caster.CurrentRegion.Time)
  				{
  					((GamePlayer)m_caster).Out.SendMessage(LanguageMgr.GetTranslation(((GamePlayer)m_caster).Client, "GamePlayer.CastSpell.MustWaitBeforeCast", (nextSpellAvailTime - m_caster.CurrentRegion.Time) / 1000), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					return false;
  				}
  				if (((GamePlayer)m_caster).Steed != null && ((GamePlayer)m_caster).Steed is GameSiegeRam)
  				{
  					if (!quiet) MessageToCaster("You can't cast in a siegeram!.", eChatType.CT_System);
  					return false;
  				}
  				GameSpellEffect naturesWomb = FindEffectOnTarget(Caster, typeof(NaturesWombEffect));
  				if (naturesWomb != null)
  				{
  					//[StephenxPimentel]
  					//Get Correct Message for 1.108 update.
  					MessageToCaster("You are silenced and cannot cast a spell right now.", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  
  			GameSpellEffect Phaseshift = FindEffectOnTarget(Caster, "Phaseshift");
  			if (Phaseshift != null && (Spell.InstrumentRequirement == 0 || Spell.SpellType == "Mesmerize"))
  			{
  				if (!quiet) MessageToCaster("You're phaseshifted and can't cast a spell", eChatType.CT_System);
  				return false;
  			}
  
  			// Apply Mentalist RA5L
  			if (Spell.Range > 0)
  			{
  				SelectiveBlindnessEffect SelectiveBlindness = Caster.EffectList.GetOfType<SelectiveBlindnessEffect>();
  				if (SelectiveBlindness != null)
  				{
  					GameLiving EffectOwner = SelectiveBlindness.EffectSource;
  					if (EffectOwner == selectedTarget)
  					{
  						if (m_caster is GamePlayer && !quiet)
  							((GamePlayer)m_caster).Out.SendMessage(string.Format("{0} is invisible to you!", selectedTarget.GetName(0, true)), eChatType.CT_Missed, eChatLoc.CL_SystemWindow);
  
  						return false;
  					}
  				}
  			}
  
  			if (selectedTarget != null && selectedTarget.HasAbility("DamageImmunity") && Spell.SpellType == "DirectDamage" && Spell.Radius == 0)
  			{
  				if (!quiet) MessageToCaster(selectedTarget.Name + " is immune to this effect!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_spell.InstrumentRequirement != 0)
  			{
  				if (!CheckInstrument())
  				{
  					if (!quiet) MessageToCaster("You are not wielding the right type of instrument!",
  												eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_caster.IsSitting) // songs can be played if sitting
  			{
  				//Purge can be cast while sitting but only if player has negative effect that
  				//don't allow standing up (like stun or mez)
  				if (!quiet) MessageToCaster("You can't cast while sitting!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster.AttackState && m_spell.CastTime != 0)
  			{
  				if (m_caster.CanCastInCombat(Spell) == false)
  				{
  					m_caster.StopAttack();
  					return false;
  				}
  			}
  
  			if (!m_spell.Uninterruptible && m_spell.CastTime > 0 && m_caster is GamePlayer &&
  				m_caster.EffectList.GetOfType<QuickCastEffect>() == null && m_caster.EffectList.GetOfType<MasteryofConcentrationEffect>() == null)
  			{
  				if (Caster.InterruptAction > 0 && Caster.InterruptAction + Caster.SpellInterruptRecastTime > Caster.CurrentRegion.Time)
  				{
  					if (!quiet) MessageToCaster("You must wait " + (((Caster.InterruptAction + Caster.SpellInterruptRecastTime) - Caster.CurrentRegion.Time) / 1000 + 1).ToString() + " seconds to cast a spell!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  
  			if (m_spell.RecastDelay > 0)
  			{
  				int left = m_caster.GetSkillDisabledDuration(m_spell);
  				if (left > 0)
  				{
  					if (m_caster is NecromancerPet && ((m_caster as NecromancerPet).Owner as GamePlayer).Client.Account.PrivLevel > (int)ePrivLevel.Player)
  					{
  						// Ignore Recast Timer
  					}
  					else
  					{
  						if (!quiet) MessageToCaster("You must wait " + (left / 1000 + 1).ToString() + " seconds to use this spell!", eChatType.CT_System);
  						return false;
  					}
  				}
  			}
  
  			String targetType = m_spell.Target.ToLower();
  
  			//[Ganrod] Nidel: Can cast pet spell on all Pet/Turret/Minion (our pet)
  			if (targetType.Equals("pet"))
  			{
  				if (selectedTarget == null || !Caster.IsControlledNPC(selectedTarget as GameNPC))
  				{
  					if (Caster.ControlledBrain != null && Caster.ControlledBrain.Body != null)
  					{
  						selectedTarget = Caster.ControlledBrain.Body;
  					}
  					else
  					{
  						if (!quiet) MessageToCaster("You must cast this spell on a creature you are controlling.",
  													eChatType.CT_System);
  						return false;
  					}
  				}
  			}
  			if (targetType == "area")
  			{
  				if (!m_caster.IsWithinRadius(m_caster.GroundTarget, CalculateSpellRange()))
  				{
  					if (!quiet) MessageToCaster("Your area target is out of range.  Select a closer target.", eChatType.CT_SpellResisted);
  					return false;
  				}
  				if (!Caster.GroundTargetInView)
  				{
  					MessageToCaster("Your ground target is not in view!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (targetType != "self" && targetType != "group" && targetType != "pet"
  					 && targetType != "controlled" && targetType != "cone" && m_spell.Range > 0)
  			{
  				// All spells that need a target.
  
  				if (selectedTarget == null || selectedTarget.ObjectState != GameLiving.eObjectState.Active)
  				{
  					if (!quiet) MessageToCaster("You must select a target for this spell!",
  												eChatType.CT_SpellResisted);
  					return false;
  				}
  
  				if (!m_caster.IsWithinRadius(selectedTarget, CalculateSpellRange()))
  				{
  					if (Caster is GamePlayer && !quiet) MessageToCaster("That target is too far away!",
  																		eChatType.CT_SpellResisted);
  					Caster.Notify(GameLivingEvent.CastFailed,
  								  new CastFailedEventArgs(this, CastFailedEventArgs.Reasons.TargetTooFarAway));
  					return false;
  				}
  
  				switch (m_spell.Target.ToLower())
  				{
  					case "enemy":
  						if (selectedTarget == m_caster)
  						{
  							if (!quiet) MessageToCaster("You can't attack yourself! ", eChatType.CT_System);
  							return false;
  						}
  
  						if (FindStaticEffectOnTarget(selectedTarget, typeof(NecromancerShadeEffect)) != null)
  						{
  							if (!quiet) MessageToCaster("Invalid target.", eChatType.CT_System);
  							return false;
  						}
  
  						if (m_spell.SpellType == "Charm" && m_spell.CastTime == 0 && m_spell.Pulse != 0)
  							break;
  
  						if (m_caster.IsObjectInFront(selectedTarget, 180) == false)
  						{
  							if (!quiet) MessageToCaster("Your target is not in view!", eChatType.CT_SpellResisted);
  							Caster.Notify(GameLivingEvent.CastFailed, new CastFailedEventArgs(this, CastFailedEventArgs.Reasons.TargetNotInView));
  							return false;
  						}
  
  						if (m_caster.TargetInView == false)
  						{
  							if (!quiet) MessageToCaster("Your target is not visible!", eChatType.CT_SpellResisted);
  							Caster.Notify(GameLivingEvent.CastFailed, new CastFailedEventArgs(this, CastFailedEventArgs.Reasons.TargetNotInView));
  							return false;
  						}
  
  						if (!GameServer.ServerRules.IsAllowedToAttack(Caster, selectedTarget, quiet))
  						{
  							return false;
  						}
  						break;
  
  					case "corpse":
  						if (selectedTarget.IsAlive || !GameServer.ServerRules.IsSameRealm(Caster, selectedTarget, true))
  						{
  							if (!quiet) MessageToCaster("This spell only works on dead members of your realm!", eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  
  					case "realm":
  						if (GameServer.ServerRules.IsAllowedToAttack(Caster, selectedTarget, true))
  						{
  							return false;
  						}
  						break;
  				}
  
  				//heals/buffs/rez need LOS only to start casting, TargetInView only works if selectedTarget == TargetObject
  				if (selectedTarget == Caster.TargetObject && !m_caster.TargetInView && m_spell.Target.ToLower() != "pet")
  				{
  					if (!quiet) MessageToCaster("Your target is not in visible!", eChatType.CT_SpellResisted);
  					Caster.Notify(GameLivingEvent.CastFailed, new CastFailedEventArgs(this, CastFailedEventArgs.Reasons.TargetNotInView));
  					return false;
  				}
  
  				if (m_spell.Target.ToLower() != "corpse" && !selectedTarget.IsAlive)
  				{
  					if (!quiet) MessageToCaster(selectedTarget.GetName(0, true) + " is dead!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  
  			//Ryan: don't want mobs to have reductions in mana
  			if (Spell.Power != 0 && m_caster is GamePlayer && (m_caster as GamePlayer).CharacterClass.ID != (int)eCharacterClass.Savage && m_caster.Mana < PowerCost(selectedTarget) && Spell.SpellType != "Archery")
  			{
  				if (!quiet) MessageToCaster("You don't have enough power to cast that!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0)
  			{
  				if (m_caster.Concentration < m_spell.Concentration)
  				{
  					if (!quiet) MessageToCaster("This spell requires " + m_spell.Concentration + " concentration points to cast!", eChatType.CT_SpellResisted);
  					return false;
  				}
  
  				if (m_caster.ConcentrationEffects.ConcSpellsCount >= 50)
  				{
  					if (!quiet) MessageToCaster("You can only cast up to 50 simultaneous concentration spells!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  
  			// Cancel engage if user starts attack
  			if (m_caster.IsEngaging)
  			{
  				EngageEffect engage = m_caster.EffectList.GetOfType<EngageEffect>();
  				if (engage != null)
  				{
  					engage.Cancel(false);
  				}
  			}
  
  			if (!(Caster is GamePlayer))
  			{
  				Caster.Notify(GameLivingEvent.CastSucceeded, this, new PetSpellEventArgs(Spell, SpellLine, selectedTarget));
  			}
  
  			return true;
  		}
  
  		/// <summary>
  		/// Does the area we are in force an LoS check on everything?
  		/// </summary>
  		/// <param name="living"></param>
  		/// <returns></returns>
  		protected bool MustCheckLOS(GameLiving living)
  		{
  			foreach (AbstractArea area in living.CurrentAreas)
  			{
  				if (area.CheckLOS)
  				{
  					return true;
  				}
  			}
  
  			return false;
  		}
  
  
  		/// <summary>
  		/// Check the Line of Sight from you to your pet
  		/// </summary>
  		/// <param name="player">The player</param>
  		/// <param name="response">The result</param>
  		/// <param name="targetOID">The target OID</param>
  		public virtual void CheckLOSYouToPet(GamePlayer player, ushort response, ushort targetOID)
  		{
  			if (player == null) // Hmm
  				return;
  			if ((response & 0x100) == 0x100) // In view ?
  				return;
  			MessageToLiving(player, "Your pet not in view.", eChatType.CT_SpellResisted);
  			InterruptCasting(); // break;
  		}
  
  		/// <summary>
  		/// Check the Line of Sight from a player to a target
  		/// </summary>
  		/// <param name="player">The player</param>
  		/// <param name="response">The result</param>
  		/// <param name="targetOID">The target OID</param>
  		public virtual void CheckLOSPlayerToTarget(GamePlayer player, ushort response, ushort targetOID)
  		{
  			if (player == null) // Hmm
  				return;
  
  			if ((response & 0x100) == 0x100) // In view?
  				return;
  
  			if (ServerProperties.Properties.ENABLE_DEBUG)
  			{
  				MessageToCaster("LoS Interrupt in CheckLOSPlayerToTarget", eChatType.CT_System);
  				log.Debug("LoS Interrupt in CheckLOSPlayerToTarget");
  			}
  
  			if (Caster is GamePlayer)
  			{
  				MessageToCaster("You can't see your target from here!", eChatType.CT_SpellResisted);
  				if (Spell.IsFocus && Spell.IsHarmful)
  				{
  					FocusSpellAction(null, Caster, null);
  				}
  			}
  
  			InterruptCasting();
  		}
  
  		/// <summary>
  		/// Check the Line of Sight from an npc to a target
  		/// </summary>
  		/// <param name="player">The player</param>
  		/// <param name="response">The result</param>
  		/// <param name="targetOID">The target OID</param>
  		public virtual void CheckLOSNPCToTarget(GamePlayer player, ushort response, ushort targetOID)
  		{
  			if (player == null) // Hmm
  				return;
  
  			if ((response & 0x100) == 0x100) // In view?
  				return;
  
  			if (ServerProperties.Properties.ENABLE_DEBUG)
  			{
  				MessageToCaster("LoS Interrupt in CheckLOSNPCToTarget", eChatType.CT_System);
  				log.Debug("LoS Interrupt in CheckLOSNPCToTarget");
  			}
  
  			InterruptCasting();
  		}
  		/// <summary>
  		/// Checks after casting before spell is executed
  		/// </summary>
  		/// <param name="target"></param>
  		/// <returns></returns>
  		public virtual bool CheckEndCast(GameLiving target)
  		{
  			if (m_caster.ObjectState != GameLiving.eObjectState.Active)
  			{
  				return false;
  			}
  
  			if (!m_caster.IsAlive)
  			{
  				MessageToCaster("You are dead and can't cast!", eChatType.CT_System);
  				return false;
  			}
  
  			if (m_spell.InstrumentRequirement != 0)
  			{
  				if (!CheckInstrument())
  				{
  					MessageToCaster("You are not wielding the right type of instrument!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_caster.IsSitting) // songs can be played if sitting
  			{
  				//Purge can be cast while sitting but only if player has negative effect that
  				//don't allow standing up (like stun or mez)
  				MessageToCaster("You can't cast while sitting!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_spell.Target.ToLower() == "area")
  			{
  				if (!m_caster.IsWithinRadius(m_caster.GroundTarget, CalculateSpellRange()))
  				{
  					MessageToCaster("Your area target is out of range.  Select a closer target.", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_spell.Target.ToLower() != "self" && m_spell.Target.ToLower() != "group" && m_spell.Target.ToLower() != "cone" && m_spell.Range > 0)
  			{
  				if (m_spell.Target.ToLower() != "pet")
  				{
  					//all other spells that need a target
  					if (target == null || target.ObjectState != GameObject.eObjectState.Active)
  					{
  						if (Caster is GamePlayer)
  							MessageToCaster("You must select a target for this spell!", eChatType.CT_SpellResisted);
  						return false;
  					}
  
  					if (!m_caster.IsWithinRadius(target, CalculateSpellRange()))
  					{
  						if (Caster is GamePlayer)
  							MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  						return false;
  					}
  				}
  
  				switch (m_spell.Target)
  				{
  					case "Enemy":
  						//enemys have to be in front and in view for targeted spells
  						if (!m_caster.IsObjectInFront(target, 180))
  						{
  							MessageToCaster("Your target is not in view. The spell fails.", eChatType.CT_SpellResisted);
  							return false;
  						}
  
  						if (!GameServer.ServerRules.IsAllowedToAttack(Caster, target, false))
  						{
  							return false;
  						}
  						break;
  
  					case "Corpse":
  						if (target.IsAlive || !GameServer.ServerRules.IsSameRealm(Caster, target, true))
  						{
  							MessageToCaster("This spell only works on dead members of your realm!",
  											eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  
  					case "Realm":
  						if (GameServer.ServerRules.IsAllowedToAttack(Caster, target, true))
  						{
  							return false;
  						}
  						break;
  
  					case "Pet":
  						/*
  						 * [Ganrod] Nidel: Can cast pet spell on all Pet/Turret/Minion (our pet)
  						 * -If caster target's isn't own pet.
  						 *  -check if caster have controlled pet, select this automatically
  						 *  -check if target isn't null
  						 * -check if target isn't too far away
  						 * If all checks isn't true, return false.
  						 */
  						if (target == null || !Caster.IsControlledNPC(target as GameNPC))
  						{
  							if (Caster.ControlledBrain != null && Caster.ControlledBrain.Body != null)
  							{
  								target = Caster.ControlledBrain.Body;
  							}
  							else
  							{
  								MessageToCaster("You must cast this spell on a creature you are controlling.", eChatType.CT_System);
  								return false;
  							}
  						}
  						//Now check distance for own pet
  						if (!m_caster.IsWithinRadius(target, CalculateSpellRange()))
  						{
  							MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  				}
  			}
  
  			if (m_caster.Mana <= 0 && Spell.Power != 0 && Spell.SpellType != "Archery")
  			{
  				MessageToCaster("You have exhausted all of your power and cannot cast spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  			if (Spell.Power != 0 && m_caster.Mana < PowerCost(target) && Spell.SpellType != "Archery")
  			{
  				MessageToCaster("You don't have enough power to cast that!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.Concentration < m_spell.Concentration)
  			{
  				MessageToCaster("This spell requires " + m_spell.Concentration + " concentration points to cast!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.ConcentrationEffects.ConcSpellsCount >= 50)
  			{
  				MessageToCaster("You can only cast up to 50 simultaneous concentration spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			return true;
  		}
  
  		public virtual bool CheckDuringCast(GameLiving target)
  		{
  			return CheckDuringCast(target, false);
  		}
  
  		public virtual bool CheckDuringCast(GameLiving target, bool quiet)
  		{
  			if (m_interrupted)
  			{
  				return false;
  			}
  
  			if (!m_spell.Uninterruptible && m_spell.CastTime > 0 && m_caster is GamePlayer &&
  				m_caster.EffectList.GetOfType<QuickCastEffect>() == null && m_caster.EffectList.GetOfType<MasteryofConcentrationEffect>() == null)
  			{
  				if (Caster.InterruptTime > 0 && Caster.InterruptTime > m_started)
  				{
  					if (!quiet)
  					{
  						if (Caster.LastInterruptMessage != "") MessageToCaster(Caster.LastInterruptMessage, eChatType.CT_SpellResisted);
  						else MessageToCaster("You are interrupted and must wait " + ((Caster.InterruptTime - m_started) / 1000 + 1).ToString() + " seconds to cast a spell!", eChatType.CT_SpellResisted);
  					}
  					return false;
  				}
  			}
  
  			if (m_caster.ObjectState != GameLiving.eObjectState.Active)
  			{
  				return false;
  			}
  
  			if (!m_caster.IsAlive)
  			{
  				if (!quiet) MessageToCaster("You are dead and can't cast!", eChatType.CT_System);
  				return false;
  			}
  
  			if (m_spell.InstrumentRequirement != 0)
  			{
  				if (!CheckInstrument())
  				{
  					if (!quiet) MessageToCaster("You are not wielding the right type of instrument!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_caster.IsSitting) // songs can be played if sitting
  			{
  				//Purge can be cast while sitting but only if player has negative effect that
  				//don't allow standing up (like stun or mez)
  				if (!quiet) MessageToCaster("You can't cast while sitting!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_spell.Target.ToLower() == "area")
  			{
  				if (!m_caster.IsWithinRadius(m_caster.GroundTarget, CalculateSpellRange()))
  				{
  					if (!quiet) MessageToCaster("Your area target is out of range.  Select a closer target.", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_spell.Target.ToLower() != "self" && m_spell.Target.ToLower() != "group" && m_spell.Target.ToLower() != "cone" && m_spell.Range > 0)
  			{
  				if (m_spell.Target.ToLower() != "pet")
  				{
  					//all other spells that need a target
  					if (target == null || target.ObjectState != GameObject.eObjectState.Active)
  					{
  						if (Caster is GamePlayer && !quiet)
  							MessageToCaster("You must select a target for this spell!", eChatType.CT_SpellResisted);
  						return false;
  					}
  
  					if (Caster is GamePlayer && !m_caster.IsWithinRadius(target, CalculateSpellRange()))
  					{
  						if (!quiet) MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  						return false;
  					}
  				}
  
  				switch (m_spell.Target.ToLower())
  				{
  					case "enemy":
  						//enemys have to be in front and in view for targeted spells
  						if (Caster is GamePlayer && !m_caster.IsObjectInFront(target, 180) && !Caster.IsWithinRadius(target, 50))
  						{
  							if (!quiet) MessageToCaster("Your target is not in view. The spell fails.", eChatType.CT_SpellResisted);
  							return false;
  						}
  
  						if (ServerProperties.Properties.CHECK_LOS_DURING_CAST)
  						{
  							GamePlayer playerChecker = null;
  
  							if (target is GamePlayer)
  							{
  								playerChecker = target as GamePlayer;
  							}
  							else if (Caster is GamePlayer)
  							{
  								playerChecker = Caster as GamePlayer;
  							}
  							else if (Caster is GameNPC && (Caster as GameNPC).Brain != null && (Caster as GameNPC).Brain is IControlledBrain)
  							{
  								playerChecker = ((Caster as GameNPC).Brain as IControlledBrain).GetPlayerOwner();
  							}
  
  							if (playerChecker != null)
  							{
  								// If the area forces an LoS check then we do it, otherwise we only check
  								// if caster or target is a player
  								// This will generate an interrupt if LOS check fails
  
  								if (Caster is GamePlayer)
  								{
  									playerChecker.Out.SendCheckLOS(Caster, target, new CheckLOSResponse(CheckLOSPlayerToTarget));
  								}
  								else if (target is GamePlayer || MustCheckLOS(Caster))
  								{
  									playerChecker.Out.SendCheckLOS(Caster, target, new CheckLOSResponse(CheckLOSNPCToTarget));
  								}
  							}
  						}
  
  						if (!GameServer.ServerRules.IsAllowedToAttack(Caster, target, quiet))
  						{
  							return false;
  						}
  						break;
  
  					case "corpse":
  						if (target.IsAlive || !GameServer.ServerRules.IsSameRealm(Caster, target, quiet))
  						{
  							if (!quiet) MessageToCaster("This spell only works on dead members of your realm!",
  														eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  
  					case "realm":
  						if (GameServer.ServerRules.IsAllowedToAttack(Caster, target, true))
  						{
  							return false;
  						}
  						break;
  
  					case "pet":
  						/*
  						 * Can cast pet spell on all Pet/Turret/Minion (our pet)
  						 * -If caster target's isn't own pet.
  						 *  -check if caster have controlled pet, select this automatically
  						 *  -check if target isn't null
  						 * -check if target isn't too far away
  						 * If all checks isn't true, return false.
  						 */
  						if (target == null || !Caster.IsControlledNPC(target as GameNPC))
  						{
  							if (Caster.ControlledBrain != null && Caster.ControlledBrain.Body != null)
  							{
  								target = Caster.ControlledBrain.Body;
  							}
  							else
  							{
  								if (!quiet) MessageToCaster("You must cast this spell on a creature you are controlling.", eChatType.CT_System);
  								return false;
  							}
  						}
  						//Now check distance for own pet
  						if (!m_caster.IsWithinRadius(target, CalculateSpellRange()))
  						{
  							if (!quiet) MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  				}
  			}
  
  			if (m_caster.Mana <= 0 && Spell.Power != 0 && Spell.SpellType != "Archery")
  			{
  				if (!quiet) MessageToCaster("You have exhausted all of your power and cannot cast spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  			if (Spell.Power != 0 && m_caster.Mana < PowerCost(target) && Spell.SpellType != "Archery")
  			{
  				if (!quiet) MessageToCaster("You don't have enough power to cast that!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.Concentration < m_spell.Concentration)
  			{
  				if (!quiet) MessageToCaster("This spell requires " + m_spell.Concentration + " concentration points to cast!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.ConcentrationEffects.ConcSpellsCount >= 50)
  			{
  				if (!quiet) MessageToCaster("You can only cast up to 50 simultaneous concentration spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			return true;
  		}
  
  		public virtual bool CheckAfterCast(GameLiving target)
  		{
  			return CheckAfterCast(target, false);
  		}
  
  
  		public virtual bool CheckAfterCast(GameLiving target, bool quiet)
  		{
  			if (m_interrupted)
  			{
  				return false;
  			}
  
  			if (!m_spell.Uninterruptible && m_spell.CastTime > 0 && m_caster is GamePlayer &&
  				m_caster.EffectList.GetOfType<QuickCastEffect>() == null && m_caster.EffectList.GetOfType<MasteryofConcentrationEffect>() == null)
  			{
  				if (Caster.InterruptTime > 0 && Caster.InterruptTime > m_started)
  				{
  					if (!quiet)
  					{
  						if (Caster.LastInterruptMessage != "") MessageToCaster(Caster.LastInterruptMessage, eChatType.CT_SpellResisted);
  						else MessageToCaster("You are interrupted and must wait " + ((Caster.InterruptTime - m_started) / 1000 + 1).ToString() + " seconds to cast a spell!", eChatType.CT_SpellResisted);
  					}
  					Caster.InterruptAction = Caster.CurrentRegion.Time - Caster.SpellInterruptRecastAgain;
  					return false;
  				}
  			}
  
  			if (m_caster.ObjectState != GameLiving.eObjectState.Active)
  			{
  				return false;
  			}
  
  			if (!m_caster.IsAlive)
  			{
  				if (!quiet) MessageToCaster("You are dead and can't cast!", eChatType.CT_System);
  				return false;
  			}
  
  			if (m_spell.InstrumentRequirement != 0)
  			{
  				if (!CheckInstrument())
  				{
  					if (!quiet) MessageToCaster("You are not wielding the right type of instrument!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_caster.IsSitting) // songs can be played if sitting
  			{
  				//Purge can be cast while sitting but only if player has negative effect that
  				//don't allow standing up (like stun or mez)
  				if (!quiet) MessageToCaster("You can't cast while sitting!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_spell.Target.ToLower() == "area")
  			{
  				if (!m_caster.IsWithinRadius(m_caster.GroundTarget, CalculateSpellRange()))
  				{
  					if (!quiet) MessageToCaster("Your area target is out of range.  Select a closer target.", eChatType.CT_SpellResisted);
  					return false;
  				}
  				if (!Caster.GroundTargetInView)
  				{
  					MessageToCaster("Your ground target is not in view!", eChatType.CT_SpellResisted);
  					return false;
  				}
  			}
  			else if (m_spell.Target.ToLower() != "self" && m_spell.Target.ToLower() != "group" && m_spell.Target.ToLower() != "cone" && m_spell.Range > 0)
  			{
  				if (m_spell.Target.ToLower() != "pet")
  				{
  					//all other spells that need a target
  					if (target == null || target.ObjectState != GameObject.eObjectState.Active)
  					{
  						if (Caster is GamePlayer && !quiet)
  							MessageToCaster("You must select a target for this spell!", eChatType.CT_SpellResisted);
  						return false;
  					}
  
  					if (Caster is GamePlayer && !m_caster.IsWithinRadius(target, CalculateSpellRange()))
  					{
  						if (!quiet) MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  						return false;
  					}
  				}
  
  				switch (m_spell.Target)
  				{
  					case "Enemy":
  						//enemys have to be in front and in view for targeted spells
  						if (Caster is GamePlayer && !m_caster.IsObjectInFront(target, 180) && !Caster.IsWithinRadius(target, 50))
  						{
  							if (!quiet) MessageToCaster("Your target is not in view. The spell fails.", eChatType.CT_SpellResisted);
  							return false;
  						}
  
  						if (!GameServer.ServerRules.IsAllowedToAttack(Caster, target, quiet))
  						{
  							return false;
  						}
  						break;
  
  					case "Corpse":
  						if (target.IsAlive || !GameServer.ServerRules.IsSameRealm(Caster, target, quiet))
  						{
  							if (!quiet) MessageToCaster("This spell only works on dead members of your realm!", eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  
  					case "Realm":
  						if (GameServer.ServerRules.IsAllowedToAttack(Caster, target, true))
  						{
  							return false;
  						}
  						break;
  
  					case "Pet":
  						/*
  						 * [Ganrod] Nidel: Can cast pet spell on all Pet/Turret/Minion (our pet)
  						 * -If caster target's isn't own pet.
  						 *  -check if caster have controlled pet, select this automatically
  						 *  -check if target isn't null
  						 * -check if target isn't too far away
  						 * If all checks isn't true, return false.
  						 */
  						if (target == null || !Caster.IsControlledNPC(target as GameNPC))
  						{
  							if (Caster.ControlledBrain != null && Caster.ControlledBrain.Body != null)
  							{
  								target = Caster.ControlledBrain.Body;
  							}
  							else
  							{
  								if (!quiet) MessageToCaster("You must cast this spell on a creature you are controlling.", eChatType.CT_System);
  								return false;
  							}
  						}
  						//Now check distance for own pet
  						if (!m_caster.IsWithinRadius(target, CalculateSpellRange()))
  						{
  							if (!quiet) MessageToCaster("That target is too far away!", eChatType.CT_SpellResisted);
  							return false;
  						}
  						break;
  				}
  			}
  
  			if (m_caster.Mana <= 0 && Spell.Power != 0 && Spell.SpellType != "Archery")
  			{
  				if (!quiet) MessageToCaster("You have exhausted all of your power and cannot cast spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  			if (Spell.Power != 0 && m_caster.Mana < PowerCost(target) && Spell.SpellType != "Archery")
  			{
  				if (!quiet) MessageToCaster("You don't have enough power to cast that!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.Concentration < m_spell.Concentration)
  			{
  				if (!quiet) MessageToCaster("This spell requires " + m_spell.Concentration + " concentration points to cast!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			if (m_caster is GamePlayer && m_spell.Concentration > 0 && m_caster.ConcentrationEffects.ConcSpellsCount >= 50)
  			{
  				if (!quiet) MessageToCaster("You can only cast up to 50 simultaneous concentration spells!", eChatType.CT_SpellResisted);
  				return false;
  			}
  
  			return true;
  		}
  
  
  		#endregion
  
  		/// <summary>
  		/// Calculates the power to cast the spell
  		/// </summary>
  		/// <param name="target"></param>
  		/// <returns></returns>
  		public virtual int PowerCost(GameLiving target)
  		{
  			// warlock
  			GameSpellEffect effect = SpellHandler.FindEffectOnTarget(m_caster, "Powerless");
  			if (effect != null && !m_spell.IsPrimary)
  				return 0;
  
  			//1.108 - Valhallas Blessing now has a 75% chance to not use power.
  			ValhallasBlessingEffect ValhallasBlessing = m_caster.EffectList.GetOfType<ValhallasBlessingEffect>();
  			if (ValhallasBlessing != null && Util.Chance(75))
  				return 0;
  
  			//patch 1.108 increases the chance to not use power to 50%.
  			FungalUnionEffect FungalUnion = m_caster.EffectList.GetOfType<FungalUnionEffect>();
  			{
  				if (FungalUnion != null && Util.Chance(50))
  					return 0;
  			}
  
  			// Arcane Syphon chance
  			int syphon = Caster.GetModified(eProperty.ArcaneSyphon);
  			if (syphon > 0)
  			{
  				if (Util.Chance(syphon))
  				{
  					return 0;
  				}
  			}
  
  			double basepower = m_spell.Power; //<== defined a basevar first then modified this base-var to tell %-costs from absolut-costs
  
  			// percent of maxPower if less than zero
  			if (basepower < 0)
  			{
  				if (Caster is GamePlayer && ((GamePlayer)Caster).CharacterClass.ManaStat != eStat.UNDEFINED)
  				{
  					GamePlayer player = Caster as GamePlayer;
  					basepower = player.CalculateMaxMana(player.Level, player.GetBaseStat(player.CharacterClass.ManaStat)) * basepower * -0.01;
  				}
  				else
  				{
  					basepower = Caster.MaxMana * basepower * -0.01;
  				}
  			}
  
  			double power = basepower * 1.2; //<==NOW holding basepower*1.2 within 'power'
  
  			eProperty focusProp = SkillBase.SpecToFocus(SpellLine.Spec);
  			if (focusProp != eProperty.Undefined)
  			{
  				double focusBonus = Caster.GetModified(focusProp) * 0.4;
  				if (Spell.Level > 0)
  					focusBonus /= Spell.Level;
  				if (focusBonus > 0.4)
  					focusBonus = 0.4;
  				else if (focusBonus < 0)
  					focusBonus = 0;
  				power -= basepower * focusBonus; //<== So i can finally use 'basepower' for both calculations: % and absolut
  			}
  			else if (Caster is GamePlayer && ((GamePlayer)Caster).CharacterClass.ClassType == eClassType.Hybrid)
  			{
  				double specBonus = 0;
  				if (Spell.Level != 0) specBonus = (((GamePlayer)Caster).GetBaseSpecLevel(SpellLine.Spec) * 0.4 / Spell.Level);
  
  				if (specBonus > 0.4)
  					specBonus = 0.4;
  				else if (specBonus < 0)
  					specBonus = 0;
  				power -= basepower * specBonus;
  			}
  			// doubled power usage if quickcasting
  			if (Caster.EffectList.GetOfType<QuickCastEffect>() != null && Spell.CastTime > 0)
  				power *= 2;
  			return (int)power;
  		}
  
  		/// <summary>
  		/// Calculates the enduance cost of the spell
  		/// </summary>
  		/// <returns></returns>
  		public virtual int CalculateEnduranceCost()
  		{
  			return 5;
  		}
  
  		/// <summary>
  		/// Calculates the range to target needed to cast the spell
  		/// NOTE: This method returns a minimum value of 32
  		/// </summary>
  		/// <returns></returns>
  		public virtual int CalculateSpellRange()
  		{
  			int range = Math.Max(32, (int)(Spell.Range * Caster.GetModified(eProperty.SpellRange) * 0.01));
  			return range;
  			//Dinberg: add for warlock range primer
  		}
  
  		/// <summary>
  		/// Called whenever the casters casting sequence is to interrupt immediately
  		/// </summary>
  		public virtual void InterruptCasting()
  		{
  			if (m_interrupted || !IsCasting)
  				return;
  
  			m_interrupted = true;
  
  			if (IsCasting)
  			{
  				foreach (GamePlayer player in m_caster.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
  				{
  					player.Out.SendInterruptAnimation(m_caster);
  				}
  			}
  
  			if (m_castTimer != null)
  			{
  				m_castTimer.Stop();
  				m_castTimer = null;
  
  				if (m_caster is GamePlayer)
  				{
  					((GamePlayer)m_caster).ClearSpellQueue();
  				}
  			}
  
  			m_startReuseTimer = false;
  			OnAfterSpellCastSequence();
  		}
  
  		/// <summary>
  		/// Casts a spell after the CastTime delay
  		/// </summary>
  		protected class DelayedCastTimer : GameTimer
  		{
  			/// <summary>
  			/// The spellhandler instance with callbacks
  			/// </summary>
  			private readonly SpellHandler m_handler;
  			/// <summary>
  			/// The target object at the moment of CastSpell call
  			/// </summary>
  			private readonly GameLiving m_target;
  			private readonly GameLiving m_caster;
  			private byte m_stage;
  			private readonly int m_delay1;
  			private readonly int m_delay2;
  			private readonly byte m_delay1_substeps;
  			private byte m_stepcount;
  
  			/// <summary>
  			/// Constructs a new DelayedSpellTimer
  			/// </summary>
  			/// <param name="actionSource">The caster</param>
  			/// <param name="handler">The spell handler</param>
  			/// <param name="target">The target object</param>
  			/// <param name="delay1">Amount of time to wait in stage 1</param>
  			/// <param name="delay2">Amount of time to wait in stage 2</param>
  			/// <param name="delay1_substeps">Number of times to repeat stage 1</param>
  			public DelayedCastTimer( GameLiving actionSource, SpellHandler handler, GameLiving target, int delay1, int delay2, byte delay1_substeps )
  				: base( actionSource.CurrentRegion.TimeManager )
  			{
  				if( handler == null )
  					throw new ArgumentNullException( "handler" );
  
  				if( actionSource == null )
  					throw new ArgumentNullException( "actionSource" );
  
  				m_handler = handler;
  				m_target = target;
  				m_caster = actionSource;
  				m_stage = 0;
  				m_delay1 = delay1;
  				m_delay2 = delay2;
  				m_delay1_substeps = delay1_substeps;
  				m_stepcount = 0;
  			}
  
  			/// <summary>
  			/// Called on every timer tick
  			/// </summary>
  			protected override void OnTick()
  			{
  				try
  				{
  					if (m_stage == 0)
  					{
  						if (!m_handler.CheckAfterCast(m_target))
  						{
  							Interval = 0;
  							m_handler.InterruptCasting();
  							m_handler.OnAfterSpellCastSequence();
  							return;
  						}
  						m_stage = 1;
  						m_handler.Stage = 1;
  						Interval = m_delay1;
  					}
  					else if (m_stage == 1)
  					{
  						++m_stepcount;
  						if (!m_handler.CheckDuringCast(m_target))
  						{
  							Interval = 0;
  							m_handler.InterruptCasting();
  							m_handler.OnAfterSpellCastSequence();
  							return;
  						}
  						if( m_stepcount < m_delay1_substeps )
  							return;
  						m_stage = 2;
  						m_handler.Stage = 2;
  						Interval = m_delay2;
  					}
  					else if (m_stage == 2)
  					{
  						m_stage = 3;
  						m_handler.Stage = 3;
  						Interval = 100;
  
  						if (m_handler.CheckEndCast(m_target))
  						{
  							m_handler.FinishSpellCast(m_target);
  						}
  					}
  					else
  					{
  						m_stage = 4;
  						m_handler.Stage = 4;
  						Interval = 0;
  						m_handler.OnAfterSpellCastSequence();
  					}
  
  					if (m_caster is GamePlayer && ServerProperties.Properties.ENABLE_DEBUG && m_stage < 3)
  					{
  						(m_caster as GamePlayer).Out.SendMessage("[DEBUG] step = " + (m_handler.Stage + 1), eChatType.CT_System, eChatLoc.CL_SystemWindow);
  					}
  
  					return;
  				}
  				catch (Exception e)
  				{
  					if (log.IsErrorEnabled)
  						log.Error(ToString(), e);
  				}
  
  				m_handler.OnAfterSpellCastSequence();
  				Interval = 0;
  			}
  
  			/// <summary>
  			/// Returns short information about the timer
  			/// </summary>
  			/// <returns>Short info about the timer</returns>
  			public override string ToString()
  			{
  				return new StringBuilder(base.ToString(), 128)
  					.Append(" spellhandler: (").Append(m_handler.ToString()).Append(')')
  					.ToString();
  			}
  		}
  
  		/// <summary>
  		/// Calculates the effective casting time
  		/// </summary>
  		/// <returns>effective casting time in milliseconds</returns>
  		public virtual int CalculateCastingTime()
  		{
  			return m_caster.CalculateCastingTime(m_spellLine, m_spell);
  		}
  
  
  		#region animations
  
  		/// <summary>
  		/// Sends the cast animation
  		/// </summary>
  		public virtual void SendCastAnimation()
  		{
  			ushort castTime = (ushort)(CalculateCastingTime() / 100);
  			SendCastAnimation(castTime);
  		}
  
  		/// <summary>
  		/// Sends the cast animation
  		/// </summary>
  		/// <param name="castTime">The cast time</param>
  		public virtual void SendCastAnimation(ushort castTime)
  		{
  			foreach (GamePlayer player in m_caster.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
  			{
  				if (player == null)
  					continue;
  				player.Out.SendSpellCastAnimation(m_caster, m_spell.ClientEffect, castTime);
  			}
  		}
  
  		/// <summary>
  		/// Send the Effect Animation
  		/// </summary>
  		/// <param name="target">The target object</param>
  		/// <param name="boltDuration">The duration of a bolt</param>
  		/// <param name="noSound">sound?</param>
  		/// <param name="success">spell success?</param>
  		public virtual void SendEffectAnimation(GameObject target, ushort boltDuration, bool noSound, byte success)
  		{
  			if (target == null)
  				target = m_caster;
  
  			foreach (GamePlayer player in target.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
  			{
  				player.Out.SendSpellEffectAnimation(m_caster, target, m_spell.ClientEffect, boltDuration, noSound, success);
  			}
  		}
  
  		/// <summary>
  		/// Send the Interrupt Cast Animation
  		/// </summary>
  		public virtual void SendInterruptCastAnimation()
  		{
  			foreach (GamePlayer player in m_caster.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
  			{
  				player.Out.SendInterruptAnimation(m_caster);
  			}
  		}
  		public virtual void SendEffectAnimation(GameObject target, ushort clientEffect, ushort boltDuration, bool noSound, byte success)
  		{
  			if (target == null)
  				target = m_caster;
  
  			foreach (GamePlayer player in target.GetPlayersInRadius(WorldMgr.VISIBILITY_DISTANCE))
  			{
  				player.Out.SendSpellEffectAnimation(m_caster, target, clientEffect, boltDuration, noSound, success);
  			}
  		}
  		#endregion
  
  		/// <summary>
  		/// called after normal spell cast is completed and effect has to be started
  		/// </summary>
  		public virtual void FinishSpellCast(GameLiving target)
  		{
  			if (Caster is GamePlayer && ((GamePlayer)Caster).IsOnHorse && !HasPositiveEffect)
  				((GamePlayer)Caster).IsOnHorse = false;
  
  			//[Stryve]: Do not break stealth if spell never breaks stealth.
  			if ((Caster is GamePlayer) && UnstealthCasterOnFinish)
  				((GamePlayer)Caster).Stealth(false);
  
  			if (Caster is GamePlayer && !HasPositiveEffect)
  			{
  				if (Caster.AttackWeapon != null && Caster.AttackWeapon is GameInventoryItem)
  				{
  					(Caster.AttackWeapon as GameInventoryItem).OnSpellCast(Caster, target, Spell);
  				}
  			}
  
  			// messages
  			if (Spell.InstrumentRequirement == 0 && Spell.ClientEffect != 0 && Spell.CastTime > 0)
  			{
  				MessageToCaster("You cast a " + m_spell.Name + " spell!", eChatType.CT_Spell);
  				foreach (GamePlayer player in m_caster.GetPlayersInRadius(WorldMgr.INFO_DISTANCE))
  				{
  					if (player != m_caster)
  						player.MessageFromArea(m_caster, m_caster.GetName(0, true) + " casts a spell!", eChatType.CT_Spell, eChatLoc.CL_SystemWindow);
  				}
  			}
  
  			if (m_spell.Pulse != 0 && m_spell.Frequency > 0)
  			{
  				CancelAllPulsingSpells(Caster);
  				PulsingSpellEffect pulseeffect = new PulsingSpellEffect(this);
  				pulseeffect.Start();
  				// show animation on caster for positive spells, negative shows on every StartSpell
  				if (m_spell.Target == "Self" || m_spell.Target == "Group")
  					SendEffectAnimation(Caster, 0, false, 1);
  				if (m_spell.Target == "Pet")
  					SendEffectAnimation(target, 0, false, 1);
  			}
  
  			StartSpell(target); // and action
  
  			//Dinberg: This is where I moved the warlock part (previously found in gameplayer) to prevent
  			//cancelling before the spell was fired.
  			if (m_spell.SpellType != "Powerless" && m_spell.SpellType != "Range" && m_spell.SpellType != "Uninterruptable")
  			{
  				GameSpellEffect effect = SpellHandler.FindEffectOnTarget(m_caster, "Powerless");
  				if (effect == null)
  					effect = SpellHandler.FindEffectOnTarget(m_caster, "Range");
  				if (effect == null)
  					effect = SpellHandler.FindEffectOnTarget(m_caster, "Uninterruptable");
  
  				//if we found an effect, cancel it!
  				if (effect != null)
  					effect.Cancel(false);
  			}
  
  			//the quick cast is unallowed whenever you miss the spell
  			//set the time when casting to can not quickcast during a minimum time
  			if (m_caster is GamePlayer)
  			{
  				QuickCastEffect quickcast = m_caster.EffectList.GetOfType<QuickCastEffect>();
  				if (quickcast != null && Spell.CastTime > 0)
  				{
  					m_caster.TempProperties.setProperty(GamePlayer.QUICK_CAST_CHANGE_TICK, m_caster.CurrentRegion.Time);
  					((GamePlayer)m_caster).DisableSkill(SkillBase.GetAbility(Abilities.Quickcast), QuickCastAbilityHandler.DISABLE_DURATION);
  					quickcast.Cancel(false);
  				}
  			}
  
  
  			if (m_ability != null)
  				m_caster.DisableSkill(m_ability.Ability, (m_spell.RecastDelay == 0 ? 3000 : m_spell.RecastDelay));
  
  			// disable spells with recasttimer (Disables group of same type with same delay)
  			if (m_spell.RecastDelay > 0 && m_startReuseTimer)
  			{
  				if (m_caster is GamePlayer)
  				{
  					ICollection<Tuple<Skill, int>> toDisable = new List<Tuple<Skill, int>>();
  
  					GamePlayer gp_caster = m_caster as GamePlayer;
  					foreach (var skills in gp_caster.GetAllUsableSkills())
  						if (skills.Item1 is Spell &&
  							(((Spell)skills.Item1).ID == m_spell.ID || (((Spell)skills.Item1).SharedTimerGroup != 0 && (((Spell)skills.Item1).SharedTimerGroup == m_spell.SharedTimerGroup))))
  							toDisable.Add(new Tuple<Skill, int>((Spell)skills.Item1, m_spell.RecastDelay));
  
  					foreach (var sl in gp_caster.GetAllUsableListSpells())
  						foreach (var sp in sl.Item2)
  							if (sp is Spell &&
  								(((Spell)sp).ID == m_spell.ID || (((Spell)sp).SharedTimerGroup != 0 && (((Spell)sp).SharedTimerGroup == m_spell.SharedTimerGroup))))
  								toDisable.Add(new Tuple<Skill, int>((Spell)sp, m_spell.RecastDelay));
  
  					m_caster.DisableSkill(toDisable);
  				}
  				else if (m_caster is GameNPC)
  					m_caster.DisableSkill(m_spell, m_spell.RecastDelay);
  			}
  
  			GameEventMgr.Notify(GameLivingEvent.CastFinished, m_caster, new CastingEventArgs(this, target, m_lastAttackData));
  		}
  
  		/// <summary>
  		/// Select all targets for this spell
  		/// </summary>
  		/// <param name="castTarget"></param>
  		/// <returns></returns>
  		public virtual IList<GameLiving> SelectTargets(GameObject castTarget)
  		{
  			var list = new List<GameLiving>(8);
  			GameLiving target = castTarget as GameLiving;
  			bool targetchanged = false;
  			string modifiedTarget = Spell.Target.ToLower();
  			ushort modifiedRadius = (ushort)Spell.Radius;
  			int newtarget = 0;
  
  			GameSpellEffect TargetMod = SpellHandler.FindEffectOnTarget(m_caster, "TargetModifier");
  			if (TargetMod != null)
  			{
  				if (modifiedTarget == "enemy" || modifiedTarget == "realm" || modifiedTarget == "group")
  				{
  					newtarget = (int)TargetMod.Spell.Value;
  
  					switch (newtarget)
  					{
  
gt: 						case 0: // Apply on heal single