context: #region Header
  // **************************************\
  //     _  _   _   __  ___  _   _   ___   |
  //    |# |#  |#  |## |### |#  |#  |###   |
  //    |# |#  |# |#    |#  |#  |# |#  |#  |
  //    |# |#  |#  |#   |#  |#  |# |#  |#  |
  //   _|# |#__|#  _|#  |#  |#__|# |#__|#  |
  //  |##   |##   |##   |#   |##    |###   |
  //        [http://www.playuo.org]        |
  // **************************************/
  //  [2014] Region.cs
  // ************************************/
  #endregion
  
  #region References
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Xml;
  
  using Server.Network;
  using Server.Targeting;
  #endregion
  
  namespace Server
  {
  	public enum MusicName
  	{
  		Invalid = -1,
  		OldUlt01 = 0,
  		Create1,
  		DragFlit,
  		OldUlt02,
  		OldUlt03,
  		OldUlt04,
  		OldUlt05,
  		OldUlt06,
  		Stones2,
  		Britain1,
  		Britain2,
  		Bucsden,
  		Jhelom,
  		LBCastle,
  		Linelle,
  		Magincia,
  		Minoc,
  		Ocllo,
  		Samlethe,
  		Serpents,
  		Skarabra,
  		Trinsic,
  		Vesper,
  		Wind,
  		Yew,
  		Cave01,
  		Dungeon9,
  		Forest_a,
  		InTown01,
  		Jungle_a,
  		Mountn_a,
  		Plains_a,
  		Sailing,
  		Swamp_a,
  		Tavern01,
  		Tavern02,
  		Tavern03,
  		Tavern04,
  		Combat1,
  		Combat2,
  		Combat3,
  		Approach,
  		Death,
  		Victory,
  		BTCastle,
  		Nujelm,
  		Dungeon2,
  		Cove,
  		Moonglow,
  		Zento,
  		TokunoDungeon,
  		Taiko,
  		DreadHornArea,
  		ElfCity,
  		GrizzleDungeon,
  		MelisandesLair,
  		ParoxysmusLair,
  		GwennoConversation,
  		GoodEndGame,
  		GoodVsEvil,
  		GreatEarthSerpents,
  		Humanoids_U9,
  		MinocNegative,
  		Paws,
  		SelimsBar,
  		SerpentIsleCombat_U7,
          ValoriaShips,
          TheWanderer,
          Castle,
          Festival,
          Honor,
          Medieval,
          BattleOnStones,
          Docktown,
          GargoyleQueen,
          GenericCombat,
          Holycity,
          HumanLevel,
          LoginLoop,
          NorthernForestBattleonStones,
          PrimevalLich,
          QueenPalace,
          RoyalCity,
          SlasherVeil,
          StygianAbyss,
          StygianDragon,
          Void,
          CodexShrine
  	}
  
  	public class Region : IComparable
  	{
  		private static readonly List<Region> m_Regions = new List<Region>();
  
  		public static List<Region> Regions { get { return m_Regions; } }
  
  		public static Region Find(Point3D p, Map map)
  		{
  			if (map == null)
  			{
  				return Map.Internal.DefaultRegion;
  			}
  
  			Sector sector = map.GetSector(p);
  			List<RegionRect> list = sector.RegionRects;
  
  			for (int i = 0; i < list.Count; ++i)
  			{
  				RegionRect regRect = list[i];
  
  				if (regRect.Contains(p))
  				{
  					return regRect.Region;
  				}
  			}
  
  			return map.DefaultRegion;
  		}
  
  		private static Type m_DefaultRegionType = typeof(Region);
  		public static Type DefaultRegionType { get { return m_DefaultRegionType; } set { m_DefaultRegionType = value; } }
  
  		private static TimeSpan m_StaffLogoutDelay = TimeSpan.Zero;
  		private static TimeSpan m_DefaultLogoutDelay = TimeSpan.FromMinutes(5.0);
  
  		public static TimeSpan StaffLogoutDelay { get { return m_StaffLogoutDelay; } set { m_StaffLogoutDelay = value; } }
  		public static TimeSpan DefaultLogoutDelay { get { return m_DefaultLogoutDelay; } set { m_DefaultLogoutDelay = value; } }
  
  		public static readonly int DefaultPriority = 50;
  
  		public static readonly int MinZ = sbyte.MinValue;
  		public static readonly int MaxZ = sbyte.MaxValue + 1;
  
  		public static Rectangle3D ConvertTo3D(Rectangle2D rect)
  		{
  			return new Rectangle3D(new Point3D(rect.Start, MinZ), new Point3D(rect.End, MaxZ));
  		}
  
  		public static Rectangle3D[] ConvertTo3D(Rectangle2D[] rects)
  		{
  			var ret = new Rectangle3D[rects.Length];
  
  			for (int i = 0; i < ret.Length; i++)
  			{
  				ret[i] = ConvertTo3D(rects[i]);
  			}
  
  			return ret;
  		}
  
  		private readonly string m_Name;
  		private readonly Map m_Map;
  		private readonly Region m_Parent;
  		private readonly List<Region> m_Children = new List<Region>();
  		private readonly Rectangle3D[] m_Area;
  		private Sector[] m_Sectors;
  		private readonly bool m_Dynamic;
  		private readonly int m_Priority;
  		private readonly int m_ChildLevel;
  		private bool m_Registered;
  
  		private Point3D m_GoLocation;
  
  		public string Name { get { return m_Name; } }
  		public Map Map { get { return m_Map; } }
  		public Region Parent { get { return m_Parent; } }
  		public List<Region> Children { get { return m_Children; } }
  		public Rectangle3D[] Area { get { return m_Area; } }
  		public Sector[] Sectors { get { return m_Sectors; } }
  		public bool Dynamic { get { return m_Dynamic; } }
  		public int Priority { get { return m_Priority; } }
  		public int ChildLevel { get { return m_ChildLevel; } }
  		public bool Registered { get { return m_Registered; } }
  
  		public Point3D GoLocation { get { return m_GoLocation; } set { m_GoLocation = value; } }
  		public MusicName Music { get; set; }
  
  		public bool IsDefault { get { return m_Map.DefaultRegion == this; } }
  		public virtual MusicName DefaultMusic { get { return m_Parent != null ? m_Parent.Music : MusicName.Invalid; } }
  
  		public Region(string name, Map map, int priority, params Rectangle2D[] area)
  			: this(name, map, priority, ConvertTo3D(area))
  		{ }
  
  		public Region(string name, Map map, int priority, params Rectangle3D[] area)
  			: this(name, map, null, area)
  		{
  			m_Priority = priority;
  		}
  
  		public Region(string name, Map map, Region parent, params Rectangle2D[] area)
  			: this(name, map, parent, ConvertTo3D(area))
  		{ }
  
  		public Region(string name, Map map, Region parent, params Rectangle3D[] area)
  		{
  			m_Name = name;
  			m_Map = map;
  			m_Parent = parent;
  			m_Area = area;
  			m_Dynamic = true;
  			Music = DefaultMusic;
  
  			if (m_Parent == null)
  			{
  				m_ChildLevel = 0;
  				m_Priority = DefaultPriority;
  			}
  			else
  			{
  				m_ChildLevel = m_Parent.ChildLevel + 1;
  				m_Priority = m_Parent.Priority;
  			}
  		}
  
  		public void Register()
  		{
  			if (m_Registered)
  			{
  				return;
  			}
  
  			OnRegister();
  
  			m_Registered = true;
  
  			if (m_Parent != null)
  			{
  				m_Parent.m_Children.Add(this);
  				m_Parent.OnChildAdded(this);
  			}
  
  			m_Regions.Add(this);
  
  			m_Map.RegisterRegion(this);
  
  			var sectors = new List<Sector>();
  
  			for (int i = 0; i < m_Area.Length; i++)
  			{
  				Rectangle3D rect = m_Area[i];
  
  				Point2D start = m_Map.Bound(new Point2D(rect.Start));
  				Point2D end = m_Map.Bound(new Point2D(rect.End));
  
  				Sector startSector = m_Map.GetSector(start);
  				Sector endSector = m_Map.GetSector(end);
  
  				for (int x = startSector.X; x <= endSector.X; x++)
  				{
  					for (int y = startSector.Y; y <= endSector.Y; y++)
  					{
  						Sector sector = m_Map.GetRealSector(x, y);
  
  						sector.OnEnter(this, rect);
  
  						if (!sectors.Contains(sector))
  						{
  							sectors.Add(sector);
  						}
  					}
  				}
  			}
  
  			m_Sectors = sectors.ToArray();
  		}
  
  		public void Unregister()
  		{
  			if (!m_Registered)
  			{
  				return;
  			}
  
  			OnUnregister();
  
  			m_Registered = false;
  
  			if (m_Children.Count > 0)
  			{
  				Console.WriteLine("Warning: Unregistering region '{0}' with children", this);
  			}
  
  			if (m_Parent != null)
  			{
  				m_Parent.m_Children.Remove(this);
  				m_Parent.OnChildRemoved(this);
  			}
  
  			m_Regions.Remove(this);
  
  			m_Map.UnregisterRegion(this);
  
  			if (m_Sectors != null)
  			{
  				for (int i = 0; i < m_Sectors.Length; i++)
  				{
  					m_Sectors[i].OnLeave(this);
  				}
  			}
  
  			m_Sectors = null;
  		}
  
  		public bool Contains(Point3D p)
  		{
  			for (int i = 0; i < m_Area.Length; i++)
  			{
  				Rectangle3D rect = m_Area[i];
  
  				if (rect.Contains(p))
  				{
  					return true;
  				}
  			}
  
  			return false;
  		}
  
  		public bool IsChildOf(Region region)
  		{
  			if (region == null)
  			{
  				return false;
  			}
  
  			Region p = m_Parent;
  
  			while (p != null)
  			{
  				if (p == region)
  				{
  					return true;
  				}
  
  				p = p.m_Parent;
  			}
  
  			return false;
  		}
  
  		public Region GetRegion(Type regionType)
  		{
  			if (regionType == null)
  			{
  				return null;
  			}
  
  			Region r = this;
  
  			do
  			{
  				if (regionType.IsAssignableFrom(r.GetType()))
  				{
  					return r;
  				}
  
  				r = r.m_Parent;
  			}
  			while (r != null);
  
  			return null;
  		}
  
  		public Region GetRegion(string regionName)
  		{
  			if (regionName == null)
  			{
  				return null;
  			}
  
  			Region r = this;
  
  			do
  			{
  				if (r.m_Name == regionName)
  				{
  					return r;
  				}
  
  				r = r.m_Parent;
  			}
  			while (r != null);
  
  			return null;
  		}
  
  		public bool IsPartOf(Region region)
  		{
  			if (this == region)
  			{
  				return true;
  			}
  
  			return IsChildOf(region);
  		}
  
  		public bool IsPartOf(Type regionType)
  		{
  			return (GetRegion(regionType) != null);
  		}
  
  		public bool IsPartOf(string regionName)
  		{
  			return (GetRegion(regionName) != null);
  		}
  
  		public virtual bool AcceptsSpawnsFrom(Region region)
  		{
  			if (!AllowSpawn())
  			{
  				return false;
  			}
  
  			if (region == this)
  			{
  				return true;
  			}
  
  			if (m_Parent != null)
  			{
  				return m_Parent.AcceptsSpawnsFrom(region);
  			}
  
  			return false;
  		}
  
  		public List<Mobile> GetPlayers()
  		{
  			var list = new List<Mobile>();
  
  			if (m_Sectors != null)
  			{
  				for (int i = 0; i < m_Sectors.Length; i++)
  				{
  					Sector sector = m_Sectors[i];
  
  					foreach (Mobile player in sector.Players)
  					{
  						if (player.Region.IsPartOf(this))
  						{
  							list.Add(player);
  						}
  					}
  				}
  			}
  
  			return list;
  		}
  
  		public int GetPlayerCount()
  		{
  			int count = 0;
  
  
gt: 			if (m_Sectors != null)