using System;
using System.Collections.Generic;
using Server.Spells;
using Server.Spells.Fifth;
using Server.Spells.First;
using Server.Spells.Fourth;
using Server.Spells.Necromancy;
using Server.Spells.Second;
using Server.Spells.Seventh;
using Server.Spells.Sixth;
using Server.Spells.Third;
using Server.Targeting;

namespace Server.Mobiles
{
	public class MageAI : BaseAI
	{
		private DateTime m_NextCastTime;
		private DateTime m_NextHealTime;

		public MageAI( BaseCreature m ) : base( m )
		{
		}

		public override bool Think()
		{
			if ( m_Mobile.Deleted )
				return false;

			if ( ProcessTarget() )
				return true;
			else
				return base.Think();
		}

        public virtual bool SmartAI
        {
            get { return (m_Mobile is BaseVendor || m_Mobile is BaseEscortable/* || m_Mobile is Changeling*/ ); } // TODO: Uncomment once added
        }

        public virtual bool IsNecromancer
        {
            get { return (m_Mobile.Skills[SkillName.Necromancy].Value > 50); }
        }

		private const double HealChance = 0.10; // 10% chance to heal at gm magery
		private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery
		private const double DispelChance = 0.75; // 75% chance to dispel at gm magery

        public virtual double ScaleBySkill(double v, SkillName skill)
        {
            return v * m_Mobile.Skills[skill].Value / 100;
        }

		public override bool DoActionWander()
		{
			if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
			{
                m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);

				m_Mobile.Combatant = m_Mobile.FocusMob;
				Action = ActionType.Combat;
				m_NextCastTime = DateTime.Now;
			}
			else if ( SmartAI && m_Mobile.Mana < m_Mobile.ManaMax )
			{
				m_Mobile.DebugSay( "I am going to meditate" );

				m_Mobile.UseSkill( SkillName.Meditation );
			}
			else
			{
				m_Mobile.DebugSay( "I am wandering" );

				m_Mobile.Warmode = false;

				base.DoActionWander();

                if ((Utility.RandomDouble() < .05))
                {
					Spell spell = CheckCastHealingSpell();

					if ( spell != null )
						spell.Cast();
				}
			}

			return true;
		}

		private Spell CheckCastHealingSpell()
		{
			// If I'm poisoned, always attempt to cure.
			if ( m_Mobile.Poisoned )
				return new CureSpell( m_Mobile, null );

			// Summoned creatures never heal themselves.
			if ( m_Mobile.Summoned )
				return null;

			if ( m_Mobile.Controlled )
			{
				if ( DateTime.Now < m_NextHealTime )
					return null;
			}

			if ( !SmartAI )
			{
                if (ScaleBySkill(HealChance, SkillName.Magery) < Utility.RandomDouble())
                    return null;
			}
			else
			{
				if ( Utility.Random( 0, 4 + (m_Mobile.Hits == 0 ? m_Mobile.HitsMax : (m_Mobile.HitsMax / m_Mobile.Hits)) ) < 3 )
					return null;
			}

			Spell spell = null;

            if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
            {
                if (UseNecromancy())
                {
                    m_Mobile.UseSkill(SkillName.SpiritSpeak);
                }
                else
                {
                    spell = new GreaterHealSpell(m_Mobile, null);

                    if (spell == null)
                        spell = new HealSpell(m_Mobile, null);
                }
            }
            else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
            {
                spell = new HealSpell(m_Mobile, null);
            }

			double delay;

			if ( m_Mobile.Int >= 500 )
				delay = Utility.RandomMinMax( 7, 10 );
			else
				delay = Math.Sqrt( 600 - m_Mobile.Int );

			m_NextHealTime = DateTime.Now + TimeSpan.FromSeconds( delay );

			return spell;
		}

		public void RunTo( Mobile m )
		{
			if ( !SmartAI )
			{
				if ( !MoveTo( m, true, m_Mobile.RangeFight ) )
					OnFailedMove();

				return;
			}

			if ( m.Paralyzed || m.Frozen )
			{
				if ( m_Mobile.InRange( m, 1 ) )
					RunFrom( m );
				else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) )
					OnFailedMove();
			}
			else
			{
				if ( !m_Mobile.InRange( m, m_Mobile.RangeFight ) )
				{
					if ( !MoveTo( m, true, 1 ) )
						OnFailedMove();
				}
				else if ( m_Mobile.InRange( m, m_Mobile.RangeFight - 1 ) )
				{
					RunFrom( m );
				}
			}
		}

		public void RunFrom( Mobile m )
		{
			Run( (m_Mobile.GetDirectionTo( m ) - 4) & Direction.Mask );
		}

		public void OnFailedMove()
		{
            if (!m_Mobile.DisallowAllMoves && (SmartAI ? Utility.Random(4) == 0 : ScaleBySkill(TeleportChance, SkillName.Magery) > Utility.RandomDouble()))
            {
				if ( m_Mobile.Target != null )
					m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled );

				new TeleportSpell( m_Mobile, null ).Cast();

				m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" );
			}
			else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
			{
                m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);

				m_Mobile.Combatant = m_Mobile.FocusMob;
				Action = ActionType.Combat;
			}
			else
			{
				m_Mobile.DebugSay( "I am stuck" );
			}
		}

		public void Run( Direction d )
		{
			if ( (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || m_Mobile.Paralyzed || m_Mobile.Frozen || m_Mobile.DisallowAllMoves )
				return;

			m_Mobile.Direction = d | Direction.Running;

			if ( !DoMove( m_Mobile.Direction, true ) )
				OnFailedMove();
		}

        public virtual bool UseNecromancy()
        {
            if (IsNecromancer)
                return (Utility.Random(m_Mobile.Skills[SkillName.Necromancy].BaseFixedPoint) > Utility.Random(m_Mobile.Skills[SkillName.Magery].BaseFixedPoint));

            return false;
        }

        public virtual Spell GetRandomDamageSpell()
        {
            return UseNecromancy() ? GetRandomDamageSpellNecro() : GetRandomDamageSpellMage();
        }

        public virtual Spell GetRandomDamageSpellNecro()
        {
            int bound = (m_Mobile.Skills[SkillName.Necromancy].Value >= 100) ? 5 : 3;

            switch (Utility.Random(bound))
            {
                case 0: m_Mobile.DebugSay("Pain Spike"); return new PainSpikeSpell(m_Mobile, null);
                case 1: m_Mobile.DebugSay("Poison Strike"); return new PoisonStrikeSpell(m_Mobile, null);
                case 2: m_Mobile.DebugSay("Strangle"); return new StrangleSpell(m_Mobile, null);
                case 3: m_Mobile.DebugSay("Wither"); return new WitherSpell(m_Mobile, null);
                default: m_Mobile.DebugSay("Vengeful Spirit"); return new VengefulSpiritSpell(m_Mobile, null);
            }
        }

        public virtual Spell GetRandomDamageSpellMage()
        {
            int maxCircle = (int)((m_Mobile.Skills[SkillName.Magery].Value + 20.0) / (100.0 / 7.0));

            if (maxCircle < 1)
                maxCircle = 1;
            else if (maxCircle > 8)
                maxCircle = 8;

            switch (Utility.Random(maxCircle * 2))
            {
                case 0:
                case 1: return new MagicArrowSpell(m_Mobile, null);
                case 2:
                case 3: return new HarmSpell(m_Mobile, null);
                case 4:
                case 5: return new FireballSpell(m_Mobile, null);
                case 6:
                case 7: return new LightningSpell(m_Mobile, null);
                case 8:
                case 9: return new MindBlastSpell(m_Mobile, null);
                case 10: return new EnergyBoltSpell(m_Mobile, null);
                case 11: return new ExplosionSpell(m_Mobile, null);
                default: return new FlameStrikeSpell(m_Mobile, null);
            }
        }

        public virtual Spell GetRandomCurseSpell()
        {
            return UseNecromancy() ? GetRandomCurseSpellNecro() : GetRandomCurseSpellMage();
        }

        public virtual Spell GetRandomCurseSpellNecro()
        {
            switch (Utility.Random(4))
            {
                case 0: m_Mobile.DebugSay("Blood Oath"); return new BloodOathSpell(m_Mobile, null);
                case 1: m_Mobile.DebugSay("Corpse Skin"); return new CorpseSkinSpell(m_Mobile, null);
                case 2: m_Mobile.DebugSay("Evil Omen"); return new EvilOmenSpell(m_Mobile, null);
                default: m_Mobile.DebugSay("Mind Rot"); return new MindRotSpell(m_Mobile, null);
            }
        }

        public virtual Spell GetRandomCurseSpellMage()
        {
            if (m_Mobile.Skills[SkillName.Magery].Value >= 40.0 && Utility.Random(4) == 0)
                return new CurseSpell(m_Mobile, null);

            switch (Utility.Random(3))
            {
                case 0: return new WeakenSpell(m_Mobile, null);
                case 1: return new ClumsySpell(m_Mobile, null);
                default: return new FeeblemindSpell(m_Mobile, null);
            }
        }

        public virtual Spell GetRandomManaDrainSpell()
        {
            if (m_Mobile.Skills[SkillName.Magery].Value >= 80.0 && Utility.RandomBool())
                return new ManaVampireSpell(m_Mobile, null);

            return new ManaDrainSpell(m_Mobile, null);
        }

        public virtual Spell DoDispel(Mobile toDispel)
        {
            if (!SmartAI)
            {
                if (ScaleBySkill(DispelChance, SkillName.Magery) > Utility.RandomDouble())
                    return new DispelSpell(m_Mobile, null);

                return ChooseSpell(toDispel);
            }

            Spell spell = CheckCastHealingSpell();

            if (spell == null)
            {
                if (!m_Mobile.DisallowAllMoves && Utility.Random((int)m_Mobile.GetDistanceToSqrt(toDispel)) == 0)
                    spell = new TeleportSpell(m_Mobile, null);
                else if (Utility.Random(3) == 0 && !m_Mobile.InRange(toDispel, 3) && !toDispel.Paralyzed && !toDispel.Frozen)
                    spell = new ParalyzeSpell(m_Mobile, null);
                else
                    spell = new DispelSpell(m_Mobile, null);
            }

            return spell;
        }

        public virtual Spell ChooseSpell(Mobile c)
        {
            Spell spell = null;

            if (!SmartAI)
            {
                spell = CheckCastHealingSpell();

                if (spell != null)
                    return spell;

                if (IsNecromancer)
                {
                    double psDamage = ((m_Mobile.Skills[SkillName.SpiritSpeak].Value - c.Skills[SkillName.MagicResist].Value) / 10) + (c.Player ? 18 : 30);

                    if (psDamage > c.Hits)
                        return new PainSpikeSpell(m_Mobile, null);
                }

                switch (Utility.Random(16))
                {
                    case 0:
                    case 1:	// Poison them
                        {
                            if (c.Poisoned)
                                goto default;

                            m_Mobile.DebugSay("Attempting to poison");

                            spell = new PoisonSpell(m_Mobile, null);
                            break;
                        }
                    case 2:	// Bless ourselves
                        {
                            m_Mobile.DebugSay("Blessing myself");

                            spell = new BlessSpell(m_Mobile, null);
                            break;
                        }
                    case 3:
                    case 4: // Curse them
                        {
                            m_Mobile.DebugSay("Attempting to curse");

                            spell = GetRandomCurseSpell();
                            break;
                        }
                    case 5:	// Paralyze them
                        {
                            if (m_Mobile.Skills[SkillName.Magery].Value <= 50.0)
                                goto default;

                            m_Mobile.DebugSay("Attempting to paralyze");

                            spell = new ParalyzeSpell(m_Mobile, null);
                            break;
                        }
                    case 6: // Drain mana
                        {
                            m_Mobile.DebugSay("Attempting to drain mana");

                            spell = GetRandomManaDrainSpell();
                            break;
                        }
                    case 7: // Invis ourselves
                        {
                            if (Utility.RandomBool())
                                goto default;

                            m_Mobile.DebugSay("Attempting to invis myself");

                            spell = new InvisibilitySpell(m_Mobile, null);
                            break;
                        }
                    default: // Damage them
                        {
                            m_Mobile.DebugSay("Just doing damage");

                            spell = GetRandomDamageSpell();
                            break;
                        }
                }

                return spell;
            }

            spell = CheckCastHealingSpell();

            if (spell != null)
                return spell;

            switch (Utility.Random(3))
            {
                case 0: // Poison them
                    {
                        if (c.Poisoned)
                            goto case 1;

                        spell = new PoisonSpell(m_Mobile, null);
                        break;
                    }
                case 1: // Deal some damage
                    {
                        spell = GetRandomDamageSpell();

                        break;
                    }
                default: // Set up a combo
                    {
                        if (m_Mobile.Mana > 15 && m_Mobile.Mana < 40)
                        {
                            if (c.Paralyzed && !c.Poisoned)
                            {
                                m_Mobile.DebugSay("I am going to meditate");

                                m_Mobile.UseSkill(SkillName.Meditation);
                            }
                            else if (!c.Poisoned)
                            {
                                spell = new ParalyzeSpell(m_Mobile, null);
                            }
                        }
                        else if (m_Mobile.Mana > 60)
                        {
                            if (Utility.RandomBool() && !c.Paralyzed && !c.Frozen && !c.Poisoned)
                            {
                                m_Combo = 0;
                                spell = new ParalyzeSpell(m_Mobile, null);
                            }
                            else
                            {
                                m_Combo = 1;
                                spell = new ExplosionSpell(m_Mobile, null);
                            }
                        }

                        break;
                    }
            }

            return spell;
        }

		protected int m_Combo = -1;

        public virtual Spell DoCombo(Mobile c)
        {
            Spell spell = null;

            if (m_Combo == 0)
            {
                spell = new ExplosionSpell(m_Mobile, null);
                ++m_Combo; // Move to next spell
            }
            else if (m_Combo == 1)
            {
                spell = new WeakenSpell(m_Mobile, null);
                ++m_Combo; // Move to next spell
            }
            else if (m_Combo == 2)
            {
                if (!c.Poisoned)
                    spell = new PoisonSpell(m_Mobile, null);
                else if (IsNecromancer)
                    spell = new StrangleSpell(m_Mobile, null);

                ++m_Combo; // Move to next spell
            }

            if (m_Combo == 3 && spell == null)
            {
                switch (Utility.Random(IsNecromancer ? 4 : 3))
                {
                    case 0:
                        {
                            if (c.Int < c.Dex)
                                spell = new FeeblemindSpell(m_Mobile, null);
                            else
                                spell = new ClumsySpell(m_Mobile, null);

                            ++m_Combo; // Move to next spell

                            break;
                        }
                    case 1:
                        {
                            spell = new EnergyBoltSpell(m_Mobile, null);
                            m_Combo = -1; // Reset combo state
                            break;
                        }
                    case 2:
                        {
                            spell = new FlameStrikeSpell(m_Mobile, null);
                            m_Combo = -1; // Reset combo state
                            break;
                        }
                    default:
                        {
                            spell = new PainSpikeSpell(m_Mobile, null);
                            m_Combo = -1; // Reset combo state
                            break;
                        }
                }
            }
            else if (m_Combo == 4 && spell == null)
            {
                spell = new MindBlastSpell(m_Mobile, null);
                m_Combo = -1;
            }

            return spell;
        }

        private TimeSpan GetDelay(Spell spell)
        {
            if (SmartAI || (spell is DispelSpell))
            {
                return TimeSpan.FromSeconds(m_Mobile.ActiveSpeed);
            }
            else
            {
                double del = ScaleBySkill(3.0, SkillName.Magery);
                double min = 6.0 - (del * 0.75);
                double max = 6.0 - (del * 1.25);

                return TimeSpan.FromSeconds(min + ((max - min) * Utility.RandomDouble()));
            }
        }

        private Mobile m_LastTarget;
        private Point3D m_LastTargetLoc;

		public override bool DoActionCombat()
		{
			Mobile c = m_Mobile.Combatant;
			m_Mobile.Warmode = true;

			if ( c == null || c.Deleted || !c.Alive || c.IsDeadBondedPet || !m_Mobile.CanSee( c ) || !m_Mobile.CanBeHarmful( c, false ) || c.Map != m_Mobile.Map )
			{
				// Our combatant is deleted, dead, hidden, or we cannot hurt them
				// Try to find another combatant

				if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
				{
                    m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name);

					m_Mobile.Combatant = c = m_Mobile.FocusMob;
					m_Mobile.FocusMob = null;
				}
				else
				{
					m_Mobile.DebugSay( "Something happened to my combatant, and nothing is around. I am on guard." );
					Action = ActionType.Guard;
					return true;
				}
			}

			if ( !m_Mobile.InLOS( c ) )
			{
				m_Mobile.DebugSay( "I can't see my target" );

				if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
				{
                    m_Mobile.DebugSay("I will switch to {0}", m_Mobile.FocusMob.Name);
                    m_Mobile.Combatant = c = m_Mobile.FocusMob;
					m_Mobile.FocusMob = null;
				}
			}

			if ( SmartAI && !m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0 )
				EventSink.InvokeStunRequest( new StunRequestEventArgs( m_Mobile ) );

			if ( !m_Mobile.InRange( c, m_Mobile.RangePerception ) )
			{
				// They are somewhat far away, can we find something else?

				if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
				{
					m_Mobile.Combatant = m_Mobile.FocusMob;
					m_Mobile.FocusMob = null;
				}
				else if ( !m_Mobile.InRange( c, m_Mobile.RangePerception * 3 ) )
				{
					m_Mobile.Combatant = null;
				}

				c = m_Mobile.Combatant;

				if ( c == null )
				{
					m_Mobile.DebugSay( "My combatant has fled, so I am on guard" );
					Action = ActionType.Guard;

					return true;
				}
			}

			if ( !m_Mobile.Controlled && !m_Mobile.Summoned && !m_Mobile.IsParagon )
			{
				if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 )
				{
					// We are low on health, should we flee?

					bool flee = false;

					if ( m_Mobile.Hits < c.Hits )
					{
						// We are more hurt than them

						int diff = c.Hits - m_Mobile.Hits;

						flee = ( Utility.Random( 0, 100 ) > (10 + diff) ); // (10 + diff)% chance to flee
					}
					else
					{
						flee = Utility.Random( 0, 100 ) > 10; // 10% chance to flee
					}
					
					if ( flee )
					{
                        m_Mobile.DebugSay("I am going to flee from {0}", c.Name);

						Action = ActionType.Flee;
						return true;
					}
				}
			}

			if ( m_Mobile.Spell == null && DateTime.Now > m_NextCastTime && m_Mobile.InRange( c, 12 ) )
			{
				// We are ready to cast a spell

				Spell spell = null;
				Mobile toDispel = FindDispelTarget( true );

				if ( m_Mobile.Poisoned ) // Top cast priority is cure
				{
					m_Mobile.DebugSay( "I am going to cure myself" );

					spell = new CureSpell( m_Mobile, null );
				}
				else if ( toDispel != null ) // Something dispellable is attacking us
				{
					m_Mobile.DebugSay( "I am going to dispel {0}", toDispel );

					spell = DoDispel( toDispel );
				}
				else if ( SmartAI && m_Combo != -1 ) // We are doing a spell combo
				{
					spell = DoCombo( c );
				}
				else if ( SmartAI && (c.Spell is HealSpell || c.Spell is GreaterHealSpell) && !c.Poisoned ) // They have a heal spell out
				{
					spell = new PoisonSpell( m_Mobile, null );
				}
				else
				{
					spell = ChooseSpell( c );
				}

				// Now we have a spell picked
				// Move first before casting

				if ( SmartAI && toDispel != null )
				{
					if ( m_Mobile.InRange( toDispel, 10 ) )
						RunFrom( toDispel );
					else if ( !m_Mobile.InRange( toDispel, 12 ) )
						RunTo( toDispel );
				}
				else
				{
					RunTo( c );
				}

				if ( spell != null )
					spell.Cast();

                m_NextCastTime = DateTime.Now + GetDelay(spell);
			}
			else if ( m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting )
			{
				RunTo( c );
			}

            m_LastTarget = c;
            m_LastTargetLoc = c.Location;

			return true;
		}

        private LandTarget m_RevealTarget;

        public override bool DoActionGuard()
        {
            if (m_LastTarget != null && m_LastTarget.Hidden)
            {
                Map map = m_Mobile.Map;

                if (map == null || !m_Mobile.InRange(m_LastTargetLoc, Core.ML ? 10 : 12))
                {
                    m_LastTarget = null;
                }
                else if (m_Mobile.Spell == null && DateTime.Now > m_NextCastTime)
                {
                    m_Mobile.DebugSay("I am going to reveal my last target");

                    m_RevealTarget = new LandTarget(m_LastTargetLoc, map);
                    Spell spell = new RevealSpell(m_Mobile, null);

                    if (spell.Cast())
                        m_LastTarget = null; // only do it once

                    m_NextCastTime = DateTime.Now + GetDelay(spell);
                }
            }
			if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
			{
				m_Mobile.DebugSay( "I am going to attack {0}", m_Mobile.FocusMob.Name );

				m_Mobile.Combatant = m_Mobile.FocusMob;
				Action = ActionType.Combat;
			}
			else
			{
				if ( !m_Mobile.Controlled )
				{
					ProcessTarget();

					Spell spell = CheckCastHealingSpell();

					if ( spell != null )
						spell.Cast();
				}

				base.DoActionGuard();
			}

			return true;
		}

		public override bool DoActionFlee()
		{
			Mobile c = m_Mobile.Combatant;

			if ( (m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2) )
			{
				m_Mobile.DebugSay( "I am stronger now, my guard is up" );
				Action = ActionType.Guard;
			}
			else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
			{
                m_Mobile.DebugSay("I am scared of {0}", m_Mobile.FocusMob.Name);

				RunFrom( m_Mobile.FocusMob );
				m_Mobile.FocusMob = null;

				if ( m_Mobile.Poisoned && Utility.Random( 0, 5 ) == 0 )
					new CureSpell( m_Mobile, null ).Cast();
			}
			else
			{
				m_Mobile.DebugSay( "Area seems clear, but my guard is up" );

				Action = ActionType.Guard;
				m_Mobile.Warmode = true;
			}

			return true;
		}

		public Mobile FindDispelTarget( bool activeOnly )
		{
			if ( m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel( m_Mobile ) || m_Mobile.AutoDispel )
				return null;

			if ( activeOnly )
			{
				List<AggressorInfo> aggressed = m_Mobile.Aggressed;
				List<AggressorInfo> aggressors = m_Mobile.Aggressors;

				Mobile active = null;
				double activePrio = 0.0;

				Mobile comb = m_Mobile.Combatant;

				if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange( comb, 12 ) && CanDispel( comb ) )
				{
					active = comb;
					activePrio = m_Mobile.GetDistanceToSqrt( comb );

					if ( activePrio <= 2 )
						return active;
				}

				for ( int i = 0; i < aggressed.Count; ++i )
				{
					AggressorInfo info = aggressed[i];
					Mobile m = info.Defender;

					if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) )
					{
						double prio = m_Mobile.GetDistanceToSqrt( m );

						if ( active == null || prio < activePrio )
						{
							active = m;
							activePrio = prio;

							if ( activePrio <= 2 )
								return active;
						}
					}
				}

				for ( int i = 0; i < aggressors.Count; ++i )
				{
					AggressorInfo info = aggressors[i];
					Mobile m = info.Attacker;

					if ( m != comb && m.Combatant == m_Mobile && m_Mobile.InRange( m, 12 ) && CanDispel( m ) )
					{
						double prio = m_Mobile.GetDistanceToSqrt( m );

						if ( active == null || prio < activePrio )
						{
							active = m;
							activePrio = prio;

							if ( activePrio <= 2 )
								return active;
						}
					}
				}

				return active;
			}
			else
			{
				Map map = m_Mobile.Map;

				if ( map != null )
				{
					Mobile active = null, inactive = null;
					double actPrio = 0.0, inactPrio = 0.0;

					Mobile comb = m_Mobile.Combatant;

					if ( comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel( comb ) )
					{
						active = inactive = comb;
						actPrio = inactPrio = m_Mobile.GetDistanceToSqrt( comb );
					}

					foreach ( Mobile m in m_Mobile.GetMobilesInRange( 12 ) )
					{
						if ( m != m_Mobile && CanDispel( m ) )
						{
							double prio = m_Mobile.GetDistanceToSqrt( m );

							if ( !activeOnly && (inactive == null || prio < inactPrio) )
							{
								inactive = m;
								inactPrio = prio;
							}

							if ( (m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio) )
							{
								active = m;
								actPrio = prio;
							}
						}
					}

					return active != null ? active : inactive;
				}
			}

			return null;
		}

		public bool CanDispel( Mobile m )
		{
			return ( m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful( m, false ) && !((BaseCreature)m).IsAnimatedDead );
		}

		private static readonly int[] m_Offsets = new int[]
			{
				-1, -1,
				-1,  0,
				-1,  1,
				 0, -1,
				 0,  1,
				 1, -1,
				 1,  0,
				 1,  1,

				-2, -2,
				-2, -1,
				-2,  0,
				-2,  1,
				-2,  2,
				-1, -2,
				-1,  2,
				 0, -2,
				 0,  2,
				 1, -2,
				 1,  2,
				 2, -2,
				 2, -1,
				 2,  0,
				 2,  1,
				 2,  2
			};

		private bool ProcessTarget()
		{
			Target targ = m_Mobile.Target;

			if ( targ == null )
				return false;

            bool isReveal = ( targ is RevealSpell.InternalTarget );
			bool isDispel = ( targ is DispelSpell.InternalTarget );
			bool isParalyze = ( targ is ParalyzeSpell.InternalTarget );
			bool isTeleport = ( targ is TeleportSpell.InternalTarget );
            bool isInvisible = (targ is InvisibilitySpell.InternalTarget);
			bool teleportAway = false;

			Mobile toTarget;

            if (isInvisible)
            {
                toTarget = m_Mobile;
            }
            else if (isDispel)
            {
				toTarget = FindDispelTarget( false );

				if ( !SmartAI && toTarget != null )
					RunTo( toTarget );
				else if ( toTarget != null && m_Mobile.InRange( toTarget, 10 ) )
					RunFrom( toTarget );
			}
            else if (SmartAI && (isParalyze || isTeleport))
            {
				toTarget = FindDispelTarget( true );

				if ( toTarget == null )
				{
					toTarget = m_Mobile.Combatant;

					if ( toTarget != null )
						RunTo( toTarget );
				}
				else if ( m_Mobile.InRange( toTarget, 10 ) )
				{
					RunFrom( toTarget );
					teleportAway = true;
				}
				else
				{
					teleportAway = true;
				}
			}
			else
			{
				toTarget = m_Mobile.Combatant;

				if ( toTarget != null )
					RunTo( toTarget );
			}

			if ( (targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null )
			{
				if ( (targ.Range == -1 || m_Mobile.InRange( toTarget, targ.Range )) && m_Mobile.CanSee( toTarget ) && m_Mobile.InLOS( toTarget ) )
				{
					targ.Invoke( m_Mobile, toTarget );
				}
				else if ( isDispel )
				{
					targ.Cancel( m_Mobile, TargetCancelType.Canceled );
				}
			}
			else if ( (targ.Flags & TargetFlags.Beneficial) != 0 )
			{
				targ.Invoke( m_Mobile, m_Mobile );
			}
            else if (isReveal && m_RevealTarget != null)
            {
                targ.Invoke(m_Mobile, m_RevealTarget);

                if (SmartAI)
                    m_Mobile.NextReacquireTime = DateTime.Now;
            }
			else if ( isTeleport && toTarget != null )
			{
				Map map = m_Mobile.Map;

				if ( map == null )
				{
					targ.Cancel( m_Mobile, TargetCancelType.Canceled );
					return true;
				}

				int px, py;

				if ( teleportAway )
				{
					int rx = m_Mobile.X - toTarget.X;
					int ry = m_Mobile.Y - toTarget.Y;

					double d = m_Mobile.GetDistanceToSqrt( toTarget );

					px = toTarget.X + (int)(rx * (10 / d));
					py = toTarget.Y + (int)(ry * (10 / d));
				}
				else
				{
					px = toTarget.X;
					py = toTarget.Y;
				}

				for ( int i = 0; i < m_Offsets.Length; i += 2 )
				{
					int x = m_Offsets[i], y = m_Offsets[i + 1];

					Point3D p = new Point3D( px + x, py + y, 0 );

					LandTarget lt = new LandTarget( p, map );

					if ( (targ.Range == -1 || m_Mobile.InRange( p, targ.Range )) && m_Mobile.InLOS( lt ) && map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, map ) )
					{
						targ.Invoke( m_Mobile, lt );
						return true;
					}
				}

				int teleRange = targ.Range;

				if ( teleRange < 0 )
					teleRange = 12;

				for ( int i = 0; i < 10; ++i )
				{
					Point3D randomPoint = new Point3D( m_Mobile.X - teleRange + Utility.Random( teleRange * 2 + 1 ), m_Mobile.Y - teleRange + Utility.Random( teleRange * 2 + 1 ), 0 );

					LandTarget lt = new LandTarget( randomPoint, map );

					if ( m_Mobile.InLOS( lt ) && map.CanSpawnMobile( lt.X, lt.Y, lt.Z ) && !SpellHelper.CheckMulti( randomPoint, map ) )
					{
						targ.Invoke( m_Mobile, new LandTarget( randomPoint, map ) );
						return true;
					}
				}

				targ.Cancel( m_Mobile, TargetCancelType.Canceled );
			}
			else
			{
				targ.Cancel( m_Mobile, TargetCancelType.Canceled );
			}

			return true;
		}
	}
}
