context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using Server.ContextMenus;
  using Server.Items;
  using EDI = Server.Mobiles.EscortDestinationInfo;
  
  namespace Server.Mobiles
  {
      public class BaseEscortable : BaseCreature
      {
          private static readonly string[] m_TownNames = new string[]
          {
              "Cove", "Britain", "Jhelom",
              "Minoc", "Ocllo", "Trinsic",
              "Vesper", "Yew", "Skara Brae", //Original List, will need to add it back for Pre-ML shards
              "Nujel'm", "Moonglow", "Magincia"
          };
          private static readonly string[] m_MLTownNames = new string[]
          {
              "Cove", "Serpent's Hold", "Jhelom", //ML List
              "Nujel'm"
          };
          private static readonly Hashtable m_EscortTable = new Hashtable();
          private static readonly TimeSpan m_EscortDelay = TimeSpan.FromMinutes(5.0);
          private EDI m_Destination;
          private string m_DestinationString;
          private DateTime m_DeleteTime;
          private Timer m_DeleteTimer;
          private DateTime m_LastSeenEscorter;
          [Constructable]
          public BaseEscortable()
              : base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0)
          {
              this.InitBody();
              this.InitOutfit();
          }
  
          public BaseEscortable(Serial serial)
              : base(serial)
          {
          }
  
          public static Hashtable EscortTable
          {
              get
              {
                  return m_EscortTable;
              }
          }
          public override bool Commandable
          {
              get
              {
                  return false;
              }
          }// Our master cannot boss us around!
          [CommandProperty(AccessLevel.GameMaster)]
          public string Destination
          {
              get
              {
                  return this.m_Destination == null ? null : this.m_Destination.Name;
              }
              set
              {
                  this.m_DestinationString = value;
                  this.m_Destination = EDI.Find(value);
              }
          }
          public virtual void InitBody()
          {
              this.SetStr(90, 100);
              this.SetDex(90, 100);
              this.SetInt(15, 25);
  
              this.Hue = Utility.RandomSkinHue();
  
              if (this.Female = Utility.RandomBool())
              {
                  this.Body = 401;
                  this.Name = NameList.RandomName("female");
              }
              else
              {
                  this.Body = 400;
                  this.Name = NameList.RandomName("male");
              }
          }
  
          public virtual void InitOutfit()
          {
              this.AddItem(new FancyShirt(Utility.RandomNeutralHue()));
              this.AddItem(new ShortPants(Utility.RandomNeutralHue()));
              this.AddItem(new Boots(Utility.RandomNeutralHue()));
  
              Utility.AssignRandomHair(this);
  
              this.PackGold(200, 250);
          }
  
          public virtual bool SayDestinationTo(Mobile m)
          {
              EDI dest = this.GetDestination();
  
              if (dest == null || !m.Alive)
                  return false;
  
              Mobile escorter = this.GetEscorter();
  
              if (escorter == null)
              {
                  this.Say("I am looking to go to {0}, will you take me?", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name);
                  return true;
              }
              else if (escorter == m)
              {
                  this.Say("Lead on! Payment will be made when we arrive in {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name);
                  return true;
              }
  
              return false;
          }
  
          public virtual bool AcceptEscorter(Mobile m)
          {
              EDI dest = this.GetDestination();
  
              if (dest == null)
                  return false;
  
              Mobile escorter = this.GetEscorter();
  
              if (escorter != null || !m.Alive)
                  return false;
  
              BaseEscortable escortable = (BaseEscortable)m_EscortTable[m];
  
              if (escortable != null && !escortable.Deleted && escortable.GetEscorter() == m)
              {
                  this.Say("I see you already have an escort.");
                  return false;
              }
              else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + m_EscortDelay) >= DateTime.UtcNow)
              {
                  int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + m_EscortDelay) - DateTime.UtcNow).TotalMinutes);
  
                  this.Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s");
                  return false;
              }
              else if (this.SetControlMaster(m))
              {
                  this.m_LastSeenEscorter = DateTime.UtcNow;
  
                  if (m is PlayerMobile)
                      ((PlayerMobile)m).LastEscortTime = DateTime.UtcNow;
  
                  this.Say("Lead on! Payment will be made when we arrive in {0}.", (dest.Name == "Ocllo" && m.Map == Map.Trammel) ? "Haven" : dest.Name);
                  m_EscortTable[m] = this;
                  this.StartFollow();
                  return true;
              }
  
              return false;
          }
  
          public override bool HandlesOnSpeech(Mobile from)
          {
              if (from.InRange(this.Location, 3))
                  return true;
  
              return base.HandlesOnSpeech(from);
          }
  
          public override void OnSpeech(SpeechEventArgs e)
          {
              base.OnSpeech(e);
  
              EDI dest = this.GetDestination();
  
              if (dest != null && !e.Handled && e.Mobile.InRange(this.Location, 3))
              {
                  if (e.HasKeyword(0x1D)) // *destination*
                      e.Handled = this.SayDestinationTo(e.Mobile);
                  else if (e.HasKeyword(0x1E)) // *i will take thee*
                      e.Handled = this.AcceptEscorter(e.Mobile);
              }
          }
  
          public override void OnAfterDelete()
          {
              if (this.m_DeleteTimer != null)
                  this.m_DeleteTimer.Stop();
  
              this.m_DeleteTimer = null;
  
              base.OnAfterDelete();
          }
  
          public override void OnThink()
          {
              base.OnThink();
              this.CheckAtDestination();
          }
  
          public virtual void StartFollow()
          {
              this.StartFollow(this.GetEscorter());
          }
  
          public virtual void StartFollow(Mobile escorter)
          {
  
gt:             if (escorter == null)