context: using System;
  using System.Collections.Generic;
  using System.Xml;
  using Server.Gumps;
  using Server.Items;
  using Server.Mobiles;
  
  namespace Server.Regions
  {
      public enum SpawnZLevel
      {
          Lowest,
          Highest,
          Random
      }
  
      public class BaseRegion : Region
      {
          private static readonly List<Rectangle3D> m_RectBuffer1 = new List<Rectangle3D>();
          private static readonly List<Rectangle3D> m_RectBuffer2 = new List<Rectangle3D>();
          private static readonly List<Int32> m_SpawnBuffer1 = new List<Int32>();
          private static readonly List<Item> m_SpawnBuffer2 = new List<Item>();
  
          private string m_RuneName;
          private bool m_NoLogoutDelay;
          private SpawnEntry[] m_Spawns;
          private SpawnZLevel m_SpawnZLevel;
          private bool m_ExcludeFromParentSpawns;
          private Rectangle3D[] m_Rectangles;
          private int[] m_RectangleWeights;
          private int m_TotalWeight;
  
          public BaseRegion(string name, Map map, int priority, params Rectangle2D[] area)
              : base(name, map, priority, area)
          {
          }
  
          public BaseRegion(string name, Map map, int priority, params Rectangle3D[] area)
              : base(name, map, priority, area)
          {
          }
  
          public BaseRegion(string name, Map map, Region parent, params Rectangle2D[] area)
              : base(name, map, parent, area)
          {
          }
  
          public BaseRegion(string name, Map map, Region parent, params Rectangle3D[] area)
              : base(name, map, parent, area)
          {
          }
  
          public BaseRegion(XmlElement xml, Map map, Region parent)
              : base(xml, map, parent)
          {
              ReadString(xml["rune"], "name", ref this.m_RuneName, false);
  
              bool logoutDelayActive = true;
              ReadBoolean(xml["logoutDelay"], "active", ref logoutDelayActive, false);
              this.m_NoLogoutDelay = !logoutDelayActive;
  
              XmlElement spawning = xml["spawning"];
              if (spawning != null)
              {
                  ReadBoolean(spawning, "excludeFromParent", ref this.m_ExcludeFromParentSpawns, false);
  
                  SpawnZLevel zLevel = SpawnZLevel.Lowest;
                  ReadEnum(spawning, "zLevel", ref zLevel, false);
                  this.m_SpawnZLevel = zLevel;
  
                  List<SpawnEntry> list = new List<SpawnEntry>();
  
                  foreach (XmlNode node in spawning.ChildNodes)
                  {
                      XmlElement el = node as XmlElement;
  
                      if (el != null)
                      {
                          SpawnDefinition def = SpawnDefinition.GetSpawnDefinition(el);
                          if (def == null)
                              continue;
  
                          int id = 0;
                          if (!ReadInt32(el, "id", ref id, true))
                              continue;
  
                          int amount = 0;
                          if (!ReadInt32(el, "amount", ref amount, true))
                              continue;
  
                          TimeSpan minSpawnTime = SpawnEntry.DefaultMinSpawnTime;
                          ReadTimeSpan(el, "minSpawnTime", ref minSpawnTime, false);
  
                          TimeSpan maxSpawnTime = SpawnEntry.DefaultMaxSpawnTime;
                          ReadTimeSpan(el, "maxSpawnTime", ref maxSpawnTime, false);
  
                          Point3D home = Point3D.Zero;
                          int range = 0;
  
                          XmlElement homeEl = el["home"];
                          if (ReadPoint3D(homeEl, map, ref home, false))
                              ReadInt32(homeEl, "range", ref range, false);
  
                          Direction dir = SpawnEntry.InvalidDirection;
                          ReadEnum(el["direction"], "value", ref dir, false);
  
                          SpawnEntry entry = new SpawnEntry(id, this, home, range, dir, def, amount, minSpawnTime, maxSpawnTime);
                          list.Add(entry);
                      }
                  }
  
                  if (list.Count > 0)
                  {
                      this.m_Spawns = list.ToArray();
                  }
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public virtual bool YoungProtected
          {
              get
              {
                  return true;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public string RuneName
          {
              get
              {
                  return this.m_RuneName;
              }
              set
              {
                  this.m_RuneName = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool NoLogoutDelay
          {
              get
              {
                  return this.m_NoLogoutDelay;
              }
              set
              {
                  this.m_NoLogoutDelay = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public SpawnEntry[] Spawns
          {
              get
              {
                  return this.m_Spawns;
              }
              set
              {
                  if (this.m_Spawns != null)
                  {
                      for (int i = 0; i < this.m_Spawns.Length; i++)
                          this.m_Spawns[i].Delete();
                  }
  
                  this.m_Spawns = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public SpawnZLevel SpawnZLevel
          {
              get
              {
                  return this.m_SpawnZLevel;
              }
              set
              {
                  this.m_SpawnZLevel = value;
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool ExcludeFromParentSpawns
          {
              get
              {
                  return this.m_ExcludeFromParentSpawns;
              }
              set
              {
                  this.m_ExcludeFromParentSpawns = value;
              }
          }
  
          public static void Configure()
          {
              Region.DefaultRegionType = typeof(BaseRegion);
          }
  
          public static string GetRuneNameFor(Region region)
          {
              while (region != null)
              {
                  BaseRegion br = region as BaseRegion;
  
                  if (br != null && br.m_RuneName != null)
                      return br.m_RuneName;
  
                  region = region.Parent;
              }
  
              return null;
          }
  
          public static bool CanSpawn(Region region, params Type[] types)
          {
              while (region != null)
              {
                  if (!region.AllowSpawn())
                      return false;
  
                  BaseRegion br = region as BaseRegion;
  
                  if (br != null)
                  {
                      if (br.Spawns != null)
                      {
                          for (int i = 0; i < br.Spawns.Length; i++)
                          {
                              SpawnEntry entry = br.Spawns[i];
  
                              if (entry.Definition.CanSpawn(types))
                                  return true;
                          }
                      }
  
                      if (br.ExcludeFromParentSpawns)
                          return false;
                  }
  
                  region = region.Parent;
              }
  
              return false;
          }
  
          public override void OnUnregister()
          {
              base.OnUnregister();
  
              this.Spawns = null;
          }
  
          public override TimeSpan GetLogoutDelay(Mobile m)
          {
              if (this.m_NoLogoutDelay)
              {
                  if (m.Aggressors.Count == 0 && m.Aggressed.Count == 0 && !m.Criminal)
                      return TimeSpan.Zero;
              }
  
              return base.GetLogoutDelay(m);
          }
  
          public override void OnEnter(Mobile m)
          {
              if (m is PlayerMobile && ((PlayerMobile)m).Young)
              {
                  if (!this.YoungProtected)
                  {
                      m.SendGump(new YoungDungeonWarning());
                  }
              }
          }
  
          public override bool AcceptsSpawnsFrom(Region region)
          {
              if (region == this || !this.m_ExcludeFromParentSpawns)
                  return base.AcceptsSpawnsFrom(region);
  
              return false;
          }
  
          public Point3D RandomSpawnLocation(int spawnHeight, bool land, bool water, Point3D home, int range)
          {
              Map map = this.Map;
  
              if (map == Map.Internal)
                  return Point3D.Zero;
  
              this.InitRectangles();
  
              if (this.m_TotalWeight <= 0)
                  return Point3D.Zero;
  
              for (int i = 0; i < 10; i++) // Try 10 times
              {
                  int x, y, minZ, maxZ;
  
                  if (home == Point3D.Zero)
                  {
                      int rand = Utility.Random(this.m_TotalWeight);
  
                      x = int.MinValue;
                      y = int.MinValue;
                      minZ = int.MaxValue;
                      maxZ = int.MinValue;
                      for (int j = 0; j < this.m_RectangleWeights.Length; j++)
                      {
                          int curWeight = this.m_RectangleWeights[j];
  
                          if (rand < curWeight)
                          {
                              Rectangle3D rect = this.m_Rectangles[j];
  
                              x = rect.Start.X + rand % rect.Width;
                              y = rect.Start.Y + rand / rect.Width;
  
                              minZ = rect.Start.Z;
                              maxZ = rect.End.Z;
  
                              break;
                          }
  
                          rand -= curWeight;
                      }
                  }
                  else
                  {
                      x = Utility.RandomMinMax(home.X - range, home.X + range);
                      y = Utility.RandomMinMax(home.Y - range, home.Y + range);
  
                      minZ = int.MaxValue;
                      maxZ = int.MinValue;
                      for (int j = 0; j < this.Area.Length; j++)
                      {
                          Rectangle3D rect = this.Area[j];
  
                          if (x >= rect.Start.X && x < rect.End.X && y >= rect.Start.Y && y < rect.End.Y)
                          {
                              minZ = rect.Start.Z;
                              maxZ = rect.End.Z;
                              break;
                          }
                      }
  
                      if (minZ == int.MaxValue)
                          continue;
                  }
  
                  if (x < 0 || y < 0 || x >= map.Width || y >= map.Height)
                      continue;
  
  
gt:                 LandTile lt = map.Tiles.GetLandTile(x, y);