context: using System;
  using System.Collections.Generic;
  using Server.ContextMenus;
  using Server.Items;
  using Server.Mobiles;
  
  namespace Server.Mobiles
  {
      public class PersonalAttendant : BaseCreature
      {
          private static readonly Dictionary<Mobile, Mobile> m_Table = new Dictionary<Mobile, Mobile>();
          private bool m_BindedToPlayer;
          private InternalTimer m_Timer;
          public PersonalAttendant(string title)
              : base(AIType.AI_Vendor, FightMode.None, 22, 1, 0.15, 0.2)
          {
              this.Title = title;
              this.Blessed = true;
              this.ControlSlots = 0;
  
              this.InitBody();
              this.InitOutfit();
  
              this.m_Timer = new InternalTimer(this, TimeSpan.FromSeconds(2));
              this.m_Timer.Start();
          }
  
          public PersonalAttendant(Serial serial)
              : base(serial)
          {
          }
  
          public override bool ShowFameTitle
          {
              get
              {
                  return true;
              }
          }
          public override bool Commandable
          {
              get
              {
                  return false;
              }
          }
          public override bool NoHouseRestrictions
          {
              get
              {
                  return true;
              }
          }
          public override bool CanOpenDoors
          {
              get
              {
                  return true;
              }
          }
          [CommandProperty(AccessLevel.GameMaster)]
          public bool BindedToPlayer
          {
              get
              {
                  return this.m_BindedToPlayer;
              }
              set
              {
                  this.m_BindedToPlayer = value;
              }
          }
          public static bool CheckAttendant(Mobile owner)
          {
              if (owner != null)
                  return m_Table.ContainsKey(owner);
  
              return false;
          }
  
          public static void AddAttendant(Mobile owner, PersonalAttendant attendant)
          {
              if (owner != null)
                  m_Table[owner] = attendant;
          }
  
          public static void RemoveAttendant(Mobile owner)
          {
              if (owner != null)
                  m_Table.Remove(owner);
          }
  
          public virtual void InitBody()
          {
          }
  
          public virtual void InitOutfit()
          {
          }
  
          public virtual void CommandFollow(Mobile by)
          { 
              this.ControlOrder = OrderType.Follow;
              this.ControlTarget = by;
  
              if (this.m_Timer != null)
              {
                  this.m_Timer.Interval = TimeSpan.FromSeconds(2);
                  this.m_Timer.Priority = TimerPriority.OneSecond;
              }
          }
  
          public virtual void CommandStop(Mobile by)
          { 
              this.ControlOrder = OrderType.Stay;
              this.ControlTarget = null;
  
              if (this.m_Timer != null)
              {
                  this.m_Timer.Interval = TimeSpan.FromSeconds(5);
                  this.m_Timer.Priority = TimerPriority.FiveSeconds;
              }
          }
  
          public virtual void Dismiss(Mobile owner)
          {
              RemoveAttendant(owner);
  
              if (this.m_BindedToPlayer)
                  owner.AddToBackpack(new PersonalAttendantDeed(owner));
              else
                  owner.AddToBackpack(new PersonalAttendantDeed());
  			
              this.Delete();
          }
  
          public virtual bool InGreetingMode(Mobile owner)
          {
              return false;
          }
  
          public virtual bool IsOwner(Mobile m)
          {
              return (this.ControlMaster == null || this.ControlMaster == m);
          }
  
          public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
          {
              if (from.Alive && this.IsOwner(from))
              {
                  list.Add(new AttendantFollowEntry(this));
                  list.Add(new AttendantStopEntry(this));
                  list.Add(new AttendantDismissEntry(this));
              }
          }
  
          public override bool CanBeRenamedBy(Mobile from)
          {
              return (int)from.AccessLevel >= (int)AccessLevel.GameMaster;
          }
  
          public override void OnAfterDelete()
          {
              base.OnAfterDelete();
  
              if (this.m_Timer != null)
                  this.m_Timer.Stop();
          }
  
          public override void Serialize(GenericWriter writer)
          {
              base.Serialize(writer);
  
              writer.WriteEncodedInt(1); // version
  
              writer.Write(this.m_BindedToPlayer);
          }
  
          public override void Deserialize(GenericReader reader)
          {
              base.Deserialize(reader);
  
              int version = reader.ReadEncodedInt();
  
              switch ( version )
              {
                  case 1:
                      this.m_BindedToPlayer = reader.ReadBool();
                      break;
              }
  
              TimeSpan delay = TimeSpan.FromSeconds(2);
  
              if (this.ControlOrder == OrderType.Stay)
                  delay = TimeSpan.FromSeconds(5);
  
              this.m_Timer = new InternalTimer(this, delay);
              this.m_Timer.Start();
  
              AddAttendant(this.ControlMaster, this);
          }
  
          private class InternalTimer : Timer
          {
              private readonly PersonalAttendant m_Attendant;
              public InternalTimer(PersonalAttendant attendant, TimeSpan delay)
                  : base(delay, delay)
              {
                  this.m_Attendant = attendant;
  
                  this.Priority = TimerPriority.FiveSeconds;
              }
  
              protected override void OnTick()
              {
                  if (this.m_Attendant != null && !this.m_Attendant.Deleted)
                  {
                      Mobile m = this.m_Attendant.ControlMaster;
  
  
gt:                     if (m != null)