context: /***************************************************************************
   *                                  Item.cs
   *                            -------------------
   *   begin                : May 1, 2002
   *   copyright            : (C) The RunUO Software Team
   *   email                : info@runuo.com
   *
   *   $Id$
   *
   ***************************************************************************/
  
  /***************************************************************************
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   ***************************************************************************/
  
  using System;
  using System.IO;
  using System.Collections;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading.Tasks;
  using Server.Network;
  using Server.Items;
  using Server.ContextMenus;
  
  namespace Server
  {
  	/// <summary>
  	/// Enumeration of item layer values.
  	/// </summary>
  	public enum Layer : byte
  	{
  		/// <summary>
  		/// Invalid layer.
  		/// </summary>
  		Invalid		 = 0x00,
  		/// <summary>
  		/// First valid layer. Equivalent to <c>Layer.OneHanded</c>.
  		/// </summary>
  		FirstValid   = 0x01,
  		/// <summary>
  		/// One handed weapon.
  		/// </summary>
  		OneHanded	 = 0x01,
  		/// <summary>
  		/// Two handed weapon or shield.
  		/// </summary>
  		TwoHanded	 = 0x02,
  		/// <summary>
  		/// Shoes.
  		/// </summary>
  		Shoes		 = 0x03,
  		/// <summary>
  		/// Pants.
  		/// </summary>
  		Pants		 = 0x04,
  		/// <summary>
  		/// Shirts.
  		/// </summary>
  		Shirt		 = 0x05,
  		/// <summary>
  		/// Helmets, hats, and masks.
  		/// </summary>
  		Helm		 = 0x06,
  		/// <summary>
  		/// Gloves.
  		/// </summary>
  		Gloves		 = 0x07,
  		/// <summary>
  		/// Rings.
  		/// </summary>
  		Ring		 = 0x08,
  		/// <summary>
  		/// Talismans.
  		/// </summary>
  		Talisman	 = 0x09,
  		/// <summary>
  		/// Gorgets and necklaces.
  		/// </summary>
  		Neck		 = 0x0A,
  		/// <summary>
  		/// Hair.
  		/// </summary>
  		Hair		 = 0x0B,
  		/// <summary>
  		/// Half aprons.
  		/// </summary>
  		Waist		 = 0x0C,
  		/// <summary>
  		/// Torso, inner layer.
  		/// </summary>
  		InnerTorso	 = 0x0D,
  		/// <summary>
  		/// Bracelets.
  		/// </summary>
  		Bracelet	 = 0x0E,
  		/// <summary>
  		/// Unused.
  		/// </summary>
  		Unused_xF	 = 0x0F,
  		/// <summary>
  		/// Beards and mustaches.
  		/// </summary>
  		FacialHair	 = 0x10,
  		/// <summary>
  		/// Torso, outer layer.
  		/// </summary>
  		MiddleTorso	 = 0x11,
  		/// <summary>
  		/// Earings.
  		/// </summary>
  		Earrings	 = 0x12,
  		/// <summary>
  		/// Arms and sleeves.
  		/// </summary>
  		Arms		 = 0x13,
  		/// <summary>
  		/// Cloaks.
  		/// </summary>
  		Cloak		 = 0x14,
  		/// <summary>
  		/// Backpacks.
  		/// </summary>
  		Backpack	 = 0x15,
  		/// <summary>
  		/// Torso, outer layer.
  		/// </summary>
  		OuterTorso	 = 0x16,
  		/// <summary>
  		/// Leggings, outer layer.
  		/// </summary>
  		OuterLegs	 = 0x17,
  		/// <summary>
  		/// Leggings, inner layer.
  		/// </summary>
  		InnerLegs	 = 0x18,
  		/// <summary>
  		/// Last valid non-internal layer. Equivalent to <c>Layer.InnerLegs</c>.
  		/// </summary>
  		LastUserValid= 0x18,
  		/// <summary>
  		/// Mount item layer.
  		/// </summary>
  		Mount		 = 0x19,
  		/// <summary>
  		/// Vendor 'buy pack' layer.
  		/// </summary>
  		ShopBuy		 = 0x1A,
  		/// <summary>
  		/// Vendor 'resale pack' layer.
  		/// </summary>
  		ShopResale	 = 0x1B,
  		/// <summary>
  		/// Vendor 'sell pack' layer.
  		/// </summary>
  		ShopSell	 = 0x1C,
  		/// <summary>
  		/// Bank box layer.
  		/// </summary>
  		Bank		 = 0x1D,
  		/// <summary>
  		/// Last valid layer. Equivalent to <c>Layer.Bank</c>.
  		/// </summary>
  		LastValid    = 0x1D
  	}
  
  	/// <summary>
  	/// Internal flags used to signal how the item should be updated and resent to nearby clients.
  	/// </summary>
  	[Flags]
  	public enum ItemDelta
  	{
  		/// <summary>
  		/// Nothing.
  		/// </summary>
  		None		= 0x00000000,
  		/// <summary>
  		/// Resend the item.
  		/// </summary>
  		Update		= 0x00000001,
  		/// <summary>
  		/// Resend the item only if it is equiped.
  		/// </summary>
  		EquipOnly	= 0x00000002,
  		/// <summary>
  		/// Resend the item's properties.
  		/// </summary>
  		Properties	= 0x00000004
  	}
  
  	/// <summary>
  	/// Enumeration containing possible ways to handle item ownership on death.
  	/// </summary>
  	public enum DeathMoveResult
  	{
  		/// <summary>
  		/// The item should be placed onto the corpse.
  		/// </summary>
  		MoveToCorpse,
  		/// <summary>
  		/// The item should remain equiped.
  		/// </summary>
  		RemainEquiped,
  		/// <summary>
  		/// The item should be placed into the owners backpack.
  		/// </summary>
  		MoveToBackpack
  	}
  
  	/// <summary>
  	/// Enumeration containing all possible light types. These are only applicable to light source items, like lanterns, candles, braziers, etc.
  	/// </summary>
  	public enum LightType
  	{
  		/// <summary>
  		/// Window shape, arched, ray shining east.
  		/// </summary>
  		ArchedWindowEast,
  		/// <summary>
  		/// Medium circular shape.
  		/// </summary>
  		Circle225,
  		/// <summary>
  		/// Small circular shape.
  		/// </summary>
  		Circle150,
  		/// <summary>
  		/// Door shape, shining south.
  		/// </summary>
  		DoorSouth,
  		/// <summary>
  		/// Door shape, shining east.
  		/// </summary>
  		DoorEast,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), north wall.
  		/// </summary>
  		NorthBig,
  		/// <summary>
  		/// Large pie shape (90 degrees), north-east corner.
  		/// </summary>
  		NorthEastBig,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), east wall.
  		/// </summary>
  		EastBig,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), west wall.
  		/// </summary>
  		WestBig,
  		/// <summary>
  		/// Large pie shape (90 degrees), south-west corner.
  		/// </summary>
  		SouthWestBig,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), south wall.
  		/// </summary>
  		SouthBig,
  		/// <summary>
  		/// Medium semicircular shape (180 degrees), north wall.
  		/// </summary>
  		NorthSmall,
  		/// <summary>
  		/// Medium pie shape (90 degrees), north-east corner.
  		/// </summary>
  		NorthEastSmall,
  		/// <summary>
  		/// Medium semicircular shape (180 degrees), east wall.
  		/// </summary>
  		EastSmall,
  		/// <summary>
  		/// Medium semicircular shape (180 degrees), west wall.
  		/// </summary>
  		WestSmall,
  		/// <summary>
  		/// Medium semicircular shape (180 degrees), south wall.
  		/// </summary>
  		SouthSmall,
  		/// <summary>
  		/// Shaped like a wall decoration, north wall.
  		/// </summary>
  		DecorationNorth,
  		/// <summary>
  		/// Shaped like a wall decoration, north-east corner.
  		/// </summary>
  		DecorationNorthEast,
  		/// <summary>
  		/// Small semicircular shape (180 degrees), east wall.
  		/// </summary>
  		EastTiny,
  		/// <summary>
  		/// Shaped like a wall decoration, west wall.
  		/// </summary>
  		DecorationWest,
  		/// <summary>
  		/// Shaped like a wall decoration, south-west corner.
  		/// </summary>
  		DecorationSouthWest,
  		/// <summary>
  		/// Small semicircular shape (180 degrees), south wall.
  		/// </summary>
  		SouthTiny,
  		/// <summary>
  		/// Window shape, rectangular, no ray, shining south.
  		/// </summary>
  		RectWindowSouthNoRay,
  		/// <summary>
  		/// Window shape, rectangular, no ray, shining east.
  		/// </summary>
  		RectWindowEastNoRay,
  		/// <summary>
  		/// Window shape, rectangular, ray shining south.
  		/// </summary>
  		RectWindowSouth,
  		/// <summary>
  		/// Window shape, rectangular, ray shining east.
  		/// </summary>
  		RectWindowEast,
  		/// <summary>
  		/// Window shape, arched, no ray, shining south.
  		/// </summary>
  		ArchedWindowSouthNoRay,
  		/// <summary>
  		/// Window shape, arched, no ray, shining east.
  		/// </summary>
  		ArchedWindowEastNoRay,
  		/// <summary>
  		/// Window shape, arched, ray shining south.
  		/// </summary>
  		ArchedWindowSouth,
  		/// <summary>
  		/// Large circular shape.
  		/// </summary>
  		Circle300,
  		/// <summary>
  		/// Large pie shape (90 degrees), north-west corner.
  		/// </summary>
  		NorthWestBig,
  		/// <summary>
  		/// Negative light. Medium pie shape (90 degrees), south-east corner.
  		/// </summary>
  		DarkSouthEast,
  		/// <summary>
  		/// Negative light. Medium semicircular shape (180 degrees), south wall.
  		/// </summary>
  		DarkSouth,
  		/// <summary>
  		/// Negative light. Medium pie shape (90 degrees), north-west corner.
  		/// </summary>
  		DarkNorthWest,
  		/// <summary>
  		/// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to <c>LightType.SouthEast</c>.
  		/// </summary>
  		DarkSouthEast2,
  		/// <summary>
  		/// Negative light. Medium circular shape (180 degrees), east wall.
  		/// </summary>
  		DarkEast,
  		/// <summary>
  		/// Negative light. Large circular shape.
  		/// </summary>
  		DarkCircle300,
  		/// <summary>
  		/// Opened door shape, shining south.
  		/// </summary>
  		DoorOpenSouth,
  		/// <summary>
  		/// Opened door shape, shining east.
  		/// </summary>
  		DoorOpenEast,
  		/// <summary>
  		/// Window shape, square, ray shining east.
  		/// </summary>
  		SquareWindowEast,
  		/// <summary>
  		/// Window shape, square, no ray, shining east.
  		/// </summary>
  		SquareWindowEastNoRay,
  		/// <summary>
  		/// Window shape, square, ray shining south.
  		/// </summary>
  		SquareWindowSouth,
  		/// <summary>
  		/// Window shape, square, no ray, shining south.
  		/// </summary>
  		SquareWindowSouthNoRay,
  		/// <summary>
  		/// Empty.
  		/// </summary>
  		Empty,
  		/// <summary>
  		/// Window shape, skinny, no ray, shining south.
  		/// </summary>
  		SkinnyWindowSouthNoRay,
  		/// <summary>
  		/// Window shape, skinny, ray shining east.
  		/// </summary>
  		SkinnyWindowEast,
  		/// <summary>
  		/// Window shape, skinny, no ray, shining east.
  		/// </summary>
  		SkinnyWindowEastNoRay,
  		/// <summary>
  		/// Shaped like a hole, shining south.
  		/// </summary>
  		HoleSouth,
  		/// <summary>
  		/// Shaped like a hole, shining south.
  		/// </summary>
  		HoleEast,
  		/// <summary>
  		/// Large circular shape with a moongate graphic embeded.
  		/// </summary>
  		Moongate,
  		/// <summary>
  		/// Unknown usage. Many rows of slightly angled lines.
  		/// </summary>
  		Strips,
  		/// <summary>
  		/// Shaped like a small hole, shining south.
  		/// </summary>
  		SmallHoleSouth,
  		/// <summary>
  		/// Shaped like a small hole, shining east.
  		/// </summary>
  		SmallHoleEast,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), north wall. Identical graphic as <c>LightType.NorthBig</c>, but slightly different positioning.
  		/// </summary>
  		NorthBig2,
  		/// <summary>
  		/// Large semicircular shape (180 degrees), west wall. Identical graphic as <c>LightType.WestBig</c>, but slightly different positioning.
  		/// </summary>
  		WestBig2,
  		/// <summary>
  		/// Large pie shape (90 degrees), north-west corner. Equivalent to <c>LightType.NorthWestBig</c>.
  		/// </summary>
  		NorthWestBig2
  	}
  
  	/// <summary>
  	/// Enumeration of an item's loot and steal state.
  	/// </summary>
  	public enum LootType : byte
  	{
  		/// <summary>
  		/// Stealable. Lootable.
  		/// </summary>
  		Regular = 0,
  		/// <summary>
  		/// Unstealable. Unlootable, unless owned by a murderer.
  		/// </summary>
  		Newbied = 1,
  		/// <summary>
  		/// Unstealable. Unlootable, always.
  		/// </summary>
  		Blessed = 2,
  		/// <summary>
  		/// Stealable. Lootable, always.
  		/// </summary>
  		Cursed  = 3
  	}
  
  	public class BounceInfo
  	{
  		public Map m_Map;
  		public Point3D m_Location, m_WorldLoc;
  		public IEntity m_Parent;
  
  		public BounceInfo( Item item )
  		{
  			m_Map = item.Map;
  			m_Location = item.Location;
  			m_WorldLoc = item.GetWorldLocation();
  			m_Parent = item.Parent;
  		}
  
  		private BounceInfo( Map map, Point3D loc, Point3D worldLoc, IEntity parent )
  		{
  			m_Map = map;
  			m_Location = loc;
  			m_WorldLoc = worldLoc;
  			m_Parent = parent;
  		}
  
  		public static BounceInfo Deserialize( GenericReader reader )
  		{
  			if ( reader.ReadBool() )
  			{
  				Map map = reader.ReadMap();
  				Point3D loc = reader.ReadPoint3D();
  				Point3D worldLoc = reader.ReadPoint3D();
  
  				IEntity parent;
  
  				Serial serial = reader.ReadInt();
  
  				if ( serial.IsItem )
  					parent = World.FindItem( serial );
  				else if ( serial.IsMobile )
  					parent = World.FindMobile( serial );
  				else
  					parent = null;
  
  				return new BounceInfo( map, loc, worldLoc, parent );
  			}
  			else
  			{
  				return null;
  			}
  		}
  
  		public static void Serialize( BounceInfo info, GenericWriter writer )
  		{
  			if ( info == null )
  			{
  				writer.Write( false );
  			}
  			else
  			{
  				writer.Write( true );
  
  				writer.Write( info.m_Map );
  				writer.Write( info.m_Location );
  				writer.Write( info.m_WorldLoc );
  
  				if ( info.m_Parent is Mobile )
  					writer.Write( (Mobile) info.m_Parent );
  				else if ( info.m_Parent is Item )
  					writer.Write( (Item) info.m_Parent );
  				else
  					writer.Write( (Serial) 0 );
  			}
  		}
  	}
  
  	public enum TotalType
  	{
  		Gold,
  		Items,
  		Weight,
  	}
  
  	[Flags]
  	public enum ExpandFlag
  	{
  		None		= 0x000,
  
  		Name		= 0x001,
  		Items		= 0x002,
  		Bounce		= 0x004,
  		Holder		= 0x008,
  		Blessed		= 0x010,
  		TempFlag	= 0x020,
  		SaveFlag	= 0x040,
  		Weight		= 0x080,
  		Spawner		= 0x100
  	}
  
  	public class Item : IEntity, IHued, IComparable<Item>, ISerializable, ISpawnable
  	{
  		public static readonly List<Item> EmptyItems = new List<Item>();
  
  		public int CompareTo( IEntity other )
  		{
  			if ( other == null )
  				return -1;
  
  			return m_Serial.CompareTo( other.Serial );
  		}
  
  		public int CompareTo( Item other )
  		{
  			return this.CompareTo( (IEntity) other );
  		}
  
  		public int CompareTo( object other )
  		{
  			if ( other == null || other is IEntity )
  				return this.CompareTo( (IEntity) other );
  
  			throw new ArgumentException();
  		}
  
  		#region Standard fields
  		private Serial m_Serial;
  		private Point3D m_Location;
  		private int m_ItemID;
  		private int m_Hue;
  		private int m_Amount;
  		private Layer m_Layer;
  		private IEntity m_Parent; // Mobile, Item, or null=World
  		private Map m_Map;
  		private LootType m_LootType;
  		private DateTime m_LastMovedTime;
  		private Direction m_Direction;
  		#endregion
  
  		private ItemDelta m_DeltaFlags;
  		private ImplFlag m_Flags;
  
  		#region Packet caches
  		private Packet m_WorldPacket;
  		private Packet m_WorldPacketSA;
  		private Packet m_WorldPacketHS;
  		private Packet m_RemovePacket;
  
  		private Packet m_OPLPacket;
  		private ObjectPropertyList m_PropertyList;
  		#endregion
  
  		public int TempFlags
  		{
  			get
  			{
  				CompactInfo info = LookupCompactInfo();
  
  				if ( info != null )
  					return info.m_TempFlags;
  
  				return 0;
  			}
  			set
  			{
  				CompactInfo info = AcquireCompactInfo();
  
  				info.m_TempFlags = value;
  
  				if ( info.m_TempFlags == 0 )
  					VerifyCompactInfo();
  			}
  		}
  
  		public int SavedFlags
  		{
  			get
  			{
  				CompactInfo info = LookupCompactInfo();
  
  				if ( info != null )
  					return info.m_SavedFlags;
  
  				return 0;
  			}
  			set
  			{
  				CompactInfo info = AcquireCompactInfo();
  
  				info.m_SavedFlags = value;
  
  				if ( info.m_SavedFlags == 0 )
  					VerifyCompactInfo();
  			}
  		}
  
  		/// <summary>
  		/// The <see cref="Mobile" /> who is currently <see cref="Mobile.Holding">holding</see> this item.
  		/// </summary>
  		public Mobile HeldBy
  		{
  			get
  			{
  				CompactInfo info = LookupCompactInfo();
  
  				if ( info != null )
  					return info.m_HeldBy;
  
  				return null;
  			}
  			set
  			{
  				CompactInfo info = AcquireCompactInfo();
  
  				info.m_HeldBy = value;
  
  				if ( info.m_HeldBy == null )
  					VerifyCompactInfo();
  			}
  		}
  
  		[Flags]
  		private enum ImplFlag : byte
  		{
  			None			= 0x00,
  			Visible			= 0x01,
  			Movable			= 0x02,
  			Deleted			= 0x04,
  			Stackable		= 0x08,
  			InQueue			= 0x10,
  			Insured			= 0x20,
  			PayedInsurance	= 0x40,
  			QuestItem		= 0x80
  		}
  
  		private class CompactInfo
  		{
  			public string m_Name;
  
  			public List<Item> m_Items;
  			public BounceInfo m_Bounce;
  
  			public Mobile m_HeldBy;
  			public Mobile m_BlessedFor;
  
  			public ISpawner m_Spawner;
  
  			public int m_TempFlags;
  			public int m_SavedFlags;
  
  			public double m_Weight = -1;
  		}
  
  		private CompactInfo m_CompactInfo;
  
  		public ExpandFlag GetExpandFlags()
  		{
  			CompactInfo info = LookupCompactInfo();
  
  			ExpandFlag flags = 0;
  
  			if ( info != null )
  			{
  				if ( info.m_BlessedFor != null )
  					flags |= ExpandFlag.Blessed;
  
  				if ( info.m_Bounce != null )
  					flags |= ExpandFlag.Bounce;
  
  				if ( info.m_HeldBy != null )
  					flags |= ExpandFlag.Holder;
  
  				if ( info.m_Items != null )
  					flags |= ExpandFlag.Items;
  
  				if ( info.m_Name != null )
  					flags |= ExpandFlag.Name;
  
  				if (info.m_Spawner != null)
  					flags |= ExpandFlag.Spawner;
  
  				if ( info.m_SavedFlags != 0 )
  					flags |= ExpandFlag.SaveFlag;
  
  				if ( info.m_TempFlags != 0 )
  					flags |= ExpandFlag.TempFlag;
  
  				if ( info.m_Weight != -1 )
  					flags |= ExpandFlag.Weight;
  			}
  
  			return flags;
  		}
  
  		private CompactInfo LookupCompactInfo()
  		{
  			return m_CompactInfo;
  		}
  
  		private CompactInfo AcquireCompactInfo()
  		{
  			if ( m_CompactInfo == null )
  				m_CompactInfo = new CompactInfo();
  
  			return m_CompactInfo;
  		}
  
  		private void ReleaseCompactInfo()
  		{
  			m_CompactInfo = null;
  		}
  
  		private void VerifyCompactInfo()
  		{
  			CompactInfo info = m_CompactInfo;
  
  			if ( info == null )
  				return;
  
  			bool isValid = ( info.m_Name != null )
  							|| ( info.m_Items != null )
  							|| ( info.m_Bounce != null )
  							|| ( info.m_HeldBy != null )
  							|| ( info.m_BlessedFor != null )
  							|| ( info.m_Spawner != null )
  							|| ( info.m_TempFlags != 0 )
  							|| ( info.m_SavedFlags != 0 )
  							|| ( info.m_Weight != -1 );
  
  			if ( !isValid )
  				ReleaseCompactInfo();
  		}
  
  		public List<Item> LookupItems()
  		{
  			if ( this is Container )
  				return ( this as Container ).m_Items;
  
  			CompactInfo info = LookupCompactInfo();
  
  			if ( info != null )
  				return info.m_Items;
  
  			return null;
  		}
  
  		public List<Item> AcquireItems()
  		{
  			if ( this is Container )
  			{
  				Container cont = this as Container;
  
  				if ( cont.m_Items == null )
  					cont.m_Items = new List<Item>();
  
  				return cont.m_Items;
  			}
  
  			CompactInfo info = AcquireCompactInfo();
  
  			if ( info.m_Items == null )
  				info.m_Items = new List<Item>();
  
  			return info.m_Items;
  		}
  
  		private void SetFlag( ImplFlag flag, bool value )
  		{
  			if ( value )
  				m_Flags |= flag;
  			else
  				m_Flags &= ~flag;
  		}
  
  		private bool GetFlag( ImplFlag flag )
  		{
  			return ( (m_Flags & flag) != 0 );
  		}
  
  		public BounceInfo GetBounce()
  		{
  			CompactInfo info = LookupCompactInfo();
  
  			if ( info != null )
  				return info.m_Bounce;
  
  			return null;
  		}
  
  		public void RecordBounce()
  		{
  			CompactInfo info = AcquireCompactInfo();
  
  			info.m_Bounce = new BounceInfo( this );
  		}
  
  		public void ClearBounce()
  		{
  			CompactInfo info = LookupCompactInfo();
  
  			if ( info != null )
  			{
  				BounceInfo bounce = info.m_Bounce;
  
  				if ( bounce != null )
  				{
  					info.m_Bounce = null;
  
  					if ( bounce.m_Parent is Item )
  					{
  						Item parent = (Item) bounce.m_Parent;
  
  						if ( !parent.Deleted )
  							parent.OnItemBounceCleared( this );
  					}
  					else if ( bounce.m_Parent is Mobile )
  					{
  						Mobile parent = (Mobile) bounce.m_Parent;
  
  						if ( !parent.Deleted )
  							parent.OnItemBounceCleared( this );
  					}
  
  					VerifyCompactInfo();
  				}
  			}
  		}
  
  		/// <summary>
  		/// Overridable. Virtual event invoked when a client, <paramref name="from" />, invokes a 'help request' for the Item. Seemingly no longer functional in newer clients.
  		/// </summary>
  		public virtual void OnHelpRequest( Mobile from )
  		{
  		}
  
  		/// <summary>
  		/// Overridable. Method checked to see if the item can be traded.
  		/// </summary>
  		/// <returns>True if the trade is allowed, false if not.</returns>
  		public virtual bool AllowSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted )
  		{
  			return true;
  		}
  
  		/// <summary>
  		/// Overridable. Virtual event invoked when a trade has completed, either successfully or not.
  		/// </summary>
  		public virtual void OnSecureTrade( Mobile from, Mobile to, Mobile newOwner, bool accepted )
  		{
  		}
  
  		/// <summary>
  		/// Overridable. Method checked to see if the elemental resistances of this Item conflict with another Item on the <see cref="Mobile" />.
  		/// </summary>
  		/// <returns>
  		/// <list type="table">
  		/// <item>
  		/// <term>True</term>
  		/// <description>There is a confliction. The elemental resistance bonuses of this Item should not be applied to the <see cref="Mobile" /></description>
  		/// </item>
  		/// <item>
  		/// <term>False</term>
  		/// <description>There is no confliction. The bonuses should be applied.</description>
  		/// </item>
  		/// </list>
  		/// </returns>
  		public virtual bool CheckPropertyConfliction( Mobile m )
  		{
  			return false;
  		}
  
  		/// <summary>
  		/// Overridable. Sends the <see cref="PropertyList">object property list</see> to <paramref name="from" />.
  		/// </summary>
  		public virtual void SendPropertiesTo( Mobile from )
  		{
  			from.Send( PropertyList );
  		}
  
  		/// <summary>
  		/// Overridable. Adds the name of this item to the given <see cref="ObjectPropertyList" />. This method should be overriden if the item requires a complex naming format.
  		/// </summary>
  		public virtual void AddNameProperty( ObjectPropertyList list )
  		{
  			string name = this.Name;
  
  			if ( name == null )
  			{
  				if ( m_Amount <= 1 )
  					list.Add( LabelNumber );
  				else
  					list.Add( 1050039, "{0}\t#{1}", m_Amount, LabelNumber ); // ~1_NUMBER~ ~2_ITEMNAME~
  			}
  			else
  			{
  				if ( m_Amount <= 1 )
  					list.Add( name );
  				else
  					list.Add( 1050039, "{0}\t{1}", m_Amount, Name ); // ~1_NUMBER~ ~2_ITEMNAME~
  			}
  		}
  
  		/// <summary>
  		/// Overridable. Adds the loot type of this item to the given <see cref="ObjectPropertyList" />. By default, this will be either 'blessed', 'cursed', or 'insured'.
  		/// </summary>
  		public virtual void AddLootTypeProperty( ObjectPropertyList list )
  		{
  			if ( m_LootType == LootType.Blessed )
  				list.Add( 1038021 ); // blessed
  			else if ( m_LootType == LootType.Cursed )
  				list.Add( 1049643 ); // cursed
  			else if ( Insured )
  				list.Add( 1061682 ); // <b>insured</b>
  		}
  
  		/// <summary>
  		/// Overridable. Adds any elemental resistances of this item to the given <see cref="ObjectPropertyList" />.
  		/// </summary>
  		public virtual void AddResistanceProperties( ObjectPropertyList list )
  		{
  			int v = PhysicalResistance;
  
  			if ( v != 0 )
  				list.Add( 1060448, v.ToString() ); // physical resist ~1_val~%
  
  			v = FireResistance;
  
  			if ( v != 0 )
  				list.Add( 1060447, v.ToString() ); // fire resist ~1_val~%
  
  			v = ColdResistance;
  
  			if ( v != 0 )
  				list.Add( 1060445, v.ToString() ); // cold resist ~1_val~%
  
  			v = PoisonResistance;
  
  			if ( v != 0 )
  				list.Add( 1060449, v.ToString() ); // poison resist ~1_val~%
  
  			v = EnergyResistance;
  
  			if ( v != 0 )
  				list.Add( 1060446, v.ToString() ); // energy resist ~1_val~%
  		}
  
  		/// <summary>
  		/// Overridable. Determines whether the item will show <see cref="AddWeightProperty" />. 
  		/// </summary>
  		public virtual bool DisplayWeight 
  		{
  			get
  			{
  				if ( !Core.ML )
  					return false;
  
  				if ( !Movable && !( IsLockedDown || IsSecure ) && ItemData.Weight == 255 )
  					return false;
  
  				return true;
  			} 
  		}
  
  		/// <summary>
  		/// Overridable. Displays cliloc 1072788-1072789. 
  		/// </summary>
  		public virtual void AddWeightProperty( ObjectPropertyList list )
  		{
  			int weight = this.PileWeight + this.TotalWeight;
  
  			if ( weight == 1 ) {
  				list.Add( 1072788, weight.ToString() ); //Weight: ~1_WEIGHT~ stone
  			} else {
  				list.Add( 1072789, weight.ToString() ); //Weight: ~1_WEIGHT~ stones
  			}
  		}
  
  		/// <summary>
  		/// Overridable. Adds header properties. By default, this invokes <see cref="AddNameProperty" />, <see cref="AddBlessedForProperty" /> (if applicable), and <see cref="AddLootTypeProperty" /> (if <see cref="DisplayLootType" />).
  		/// </summary>
  		public virtual void AddNameProperties( ObjectPropertyList list )
  		{
  			AddNameProperty( list );
  
  			if ( IsSecure )
  				AddSecureProperty( list );
  			else if ( IsLockedDown )
  				AddLockedDownProperty( list );
  
  			Mobile blessedFor = this.BlessedFor;
  
  			if ( blessedFor != null && !blessedFor.Deleted )
  				AddBlessedForProperty( list, blessedFor );
  
  			if ( DisplayLootType )
  				AddLootTypeProperty( list );
  
  			if ( DisplayWeight )
  				AddWeightProperty( list );
  
  			if( QuestItem )
  				AddQuestItemProperty( list );
  
  
  			AppendChildNameProperties( list );
  		}
  
  		/// <summary>
  		/// Overridable. Adds the "Quest Item" property to the given <see cref="ObjectPropertyList" />.
  		/// </summary>
  		public virtual void AddQuestItemProperty( ObjectPropertyList list )
  		{
  			list.Add( 1072351 ); // Quest Item
  		}
  
  		/// <summary>
  		/// Overridable. Adds the "Locked Down & Secure" property to the given <see cref="ObjectPropertyList" />.
  		/// </summary>
  		public virtual void AddSecureProperty( ObjectPropertyList list )
  		{
  			list.Add( 501644 ); // locked down & secure
  		}
  
  		/// <summary>
  		/// Overridable. Adds the "Locked Down" property to the given <see cref="ObjectPropertyList" />.
  		/// </summary>
  		public virtual void AddLockedDownProperty( ObjectPropertyList list )
  		{
  			list.Add( 501643 ); // locked down
  		}
  
  		/// <summary>
  		/// Overridable. Adds the "Blessed for ~1_NAME~" property to the given <see cref="ObjectPropertyList" />.
  		/// </summary>
  		public virtual void AddBlessedForProperty( ObjectPropertyList list, Mobile m )
  		{
  			list.Add( 1062203, "{0}", m.Name ); // Blessed for ~1_NAME~
  		}
  
  		/// <summary>
  		/// Overridable. Fills an <see cref="ObjectPropertyList" /> with everything applicable. By default, this invokes <see cref="AddNameProperties" />, then <see cref="Item.GetChildProperties">Item.GetChildProperties</see> or <see cref="Mobile.GetChildProperties">Mobile.GetChildProperties</see>. This method should be overriden to add any custom properties.
  		/// </summary>
  		public virtual void GetProperties( ObjectPropertyList list )
  		{
  			AddNameProperties( list );
  		}
  
  		/// <summary>
  		/// Overridable. Event invoked when a child (<paramref name="item" />) is building it's <see cref="ObjectPropertyList" />. Recursively calls <see cref="Item.GetChildProperties">Item.GetChildProperties</see> or <see cref="Mobile.GetChildProperties">Mobile.GetChildProperties</see>.
  		/// </summary>
  		public virtual void GetChildProperties( ObjectPropertyList list, Item item )
  		{
  			if ( m_Parent is Item )
  				((Item)m_Parent).GetChildProperties( list, item );
  			else if ( m_Parent is Mobile )
  				((Mobile)m_Parent).GetChildProperties( list, item );
  		}
  
  		/// <summary>
  		/// Overridable. Event invoked when a child (<paramref name="item" />) is building it's Name <see cref="ObjectPropertyList" />. Recursively calls <see cref="Item.GetChildProperties">Item.GetChildNameProperties</see> or <see cref="Mobile.GetChildProperties">Mobile.GetChildNameProperties</see>.
  		/// </summary>
  		public virtual void GetChildNameProperties( ObjectPropertyList list, Item item )
  		{
  			if ( m_Parent is Item )
  				((Item)m_Parent).GetChildNameProperties( list, item );
  			else if ( m_Parent is Mobile )
  				((Mobile)m_Parent).GetChildNameProperties( list, item );
  		}
  
  		public virtual bool IsChildVisibleTo( Mobile m, Item child )
  		{
  			return true;
  		}
  
  		public void Bounce( Mobile from )
  		{
  			if ( m_Parent is Item )
  				((Item)m_Parent).RemoveItem( this );
  			else if ( m_Parent is Mobile )
  				((Mobile)m_Parent).RemoveItem( this );
  
  			m_Parent = null;
  
  			BounceInfo bounce = this.GetBounce();
  
  			if ( bounce != null )
  			{
  				IEntity parent = bounce.m_Parent;
  
  				if (parent == null || parent.Deleted)
  				{
  					MoveToWorld(bounce.m_WorldLoc, bounce.m_Map);
  				}
  				else if ( parent is Item )
  				{
  					Item p = (Item)parent;
  					IEntity root = p.RootParent;
  					if ( p.IsAccessibleTo( from ) && ( !(root is Mobile) || ((Mobile)root).CheckNonlocalDrop( from, this, p ) ) )
  					{
  						Location = bounce.m_Location;
  						p.AddItem( this );
  					}
  					else
  					{
  						MoveToWorld( from.Location, from.Map );
  					}
  				}
  				else if ( parent is Mobile )
  				{
  					if ( !((Mobile)parent).EquipItem( this ) )
  						MoveToWorld( bounce.m_WorldLoc, bounce.m_Map );
  				}
  				else
  				{
  					MoveToWorld( bounce.m_WorldLoc, bounce.m_Map );
  				}
  
  				ClearBounce();
  			}
  			else
  			{
  				MoveToWorld( from.Location, from.Map );
  			}
  		}
  
  		/// <summary>
  		/// Overridable. Method checked to see if this item may be equiped while casting a spell. By default, this returns false. It is overriden on spellbook and spell channeling weapons or shields.
  		/// </summary>
  		/// <returns>True if it may, false if not.</returns>
  		/// <example>
  		/// <code>
  		///	public override bool AllowEquipedCast( Mobile from )
  		///	{
  		///		if ( from.Int &gt;= 100 )
  		///			return true;
  		///		
  		///		return base.AllowEquipedCast( from );
  		/// }</code>
  		/// 
  		/// When placed in an Item script, the item may be cast when equiped if the <paramref name="from" /> has 100 or more intelligence. Otherwise, it will drop to their backpack.
  		/// </example>
  		public virtual bool AllowEquipedCast( Mobile from )
  		{
  			return false;
  		}
  
  		public virtual bool CheckConflictingLayer( Mobile m, Item item, Layer layer )
  		{
  			return ( m_Layer == layer );
  		}
  
  		public virtual bool CanEquip( Mobile m )
  		{
  			return ( m_Layer != Layer.Invalid && m.FindItemOnLayer( m_Layer ) == null );
  		}
  
  		public virtual void GetChildContextMenuEntries( Mobile from, List<ContextMenuEntry> list, Item item )
  		{
  			if ( m_Parent is Item )
  				((Item)m_Parent).GetChildContextMenuEntries( from, list, item );
  			else if ( m_Parent is Mobile )
  				((Mobile)m_Parent).GetChildContextMenuEntries( from, list, item );
  		}
  
  		public virtual void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
  		{
  			if ( m_Parent is Item )
  				((Item)m_Parent).GetChildContextMenuEntries( from, list, this );
  			else if ( m_Parent is Mobile )
  				((Mobile)m_Parent).GetChildContextMenuEntries( from, list, this );
  		}
  
  		public virtual bool VerifyMove( Mobile from )
  		{
  			return Movable;
  		}
  
  		public virtual DeathMoveResult OnParentDeath( Mobile parent )
  		{
  			if ( !Movable )
  				return DeathMoveResult.RemainEquiped;
  			else if ( parent.KeepsItemsOnDeath )
  				return DeathMoveResult.MoveToBackpack;
  			else if ( CheckBlessed( parent ) )
  				return DeathMoveResult.MoveToBackpack;
  			else if ( CheckNewbied() && parent.Kills < 5 )
  				return DeathMoveResult.MoveToBackpack;
  			else if( parent.Player && Nontransferable )
  				return DeathMoveResult.MoveToBackpack;
  			else
  				return DeathMoveResult.MoveToCorpse;
  		}
  
  		public virtual DeathMoveResult OnInventoryDeath( Mobile parent )
  		{
  			if ( !Movable )
  				return DeathMoveResult.MoveToBackpack;
  			else if ( parent.KeepsItemsOnDeath )
  				return DeathMoveResult.MoveToBackpack;
  			else if ( CheckBlessed( parent ) )
  				return DeathMoveResult.MoveToBackpack;
  			else if ( CheckNewbied() && parent.Kills < 5 )
  				return DeathMoveResult.MoveToBackpack;
  			else if( parent.Player && Nontransferable )
  				return DeathMoveResult.MoveToBackpack;
  			else
  				return DeathMoveResult.MoveToCorpse;
  		}
  
  		/// <summary>
  		/// Moves the Item to <paramref name="location" />. The Item does not change maps.
  		/// </summary>
  		public virtual void MoveToWorld( Point3D location )
  		{
  			MoveToWorld( location, m_Map );
  		}
  
  		public void LabelTo( Mobile to, int number )
  		{
  			to.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", "" ) );
  		}
  
  		public void LabelTo( Mobile to, int number, string args )
  		{
  			to.Send( new MessageLocalized( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", args ) );
  		}
  
  		public void LabelTo( Mobile to, string text )
  		{
  			to.Send( new UnicodeMessage( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, "ENU", "", text ) );
  		}
  
  		public void LabelTo( Mobile to, string format, params object[] args )
  		{
  			LabelTo( to, String.Format( format, args ) );
  		}
  
  		public void LabelToAffix( Mobile to, int number, AffixType type, string affix )
  		{
  			to.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, "" ) );
  		}
  
  		public void LabelToAffix( Mobile to, int number, AffixType type, string affix, string args )
  		{
  			to.Send( new MessageLocalizedAffix( m_Serial, m_ItemID, MessageType.Label, 0x3B2, 3, number, "", type, affix, args ) );
  		}
  
  		public virtual void LabelLootTypeTo( Mobile to )
  		{
  			if ( m_LootType == LootType.Blessed )
  
gt: 				LabelTo( to, 1041362 ); // (blessed)