context: using Server.Gumps;
  using Server.Network;
  using System;
  using System.Collections;
  
  namespace Server.Items
  {
      public class PowerGenerator : BaseAddon
      {
          [Constructable]
          public PowerGenerator()
              : this(Utility.RandomMinMax(3, 6))
          {
          }
  
          [Constructable]
          public PowerGenerator(int sideLength)
          {
              AddGeneratorComponent(0x73, 0, 0, 0);
              AddGeneratorComponent(0x76, -1, 0, 0);
              AddGeneratorComponent(0x75, 0, -1, 0);
              AddGeneratorComponent(0x37F4, 0, 0, 13);
  
              AddComponent(new ControlPanel(sideLength), 1, 0, -2);
          }
  
          public PowerGenerator(Serial serial)
              : base(serial)
          {
          }
  
          public override bool ShareHue => false;
          public override void Serialize(GenericWriter writer)
          {
              base.Serialize(writer);
  
              writer.WriteEncodedInt(0); // version
          }
  
          public override void Deserialize(GenericReader reader)
          {
              base.Deserialize(reader);
  
              int version = reader.ReadEncodedInt();
          }
  
          private void AddGeneratorComponent(int itemID, int x, int y, int z)
          {
              AddonComponent component = new AddonComponent(itemID);
              component.Name = "a power generator";
              component.Hue = 0x451;
  
              AddComponent(component, x, y, z);
          }
      }
  
      public class ControlPanel : AddonComponent
      {
          private static readonly TimeSpan m_UseTimeout = TimeSpan.FromMinutes(2.0);
          private readonly Hashtable m_DamageTable = new Hashtable();
          private int m_SideLength;
          private Node[] m_Path;
          private Mobile m_User;
          private DateTime m_LastUse;
          public ControlPanel(int sideLength)
              : base(0xBDC)
          {
              Hue = 0x835;
  
              SideLength = sideLength;
          }
  
          public ControlPanel(Serial serial)
              : base(serial)
          {
          }
  
          private enum PathDirection
          {
              Left,
              Up,
              Right,
              Down
          }
          [CommandProperty(AccessLevel.GameMaster)]
          public int SideLength
          {
              get
              {
                  return m_SideLength;
              }
              set
              {
                  if (value < 3)
                      value = 3;
                  else if (value > 6)
                      value = 6;
  
                  if (m_SideLength != value)
                  {
                      m_SideLength = value;
                      InitPath();
                  }
              }
          }
          public Node[] Path => m_Path;
          public override string DefaultName => "a control panel";
          public void InitPath()
          {
              // Depth-First Search algorithm
              int totalNodes = SideLength * SideLength;
  
              Node[] stack = new Node[totalNodes];
              Node current = stack[0] = new Node(0, 0);
              int stackSize = 1;
  
              bool[,] visited = new bool[SideLength, SideLength];
              visited[0, 0] = true;
  
              while (true)
              {
                  PathDirection[] choices = new PathDirection[4];
                  int count = 0;
  
                  if (current.X > 0 && !visited[current.X - 1, current.Y])
                      choices[count++] = PathDirection.Left;
  
                  if (current.Y > 0 && !visited[current.X, current.Y - 1])
                      choices[count++] = PathDirection.Up;
  
                  if (current.X < SideLength - 1 && !visited[current.X + 1, current.Y])
                      choices[count++] = PathDirection.Right;
  
                  if (current.Y < SideLength - 1 && !visited[current.X, current.Y + 1])
                      choices[count++] = PathDirection.Down;
  
                  if (count > 0)
                  {
                      PathDirection dir = choices[Utility.Random(count)];
  
                      switch (dir)
                      {
                          case PathDirection.Left:
                              current = new Node(current.X - 1, current.Y);
                              break;
                          case PathDirection.Up:
                              current = new Node(current.X, current.Y - 1);
                              break;
                          case PathDirection.Right:
                              current = new Node(current.X + 1, current.Y);
                              break;
                          default:
                              current = new Node(current.X, current.Y + 1);
                              break;
                      }
  
                      stack[stackSize++] = current;
  
                      if (current.X == SideLength - 1 && current.Y == SideLength - 1)
                          break;
  
                      visited[current.X, current.Y] = true;
                  }
                  else
                  {
                      current = stack[--stackSize - 1];
                  }
              }
  
              m_Path = new Node[stackSize];
  
              for (int i = 0; i < stackSize; i++)
              {
                  m_Path[i] = stack[i];
              }
  
              if (m_User != null)
              {
                  m_User.CloseGump(typeof(GameGump));
                  m_User = null;
              }
          }
  
          public override void OnDoubleClick(Mobile from)
          {
              if (!from.InRange(this, 3))
              {
                  from.SendLocalizedMessage(500446); // That is too far away.
                  return;
              }
  
              if (m_User != null)
              {
                  if (m_User == from)
                      return;
  
                  if (m_User.Deleted || m_User.Map != Map || !m_User.InRange(this, 3) ||
                      m_User.NetState == null || DateTime.UtcNow - m_LastUse >= m_UseTimeout)
                  {
                      m_User.CloseGump(typeof(GameGump));
                  }
                  else
                  {
                      from.SendMessage("Someone is currently using the control panel.");
                      return;
                  }
              }
  
              m_User = from;
              m_LastUse = DateTime.UtcNow;
  
              from.SendGump(new GameGump(this, from, 0, false));
          }
  
          public void DoDamage(Mobile to)
          {
              to.Send(new UnicodeMessage(Serial, ItemID, MessageType.Regular, 0x3B2, 3, "", "", "The generator shoots an arc of electricity at you!"));
              to.BoltEffect(0);
              to.LocalOverheadMessage(MessageType.Regular, 0xC9, true, "* Your body convulses from electric shock *");
              to.NonlocalOverheadMessage(MessageType.Regular, 0xC9, true, string.Format("* {0} spasms from electric shock *", to.Name));
  
              AOS.Damage(to, to, 60, 0, 0, 0, 0, 100);
  
              if (!to.Alive)
                  return;
  
              if (m_DamageTable[to] == null)
              {
                  to.Frozen = true;
  
  
gt:                 DamageTimer timer = new DamageTimer(this, to);