context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using Server.Items;
  using Server.ContextMenus;
  using EDI = Server.Mobiles.EscortDestinationInfo;
  using Server.Engines.MLQuests;
  using Server.Engines.MLQuests.Definitions;
  using Server.Engines.MLQuests.Objectives;
  
  namespace Server.Mobiles
  {
      public class BaseEscortable : BaseCreature
  	{
  		public static readonly TimeSpan EscortDelay = TimeSpan.FromMinutes( 5.0 );
  		public static readonly TimeSpan AbandonDelay = MLQuestSystem.Enabled ? TimeSpan.FromMinutes( 1.0 ) : TimeSpan.FromMinutes( 2.0 );
  		public static readonly TimeSpan DeleteTime = MLQuestSystem.Enabled ? TimeSpan.FromSeconds( 100 ) : TimeSpan.FromSeconds( 30 );
  
  		public override bool StaticMLQuester { get { return false; } } // Suppress automatic quest registration on creation/deserialization
  
  		private MLQuest m_MLQuest;
  
  		protected override List<MLQuest> ConstructQuestList()
  		{
  			if ( m_MLQuest == null )
  			{
  				Region reg = Region;
  				Type[] list = reg.IsPartOf( "Haven Island" ) ? m_MLQuestTypesNH : m_MLQuestTypes;
  
  				int randomIdx = Utility.Random( list.Length );
  
  				for ( int i = 0; i < list.Length; ++i )
  				{
  					Type questType = list[randomIdx];
  
  					MLQuest quest = MLQuestSystem.FindQuest( questType );
  
  					if ( quest != null )
  					{
  						bool okay = true;
  
  						foreach ( BaseObjective obj in quest.Objectives )
  						{
  							if ( obj is EscortObjective && ( (EscortObjective)obj ).Destination.Contains( reg ) )
  							{
  								okay = false; // We're already there!
  								break;
  							}
  						}
  
  						if ( okay )
  						{
  							m_MLQuest = quest;
  							break;
  						}
  					}
  					else if ( MLQuestSystem.Debug )
  					{
  						Console.WriteLine( "Warning: Escortable cannot be assigned quest type '{0}', it is not registered", questType.Name );
  					}
  
  					randomIdx = ( randomIdx + 1 ) % list.Length;
  				}
  
  				if ( m_MLQuest == null )
  				{
  					if ( MLQuestSystem.Debug )
  						Console.WriteLine( "Warning: No suitable quest found for escort {0}", Serial );
  
  					return null;
  				}
  			}
  
  			List<MLQuest> result = new List<MLQuest>();
  			result.Add( m_MLQuest );
  
  			return result;
  		}
  
  		public override bool CanShout { get { return ( !Controlled && !IsBeingDeleted ); } }
  
  		public override void Shout( PlayerMobile pm )
  		{
  			/*
  			 * 1072301 - You there!  Care to hear how to earn some easy gold?
  			 * 1072302 - Adventurer!  I have an offer for you.
  			 * 1072303 - Wait!  I have an opportunity for you to make some gold!
  			 */
  			MLQuestSystem.Tell( this, pm, Utility.Random( 1072301, 3 ) );
  		}
  
  		private EDI m_Destination;
  		private string m_DestinationString;
  
  		private DateTime m_DeleteTime;
  		private Timer m_DeleteTimer;
  
  		private bool m_DeleteCorpse = false;
  
  		public bool IsBeingDeleted
  		{
  			get { return ( m_DeleteTimer != null ); }
  		}
  
  		public override bool Commandable { get { return false; } } // Our master cannot boss us around!
  		public override bool DeleteCorpseOnDeath { get { return m_DeleteCorpse; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public string Destination
  		{
  			get { return m_Destination == null ? null : m_Destination.Name; }
  			set { m_DestinationString = value; m_Destination = EDI.Find(value); }
  		}
  
  		// Classic list
  		// Used when: !MLQuestSystem.Enabled && !Core.ML
  		private static string[] m_TownNames = new string[]
  		{
  			"Cove", "Britain", "Jhelom",
  			"Minoc", "Ocllo", "Trinsic",
  			"Vesper", "Yew", "Skara Brae",
  			"Nujel'm", "Moonglow", "Magincia"
  		};
  
  		// ML list, pre-ML quest system
  		// Used when: !MLQuestSystem.Enabled && Core.ML
  		private static string[] m_MLTownNames = new string[]
  		{
  			"Cove", "Serpent's Hold", "Jhelom",
  			"Nujel'm"
  		};
  
  		// ML quest system general list
  		// Used when: MLQuestSystem.Enabled && !Region.IsPartOf( "Haven Island" )
  		private static Type[] m_MLQuestTypes =
  		{
  			typeof( EscortToYew ),
  			typeof( EscortToVesper ),
  			typeof( EscortToTrinsic ),
  			typeof( EscortToSkaraBrae ),
  			typeof( EscortToSerpentsHold ),
  			typeof( EscortToNujelm ),
  			typeof( EscortToMoonglow ),
  			typeof( EscortToMinoc ),
  			typeof( EscortToMagincia ),
  			typeof( EscortToJhelom ),
  			typeof( EscortToCove ),
  			typeof( EscortToBritain )
  			// Ocllo was removed in pub 56
  			//typeof( EscortToOcllo )
  		};
  
  		// ML quest system New Haven list
  		// Used when: MLQuestSystem.Enabled && Region.IsPartOf( "Haven Island" )
  		private static Type[] m_MLQuestTypesNH =
  		{
  			typeof( EscortToNHAlchemist ),
  			typeof( EscortToNHBard ),
  			typeof( EscortToNHWarrior ),
  			typeof( EscortToNHTailor ),
  			typeof( EscortToNHCarpenter ),
  			typeof( EscortToNHMapmaker ),
  			typeof( EscortToNHMage ),
  			typeof( EscortToNHInn ),
  			// Farm destination was removed
  			//typeof( EscortToNHFarm ),
  			typeof( EscortToNHDocks ),
  			typeof( EscortToNHBowyer ),
  			typeof( EscortToNHBank )
  		};
  
  		[Constructable]
  		public BaseEscortable()
  			: base(AIType.AI_Melee, FightMode.Aggressor, 22, 1, 0.2, 1.0)
  		{
  			InitBody();
  			InitOutfit();
  
  			Fame = 200;
  			Karma = 4000;
  		}
  
  		public virtual void InitBody()
  		{
  			SetStr(90, 100);
  			SetDex(90, 100);
  			SetInt(15, 25);
  
  			Hue = Utility.RandomSkinHue();
  
  			if (Female = Utility.RandomBool())
  			{
  				Body = 401;
  				Name = NameList.RandomName("female");
  			}
  			else
  			{
  				Body = 400;
  				Name = NameList.RandomName("male");
  			}
  		}
  
  		public virtual void InitOutfit()
  		{
  			AddItem(new FancyShirt(Utility.RandomNeutralHue()));
  			AddItem(new ShortPants(Utility.RandomNeutralHue()));
  			AddItem(new Boots(Utility.RandomNeutralHue()));
  
  			Utility.AssignRandomHair(this);
  
  			PackGold(200, 250);
  		}
  
  		public virtual bool SayDestinationTo(Mobile m)
  		{
  			EDI dest = GetDestination();
  
  			if (dest == null || !m.Alive)
  				return false;
  
  			Mobile escorter = GetEscorter();
  
  			if (escorter == null)
  			{
  				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)
  			{
  				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;
  		}
  
  		private static Hashtable m_EscortTable = new Hashtable();
  
  		public static Hashtable EscortTable
  		{
  			get { return m_EscortTable; }
  		}
  
  		public virtual bool AcceptEscorter(Mobile m)
  		{
  			EDI dest = GetDestination();
  
  			if (dest == null)
  				return false;
  
  			Mobile escorter = GetEscorter();
  
  			if (escorter != null || !m.Alive)
  				return false;
  
  			BaseEscortable escortable = (BaseEscortable)m_EscortTable[m];
  
  			if (escortable != null && !escortable.Deleted && escortable.GetEscorter() == m)
  			{
  				Say("I see you already have an escort.");
  				return false;
  			}
  			else if (m is PlayerMobile && (((PlayerMobile)m).LastEscortTime + EscortDelay) >= DateTime.UtcNow)
  			{
  				int minutes = (int)Math.Ceiling(((((PlayerMobile)m).LastEscortTime + EscortDelay) - DateTime.UtcNow).TotalMinutes);
  
  				Say("You must rest {0} minute{1} before we set out on this journey.", minutes, minutes == 1 ? "" : "s");
  				return false;
  			}
  			else if (SetControlMaster(m))
  			{
  				m_LastSeenEscorter = DateTime.UtcNow;
  
  				if (m is PlayerMobile)
  					((PlayerMobile)m).LastEscortTime = DateTime.UtcNow;
  
  				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;
  				StartFollow();
  				return true;
  			}
  
  			return false;
  		}
  
  		public override bool HandlesOnSpeech(Mobile from)
  		{
  			if ( MLQuestSystem.Enabled )
  				return false;
  
  			if (from.InRange(this.Location, 3))
  				return true;
  
  			return base.HandlesOnSpeech(from);
  		}
  
  		public override void OnSpeech(SpeechEventArgs e)
  		{
  			base.OnSpeech(e);
  
  			EDI dest = GetDestination();
  
  			if (dest != null && !e.Handled && e.Mobile.InRange(this.Location, 3))
  			{
  				if (e.HasKeyword(0x1D)) // *destination*
  					e.Handled = SayDestinationTo(e.Mobile);
  				else if (e.HasKeyword(0x1E)) // *i will take thee*
  
gt: 					e.Handled = AcceptEscorter(e.Mobile);