using System;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using Server.Network;
using Server.Targeting;
using Server.Mobiles;
using Server.Factions;
using Server.Engines.Craft;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Spells.Bushido;
using Server.Spells.Ninjitsu;
using Server.Spells.Spellweaving;

namespace Server.Items
{
    public interface ISlayer
    {
        SlayerName Slayer { get; set; }
        SlayerName Slayer2 { get; set; }
    }

    public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability
    {
        #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;
        private SkillMod m_SkillMod, m_MageMod;
        private CraftResource m_Resource;
        private bool m_PlayerConstructed;

        private bool m_Immolating; // Is this weapon immolating via Immolating Weapon arcanist spell? Temporary; not serialized.
        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.

        private AosAttributes m_AosAttributes;
        private AosWeaponAttributes m_AosWeaponAttributes;
        private AosSkillBonuses m_AosSkillBonuses;
        private AosElementAttributes m_AosElementDamages;

        // 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 int m_Speed;
        private int m_MaxRange;
        private SkillName m_Skill;
        private WeaponType m_Type;
        private WeaponAnimation m_Animation;
        private WeaponAbility m_PrimaryAbilityNew;
        private WeaponAbility m_SecondaryAbilityNew;
        private WeaponAbility.AbilityType m_NewPrimaryAbility;
        private WeaponAbility.AbilityType m_NewSecondaryAbility;
        private bool m_IsUWItem;
        #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 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 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; } }
        #endregion

        #region Getters & Setters
        [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 { }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public bool Immolating
        {
            get { return m_Immolating; }
            set { m_Immolating = value; }
        }

        [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; }
        }

        [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 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 ? !m_IsUWItem ? AosMaxRange : OldMaxRange : m_MaxRange); }
            set { m_MaxRange = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public WeaponAnimation Animation
        {
            get { return (m_Animation == (WeaponAnimation)(-1) ? !m_IsUWItem ? AosAnimation : OldAnimation : m_Animation); }
            set { m_Animation = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public WeaponType Type
        {
            get { return (m_Type == (WeaponType)(-1) ? !m_IsUWItem ? AosType : OldType : m_Type); }
            set { m_Type = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public SkillName Skill
        {
            get { return (m_Skill == (SkillName)(-1) ? !m_IsUWItem ? AosSkill : OldSkill : m_Skill); }
            set { m_Skill = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int HitSound
        {
            get { return (m_HitSound == -1 ? !m_IsUWItem ? AosHitSound : OldHitSound : m_HitSound); }
            set { m_HitSound = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int MissSound
        {
            get { return (m_MissSound == -1 ? !m_IsUWItem ? AosMissSound : OldMissSound : m_MissSound); }
            set { m_MissSound = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int MinDamage
        {
            get { return (m_MinDamage == -1 ? !m_IsUWItem ? AosMinDamage : OldMinDamage : m_MinDamage); }
            set { m_MinDamage = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int MaxDamage
        {
            get { return (m_MaxDamage == -1 ? !m_IsUWItem ? AosMaxDamage : OldMaxDamage : m_MaxDamage); }
            set { m_MaxDamage = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int Speed
        {
            get { return (m_Speed == -1 ? !m_IsUWItem ? AosSpeed : OldSpeed : m_Speed); }
            set { m_Speed = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int StrRequirement
        {
            get { return (m_StrReq == -1 ? !m_IsUWItem ? AosStrengthReq : OldStrengthReq : m_StrReq); }
            set { m_StrReq = value; InvalidateProperties(); }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int DexRequirement
        {
            get { return (m_DexReq == -1 ? !m_IsUWItem ? AosDexterityReq : OldDexterityReq : m_DexReq); }
            set { m_DexReq = value; }
        }

        [CommandProperty(AccessLevel.GameMaster)]
        public int IntRequirement
        {
            get { return (m_IntReq == -1 ? !m_IsUWItem ? 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();
                }
            }
        }

        public WeaponAbility PrimaryAbilityNew { get { return m_PrimaryAbilityNew; } set { m_PrimaryAbilityNew = value; InvalidateProperties(); } }
        public WeaponAbility SecondaryAbilityNew { get { return m_SecondaryAbilityNew; } set { m_SecondaryAbilityNew = value; InvalidateProperties(); } }

        [CommandProperty(AccessLevel.GameMaster)]
        public bool IsUWItem { get { return m_IsUWItem; } set { m_IsUWItem = value; InvalidateProperties(); } }

        [CommandProperty(AccessLevel.GameMaster)]
        public WeaponAbility.AbilityType NewPrimaryAbility { get { return m_NewPrimaryAbility; } set { m_NewPrimaryAbility = value; m_PrimaryAbilityNew = WeaponAbility.GetNewAbility(m_NewPrimaryAbility); } }

        [CommandProperty(AccessLevel.GameMaster)]
        public WeaponAbility.AbilityType NewSecondaryAbility { get { return m_NewSecondaryAbility; } set { m_NewSecondaryAbility = value; m_SecondaryAbilityNew = WeaponAbility.GetNewAbility(m_NewSecondaryAbility); } }
        #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 (!m_IsUWItem)
            {
                bonus += m_AosWeaponAttributes.DurabilityBonus;

                CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource);
                CraftAttributeInfo attrInfo = null;

                if (resInfo != null)
                    attrInfo = resInfo.AttributeInfo;

                if (attrInfo != null)
                    bonus += attrInfo.WeaponDurability;
            }
            else
            {
                switch (m_Resource)
                {
                    case CraftResource.DullCopper: bonus += 10; break;
                    case CraftResource.ShadowIron: bonus += 15; break;
                    case CraftResource.Copper: bonus += 20; break;
                    case CraftResource.Bronze: bonus += 25; break;
                    case CraftResource.Gold: bonus += 30; break;
                    case CraftResource.Agapite: bonus += 40; break;
                    case CraftResource.Verite: bonus += 50; break;
                    case CraftResource.Valorite: bonus += 60; break;
                }
            }

            return bonus;
        }

        public int GetLowerStatReq()
        {
            if (!Core.AOS)
                return 0;

            int v = m_AosWeaponAttributes.LowerStatReq;

            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 Mobile m_Mobile;

            public ResetEquipTimer(Mobile m, TimeSpan duration)
            : base(duration)
            {
                m_Mobile = m;
            }

            protected override void OnTick()
            {
                m_Mobile.EndAction(typeof(BaseWeapon));
                m_Mobile.SendLocalizedMessage(1060168); //Your confusion has passed, you may now arm a weapon!
            }
        }

        public override bool CheckConflictingLayer(Mobile m, Item item, Layer layer)
        {
            if (base.CheckConflictingLayer(m, item, layer))
                return true;

            if (this.Layer == Layer.TwoHanded && layer == Layer.OneHanded)
            {
                m.SendLocalizedMessage(500214); // You already have something in both hands.
                return true;
            }
            else if (this.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 (!Ethics.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

        public override bool CanEquip(Mobile from)
        {
            if (!Ethics.Ethic.CheckEquip(from, this))
                return false;

            if (RequiredRace != null && from.Race != RequiredRace)
            {
                if (RequiredRace == Race.Elf)
                    from.SendLocalizedMessage(1072203); // Only Elves may use this.
                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;
            }
            else
                // XmlAttachment check for CanEquip
                if (!Server.Engines.XmlSpawner2.XmlAttach.CheckCanEquip(this, from))
            {
                return false;
            }
            else if (IsUWItem && from.Map != Map.Underworld)
            {
                from.SendMessage("Tento predmet lze pouzit pouze na mape Underworld");
                return false;
            }
            else if (!IsUWItem && from.Map == Map.Underworld)
            {
                from.SendMessage("Tento predmet nelze pouzit na mape Underworld");
                return false;
            }
            else
            {
                return base.CanEquip(from);
            }
        }

        public virtual bool UseSkillMod { get { return m_IsUWItem; } }

        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 = this.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 = DateTime.Now + GetDelay(from);

            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);
            }

            // XmlAttachment check for OnEquip
            Server.Engines.XmlSpawner2.XmlAttach.CheckOnEquip(this, from);

            return true;
        }

        public override void OnAdded(object parent)
        {
            base.OnAdded(parent);

            if (parent is Mobile)
            {
                Mobile from = (Mobile)parent;

                m_AosSkillBonuses.AddTo(from);

                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 = this.Serial.ToString();

                m.RemoveStatMod(modName + "Str");
                m.RemoveStatMod(modName + "Dex");
                m.RemoveStatMod(modName + "Int");

                if (weapon != null)
                    m.NextCombatTime = DateTime.Now + weapon.GetDelay(m);

                if (UseSkillMod && m_SkillMod != null)
                {
                    m_SkillMod.Remove();
                    m_SkillMod = null;
                }

                if (m_MageMod != null)
                {
                    m_MageMod.Remove();
                    m_MageMod = null;
                }

                m_AosSkillBonuses.Remove();

                m.CheckStatTimers();

                m.Delta(MobileDelta.WeaponDamage);
            }

            // XmlAttachment check for OnRemoved
            Server.Engines.XmlSpawner2.XmlAttach.CheckOnRemoved(this, parent);
        }

        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);

            //attacker.CheckSkill( atkSkill.SkillName, defValue - 20.0, 120.0 );
            //defender.CheckSkill( defSkill.SkillName, atkValue - 20.0, 120.0 );

            double ourValue, theirValue;

            int bonus = GetHitChanceBonus();

            if (attacker.Map != Map.Underworld)
            {
                if (atkValue <= -20.0)
                    atkValue = -19.9;

                if (defValue <= -20.0)
                    defValue = -19.9;

                // Hit Chance Increase = 55%
                int atkChance = AosAttributes.GetValue(attacker, AosAttribute.AttackChance);
                if (!attacker.Player && atkChance > 55)
                    atkChance = 55;

                bonus += atkChance;

                if (Spells.Chivalry.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

                ourValue = (atkValue + 20.0) * (100 + bonus);

                // Defense Chance Increase = 55%
                bonus = AosAttributes.GetValue(defender, AosAttribute.DefendChance);
                if (bonus > 55)
                    bonus = 55;

                if (Spells.Chivalry.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 (SkillHandlers.Discordance.GetEffect(attacker, ref discordanceEffect))
                    bonus -= discordanceEffect;

                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);

                //Pridano zvyseni hit chance pro hrace
                if (attacker.Player)
                    ourValue += 30;

                theirValue = (defValue + 50.0);

                return attacker.CheckSkill(atkSkill.SkillName, ourValue / (theirValue * 2.0));
            }

            double chance = ourValue / (theirValue * 2.0);

            chance *= 1.0 + ((double)bonus / 100);

            if (chance < 0.02)
                chance = 0.02;

            WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker);

            if (ability != null)
                chance *= ability.AccuracyScalar;

            SpecialMove move = SpecialMove.GetCurrentMove(attacker);

            if (move != null)
                chance *= move.GetAccuracyScalar(attacker);

            return attacker.CheckSkill(atkSkill.SkillName, chance);

            //return ( chance >= Utility.RandomDouble() );
        }

        public virtual TimeSpan GetDelay(Mobile m)
        {
            int speed = this.Speed;

            if (speed == 0)
                return TimeSpan.FromHours(1.0);

            if (m.Map == Map.Underworld)
            {
                int v = (m.Stam + 100) * speed;

                if (v <= 0)
                    v = 1;

                return TimeSpan.FromSeconds(15000.0 / v);
            }

            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 (Spells.Chivalry.DivineFurySpell.UnderEffect(m))
                    bonus += 10;

                // Bonus granted by successful use of Honorable Execution.
                bonus += HonorableExecution.GetSwingBonus(m);

                if (DualWield.Registry.Contains(m))
                {
                    if (this is RazorClaws)
                        return TimeSpan.FromSeconds(0.75);

                    bonus += ((DualWield.DualWieldTimer)DualWield.Registry[m]).BonusSwingSpeed;
                }

                if (Feint.Registry.Contains(m))
                    bonus -= ((Feint.FeintTimer)Feint.Registry[m]).SwingSpeedReduction;

                int discordanceEffect = 0;

                // Discordance gives a malus of -0/-28% to swing speed.
                if (SkillHandlers.Discordance.GetEffect(m, ref discordanceEffect))
                    bonus -= discordanceEffect;

                if (bonus > 60)
                    bonus = 60;

                speed = (int)Math.Floor(speed * (bonus + 100.0) / 100.0);

                if (speed <= 0)
                    speed = 1;

                int ticks = (int)Math.Floor((80000.0 / ((m.Stam + 100) * speed)) - 2);

                // Swing speed currently capped at one swing every 1.25 seconds (5 ticks).
                if (ticks < 4)
                    ticks = 4;

                delayInSeconds = ticks * 0.25;
            }
            else if (Core.AOS)
            {
                // 				int v = (m.Stam + 100) * speed;
                int v = (m.Stam + 200) * speed;

                int bonus = AosAttributes.GetValue(m, AosAttribute.WeaponSpeed);

                if (Spells.Chivalry.DivineFurySpell.UnderEffect(m))
                    bonus += 10;

                int discordanceEffect = 0;

                // Discordance gives a malus of -0/-28% to swing speed.
                if (SkillHandlers.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.0)
                    delayInSeconds = 1.0;
            }
            else
            {
                // 				int v = (m.Stam + 100) * speed;
                int v = (m.Stam + 200) * 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 (!m_IsUWItem)
            {
                canSwing = (!attacker.Paralyzed && !attacker.Frozen);

                if (canSwing)
                {
                    Spell sp = attacker.Spell as Spell;

                    canSwing = (sp == null || !sp.IsCasting || !sp.BlocksMovement);
                }
            }

            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)
        {
            return CheckParry(defender, false);
        }

        public static bool CheckParry(Mobile defender, bool spell)
        {
            if (defender == null)
                return false;

            BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;

            if (shield != null)
            {
                if (spell && (shield.Attributes.SpellChanneling < 1 || defender.Map == Map.Underworld))
                    return false;

                double parry = defender.Skills[SkillName.Parry].Value;
                double chance = parry / 450.0;	//As per OSI, no negitive effect from the Racial stuffs, ie, 120 bushido and '0' parry with humans

                if (chance > 0.3)
                    chance = 0.3;

                if (parry >= 120.0)
                {
                    parry += 0.05;
                }

                // Evasion grants a 50% bonus.
                if (Evasion.IsEvading(defender))
                    chance *= 1.5;

                // 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) && !(defender.Weapon is NoAmmoRanged) && !(defender.Weapon is MagicRanged))
            {
                BaseWeapon weapon = defender.Weapon as BaseWeapon;

                if (weapon == null || weapon.Layer == Layer.OneHanded)
                    return false;

                if (spell && (weapon.Attributes.SpellChanneling < 1 || defender.Map == Map.Underworld))
                    return false;

                double bushido = defender.Skills[SkillName.Bushido].Value;
                double chance = bushido / 450.0;

                if (chance > 0.3)
                    chance = 0.3;

                if (bushido >= 120.0)
                {
                    chance += 0.05;
                }

                // Evasion grants a 50% bonus.
                if (Evasion.IsEvading(defender))
                    chance *= 1.5;

                // Low dexterity lowers the chance.
                if (defender.Dex < 80)
                    chance = chance * (20 + defender.Dex) / 100;

                return (chance > Utility.RandomDouble());
            }

            return false;
        }

        public virtual int AbsorbDamageAOS(Mobile attacker, Mobile defender, int damage)
        {
            bool blocked = false;
            int originaldamage = damage;

            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)
                            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);

                        // XmlAttachment check for OnArmorHit
                        Server.Engines.XmlSpawner2.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

                    // XmlAttachment check for OnArmorHit
                    damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, armorItem, this, originaldamage);
                }
            }

            return damage;
        }

        public virtual int AbsorbDamage(Mobile attacker, Mobile defender, int damage)
        {
            if (defender.Map != Map.Underworld)
                return AbsorbDamageAOS(attacker, defender, 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);

            BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
            if (shield != null)
                damage = shield.OnHit(this, damage);

            // XmlAttachment check for OnArmorHit
            damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, armorItem, this, damage);
            damage -= Server.Engines.XmlSpawner2.XmlAttach.OnArmorHit(attacker, defender, shield, this, damage);

            int virtualArmor = defender.VirtualArmor + defender.VirtualArmorMod;

            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(3))
            {
                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 >= 2 && !(this is Xanthos.Evo.BaseEvo))
                bc.BandageSelf();

            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 virtual void UWOnHit(Mobile attacker, Mobile defender, double damageBonus)
        {
            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);

            if (a != null)
            {
                percentageBonus += (int)(a.DamageScalar * 100) - 100;
            }

            CheckSlayerResult cs = CheckSlayers(attacker, defender);

            if (m_Identified && cs != CheckSlayerResult.None)
            {
                if (cs == CheckSlayerResult.Slayer)
                    defender.FixedEffect(0x37B9, 10, 5);

                percentageBonus += 100;
            }

            int packInstinctBonus = GetPackInstinctBonus(attacker, defender);

            if (packInstinctBonus != 0)
            {
                percentageBonus += packInstinctBonus;
            }

            if (m_InDoubleStrike)
            {
                percentageBonus -= 10;
            }

            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 (damage < 1)
                damage = 1;

            AddBlood(attacker, defender, damage);

            int damageGiven = damage;

            if (a != null && !a.OnBeforeDamage(attacker, defender))
            {
                WeaponAbility.ClearCurrentAbility(attacker);
                a = null;
            }

            if (a is ArmorIgnore)
                damageGiven = AOS.Scale(damage, 135);

            Server.Engines.XmlSpawner2.XmlAttach.OnWeaponHit(this, attacker, defender, damageGiven);

            if (defender.MeleeDamageAbsorb > 0)
            {
                if (this is BaseMeleeWeapon && !AttunementSpell.IsAbsorbing(defender))
                {
                    int absorb = Math.Min(damageGiven, defender.MeleeDamageAbsorb);

                    damageGiven -= absorb;
                    defender.MeleeDamageAbsorb -= absorb;

                    defender.SendLocalizedMessage(1075127, String.Format("{0}\t{1}", absorb, defender.MeleeDamageAbsorb)); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain.
                    attacker.PlaySound(0x1F1);
                    attacker.FixedEffect(0x374A, 10, 16);

                    if (defender.MeleeDamageAbsorb <= 0)
                    {
                        defender.MeleeDamageAbsorb = 0;
                        defender.SendMessage("Tva ochrana pred fyzickym utokem skoncila");
                        DefensiveSpell.Nullify(defender);
                    }

                    if (damageGiven <= 0)
                        damageGiven = -1;
                }
                else // SPELLWEAVING: Attunement
                {
                    AttunementSpell.TryAbsorb(defender, ref damageGiven);
                }
            }

            if (damageGiven == -1) // completely absorbed by attunement
            {
                /* Tested in Osi:
                 * 
                 * Even when a hit is completely absorbed
                 * by attunement:
                 * 
                 * -Spell casting fizzles.
                 * -Active meditation stops.
                 * -You become revealed (Sanity).
                 * -Attacker registers an aggressive action towards you.
                 */
                damageGiven = 0;

                if (defender.Spell != null)
                    defender.Spell.OnCasterHurt();

                defender.DisruptiveAction();
                defender.RevealingAction();

                attacker.DoHarmful(defender);
            }

            defender.Damage(damageGiven, attacker);

            if (m_Identified)
            {
                int lifeLeech = 0;
                int stamLeech = 0;
                int manaLeech = 0;

                if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechHits)) > Utility.Random(100))
                    lifeLeech += 10; // HitLeechHits% chance to leech 10% of damage as hit points

                if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechStam)) > Utility.Random(100))
                    stamLeech += 10; // HitLeechStam% chance to leech 10% of damage as stamina

                if ((int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLeechMana)) > Utility.Random(100))
                    manaLeech += 10; // HitLeechMana% chance to leech 10% of damage as mana

                if (m_Cursed)
                    lifeLeech += 5; // Additional 10% life leech for cursed weapons (necro spell)

                if (lifeLeech != 0)
                    attacker.Hits += AOS.Scale(attacker.HitsMax, lifeLeech);

                if (stamLeech != 0)
                    attacker.Stam += AOS.Scale(attacker.StamMax, stamLeech);

                if (manaLeech != 0)
                    attacker.Mana += AOS.Scale(attacker.ManaMax, manaLeech);

                if (lifeLeech != 0 || stamLeech != 0 || manaLeech != 0)
                    attacker.PlaySound(0x44D);

                int maChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitMagicArrow));
                int harmChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitHarm));
                int fireballChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitFireball));
                int lightningChance = (int)(AosWeaponAttributes.GetValue(attacker, AosWeaponAttribute.HitLightning));

                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 (m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is ToxicElemental)) || Utility.Random(50) == 0)) // Stratics says 50% chance, seems more like 4%..
            {
                if (MaxRange <= 1 && (defender is Slime || defender is ToxicElemental))
                    attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!*

                if (m_AosWeaponAttributes.SelfRepair > 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 BaseCreature)
                ((BaseCreature)attacker).OnGaveMeleeAttack(defender);

            if (defender is BaseCreature)
                ((BaseCreature)defender).OnGotMeleeAttack(attacker);

            if (a != null)
                a.OnHit(attacker, defender, damage);
        }

        public virtual void OnHit(Mobile attacker, Mobile defender)
        {
            OnHit(attacker, defender, 1.0);
        }

        public virtual void OnHit(Mobile attacker, Mobile defender, double damageBonus)
        {
            if (attacker.Map == Map.Underworld)
            {
                UWOnHit(attacker, defender, damageBonus);
                return;
            }

            if (attacker.Player && attacker.AccessLevel < AccessLevel.Counselor) //GROUP DUNG
            {
                Server.Regions.GroupDungeonRegion groupRegion = (Server.Regions.GroupDungeonRegion)attacker.Region.GetRegion(typeof(Server.Regions.GroupDungeonRegion));

                if (SpellHelper.IsSorcerers(attacker.Map, attacker.Location) || (groupRegion != null && groupRegion.Stone != null && groupRegion.Stone.MageDung))
                {
                    if (this is BaseStaff || this is Fists)
                        return;
                    else
                    {
                        attacker.BoltEffect(0);
                        attacker.Kill();
                        return;
                    }
                }
            }

            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%).
			 */
            double factor = 1.0;

            WeaponAbility a = WeaponAbility.GetCurrentAbility(attacker);
            SpecialMove move = SpecialMove.GetCurrentMove(attacker);

            if (a != null)
                factor *= a.DamageScalar;

            if (move != null)
                factor *= move.GetDamageScalar(attacker, defender);

            factor *= damageBonus;

            CheckSlayerResult cs = CheckSlayers(attacker, defender);

            if (cs != CheckSlayerResult.None)
            {
                if (cs == CheckSlayerResult.Slayer)
                {
                    defender.FixedEffect(0x37B9, 10, 5);
                    factor *= 2.0;
                }
                else if (cs == CheckSlayerResult.Opposition && !CrusadersShield.FullCrusadersSetPresent(attacker))
                    factor *= 0.5;
            }

            if (!attacker.Player)
            {
                if (defender is PlayerMobile)
                {
                    PlayerMobile pm = (PlayerMobile)defender;

                    if (pm.EnemyOfOneType != null && pm.EnemyOfOneType != attacker.GetType())
                        factor *= 2.0;
                }
            }
            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);
                        factor *= (attacker.ChestArmor is PlateOfJustice && ((PlateOfJustice)attacker.ChestArmor).Bonus > 4) ? 1.65 : 1.5;
                    }
                }
            }

            int packInstinctBonus = GetPackInstinctBonus(attacker, defender);

            if (packInstinctBonus != 0)
                factor *= 1.0 + (double)packInstinctBonus / 100.0;

            if (m_InDoubleStrike)
                factor *= 0.8; // 10% loss when attacking with double-strike

            TransformContext context = TransformationSpell.GetContext(defender);

            if ((m_Slayer == SlayerName.Silver || m_Slayer2 == SlayerName.Silver) && context != null && context.Type != typeof(HorrificBeastSpell))
                factor *= 1.25; // Every necromancer transformation other than horrific beast takes an additional 25% damage

            if (attacker is PlayerMobile && !(Core.ML && defender is PlayerMobile))
            {
                PlayerMobile pmAttacker = (PlayerMobile)attacker;

                if (pmAttacker.HonorActive && pmAttacker.InRange(defender, 1))
                    factor *= 1.25;

                if (pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender)
                    pmAttacker.SentHonorContext.ApplyPerfectionDamageBonus(ref factor);
            }

            if (factor > 3.0)
                factor = 3.0;

            if (attacker is PlayerMobile)
            {
                PlayerMobile pmAttacker = (PlayerMobile)attacker;

                if (pmAttacker.SentHonorContext != null && pmAttacker.SentHonorContext.Target == defender)
                    pmAttacker.SentHonorContext.ApplyPerfectionArmorBonus((Mobile)pmAttacker, ref factor);
            }

            //Battle Lust    
            if (defender is BaseCreature && m_AosWeaponAttributes.BattleLust > 0)
            {
                factor *= BattleLust.GetBonus(attacker, defender);
            }

            if (this is Eradicator && MortalStrike.IsWounded(defender))
                factor *= 1.75;
            else if (this is Zanbato && ((Zanbato)this).Bonus > 0 && defender is BaseChampion)
                factor *= 1.00 + (((double)((Zanbato)this).Bonus) * 0.1);
            else if (CrusadersShield.FullCrusadersSetPresent(attacker) && (((BaseCreature)defender).IsParagon && ((BaseCreature)defender).IsTeragon))
            {
                //attacker.SendMessage("factor: {0:F3}", factor);
                factor *= 1.00 + Math.Max(((CrusadersWarMace)this).KoBonus, 5) * 0.01;
                //attacker.SendMessage("factor 2: {0:F3}", factor);
            }

            damage = (int)(damage * factor);
            //attacker.SendMessage("damage * factor: {0}", damage);
            #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!
                }
            }

            // SPELLWEAVING: Immolating Weapon's damage is given before ordinary damage is.
            if (m_Immolating)
            {
                int d = ImmolatingWeaponSpell.GetImmolatingDamage(this);

                //As per Osi, hits slightly vary in damage counts.
                d = Utility.RandomMinMax(d - 2, d + 2);
                d = AOS.Damage(defender, attacker, d, false, 0, 100, 0, 0, 0, false, false, 0);

                // SPELLWEAVING: Attunement
                if (defender.MeleeDamageAbsorb > 0)
                {
                    AttunementSpell.TryAbsorb(defender, ref d);
                }

                if (d != null && d > 0 && defender != null && attacker != null)
                    defender.Damage(d, attacker);
            }

            // ---
            AddBlood(attacker, defender, damage);

            int phys, fire, cold, pois, nrgy;

            GetDamageTypes(attacker, out phys, out fire, out cold, out pois, out nrgy);

            //Charm
            if (attacker.Player && cold > 0 && (defender is BaseCreature && !TalismanSlayer.Check(TalismanSlayerName.Ice, (BaseCreature)defender)) && attacker.Backpack != null && Utility.RandomDouble() < 0.01)
            {
                BaseCharm charm = (BaseCharm)attacker.Backpack.FindItemByType(typeof(CharmOfColdSnap));

                if (charm != null && charm.Charges > 0 && charm.BlessedFor == attacker)
                {
                    defender.Freeze(TimeSpan.FromSeconds(4.0));
                    defender.Emote("*Cold Snap!*");

                    if (this is Eradicator || this is TheCalamity)
                    {
                    }
                    else
                        charm.Charges--;
                }
            }

            if (m_Consecrated || (attacker is Xanthos.Evo.EvoGolem && attacker.IsBodyMod))
            {
                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 = 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;
            }

            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, false, false, 0); //Kenko mod, does not actually damage the mobile.

            if (defender.MeleeDamageAbsorb > 0)
            {
                if (this is BaseMeleeWeapon && !AttunementSpell.IsAbsorbing(defender))
                {
                    int absorb = Math.Min(damageGiven, defender.MeleeDamageAbsorb);

                    int react = damageGiven / 3;

                    if (react <= 0)
                        react = 1;

                    attacker.Damage(react, defender);

                    damageGiven -= absorb;
                    defender.MeleeDamageAbsorb -= absorb;

                    defender.SendLocalizedMessage(1075127, String.Format("{0}\t{1}", absorb, defender.MeleeDamageAbsorb)); // ~1_damage~ point(s) of damage have been absorbed. A total of ~2_remaining~ point(s) of shielding remain.
                    attacker.PlaySound(0x1F1);
                    attacker.FixedEffect(0x374A, 10, 16);

                    if (defender.MeleeDamageAbsorb <= 0)
                    {
                        defender.MeleeDamageAbsorb = 0;
                        defender.SendMessage("Tva ochrana pred fyzickym utokem skoncila");
                        DefensiveSpell.Nullify(defender);
                    }

                    if (damageGiven <= 0)
                        damageGiven = -1;
                }
                else // SPELLWEAVING: Attunement
                {
                    AttunementSpell.TryAbsorb(defender, ref damageGiven);
                }
            }

            if (damageGiven == -1) // completely absorbed by attunement
            {
                /* Tested in Osi:
                 * 
                 * Even when a hit is completely absorbed
                 * by attunement:
                 * 
                 * -Spell casting fizzles.
                 * -Active meditation stops.
                 * -You become revealed (Sanity).
                 * -Attacker registers an aggressive action towards you.
                 */
                damageGiven = 0;

                if (defender.Spell != null)
                    defender.Spell.OnCasterHurt();

                defender.DisruptiveAction();
                defender.RevealingAction();

                attacker.DoHarmful(defender);
            }

            // ---

            AddBlood(attacker, defender, damage);

            //TALENT
            if (attacker is PlayerMobile && defender is BaseCreature/*  && attacker.Map != Map.Underworld */ && Utility.RandomDouble() < 0.2 && !(this is BaseRanged) && !(this is MagicRanged) && !(this is NoAmmoRanged))
            {
                PlayerMobile.TalentEntry te = ((PlayerMobile)attacker).GetTalent(PlayerMobile.TalentType.Seknuti);

                if (te != null && te.Enabled && te.Charges >= 20)
                {
                    ArrayList targets = Utilitky.GetPlayerTargets(defender, 2);
                    int count = Math.Min(targets.Count, 5);

                    if (count > 0)
                    {
                        for (int i = 0; i < count; ++i)
                        {
                            Mobile m = (Mobile)targets[i];

                            if (m == null || m.Deleted || !m.Alive)
                                continue;

                            m.PlaySound(GetHitDefendSound(attacker, m));
                            m.FixedParticles(0x377A, 1, 32, 9949, 348, 0, EffectLayer.Head);
                            PlayHurtAnimation(m);
                            AddBlood(attacker, m, damage);

                            m.Damage(damage / count, attacker);
                        }

                        te.Charges -= 20;

                        if (te.Charges < 20)
                            te.Enabled = false;
                    }
                }
            }

            if (damageGiven > 100 && defender.LegsArmor is LegsOfYuki && ((LegsOfYuki)defender.LegsArmor).Bonus > 4 && !Ability.IsDoTted(defender))
            {
                //                defender.SendMessage( "damageGiven {0}, dot {1}",  damageGiven,  damageGiven / 6 );
                defender.Damage(damageGiven / 6, attacker);
                Ability.BeginDoT(defender, attacker, damageGiven / 6);
            }
            else
            {
                if (damageGiven > 20 && this is Zanbato && ((Zanbato)this).Bonus > 0 && !Ability.IsDoTted(defender))
                {
                    Ability.BeginDoT(defender, attacker, AOS.Scale(damageGiven, ((Zanbato)this).Bonus * 50) / 5);
                }

                defender.Damage(damageGiven, attacker);
            }

            double propertyBonus = (move == null) ? 1.0 : move.GetPropertyBonus(attacker);

            if (Ability.UnderColdBlood(attacker) || m_InDoubleStrike || (defender.Map != Map.Underworld && ((defender is BaseCreature && ((BaseCreature)defender).BleedImmune) && !Server.Commands.DrinkCommand.ForcedLeech(attacker))))
            { }
            else
            {
                int lifeLeech = 0;
                int stamLeech = 0;
                int manaLeech = 0;
                int wraithLeech = 0;

                if ((int)(m_AosWeaponAttributes.HitLeechHits * propertyBonus) > Utility.Random(100))
                    lifeLeech += 30; // HitLeechHits% chance to leech 30% of damage as hit points

                if ((int)(m_AosWeaponAttributes.HitLeechStam * propertyBonus) > Utility.Random(100))
                    stamLeech += 100; // HitLeechStam% chance to leech 100% of damage as stamina

                if ((int)(m_AosWeaponAttributes.HitLeechMana * propertyBonus) > Utility.Random(100))
                    manaLeech += 40; // HitLeechMana% chance to leech 40% of damage as mana

                if (this is ILevelable && this.Quality == WeaponQuality.Exceptional)
                {
                    if (lifeLeech != 0)
                        lifeLeech += 15;

                    if (manaLeech != 0)
                        manaLeech += 5;

                    if (stamLeech != 0)
                        stamLeech += 15;
                }

                if (m_Cursed)
                    lifeLeech += 50; // Additional 50% life leech for cursed weapons (necro spell)

                context = TransformationSpell.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 += Math.Min(AOS.Scale(damageGiven, lifeLeech), AOS.Scale(attacker.HitsMax, 20));

                if (stamLeech != 0)
                    attacker.Stam += Math.Min(AOS.Scale(damageGiven, stamLeech), AOS.Scale(attacker.StamMax, 20));

                if (manaLeech != 0)
                    attacker.Mana += Math.Min(AOS.Scale(damageGiven, manaLeech), AOS.Scale(attacker.ManaMax, 15));

                if (lifeLeech != 0 || stamLeech != 0 || manaLeech != 0)
                    attacker.PlaySound(0x44D);
            }

            if (m_MaxHits > 0 && ((MaxRange <= 1 && (defender is Slime || defender is ToxicElemental)) || Utility.Random(25) == 0)) // Stratics says 50% chance, seems more like 4%..
            {
                if (MaxRange <= 1 && (defender is Slime || defender is ToxicElemental))
                    attacker.LocalOverheadMessage(MessageType.Regular, 0x3B2, 500263); // *Acid blood scars your weapon!*

                if (Core.AOS && m_AosWeaponAttributes.SelfRepair > 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;
            }

            int physChance = (int)(m_AosWeaponAttributes.HitPhysicalArea * propertyBonus);
            int fireChance = (int)(m_AosWeaponAttributes.HitFireArea * propertyBonus);
            int coldChance = (int)(m_AosWeaponAttributes.HitColdArea * propertyBonus);
            int poisChance = (int)(m_AosWeaponAttributes.HitPoisonArea * propertyBonus);
            int nrgyChance = (int)(m_AosWeaponAttributes.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)(m_AosWeaponAttributes.HitMagicArrow * propertyBonus);
            int harmChance = (int)(m_AosWeaponAttributes.HitHarm * propertyBonus);
            int fireballChance = (int)(m_AosWeaponAttributes.HitFireball * propertyBonus);
            int lightningChance = (int)(m_AosWeaponAttributes.HitLightning * propertyBonus);
            int dispelChance = (int)(m_AosWeaponAttributes.HitDispel * propertyBonus);

            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);

            int laChance = (int)(m_AosWeaponAttributes.HitLowerAttack * propertyBonus);
            int ldChance = (int)(m_AosWeaponAttributes.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) && !(this is MagicRanged) && !(this is NoAmmoRanged))
            {
                if (AnimalForm.UnderTransformation(attacker, typeof(GiantSerpent)))
                    defender.ApplyPoison(attacker, Poison.Lesser);

                if (AnimalForm.UnderTransformation(defender, typeof(BullFrog)))
                    attacker.ApplyPoison(defender, Poison.Regular);
            }

            // hook for attachment OnWeaponHit method
            Server.Engines.XmlSpawner2.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 && !m_InDoubleStrike)
            {
                // Int bonus
                damageBonus += (attacker.Int / 10);

                // SDI bonus
                damageBonus += AosAttributes.GetValue(attacker, AosAttribute.SpellDamage);

                // SPELLWEAVING: Reaper Form bonus
                damageBonus += ReaperFormSpell.GetSDIBonus(attacker);

                if (this is ILevelable && this.Quality == WeaponQuality.Exceptional)
                    damageBonus += 40;
            }

            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);

            attacker.MovingParticles(defender, 0x36E4, 5, 0, false, true, 3006, 4006, 0);
            attacker.PlaySound(0x1E5);
            double damage;

            if (IsUWItem)
            {
                damage = Utility.Random(4, 6);
                // damage *= Spell.GetDamageScalar(defender);
            }
            else
            {
                damage = GetAosDamage(attacker, 2, 1, 4);
            }

            SpellHelper.Damage(TimeSpan.FromSeconds(1.0), defender, attacker, damage, 0, 100, 0, 0, 0, 2);
        }

        public virtual void DoHarm(Mobile attacker, Mobile defender)
        {
            if (!attacker.CanBeHarmful(defender, false))
                return;

            attacker.DoHarmful(defender);
            double damage;

            if (IsUWItem)
            {
                damage = Utility.Random(1, 15);
                // damage *= Spell.GetDamageScalar(defender);
            }
            else
            {
                damage = GetAosDamage(attacker, 7, 1, 5);
            }

            defender.FixedParticles(0x374A, 10, 30, 5013, 1153, 2, EffectLayer.Waist);
            defender.PlaySound(0x0FC);

            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

            SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 100, 0, 0, 2);
        }

        public virtual void DoFireball(Mobile attacker, Mobile defender)
        {
            if (!attacker.CanBeHarmful(defender, false))
                return;

            attacker.DoHarmful(defender);
            double damage;

            if (IsUWItem)
            {
                damage = Utility.Random(1, 15);
                // damage *= Spell.GetDamageScalar(defender);
            }
            else
            {
                damage = GetAosDamage(attacker, 9, 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, 2);
        }

        public virtual void DoLightning(Mobile attacker, Mobile defender)
        {
            if (!attacker.CanBeHarmful(defender, false))
                return;

            attacker.DoHarmful(defender);
            double damage;

            if (IsUWItem)
            {
                damage = Utility.Random(9, 12);
                // damage *= Spell.GetDamageScalar(defender);
            }
            else
            {
                damage = GetAosDamage(attacker, 13, 1, 4);
            }

            defender.BoltEffect(0);

            SpellHelper.Damage(TimeSpan.Zero, defender, attacker, damage, 0, 0, 0, 0, 100, 2);
        }

        public virtual void DoDispel(Mobile attacker, Mobile defender)
        {
            bool dispellable = false;

            if (defender is BaseCreature)
                dispellable = (((BaseCreature)defender).Summoned && !((BaseCreature)defender).IsAnimatedDead) || defender is BaseSummoned;

            if (!dispellable)
                return;

            if (!attacker.CanBeHarmful(defender, false))
                return;

            attacker.DoHarmful(defender);

            Spells.Spell sp = new Spells.Sixth.DispelSpell(attacker, null);

            if (sp.CheckResisted(defender) && !(defender is BaseSummoned))
            {
                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();
            }
        }

        public virtual void DoLowerAttack(Mobile from, Mobile defender)
        {
            if (IsUWItem)
                return;

            if (HitLower.ApplyAttack(defender))
            {
                defender.PlaySound(0x28E);
                Effects.SendTargetEffect(defender, 0x37BE, 1, 4, 0xA, 3);
            }
        }

        public virtual void DoLowerDefense(Mobile from, Mobile defender)
        {
            if (IsUWItem)
                return;

            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 || IsUWItem)
                return;

            List<Mobile> list = new List<Mobile>();

            foreach (Mobile m in from.GetMobilesInRange(3))
            {
                if (from != m && defender != m && SpellHelper.ValidIndirectTarget(from, m) && from.CanBeHarmful(m, false) && 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 = (6 - 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);

                if (phys > 0 && from is Xanthos.Evo.EvoGolem && m is BaseCreature)
                {
                    if (((BaseCreature)from).ControlMaster != null && m.Combatant == ((BaseCreature)from).ControlMaster)
                    {
                        m.Combatant = from;
                    }
                }

                AOS.Damage(m, from, (int)(GetBaseDamage(from) * scalar), phys, fire, cold, pois, nrgy, 2);
            }
        }

        #endregion

        public virtual CheckSlayerResult CheckSlayers(Mobile attacker, Mobile defender)
        {
            BaseWeapon atkWeapon = attacker.Weapon as BaseWeapon;

            if (atkWeapon is BaseStaff)
                return CheckSlayerResult.None;

            SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkWeapon.Slayer);
            SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkWeapon.Slayer2);

            if (atkSlayer != null && atkSlayer.Group.OppositionSuperSlays(defender))
                return CheckSlayerResult.Opposition;

            if (atkSlayer2 != null && atkSlayer2.Group.OppositionSuperSlays(defender))
                return CheckSlayerResult.Opposition;

            if (atkSlayer != null && atkSlayer.Slays(defender))
                return CheckSlayerResult.Slayer;

            if (atkSlayer2 != null && atkSlayer2.Slays(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);
                }
            }

            /* if ( damage <= 2 )
                return;

            Direction d = defender.GetDirectionTo( attacker );

            int maxCount = damage / 15;

            if ( maxCount < 1 )
                maxCount = 1;
            else if ( maxCount > 4 )
                maxCount = 4;

            for( int i = 0; i < Utility.Random( 1, maxCount ); ++i )
            {
                int x = defender.X;
                int y = defender.Y;

                switch( d )
                {
                    case Direction.North:
                        x += Utility.Random( -1, 3 );
                        y += Utility.Random( 2 );
                        break;
                    case Direction.East:
                        y += Utility.Random( -1, 3 );
                        x += Utility.Random( -1, 2 );
                        break;
                    case Direction.West:
                        y += Utility.Random( -1, 3 );
                        x += Utility.Random( 2 );
                        break;
                    case Direction.South:
                        x += Utility.Random( -1, 3 );
                        y += Utility.Random( -1, 2 );
                        break;
                    case Direction.Up:
                        x += Utility.Random( 2 );
                        y += Utility.Random( 2 );
                        break;
                    case Direction.Down:
                        x += Utility.Random( -1, 2 );
                        y += Utility.Random( -1, 2 );
                        break;
                    case Direction.Left:
                        x += Utility.Random( 2 );
                        y += Utility.Random( -1, 2 );
                        break;
                    case Direction.Right:
                        x += Utility.Random( -1, 2 );
                        y += Utility.Random( 2 );
                        break;
                }

                new Blood().MoveToWorld( new Point3D( x, y, 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)
        {
            if (wielder is BaseCreature)
            {
                BaseCreature bc = (BaseCreature)wielder;

                phys = bc.PhysicalDamage;
                fire = bc.FireDamage;
                cold = bc.ColdDamage;
                pois = bc.PoisonDamage;
                nrgy = bc.EnergyDamage;
            }
            else
            {
                fire = m_AosElementDamages.Fire;
                cold = m_AosElementDamages.Cold;
                pois = m_AosElementDamages.Poison;
                nrgy = m_AosElementDamages.Energy;

                phys = 100 - fire - cold - pois - nrgy;

                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);

                        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);

            return Utility.RandomMinMax(min, max);
        }

        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()
        {
            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 (from.Map != Map.Underworld)
            {
                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, 150.0); // Passively check tactics for gain
                attacker.CheckSkill(SkillName.Anatomy, 0.0, 150.0); // Passively check Anatomy for gain

                if (Type == WeaponType.Axe)
                    attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 150.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 (TransformationSpell.UnderTransformation(attacker, typeof(HorrificBeastSpell)))
                damageBonus += 25;

            // Divine Fury gives a +10% bonus to damage.
            if (Spells.Chivalry.DivineFurySpell.UnderEffect(attacker))
                damageBonus += 10;

            int defenseMasteryMalus = 0;

            // Defense Mastery gives a -50%/-80% malus to damage.
            if (Server.Items.DefenseMastery.GetMalus(attacker, ref defenseMasteryMalus))
                damageBonus -= defenseMasteryMalus;

            int discordanceEffect = 0;

            // Discordance gives a -2%/-48% malus to damage.
            if (SkillHandlers.Discordance.GetEffect(attacker, ref discordanceEffect))
                damageBonus -= discordanceEffect * 2;

            if (damageBonus > 400)
            {
                damageBonus = 400;

                if (attacker.FindItemOnLayer(Layer.Shoes) is BaseShoes)
                    damageBonus += ((BaseShoes)attacker.FindItemOnLayer(Layer.Shoes)).DIBonus;
                else if (attacker.FindItemOnLayer(Layer.Shoes) is BaseLevelShoes)
                    damageBonus += ((BaseLevelShoes)attacker.FindItemOnLayer(Layer.Shoes)).DIBonus;
            }

            #endregion

            double totalBonus = strengthBonus + anatomyBonus + tacticsBonus + lumberBonus + ((double)(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, 150.0); // Passively check tactics for gain
                attacker.CheckSkill(SkillName.Anatomy, 0.0, 150.0); // Passively check Anatomy for gain

                if (Type == WeaponType.Axe)
                    attacker.CheckSkill(SkillName.Lumberjacking, 0.0, 150.0); // Passively check Lumberjacking for gain
            }

            /* Compute tactics modifier
             * :   0.0 = 50% loss
             * :  50.0 = unchanged
             * : 100.0 = 50% bonus
             */
            double tacticsBonus = (attacker.Skills[SkillName.Tactics].Value - 50.0) / 100.0;

            /* Compute strength modifier
             * : 1% bonus for every 5 strength
             */
            double strBonus = (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;
            double anatomyBonus = (anatomyValue / 5.0) / 100.0;

            if (anatomyValue >= 100.0)
                anatomyBonus += 0.1;

            /* Compute lumberjacking bonus
         * : 1% bonus for every 5 points of lumberjacking
         * : +10% bonus at Grandmaster or higher
         */
            double lumberBonus;

            if (Type == WeaponType.Axe)
            {
                double lumberValue = attacker.Skills[SkillName.Lumberjacking].Value;

                lumberBonus = (lumberValue / 5.0) / 100.0;

                if (lumberValue >= 100.0)
                    lumberBonus += 0.1;
            }
            else
            {
                lumberBonus = 0.0;
            }

            // New quality bonus:
            double qualityBonus = ((int)m_Quality - 1) * 0.2;

            // Apply bonuses
            damage += (damage * tacticsBonus) + (damage * strBonus) + (damage * anatomyBonus) + (damage * lumberBonus) + (damage * qualityBonus) + ((damage * VirtualDamageBonus) / 100);

            // Old quality bonus:
#if false
			/* Apply quality offset
			 * : Low         : -4
			 * : Regular     :  0
			 * : Exceptional : +4
			 */
			damage += ((int)m_Quality - 1) * 4.0;
#endif

            /* Apply damage level offset
			 * : Regular : 0
			 * : Ruin    : 1
			 * : Might   : 3
			 * : Force   : 5
			 * : Power   : 7
			 * : Vanq    : 9
			 */
            if (m_DamageLevel != WeaponDamageLevel.Regular)
                damage += (2.0 * (int)m_DamageLevel) - 1.0;

            switch (m_Resource)
            {
                case CraftResource.Agapite: damage += 1; break;
                case CraftResource.Verite: damage += 2; break;
                case CraftResource.Valorite: damage += 3; break;
            }

            // Halve the computed damage and return
            damage /= 2.0;

            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 (defender.Map != Map.Underworld)
                return ComputeDamageAOS(attacker, defender);

            return (int)ScaleDamageOld(attacker, GetBaseDamage(attacker), true);
        }

        public static 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((int)10); // version

            writer.Write((bool)m_IsUWItem);

            writer.Write((int)m_NewPrimaryAbility);
            writer.Write((int)m_NewSecondaryAbility);

            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 != false);
            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);

            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((int)m_Hits);

            if (GetSaveFlag(flags, SaveFlag.MaxHits))
                writer.Write((int)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((int)m_PoisonCharges);

            if (GetSaveFlag(flags, SaveFlag.Crafter))
                writer.Write((Mobile)m_Crafter);

            if (GetSaveFlag(flags, SaveFlag.StrReq))
                writer.Write((int)m_StrReq);

            if (GetSaveFlag(flags, SaveFlag.DexReq))
                writer.Write((int)m_DexReq);

            if (GetSaveFlag(flags, SaveFlag.IntReq))
                writer.Write((int)m_IntReq);

            if (GetSaveFlag(flags, SaveFlag.MinDamage))
                writer.Write((int)m_MinDamage);

            if (GetSaveFlag(flags, SaveFlag.MaxDamage))
                writer.Write((int)m_MaxDamage);

            if (GetSaveFlag(flags, SaveFlag.HitSound))
                writer.Write((int)m_HitSound);

            if (GetSaveFlag(flags, SaveFlag.MissSound))
                writer.Write((int)m_MissSound);

            if (GetSaveFlag(flags, SaveFlag.Speed))
                writer.Write((int)m_Speed);

            if (GetSaveFlag(flags, SaveFlag.MaxRange))
                writer.Write((int)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);

            if (GetSaveFlag(flags, SaveFlag.xAttributes))
                m_AosAttributes.Serialize(writer);

            if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes))
                m_AosWeaponAttributes.Serialize(writer);

            if (GetSaveFlag(flags, SaveFlag.SkillBonuses))
                m_AosSkillBonuses.Serialize(writer);

            if (GetSaveFlag(flags, SaveFlag.Slayer2))
                writer.Write((int)m_Slayer2);

            if (GetSaveFlag(flags, SaveFlag.ElementalDamages))
                m_AosElementDamages.Serialize(writer);
        }

        [Flags]
        private enum SaveFlag
        {
            None = 0x00000000,
            DamageLevel = 0x00000001,
            AccuracyLevel = 0x00000002,
            DurabilityLevel = 0x00000004,
            Quality = 0x00000008,
            Hits = 0x00000010,
            MaxHits = 0x00000020,
            Slayer = 0x00000040,
            Poison = 0x00000080,
            PoisonCharges = 0x00000100,
            Crafter = 0x00000200,
            Identified = 0x00000400,
            StrReq = 0x00000800,
            DexReq = 0x00001000,
            IntReq = 0x00002000,
            MinDamage = 0x00004000,
            MaxDamage = 0x00008000,
            HitSound = 0x00010000,
            MissSound = 0x00020000,
            Speed = 0x00040000,
            MaxRange = 0x00080000,
            Skill = 0x00100000,
            Type = 0x00200000,
            Animation = 0x00400000,
            Resource = 0x00800000,
            xAttributes = 0x01000000,
            xWeaponAttributes = 0x02000000,
            PlayerConstructed = 0x04000000,
            SkillBonuses = 0x08000000,
            Slayer2 = 0x10000000,
            ElementalDamages = 0x20000000
        }

        public override void Deserialize(GenericReader reader)
        {
            base.Deserialize(reader);

            int version = reader.ReadInt();

            switch (version)
            {
                case 10:
                    {
                        m_IsUWItem = reader.ReadBool();
                        goto case 9;
                    }

                case 9:
                    {
                        NewPrimaryAbility = (WeaponAbility.AbilityType)reader.ReadInt();
                        NewSecondaryAbility = (WeaponAbility.AbilityType)reader.ReadInt();
                        goto case 5;
                    }

                case 8:
                case 7:
                case 6:
                case 5:
                    {
                        SaveFlag flags = (SaveFlag)reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.DamageLevel))
                        {
                            m_DamageLevel = (WeaponDamageLevel)reader.ReadInt();

                            if (m_DamageLevel > WeaponDamageLevel.Vanq)
                                m_DamageLevel = WeaponDamageLevel.Ruin;
                        }

                        if (GetSaveFlag(flags, SaveFlag.AccuracyLevel))
                        {
                            m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt();

                            if (m_AccuracyLevel > WeaponAccuracyLevel.Supremely)
                                m_AccuracyLevel = WeaponAccuracyLevel.Accurate;
                        }

                        if (GetSaveFlag(flags, SaveFlag.DurabilityLevel))
                        {
                            m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt();

                            if (m_DurabilityLevel > WeaponDurabilityLevel.Indestructible)
                                m_DurabilityLevel = WeaponDurabilityLevel.Durable;
                        }

                        if (GetSaveFlag(flags, SaveFlag.Quality))
                            m_Quality = (WeaponQuality)reader.ReadInt();
                        else
                            m_Quality = WeaponQuality.Regular;

                        if (GetSaveFlag(flags, SaveFlag.Hits))
                            m_Hits = reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.MaxHits))
                            m_MaxHits = reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.Slayer))
                            m_Slayer = (SlayerName)reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.Poison))
                            m_Poison = Poison.Deserialize(reader);

                        if (GetSaveFlag(flags, SaveFlag.PoisonCharges))
                            m_PoisonCharges = reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.Crafter))
                            m_Crafter = reader.ReadMobile();

                        if (GetSaveFlag(flags, SaveFlag.Identified))
                            m_Identified = (version >= 6 || reader.ReadBool());

                        if (GetSaveFlag(flags, SaveFlag.StrReq))
                            m_StrReq = reader.ReadInt();
                        else
                            m_StrReq = -1;

                        if (GetSaveFlag(flags, SaveFlag.DexReq))
                            m_DexReq = reader.ReadInt();
                        else
                            m_DexReq = -1;

                        if (GetSaveFlag(flags, SaveFlag.IntReq))
                            m_IntReq = reader.ReadInt();
                        else
                            m_IntReq = -1;

                        if (GetSaveFlag(flags, SaveFlag.MinDamage))
                            m_MinDamage = reader.ReadInt();
                        else
                            m_MinDamage = -1;

                        if (GetSaveFlag(flags, SaveFlag.MaxDamage))
                            m_MaxDamage = reader.ReadInt();
                        else
                            m_MaxDamage = -1;

                        if (GetSaveFlag(flags, SaveFlag.HitSound))
                            m_HitSound = reader.ReadInt();
                        else
                            m_HitSound = -1;

                        if (GetSaveFlag(flags, SaveFlag.MissSound))
                            m_MissSound = reader.ReadInt();
                        else
                            m_MissSound = -1;

                        if (GetSaveFlag(flags, SaveFlag.Speed))
                            m_Speed = reader.ReadInt();
                        else
                            m_Speed = -1;

                        if (GetSaveFlag(flags, SaveFlag.MaxRange))
                            m_MaxRange = reader.ReadInt();
                        else
                            m_MaxRange = -1;

                        if (GetSaveFlag(flags, SaveFlag.Skill))
                            m_Skill = (SkillName)reader.ReadInt();
                        else
                            m_Skill = (SkillName)(-1);

                        if (GetSaveFlag(flags, SaveFlag.Type))
                            m_Type = (WeaponType)reader.ReadInt();
                        else
                            m_Type = (WeaponType)(-1);

                        if (GetSaveFlag(flags, SaveFlag.Animation))
                            m_Animation = (WeaponAnimation)reader.ReadInt();
                        else
                            m_Animation = (WeaponAnimation)(-1);

                        if (GetSaveFlag(flags, SaveFlag.Resource))
                            m_Resource = (CraftResource)reader.ReadInt();
                        else
                            m_Resource = CraftResource.Iron;

                        if (GetSaveFlag(flags, SaveFlag.xAttributes))
                            m_AosAttributes = new AosAttributes(this, reader);
                        else
                            m_AosAttributes = new AosAttributes(this);

                        if (GetSaveFlag(flags, SaveFlag.xWeaponAttributes))
                            m_AosWeaponAttributes = new AosWeaponAttributes(this, reader);
                        else
                            m_AosWeaponAttributes = new AosWeaponAttributes(this);

                        if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile)
                        {
                            m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5);
                            ((Mobile)Parent).AddSkillMod(m_SkillMod);
                        }

                        if (version < 7 && m_AosWeaponAttributes.MageWeapon != 0)
                            m_AosWeaponAttributes.MageWeapon = 30 - m_AosWeaponAttributes.MageWeapon;

                        if (Core.AOS && m_AosWeaponAttributes.MageWeapon != 0 && m_AosWeaponAttributes.MageWeapon != 30 && Parent is Mobile)
                        {
                            m_MageMod = new DefaultSkillMod(SkillName.Magery, true, -30 + m_AosWeaponAttributes.MageWeapon);
                            ((Mobile)Parent).AddSkillMod(m_MageMod);
                        }

                        if (GetSaveFlag(flags, SaveFlag.PlayerConstructed))
                            m_PlayerConstructed = true;

                        if (GetSaveFlag(flags, SaveFlag.SkillBonuses))
                            m_AosSkillBonuses = new AosSkillBonuses(this, reader);
                        else
                            m_AosSkillBonuses = new AosSkillBonuses(this);

                        if (GetSaveFlag(flags, SaveFlag.Slayer2))
                            m_Slayer2 = (SlayerName)reader.ReadInt();

                        if (GetSaveFlag(flags, SaveFlag.ElementalDamages))
                            m_AosElementDamages = new AosElementAttributes(this, reader);
                        else
                            m_AosElementDamages = new AosElementAttributes(this);

                        break;
                    }

                case 4:
                    {
                        m_Slayer = (SlayerName)reader.ReadInt();

                        goto case 3;
                    }

                case 3:
                    {
                        m_StrReq = reader.ReadInt();
                        m_DexReq = reader.ReadInt();
                        m_IntReq = reader.ReadInt();

                        goto case 2;
                    }

                case 2:
                    {
                        m_Identified = reader.ReadBool();

                        goto case 1;
                    }

                case 1:
                    {
                        m_MaxRange = reader.ReadInt();

                        goto case 0;
                    }

                case 0:
                    {
                        if (version == 0)
                            m_MaxRange = 1; // default

                        if (version < 5)
                        {
                            m_Resource = CraftResource.Iron;
                            m_AosAttributes = new AosAttributes(this);
                            m_AosWeaponAttributes = new AosWeaponAttributes(this);
                            m_AosElementDamages = new AosElementAttributes(this);
                            m_AosSkillBonuses = new AosSkillBonuses(this);
                        }

                        m_MinDamage = reader.ReadInt();
                        m_MaxDamage = reader.ReadInt();

                        m_Speed = reader.ReadInt();

                        m_HitSound = reader.ReadInt();
                        m_MissSound = reader.ReadInt();

                        m_Skill = (SkillName)reader.ReadInt();
                        m_Type = (WeaponType)reader.ReadInt();
                        m_Animation = (WeaponAnimation)reader.ReadInt();
                        m_DamageLevel = (WeaponDamageLevel)reader.ReadInt();
                        m_AccuracyLevel = (WeaponAccuracyLevel)reader.ReadInt();
                        m_DurabilityLevel = (WeaponDurabilityLevel)reader.ReadInt();
                        m_Quality = (WeaponQuality)reader.ReadInt();

                        m_Crafter = reader.ReadMobile();

                        m_Poison = Poison.Deserialize(reader);
                        m_PoisonCharges = reader.ReadInt();

                        if (m_StrReq == OldStrengthReq)
                            m_StrReq = -1;

                        if (m_DexReq == OldDexterityReq)
                            m_DexReq = -1;

                        if (m_IntReq == OldIntelligenceReq)
                            m_IntReq = -1;

                        if (m_MinDamage == OldMinDamage)
                            m_MinDamage = -1;

                        if (m_MaxDamage == OldMaxDamage)
                            m_MaxDamage = -1;

                        if (m_HitSound == OldHitSound)
                            m_HitSound = -1;

                        if (m_MissSound == OldMissSound)
                            m_MissSound = -1;

                        if (m_Speed == OldSpeed)
                            m_Speed = -1;

                        if (m_MaxRange == OldMaxRange)
                            m_MaxRange = -1;

                        if (m_Skill == OldSkill)
                            m_Skill = (SkillName)(-1);

                        if (m_Type == OldType)
                            m_Type = (WeaponType)(-1);

                        if (m_Animation == OldAnimation)
                            m_Animation = (WeaponAnimation)(-1);

                        if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular && Parent is Mobile)
                        {
                            m_SkillMod = new DefaultSkillMod(AccuracySkill, true, (int)m_AccuracyLevel * 5);
                            ((Mobile)Parent).AddSkillMod(m_SkillMod);
                        }

                        break;
                    }
            }

            if (Core.AOS && Parent is Mobile)
                m_AosSkillBonuses.AddTo((Mobile)Parent);

            int strBonus = m_AosAttributes.BonusStr;
            int dexBonus = m_AosAttributes.BonusDex;
            int intBonus = m_AosAttributes.BonusInt;

            if (this.Parent is Mobile && (strBonus != 0 || dexBonus != 0 || intBonus != 0))
            {
                Mobile m = (Mobile)this.Parent;

                string modName = this.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));
            }

            if (Parent is Mobile)
                ((Mobile)Parent).CheckStatTimers();

            if (m_Hits <= 0 && m_MaxHits <= 0)
            {
                m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits);
            }

            if (version < 6)
                m_PlayerConstructed = true; // we don't know, so, assume it's crafted

            if (version < 9)
            {
                NewPrimaryAbility = WeaponAbility.SetNewAbility(this.PrimaryAbility);
                NewSecondaryAbility = WeaponAbility.SetNewAbility(this.SecondaryAbility);
            }
        }

        #endregion

        public BaseWeapon(int itemID)
        : base(itemID)
        {
            Layer = (Layer)ItemData.Quality;

            m_Quality = WeaponQuality.Regular;
            m_StrReq = -1;
            m_DexReq = -1;
            m_IntReq = -1;
            m_MinDamage = -1;
            m_MaxDamage = -1;
            m_HitSound = -1;
            m_MissSound = -1;
            m_Speed = -1;
            m_MaxRange = -1;
            m_Skill = (SkillName)(-1);
            m_Type = (WeaponType)(-1);
            m_Animation = (WeaponAnimation)(-1);

            m_Hits = m_MaxHits = Utility.RandomMinMax(InitMinHits, InitMaxHits);

            m_Resource = CraftResource.Iron;

            m_AosAttributes = new AosAttributes(this);
            m_AosWeaponAttributes = new AosWeaponAttributes(this);
            m_AosSkillBonuses = new AosSkillBonuses(this);
            m_AosElementDamages = new AosElementAttributes(this);

            NewPrimaryAbility = WeaponAbility.SetNewAbility(this.PrimaryAbility);
            NewSecondaryAbility = WeaponAbility.SetNewAbility(this.SecondaryAbility);
        }

        public BaseWeapon(Serial serial)
        : base(serial)
        {
        }

        private string GetNameString()
        {
            string name = this.Name;

            if (name == null)
                name = String.Format("#{0}", LabelNumber);

            return name;
        }

        [Hue, CommandProperty(AccessLevel.GameMaster)]
        public override int Hue
        {
            get { return base.Hue; }
            set { base.Hue = value; InvalidateProperties(); }
        }

        public int GetElementalDamageHue()
        {
            int phys, fire, cold, pois, nrgy;
            GetDamageTypes(null, out phys, out fire, out cold, out pois, out nrgy);
            //Order is Cold, Energy, Fire, Poison, Physical left

            int currentMax = 50;
            int hue = 0;

            if (pois >= currentMax)
            {
                hue = 1267 + (pois - 50) / 10;
                currentMax = pois;
            }

            if (fire >= currentMax)
            {
                hue = 1255 + (fire - 50) / 10;
                currentMax = fire;
            }

            if (nrgy >= currentMax)
            {
                hue = 1273 + (nrgy - 50) / 10;
                currentMax = nrgy;
            }

            if (cold >= currentMax)
            {
                hue = 1261 + (cold - 50) / 10;
                currentMax = cold;
            }

            return hue;
        }

        public override void AddNameProperty(ObjectPropertyList list)
        {
            string oreType;

            if (Hue == 0)
            {
                oreType = "";
            }
            else
            {
                switch (m_Resource)
                {
                    case CraftResource.DullCopper: oreType = "dull copper"; break; // dull copper
                    case CraftResource.ShadowIron: oreType = "shadow iron"; break; // shadow iron
                    case CraftResource.Copper: oreType = "copper"; break; // copper
                    case CraftResource.Bronze: oreType = "bronze"; break; // bronze
                    case CraftResource.Gold: oreType = "golden"; break; // golden
                    case CraftResource.Agapite: oreType = "agapite"; break; // agapite
                    case CraftResource.Verite: oreType = "verite"; break; // verite
                    case CraftResource.Valorite: oreType = "valorite"; break; // valorite
                    case CraftResource.Silver: oreType = "silver"; break; // silver
                    case CraftResource.Platinum: oreType = "platinum"; break; // platinum
                    case CraftResource.Mythril: oreType = "mythril"; break; // mythril
                    case CraftResource.Obsidian: oreType = "obsidian"; break; // obsidian
                    case CraftResource.Jade: oreType = "jade"; break; // jade
                    case CraftResource.Moonstone: oreType = "moonstone"; break; // moonstone
                    case CraftResource.Sunstone: oreType = "sunstone"; break; // sunstone
                    case CraftResource.Bloodstone: oreType = "bloodstone"; break; // bloodstone
                    case CraftResource.SpinedLeather: oreType = "spined"; break; // spined
                    case CraftResource.HornedLeather: oreType = "horned"; break; // horned
                    case CraftResource.BarbedLeather: oreType = "barbed"; break; // barbed
                    case CraftResource.DragonLeather: oreType = "dragon"; break; // dragon
                    case CraftResource.DaemonLeather: oreType = "daemon"; break; // daemon
                    case CraftResource.Oak: oreType = "oak"; break;
                    case CraftResource.Ash: oreType = "ash"; break;
                    case CraftResource.Yew: oreType = "yew"; break;
                    case CraftResource.Heartwood: oreType = "heartwood"; break;
                    case CraftResource.Bloodwood: oreType = "bloodwood"; break;
                    case CraftResource.Frostwood: oreType = "frostwood"; break;
                    case CraftResource.Pine: oreType = "pine"; break;
                    case CraftResource.Cedar: oreType = "cedar"; break;
                    case CraftResource.Cherry: oreType = "cherry"; break;
                    case CraftResource.Mahogany: oreType = "mahogany"; break;
                    case CraftResource.RedScales: oreType = "red"; break; // red
                    case CraftResource.YellowScales: oreType = "yellow"; break; // yellow
                    case CraftResource.BlackScales: oreType = "black"; break; // black
                    case CraftResource.GreenScales: oreType = "green"; break; // green
                    case CraftResource.WhiteScales: oreType = "white"; break; // white
                    case CraftResource.BlueScales: oreType = "blue"; break; // blue
                    default: oreType = ""; break;
                }
            }

            //if ( oreType != 0 )
            list.Add(1053099, "{0}\t{1}", oreType, GetNameString()); // ~1_oretype~ ~2_armortype~
                                                                     /*else if ( Name == null )
                                                                     list.Add( LabelNumber );
                                                                 else
                                                                     list.Add( Name );*/
        }

        public override bool AllowEquipedCast(Mobile from)
        {
            if (base.AllowEquipedCast(from))
                return true;

            return (m_AosAttributes.SpellChanneling != 0);
        }

        public virtual int ArtifactRarity
        {
            get { return 0; }
        }

        public virtual int GetLuckBonus()
        {
            CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource);

            if (resInfo == null)
                return 0;

            CraftAttributeInfo attrInfo = resInfo.AttributeInfo;

            if (attrInfo == null)
                return 0;

            return attrInfo.WeaponLuck;
        }

        public override void GetProperties(ObjectPropertyList list)
        {
            base.GetProperties(list);

            // 			if ( Weight != 1 )
            // 				list.Add( 1072789, Weight.ToString() ); // Weight: ~1_WEIGHT~ stones
            // 			else
            // 				list.Add( 1072788, Weight.ToString() ); // Weight: ~1_WEIGHT~ stone

            if (m_Crafter != null)
                list.Add(1050043, m_Crafter.RawName); // crafted by ~1_NAME~

            #region Factions
            if (m_FactionState != null)
                list.Add(1041350); // faction item
            #endregion

            if (m_Quality == WeaponQuality.Exceptional)
                list.Add(1060636); // exceptional

            if (RequiredRace == Race.Elf)
                list.Add(1075086); // Elves Only

            if (ArtifactRarity > 0)
                list.Add(1061078, ArtifactRarity.ToString()); // artifact rarity ~1_val~

            if (this is IUsesRemaining && ((IUsesRemaining)this).ShowUsesRemaining)
                list.Add(1060584, ((IUsesRemaining)this).UsesRemaining.ToString()); // uses remaining: ~1_val~

            if (m_Poison != null && m_PoisonCharges > 0)
                list.Add(1062412 + m_Poison.Level, "<basefont color=#00FF00>" + m_PoisonCharges.ToString() + "<basefont color=White>");

            //damage level
            string bonusStr = null;

            if (m_IsUWItem/* this.Map == Map.Underworld */)
            {
                if (m_Identified || m_PlayerConstructed)
                {
                    if (m_DurabilityLevel != WeaponDurabilityLevel.Regular)
                        list.Add(1038000 + (int)m_DurabilityLevel);

                    if (m_DamageLevel != WeaponDamageLevel.Regular)
                        list.Add(1038015 + (int)m_DamageLevel);

                    if (m_AccuracyLevel != WeaponAccuracyLevel.Regular)
                        list.Add(1038010 + (int)m_AccuracyLevel);

                    if (m_Slayer != SlayerName.None)
                    {
                        SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer);
                        if (entry != null)
                            list.Add(entry.GetTitleByMap(this.Map));
                    }

                    if (m_Slayer2 != SlayerName.None)
                    {
                        SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2);
                        if (entry != null)
                            list.Add(entry.GetTitleByMap(this.Map));
                    }

                    if (m_AosSkillBonuses != null)
                        m_AosSkillBonuses.GetProperties(list);

                    int prop;

                    if ((prop = m_AosAttributes.CastRecovery) != 0)
                        list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~

                    if ((prop = m_AosAttributes.CastSpeed) != 0)
                        list.Add(1060413, prop.ToString()); // faster casting ~1_val~

                    if ((prop = m_AosWeaponAttributes.HitFireball) != 0)
                        list.Add(1060420, prop.ToString()); // hit fireball ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitHarm) != 0)
                        list.Add(1060421, prop.ToString()); // hit harm ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitLeechHits) != 0)
                        list.Add(1060422, prop.ToString()); // hit life leech ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitLightning) != 0)
                        list.Add(1060423, prop.ToString()); // hit lightning ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitMagicArrow) != 0)
                        list.Add(1060426, prop.ToString()); // hit magic arrow ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitLeechMana) != 0)
                        list.Add(1060427, prop.ToString()); // hit mana leech ~1_val~%

                    if ((prop = m_AosWeaponAttributes.HitLeechStam) != 0)
                        list.Add(1060430, prop.ToString()); // hit stamina leech ~1_val~%

                    if ((prop = m_AosAttributes.BonusDex) != 0)
                        list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~

                    if ((prop = m_AosAttributes.BonusHits) != 0)
                        list.Add(1060431, prop.ToString()); // hit point increase ~1_val~

                    if ((prop = m_AosAttributes.BonusInt) != 0)
                        list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~

                    if ((prop = m_AosAttributes.LowerManaCost) != 0)
                        list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~%

                    if ((prop = m_AosAttributes.LowerRegCost) != 0)
                        list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~%

                    if ((prop = m_AosAttributes.BonusMana) != 0)
                        list.Add(1060439, prop.ToString()); // mana increase ~1_val~

                    if ((prop = m_AosAttributes.RegenMana) != 0)
                        list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~

                    if ((prop = m_AosAttributes.NightSight) != 0)
                        list.Add(1060441); // night sight

                    if ((prop = m_AosAttributes.RegenStam) != 0)
                        list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~

                    if ((prop = m_AosAttributes.RegenHits) != 0)
                        list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~

                    if ((prop = m_AosWeaponAttributes.SelfRepair) != 0)
                        list.Add(1060450, prop.ToString()); // self repair ~1_val~

                    if ((prop = m_AosAttributes.BonusStam) != 0)
                        list.Add(1060484, prop.ToString()); // stamina increase ~1_val~

                    if ((prop = m_AosAttributes.BonusStr) != 0)
                        list.Add(1060485, prop.ToString()); // strength bonus ~1_val~

                    int mindmg = MinDamage;
                    int maxdmg = MaxDamage;

                    if (m_Quality == WeaponQuality.Exceptional)
                    {
                        mindmg += 1;
                        maxdmg += 1;
                    }

                    switch (m_Resource)
                    {
                        case CraftResource.Agapite: mindmg += 1; maxdmg += 1; break;
                        case CraftResource.Verite: mindmg += 2; maxdmg += 2; break;
                        case CraftResource.Valorite: mindmg += 3; maxdmg += 3; break;
                    }

                    if (m_DamageLevel > WeaponDamageLevel.Regular && m_DamageLevel <= WeaponDamageLevel.Vanq)
                    {
                        switch (m_DamageLevel)
                        {
                            case WeaponDamageLevel.Ruin: mindmg += 1; maxdmg += 1; break;
                            case WeaponDamageLevel.Might: mindmg += 3; maxdmg += 3; break;
                            case WeaponDamageLevel.Force: mindmg += 5; maxdmg += 5; break;
                            case WeaponDamageLevel.Power: mindmg += 7; maxdmg += 7; break;
                            default: mindmg += 9; maxdmg += 9; break;
                        }
                    }

                    mindmg = ScaleDamageByDurability(mindmg);
                    maxdmg = ScaleDamageByDurability(maxdmg);

                    list.Add(1061168, "{0}\t{1}", mindmg.ToString(), maxdmg.ToString()); // weapon damage ~1_val~ - ~2_val~
                }
                else
                    list.Add(1038000);
            }
            else
            {
                if (m_Identified)
                {
                    //list.Add( 1008157 ); //Identified
                    bonusStr = "Identified";

                    if (m_DurabilityLevel != WeaponDurabilityLevel.Regular)
                        list.Add(1038000 + (int)m_DurabilityLevel);

                    if (m_DamageLevel != WeaponDamageLevel.Regular)
                        list.Add(1038015 + (int)m_DamageLevel);

                    if (m_AccuracyLevel != WeaponAccuracyLevel.Regular)
                        list.Add(1038010 + (int)m_AccuracyLevel);
                }

                if (m_Slayer != SlayerName.None)
                {
                    SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer);
                    if (entry != null)
                        list.Add(entry.GetTitleByMap(this.Map));
                }

                if (m_Slayer2 != SlayerName.None)
                {
                    SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2);
                    if (entry != null)
                        list.Add(entry.GetTitleByMap(this.Map));
                }

                if (m_AosSkillBonuses != null)
                    m_AosSkillBonuses.GetProperties(list);

                int prop;

                if ((prop = m_AosWeaponAttributes.UseBestSkill) != 0)
                    list.Add(1060400); // use best weapon skill

                if ((prop = (GetDamageBonus() + m_AosAttributes.WeaponDamage)) != 0)
                    list.Add(1060401, prop.ToString()); // damage increase ~1_val~%

                if ((prop = m_AosAttributes.DefendChance) != 0)
                    list.Add(1060408, prop.ToString()); // defense chance increase ~1_val~%

                if ((prop = m_AosAttributes.EnhancePotions) != 0)
                    list.Add(1060411, prop.ToString()); // enhance potions ~1_val~%

                if ((prop = m_AosAttributes.CastRecovery) != 0)
                    list.Add(1060412, prop.ToString()); // faster cast recovery ~1_val~

                if ((prop = m_AosAttributes.CastSpeed) != 0)
                    list.Add(1060413, prop.ToString()); // faster casting ~1_val~

                if ((prop = (GetHitChanceBonus() + m_AosAttributes.AttackChance)) != 0)
                    list.Add(1060415, prop.ToString()); // hit chance increase ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitColdArea) != 0)
                    list.Add(1060416, prop.ToString()); // hit cold area ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitDispel) != 0)
                    list.Add(1060417, prop.ToString()); // hit dispel ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitEnergyArea) != 0)
                    list.Add(1060418, prop.ToString()); // hit energy area ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitFireArea) != 0)
                    list.Add(1060419, prop.ToString()); // hit fire area ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitFireball) != 0)
                    list.Add(1060420, prop.ToString()); // hit fireball ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitHarm) != 0)
                    list.Add(1060421, prop.ToString()); // hit harm ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLeechHits) != 0)
                    list.Add(1060422, prop.ToString()); // hit life leech ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLightning) != 0)
                    list.Add(1060423, prop.ToString()); // hit lightning ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLowerAttack) != 0)
                    list.Add(1060424, prop.ToString()); // hit lower attack ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLowerDefend) != 0)
                    list.Add(1060425, prop.ToString()); // hit lower defense ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitMagicArrow) != 0)
                    list.Add(1060426, prop.ToString()); // hit magic arrow ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLeechMana) != 0)
                    list.Add(1060427, prop.ToString()); // hit mana leech ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitPhysicalArea) != 0)
                    list.Add(1060428, prop.ToString()); // hit physical area ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitPoisonArea) != 0)
                    list.Add(1060429, prop.ToString()); // hit poison area ~1_val~%

                if ((prop = m_AosWeaponAttributes.HitLeechStam) != 0)
                    list.Add(1060430, prop.ToString()); // hit stamina leech ~1_val~%

                if ((prop = m_AosAttributes.BonusDex) != 0)
                    list.Add(1060409, prop.ToString()); // dexterity bonus ~1_val~

                if ((prop = m_AosAttributes.BonusHits) != 0)
                    list.Add(1060431, prop.ToString()); // hit point increase ~1_val~

                if ((prop = m_AosAttributes.BonusInt) != 0)
                    list.Add(1060432, prop.ToString()); // intelligence bonus ~1_val~

                if ((prop = m_AosAttributes.LowerManaCost) != 0)
                    list.Add(1060433, prop.ToString()); // lower mana cost ~1_val~%

                if ((prop = m_AosAttributes.LowerRegCost) != 0)
                    list.Add(1060434, prop.ToString()); // lower reagent cost ~1_val~%

                if ((prop = GetLowerStatReq()) != 0)
                    list.Add(1060435, prop.ToString()); // lower requirements ~1_val~%

                if ((prop = (GetLuckBonus() + m_AosAttributes.Luck)) != 0)
                    list.Add(1060436, prop.ToString()); // luck ~1_val~

                if ((prop = m_AosWeaponAttributes.MageWeapon) != 0)
                    list.Add(1060438, (30 - prop).ToString()); // mage weapon -~1_val~ skill

                if ((prop = m_AosAttributes.BonusMana) != 0)
                    list.Add(1060439, prop.ToString()); // mana increase ~1_val~

                if ((prop = m_AosAttributes.RegenMana) != 0)
                    list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~

                if ((prop = m_AosAttributes.NightSight) != 0)
                    list.Add(1060441); // night sight

                if ((prop = m_AosAttributes.ReflectPhysical) != 0)
                    list.Add(1060442, prop.ToString()); // reflect physical damage ~1_val~%

                if ((prop = m_AosAttributes.RegenStam) != 0)
                    list.Add(1060443, prop.ToString()); // stamina regeneration ~1_val~

                if ((prop = m_AosAttributes.RegenHits) != 0)
                    list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~

                if ((prop = m_AosWeaponAttributes.SelfRepair) != 0)
                    list.Add(1060450, prop.ToString()); // self repair ~1_val~

                if ((prop = m_AosAttributes.SpellChanneling) != 0)
                    list.Add(1060482); // spell channeling

                if ((prop = m_AosAttributes.SpellDamage) != 0)
                    list.Add(1060483, prop.ToString()); // spell damage increase ~1_val~%

                if ((prop = m_AosAttributes.BonusStam) != 0)
                    list.Add(1060484, prop.ToString()); // stamina increase ~1_val~

                if ((prop = m_AosAttributes.BonusStr) != 0)
                    list.Add(1060485, prop.ToString()); // strength bonus ~1_val~

                if ((prop = m_AosAttributes.WeaponSpeed) != 0)
                    list.Add(1060486, prop.ToString()); // swing speed increase ~1_val~%

                if (m_AosWeaponAttributes.BattleLust != 0)
                {
                    if (!String.IsNullOrEmpty(bonusStr))
                        bonusStr = bonusStr + "\nBattle Lust";
                    else
                        bonusStr = bonusStr + "Battle Lust";
                }

                base.AddResistanceProperties(list);

                // start added
                int TR = (PhysicalResistance + ColdResistance + FireResistance + PoisonResistance + EnergyResistance);
                if (TR != 0 && TR != PhysicalResistance && TR != ColdResistance && TR != FireResistance && TR != PoisonResistance && TR != EnergyResistance)
                {
                    string Tag = "Total Resist";
                    string TRNum = TR.ToString() + "%";
                    list.Add(1060658, "<basefont color=#9999FF>{0}\t{1}<basefont color=White>", Tag, TRNum);
                }

                // end added

                int phys, fire, cold, pois, nrgy;

                GetDamageTypes(null, out phys, out fire, out cold, out pois, out nrgy);

                if (phys != 0)
                    list.Add(1060403, phys.ToString()); // physical damage ~1_val~%

                if (fire != 0)
                    list.Add(1060405, fire.ToString()); // fire damage ~1_val~%

                if (cold != 0)
                    list.Add(1060404, cold.ToString()); // cold damage ~1_val~%

                if (pois != 0)
                    list.Add(1060406, pois.ToString()); // poison damage ~1_val~%

                if (nrgy != 0)
                    list.Add(1060407, nrgy.ToString()); // energy damage ~1_val~%

                list.Add(1061168, "{0}\t{1}", MinDamage.ToString(), MaxDamage.ToString()); // weapon damage ~1_val~ - ~2_val~
                list.Add(1061167, Speed.ToString()); // weapon speed ~1_val~

                if (MaxRange > 1)
                    list.Add(1061169, MaxRange.ToString()); // range ~1_val~

                if (!String.IsNullOrEmpty(bonusStr))
                    list.Add(bonusStr);

                BaseRanged br = this as BaseRanged;
                NoAmmoRanged nar = this as NoAmmoRanged;

                if (br != null)
                {
                    if (br.Balanced)
                        list.Add(1072792);//Balanced
                }
                else if (nar != null)
                {
                    if (nar.Balanced)
                        list.Add(1072792);//Balanced
                }

                if (PrimaryAbility != PrimaryAbilityNew)
                    list.Add(1060661, "{0}\t{1}", WeaponAbility.AbilityName[(int)WeaponAbility.SetNewAbility(PrimaryAbility)], WeaponAbility.AbilityName[(int)NewPrimaryAbility]);

                if (SecondaryAbility != SecondaryAbilityNew)
                    list.Add(1060662, "{0}\t{1}", WeaponAbility.AbilityName[(int)WeaponAbility.SetNewAbility(SecondaryAbility)], WeaponAbility.AbilityName[(int)NewSecondaryAbility]);
            }

            //             int strReq = AOS.Scale(StrRequirement, 100 - GetLowerStatReq());
            // 
            //             if (strReq > 0)
            //                 list.Add(1061170, strReq.ToString()); // strength requirement ~1_val~

            //             if (Layer == Layer.TwoHanded)
            //                 list.Add(1061171); // two-handed weapon
            //             else
            //                 list.Add(1061824); // one-handed weapon
            // 
            //             if (Core.SE || m_AosWeaponAttributes.UseBestSkill == 0)
            //             {
            //                 switch (Skill)
            //                 {
            //                     case SkillName.Swords: list.Add(1061172); break; // skill required: swordsmanship
            //                     case SkillName.Macing: list.Add(1061173); break; // skill required: mace fighting
            //                     case SkillName.Fencing: list.Add(1061174); break; // skill required: fencing
            //                     case SkillName.Archery: list.Add(1061175); break; // skill required: archery
            //                 }
            //             }

            if (m_Hits >= 0 && m_MaxHits > 0)
            {
                if (this.Map == Map.Underworld)
                {
                    int hp = (int)((m_Hits / (double)m_MaxHits) * 10);

                    if (hp < 0)
                        hp = 0;
                    else if (hp > 9)
                        hp = 9;

                    list.Add(1038285 + hp);
                }
                else
                {
                    list.Add(1060639, m_Hits == 0 ? "<basefont color=#FF0000>{0}\t{1}<basefont color=white>" : "{0}\t{1}", m_Hits, m_MaxHits); // durability ~1_val~ / ~2_val~
                }
            }

            // mod to display attachment properties
            Server.Engines.XmlSpawner2.XmlAttach.AddAttachmentProperties(this, list);
        }

        public override void OnSingleClick(Mobile from)
        {
            List<EquipInfoAttribute> attrs = new List<EquipInfoAttribute>();

            if (DisplayLootType)
            {
                if (LootType == LootType.Blessed)
                    attrs.Add(new EquipInfoAttribute(1038021)); // blessed
                else if (LootType == LootType.Cursed)
                    attrs.Add(new EquipInfoAttribute(1049643)); // cursed
            }

            #region Factions
            if (m_FactionState != null)
                attrs.Add(new EquipInfoAttribute(1041350)); // faction item
            #endregion

            if (m_Quality == WeaponQuality.Exceptional)
                attrs.Add(new EquipInfoAttribute(1018305 - (int)m_Quality));

            if (m_Identified || from.AccessLevel >= AccessLevel.GameMaster)
            {
                if (m_Slayer != SlayerName.None)
                {
                    SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer);
                    if (entry != null)
                        attrs.Add(new EquipInfoAttribute(entry.Title));
                }

                if (m_Slayer2 != SlayerName.None)
                {
                    SlayerEntry entry = SlayerGroup.GetEntryByName(m_Slayer2);
                    if (entry != null)
                        attrs.Add(new EquipInfoAttribute(entry.Title));
                }

                if (m_DurabilityLevel != WeaponDurabilityLevel.Regular)
                    attrs.Add(new EquipInfoAttribute(1038000 + (int)m_DurabilityLevel));

                if (m_DamageLevel != WeaponDamageLevel.Regular)
                    attrs.Add(new EquipInfoAttribute(1038015 + (int)m_DamageLevel));

                if (m_AccuracyLevel != WeaponAccuracyLevel.Regular)
                    attrs.Add(new EquipInfoAttribute(1038010 + (int)m_AccuracyLevel));
            }
            else if (m_Slayer != SlayerName.None || m_Slayer2 != SlayerName.None || m_DurabilityLevel != WeaponDurabilityLevel.Regular || m_DamageLevel != WeaponDamageLevel.Regular || m_AccuracyLevel != WeaponAccuracyLevel.Regular)
                attrs.Add(new EquipInfoAttribute(1038000)); // Unidentified

            if (m_Poison != null && m_PoisonCharges > 0)
                attrs.Add(new EquipInfoAttribute(1017383, m_PoisonCharges));

            int number;

            if (Name == null)
            {
                number = LabelNumber;
            }
            else
            {
                this.LabelTo(from, Name);
                number = 1041000;
            }

            if (attrs.Count == 0 && Crafter == null && Name != null)
                return;

            EquipmentInfo eqInfo = new EquipmentInfo(number, m_Crafter, false, attrs.ToArray());

            from.Send(new DisplayEquipmentInfo(this, eqInfo));
        }

        private static BaseWeapon m_Fists; // This value holds the default--fist--weapon

        public static BaseWeapon Fists
        {
            get { return m_Fists; }
            set { m_Fists = value; }
        }

        #region ICraftable Members

        public int OnCraft(int quality, bool makersMark, Mobile from, CraftSystem craftSystem, Type typeRes, BaseTool tool, CraftItem craftItem, int resHue)
        {
            Quality = (WeaponQuality)quality;

            if (makersMark)
                Crafter = from;

            PlayerConstructed = true;

            if (from.Map == Map.Underworld)
            {
                Identified = true;
                IsUWItem = true;
            }

            Type resourceType = typeRes;

            if (resourceType == null)
                resourceType = craftItem.Ressources.GetAt(0).ItemType;

            Resource = CraftResources.GetFromType(resourceType);

            if (!IsUWItem)
            {
                CraftContext context = craftSystem.GetContext(from);

                if (context != null && context.DoNotColor)
                    Hue = 0;

                if (tool is BaseRunicTool)
                    ((BaseRunicTool)tool).ApplyAttributesTo(this, from);

                if (Quality == WeaponQuality.Exceptional)
                {
                    Attributes.WeaponDamage += 25;
                }
            }
            else if (tool is BaseRunicTool)
            {
                if (10 > Utility.Random(100))
                    ((BaseRunicTool)tool).ApplyAttributesTo(this, from);

                CraftResource thisResource = CraftResources.GetFromType(resourceType);

                if (thisResource == ((BaseRunicTool)tool).Resource)
                {
                    Resource = thisResource;

                    CraftContext context = craftSystem.GetContext(from);

                    if (context != null && context.DoNotColor)
                        Hue = 0;

                    switch (thisResource)
                    {
                        case CraftResource.DullCopper:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Durable;
                                AccuracyLevel = WeaponAccuracyLevel.Accurate;
                                break;
                            }

                        case CraftResource.ShadowIron:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Durable;
                                DamageLevel = WeaponDamageLevel.Ruin;
                                break;
                            }

                        case CraftResource.Copper:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Fortified;
                                DamageLevel = WeaponDamageLevel.Ruin;
                                AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
                                break;
                            }

                        case CraftResource.Bronze:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Fortified;
                                DamageLevel = WeaponDamageLevel.Might;
                                AccuracyLevel = WeaponAccuracyLevel.Surpassingly;
                                break;
                            }

                        case CraftResource.Gold:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                                DamageLevel = WeaponDamageLevel.Force;
                                AccuracyLevel = WeaponAccuracyLevel.Eminently;
                                break;
                            }

                        case CraftResource.Agapite:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                                DamageLevel = WeaponDamageLevel.Power;
                                AccuracyLevel = WeaponAccuracyLevel.Eminently;
                                break;
                            }

                        case CraftResource.Verite:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                                DamageLevel = WeaponDamageLevel.Power;
                                AccuracyLevel = WeaponAccuracyLevel.Exceedingly;
                                break;
                            }

                        case CraftResource.Valorite:
                            {
                                DurabilityLevel = WeaponDurabilityLevel.Indestructible;
                                DamageLevel = WeaponDamageLevel.Vanq;
                                AccuracyLevel = WeaponAccuracyLevel.Supremely;
                                break;
                            }
                    }
                }
            }

            CraftResourceInfo resInfo = CraftResources.GetInfo(m_Resource);

            if (resInfo == null)
                return quality;

            CraftAttributeInfo attrInfo = resInfo.AttributeInfo;

            if (attrInfo == null)
                return quality;

            if (m_Resource == CraftResource.Silver)
            {
                Slayer2 = SlayerName.Silver;
            }
            else if (m_Resource == CraftResource.DullCopper && IsUWItem)
            {
                WeaponAttributes.SelfRepair += 1;
            }
            else if (quality == 2 && (m_Resource == CraftResource.Moonstone || m_Resource == CraftResource.Sunstone || m_Resource == CraftResource.Bloodstone
               || m_Resource == CraftResource.Heartwood || m_Resource == CraftResource.Bloodwood || m_Resource == CraftResource.Frostwood))
            {
                PlayerTitles.TitleProgress(from, "craft", 1);
            }

            return quality;
        }

        #endregion
    }

    public enum CheckSlayerResult
    {
        None,
        Slayer,
        Opposition
    }
}