context: using System;
  using System.Collections.Generic;
  using System.IO;
  using Server.ContextMenus;
  using Server.Engines.Harvest;
  using Server.Mobiles;
  using Server.Network;
  using Server.Targeting;
  using Server.Engines.ChampionSpawns;
  using Server.Regions;
  
  namespace Server.Items
  {
      public class TreasureMap : MapItem
      {
          public static bool NewChestLocations = true;
          public static double LootChance = .01;
          private static TimeSpan ResetTime = TimeSpan.FromDays(30.0);
  
          #region Spawn Types
          private static Type[][] m_SpawnTypes = new Type[][]
  		{
  			new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) },
  			new Type[]{ typeof( Mongbat ), typeof( Ratman ), typeof( HeadlessOne ), typeof( Skeleton ), typeof( Zombie ) },
  			new Type[]{ typeof( OrcishMage ), typeof( Gargoyle ), typeof( Gazer ), typeof( HellHound ), typeof( EarthElemental ) },
  			new Type[]{ typeof( Lich ), typeof( OgreLord ), typeof( DreadSpider ), typeof( AirElemental ), typeof( FireElemental ) },
  			new Type[]{ typeof( DreadSpider ), typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( OgreLord ) },
  			new Type[]{ typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( PoisonElemental ), typeof( BloodElemental ) },
  			new Type[]{ typeof( AncientWyrm ), typeof( Balron ), typeof( BloodElemental ), typeof( PoisonElemental ), typeof( Titan ) },
              new Type[]{ typeof( BloodElemental), typeof(ColdDrake), typeof(FrostDragon), typeof(GreaterDragon), typeof(PoisonElemental)}
  		};
  
          private static Type[][] m_TokunoSpawnTypes = new Type[][]
          {
              new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) },
  			new Type[]{ typeof( HeadlessOne ), typeof( Mongbat ), typeof( Ratman ), typeof( Skeleton), typeof( Zombie ),  },
  			new Type[]{ typeof( EarthElemental ), typeof( Gazer ), typeof( Gargoyle ), typeof( HellHound ), typeof( OrcishMage ), },
  			new Type[]{ typeof( AirElemental ), typeof( DreadSpider ), typeof( FireElemental ), typeof( Lich ), typeof( OgreLord ), },
  			new Type[]{ typeof( ElderGazer ), typeof( Daemon ), typeof( DreadSpider ), typeof( LichLord ), typeof( OgreLord ), },
  			new Type[]{ typeof( FanDancer ), typeof( RevenantLion ), typeof( Ronin ), typeof( RuneBeetle ) },
  			new Type[]{ typeof( Hiryu ), typeof( LadyOfTheSnow ), typeof( Oni ), typeof( RuneBeetle ), typeof( YomotsuWarrior ), typeof( YomotsuPriest ) },
              new Type[]{ typeof( Yamandon ), typeof( LadyOfTheSnow ), typeof( RuneBeetle ), typeof( YomotsuPriest ) }
          };
  
          private static Type[][] m_MalasSpawnTypes = new Type[][]
          {
              new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) },
  			new Type[]{ typeof( Mongbat ), typeof( Ratman ), typeof( HeadlessOne ), typeof( Skeleton ), typeof( Zombie ) },
  			new Type[]{ typeof( OrcishMage ), typeof( Gargoyle ), typeof( Gazer ), typeof( HellHound ), typeof( EarthElemental ) },
  			new Type[]{ typeof( Lich ), typeof( OgreLord ), typeof( DreadSpider ), typeof( AirElemental ), typeof( FireElemental ) },
  			new Type[]{ typeof( DreadSpider ), typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( OgreLord ) },
  			new Type[]{ typeof( LichLord ), typeof( Ravager ), typeof( WandererOfTheVoid ), typeof( Minotaur ) },
  			new Type[]{ typeof( Devourer ), typeof( MinotaurScout ), typeof( MinotaurCaptain ), typeof( RottingCorpse ), typeof( WandererOfTheVoid ) },
              new Type[]{ typeof( Devourer ), typeof(MinotaurScout), typeof( MinotaurCaptain ), typeof( RottingCorpse ), typeof( WandererOfTheVoid ) }
   
          };
  
          private static Type[][] m_IlshenarSpawnTypes = new Type[][]
          {
              new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) },
  			new Type[]{ typeof( Mongbat ), typeof( Ratman ), typeof( HeadlessOne ), typeof( Skeleton ), typeof( Zombie ) },
  			new Type[]{ typeof( OrcishMage ), typeof( Gargoyle ), typeof( Gazer ), typeof( HellHound ), typeof( EarthElemental ) },
  			new Type[]{ typeof( Lich ), typeof( OgreLord ), typeof( DreadSpider ), typeof( AirElemental ), typeof( FireElemental ) },
  			new Type[]{ typeof( DreadSpider ), typeof( LichLord ), typeof( Daemon ), typeof( ElderGazer ), typeof( OgreLord ) },
  			new Type[]{ typeof( DarkGuardian ), typeof( ExodusOverseer ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ), typeof( PoisonElemental ) },
  			new Type[]{ typeof( Changeling ), typeof( ExodusMinion ), typeof( GargoyleEnforcer ), typeof( GargoyleDestroyer ), typeof( Titan ) },
              new Type[]{ typeof( RenegadeChangeling ), typeof( ExodusMinion ), typeof( GargoyleEnforcer ), typeof( GargoyleDestroyer ), typeof( Titan ) }
          };
  
          private static Type[][] m_TerMurSpawnTypes = new Type[][]
          {
              new Type[]{ typeof( HeadlessOne ), typeof( Skeleton ) },
  			new Type[]{ typeof( ClockworkScorpion ), typeof( CorrosiveSlime ), typeof( GreaterMongbat ) },
  			new Type[]{ typeof( AcidSlug ), typeof( FireElemental ), typeof( WaterElemental ) },
  			new Type[]{ typeof( LeatherWolf ), typeof( StoneSlith ), typeof( ToxicSlith ) },
  			new Type[]{ typeof( BloodWorm ), typeof( Kepetch ), typeof( StoneSlith ), typeof( ToxicSlith ) },
  			new Type[]{ typeof( FireAnt ), typeof( LavaElemental ), typeof( MaddeningHorror ) },
  			new Type[]{ typeof( EnragedEarthElemental ), typeof( FireDaemon ), typeof( GreaterPoisonElemental ), typeof( LavaElemental ) },
              new Type[]{ typeof( EnragedEarthElemental ), typeof( FireDaemon ), typeof( GreaterPoisonElemental ), typeof( LavaElemental ) }
          };
          #endregion
  
          #region Spawn Locations
          private static Rectangle2D[] m_FelTramWrap = new Rectangle2D[]
          {
              new Rectangle2D(0, 0, 5119, 4095)
          };
  
          private static Rectangle2D[] m_TokunoWrap = new Rectangle2D[]
          {
              new Rectangle2D(155, 207, 30, 40),
              new Rectangle2D(280, 230, 157, 45),
              new Rectangle2D(445, 215, 30, 35 ),
              new Rectangle2D(447, 53, 58, 40),
              new Rectangle2D(612, 240, 20, 17),
              new Rectangle2D(167, 275, 53, 60),
              new Rectangle2D(734, 407, 14, 22),
              new Rectangle2D(753, 489, 8, 30),
              new Rectangle2D(624, 619, 20, 24),
              new Rectangle2D(624, 725, 8, 8),
              new Rectangle2D(574, 734, 20, 16),
              new Rectangle2D(431, 752, 25, 27),
              new Rectangle2D(348, 968, 52, 135),
              new Rectangle2D(282, 1188, 90, 100),
              new Rectangle2D(348, 1335, 50, 50),
   
              new Rectangle2D(228, 284, 500, 316),
              new Rectangle2D(95, 600, 345, 243),
              new Rectangle2D(155, 842, 146, 1358),
              new Rectangle2D(495, 812, 435, 350),
              new Rectangle2D(501, 1156, 100, 150),
              new Rectangle2D(876, 1156, 90, 150),
   
              new Rectangle2D(970, 1159, 14, 25),
              new Rectangle2D(990, 1151, 5, 15),
              new Rectangle2D(1004, 1120, 16, 30),
              new Rectangle2D(1008, 1032, 12, 15),
              new Rectangle2D(1163, 383, 20, 20),
   
              new Rectangle2D(839, 30, 168, 120),
              new Rectangle2D(707, 150, 307, 250),
              new Rectangle2D(845, 397, 179, 75),
              new Rectangle2D(1068, 382, 60, 80),
              new Rectangle2D(787, 687, 60, 72),
              new Rectangle2D(848, 473, 557, 655),
          };
  
          private static Rectangle2D[] m_MalasWrap = new Rectangle2D[]
          {
              new Rectangle2D(611, 67, 1862, 705),
              new Rectangle2D(1540, 852, 286, 182),
              new Rectangle2D(602, 784, 546, 746),
              new Rectangle2D(1160, 1035, 1299, 871)
          };
  
          private static Rectangle2D[] m_IlshenarWrap = new Rectangle2D[]
          {
              new Rectangle2D(221, 314, 657, 286),
              new Rectangle2D(530, 600, 212, 205),
              new Rectangle2D(261, 805, 495, 655),
              new Rectangle2D(908, 925, 90, 170),
              new Rectangle2D(1031, 904, 730, 450),
              new Rectangle2D(1028, 630, 318, 161),
              new Rectangle2D(1205, 368, 265, 237),
              new Rectangle2D(1551, 516, 200, 130),
          };
  
          private static Rectangle2D[] m_TerMurWrap = new Rectangle2D[]
          {
              new Rectangle2D(535, 2895, 85, 117),
              new Rectangle2D(525, 3085, 115, 70),
              new Rectangle2D(755, 2860, 400, 270),
              new Rectangle2D(1025, 3280, 190, 100 ),
              new Rectangle2D(305, 3445, 175, 255),
              new Rectangle2D(480, 3540, 90, 110),
              new Rectangle2D(605, 3880, 200, 170),
              new Rectangle2D(750, 3830, 80, 80),
          };
          #endregion
  
          private static Point2D[] m_Locations;
          private static Point2D[] m_HavenLocations;
  
          private int m_Level;
          private bool m_Completed;
          private Mobile m_CompletedBy;
          private Mobile m_Decoder;
          //private Map m_Map;
          private Point2D m_Location;
          private DateTime m_NextReset;
  
          [CommandProperty(AccessLevel.GameMaster)]
          public int Level
          {
              get { return m_Level; }
              set
              {
                  m_Level = value;
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public bool Completed
          {
              get { return m_Completed; }
              set
              {
                  m_Completed = value;
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Mobile CompletedBy
          {
              get { return m_CompletedBy; }
              set
              {
                  m_CompletedBy = value;
                  InvalidateProperties();
              }
          }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Mobile Decoder
          {
              get { return m_Decoder; }
              set
              {
                  m_Decoder = value;
                  InvalidateProperties();
              }
          }
  
          /*[CommandProperty(AccessLevel.GameMaster)]
          public Map ChestMap
          {
              get { return m_Map; }
              set
              {
                  m_Map = value;
                  InvalidateProperties();
              }
          }*/
  
          [CommandProperty(AccessLevel.GameMaster)]
          public Point2D ChestLocation { get { return m_Location; } set { m_Location = value; } }
  
          [CommandProperty(AccessLevel.GameMaster)]
          public DateTime NextReset { get { return m_NextReset; } set { m_NextReset = value; } }
  
          public override int LabelNumber
          {
              get
              {
                  if (m_Decoder != null)
                  {
                      if (m_Level == 6)
                      {
                          return 1063453;
                      }
                      else if (m_Level == 7)
                      {
                          return 1116773;
                      }
                      else
                      {
                          return 1041516 + m_Level;
                      }
                  }
                  else if (m_Level == 6)
                  {
                      return 1063452;
                  }
                  else if (m_Level == 7)
                  {
                      return 1116790;
                  }
                  else
                  {
                      return 1041510 + m_Level;
                  }
              }
          }
  
          [Constructable]
          public TreasureMap()
          {
          }
  
          [Constructable]
          public TreasureMap(int level, Map map)
          {
              m_Level = level;
  
              if (level == 7 || map == Map.Internal)
                  map = GetRandomMap();
  
              Facet = map;
  
              if (level == 0)
              {
                  m_Location = GetRandomHavenLocation();
              }
              else
              {
                  m_Location = GetRandomLocation(map);
              }
  
              Width = 300;
              Height = 300;
              int width, height;
  
              GetWidthAndHeight(map, out width, out height);
  
              int x1 = m_Location.X - Utility.RandomMinMax(width / 4, (width / 4) * 3);
              int y1 = m_Location.Y - Utility.RandomMinMax(height / 4, (height / 4) * 3);
  
              if (x1 < 0)
                  x1 = 0;
  
              if (y1 < 0)
                  y1 = 0;
  
              int x2;
              int y2;
  
              AdjustMap(map, out x2, out y2, x1, y1, width, height);
  
              x1 = x2 - width;
              y1 = y2 - height;
  
              Bounds = new Rectangle2D(x1, y1, width, height);
              Protected = true;
  
              AddWorldPin(m_Location.X, m_Location.Y);
  
              if (map != Map.Trammel && map != Map.Felucca)
                  m_NextReset = DateTime.UtcNow + ResetTime;
          }
  
          public Map GetRandomMap()
          {
              switch (Utility.Random(8))
              {
                  default:
                  case 0: return Map.Trammel;
                  case 1: return Map.Felucca;
                  case 2:
                  case 3: return Map.Ilshenar;
                  case 4:
                  case 5: return Map.Malas;
                  case 6:
                  case 7: return Map.Tokuno;
              }
          }
  
          public static Point2D GetRandomLocation(Map map)
          {
              if (!NewChestLocations)
                  return GetRandomClassicLocation();
  
              Rectangle2D[] recs;
  
              int x = 0;
              int y = 0;
  
              if (map == Map.Trammel || map == Map.Felucca)
                  recs = m_FelTramWrap;
              else if (map == Map.Tokuno)
                  recs = m_TokunoWrap;
              else if (map == Map.Malas)
                  recs = m_MalasWrap;
              else if (map == Map.Ilshenar)
                  recs = m_IlshenarWrap;
              else
                  recs = m_TerMurWrap;
  
              while (true)
              {
                  Rectangle2D rec = recs[Utility.Random(recs.Length)];
  
                  x = Utility.Random(rec.X, rec.Width);
                  y = Utility.Random(rec.Y, rec.Height);
  
                  if (ValidateLocation(x, y, map))
                      return new Point2D(x, y);
              }
          }
  
          public static bool ValidateLocation(int x, int y, Map map)
          {
              int z = map.GetAverageZ(x, y);
  
              LandTile lt = map.Tiles.GetLandTile(x, y);
              LandData landID = TileData.LandTable[lt.ID];
              TileFlag landFlags = landID.Flags;
  
              //Checks for impassable flag..cant walk, cant have a chest
              if ((landFlags & TileFlag.Impassable) > 0)
                  return false;
  
              Region reg = Region.Find(new Point3D(x, y, z), map);
  
              //no-go in towns, houses, dungeons and champspawns
              if (reg != null && (reg is TownRegion || reg is HouseRegion || reg is DungeonRegion || reg is ChampionSpawnRegion))
                  return false;
  
              //check for house within 5 tiles
              for (int xx = x - 5; xx <= x + 5; xx++)
              {
                  for (int yy = y - 5; yy <= y + 5; yy++)
                  {
                      if (Server.Multis.BaseHouse.FindHouseAt(new Point3D(xx, yy, map.GetAverageZ(xx, yy)), map, 16) != null)
                          return false;
                  }
              }
  
  
  
              //Checks for roads
              //for (int i = 0; i < Server.Multis.HousePlacement.RoadIDs.Length; i += 2)
              //{
              //    if (lt.ID >= Server.Multis.HousePlacement.RoadIDs[i] && lt.ID <= Server.Multis.HousePlacement.RoadIDs[i + 1])
              //        return false;
              //}
  
              string n = landID.Name == null ? "" : landID.Name.ToLower();
              if (n != "dirt" && n != "grass" && n != "jungle" && n != "forest" && n != "snow")
                  return false;
  
              //Rare occrunces where a static tile needs to be checked
              StaticTile[] st = map.Tiles.GetStaticTiles(x, y, true);
              foreach (StaticTile tile in st)
              {
                  ItemData id = TileData.ItemTable[tile.ID & TileData.MaxItemValue];
                  n = id.Name == null ? "" : id.Name.ToLower();
                  TileFlag flags = id.Flags;
                  if ((flags & TileFlag.Impassable) > 0)
                      return false;
  
                  if (n != "dirt" && n != "grass" && n != "jungle" && n != "forest" && n != "snow")
                      return false;
              }
  
              return true;
          }
  
          public void GetWidthAndHeight(Map map, out int width, out int height)
          {
              if (map == Map.Trammel || map == Map.Felucca)
              {
                  width = 600;
                  height = 600;
              }
              if (map == Map.TerMur)
              {
                  width = 200;
                  height = 200;
              }
              else
              {
                  width = 300;
                  height = 300;
              }
          }
  
          public void AdjustMap(Map map, out int x2, out int y2, int x1, int y1, int width, int height)
          {
              x2 = x1 + width;
              y2 = y1 + height;
  
              if (map == Map.Trammel || map == Map.Felucca)
              {
                  if (x2 >= 5120)
                      x2 = 5119;
  
                  if (y2 >= 4096)
                      y2 = 4095;
              }
              else if (map == Map.Ilshenar)
              {
                  if (x2 >= 1890)
                      x2 = 1889;
  
                  if (x2 <= 120)
                      x2 = 121;
  
                  if (y2 >= 1465)
                      y2 = 1464;
  
                  if (y2 <= 105)
                      y2 = 106;
              }
              else if (map == Map.Malas)
              {
                  if (x2 >= 2522)
                      x2 = 2521;
  
                  if (x2 <= 515)
                      x2 = 516;
  
                  if (y2 >= 1990)
                      y2 = 1989;
  
                  if (y2 <= 0)
                      y2 = 1;
              }
              else if (map == Map.Tokuno)
              {
                  if (x2 >= 1428)
                      x2 = 1427;
  
                  if (x2 <= 0)
                      x2 = 1;
  
                  if (y2 >= 1420)
                      y2 = 1419;
  
                  if (y2 <= 0)
                      y2 = 1;
              }
              else if (map == Map.TerMur)
              {
                  if (x2 >= 1271)
                      x2 = 1270;
  
                  if (x2 <= 260)
                      x2 = 261;
  
                  if (y2 >= 4094)
                      y2 = 4083;
  
                  if (y2 <= 2760)
                      y2 = 2761;
              }
          }
  
          public TreasureMap(Serial serial)
              : base(serial)
          { }
  
          public static Point2D GetRandomClassicLocation()
          {
              if (m_Locations == null)
              {
                  LoadLocations();
              }
  
              if (m_Locations.Length > 0)
              {
                  return m_Locations[Utility.Random(m_Locations.Length)];
              }
  
              return Point2D.Zero;
          }
  
          public static Point2D GetRandomHavenLocation()
          {
              if (m_HavenLocations == null)
              {
                  LoadLocations();
              }
  
              if (m_HavenLocations.Length > 0)
              {
                  return m_HavenLocations[Utility.Random(m_HavenLocations.Length)];
              }
  
              return Point2D.Zero;
          }
  
          public static bool IsInHavenIsland(IPoint2D loc)
          {
              return (loc.X >= 3314 && loc.X <= 3814 && loc.Y >= 2345 && loc.Y <= 3095);
          }
  
          public static BaseCreature Spawn(int level, Point3D p, bool guardian, Map map)
          {
              Type[][] spawns;
  
              if (map == Map.Trammel || map == Map.Felucca)
                  spawns = m_SpawnTypes;
              else if (map == Map.Tokuno)
                  spawns = m_TokunoSpawnTypes;
              else if (map == Map.Ilshenar)
                  spawns = m_IlshenarSpawnTypes;
              else if (map == Map.Malas)
                  spawns = m_MalasSpawnTypes;
              else
                  spawns = m_TerMurSpawnTypes;
  
              if (level >= 0 && level < spawns.Length)
              {
                  BaseCreature bc;
  
                  try
                  {
                      bc = (BaseCreature)Activator.CreateInstance(m_SpawnTypes[level][Utility.Random(spawns[level].Length)]);
                  }
                  catch
                  {
                      return null;
                  }
  
                  bc.Home = p;
                  bc.RangeHome = 5;
                  bc.Title = "(Guardian)";
  
                  if (guardian && level == 0)
                  {
                      bc.Name = "a chest guardian";
                      bc.Hue = 0x835;
                  }
  
                  return bc;
              }
  
              return null;
          }
  
          public static BaseCreature Spawn(int level, Point3D p, Map map, Mobile target, bool guardian)
          {
              if (map == null)
              {
                  return null;
              }
  
              BaseCreature c = Spawn(level, p, guardian, map);
  
              if (c != null)
              {
                  bool spawned = false;
  
                  for (int i = 0; !spawned && i < 10; ++i)
                  {
                      int x = p.X - 3 + Utility.Random(7);
                      int y = p.Y - 3 + Utility.Random(7);
  
                      if (map.CanSpawnMobile(x, y, p.Z))
                      {
                          c.MoveToWorld(new Point3D(x, y, p.Z), map);
                          spawned = true;
                      }
                      else
                      {
  
gt:                         int z = map.GetAverageZ(x, y);