context: /*
  Package Name: CEO's Yet Another Arya Addon Generator (YAAAG)
  Author: CEO
  Version: 1.2
  Public Release: 09/25/07
  Purpose:  Generates AddOns from statics, items, and tiles. Oh my!
  */
  /* Modified to work with the new SA & High Seas items by Hammerhand */
  // If you're using an SVN that supports List<> methods (remove the //s) to use those instead of arrays or add them for RC1.
  #define RC2
  //#define DEBUG
  #undef DEBUG
  using System;
  using System.Collections;
  using System.IO;
  using Server;
  using Server.Items;
  using Server.Gumps;
  using Server.Commands;
  using System.Collections.Generic;
  using Server.ContextMenus;
  using Server.Network;
  using Server.Targeting;
  
  namespace Arya.Misc
  {
      public class AddonGenerator
      {
          /// <summary>
          /// Set this value if you wish the scripts to be output somewhere else rather than in the default RunUO\TheBox
          /// directory. This should be a full valid path on your computer
          /// 
          /// Example:
          /// 
          /// private static string m_CustomOutputDirector = @"C:\Program Files\RunUO\Scripts\Custom\Addons";
          /// </summary>
          private static string m_CustomOutputDirectory = null;
  
          #region Template
  
          private const string m_SimpleCode = @"
              for (int i = 0; i < m_AddOnSimpleComponents.Length / 4; i++)
                  AddComponent( new AddonComponent( m_AddOnSimpleComponents[i,0] ), m_AddOnSimpleComponents[i,1], m_AddOnSimpleComponents[i,2], m_AddOnSimpleComponents[i,3] );";
  
          private const string m_ComplexCode = @"
              for (int i = 0; i < m_AddOnComplexComponents.Length / 6; i++)
                  AddComplexComponent( (BaseAddon)this, m_AddOnComplexComponents[i,0], m_AddOnComplexComponents[i,1], m_AddOnComplexComponents[i,2], m_AddOnComplexComponents[i,3], m_AddOnComplexComponents[i,4], m_AddOnComplexComponents[i,5] );";
  
          private const string m_ComplexNameCode = @"
          private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource)
          {
              AddComplexComponent(addon, item, xoffset, yoffset, zoffset, hue, lightsource, null, 1);
          }
  
          private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource, string name, int amount)
          {
              AddonComponent ac;
              ac = new AddonComponent(item);
              if (name != null && name.Length > 0)
                  ac.Name = name;
              if (hue != 0)
                  ac.Hue = hue;
              if (amount > 1)
              {
                  ac.Stackable = true;
                  ac.Amount = amount;
              }
              if (lightsource != -1)
                  ac.Light = (LightType) lightsource;
              addon.AddComponent(ac, xoffset, yoffset, zoffset);
          }";
  
          private const string m_Template = @"
  ////////////////////////////////////////
  //                                     //
  //   Generated by CEO's YAAAG - Ver 2  //
  // (Yet Another Arya Addon Generator)  //
  //    Modified by Hammerhand for       //
  //      SA & High Seas content         //
  //                                     //
  ////////////////////////////////////////
  using System;
  using Server;
  using Server.Items;
  
  namespace {namespace}
  {
  	public class {name}Addon : BaseAddon
  	{
          {simplelist} 
          {complexlist}    
  		public override BaseAddonDeed Deed
  		{
  			get
  			{
  				return new {name}AddonDeed();
  			}
  		}
  
  		[ Constructable ]
  		public {name}Addon()
  		{
  {simplecomponentscode}
  {complexcomponentscode}
  {namedcomponentscode}
  		}
  
  		public {name}Addon( Serial serial ) : base( serial )
  		{
  		}
  {complexnamecomponentscode}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  			writer.Write( 0 ); // Version
  		}
  
  		public override void Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  			int version = reader.ReadInt();
  		}
  	}
  
  	public class {name}AddonDeed : BaseAddonDeed
  	{
  		public override BaseAddon Addon
  		{
  			get
  			{
  				return new {name}Addon();
  			}
  		}
  
  		[Constructable]
  		public {name}AddonDeed()
  		{
  			Name = ""{name}"";
  		}
  
  		public {name}AddonDeed( Serial serial ) : base( serial )
  		{
  		}
  
  		public override void Serialize( GenericWriter writer )
  		{
  			base.Serialize( writer );
  			writer.Write( 0 ); // Version
  		}
  
  		public override void	Deserialize( GenericReader reader )
  		{
  			base.Deserialize( reader );
  			int version = reader.ReadInt();
  		}
  	}
  }";
  
          #endregion
  
          public static void Initialize()
          {
              CommandSystem.Register("AddonGen", AccessLevel.Administrator, new CommandEventHandler(OnAddonGen));
          }
  
          #region Command
          [Usage("AddonGen [<name> [namespace]]"),
          Description("Brings up the addon script generator gump. When used with the name (and eventually namespace) parameter generates an addon script from the targeted region.")]
          private static void OnAddonGen(CommandEventArgs e)
          {
  
              object[] state = new object[18];
  
              state[0] = "";
              state[1] = "Server.Items";
              state[2] = true;
              state[3] = false;
              state[4] = false;
              state[5] = true;
              state[6] = true;
              state[7] = true;
              state[8] = true;
              state[9] = -128;
              state[10] = 127;
              state[11] = state[13] = state[15] = 2;
              state[12] = state[14] = state[16] = 36653;
  
              if (e.Arguments.Length > 0)
              {
                  state[0] = e.Arguments[0];
  
                  if (e.Arguments.Length > 1)
                      state[1] = e.Arguments[1];
              }
              e.Mobile.SendGump(new InternalGump(e.Mobile, state));
          }
          #endregion
  
          private static void PickerCallback(Mobile from, Map map, Point3D start, Point3D end, object state)
          {
              object[] args = state as object[];
              int m_SimpleComponents = 0;
              int m_ComplexComponents = 0;
              int m_NamedComponents = 0;
              int m_TotalComponents = 0;
  
              if (start.X > end.X)
              {
                  int x = start.X;
                  start.X = end.X;
                  end.X = x;
              }
  
              if (start.Y > end.Y)
              {
                  int y = start.Y;
                  start.Y = end.Y;
                  end.Y = y;
              }
  
              Rectangle2D bounds = new Rectangle2D(start, end);
  
              string name = args[0] as string;
              string ns = args[1] as string;
  
              bool getStatics = (bool)args[2];
              bool getItems = (bool)args[3];
              bool getTiles = (bool)args[4];
              bool includeStaticRange = (bool)args[5];
              bool includeItemRange = (bool)args[6];
              bool includeTileRange = (bool)args[7];
              bool includeZRange = (bool)args[8];
              bool generateTest = (bool)args[17];
  
              sbyte min = sbyte.MinValue;
              sbyte max = sbyte.MaxValue;
  
              int minStaticID = 2;
              int maxStaticID = 36653;
              int minItemID = 2;
              int maxItemID = 36653;
              int minTileID = 2;
              int maxTileID = 36653;
  
              try { min = sbyte.Parse(args[9] as string); }
              catch { }
              try { max = sbyte.Parse(args[10] as string); }
              catch { }
              try { minStaticID = int.Parse(args[11] as string); }
              catch { }
              try { maxStaticID = int.Parse(args[12] as string); }
              catch { }
              try { minItemID = int.Parse(args[13] as string); }
              catch { }
              try { maxItemID = int.Parse(args[14] as string); }
              catch { }
              try { minTileID = int.Parse(args[15] as string); }
              catch { }
              try { maxTileID = int.Parse(args[16] as string); }
              catch { }
  
              Hashtable tiles = new Hashtable();
  
              if (getTiles)
              {
                  for (int x = start.X; x <= end.X; x++)
                  {
                      for (int y = start.Y; y <= end.Y; y++)
                      {
  #if RC2
                          StaticTile[] stlist = map.Tiles.GetStaticTiles(x, y, true);
                          List<Server.StaticTile> list = new List<Server.StaticTile>();
                          List<Server.StaticTile> remove = new List<Server.StaticTile>();
  #else
                          ArrayList list = map.GetTilesAt(new Point2D(x, y), false, false, true);
                          ArrayList remove = new ArrayList();
  #endif
  
                          foreach (StaticTile t in stlist)
                          {
                              list.Add(t);
                              
                              int id = t.ID - 36653;
                              if (id < 2 || id > 36653)
                                  remove.Add(t);
                              else if (includeZRange && (t.Z < min || t.Z > max))
                                  remove.Add(t);
                              else if (!includeZRange && (t.Z >= min && t.Z <= max))
                                  remove.Add(t);
                              else if (includeTileRange && (id < minTileID || id > maxTileID))
                                  remove.Add(t);
                              else if (!includeTileRange && (id >= minTileID && id <= maxTileID))
                                  remove.Add(t);
                          }
  
                          foreach (StaticTile t in remove)
                          {
                              list.Remove(t);
                          }
  
                          if (list != null && list.Count > 0)
                          {
                              tiles[new Point2D(x, y)] = list;
                          }
                      }
                  }
              }
  
              IPooledEnumerable en = map.GetItemsInBounds(bounds);
              ArrayList target = new ArrayList();
              bool fail = false;
  
              try
              {
                  foreach (object o in en)
                  {
                      if (getStatics)
                      {
                          Static s = o as Static;
                          if (s == null)
                          { }
                          else if (s.Deleted)
                          { }
                          else if (includeZRange && (s.Z < min || s.Z > max))
                              continue;
                          else if (!includeZRange && (s.Z >= min && s.Z <= max))
                              continue;
                          else if (includeStaticRange && (s.ItemID < minStaticID || s.ItemID > maxStaticID))
                              continue;
                          else if (!includeStaticRange && (s.ItemID >= minStaticID && s.ItemID <= maxStaticID))
                              continue;
                          else
                          {
                              target.Add(o);
  #if DEBUG
                              Console.WriteLine("Static={0}:{1}", s.GetType().ToString(), s.ItemID);
  #endif
                              continue;
                          }
                      }
                      if (getItems)
                      {
                          Static s = o as Static;
                          if (s != null) // Don't want a static
                              continue;
                          Item i = o as Item;
                          if (i == null)
                              continue;
                          else if (i.Deleted)
                              continue;
                          else if (i is BaseAddon) // Not a good idea to add a BaseAddOn for obvious reasons
                              continue;
                          else if (i.ItemID < 2 || i.ItemID > 36653) // This is not an Item within the normal artwork.. multi... etc.. Toss it
                              continue;
                          else if (includeZRange && (i.Z < min || i.Z > max))
                              continue;
                          else if (!includeZRange && (i.Z >= min && i.Z <= max))
                              continue;
                          else if (includeItemRange && (i.ItemID < minItemID || i.ItemID > maxItemID))
                              continue;
                          else if (!includeItemRange && (i.ItemID >= minItemID && i.ItemID <= maxItemID))
                              continue;
  #if DEBUG
                          Console.WriteLine("item={0}:{1}, {2}-map{3}", i.GetType().ToString(), i.ItemID, i.Deleted, i.Map);
  #endif
                          target.Add(o);
                      }
                  }
              }
              catch (Exception err)
              {
                  Console.WriteLine(err.ToString());
                  from.SendMessage(0x40, "The targeted components have been modified. Please retry.");
                  fail = true;
              }
              finally
              {
                  en.Free();
              }
  
              if (fail)
                  return;
  
              if (target.Count == 0 && tiles.Keys.Count == 0)
              {
                  from.SendMessage(0x40, "No components have been selected.");
                  from.SendGump(new InternalGump(from, args));
                  return;
              }
  
              // Get center
              Point3D center = new Point3D();
              center.Z = 127;
  
              int x1 = bounds.End.X;
              int y1 = bounds.End.Y;
              int x2 = bounds.Start.X;
              int y2 = bounds.Start.Y;
  
              // Get correct bounds
              foreach (Item item in target)
              {
                  if (item.Z < center.Z)
                  {
                      center.Z = item.Z;
                  }
  
                  x1 = Math.Min(x1, item.X);
                  y1 = Math.Min(y1, item.Y);
                  x2 = Math.Max(x2, item.X);
                  y2 = Math.Max(y2, item.Y);
              }
              CEOIdentifyAddon IdentifyAddon = null;
  
              if (generateTest)
                  IdentifyAddon = new CEOIdentifyAddon("init");
  
              foreach (Point2D p in tiles.Keys)
              {
  #if RC2
                  List<Server.StaticTile> list = tiles[p] as List<Server.StaticTile>;
  #else
                  ArrayList list = tiles[p] as ArrayList;
  #endif
  
                  if (list == null)
                  {
                      Console.WriteLine("The list is null... ");
                      return;
                  }
  
                  foreach (StaticTile t in list)
                  {
                      if (t.Z < center.Z)
                      {
                          center.Z = t.Z;
                      }
                  }
  
                  x1 = Math.Min(x1, p.X);
                  y1 = Math.Min(y1, p.Y);
                  x2 = Math.Max(x2, p.X);
                  y2 = Math.Max(y2, p.Y);
              }
  
              center.X = x1 + ((x2 - x1) / 2);
              center.Y = y1 + ((y2 - y1) / 2);
  
              // Build items
              System.Text.StringBuilder nc = new System.Text.StringBuilder();
              nc.Append("\n");
              System.Text.StringBuilder sl = new System.Text.StringBuilder();
              sl.Append("private static int[,] m_AddOnSimpleComponents = new int[,] {\n\t\t\t  ");
              System.Text.StringBuilder cl = new System.Text.StringBuilder();
              cl.Append("private static int[,] m_AddOnComplexComponents = new int[,] {\n\t\t\t  ");
              System.Text.StringBuilder sc = new System.Text.StringBuilder();
              sc.Append("// ");
              System.Text.StringBuilder cc = new System.Text.StringBuilder();
              cc.Append("// ");
  
              int simplecount = 0;
              int complexcount = 0;
              // Tiles
              foreach (Point2D p in tiles.Keys)
              {
  #if RC2
                  List<Server.StaticTile> list = tiles[p] as List<Server.StaticTile>;
  #else
                  ArrayList list = tiles[p] as ArrayList;
  #endif
                  int xOffset = p.X - center.X;
                  int yOffset = p.Y - center.Y;
  
                  foreach (StaticTile t in list)
                  {
                      int zOffset = t.Z - center.Z;
                      int id = t.ID - 36653;
                      m_SimpleComponents++;
                      simplecount++;
                      m_TotalComponents++;
                      sc.AppendFormat("{0}\t ", m_TotalComponents);
                      if (simplecount > 1)
                          sl.Append(", ");
                      sl.Append("{");
                      sl.AppendFormat("{0}, {1}, {2}, {3}", id, xOffset, yOffset, zOffset);
                      sl.Append("}");
                      if (simplecount % 3 == 0)
                      {
                          sl.AppendFormat("{0}\n\t\t\t", sc.ToString());
                          sc.Length = 0;
                          sc.Append("// ");
                      }
                      if (generateTest)
                          AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, 0, -1, string.Format("({0}):{1},{2},{3}", m_TotalComponents, xOffset, yOffset, zOffset), 0);
                  }
              }
              // Statics & Items
              foreach (Item item in target)
              {
                  if (item.Deleted)
                      continue;
                  int xOffset = item.X - center.X;
                  int yOffset = item.Y - center.Y;
                  int zOffset = item.Z - center.Z;
                  int id = item.ItemID;
  
                  if (((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource) || (item.Hue != 0) || (item.Name != null) || item.Amount > 1) // Use old method
                  {
                      if (item.Name != null || item.Amount != 0) // Have to do this one the old method
                      {
                          m_NamedComponents++;
                          m_TotalComponents++;
                          int lightsource = -1;
                          if ((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource)
                              lightsource = (int)item.Light;
                          nc.AppendFormat("\t\t\tAddComplexComponent( (BaseAddon) this, {0}, {1}, {2}, {3}, {4}, {5}, \"{6}\", {7});// {8}\n", id, xOffset, yOffset, zOffset, item.Hue, lightsource, item.Name, item.Amount, m_TotalComponents);
                          if (generateTest)
                              AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), item.Amount);
  
                      }
                      else //if (item.Hue != 0 || (item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource)
                      {
                          int lightsource = -1;
                          if ((item.ItemData.Flags & TileFlag.LightSource) == TileFlag.LightSource)
                              lightsource = (int)item.Light;
                          m_ComplexComponents++;
                          m_TotalComponents++;
                          cc.AppendFormat("{0}\t", m_TotalComponents);
                          complexcount++;
                          if (complexcount > 1)
                              cl.Append(", ");
                          cl.Append("{");
                          cl.AppendFormat("{0}, {1}, {2}, {3}, {4}, {5} ", id, xOffset, yOffset, zOffset, item.Hue, lightsource);
                          cl.Append("}");
                          if (complexcount % 3 == 0)
                          {
                              cl.AppendFormat("{0}\n\t\t\t", cc.ToString());
                              cc.Length = 0;
                              cc.Append("// ");
                          }
                          if (generateTest)
                              AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), 0);
                      }
                  }
                  else // Add data to static table
                  {
                      m_SimpleComponents++;
                      m_TotalComponents++;
                      sc.AppendFormat("{0}\t", m_TotalComponents);
                      simplecount++;
                      if (simplecount > 1)
                          sl.Append(", ");
                      sl.Append("{");
                      sl.AppendFormat("{0}, {1}, {2}, {3}", id, xOffset, yOffset, zOffset);
                      sl.Append("}");
                      if (simplecount % 3 == 0)
                      {
                          sl.AppendFormat("{0}\n\t\t\t", sc.ToString());
                          sc.Length = 0;
                          sc.Append("// ");
                      }
                      if (generateTest)
                          AddIdentifyAddOnComponent(IdentifyAddon, id, xOffset, yOffset, zOffset, item.Hue, -1, string.Format("({0},{1}): {2}, {3}, {4}", m_TotalComponents, id, xOffset, yOffset, zOffset), 0);
                  }
              }
              if (sc.Length > 4)
                  sl.AppendFormat("{0}\n", sc.ToString());
              if (cc.Length > 4)
                  cl.AppendFormat("{0}\n", cc.ToString());
              if (m_SimpleComponents > 0)
                  sl.Append("\t\t};\n\n");
              if (m_ComplexComponents > 0)
                  cl.Append("\t\t};\n\n");
  
              string output = m_Template.Replace("{name}", name);
              output = output.Replace("{simplelist}", m_SimpleComponents > 0 ? sl.ToString() : "");
              output = output.Replace("{simplecomponentscode}", m_SimpleComponents > 0 ? m_SimpleCode : "");
              output = output.Replace("{complexlist}", m_ComplexComponents > 0 ? cl.ToString() : "");
              output = output.Replace("{complexcomponentscode}", m_ComplexComponents > 0 ? m_ComplexCode : "");
              output = output.Replace("{namedcomponentscode}", m_NamedComponents > 0 ? nc.ToString() : "");
              output = output.Replace("{complexnamecomponentscode}", (m_ComplexComponents > 0 || m_NamedComponents > 0) ? m_ComplexNameCode : "");
  
              output = output.Replace("{namespace}", ns);
  
              StreamWriter writer = null;
              string path = null;
  
              if (m_CustomOutputDirectory != null)
                  path = Path.Combine(m_CustomOutputDirectory, string.Format(@"TheBox\{0}Addon.cs", name));
              else
                  path = Path.Combine(Core.BaseDirectory, string.Format(@"TheBox\{0}Addon.cs", name));
  
              fail = false;
  
              try
              {
                  string folder = Path.GetDirectoryName(path);
  
                  if (!Directory.Exists(folder))
                  {
                      Directory.CreateDirectory(folder);
                  }
  
                  writer = new StreamWriter(path, false);
                  writer.Write(output);
              }
              catch
              {
                  from.SendMessage(0x40, "An error occurred when writing the file.");
                  fail = true;
              }
              finally
              {
                  if (writer != null)
                      writer.Close();
              }
  
              if (!fail)
              {
                  from.SendMessage(0x40, "Script saved to {0}", path);
                  from.SendMessage(0x40, "Total components in AddOn: {0}", m_TotalComponents);
                  if (generateTest && IdentifyAddon != null)
                  {
                      from.SendMessage(0x37, "Now target a land tile to place a your addon.");
                      from.Target = new InternalTarget(IdentifyAddon);
                  }
              }
          }
  
          private static void AddIdentifyAddOnComponent(CEOIdentifyAddon ai, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource, string name, int amount)
          {
              if (ai == null)
                  return;
              AddonComponent ac;
              ac = new AddonComponent(item);
  
gt:             if (name != null && name.Length > 0)