context: #region Header
  // **********
  // ServUO - BaseWeapon.cs
  // **********
  #endregion
  
  #region References
  using System;
  using System.Collections.Generic;
  
  using Server.ContextMenus;
  using Server.Engines.Craft;
  using Server.Engines.XmlSpawner2;
  using Server.Ethics;
  using Server.Factions;
  using Server.Mobiles;
  using Server.Network;
  using Server.SkillHandlers;
  using Server.Spells;
  using Server.Spells.Bushido;
  using Server.Spells.Chivalry;
  using Server.Spells.Necromancy;
  using Server.Spells.Ninjitsu;
  using Server.Spells.Sixth;
  using Server.Spells.Spellweaving;
  using System.Text;
  using System.Collections;
  using Server.Targeting;
  
  #endregion
  
  namespace Server.Items
  {
  	public interface ISlayer
  	{
  		SlayerName Slayer { get; set; }
  		SlayerName Slayer2 { get; set; }
  	}
  
  	public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability, ISetItem
  	{
  		private string m_EngravedText;
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public string EngravedText
  		{
  			get { return m_EngravedText; }
  			set
  			{
  				m_EngravedText = value;
  				InvalidateProperties();
  			}
  		}
  
  		#region Factions
  		private FactionItem m_FactionState;
  
  		public FactionItem FactionItemState
  		{
  			get { return m_FactionState; }
  			set
  			{
  				m_FactionState = value;
  
  				if (m_FactionState == null)
  				{
  					Hue = CraftResources.GetHue(Resource);
  				}
  
  				LootType = (m_FactionState == null ? LootType.Regular : LootType.Blessed);
  			}
  		}
  		#endregion
  
  		/* Weapon internals work differently now (Mar 13 2003)
          * 
          * The attributes defined below default to -1.
          * If the value is -1, the corresponding virtual 'Aos/Old' property is used.
          * If not, the attribute value itself is used. Here's the list:
          *  - MinDamage
          *  - MaxDamage
          *  - Speed
          *  - HitSound
          *  - MissSound
          *  - StrRequirement, DexRequirement, IntRequirement
          *  - WeaponType
          *  - WeaponAnimation
          *  - MaxRange
          */
  
  		#region Var declarations
  		// Instance values. These values are unique to each weapon.
  		private WeaponDamageLevel m_DamageLevel;
  		private WeaponAccuracyLevel m_AccuracyLevel;
  		private WeaponDurabilityLevel m_DurabilityLevel;
  		private WeaponQuality m_Quality;
  		private Mobile m_Crafter;
  		private Poison m_Poison;
  		private int m_PoisonCharges;
  		private bool m_Identified;
  		private int m_Hits;
  		private int m_MaxHits;
  		private SlayerName m_Slayer;
  		private SlayerName m_Slayer2;
  
  		#region SF Imbuing
  		private int m_TimesImbued;
  		private bool m_DImodded;
  		#endregion
  
  		#region Mondain's Legacy
  		private TalismanSlayerName m_Slayer3;
  		#endregion
  
  		private SkillMod m_SkillMod, m_MageMod;
  		private CraftResource m_Resource;
  		private bool m_PlayerConstructed;
  
  		private bool m_Cursed; // Is this weapon cursed via Curse Weapon necromancer spell? Temporary; not serialized.
  
  		private bool m_Consecrated;
  					 // Is this weapon blessed via Consecrate Weapon paladin ability? Temporary; not serialized.
  
  		#region Mondain's Legacy
  		private bool m_Immolating; // Is this weapon blessed via Immolating Weapon arcanists spell? Temporary; not serialized.
  		#endregion
  
  		private AosAttributes m_AosAttributes;
  		private AosWeaponAttributes m_AosWeaponAttributes;
  		private AosSkillBonuses m_AosSkillBonuses;
  		private AosElementAttributes m_AosElementDamages;
  
  		#region SA
  		private SAAbsorptionAttributes m_SAAbsorptionAttributes;
  		#endregion
  
  		// Overridable values. These values are provided to override the defaults which get defined in the individual weapon scripts.
  		private int m_StrReq, m_DexReq, m_IntReq;
  		private int m_MinDamage, m_MaxDamage;
  		private int m_HitSound, m_MissSound;
  		private float m_Speed;
  		private int m_MaxRange;
  		private SkillName m_Skill;
  		private WeaponType m_Type;
  		private WeaponAnimation m_Animation;
  		#endregion
  
  		#region Virtual Properties
  		public virtual WeaponAbility PrimaryAbility { get { return null; } }
  		public virtual WeaponAbility SecondaryAbility { get { return null; } }
  
  		public virtual int DefMaxRange { get { return 1; } }
  		public virtual int DefHitSound { get { return 0; } }
  		public virtual int DefMissSound { get { return 0; } }
  		public virtual SkillName DefSkill { get { return SkillName.Swords; } }
  		public virtual WeaponType DefType { get { return WeaponType.Slashing; } }
  		public virtual WeaponAnimation DefAnimation { get { return WeaponAnimation.Slash1H; } }
  
  		public virtual int AosStrengthReq { get { return 0; } }
  		public virtual int AosDexterityReq { get { return 0; } }
  		public virtual int AosIntelligenceReq { get { return 0; } }
  		public virtual int AosMinDamage { get { return 0; } }
  		public virtual int AosMaxDamage { get { return 0; } }
  		public virtual int AosSpeed { get { return 0; } }
  		public virtual float MlSpeed { get { return 0.0f; } }
  		public virtual int AosMaxRange { get { return DefMaxRange; } }
  		public virtual int AosHitSound { get { return DefHitSound; } }
  		public virtual int AosMissSound { get { return DefMissSound; } }
  		public virtual SkillName AosSkill { get { return DefSkill; } }
  		public virtual WeaponType AosType { get { return DefType; } }
  		public virtual WeaponAnimation AosAnimation { get { return DefAnimation; } }
  
  		public virtual int OldStrengthReq { get { return 0; } }
  		public virtual int OldDexterityReq { get { return 0; } }
  		public virtual int OldIntelligenceReq { get { return 0; } }
  		public virtual int OldMinDamage { get { return 0; } }
  		public virtual int OldMaxDamage { get { return 0; } }
  		public virtual int OldSpeed { get { return 0; } }
  		public virtual int OldMaxRange { get { return DefMaxRange; } }
  		public virtual int OldHitSound { get { return DefHitSound; } }
  		public virtual int OldMissSound { get { return DefMissSound; } }
  		public virtual SkillName OldSkill { get { return DefSkill; } }
  		public virtual WeaponType OldType { get { return DefType; } }
  		public virtual WeaponAnimation OldAnimation { get { return DefAnimation; } }
  
  		public virtual int InitMinHits { get { return 0; } }
  		public virtual int InitMaxHits { get { return 0; } }
  
  		public virtual bool CanFortify { get { return true; } }
  
  		public override int PhysicalResistance { get { return m_AosWeaponAttributes.ResistPhysicalBonus; } }
  		public override int FireResistance { get { return m_AosWeaponAttributes.ResistFireBonus; } }
  		public override int ColdResistance { get { return m_AosWeaponAttributes.ResistColdBonus; } }
  		public override int PoisonResistance { get { return m_AosWeaponAttributes.ResistPoisonBonus; } }
  		public override int EnergyResistance { get { return m_AosWeaponAttributes.ResistEnergyBonus; } }
  
  		public virtual SkillName AccuracySkill { get { return SkillName.Tactics; } }
  
  		#region Personal Bless Deed
  		private Mobile m_BlessedBy;
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public Mobile BlessedBy
  		{
  			get { return m_BlessedBy; }
  			set
  			{
  				m_BlessedBy = value;
  				InvalidateProperties();
  			}
  		}
  
  		private class UnBlessEntry : ContextMenuEntry
  		{
  			private readonly Mobile m_From;
  			private readonly BaseWeapon m_Weapon; // BaseArmor, BaseWeapon or BaseClothing
  
  			public UnBlessEntry(Mobile from, BaseWeapon weapon)
  				: base(6208, -1)
  			{
  				m_From = from;
  				m_Weapon = weapon;
  			}
  
  			public override void OnClick()
  			{
  				m_Weapon.BlessedFor = null;
  				m_Weapon.BlessedBy = null;
  
  				Container pack = m_From.Backpack;
  
  				if (pack != null)
  				{
  					pack.DropItem(new PersonalBlessDeed(m_From));
  					m_From.SendLocalizedMessage(1062200); // A personal bless deed has been placed in your backpack.
  				}
  			}
  		}
  		#endregion
  
  		#endregion
  
  		#region Getters & Setters
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int TimesImbued
  		{
  			get { return m_TimesImbued; }
  			set
  			{
  				m_TimesImbued = value;
  				InvalidateProperties();
  			}
  		}
  
  		public bool DImodded { get { return m_DImodded; } set { m_DImodded = value; InvalidateProperties(); } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public AosAttributes Attributes { get { return m_AosAttributes; } set { } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public AosWeaponAttributes WeaponAttributes { get { return m_AosWeaponAttributes; } set { } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public AosSkillBonuses SkillBonuses { get { return m_AosSkillBonuses; } set { } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public AosElementAttributes AosElementDamages { get { return m_AosElementDamages; } set { } }
  
  		#region Stygian Abyss
  		[CommandProperty(AccessLevel.GameMaster)]
  		public SAAbsorptionAttributes AbsorptionAttributes { get { return m_SAAbsorptionAttributes; } set { } }
  		#endregion
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public bool Cursed { get { return m_Cursed; } set { m_Cursed = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public bool Consecrated { get { return m_Consecrated; } set { m_Consecrated = value; } }
  
  		#region Mondain's Legacy
  		[CommandProperty(AccessLevel.GameMaster)]
  		public bool Immolating { get { return m_Immolating; } set { m_Immolating = value; } }
  		#endregion
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public bool Identified
  		{
  			get { return m_Identified; }
  			set
  			{
  				m_Identified = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int HitPoints
  		{
  			get { return m_Hits; }
  			set
  			{
  				if (m_Hits == value)
  				{
  					return;
  				}
  
  				if (value > m_MaxHits)
  				{
  					value = m_MaxHits;
  				}
  
  				m_Hits = value;
  
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int MaxHitPoints
  		{
  			get { return m_MaxHits; }
  			set
  			{
  				m_MaxHits = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int PoisonCharges
  		{
  			get { return m_PoisonCharges; }
  			set
  			{
  				m_PoisonCharges = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public Poison Poison
  		{
  			get { return m_Poison; }
  			set
  			{
  				m_Poison = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponQuality Quality
  		{
  			get { return m_Quality; }
  			set
  			{
  				UnscaleDurability();
  				m_Quality = value;
  				ScaleDurability();
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public Mobile Crafter
  		{
  			get { return m_Crafter; }
  			set
  			{
  				m_Crafter = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public SlayerName Slayer
  		{
  			get { return m_Slayer; }
  			set
  			{
  				m_Slayer = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public SlayerName Slayer2
  		{
  			get { return m_Slayer2; }
  			set
  			{
  				m_Slayer2 = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public TalismanSlayerName Slayer3
  		{
  			get { return m_Slayer3; }
  			set
  			{
  				m_Slayer3 = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public CraftResource Resource
  		{
  			get { return m_Resource; }
  			set
  			{
  				UnscaleDurability();
  				m_Resource = value;
  				Hue = CraftResources.GetHue(m_Resource);
  				InvalidateProperties();
  				ScaleDurability();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponDamageLevel DamageLevel
  		{
  			get { return m_DamageLevel; }
  			set
  			{
  				m_DamageLevel = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponDurabilityLevel DurabilityLevel
  		{
  			get { return m_DurabilityLevel; }
  			set
  			{
  				UnscaleDurability();
  				m_DurabilityLevel = value;
  				InvalidateProperties();
  				ScaleDurability();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public bool PlayerConstructed { get { return m_PlayerConstructed; } set { m_PlayerConstructed = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int MaxRange
  		{
  			get { return (m_MaxRange == -1 ? Core.AOS ? AosMaxRange : OldMaxRange : m_MaxRange); }
  			set
  			{
  				m_MaxRange = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponAnimation Animation { get { return (m_Animation == (WeaponAnimation)(-1) ? Core.AOS ? AosAnimation : OldAnimation : m_Animation); } set { m_Animation = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponType Type { get { return (m_Type == (WeaponType)(-1) ? Core.AOS ? AosType : OldType : m_Type); } set { m_Type = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public SkillName Skill
  		{
  			get { return (m_Skill == (SkillName)(-1) ? Core.AOS ? AosSkill : OldSkill : m_Skill); }
  			set
  			{
  				m_Skill = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int HitSound { get { return (m_HitSound == -1 ? Core.AOS ? AosHitSound : OldHitSound : m_HitSound); } set { m_HitSound = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int MissSound { get { return (m_MissSound == -1 ? Core.AOS ? AosMissSound : OldMissSound : m_MissSound); } set { m_MissSound = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int MinDamage
  		{
  			get { return (m_MinDamage == -1 ? Core.AOS ? AosMinDamage : OldMinDamage : m_MinDamage); }
  			set
  			{
  				m_MinDamage = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int MaxDamage
  		{
  			get { return (m_MaxDamage == -1 ? Core.AOS ? AosMaxDamage : OldMaxDamage : m_MaxDamage); }
  			set
  			{
  				m_MaxDamage = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public float Speed
  		{
  			get
  			{
  				if (m_Speed != -1)
  				{
  					return m_Speed;
  				}
  
  				if (Core.ML)
  				{
  					return MlSpeed;
  				}
  				else if (Core.AOS)
  				{
  					return AosSpeed;
  				}
  
  				return OldSpeed;
  			}
  			set
  			{
  				m_Speed = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int StrRequirement
  		{
  			get { return (m_StrReq == -1 ? Core.AOS ? AosStrengthReq : OldStrengthReq : m_StrReq); }
  			set
  			{
  				m_StrReq = value;
  				InvalidateProperties();
  			}
  		}
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int DexRequirement { get { return (m_DexReq == -1 ? Core.AOS ? AosDexterityReq : OldDexterityReq : m_DexReq); } set { m_DexReq = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public int IntRequirement { get { return (m_IntReq == -1 ? Core.AOS ? AosIntelligenceReq : OldIntelligenceReq : m_IntReq); } set { m_IntReq = value; } }
  
  		[CommandProperty(AccessLevel.GameMaster)]
  		public WeaponAccuracyLevel AccuracyLevel
  		{
  			get { return m_AccuracyLevel; }
  			set
  			{
  				if (m_AccuracyLevel != value)
  				{
  					m_AccuracyLevel = value;
  
  					if (UseSkillMod)
  					{
  						if (m_AccuracyLevel == WeaponAccuracyLevel.Regular)
  						{
  							if (m_SkillMod != null)
  							{
  								m_SkillMod.Remove();
  							}
  
  							m_SkillMod = null;
  						}
  						else if (m_SkillMod == null && Parent is Mobile)
  						{
  							m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5);
  							((Mobile)Parent).AddSkillMod(m_SkillMod);
  						}
  						else if (m_SkillMod != null)
  						{
  							m_SkillMod.Value = (int)m_AccuracyLevel * 5;
  						}
  					}
  
  					InvalidateProperties();
  				}
  			}
  		}
  		#endregion
  
  		public override void GetContextMenuEntries(Mobile from, List<ContextMenuEntry> list)
  		{
  			base.GetContextMenuEntries(from, list);
  
  			if (BlessedFor == from && BlessedBy == from && RootParent == from)
  			{
  				list.Add(new UnBlessEntry(from, this));
  			}
  
  			XmlLevelItem levitem = XmlAttach.FindAttachment(this, typeof(XmlLevelItem)) as XmlLevelItem;
  
  			if (levitem != null)
  			{
  				list.Add(new LevelInfoEntry(from, this, AttributeCategory.Melee));
  			}
  		}
  
  		public override void OnAfterDuped(Item newItem)
  		{
  			BaseWeapon weap = newItem as BaseWeapon;
  
  			if (weap == null)
  			{
  				return;
  			}
  
  			weap.m_AosAttributes = new AosAttributes(newItem, m_AosAttributes);
  			weap.m_AosElementDamages = new AosElementAttributes(newItem, m_AosElementDamages);
  			weap.m_AosSkillBonuses = new AosSkillBonuses(newItem, m_AosSkillBonuses);
  			weap.m_AosWeaponAttributes = new AosWeaponAttributes(newItem, m_AosWeaponAttributes);
  
  			#region Mondain's Legacy
  			weap.m_SetAttributes = new AosAttributes(newItem, m_SetAttributes);
  			weap.m_SetSkillBonuses = new AosSkillBonuses(newItem, m_SetSkillBonuses);
  			#endregion
  
  			#region SA
  			weap.m_SAAbsorptionAttributes = new SAAbsorptionAttributes(newItem, m_SAAbsorptionAttributes);
  			#endregion
  		}
  
  		public virtual void UnscaleDurability()
  		{
  			int scale = 100 + GetDurabilityBonus();
  
  			m_Hits = ((m_Hits * 100) + (scale - 1)) / scale;
  			m_MaxHits = ((m_MaxHits * 100) + (scale - 1)) / scale;
  			InvalidateProperties();
  		}
  
  		public virtual void ScaleDurability()
  		{
  			int scale = 100 + GetDurabilityBonus();
  
  			m_Hits = ((m_Hits * scale) + 99) / 100;
  			m_MaxHits = ((m_MaxHits * scale) + 99) / 100;
  			InvalidateProperties();
  		}
  
  		public int GetDurabilityBonus()
  		{
  			int bonus = 0;
  
  			if (m_Quality == WeaponQuality.Exceptional)
  			{
  				bonus += 20;
  			}
  
  			switch (m_DurabilityLevel)
  			{
  				case WeaponDurabilityLevel.Durable:
  					bonus += 20;
  					break;
  				case WeaponDurabilityLevel.Substantial:
  					bonus += 50;
  					break;
  				case WeaponDurabilityLevel.Massive:
  					bonus += 70;
  					break;
  				case WeaponDurabilityLevel.Fortified:
  					bonus += 100;
  					break;
  				case WeaponDurabilityLevel.Indestructible:
  					bonus += 120;
  					break;
  			}
  
  			if (Core.AOS)
  			{
  				bonus += m_AosWeaponAttributes.DurabilityBonus;
  
  				#region Mondain's Legacy
  				if (m_Resource == CraftResource.Heartwood)
  				{
  					return bonus;
  				}
  				#endregion
  
  				CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource);
  				CraftAttributeInfo attrInfo = null;
  
  				if (resInfo != null)
  				{
  					attrInfo = resInfo.AttributeInfo;
  				}
  
  				if (attrInfo != null)
  				{
  					bonus += attrInfo.WeaponDurability;
  				}
  			}
  
  			return bonus;
  		}
  
  		public int GetLowerStatReq()
  		{
  			if (!Core.AOS)
  			{
  				return 0;
  			}
  
  			int v = m_AosWeaponAttributes.LowerStatReq;
  
  			#region Mondain's Legacy
  			if (m_Resource == CraftResource.Heartwood)
  			{
  				return v;
  			}
  			#endregion
  
  			CraftResourceInfo info = CraftResources.GetInfo(m_Resource);
  
  			if (info != null)
  			{
  				CraftAttributeInfo attrInfo = info.AttributeInfo;
  
  				if (attrInfo != null)
  				{
  					v += attrInfo.WeaponLowerRequirements;
  				}
  			}
  
  			if (v > 100)
  			{
  				v = 100;
  			}
  
  			return v;
  		}
  
  		public static void BlockEquip(Mobile m, TimeSpan duration)
  		{
  			if (m.BeginAction(typeof(BaseWeapon)))
  			{
  				new ResetEquipTimer(m, duration).Start();
  			}
  		}
  
  		private class ResetEquipTimer : Timer
  		{
  			private readonly Mobile m_Mobile;
  
  			public ResetEquipTimer(Mobile m, TimeSpan duration)
  				: base(duration)
  			{
  				m_Mobile = m;
  			}
  
  			protected override void OnTick()
  			{
  				m_Mobile.EndAction(typeof(BaseWeapon));
  			}
  		}
  
  		public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer)
  		{
  			if (base.CheckConflictingLayer(m, item, layer))
  			{
  				return true;
  			}
  
  			if (Layer == Layer.TwoHanded && layer == Layer.OneHanded)
  			{
  				m.SendLocalizedMessage(500214); // You already have something in both hands.
  				return true;
  			}
  			else if (Layer == Layer.OneHanded && layer == Layer.TwoHanded && !(item is BaseShield) && !(item is BaseEquipableLight))
  			{
  				m.SendLocalizedMessage(500215); // You can only wield one weapon at a time.
  				return true;
  			}
  
  			return false;
  		}
  
  		public override bool AllowSecureTrade(Mobile from, Mobile to, Mobile newOwner, bool accepted)
  		{
  			if (!Ethic.CheckTrade(from, to, newOwner, this))
  			{
  				return false;
  			}
  
  			return base.AllowSecureTrade(from, to, newOwner, accepted);
  		}
  
  		public virtual Race RequiredRace { get { return null; } }
  		//On OSI, there are no weapons with race requirements, this is for custom stuff
  
  		#region SA
  		public virtual bool CanBeWornByGargoyles { get { return false; } }
  		#endregion
  
  		public override bool CanEquip(Mobile from)
  		{
  			if (!Ethic.CheckEquip(from, this))
  			{
  				return false;
  			}
  
  			#region Stygian Abyss
  			if (from.Race == Race.Gargoyle && !CanBeWornByGargoyles && from.IsPlayer())
  			{
  				from.SendLocalizedMessage(1111708); // Gargoyles can't wear this.
  				return false;
  			}
  			#endregion
  
  			if (RequiredRace != null && from.Race != RequiredRace)
  			{
  				if (RequiredRace == Race.Elf)
  				{
  					from.SendLocalizedMessage(1072203); // Only Elves may use this.
  				}
  					#region SA
  				else if (RequiredRace == Race.Gargoyle)
  				{
  					from.SendLocalizedMessage(1111707); // Only gargoyles can wear this.
  				}
  					#endregion
  
  				else
  				{
  					from.SendMessage("Only {0} may use this.", RequiredRace.PluralName);
  				}
  
  				return false;
  			}
  			else if (from.Dex < DexRequirement)
  			{
  				from.SendMessage("You are not nimble enough to equip that.");
  				return false;
  			}
  			else if (from.Str < AOS.Scale(StrRequirement, 100 - GetLowerStatReq()))
  			{
  				from.SendLocalizedMessage(500213); // You are not strong enough to equip that.
  				return false;
  			}
  			else if (from.Int < IntRequirement)
  			{
  				from.SendMessage("You are not smart enough to equip that.");
  				return false;
  			}
  			else if (!from.CanBeginAction(typeof(BaseWeapon)))
  			{
  				return false;
  			}
  				#region Personal Bless Deed
  			else if (BlessedBy != null && BlessedBy != from)
  			{
  				from.SendLocalizedMessage(1075277); // That item is blessed by another player.
  
  				return false;
  			}
  			else if (!XmlAttach.CheckCanEquip(this, from))
  			{
  				return false;
  			}
  				#endregion
  
  			else
  			{
  				return base.CanEquip(from);
  			}
  		}
  
  		public virtual bool UseSkillMod { get { return !Core.AOS; } }
  
  		public override bool OnEquip(Mobile from)
  		{
  			int strBonus = m_AosAttributes.BonusStr;
  			int dexBonus = m_AosAttributes.BonusDex;
  			int intBonus = m_AosAttributes.BonusInt;
  
  			if ((strBonus != 0 || dexBonus != 0 || intBonus != 0))
  			{
  				Mobile m = from;
  
  				string modName = Serial.ToString();
  
  				if (strBonus != 0)
  				{
  					m.AddStatMod(new StatMod(StatType.Str, modName + "Str", strBonus, TimeSpan.Zero));
  				}
  
  				if (dexBonus != 0)
  				{
  					m.AddStatMod(new StatMod(StatType.Dex, modName + "Dex", dexBonus, TimeSpan.Zero));
  				}
  
  				if (intBonus != 0)
  				{
  					m.AddStatMod(new StatMod(StatType.Int, modName + "Int", intBonus, TimeSpan.Zero));
  				}
  			}
  
  			from.NextCombatTime = Core.TickCount + (int)GetDelay(from).TotalMilliseconds;
  
  			if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular)
  			{
  				if (m_SkillMod != null)
  				{
  					m_SkillMod.Remove();
  				}
  
  				m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5);
  				from.AddSkillMod(m_SkillMod);
  			}
  
  			if (Core.AOS && m_AosWeaponAttributes.MageWeapon != 0 && m_AosWeaponAttributes.MageWeapon != 30)
  			{
  				if (m_MageMod != null)
  				{
  					m_MageMod.Remove();
  				}
  
  				m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + m_AosWeaponAttributes.MageWeapon);
  				from.AddSkillMod(m_MageMod);
  			}
  
  			XmlAttach.CheckOnEquip(this, from);
  
  			return true;
  		}
  
  		public override void OnAdded(object parent)
  		{
  			base.OnAdded(parent);
  
  			if (parent is Mobile)
  			{
  				Mobile from = (Mobile)parent;
  
  				if (Core.AOS)
  				{
  					m_AosSkillBonuses.AddTo(from);
  				}
  
  				#region Mondain's Legacy Sets
  				if (IsSetItem)
  				{
  					m_SetEquipped = SetHelper.FullSetEquipped(from, SetID, Pieces);
  
  					if (m_SetEquipped)
  					{
  						m_LastEquipped = true;
  						SetHelper.AddSetBonus(from, SetID);
  					}
  				}
  				#endregion
  
  				from.CheckStatTimers();
  				from.Delta(MobileDelta.WeaponDamage);
  			}
  		}
  
  		public override void OnRemoved(object parent)
  		{
  			if (parent is Mobile)
  			{
  				Mobile m = (Mobile)parent;
  				BaseWeapon weapon = m.Weapon as BaseWeapon;
  
  				string modName = Serial.ToString();
  
  				m.RemoveStatMod(modName + "Str");
  				m.RemoveStatMod(modName + "Dex");
  				m.RemoveStatMod(modName + "Int");
  
  				if (weapon != null)
  				{
  					m.NextCombatTime = Core.TickCount + (int)weapon.GetDelay(m).TotalMilliseconds;
  				}
  
  				if (UseSkillMod && m_SkillMod != null)
  				{
  					m_SkillMod.Remove();
  					m_SkillMod = null;
  				}
  
  				if (m_MageMod != null)
  				{
  					m_MageMod.Remove();
  					m_MageMod = null;
  				}
  
  				if (Core.AOS)
  				{
  					m_AosSkillBonuses.Remove();
  				}
  
  				ImmolatingWeaponSpell.StopImmolating(this);
  
  				m.CheckStatTimers();
  
  				m.Delta(MobileDelta.WeaponDamage);
  
  				XmlAttach.CheckOnRemoved(this, parent);
  
  				#region Mondain's Legacy Sets
  				if (IsSetItem && m_SetEquipped)
  				{
  					SetHelper.RemoveSetBonus(m, SetID, this);
  				}
  				#endregion
  			}
  		}
  
  		public virtual SkillName GetUsedSkill(Mobile m, bool checkSkillAttrs)
  		{
  			SkillName sk;
  
  			if (checkSkillAttrs && m_AosWeaponAttributes.UseBestSkill != 0)
  			{
  				double swrd = m.Skills[SkillName.Swords].Value;
  				double fenc = m.Skills[SkillName.Fencing].Value;
  				double mcng = m.Skills[SkillName.Macing].Value;
  				double val;
  
  				sk = SkillName.Swords;
  				val = swrd;
  
  				if (fenc > val)
  				{
  					sk = SkillName.Fencing;
  					val = fenc;
  				}
  				if (mcng > val)
  				{
  					sk = SkillName.Macing;
  					val = mcng;
  				}
  			}
  			else if (m_AosWeaponAttributes.MageWeapon != 0)
  			{
  				if (m.Skills[SkillName.Magery].Value > m.Skills[Skill].Value)
  				{
  					sk = SkillName.Magery;
  				}
  				else
  				{
  					sk = Skill;
  				}
  			}
  			else
  			{
  				sk = Skill;
  
  				if (sk != SkillName.Wrestling && !m.Player && !m.Body.IsHuman &&
  					m.Skills[SkillName.Wrestling].Value > m.Skills[sk].Value)
  				{
  					sk = SkillName.Wrestling;
  				}
  			}
  
  			return sk;
  		}
  
  		public virtual double GetAttackSkillValue(Mobile attacker, Mobile defender)
  		{
  			return attacker.Skills[GetUsedSkill(attacker, true)].Value;
  		}
  
  		public virtual double GetDefendSkillValue(Mobile attacker, Mobile defender)
  		{
  			return defender.Skills[GetUsedSkill(defender, true)].Value;
  		}
  
  		private static bool CheckAnimal(Mobile m, Type type)
  		{
  			return AnimalForm.UnderTransformation(m, type);
  		}
  
  		public virtual bool CheckHit(Mobile attacker, Mobile defender)
  		{
  			BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;
  			BaseWeapon defWeapon = defender.Weapon as BaseWeapon;
  
  			Skill atkSkill = attacker.Skills[atkWeapon.Skill];
  			Skill defSkill = defender.Skills[defWeapon.Skill];
  
  			double atkValue = atkWeapon.GetAttackSkillValue(attacker, defender);
  			double defValue = defWeapon.GetDefendSkillValue(attacker, defender);
  
  			double ourValue, theirValue;
  
  			int bonus = GetHitChanceBonus();
  
  			#region Stygian Abyss
  			if (atkWeapon is BaseThrown)
  			{
  				int min = ((BaseThrown)atkWeapon).MinThrowRange;
  				int throwchances = 0;
  
  				if (attacker.InRange(defender, 1))
  				{
  					throwchances -= 12 - (int)(attacker.Skills[SkillName.Swords].Value / 10);
  				}
  				else if (!attacker.InRange(defender, min - 1))
  				{
  					throwchances -= 12;
  				}
  
  				BaseShield shield = attacker.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
  
  				if (shield != null)
  				{
  					throwchances -= 12 - (int)(attacker.Skills[SkillName.Parry].Value / 10);
  					throwchances -= Math.Max(0, (10 - (attacker.Dex / 10)));
  				}
  
  				if (throwchances < 0)
  				{
  					throwchances = 0;
  				}
  
  				bonus += throwchances;
  			}
  			#endregion
  
  			if (Core.AOS)
  			{
  				if (atkValue <= -20.0)
  				{
  					atkValue = -19.9;
  				}
  
  				if (defValue <= -20.0)
  				{
  					defValue = -19.9;
  				}
  
  				bonus += AosAttributes.GetValue(attacker, AosAttribute.AttackChance);
  
  				if (DivineFurySpell.UnderEffect(attacker))
  				{
  					bonus += 10; // attacker gets 10% bonus when they're under divine fury
  				}
  
  				if (CheckAnimal(attacker, typeof(GreyWolf)) || CheckAnimal(attacker, typeof(BakeKitsune)))
  				{
  					bonus += 20; // attacker gets 20% bonus when under Wolf or Bake Kitsune form
  				}
  
  				if (HitLower.IsUnderAttackEffect(attacker))
  				{
  					bonus -= 25; // Under Hit Lower Attack effect -> 25% malus
  				}
  
  				WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker);
  
  				if (ability != null)
  				{
  					bonus += ability.AccuracyBonus;
  				}
  
  				SpecialMove move = SpecialMove.GetCurrentMove(attacker);
  
  				if (move != null)
  				{
  					bonus += move.GetAccuracyBonus(attacker);
  				}
  
  				// Max Hit Chance Increase = 45%
  				if (bonus > 45)
  				{
  					bonus = 45;
  				}
  
  				ourValue = (atkValue + 20.0) * (100 + bonus);
  
  				bonus = AosAttributes.GetValue(defender, AosAttribute.DefendChance);
  
  				if (DivineFurySpell.UnderEffect(defender))
  				{
  					bonus -= 20; // defender loses 20% bonus when they're under divine fury
  				}
  
  				if (HitLower.IsUnderDefenseEffect(defender))
  				{
  					bonus -= 25; // Under Hit Lower Defense effect -> 25% malus
  				}
  
  				int blockBonus = 0;
  
  				if (Block.GetBonus(defender, ref blockBonus))
  				{
  					bonus += blockBonus;
  				}
  
  				int surpriseMalus = 0;
  
  				if (SurpriseAttack.GetMalus(defender, ref surpriseMalus))
  				{
  					bonus -= surpriseMalus;
  				}
  
  				int discordanceEffect = 0;
  
  				// Defender loses -0/-28% if under the effect of Discordance.
  				if (Discordance.GetEffect(attacker, ref discordanceEffect))
  				{
  					bonus -= discordanceEffect;
  				}
  
  				// Defense Chance Increase = 45%
  				if (bonus > 45)
  				{
  					bonus = 45;
  				}
  
  				theirValue = (defValue + 20.0) * (100 + bonus);
  
  				bonus = 0;
  			}
  			else
  			{
  				if (atkValue <= -50.0)
  				{
  					atkValue = -49.9;
  				}
  
  				if (defValue <= -50.0)
  				{
  					defValue = -49.9;
  				}
  
  				ourValue = (atkValue + 50.0);
  				theirValue = (defValue + 50.0);
  			}
  
  			double chance = ourValue / (theirValue * 2.0);
  
  			chance *= 1.0 + ((double)bonus / 100);
  
  			if (Core.AOS && chance < 0.02)
  			{
  				chance = 0.02;
  			}
  
  			return attacker.CheckSkill(atkSkill.SkillName, chance);
  		}
  
  		public virtual TimeSpan GetDelay(Mobile m)
  		{
  			double speed = Speed;
  
  			if (speed == 0)
  			{
  				return TimeSpan.FromHours(1.0);
  			}
  
  			double delayInSeconds;
  
  			if (Core.SE)
  			{
  				/*
                  * This is likely true for Core.AOS as well... both guides report the same
                  * formula, and both are wrong.
                  * The old formula left in for AOS for legacy & because we aren't quite 100%
                  * Sure that AOS has THIS formula
                  */
  				int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed);
  
  				if (DivineFurySpell.UnderEffect(m))
  				{
  					bonus += 10;
  				}
  
  				// Bonus granted by successful use of Honorable Execution.
  				bonus += HonorableExecution.GetSwingBonus(m);
  
  				if (DualWield.Registry.Contains(m))
  				{
  					bonus += ((DualWield.DualWieldTimer)DualWield.Registry[m]).BonusSwingSpeed;
  				}
  
  				if (Feint.Registry.Contains(m))
  				{
  					bonus -= ((Feint.FeintTimer)Feint.Registry[m]).SwingSpeedReduction;
  				}
  
  				TransformContext context = TransformationSpellHelper.GetContext(m);
  
  				if (context != null && context.Spell is ReaperFormSpell)
  				{
  					bonus += ((ReaperFormSpell)context.Spell).SwingSpeedBonus;
  				}
  
  				int discordanceEffect = 0;
  
  				// Discordance gives a malus of -0/-28% to swing speed.
  				if (Discordance.GetEffect(m, ref discordanceEffect))
  				{
  					bonus -= discordanceEffect;
  				}
  
  				if (EssenceOfWindSpell.IsDebuffed(m))
  				{
  					bonus -= EssenceOfWindSpell.GetSSIMalus(m);
  				}
  
  				if (bonus > 60)
  				{
  					bonus = 60;
  				}
  
  				double ticks;
  
  				if (Core.ML)
  				{
  					int stamTicks = m.Stam / 30;
  
  					ticks = speed * 4;
  					ticks = Math.Floor((ticks - stamTicks) * (100.0 / (100 + bonus)));
  				}
  				else
  				{
  					speed = Math.Floor(speed * (bonus + 100.0) / 100.0);
  
  					if (speed <= 0)
  					{
  						speed = 1;
  					}
  
  					ticks = Math.Floor((80000.0 / ((m.Stam + 100) * speed)) - 2);
  				}
  
  				// Swing speed currently capped at one swing every 1.25 seconds (5 ticks).
  				if (ticks < 5)
  				{
  					ticks = 5;
  				}
  
  				delayInSeconds = ticks * 0.25;
  			}
  			else if (Core.AOS)
  			{
  				int v = (m.Stam + 100) * (int)speed;
  
  				int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed);
  
  				if (DivineFurySpell.UnderEffect(m))
  				{
  					bonus += 10;
  				}
  
  				int discordanceEffect = 0;
  
  				// Discordance gives a malus of -0/-28% to swing speed.
  				if (Discordance.GetEffect(m, ref discordanceEffect))
  				{
  					bonus -= discordanceEffect;
  				}
  
  				v += AOS.Scale(v, bonus);
  
  				if (v <= 0)
  				{
  					v = 1;
  				}
  
  				delayInSeconds = Math.Floor(40000.0 / v) * 0.5;
  
  				// Maximum swing rate capped at one swing per second 
  				// OSI dev said that it has and is supposed to be 1.25
  				if (delayInSeconds < 1.25)
  				{
  					delayInSeconds = 1.25;
  				}
  			}
  			else
  			{
  				int v = (m.Stam + 100) * (int)speed;
  
  				if (v <= 0)
  				{
  					v = 1;
  				}
  
  				delayInSeconds = 15000.0 / v;
  			}
  
  			return TimeSpan.FromSeconds(delayInSeconds);
  		}
  
  		public virtual void OnBeforeSwing(Mobile attacker, Mobile defender)
  		{
  			WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker);
  
  			if (a != null && !a.OnBeforeSwing(attacker, defender))
  			{
  				WeaponAbility.ClearCurrentAbility(attacker);
  			}
  
  			SpecialMove move = SpecialMove.GetCurrentMove(attacker);
  
  			if (move != null && !move.OnBeforeSwing(attacker, defender))
  			{
  				SpecialMove.ClearCurrentMove(attacker);
  			}
  		}
  
  		public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender)
  		{
  			return OnSwing(attacker, defender, 1.0);
  		}
  
  		public virtual TimeSpan OnSwing(Mobile attacker, Mobile defender, double damageBonus)
  		{
  			bool canSwing = true;
  
  			if (Core.AOS)
  			{
  				canSwing = (!attacker.Paralyzed && !attacker.Frozen);
  
  				if (canSwing)
  				{
  					Spell sp = attacker.Spell as Spell;
  
  					canSwing = (sp == null || !sp.IsCasting || !sp.BlocksMovement);
  				}
  
  				if (canSwing)
  				{
  					PlayerMobile p = attacker as PlayerMobile;
  
  					canSwing = (p == null || p.PeacedUntil <= DateTime.UtcNow);
  				}
  			}
  
  			#region Dueling
  			if (attacker is PlayerMobile)
  			{
  				PlayerMobile pm = (PlayerMobile)attacker;
  
  				if (pm.DuelContext != null && !pm.DuelContext.CheckItemEquip(attacker, this))
  				{
  					canSwing = false;
  				}
  			}
  			#endregion
  
  			if (canSwing && attacker.HarmfulCheck(defender))
  			{
  				attacker.DisruptiveAction();
  
  				if (attacker.NetState != null)
  				{
  					attacker.Send(new Swing(0, attacker, defender));
  				}
  
  				if (attacker is BaseCreature)
  				{
  					BaseCreature bc = (BaseCreature)attacker;
  					WeaponAbility ab = bc.GetWeaponAbility();
  
  					if (ab != null)
  					{
  						if (bc.WeaponAbilityChance > Utility.RandomDouble())
  						{
  							WeaponAbility.SetCurrentAbility(bc, ab);
  						}
  						else
  						{
  							WeaponAbility.ClearCurrentAbility(bc);
  						}
  					}
  				}
  
  				if (CheckHit(attacker, defender))
  				{
  					OnHit(attacker, defender, damageBonus);
  				}
  				else
  				{
  					OnMiss(attacker, defender);
  				}
  			}
  
  			return GetDelay(attacker);
  		}
  
  		#region Sounds
  		public virtual int GetHitAttackSound(Mobile attacker, Mobile defender)
  		{
  			int sound = attacker.GetAttackSound();
  
  			if (sound == -1)
  			{
  				sound = HitSound;
  			}
  
  			return sound;
  		}
  
  		public virtual int GetHitDefendSound(Mobile attacker, Mobile defender)
  		{
  			return defender.GetHurtSound();
  		}
  
  		public virtual int GetMissAttackSound(Mobile attacker, Mobile defender)
  		{
  			if (attacker.GetAttackSound() == -1)
  			{
  				return MissSound;
  			}
  			else
  			{
  				return -1;
  			}
  		}
  
  		public virtual int GetMissDefendSound(Mobile attacker, Mobile defender)
  		{
  			return -1;
  		}
  		#endregion
  
  		public static bool CheckParry(Mobile defender)
  		{
  			if (defender == null)
  			{
  				return false;
  			}
  
  			BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
  
  			double parry = defender.Skills[SkillName.Parry].Value;
  			double bushidoNonRacial = defender.Skills[SkillName.Bushido].NonRacialValue;
  			double bushido = defender.Skills[SkillName.Bushido].Value;
  
  			if (shield != null)
  			{
  				double chance = (parry - bushidoNonRacial) / 400.0;
  					// As per OSI, no negitive effect from the Racial stuffs, ie, 120 parry and '0' bushido with humans
  
  				if (chance < 0) // chance shouldn't go below 0
  				{
  					chance = 0;
  				}
  
  				// Parry/Bushido over 100 grants a 5% bonus.
  				if (parry >= 100.0 || bushido >= 100.0)
  				{
  					chance += 0.05;
  				}
  
  				// Evasion grants a variable bonus post ML. 50% prior.
  				if (Evasion.IsEvading(defender))
  				{
  					chance *= Evasion.GetParryScalar(defender);
  				}
  
  				// Low dexterity lowers the chance.
  				if (defender.Dex < 80)
  				{
  					chance = chance * (20 + defender.Dex) / 100;
  				}
  
  				return defender.CheckSkill(SkillName.Parry, chance);
  			}
  			else if (!(defender.Weapon is Fists) && !(defender.Weapon is BaseRanged))
  			{
  				BaseWeapon weapon = defender.Weapon as BaseWeapon;
  
  				double divisor = (weapon.Layer == Layer.OneHanded) ? 48000.0 : 41140.0;
  
  				double chance = (parry * bushido) / divisor;
  
  				double aosChance = parry / 800.0;
  
  				// Parry or Bushido over 100 grant a 5% bonus.
  				if (parry >= 100.0)
  				{
  					chance += 0.05;
  					aosChance += 0.05;
  				}
  				else if (bushido >= 100.0)
  				{
  					chance += 0.05;
  				}
  
  				// Evasion grants a variable bonus post ML. 50% prior.
  				if (Evasion.IsEvading(defender))
  				{
  					chance *= Evasion.GetParryScalar(defender);
  				}
  
  				// Low dexterity lowers the chance.
  				if (defender.Dex < 80)
  				{
  					chance = chance * (20 + defender.Dex) / 100;
  				}
  
  				if (chance > aosChance)
  				{
  					return defender.CheckSkill(SkillName.Parry, chance);
  				}
  				else
  				{
  					return (aosChance > Utility.RandomDouble());
  						// Only skillcheck if wielding a shield & there's no effect from Bushido
  				}
  			}
  
  			return false;
  		}
  
  		public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage)
  		{
  			int originalDamage = damage;
  
  			bool blocked = false;
  
  			if (defender.Player || defender.Body.IsHuman)
  			{
  				blocked = CheckParry(defender);
  
  				if (blocked)
  				{
  					defender.FixedEffect(0x37B9, 10, 16);
  					damage = 0;
  
  					// Successful block removes the Honorable Execution penalty.
  					HonorableExecution.RemovePenalty(defender);
  
  					if (CounterAttack.IsCountering(defender))
  					{
  						BaseWeapon weapon = defender.Weapon as BaseWeapon;
  
  						if (weapon != null)
  						{
  							defender.FixedParticles(0x3779, 1, 15, 0x158B, 0x0, 0x3, EffectLayer.Waist);
  							weapon.OnSwing(defender, attacker);
  						}
  
  						CounterAttack.StopCountering(defender);
  					}
  
  					if (Confidence.IsConfident(defender))
  					{
  						defender.SendLocalizedMessage(1063117);
  							// Your confidence reassures you as you successfully block your opponent's blow.
  
  						double bushido = defender.Skills.Bushido.Value;
  
  						defender.Hits += Utility.RandomMinMax(1, (int)(bushido / 12));
  						defender.Stam += Utility.RandomMinMax(1, (int)(bushido / 5));
  					}
  
  					BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
  
  					if (shield != null)
  					{
  						shield.OnHit(this, damage);
  
  						XmlAttach.OnArmorHit(attacker, defender, shield, this, originalDamage);
  					}
  				}
  			}
  
  			if (!blocked)
  			{
  				double positionChance = Utility.RandomDouble();
  
  				Item armorItem;
  
  				if (positionChance < 0.07)
  				{
  					armorItem = defender.NeckArmor;
  				}
  				else if (positionChance < 0.14)
  				{
  					armorItem = defender.HandArmor;
  				}
  				else if (positionChance < 0.28)
  				{
  					armorItem = defender.ArmsArmor;
  				}
  				else if (positionChance < 0.43)
  				{
  					armorItem = defender.HeadArmor;
  				}
  				else if (positionChance < 0.65)
  				{
  					armorItem = defender.LegsArmor;
  				}
  				else
  				{
  					armorItem = defender.ChestArmor;
  				}
  
  				IWearableDurability armor = armorItem as IWearableDurability;
  
  				if (armor != null)
  				{
  					armor.OnHit(this, damage); // call OnHit to lose durability
  					damage -= XmlAttach.OnArmorHit(attacker, defender, armorItem, this, originalDamage);
  				}
  			}
  
  			return damage;
  		}
  
  		public virtual int AbsorbDamage(Mobile attacker, Mobile defender, int damage)
  		{
  			if (Core.AOS)
  			{
  				return AbsorbDamageAOS(attacker, defender, damage);
  			}
  
  			BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
  			if (shield != null)
  			{
  				damage = shield.OnHit(this, damage);
  			}
  
  			double chance = Utility.RandomDouble();
  
  			Item armorItem;
  
  			if (chance < 0.07)
  			{
  				armorItem = defender.NeckArmor;
  			}
  			else if (chance < 0.14)
  			{
  				armorItem = defender.HandArmor;
  			}
  			else if (chance < 0.28)
  			{
  				armorItem = defender.ArmsArmor;
  			}
  			else if (chance < 0.43)
  			{
  				armorItem = defender.HeadArmor;
  			}
  			else if (chance < 0.65)
  			{
  				armorItem = defender.LegsArmor;
  			}
  			else
  			{
  				armorItem = defender.ChestArmor;
  			}
  
  			IWearableDurability armor = armorItem as IWearableDurability;
  
  			if (armor != null)
  			{
  				damage = armor.OnHit(this, damage);
  			}
  
  			int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod;
  
  			damage -= XmlAttach.OnArmorHit(attacker, defender, armorItem, this, damage);
  			damage -= XmlAttach.OnArmorHit(attacker, defender, shield, this, damage);
  
  			if (virtualArmor > 0)
  			{
  				double scalar;
  
  				if (chance < 0.14)
  				{
  					scalar = 0.07;
  				}
  				else if (chance < 0.28)
  				{
  					scalar = 0.14;
  				}
  				else if (chance < 0.43)
  				{
  					scalar = 0.15;
  				}
  				else if (chance < 0.65)
  				{
  					scalar = 0.22;
  				}
  				else
  				{
  					scalar = 0.35;
  				}
  
  				int from = (int)(virtualArmor * scalar) / 2;
  				int to = (int)(virtualArmor * scalar);
  
  				damage -= Utility.Random(from, (to - from) + 1);
  			}
  
  			return damage;
  		}
  
  		public virtual int GetPackInstinctBonus(Mobile attacker, Mobile defender)
  		{
  			if (attacker.Player || defender.Player)
  			{
  				return 0;
  			}
  
  			BaseCreature bc = attacker as BaseCreature;
  
  			if (bc == null || bc.PackInstinct == PackInstinct.None || (!bc.Controlled && !bc.Summoned))
  			{
  				return 0;
  			}
  
  			Mobile master = bc.ControlMaster;
  
  			if (master == null)
  			{
  				master = bc.SummonMaster;
  			}
  
  			if (master == null)
  			{
  				return 0;
  			}
  
  			int inPack = 1;
  
  			foreach (Mobile m in defender.GetMobilesInRange(1))
  			{
  				if (m != attacker && m is BaseCreature)
  				{
  					BaseCreature tc = (BaseCreature)m;
  
  					if ((tc.PackInstinct & bc.PackInstinct) == 0 || (!tc.Controlled && !tc.Summoned))
  					{
  						continue;
  					}
  
  					Mobile theirMaster = tc.ControlMaster;
  
  					if (theirMaster == null)
  					{
  						theirMaster = tc.SummonMaster;
  					}
  
  					if (master == theirMaster && tc.Combatant == defender)
  					{
  						++inPack;
  					}
  				}
  			}
  
  			if (inPack >= 5)
  			{
  				return 100;
  			}
  			else if (inPack >= 4)
  			{
  				return 75;
  			}
  			else if (inPack >= 3)
  			{
  				return 50;
  			}
  			else if (inPack >= 2)
  			{
  				return 25;
  			}
  
  			return 0;
  		}
  
  		private static bool m_InDoubleStrike;
  
  		public static bool InDoubleStrike { get { return m_InDoubleStrike; } set { m_InDoubleStrike = value; } }
  
  		public void OnHit(Mobile attacker, Mobile defender)
  		{
  			OnHit(attacker, defender, 1.0);
  		}
  
  		public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus)
  		{
  			if (MirrorImage.HasClone(defender) && (defender.Skills.Ninjitsu.Value / 150.0) > Utility.RandomDouble())
  			{
  				Clone bc;
  
  				foreach (Mobile m in defender.GetMobilesInRange(4))
  				{
  					bc = m as Clone;
  
  					if (bc != null && bc.Summoned && bc.SummonMaster == defender)
  					{
  						attacker.SendLocalizedMessage(1063141); // Your attack has been diverted to a nearby mirror image of your target!
  						defender.SendLocalizedMessage(1063140); // You manage to divert the attack onto one of your nearby mirror images.
  
  						/*
                          * TODO: What happens if the Clone parries a blow?
                          * And what about if the attacker is using Honorable Execution
                          * and kills it?
                          */
  
  						defender = m;
  						break;
  					}
  				}
  			}
  
  			PlaySwingAnimation(attacker);
  			PlayHurtAnimation(defender);
  
  			attacker.PlaySound(GetHitAttackSound(attacker, defender));
  			defender.PlaySound(GetHitDefendSound(attacker, defender));
  
  			int damage = ComputeDamage(attacker, defender);
  
  			#region Damage Multipliers
  			/*
              * The following damage bonuses multiply damage by a factor.
              * Capped at x3 (300%).
              */
  			int percentageBonus = 0;
  
  			WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker);
  			SpecialMove move = SpecialMove.GetCurrentMove(attacker);
  
  			if (a != null)
  			{
  				percentageBonus += (int)(a.DamageScalar * 100) - 100;
  			}
  
  			if (move != null)
  			{
  				percentageBonus += (int)(move.GetDamageScalar(attacker, defender) * 100) - 100;
  			}
  
  			percentageBonus += (int)(damageBonus * 100) - 100;
  
  			CheckSlayerResult cs = CheckSlayers(attacker, defender);
  
  			if (cs != CheckSlayerResult.None)
  			{
  				if (cs == CheckSlayerResult.Slayer)
  				{
  					defender.FixedEffect(0x37B9, 10, 5);
  				}
  
  				percentageBonus += 100;
  			}
  
  			if (!attacker.Player)
  			{
  				if (defender is PlayerMobile)
  				{
  					PlayerMobile pm = (PlayerMobile)defender;
  
  					if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType())
  					{
  						percentageBonus += 100;
  					}
  				}
  			}
  			else if (!defender.Player)
  			{
  				if (attacker is PlayerMobile)
  				{
  					PlayerMobile pm = (PlayerMobile)attacker;
  
  					if (pm.WaitingForEnemy)
  					{
  						pm.EnemyOfOneType = defender.GetType();
  						pm.WaitingForEnemy = false;
  					}
  
  					if (pm.EnemyOfOneType == defender.GetType())
  					{
  						defender.FixedEffect(0x37B9, 10, 5, 1160, 0);
  
  						percentageBonus += 50;
  					}
  				}
  			}
  
  			int packInstinctBonus = GetPackInstinctBonus(attacker, defender);
  
  			if (packInstinctBonus != 0)
  			{
  				percentageBonus += packInstinctBonus;
  			}
  
  			if (m_InDoubleStrike)
  			{
  				percentageBonus -= 10;
  			}
  
  			TransformContext context = TransformationSpellHelper.GetContext(defender);
  
  			if ((m_Slayer == SlayerName.Silver || m_Slayer2 == SlayerName.Silver) && context != null &&
  				context.Spell is NecromancerSpell && context.Type != typeof(HorrificBeastSpell))
  			{
  				// Every necromancer transformation other than horrific beast takes an additional 25% damage
  				percentageBonus += 25;
  			}
  
  			if (attacker is PlayerMobile && !(Core.ML && defender is PlayerMobile))
  			{
  				PlayerMobile pmAttacker = (PlayerMobile)attacker;
  
  				if (pmAttacker.HonorActive && pmAttacker.InRange(defender, 1))
  				{
  					percentageBonus += 25;
  				}
  
  				if (pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender)
  				{
  					percentageBonus += pmAttacker.SentHonorContext.PerfectionDamageBonus;
  				}
  			}
  
  			#region Stygian Abyss
  			percentageBonus += BattleLust.GetBonus(attacker, defender);
  
  			if (this is BaseThrown)
  			{
  				int max = ((BaseThrown)this).MaxThrowRange;
  
  				if (attacker.InRange(defender, max))
  				{
  					percentageBonus += -47;
  				}
  			}
  			#endregion
  
  			#region Mondain's Legacy
  			if (Core.ML)
  			{
  				BaseTalisman talisman = attacker.Talisman as BaseTalisman;
  
  				if (talisman != null && talisman.Killer != null)
  				{
  					percentageBonus += talisman.Killer.DamageBonus(defender);
  				}
  
  				if (this is ButchersWarCleaver)
  				{
  					if (defender is Bull || defender is Cow || defender is Gaman)
  					{
  						percentageBonus += 100;
  					}
  				}
  			}
  			#endregion
  
  			percentageBonus = Math.Min(percentageBonus, 300);
  
  			damage = AOS.Scale(damage, 100 + percentageBonus);
  			#endregion
  
  			if (attacker is BaseCreature)
  			{
  				((BaseCreature)attacker).AlterMeleeDamageTo(defender, ref damage);
  			}
  
  			if (defender is BaseCreature)
  			{
  				((BaseCreature)defender).AlterMeleeDamageFrom(attacker, ref damage);
  			}
  
  			damage = AbsorbDamage(attacker, defender, damage);
  
  			if (!Core.AOS && damage < 1)
  			{
  				damage = 1;
  			}
  			else if (Core.AOS && damage == 0) // parried
  			{
  				if (a != null && a.Validate(attacker) /*&& a.CheckMana( attacker, true )*/)
  					// Parried special moves have no mana cost 
  				{
  					a = null;
  					WeaponAbility.ClearCurrentAbility(attacker);
  
  					attacker.SendLocalizedMessage(1061140); // Your attack was parried!
  				}
  
  				#region Stygian Abyss
  				if (AosArmorAttributes.GetValue(defender, AosArmorAttribute.ReactiveParalyze) > Utility.RandomMinMax(1, 100))
  				{
  					attacker.Paralyze(TimeSpan.FromSeconds(3));
  				}
  				#endregion
  			}
  
  			#region Mondain's Legacy
  			if (m_Immolating)
  			{
  				int d = ImmolatingWeaponSpell.GetImmolatingDamage(this);
  				d = AOS.Damage(defender, attacker, d, 0, 100, 0, 0, 0);
  
  				AttuneWeaponSpell.TryAbsorb(defender, ref d);
  
  				if (d > 0)
  				{
  					defender.Damage(d);
  				}
  			}
  			#endregion
  
  			AddBlood(attacker, defender, damage);
  
  			int phys, fire, cold, pois, nrgy, chaos, direct;
  
  			GetDamageTypes(attacker, out phys, out fire, out cold, out pois, out nrgy, out chaos, out direct);
  
  			if (Core.ML && this is BaseRanged)
  			{
  				BaseQuiver quiver = attacker.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
  
  				if (quiver != null)
  				{
  					quiver.AlterBowDamage(ref phys, ref fire, ref cold, ref pois, ref nrgy, ref chaos, ref direct);
  				}
  			}
  
  			if (m_Consecrated)
  			{
  				phys = defender.PhysicalResistance;
  				fire = defender.FireResistance;
  				cold = defender.ColdResistance;
  				pois = defender.PoisonResistance;
  				nrgy = defender.EnergyResistance;
  
  				int low = phys, type = 0;
  
  				if (fire < low)
  				{
  					low = fire;
  					type = 1;
  				}
  				if (cold < low)
  				{
  					low = cold;
  					type = 2;
  				}
  				if (pois < low)
  				{
  					low = pois;
  					type = 3;
  				}
  				if (nrgy < low)
  				{
  					low = nrgy;
  					type = 4;
  				}
  
  				phys = fire = cold = pois = nrgy = chaos = direct = 0;
  
  				if (type == 0)
  				{
  					phys = 100;
  				}
  				else if (type == 1)
  				{
  					fire = 100;
  				}
  				else if (type == 2)
  				{
  					cold = 100;
  				}
  				else if (type == 3)
  				{
  					pois = 100;
  				}
  				else if (type == 4)
  				{
  					nrgy = 100;
  				}
  			}
  
  			// TODO: Scale damage, alongside the leech effects below, to weapon speed.
  			if (ImmolatingWeaponSpell.IsImmolating(this) && damage > 0)
  			{
  				ImmolatingWeaponSpell.DoEffect(this, defender);
  			}
  
  			int damageGiven = damage;
  
  			if (a != null && !a.OnBeforeDamage(attacker, defender))
  			{
  				WeaponAbility.ClearCurrentAbility(attacker);
  				a = null;
  			}
  
  			if (move != null && !move.OnBeforeDamage(attacker, defender))
  			{
  				SpecialMove.ClearCurrentMove(attacker);
  				move = null;
  			}
  
  			bool ignoreArmor = (a is ArmorIgnore || (move != null && move.IgnoreArmor(attacker)));
  
  			damageGiven = AOS.Damage(
  				defender,
  				attacker,
  				damage,
  				ignoreArmor,
  				phys,
  				fire,
  				cold,
  				pois,
  				nrgy,
  				chaos,
  				direct,
  				false,
  				this is BaseRanged,
  				false);
  
  			double propertyBonus = (move == null) ? 1.0 : move.GetPropertyBonus(attacker);
  
  			if (Core.AOS)
  			{
  				int lifeLeech = 0;
  				int stamLeech = 0;
  				int manaLeech = 0;
  				int wraithLeech = 0;
  
  				if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechHits) * propertyBonus) >
  					Utility.Random(100))
  				{
  					lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points
  				}
  
  				if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechStam) * propertyBonus) >
  					Utility.Random(100))
  				{
  					stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina
  				}
  
  				if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechMana) * propertyBonus) >
  					Utility.Random(100))
  				{
  					manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana
  				}
  
  				if (m_Cursed)
  				{
  					lifeLeech += 50; // Additional 50% life leech for cursed weapons (necro spell)
  				}
  
  				context = TransformationSpellHelper.GetContext(attacker);
  
  				if (context != null && context.Type == typeof(VampiricEmbraceSpell))
  				{
  					lifeLeech += 20; // Vampiric embrace gives an additional 20% life leech
  				}
  
  				if (context != null && context.Type == typeof(WraithFormSpell))
  				{
  					wraithLeech = (5 + (int)((15 * attacker.Skills.SpiritSpeak.Value) / 100));
  						// Wraith form gives an additional 5-20% mana leech
  
  					// Mana leeched by the Wraith Form spell is actually stolen, not just leeched.
  					defender.Mana -= AOS.Scale(damageGiven, wraithLeech);
  
  					manaLeech += wraithLeech;
  				}
  
  				if (lifeLeech != 0)
  				{
  					attacker.Hits += AOS.Scale(damageGiven, lifeLeech);
  				}
  
  				if (stamLeech != 0)
  				{
  					attacker.Stam += AOS.Scale(damageGiven, stamLeech);
  				}
  
  				if (manaLeech != 0)
  				{
  					attacker.Mana += AOS.Scale(damageGiven, manaLeech);
  				}
  
  				if (lifeLeech != 0 || stamLeech != 0 || manaLeech != 0)
  				{
  					attacker.PlaySound(0x44D);
  				}
  			}
  
  			if (m_MaxHits > 0 &&
  				((MaxRange <= 1 && (defender is Slime || defender is ToxicElemental || defender is CorrosiveSlime)) ||
  				 Utility.Random(25) == 0)) // Stratics says 50% chance, seems more like 4%..
  			{
  				if (MaxRange <= 1 && (defender is Slime || defender is ToxicElemental || defender is CorrosiveSlime))
  				{
  					attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!*
  				}
  
  				if (Core.AOS &&
  					m_AosWeaponAttributes.SelfRepair + (IsSetItem && m_SetEquipped ? m_SetSelfRepair : 0) > Utility.Random(10))
  				{
  					HitPoints += 2;
  				}
  				else
  				{
  					if (m_Hits > 0)
  					{
  						--HitPoints;
  					}
  					else if (m_MaxHits > 1)
  					{
  						--MaxHitPoints;
  
  						if (Parent is Mobile)
  						{
  							((Mobile)Parent).LocalOverheadMessage(MessageType.Regular, 0x3B2, 1061121);
  								// Your equipment is severely damaged.
  						}
  					}
  					else
  					{
  						Delete();
  					}
  				}
  			}
  
  			if (attacker is VampireBatFamiliar)
  			{
  				BaseCreature bc = (BaseCreature)attacker;
  				Mobile caster = bc.ControlMaster;
  
  				if (caster == null)
  				{
  					caster = bc.SummonMaster;
  				}
  
  				if (caster != null && caster.Map == bc.Map && caster.InRange(bc, 2))
  				{
  					caster.Hits += damage;
  				}
  				else
  				{
  					bc.Hits += damage;
  				}
  			}
  
  			if (Core.AOS)
  			{
  				int physChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPhysicalArea) * propertyBonus);
  				int fireChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireArea) * propertyBonus);
  				int coldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitColdArea) * propertyBonus);
  				int poisChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitPoisonArea) * propertyBonus);
  				int nrgyChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitEnergyArea) * propertyBonus);
  
  				if (physChance != 0 && physChance > Utility.Random(100))
  				{
  					DoAreaAttack(attacker, defender, 0x10E, 50, 100, 0, 0, 0, 0);
  				}
  
  				if (fireChance != 0 && fireChance > Utility.Random(100))
  				{
  					DoAreaAttack(attacker, defender, 0x11D, 1160, 0, 100, 0, 0, 0);
  				}
  
  				if (coldChance != 0 && coldChance > Utility.Random(100))
  				{
  					DoAreaAttack(attacker, defender, 0x0FC, 2100, 0, 0, 100, 0, 0);
  				}
  
  				if (poisChance != 0 && poisChance > Utility.Random(100))
  				{
  					DoAreaAttack(attacker, defender, 0x205, 1166, 0, 0, 0, 100, 0);
  				}
  
  				if (nrgyChance != 0 && nrgyChance > Utility.Random(100))
  				{
  					DoAreaAttack(attacker, defender, 0x1F1, 120, 0, 0, 0, 0, 100);
  				}
  
  				int maChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitMagicArrow) * propertyBonus);
  				int harmChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitHarm) * propertyBonus);
  				int fireballChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireball) * propertyBonus);
  				int lightningChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLightning) * propertyBonus);
  				int dispelChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitDispel) * propertyBonus);
  
  				#region Stygian Abyss
  				int curseChance = (int)(m_AosWeaponAttributes.HitCurse * propertyBonus);
  				int fatigueChance = (int)(m_AosWeaponAttributes.HitFatigue * propertyBonus);
  				int manadrainChance = (int)(m_AosWeaponAttributes.HitManaDrain * propertyBonus);
  				#endregion
  
  				if (maChance != 0 && maChance > Utility.Random(100))
  				{
  					DoMagicArrow(attacker, defender);
  				}
  
  				if (harmChance != 0 && harmChance > Utility.Random(100))
  				{
  					DoHarm(attacker, defender);
  				}
  
  				if (fireballChance != 0 && fireballChance > Utility.Random(100))
  				{
  					DoFireball(attacker, defender);
  				}
  
  				if (lightningChance != 0 && lightningChance > Utility.Random(100))
  				{
  					DoLightning(attacker, defender);
  				}
  
  				if (dispelChance != 0 && dispelChance > Utility.Random(100))
  				{
  					DoDispel(attacker, defender);
  				}
  
  				#region Stygian Abyss
  				if (curseChance != 0 && curseChance > Utility.Random(100))
  				{
  					DoCurse(attacker, defender);
  				}
  
  				if (fatigueChance != 0 && fatigueChance > Utility.Random(100))
  				{
  					DoFatigue(attacker, defender, damageGiven);
  				}
  
  				if (manadrainChance != 0 && manadrainChance > Utility.Random(100))
  				{
  					DoManaDrain(attacker, defender, damageGiven);
  				}
  				#endregion
  
  				int laChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerAttack) * propertyBonus);
  				int ldChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLowerDefend) * propertyBonus);
  
  				if (laChance != 0 && laChance > Utility.Random(100))
  				{
  					DoLowerAttack(attacker, defender);
  				}
  
  				if (ldChance != 0 && ldChance > Utility.Random(100))
  				{
  					DoLowerDefense(attacker, defender);
  				}
  			}
  
  			if (attacker is BaseCreature)
  			{
  				((BaseCreature)attacker).OnGaveMeleeAttack(defender);
  			}
  
  			if (defender is BaseCreature)
  			{
  				((BaseCreature)defender).OnGotMeleeAttack(attacker);
  			}
  
  			if (a != null)
  			{
  				a.OnHit(attacker, defender, damage);
  			}
  
  			if (move != null)
  			{
  				move.OnHit(attacker, defender, damage);
  			}
  
  			if (defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null)
  			{
  				((IHonorTarget)defender).ReceivedHonorContext.OnTargetHit(attacker);
  			}
  
  			if (!(this is BaseRanged))
  			{
  				if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent)))
  				{
  					defender.ApplyPoison(attacker, Poison.Lesser);
  				}
  
  				if (AnimalForm.UnderTransformation(defender, typeof(BullFrog)))
  				{
  					attacker.ApplyPoison(defender, Poison.Regular);
  				}
  			}
  
  			XmlAttach.OnWeaponHit(this, attacker, defender, damageGiven);
  		}
  
  		public virtual double GetAosDamage(Mobile attacker, int bonus, int dice, int sides)
  		{
  			int damage = Utility.Dice(dice, sides, bonus) * 100;
  			int damageBonus = 0;
  
  			// Inscription bonus
  			int inscribeSkill = attacker.Skills[SkillName.Inscribe].Fixed;
  
  			damageBonus += inscribeSkill / 200;
  
  			if (inscribeSkill >= 1000)
  			{
  				damageBonus += 5;
  			}
  
  			if (attacker.Player)
  			{
  				// Int bonus
  				damageBonus += (attacker.Int / 10);
  
  				// SDI bonus
  				damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage);
  
  				TransformContext context = TransformationSpellHelper.GetContext(attacker);
  
  				if (context != null && context.Spell is ReaperFormSpell)
  				{
  					damageBonus += ((ReaperFormSpell)context.Spell).SpellDamageBonus;
  				}
  			}
  
  			damage = AOS.Scale(damage, 100 + damageBonus);
  
  			return damage / 100;
  		}
  
  		#region Do<AoSEffect>
  		public virtual void DoMagicArrow(Mobile attacker, Mobile defender)
  		{
  			if (!attacker.CanBeHarmful(defender, false))
  			{
  				return;
  			}
  
  			attacker.DoHarmful(defender);
  
  			double damage = GetAosDamage(attacker, 10, 1, 4);
  
  			attacker.MovingParticles(defender, 0x36E4, 5, 0, false, true, 3006, 4006, 0);
  			attacker.PlaySound(0x1E5);
  
  			SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0);
  		}
  
  		public virtual void DoHarm(Mobile attacker, Mobile defender)
  		{
  			if (!attacker.CanBeHarmful(defender, false))
  			{
  				return;
  			}
  
  			attacker.DoHarmful(defender);
  
  			double damage = GetAosDamage(attacker, 17, 1, 5);
  
  			if (!defender.InRange(attacker, 2))
  			{
  				damage *= 0.25; // 1/4 damage at > 2 tile range
  			}
  			else if (!defender.InRange(attacker, 1))
  			{
  				damage *= 0.50; // 1/2 damage at 2 tile range
  			}
  
  			defender.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist);
  			defender.PlaySound(0x0FC);
  
  			SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 100, 0, 0);
  		}
  
  		public virtual void DoFireball(Mobile attacker, Mobile defender)
  		{
  			if (!attacker.CanBeHarmful(defender, false))
  			{
  				return;
  			}
  
  			attacker.DoHarmful(defender);
  
  			double damage = GetAosDamage(attacker, 19, 1, 5);
  
  			attacker.MovingParticles(defender, 0x36D4, 7, 0, false, true, 9502, 4019, 0x160);
  			attacker.PlaySound(0x15E);
  
  			SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0);
  		}
  
  		public virtual void DoLightning(Mobile attacker, Mobile defender)
  		{
  			if (!attacker.CanBeHarmful(defender, false))
  			{
  				return;
  			}
  
  			attacker.DoHarmful(defender);
  
  			double damage = GetAosDamage(attacker, 23, 1, 4);
  
  			defender.BoltEffect(0);
  
  			SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100);
  		}
  
  		public virtual void DoDispel(Mobile attacker, Mobile defender)
  		{
  			bool dispellable = false;
  
  			if (defender is BaseCreature)
  			{
  				dispellable = ((BaseCreature)defender).Summoned && !((BaseCreature)defender).IsAnimatedDead;
  			}
  
  			if (!dispellable)
  			{
  				return;
  			}
  
  			if (!attacker.CanBeHarmful(defender, false))
  			{
  				return;
  			}
  
  			attacker.DoHarmful(defender);
  
  			MagerySpell sp = new DispelSpell(attacker, null);
  
  			if (sp.CheckResisted(defender))
  			{
  				defender.FixedEffect(0x3779, 10, 20);
  			}
  			else
  			{
  				Effects.SendLocationParticles(
  					EffectItem.Create(defender.Location, defender.Map, EffectItem.DefaultDuration), 0x3728, 8, 20, 5042);
  				Effects.PlaySound(defender, defender.Map, 0x201);
  
  				defender.Delete();
  			}
  		}
  
  		#region Stygian Abyss
  		public virtual void DoCurse(Mobile attacker, Mobile defender)
  		{
  			attacker.SendLocalizedMessage(1113717); // You have hit your target with a curse effect.
  			defender.SendLocalizedMessage(1113718); // You have been hit with a curse effect.
  			defender.FixedParticles(0x374A, 10, 15, 5028, EffectLayer.Waist);
  			defender.PlaySound(0x1EA);
  			defender.AddStatMod(
  				new StatMod(StatType.Str, String.Format("[Magic] {0} Offset", StatType.Str), -10, TimeSpan.FromSeconds(30)));
  			defender.AddStatMod(
  				new StatMod(StatType.Dex, String.Format("[Magic] {0} Offset", StatType.Dex), -10, TimeSpan.FromSeconds(30)));
  			defender.AddStatMod(
  				new StatMod(StatType.Int, String.Format("[Magic] {0} Offset", StatType.Int), -10, TimeSpan.FromSeconds(30)));
  
  			int percentage = -10; //(int)(SpellHelper.GetOffsetScalar(Caster, m, true) * 100);
  			string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\t{6}", percentage, percentage, percentage, 10, 10, 10, 10);
  
  			BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.Curse, 1075835, 1075836, TimeSpan.FromSeconds(30), defender, args));
  		}
  
  		public virtual void DoFatigue(Mobile attacker, Mobile defender, int damagegiven)
  		{
  			// Message?
  			// Effects?
  			defender.Stam -= (damagegiven * (100 - m_AosWeaponAttributes.HitFatigue)) / 100;
  		}
  
  		public virtual void DoManaDrain(Mobile attacker, Mobile defender, int damagegiven)
  		{
  			// Message?
  			defender.FixedParticles(0x3789, 10, 25, 5032, EffectLayer.Head);
  			defender.PlaySound(0x1F8);
  			defender.Mana -= (damagegiven * (100 - m_AosWeaponAttributes.HitManaDrain)) / 100;
  		}
  		#endregion
  
  		public virtual void DoLowerAttack(Mobile from, Mobile defender)
  		{
  			if (HitLower.ApplyAttack(defender))
  			{
  				defender.PlaySound(0x28E);
  				Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0xA, 3);
  			}
  		}
  
  		public virtual void DoLowerDefense(Mobile from, Mobile defender)
  		{
  			if (HitLower.ApplyDefense(defender))
  			{
  				defender.PlaySound(0x28E);
  				Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0x23, 3);
  			}
  		}
  
  		public virtual void DoAreaAttack(
  			Mobile from, Mobile defender, int sound, int hue, int phys, int fire, int cold, int pois, int nrgy)
  		{
  			Map map = from.Map;
  
  			if (map == null)
  			{
  				return;
  			}
  
  			var list = new List<Mobile>();
  
  			foreach (Mobile m in from.GetMobilesInRange(10))
  			{
  				if (from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) && from.CanBeHarmful(m, false) &&
  					(!Core.ML || from.InLOS(m)))
  				{
  					list.Add(m);
  				}
  			}
  
  			if (list.Count == 0)
  			{
  				return;
  			}
  
  			Effects.PlaySound(from.Location, map, sound);
  
  			// TODO: What is the damage calculation?
  
  			for (int i = 0; i < list.Count; ++i)
  			{
  				Mobile m = list[i];
  
  				double scalar = (11 - from.GetDistanceToSqrt(m)) / 10;
  
  				if (scalar > 1.0)
  				{
  					scalar = 1.0;
  				}
  				else if (scalar < 0.0)
  				{
  					continue;
  				}
  
  				from.DoHarmful(m, true);
  				m.FixedEffect(0x3779, 1, 15, hue, 0);
  				AOS.Damage(m, from, (int)(GetBaseDamage(from) * scalar), phys, fire, cold, pois, nrgy);
  			}
  		}
  		#endregion
  
  		public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender)
  		{
  			BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;
  			SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkWeapon.Slayer);
  			SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon.Slayer2);
  
  			if (atkSlayer != null && atkSlayer.Slays(defender) || atkSlayer2 != null && atkSlayer2.Slays(defender))
  			{
  				return CheckSlayerResult.Slayer;
  			}
  
  			BaseTalisman talisman = attacker.Talisman as BaseTalisman;
  
  			if (talisman != null && TalismanSlayer.Slays(talisman.Slayer, defender))
  			{
  				return CheckSlayerResult.Slayer;
  			}
  
  			if (!Core.SE)
  			{
  				ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender);
  
  				if (defISlayer == null)
  				{
  					defISlayer = defender.Weapon as ISlayer;
  				}
  
  				if (defISlayer != null)
  				{
  					SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer);
  					SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2);
  
  					if (defSlayer != null && defSlayer.Group.OppositionSuperSlays(attacker) ||
  						defSlayer2 != null && defSlayer2.Group.OppositionSuperSlays(attacker))
  					{
  						return CheckSlayerResult.Opposition;
  					}
  				}
  			}
  
  			return CheckSlayerResult.None;
  		}
  
  		public virtual void AddBlood(Mobile attacker, Mobile defender, int damage)
  		{
  			if (damage > 0)
  			{
  				new Blood().MoveToWorld(defender.Location, defender.Map);
  
  				int extraBlood = (Core.SE ? Utility.RandomMinMax(3, 4) : Utility.RandomMinMax(0, 1));
  
  				for (int i = 0; i < extraBlood; i++)
  				{
  					new Blood().MoveToWorld(
  						new Point3D(defender.X + Utility.RandomMinMax(-1, 1), defender.Y + Utility.RandomMinMax(-1, 1), defender.Z),
  						defender.Map);
  				}
  			}
  		}
  
  		public virtual void GetDamageTypes(
  			Mobile wielder, out int phys, out int fire, out int cold, out int pois, out int nrgy, out int chaos, out int direct)
  		{
  			if (wielder is BaseCreature)
  			{
  				BaseCreature bc = (BaseCreature)wielder;
  
  				phys = bc.PhysicalDamage;
  				fire = bc.FireDamage;
  				cold = bc.ColdDamage;
  				pois = bc.PoisonDamage;
  				nrgy = bc.EnergyDamage;
  				chaos = bc.ChaosDamage;
  				direct = bc.DirectDamage;
  			}
  			else
  			{
  				fire = m_AosElementDamages.Fire;
  				cold = m_AosElementDamages.Cold;
  				pois = m_AosElementDamages.Poison;
  				nrgy = m_AosElementDamages.Energy;
  				chaos = m_AosElementDamages.Chaos;
  				direct = m_AosElementDamages.Direct;
  
  				phys = 100 - fire - cold - pois - nrgy - chaos - direct;
  
  				CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource);
  
  				if (resInfo != null)
  				{
  					CraftAttributeInfo attrInfo = resInfo.AttributeInfo;
  
  					if (attrInfo != null)
  					{
  						int left = phys;
  
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponColdDamage, ref cold, left);
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponEnergyDamage, ref nrgy, left);
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponFireDamage, ref fire, left);
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponPoisonDamage, ref pois, left);
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponChaosDamage, ref chaos, left);
  						left = ApplyCraftAttributeElementDamage(attrInfo.WeaponDirectDamage, ref direct, left);
  
  						phys = left;
  					}
  				}
  			}
  		}
  
  		private int ApplyCraftAttributeElementDamage(int attrDamage, ref int element, int totalRemaining)
  		{
  			if (totalRemaining <= 0)
  			{
  				return 0;
  			}
  
  			if (attrDamage <= 0)
  			{
  				return totalRemaining;
  			}
  
  			int appliedDamage = attrDamage;
  
  			if ((appliedDamage + element) > 100)
  			{
  				appliedDamage = 100 - element;
  			}
  
  			if (appliedDamage > totalRemaining)
  			{
  				appliedDamage = totalRemaining;
  			}
  
  			element += appliedDamage;
  
  			return totalRemaining - appliedDamage;
  		}
  
  		public virtual void OnMiss(Mobile attacker, Mobile defender)
  		{
  			PlaySwingAnimation(attacker);
  			attacker.PlaySound(GetMissAttackSound(attacker, defender));
  			defender.PlaySound(GetMissDefendSound(attacker, defender));
  
  			WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker);
  
  			if (ability != null)
  			{
  				ability.OnMiss(attacker, defender);
  			}
  
  			SpecialMove move = SpecialMove.GetCurrentMove(attacker);
  
  			if (move != null)
  			{
  				move.OnMiss(attacker, defender);
  			}
  
  			if (defender is IHonorTarget && ((IHonorTarget)defender).ReceivedHonorContext != null)
  			{
  				((IHonorTarget)defender).ReceivedHonorContext.OnTargetMissed(attacker);
  			}
  		}
  
  		public virtual void GetBaseDamageRange(Mobile attacker, out int min, out int max)
  		{
  			if (attacker is BaseCreature)
  			{
  				BaseCreature c = (BaseCreature)attacker;
  
  				if (c.DamageMin >= 0)
  				{
  					min = c.DamageMin;
  					max = c.DamageMax;
  					return;
  				}
  
  				if (this is Fists && !attacker.Body.IsHuman)
  				{
  					min = attacker.Str / 28;
  					max = attacker.Str / 28;
  					return;
  				}
  			}
  
  			min = MinDamage;
  			max = MaxDamage;
  		}
  
  		public virtual double GetBaseDamage(Mobile attacker)
  		{
  			int min, max;
  
  			GetBaseDamageRange(attacker, out min, out max);
  
  			int damage = Utility.RandomMinMax(min, max);
  
  			if (Core.AOS)
  			{
  				return damage;
  			}
  
  			/* Apply damage level offset
               * : Regular : 0
               * : Ruin    : 1
               * : Might   : 3
               * : Force   : 5
               * : Power   : 7
               * : Vanq    : 9
               */
  			if (m_DamageLevel != WeaponDamageLevel.Regular)
  			{
  				damage += (2 * (int)m_DamageLevel) - 1;
  			}
  
  			return damage;
  		}
  
  		public virtual double GetBonus(double value, double scalar, double threshold, double offset)
  		{
  			double bonus = value * scalar;
  
  			if (value >= threshold)
  			{
  				bonus += offset;
  			}
  
  			return bonus / 100;
  		}
  
  		public virtual int GetHitChanceBonus()
  		{
  			if (!Core.AOS)
  			{
  				return 0;
  			}
  
  			int bonus = 0;
  
  			switch (m_AccuracyLevel)
  			{
  				case WeaponAccuracyLevel.Accurate:
  					bonus += 02;
  					break;
  				case WeaponAccuracyLevel.Surpassingly:
  					bonus += 04;
  					break;
  				case WeaponAccuracyLevel.Eminently:
  					bonus += 06;
  					break;
  				case WeaponAccuracyLevel.Exceedingly:
  					bonus += 08;
  					break;
  				case WeaponAccuracyLevel.Supremely:
  					bonus += 10;
  					break;
  			}
  
  			return bonus;
  		}
  
  		public virtual int GetDamageBonus()
  		{
  			int bonus = VirtualDamageBonus;
  
  			switch (m_Quality)
  			{
  				case WeaponQuality.Low:
  					bonus -= 20;
  					break;
  				case WeaponQuality.Exceptional:
  					bonus += 20;
  					break;
  			}
  
  			switch (m_DamageLevel)
  			{
  				case WeaponDamageLevel.Ruin:
  					bonus += 15;
  					break;
  				case WeaponDamageLevel.Might:
  					bonus += 20;
  					break;
  				case WeaponDamageLevel.Force:
  					bonus += 25;
  					break;
  				case WeaponDamageLevel.Power:
  					bonus += 30;
  					break;
  				case WeaponDamageLevel.Vanq:
  					bonus += 35;
  					break;
  			}
  
  			return bonus;
  		}
  
  		public virtual void GetStatusDamage(Mobile from, out int min, out int max)
  		{
  			int baseMin, baseMax;
  
  			GetBaseDamageRange(from, out baseMin, out baseMax);
  
  			if (Core.AOS)
  			{
  				min = Math.Max((int)ScaleDamageAOS(from, baseMin, false), 1);
  				max = Math.Max((int)ScaleDamageAOS(from, baseMax, false), 1);
  			}
  			else
  			{
  				min = Math.Max((int)ScaleDamageOld(from, baseMin, false), 1);
  				max = Math.Max((int)ScaleDamageOld(from, baseMax, false), 1);
  			}
  		}
  
  		public virtual double ScaleDamageAOS(Mobile attacker, double damage, bool checkSkills)
  		{
  			if (checkSkills)
  			{
  				attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills[SkillName.Tactics].Cap);
  					// Passively check tactics for gain
  				attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills[SkillName.Anatomy].Cap);
  					// Passively check Anatomy for gain
  
  				if (Type == WeaponType.Axe)
  				{
  					attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain
  				}
  			}
  
  			#region Physical bonuses
  			/*
              * These are the bonuses given by the physical characteristics of the mobile.
              * No caps apply.
              */
  			double strengthBonus = GetBonus(attacker.Str, 0.300, 100.0, 5.00);
  			double anatomyBonus = GetBonus(attacker.Skills[SkillName.Anatomy].Value, 0.500, 100.0, 5.00);
  			double tacticsBonus = GetBonus(attacker.Skills[SkillName.Tactics].Value, 0.625, 100.0, 6.25);
  			double lumberBonus = GetBonus(attacker.Skills[SkillName.Lumberjacking].Value, 0.200, 100.0, 10.00);
  
  			if (Type != WeaponType.Axe)
  			{
  				lumberBonus = 0.0;
  			}
  			#endregion
  
  			#region Modifiers
  			/*
              * The following are damage modifiers whose effect shows on the status bar.
              * Capped at 100% total.
              */
  			int damageBonus = AosAttributes.GetValue(attacker, AosAttribute.WeaponDamage);
  
  			// Horrific Beast transformation gives a +25% bonus to damage.
  			if (TransformationSpellHelper.UnderTransformation(attacker, typeof(HorrificBeastSpell)))
  			{
  				damageBonus += 25;
  			}
  
  			// Divine Fury gives a +10% bonus to damage.
  			if (DivineFurySpell.UnderEffect(attacker))
  			{
  				damageBonus += 10;
  			}
  
  			int defenseMasteryMalus = 0;
  
  			// Defense Mastery gives a -50%/-80% malus to damage.
  			if (DefenseMastery.GetMalus(attacker, ref defenseMasteryMalus))
  			{
  				damageBonus -= defenseMasteryMalus;
  			}
  
  			int discordanceEffect = 0;
  
  			// Discordance gives a -2%/-48% malus to damage.
  			if (Discordance.GetEffect(attacker, ref discordanceEffect))
  			{
  				damageBonus -= discordanceEffect * 2;
  			}
  
  			if (damageBonus > 100)
  			{
  				damageBonus = 100;
  			}
  			#endregion
  
  			double totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus +
  								((GetDamageBonus() + damageBonus) / 100.0);
  
  			return damage + (int)(damage * totalBonus);
  		}
  
  		public virtual int VirtualDamageBonus { get { return 0; } }
  
  		public virtual int ComputeDamageAOS(Mobile attacker, Mobile defender)
  		{
  			return (int)ScaleDamageAOS(attacker, GetBaseDamage(attacker), true);
  		}
  
  		public virtual double ScaleDamageOld(Mobile attacker, double damage, bool checkSkills)
  		{
  			if (checkSkills)
  			{
  				attacker.CheckSkill(SkillName.Tactics, 0.0, attacker.Skills[SkillName.Tactics].Cap);
  					// Passively check tactics for gain
  				attacker.CheckSkill(SkillName.Anatomy, 0.0, attacker.Skills[SkillName.Anatomy].Cap);
  					// Passively check Anatomy for gain
  
  				if (Type == WeaponType.Axe)
  				{
  					attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 100.0); // Passively check Lumberjacking for gain
  				}
  			}
  
  			/* Compute tactics modifier
              * :   0.0 = 50% loss
              * :  50.0 = unchanged
              * : 100.0 = 50% bonus
              */
  			damage += (damage * ((attacker.Skills[SkillName.Tactics].Value - 50.0) / 100.0));
  
  			/* Compute strength modifier
              * : 1% bonus for every 5 strength
              */
  			double modifiers = (attacker.Str / 5.0) / 100.0;
  
  			/* Compute anatomy modifier
              * : 1% bonus for every 5 points of anatomy
              * : +10% bonus at Grandmaster or higher
              */
  			double anatomyValue = attacker.Skills[SkillName.Anatomy].Value;
  			modifiers += ((anatomyValue / 5.0) / 100.0);
  
  			if (anatomyValue >= 100.0)
  			{
  				modifiers += 0.1;
  			}
  
  			/* Compute lumberjacking bonus
              * : 1% bonus for every 5 points of lumberjacking
              * : +10% bonus at Grandmaster or higher
              */
  
  			if (Type == WeaponType.Axe)
  			{
  				double lumberValue = attacker.Skills[SkillName.Lumberjacking].Value;
  
  				modifiers += ((lumberValue / 5.0) / 100.0);
  
  				if (lumberValue >= 100.0)
  				{
  					modifiers += 0.1;
  				}
  			}
  
  			// New quality bonus:
  			if (m_Quality != WeaponQuality.Regular)
  			{
  				modifiers += (((int)m_Quality - 1) * 0.2);
  			}
  
  			// Virtual damage bonus:
  			if (VirtualDamageBonus != 0)
  			{
  				modifiers += (VirtualDamageBonus / 100.0);
  			}
  
  			// Apply bonuses
  			damage += (damage * modifiers);
  
  			return ScaleDamageByDurability((int)damage);
  		}
  
  		public virtual int ScaleDamageByDurability(int damage)
  		{
  			int scale = 100;
  
  			if (m_MaxHits > 0 && m_Hits < m_MaxHits)
  			{
  				scale = 50 + ((50 * m_Hits) / m_MaxHits);
  			}
  
  			return AOS.Scale(damage, scale);
  		}
  
  		public virtual int ComputeDamage(Mobile attacker, Mobile defender)
  		{
  			if (Core.AOS)
  			{
  				return ComputeDamageAOS(attacker, defender);
  			}
  
  			int damage = (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true);
  
  			// pre-AOS, halve damage if the defender is a player or the attacker is not a player
  			if (defender is PlayerMobile || !(attacker is PlayerMobile))
  			{
  				damage = (int)(damage / 2.0);
  			}
  
  			return damage;
  		}
  
  		public virtual void PlayHurtAnimation(Mobile from)
  		{
  			int action;
  			int frames;
  
  			switch (from.Body.Type)
  			{
  				case BodyType.Sea:
  				case BodyType.Animal:
  					{
  						action = 7;
  						frames = 5;
  						break;
  					}
  				case BodyType.Monster:
  					{
  						action = 10;
  						frames = 4;
  						break;
  					}
  				case BodyType.Human:
  					{
  						action = 20;
  						frames = 5;
  						break;
  					}
  				default:
  					return;
  			}
  
  			if (from.Mounted)
  			{
  				return;
  			}
  
  			from.Animate(action, frames, 1, true, false, 0);
  		}
  
  		public virtual void PlaySwingAnimation(Mobile from)
  		{
  			int action;
  
  			switch (from.Body.Type)
  			{
  				case BodyType.Sea:
  				case BodyType.Animal:
  					{
  						action = Utility.Random(5, 2);
  						break;
  					}
  				case BodyType.Monster:
  					{
  						switch (Animation)
  						{
  							default:
  							case WeaponAnimation.Wrestle:
  							case WeaponAnimation.Bash1H:
  							case WeaponAnimation.Pierce1H:
  							case WeaponAnimation.Slash1H:
  							case WeaponAnimation.Bash2H:
  							case WeaponAnimation.Pierce2H:
  							case WeaponAnimation.Slash2H:
  								action = Utility.Random(4, 3);
  								break;
  							case WeaponAnimation.ShootBow:
  								return; // 7
  							case WeaponAnimation.ShootXBow:
  								return; // 8
  						}
  
  						break;
  					}
  				case BodyType.Human:
  					{
  						if (!from.Mounted)
  						{
  							action = (int)Animation;
  						}
  						else
  						{
  							switch (Animation)
  							{
  								default:
  								case WeaponAnimation.Wrestle:
  								case WeaponAnimation.Bash1H:
  								case WeaponAnimation.Pierce1H:
  								case WeaponAnimation.Slash1H:
  									action = 26;
  									break;
  								case WeaponAnimation.Bash2H:
  								case WeaponAnimation.Pierce2H:
  								case WeaponAnimation.Slash2H:
  									action = 29;
  									break;
  								case WeaponAnimation.ShootBow:
  									action = 27;
  									break;
  								case WeaponAnimation.ShootXBow:
  									action = 28;
  									break;
  							}
  						}
  
  						break;
  					}
  				default:
  					return;
  			}
  
  			from.Animate(action, 7, 1, true, false, 0);
  		}
  
  		#region Serialization/Deserialization
  		private static void SetSaveFlag(ref SaveFlag flags, SaveFlag toSet, bool setIf)
  		{
  			if (setIf)
  			{
  				flags |= toSet;
  			}
  		}
  
  		private static bool GetSaveFlag(SaveFlag flags, SaveFlag toGet)
  		{
  			return ((flags & toGet) != 0);
  		}
  
  		public override void Serialize(GenericWriter writer)
  		{
  			base.Serialize(writer);
  
  			writer.Write(12); // version
  
  			//Version 12
  			#region SF Imbuing
  			writer.Write((bool)m_DImodded);
  			#endregion
  
  			// Version 11
  			writer.Write(m_TimesImbued);
  
  			// Version 10
  			writer.Write(m_BlessedBy); // Bless Deed
  
  			#region Veteran Rewards
  			writer.Write(m_EngravedText);
  			#endregion
  
  			#region Mondain's Legacy
  			writer.Write((int)m_Slayer3);
  			#endregion
  
  			#region Mondain's Legacy Sets
  			SetFlag sflags = SetFlag.None;
  
  			SetSaveFlag(ref sflags, SetFlag.Attributes, !m_SetAttributes.IsEmpty);
  			SetSaveFlag(ref sflags, SetFlag.SkillBonuses, !m_SetSkillBonuses.IsEmpty);
  			SetSaveFlag(ref sflags, SetFlag.Hue, m_SetHue != 0);
  			SetSaveFlag(ref sflags, SetFlag.LastEquipped, m_LastEquipped);
  			SetSaveFlag(ref sflags, SetFlag.SetEquipped, m_SetEquipped);
  			SetSaveFlag(ref sflags, SetFlag.SetSelfRepair, m_SetSelfRepair != 0);
  
  			writer.WriteEncodedInt((int)sflags);
  
  			if (GetSaveFlag(sflags, SetFlag.Attributes))
  			{
  				m_SetAttributes.Serialize(writer);
  			}
  
  			if (GetSaveFlag(sflags, SetFlag.SkillBonuses))
  			{
  				m_SetSkillBonuses.Serialize(writer);
  			}
  
  			if (GetSaveFlag(sflags, SetFlag.Hue))
  			{
  				writer.Write(m_SetHue);
  			}
  
  			if (GetSaveFlag(sflags, SetFlag.LastEquipped))
  			{
  				writer.Write(m_LastEquipped);
  			}
  
  			if (GetSaveFlag(sflags, SetFlag.SetEquipped))
  			{
  				writer.Write(m_SetEquipped);
  			}
  
  			if (GetSaveFlag(sflags, SetFlag.SetSelfRepair))
  			{
  				writer.WriteEncodedInt(m_SetSelfRepair);
  			}
  			#endregion
  
  			// Version 9
  			SaveFlag flags = SaveFlag.None;
  
  			SetSaveFlag(ref flags, SaveFlag.DamageLevel, m_DamageLevel != WeaponDamageLevel.Regular);
  			SetSaveFlag(ref flags, SaveFlag.AccuracyLevel, m_AccuracyLevel != WeaponAccuracyLevel.Regular);
  			SetSaveFlag(ref flags, SaveFlag.DurabilityLevel, m_DurabilityLevel != WeaponDurabilityLevel.Regular);
  			SetSaveFlag(ref flags, SaveFlag.Quality, m_Quality != WeaponQuality.Regular);
  			SetSaveFlag(ref flags, SaveFlag.Hits, m_Hits != 0);
  			SetSaveFlag(ref flags, SaveFlag.MaxHits, m_MaxHits != 0);
  			SetSaveFlag(ref flags, SaveFlag.Slayer, m_Slayer != SlayerName.None);
  			SetSaveFlag(ref flags, SaveFlag.Poison, m_Poison != null);
  			SetSaveFlag(ref flags, SaveFlag.PoisonCharges, m_PoisonCharges != 0);
  			SetSaveFlag(ref flags, SaveFlag.Crafter, m_Crafter != null);
  			SetSaveFlag(ref flags, SaveFlag.Identified, m_Identified);
  			SetSaveFlag(ref flags, SaveFlag.StrReq, m_StrReq != -1);
  			SetSaveFlag(ref flags, SaveFlag.DexReq, m_DexReq != -1);
  			SetSaveFlag(ref flags, SaveFlag.IntReq, m_IntReq != -1);
  			SetSaveFlag(ref flags, SaveFlag.MinDamage, m_MinDamage != -1);
  			SetSaveFlag(ref flags, SaveFlag.MaxDamage, m_MaxDamage != -1);
  			SetSaveFlag(ref flags, SaveFlag.HitSound, m_HitSound != -1);
  			SetSaveFlag(ref flags, SaveFlag.MissSound, m_MissSound != -1);
  			SetSaveFlag(ref flags, SaveFlag.Speed, m_Speed != -1);
  			SetSaveFlag(ref flags, SaveFlag.MaxRange, m_MaxRange != -1);
  			SetSaveFlag(ref flags, SaveFlag.Skill, m_Skill != (SkillName)(-1));
  			SetSaveFlag(ref flags, SaveFlag.Type, m_Type != (WeaponType)(-1));
  			SetSaveFlag(ref flags, SaveFlag.Animation, m_Animation != (WeaponAnimation)(-1));
  			SetSaveFlag(ref flags, SaveFlag.Resource, m_Resource != CraftResource.Iron);
  			SetSaveFlag(ref flags, SaveFlag.xAttributes, !m_AosAttributes.IsEmpty);
  			SetSaveFlag(ref flags, SaveFlag.xWeaponAttributes, !m_AosWeaponAttributes.IsEmpty);
  			SetSaveFlag(ref flags, SaveFlag.PlayerConstructed, m_PlayerConstructed);
  			SetSaveFlag(ref flags, SaveFlag.SkillBonuses, !m_AosSkillBonuses.IsEmpty);
  			SetSaveFlag(ref flags, SaveFlag.Slayer2, m_Slayer2 != SlayerName.None);
  			SetSaveFlag(ref flags, SaveFlag.ElementalDamages, !m_AosElementDamages.IsEmpty);
  			SetSaveFlag(ref flags, SaveFlag.EngravedText, !String.IsNullOrEmpty(m_EngravedText));
  			SetSaveFlag(ref flags, SaveFlag.xAbsorptionAttributes, !m_SAAbsorptionAttributes.IsEmpty);
  
  			writer.Write((int)flags);
  
  			if (GetSaveFlag(flags, SaveFlag.DamageLevel))
  			{
  				writer.Write((int)m_DamageLevel);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.AccuracyLevel))
  			{
  				writer.Write((int)m_AccuracyLevel);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.DurabilityLevel))
  			{
  				writer.Write((int)m_DurabilityLevel);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Quality))
  			{
  				writer.Write((int)m_Quality);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Hits))
  			{
  				writer.Write(m_Hits);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.MaxHits))
  			{
  				writer.Write(m_MaxHits);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Slayer))
  			{
  				writer.Write((int)m_Slayer);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Poison))
  			{
  				Poison.Serialize(m_Poison, writer);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.PoisonCharges))
  			{
  				writer.Write(m_PoisonCharges);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Crafter))
  			{
  				writer.Write(m_Crafter);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.StrReq))
  			{
  				writer.Write(m_StrReq);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.DexReq))
  			{
  				writer.Write(m_DexReq);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.IntReq))
  			{
  				writer.Write(m_IntReq);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.MinDamage))
  			{
  				writer.Write(m_MinDamage);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.MaxDamage))
  			{
  				writer.Write(m_MaxDamage);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.HitSound))
  			{
  				writer.Write(m_HitSound);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.MissSound))
  			{
  				writer.Write(m_MissSound);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Speed))
  			{
  				writer.Write(m_Speed);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.MaxRange))
  			{
  				writer.Write(m_MaxRange);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Skill))
  			{
  				writer.Write((int)m_Skill);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Type))
  			{
  				writer.Write((int)m_Type);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Animation))
  			{
  				writer.Write((int)m_Animation);
  			}
  
  			if (GetSaveFlag(flags, SaveFlag.Resource))
  			{
  				writer.Write((int)m_Resource);
  			}
  
  
gt: 			if (GetSaveFlag(flags, SaveFlag.xAttributes))