context: using System;
  using System.Collections.Generic;
  using Server.Engines.CannedEvil;
  using Server.Engines.PartySystem;
  using Server.Factions;
  using Server.Guilds;
  using Server.Items;
  using Server.Regions;
  
  namespace Server.Spells.Necromancy
  {
      public class ExorcismSpell : NecromancerSpell
      {
          private static readonly SpellInfo m_Info = new SpellInfo(
              "Exorcism", "Ort Corp Grav",
              203,
              9031,
              Reagent.NoxCrystal,
              Reagent.GraveDust);
          private static readonly int Range = (Core.ML ? 48 : 18);
          private static readonly Point3D[] m_BritanniaLocs = new Point3D[]
          {
              new Point3D(1470, 843, 0),
              new Point3D(1857, 865, -1),
              new Point3D(4220, 563, 36),
              new Point3D(1732, 3528, 0),
              new Point3D(1300, 644, 8),
              new Point3D(3355, 302, 9),
              new Point3D(1606, 2490, 5),
              new Point3D(2500, 3931, 3),
              new Point3D(4264, 3707, 0)
          };
          private static readonly Point3D[] m_IllshLocs = new Point3D[]
          {
              new Point3D(1222, 474, -17),
              new Point3D(718, 1360, -60),
              new Point3D(297, 1014, -19),
              new Point3D(986, 1006, -36),
              new Point3D(1180, 1288, -30),
              new Point3D(1538, 1341, -3),
              new Point3D(528, 223, -38)
          };
          private static readonly Point3D[] m_MalasLocs = new Point3D[]
          {
              new Point3D(976, 517, -30)
          };
          private static readonly Point3D[] m_TokunoLocs = new Point3D[]
          {
              new Point3D(710, 1162, 25),
              new Point3D(1034, 515, 18),
              new Point3D(295, 712, 55)
          };
          public ExorcismSpell(Mobile caster, Item scroll)
              : base(caster, scroll, m_Info)
          {
          }
  
          public override TimeSpan CastDelayBase
          {
              get
              {
                  return TimeSpan.FromSeconds(2.0);
              }
          }
          public override double RequiredSkill
          {
              get
              {
                  return 80.0;
              }
          }
          public override int RequiredMana
          {
              get
              {
                  return 40;
              }
          }
          public override bool DelayedDamage
          {
              get
              {
                  return false;
              }
          }
          public override bool CheckCast()
          {
              if (this.Caster.Skills.SpiritSpeak.Value < 100.0)
              {
                  this.Caster.SendLocalizedMessage(1072112); // You must have GM Spirit Speak to use this spell
                  return false;
              }
  
              return base.CheckCast();
          }
  
          public override int ComputeKarmaAward()
          {
              return 0;	//no karma lost from this spell!
          }
  
          public override void OnCast()
          {
              ChampionSpawnRegion r = this.Caster.Region.GetRegion(typeof(ChampionSpawnRegion)) as ChampionSpawnRegion;
  
              if (r == null || !this.Caster.InRange(r.ChampionSpawn, Range))
              {
                  this.Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region.
              }
              else if (this.CheckSequence())
              {
                  Map map = this.Caster.Map;
  
                  if (map != null)
                  {
                      List<Mobile> targets = new List<Mobile>();
  
                      foreach (Mobile m in r.ChampionSpawn.GetMobilesInRange(Range))
                          if (this.IsValidTarget(m))
                              targets.Add(m);
  
                      for (int i = 0; i < targets.Count; ++i)
                      {
                          Mobile m = targets[i];
  
                          //Suprisingly, no sparkle type effects
  
                          m.Location = GetNearestShrine(m);
                      }
                  }
              }
  
              this.FinishSequence();
          }
  
          private static Point3D GetNearestShrine(Mobile m)
          {
              Map map = m.Map;
  
              Point3D[] locList;
  
              if (map == Map.Felucca || map == Map.Trammel)
                  locList = m_BritanniaLocs;
              else if (map == Map.Ilshenar)
                  locList = m_IllshLocs;
              else if (map == Map.Tokuno)
                  locList = m_TokunoLocs;
              else if (map == Map.Malas)
                  locList = m_MalasLocs;
              else
                  locList = new Point3D[0];
  
              Point3D closest = Point3D.Zero;
              double minDist = double.MaxValue;
  
              for (int i = 0; i < locList.Length; i++)
              {
                  Point3D p = locList[i];
  
                  double dist = m.GetDistanceToSqrt(p);
                  if (minDist > dist)
                  {
                      closest = p;
                      minDist = dist;
                  }
              }
  
              return closest;
          }
  
          private bool IsValidTarget(Mobile m)
          {
              if (!m.Player || m.Alive)
                  return false;
  
              Corpse c = m.Corpse as Corpse;
              Map map = m.Map;
  
              if (c != null && !c.Deleted && map != null && c.Map == map)
              {
                  if (SpellHelper.IsAnyT2A(map, c.Location) && SpellHelper.IsAnyT2A(map, m.Location))
                      return false;	//Same Map, both in T2A, ie, same 'sub server'.
  
                  if (m.Region.IsPartOf(typeof(DungeonRegion)) == Region.Find(c.Location, map).IsPartOf(typeof(DungeonRegion)))
                      return false; //Same Map, both in Dungeon region OR They're both NOT in a dungeon region.
                  //Just an approximation cause RunUO doens't divide up the world the same way OSI does ;p
              }
  
              Party p = Party.Get(m);
  
              if (p != null && p.Contains(this.Caster))
                  return false;
  
              if (m.Guild != null && this.Caster.Guild != null)
              {
                  Guild mGuild = m.Guild as Guild;
                  Guild cGuild = this.Caster.Guild as Guild;
  
                  if (mGuild.IsAlly(cGuild))
                      return false;
  
                  if (mGuild == cGuild)
                      return false;
              }
  
  
gt:             Faction f = Faction.Find(m);