context: using Server.Commands;
  using Server.Items;
  using Server.Mobiles;
  using Server.Network;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  
  namespace Server.Engines.Quests
  {
      public class MadScientistQuest
      {
          #region Generation
          public static void Initialize()
          {
              CommandSystem.Register("GenSutek", AccessLevel.Developer, GenQuest_Command);
          }
  
          private static void GenQuest_Command(CommandEventArgs e)
          {
              e.Mobile.SendMessage("Creating Mad Scientist Quest...");
  
              foreach (SutekIngredientInfo def in m_Ingredients)
              {
                  WeakEntityCollection.Add("sa", new SutekIngredientItem(def));
              }
  
              XmlSpawner sp = new XmlSpawner("Sutek")
              {
                  SpawnRange = 5,
                  HomeRange = 5
              };
              sp.MoveToWorld(new Point3D(917, 594, -14), Map.TerMur);
              sp.Respawn();
              WeakEntityCollection.Add("sa", sp);
  
              List<Item> toDelete = new List<Item>(World.Items.Values.Where(i => i is XmlSpawner && (i.Name == "PerfectTimingSpawner" || i.Name == "PerfectTimingSpawner2")));
  
              foreach (Item item in toDelete)
              {
                  item.Delete();
              }
  
              e.Mobile.SendMessage("Generation completed, deleted {0} spawners!", toDelete.Count);
              ColUtility.Free(toDelete);
          }
          #endregion
  
          #region Definitions
          public static readonly int NeededIngredients = 20;
          public static readonly TimeSpan Timeout = TimeSpan.FromSeconds(15.0);
  
          public static readonly SutekIngredientInfo[] m_Ingredients =
          {
              new SutekIngredientInfo(SutekIngredient.Feathers,      new Point3D(921, 598, -8),    0x1BD3, 1023578),
              new SutekIngredientInfo(SutekIngredient.Shafts,        new Point3D(918, 591, -14),   0x1BD6, 1027125),
              new SutekIngredientInfo(SutekIngredient.PowerCrystal,  new Point3D(917, 589, -5),    0x1F1C, 1112811),
              new SutekIngredientInfo(SutekIngredient.PowerCrystal,  new Point3D(926, 597, -4),    0x1F19, 1112811),
              new SutekIngredientInfo(SutekIngredient.YellowPotion,  new Point3D(926, 593, -8),    0x183B, 1023852),
              new SutekIngredientInfo(SutekIngredient.BarrelHoops,   new Point3D(931, 601, -14),   0x1DB7, 1011228),
              new SutekIngredientInfo(SutekIngredient.BarrelHoops,   new Point3D(931, 601, -12),   0x1DB7, 1011228),
              new SutekIngredientInfo(SutekIngredient.BarrelStaves,  new Point3D(932, 600, -14),   0x1EB2, 1027857),
              new SutekIngredientInfo(SutekIngredient.BarrelStaves,  new Point3D(933, 600, -14),   0x1EB3, 1027857),
              new SutekIngredientInfo(SutekIngredient.Bones,         new Point3D(925, 605, -14),   0x21FC, 1023786),
              new SutekIngredientInfo(SutekIngredient.FetidEssence,  new Point3D(926, 599, -5),    0x2D92, 1031066),
              new SutekIngredientInfo(SutekIngredient.VoidEssence,   new Point3D(926, 589, -3),    0x2D92, 1112327, 0x835),
              new SutekIngredientInfo(SutekIngredient.SpiritEssence, new Point3D(916, 602, -4),    0x2D87, 1055029, 0x481),
              new SutekIngredientInfo(SutekIngredient.Rope,          new Point3D(911, 589, -13),   0x14F8, 1020934),
              new SutekIngredientInfo(SutekIngredient.Rope,          new Point3D(919, 581, -14),   0x14FA, 1020934),
              new SutekIngredientInfo(SutekIngredient.WoodenLogs,    new Point3D(910, 590, -13),   0x1BDF, 1021217),
              new SutekIngredientInfo(SutekIngredient.WoodenLogs,    new Point3D(916, 609, -14),   0x1BE1, 1021217),
              new SutekIngredientInfo(SutekIngredient.WoodenLogs,    new Point3D(939, 593, -14),   0x1BDE, 1021217),
              new SutekIngredientInfo(SutekIngredient.WoodenLogs,    new Point3D(911, 602, -14),   0x1BE2, 1021217),
              new SutekIngredientInfo(SutekIngredient.PurplePotion,  new Point3D(916, 601, -6),    0x1841, 1023853),
              new SutekIngredientInfo(SutekIngredient.Scales,        new Point3D(921, 588, -8),    0x26B5, 1029905),
              new SutekIngredientInfo(SutekIngredient.Scales,        new Point3D(923, 603, -6),    0x26B2, 1029905),
              new SutekIngredientInfo(SutekIngredient.WhiteStone,    new Point3D(927, 605, -14),   0x177A, 1112813),
              new SutekIngredientInfo(SutekIngredient.DarkStone,     new Point3D(931, 583, -14),   0x1776, 1112866),
              new SutekIngredientInfo(SutekIngredient.Beeswax,       new Point3D(926, 600, -6),    0x1425, 1025154),
              new SutekIngredientInfo(SutekIngredient.Beeswax,       new Point3D(925, 603, -8),    0x1426, 1025154),
              new SutekIngredientInfo(SutekIngredient.Thorns,        new Point3D(928, 595, -14),   0x3022, 1112818),
              new SutekIngredientInfo(SutekIngredient.Thorns,        new Point3D(928, 596, -14),   0x3022, 1112818),
              new SutekIngredientInfo(SutekIngredient.WoodenBoards,  new Point3D(939, 592, -14),   0x1BDB, 1021189),
              new SutekIngredientInfo(SutekIngredient.WoodenBoards,  new Point3D(928, 590, -14),   0x1BDC, 1021189),
              new SutekIngredientInfo(SutekIngredient.WoodenBoards,  new Point3D(911, 591, -14),   0x1BD8, 1021189),
              new SutekIngredientInfo(SutekIngredient.WoodenBoards,  new Point3D(916, 598, -14),   0x1BD9, 1021189),
              new SutekIngredientInfo(SutekIngredient.BrownStone,    new Point3D(922, 577, -14),   0x1772, 1112814),
              new SutekIngredientInfo(SutekIngredient.RedPotion,     new Point3D(925, 603, -8),    0x183E, 1023851),
              new SutekIngredientInfo(SutekIngredient.PurplePotion,  new Point3D(921, 597, -10),   0x1839, 1023853),
              new SutekIngredientInfo(SutekIngredient.BluePotion,    new Point3D(921, 596, -7),    0x1844, 1023848),
              new SutekIngredientInfo(SutekIngredient.Gears,         new Point3D(920, 597, -8),    0x1051, 1024177),
              new SutekIngredientInfo(SutekIngredient.MeltedWax,     new Point3D(916, 600, -6),    0x142B, 1025162),
              new SutekIngredientInfo(SutekIngredient.MeltedWax,     new Point3D(926, 595, -7),    0x142A, 1025162),
              new SutekIngredientInfo(SutekIngredient.Leather,       new Point3D(924, 588, -14),   0x1078, 1024216),
              new SutekIngredientInfo(SutekIngredient.CopperWire,    new Point3D(910, 589, -8),    0x1879, 1026265),
              new SutekIngredientInfo(SutekIngredient.GoldWire,      new Point3D(910, 589, -13),   0x1878, 1026264),
              new SutekIngredientInfo(SutekIngredient.SilverWire,    new Point3D(910, 589, -10),   0x1877, 1026263),
              new SutekIngredientInfo(SutekIngredient.IronWire,      new Point3D(910, 589, -6),    0x1876, 1026262),
              new SutekIngredientInfo(SutekIngredient.SilverIngots,  new Point3D(911, 588, -14),   0x1BFA, 1027158),
              new SutekIngredientInfo(SutekIngredient.SilverIngots,  new Point3D(928, 603, -14),   0x1BF7, 1027158),
              new SutekIngredientInfo(SutekIngredient.GoldIngots,    new Point3D(914, 581, -14),   0x1BEE, 1027146),
              new SutekIngredientInfo(SutekIngredient.GoldIngots,    new Point3D(922, 594, -14),   0x1BEB, 1027146),
              new SutekIngredientInfo(SutekIngredient.CopperIngots,  new Point3D(914, 580, -14),   0x1BE5, 1027140),
              new SutekIngredientInfo(SutekIngredient.CopperIngots,  new Point3D(916, 590, -11),   0x1BE8, 1027140),
              new SutekIngredientInfo(SutekIngredient.IronIngots,    new Point3D(915, 580, -14),   0x1BF1, 1027152),
              new SutekIngredientInfo(SutekIngredient.IronIngots,    new Point3D(912, 602, -15),   0x1BF4, 1027152),
              new SutekIngredientInfo(SutekIngredient.OilOfVitriol,  new Point3D(916, 601, -8),    0x098D, 1077482),
              new SutekIngredientInfo(SutekIngredient.BlackPowder,   new Point3D(920, 597, -6),    0x0B48, 1112815, 0x497),
              new SutekIngredientInfo(SutekIngredient.WhitePowder,   new Point3D(926, 602, -6),    0x241D, 1112816),
              new SutekIngredientInfo(SutekIngredient.BluePowder,    new Point3D(926, 594, -4),    0x241E, 1112817),
              new SutekIngredientInfo(SutekIngredient.Nails,         new Point3D(915, 589, -14),   0x102E, 1024142),
          };
  
          private static readonly Dictionary<Mobile, QuestContext> m_Table = new Dictionary<Mobile, QuestContext>();
          #endregion
  
          public static bool QuestStarted(Mobile from)
          {
              return m_Table.ContainsKey(from);
          }
  
          public static void StartQuest(Mobile from, ClockworkMechanism mechanism)
          {
              if (QuestStarted(from))
                  return;
  
              QuestContext context = m_Table[from] = new QuestContext(from, mechanism);
              context.StartTimer();
          }
  
          public static void OnDoubleClickIngredient(Mobile from, SutekIngredient ingredient)
          {
              if (!QuestStarted(from))
                  return;
  
              QuestContext context = m_Table[from];
  
              if (ingredient == context.CurrentIngredient)
              {
                  from.SendLocalizedMessage(1112819); // You've successfully added this ingredient.
  
                  context.OnIngredientAcquired();
              }
              else
              {
                  from.SendLocalizedMessage(1112820); // That is not the right ingredient.
  
                  BarkIngredient(from);
              }
          }
  
          public static void BarkIngredient(Mobile from)
          {
              if (!QuestStarted(from))
                  return;
  
              QuestContext context = m_Table[from];
  
              from.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1112821, string.Format("#{0}", (int)context.CurrentIngredient)); // I need to add some ~1_INGREDIENT~.
          }
  
          public class QuestContext
          {
              private readonly Mobile m_Owner;
              private int m_IngredientsLeft = NeededIngredients;
              private SutekIngredient m_CurrentIngredient;
              private Timer m_ExpireTimer;
              private readonly ClockworkMechanism m_Mechanism;
  
              public Mobile Owner => m_Owner;
              public int IngredientsLeft => m_IngredientsLeft;
              public SutekIngredient CurrentIngredient => m_CurrentIngredient;
              public Timer ExpireTimer => m_ExpireTimer;
              public ClockworkMechanism Mechanism => m_Mechanism;
  
              public QuestContext(Mobile from, ClockworkMechanism mechanism)
              {
                  m_Owner = from;
                  m_Mechanism = mechanism;
              }
  
              public void StartTimer()
              {
                  if (m_ExpireTimer != null)
                      m_ExpireTimer.Stop();
  
                  m_ExpireTimer = Timer.DelayCall(Timeout, OnExpired);
  
                  SutekIngredient[] ingredients = (SutekIngredient[])Enum.GetValues(typeof(SutekIngredient));
                  m_CurrentIngredient = ingredients[Utility.Random(ingredients.Length)];
  
                  m_Owner.PublicOverheadMessage(MessageType.Regular, 0x3B2, 1112821, string.Format("#{0}", (int)m_CurrentIngredient)); // I need to add some ~1_INGREDIENT~.
  
                  m_IngredientsLeft--;
              }
  
              public void OnExpired()
              {
                  m_ExpireTimer.Stop();
  
                  m_Owner.SendLocalizedMessage(1112822); // You fail to find the next ingredient in time. Your clockwork assembly crumbles.
  
                  m_Mechanism.Delete();
                  m_Table.Remove(m_Owner);
              }
  
              public void OnIngredientAcquired()
              {
  
gt:                 if (m_IngredientsLeft == 0)